summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErik de Castro Lopo <erikd@mega-nerd.com>2007-05-14 19:55:24 +1000
committerErik de Castro Lopo <erikd@mega-nerd.com>2007-05-14 19:55:24 +1000
commitcb979e10a703033864f8f42c94e9d1d335e5be40 (patch)
tree6bb359e4b64f1719b7afcd887da975e1021405ec
First snapshot of the public project.
-rw-r--r--AUTHORS14
-rw-r--r--COPYING503
-rw-r--r--ChangeLog6641
-rw-r--r--INSTALL182
-rw-r--r--Make.bat33
-rw-r--r--Makefile.am27
-rw-r--r--NEWS131
-rw-r--r--Octave/Makefile.am14
-rw-r--r--Octave/sndfile_load.m59
-rw-r--r--Octave/sndfile_play.m66
-rw-r--r--Octave/sndfile_save.m60
-rw-r--r--README71
-rw-r--r--Win32/Makefile.am10
-rw-r--r--Win32/Makefile.mingw.in401
-rw-r--r--Win32/Makefile.msvc577
-rw-r--r--Win32/README-Win32.txt96
-rw-r--r--Win32/README-precompiled-dll.txt40
-rw-r--r--Win32/config.h290
-rw-r--r--Win32/libtool.mingw7273
-rw-r--r--Win32/sndfile.h539
-rw-r--r--Win32/testprog.c24
-rw-r--r--acinclude.m4569
-rw-r--r--binheader_readf_check.py69
-rw-r--r--configure.ac673
-rw-r--r--doc/FAQ.html720
-rw-r--r--doc/Makefile.am16
-rw-r--r--doc/api.html703
-rw-r--r--doc/bugs.html84
-rw-r--r--doc/command.html1245
-rw-r--r--doc/development.html83
-rw-r--r--doc/dither.html1024
-rw-r--r--doc/embedded_files.html54
-rw-r--r--doc/index.html476
-rw-r--r--doc/libsndfile.css.in81
-rw-r--r--doc/libsndfile.jpgbin0 -> 22043 bytes
-rw-r--r--doc/linux_games_programming.txt440
-rw-r--r--doc/lists.html59
-rw-r--r--doc/new_file_type.HOWTO135
-rw-r--r--doc/octave.html125
-rw-r--r--doc/pkgconfig.html78
-rw-r--r--doc/sndfile_info.html60
-rw-r--r--doc/win32.html141
-rw-r--r--examples/Makefile.am46
-rw-r--r--examples/generate.c125
-rw-r--r--examples/generate.cs255
-rw-r--r--examples/list_formats.c76
-rw-r--r--examples/make_sine.c89
-rw-r--r--examples/paf_write.c88
-rw-r--r--examples/sfprocess.c131
-rw-r--r--examples/sndfile-convert.c395
-rw-r--r--examples/sndfile-data-trim.c65
-rw-r--r--examples/sndfile-info.c354
-rw-r--r--examples/sndfile-play-beos.cpp153
-rw-r--r--examples/sndfile-play.c960
-rw-r--r--libsndfile.spec.in69
-rw-r--r--make_lite.py499
-rw-r--r--man/Makefile.am12
-rw-r--r--man/sndfile-convert.128
-rw-r--r--man/sndfile-info.122
-rw-r--r--man/sndfile-play.141
-rwxr-xr-xreconfigure.mk58
-rw-r--r--regtest/Makefile.am18
-rw-r--r--regtest/Readme.txt114
-rw-r--r--regtest/checksum.c125
-rw-r--r--regtest/database.c502
-rw-r--r--regtest/regtest.h45
-rw-r--r--regtest/sndfile-regtest.c128
-rw-r--r--sndfile.pc.in11
-rw-r--r--src/FLAC/AUTHORS41
-rw-r--r--src/FLAC/COPYING.FDL397
-rw-r--r--src/FLAC/COPYING.GPL340
-rw-r--r--src/FLAC/COPYING.LGPL504
-rw-r--r--src/FLAC/COPYING.Xiph28
-rw-r--r--src/FLAC/Makefile.am39
-rw-r--r--src/FLAC/README269
-rw-r--r--src/FLAC/include/FLAC/Makefile.am42
-rw-r--r--src/FLAC/include/FLAC/all.h344
-rw-r--r--src/FLAC/include/FLAC/assert.h45
-rw-r--r--src/FLAC/include/FLAC/callback.h184
-rw-r--r--src/FLAC/include/FLAC/export.h87
-rw-r--r--src/FLAC/include/FLAC/format.h995
-rw-r--r--src/FLAC/include/FLAC/metadata.h2112
-rw-r--r--src/FLAC/include/FLAC/ordinals.h80
-rw-r--r--src/FLAC/include/FLAC/stream_decoder.h1559
-rw-r--r--src/FLAC/include/FLAC/stream_encoder.h1769
-rw-r--r--src/FLAC/include/Makefile.am18
-rw-r--r--src/FLAC/include/share/Makefile.am12
-rw-r--r--src/FLAC/include/share/getopt.h184
-rw-r--r--src/FLAC/include/share/grabbag.h29
-rw-r--r--src/FLAC/include/share/grabbag/Makefile.am10
-rw-r--r--src/FLAC/include/share/grabbag/cuesheet.h42
-rw-r--r--src/FLAC/include/share/grabbag/file.h63
-rw-r--r--src/FLAC/include/share/grabbag/picture.h46
-rw-r--r--src/FLAC/include/share/grabbag/replaygain.h72
-rw-r--r--src/FLAC/include/share/grabbag/seektable.h38
-rw-r--r--src/FLAC/include/share/replaygain_analysis.h59
-rw-r--r--src/FLAC/include/share/replaygain_synthesis.h51
-rw-r--r--src/FLAC/include/share/utf8.h25
-rw-r--r--src/FLAC/include/test_libs_common/Makefile.am7
-rw-r--r--src/FLAC/include/test_libs_common/file_utils_flac.h34
-rw-r--r--src/FLAC/include/test_libs_common/metadata_utils.h73
-rw-r--r--src/FLAC/src/Makefile.am27
-rw-r--r--src/FLAC/src/libFLAC/Makefile.am92
-rw-r--r--src/FLAC/src/libFLAC/bitmath.c149
-rw-r--r--src/FLAC/src/libFLAC/bitreader.c1363
-rw-r--r--src/FLAC/src/libFLAC/bitwriter.c872
-rw-r--r--src/FLAC/src/libFLAC/cpu.c418
-rw-r--r--src/FLAC/src/libFLAC/crc.c142
-rw-r--r--src/FLAC/src/libFLAC/fixed.c435
-rw-r--r--src/FLAC/src/libFLAC/flac.pc.in10
-rw-r--r--src/FLAC/src/libFLAC/float.c308
-rw-r--r--src/FLAC/src/libFLAC/format.c583
-rw-r--r--src/FLAC/src/libFLAC/ia32/Makefile.am45
-rw-r--r--src/FLAC/src/libFLAC/ia32/bitreader_asm.nasm568
-rw-r--r--src/FLAC/src/libFLAC/ia32/cpu_asm.nasm121
-rw-r--r--src/FLAC/src/libFLAC/ia32/fixed_asm.nasm312
-rw-r--r--src/FLAC/src/libFLAC/ia32/lpc_asm-unrolled.nasm784
-rw-r--r--src/FLAC/src/libFLAC/ia32/lpc_asm.nasm1511
-rw-r--r--src/FLAC/src/libFLAC/ia32/nasm.h75
-rw-r--r--src/FLAC/src/libFLAC/ia32/stream_encoder_asm.nasm157
-rw-r--r--src/FLAC/src/libFLAC/include/Makefile.am31
-rw-r--r--src/FLAC/src/libFLAC/include/private/Makefile.am50
-rw-r--r--src/FLAC/src/libFLAC/include/private/all.h49
-rw-r--r--src/FLAC/src/libFLAC/include/private/bitmath.h42
-rw-r--r--src/FLAC/src/libFLAC/include/private/bitreader.h99
-rw-r--r--src/FLAC/src/libFLAC/include/private/bitwriter.h103
-rw-r--r--src/FLAC/src/libFLAC/include/private/cpu.h88
-rw-r--r--src/FLAC/src/libFLAC/include/private/crc.h61
-rw-r--r--src/FLAC/src/libFLAC/include/private/fixed.h97
-rw-r--r--src/FLAC/src/libFLAC/include/private/float.h97
-rw-r--r--src/FLAC/src/libFLAC/include/private/format.h44
-rw-r--r--src/FLAC/src/libFLAC/include/private/lpc.h214
-rw-r--r--src/FLAC/src/libFLAC/include/private/md5.h44
-rw-r--r--src/FLAC/src/libFLAC/include/private/memory.h56
-rw-r--r--src/FLAC/src/libFLAC/include/private/metadata.h45
-rw-r--r--src/FLAC/src/libFLAC/include/private/ogg_decoder_aspect.h79
-rw-r--r--src/FLAC/src/libFLAC/include/private/ogg_encoder_aspect.h62
-rw-r--r--src/FLAC/src/libFLAC/include/private/ogg_helper.h43
-rw-r--r--src/FLAC/src/libFLAC/include/private/ogg_mapping.h63
-rw-r--r--src/FLAC/src/libFLAC/include/private/stream_encoder_framing.h45
-rw-r--r--src/FLAC/src/libFLAC/include/private/window.h71
-rw-r--r--src/FLAC/src/libFLAC/include/protected/Makefile.am34
-rw-r--r--src/FLAC/src/libFLAC/include/protected/all.h38
-rw-r--r--src/FLAC/src/libFLAC/include/protected/stream_decoder.h58
-rw-r--r--src/FLAC/src/libFLAC/include/protected/stream_encoder.h109
-rw-r--r--src/FLAC/src/libFLAC/libFLAC.m4114
-rw-r--r--src/FLAC/src/libFLAC/lpc.c1373
-rw-r--r--src/FLAC/src/libFLAC/md5.c417
-rw-r--r--src/FLAC/src/libFLAC/memory.c194
-rw-r--r--src/FLAC/src/libFLAC/metadata_iterators.c3304
-rw-r--r--src/FLAC/src/libFLAC/metadata_object.c1789
-rw-r--r--src/FLAC/src/libFLAC/ogg_decoder_aspect.c253
-rw-r--r--src/FLAC/src/libFLAC/ogg_encoder_aspect.c227
-rw-r--r--src/FLAC/src/libFLAC/ogg_helper.c208
-rw-r--r--src/FLAC/src/libFLAC/ogg_mapping.c47
-rw-r--r--src/FLAC/src/libFLAC/ppc/Makefile.am31
-rw-r--r--src/FLAC/src/libFLAC/ppc/as/Makefile.am34
-rw-r--r--src/FLAC/src/libFLAC/ppc/as/lpc_asm.s429
-rw-r--r--src/FLAC/src/libFLAC/ppc/gas/Makefile.am33
-rw-r--r--src/FLAC/src/libFLAC/ppc/gas/lpc_asm.s431
-rw-r--r--src/FLAC/src/libFLAC/stream_decoder.c3338
-rw-r--r--src/FLAC/src/libFLAC/stream_encoder.c4252
-rw-r--r--src/FLAC/src/libFLAC/stream_encoder_framing.c515
-rw-r--r--src/FLAC/src/libFLAC/window.c225
-rw-r--r--src/FLAC/src/monkeys_audio_utilities/Makefile.am18
-rw-r--r--src/FLAC/src/monkeys_audio_utilities/flac_mac/Makefile.am19
-rw-r--r--src/FLAC/src/monkeys_audio_utilities/flac_mac/main.c208
-rw-r--r--src/FLAC/src/monkeys_audio_utilities/flac_ren/Makefile.am19
-rw-r--r--src/FLAC/src/monkeys_audio_utilities/flac_ren/main.c39
-rw-r--r--src/FLAC/src/share/Makefile.am19
-rw-r--r--src/FLAC/src/share/README5
-rw-r--r--src/FLAC/src/share/getopt/Makefile.am15
-rw-r--r--src/FLAC/src/share/getopt/getopt.c1064
-rw-r--r--src/FLAC/src/share/getopt/getopt1.c204
-rw-r--r--src/FLAC/src/share/grabbag/Makefile.am20
-rw-r--r--src/FLAC/src/share/grabbag/cuesheet.c599
-rw-r--r--src/FLAC/src/share/grabbag/file.c192
-rw-r--r--src/FLAC/src/share/grabbag/picture.c406
-rw-r--r--src/FLAC/src/share/grabbag/replaygain.c670
-rw-r--r--src/FLAC/src/share/grabbag/seektable.c132
-rw-r--r--src/FLAC/src/share/replaygain_anal/Makefile.am15
-rw-r--r--src/FLAC/src/share/replaygain_anal/replaygain_analysis.c419
-rw-r--r--src/FLAC/src/share/replaygain_syn/Makefile.am18
-rw-r--r--src/FLAC/src/share/replaygain_syn/include/Makefile.am18
-rw-r--r--src/FLAC/src/share/replaygain_syn/include/private/Makefile.am19
-rw-r--r--src/FLAC/src/share/replaygain_syn/include/private/fast_float_math_hack.h39
-rw-r--r--src/FLAC/src/share/replaygain_syn/replaygain_synthesis.c467
-rw-r--r--src/FLAC/src/share/utf8/Makefile.am21
-rw-r--r--src/FLAC/src/share/utf8/charmaps.h57
-rw-r--r--src/FLAC/src/share/utf8/charset.c532
-rw-r--r--src/FLAC/src/share/utf8/charset.h72
-rw-r--r--src/FLAC/src/share/utf8/charset_test.c263
-rw-r--r--src/FLAC/src/share/utf8/charsetmap.h79
-rw-r--r--src/FLAC/src/share/utf8/iconvert.c248
-rw-r--r--src/FLAC/src/share/utf8/makemap.c81
-rw-r--r--src/FLAC/src/share/utf8/utf8.c303
-rw-r--r--src/FLAC/src/test_grabbag/Makefile.am19
-rw-r--r--src/FLAC/src/test_grabbag/cuesheet/Makefile.am30
-rw-r--r--src/FLAC/src/test_grabbag/cuesheet/main.c138
-rw-r--r--src/FLAC/src/test_grabbag/picture/Makefile.am29
-rw-r--r--src/FLAC/src/test_grabbag/picture/main.c224
-rw-r--r--src/FLAC/src/test_libFLAC/Makefile.am42
-rw-r--r--src/FLAC/src/test_libFLAC/bitwriter.c584
-rw-r--r--src/FLAC/src/test_libFLAC/bitwriter.h26
-rw-r--r--src/FLAC/src/test_libFLAC/decoders.c1048
-rw-r--r--src/FLAC/src/test_libFLAC/decoders.h26
-rw-r--r--src/FLAC/src/test_libFLAC/encoders.c521
-rw-r--r--src/FLAC/src/test_libFLAC/encoders.h26
-rw-r--r--src/FLAC/src/test_libFLAC/format.c256
-rw-r--r--src/FLAC/src/test_libFLAC/format.h26
-rw-r--r--src/FLAC/src/test_libFLAC/main.c49
-rw-r--r--src/FLAC/src/test_libFLAC/metadata.c40
-rw-r--r--src/FLAC/src/test_libFLAC/metadata.h28
-rw-r--r--src/FLAC/src/test_libFLAC/metadata_manip.c2138
-rw-r--r--src/FLAC/src/test_libFLAC/metadata_object.c2299
-rw-r--r--src/FLAC/src/test_libs_common/Makefile.am27
-rw-r--r--src/FLAC/src/test_libs_common/README2
-rw-r--r--src/FLAC/src/test_libs_common/file_utils_flac.c153
-rw-r--r--src/FLAC/src/test_libs_common/metadata_utils.c657
-rw-r--r--src/FLAC/src/test_seeking/Makefile.am28
-rw-r--r--src/FLAC/src/test_seeking/main.c399
-rw-r--r--src/FLAC/src/test_streams/Makefile.am26
-rw-r--r--src/FLAC/src/test_streams/main.c933
-rwxr-xr-xsrc/FLAC/strip_non_asm_libtool_args.sh19
-rw-r--r--src/FLAC/test/Makefile.am36
-rwxr-xr-xsrc/FLAC/test/test_bins.sh114
-rwxr-xr-xsrc/FLAC/test/test_libFLAC.sh49
-rw-r--r--src/G72x/ChangeLog50
-rw-r--r--src/G72x/Makefile.am28
-rw-r--r--src/G72x/README0
-rw-r--r--src/G72x/README.original94
-rw-r--r--src/G72x/g721.c162
-rw-r--r--src/G72x/g723_16.c169
-rw-r--r--src/G72x/g723_24.c146
-rw-r--r--src/G72x/g723_40.c160
-rw-r--r--src/G72x/g72x.c652
-rw-r--r--src/G72x/g72x.h99
-rw-r--r--src/G72x/g72x_priv.h118
-rw-r--r--src/G72x/g72x_test.c222
-rw-r--r--src/GSM610/COPYRIGHT16
-rw-r--r--src/GSM610/ChangeLog56
-rw-r--r--src/GSM610/Makefile.am21
-rw-r--r--src/GSM610/README36
-rw-r--r--src/GSM610/add.c248
-rw-r--r--src/GSM610/code.c97
-rw-r--r--src/GSM610/config.h33
-rw-r--r--src/GSM610/decode.c67
-rw-r--r--src/GSM610/gsm.h58
-rw-r--r--src/GSM610/gsm610_priv.h308
-rw-r--r--src/GSM610/gsm_create.c44
-rw-r--r--src/GSM610/gsm_decode.c366
-rw-r--r--src/GSM610/gsm_destroy.c31
-rw-r--r--src/GSM610/gsm_encode.c456
-rw-r--r--src/GSM610/gsm_option.c74
-rw-r--r--src/GSM610/long_term.c969
-rw-r--r--src/GSM610/lpc.c341
-rw-r--r--src/GSM610/preprocess.c115
-rw-r--r--src/GSM610/rpe.c490
-rw-r--r--src/GSM610/short_term.c427
-rw-r--r--src/GSM610/table.c69
-rw-r--r--src/Makefile.am121
-rw-r--r--src/OGG/Makefile.am29
-rw-r--r--src/OGG/README.txt7
-rw-r--r--src/OGG/bitwise.c788
-rw-r--r--src/OGG/framing.c1808
-rw-r--r--src/OGG/include/Makefile.am3
-rw-r--r--src/OGG/include/ogg/Makefile.am3
-rw-r--r--src/OGG/include/ogg/config_types.h12
-rw-r--r--src/OGG/include/ogg/ogg.h202
-rw-r--r--src/OGG/include/ogg/os_types.h127
-rw-r--r--src/aiff.c1522
-rw-r--r--src/alaw.c544
-rw-r--r--src/au.c453
-rw-r--r--src/audio_detect.c106
-rw-r--r--src/avr.c254
-rwxr-xr-xsrc/binheader_writef_check.py114
-rw-r--r--src/broadcast.c89
-rw-r--r--src/caf.c538
-rw-r--r--src/command.c363
-rw-r--r--src/common.c1291
-rw-r--r--src/common.h813
-rwxr-xr-xsrc/create_symbols_file.py153
-rw-r--r--src/dither.c533
-rw-r--r--src/double64.c1042
-rw-r--r--src/dwd.c208
-rw-r--r--src/dwvw.c669
-rw-r--r--src/file_io.c1537
-rw-r--r--src/flac.c1112
-rw-r--r--src/float32.c995
-rw-r--r--src/float_cast.h262
-rw-r--r--src/g72x.c611
-rw-r--r--src/gsm610.c626
-rw-r--r--src/htk.c225
-rw-r--r--src/ima_adpcm.c976
-rw-r--r--src/interleave.c306
-rw-r--r--src/ircam.c329
-rw-r--r--src/macbinary3.c52
-rw-r--r--src/macos.c58
-rw-r--r--src/mat4.c395
-rw-r--r--src/mat5.c507
-rw-r--r--src/ms_adpcm.c834
-rw-r--r--src/new.c123
-rw-r--r--src/nist.c367
-rw-r--r--src/ogg.c44
-rw-r--r--src/paf.c838
-rw-r--r--src/pcm.c2901
-rw-r--r--src/pvf.c195
-rw-r--r--src/raw.c111
-rw-r--r--src/rx2.c326
-rw-r--r--src/sd2.c624
-rw-r--r--src/sds.c993
-rw-r--r--src/sf_unistd.h67
-rw-r--r--src/sfconfig.h108
-rw-r--r--src/sfendian.h261
-rw-r--r--src/sndfile.c2756
-rw-r--r--src/sndfile.h.in602
-rw-r--r--src/sndfile.hh351
-rw-r--r--src/strings.c204
-rw-r--r--src/svx.c413
-rw-r--r--src/test_audio_detect.c126
-rw-r--r--src/test_conversions.c101
-rw-r--r--src/test_endswap.def28
-rw-r--r--src/test_endswap.tpl135
-rw-r--r--src/test_file_io.c448
-rw-r--r--src/test_log_printf.c133
-rw-r--r--src/txw.c379
-rw-r--r--src/ulaw.c1047
-rw-r--r--src/voc.c878
-rw-r--r--src/vox_adpcm.c537
-rw-r--r--src/w64.c587
-rw-r--r--src/wav.c1673
-rw-r--r--src/wav_w64.c578
-rw-r--r--src/wav_w64.h293
-rw-r--r--src/wve.c209
-rw-r--r--src/xi.c1200
-rw-r--r--tests/Makefile.am412
-rw-r--r--tests/aiff_rw_test.c169
-rw-r--r--tests/alaw_test.c250
-rw-r--r--tests/benchmark-0.0.2840
-rw-r--r--tests/benchmark-1.0.035
-rw-r--r--tests/benchmark-1.0.0rc231
-rw-r--r--tests/benchmark-1.0.6pre10-coltrane39
-rw-r--r--tests/benchmark-1.0.6pre10-miles39
-rw-r--r--tests/benchmark-latest-coltrane75
-rw-r--r--tests/benchmark.def25
-rw-r--r--tests/benchmark.tpl361
-rw-r--r--tests/command_test.c880
-rw-r--r--tests/cpp_crack_test.cc144
-rw-r--r--tests/cpp_test.cc197
-rw-r--r--tests/dft_cmp.c137
-rw-r--r--tests/dft_cmp.h30
-rw-r--r--tests/dither_test.c192
-rw-r--r--tests/dwvw_test.c119
-rw-r--r--tests/error_test.c113
-rw-r--r--tests/fix_this.c331
-rw-r--r--tests/floating_point_test.def40
-rw-r--r--tests/floating_point_test.tpl347
-rw-r--r--tests/header_test.def30
-rw-r--r--tests/header_test.tpl498
-rw-r--r--tests/headerless_test.c187
-rw-r--r--tests/largefile_test.c90
-rw-r--r--tests/locale_test.c114
-rw-r--r--tests/lossy_comp_test.c2194
-rw-r--r--tests/misc_test.c365
-rw-r--r--tests/multi_file_test.c258
-rw-r--r--tests/open_fail_test.c81
-rw-r--r--tests/pcm_test.def42
-rw-r--r--tests/pcm_test.tpl940
-rw-r--r--tests/peak_chunk_test.c289
-rw-r--r--tests/pipe_test.def22
-rw-r--r--tests/pipe_test.tpl382
-rw-r--r--tests/raw_test.c195
-rw-r--r--tests/scale_clip_test.def62
-rw-r--r--tests/scale_clip_test.tpl339
-rw-r--r--tests/sftest.c73
-rw-r--r--tests/sfversion.c49
-rw-r--r--tests/stdin_test.c204
-rw-r--r--tests/stdio_test.c159
-rw-r--r--tests/stdout_test.c167
-rw-r--r--tests/string_test.c227
-rw-r--r--tests/ulaw_test.c262
-rw-r--r--tests/utils.def59
-rw-r--r--tests/utils.tpl704
-rw-r--r--tests/virtual_io_test.c238
-rw-r--r--tests/win32_ordinal_test.c146
-rw-r--r--tests/win32_test.c235
-rw-r--r--tests/write_read_test.def73
-rw-r--r--tests/write_read_test.tpl1026
388 files changed, 141264 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..95770ab
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,14 @@
+The main author of libsndfile is Erik de Castro Lopo <erikd@mega-nerd.com>.
+
+The code in the src/GSM610 directory was written by Jutta Degener
+<jutta@cs.tu-berlin.de> and Carsten Bormann <cabo@cs.tu-berlin.de>.
+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
+
+Code in the src/G72x directory was 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.
+
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..c396169
--- /dev/null
+++ b/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.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..d61f2dd
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,6641 @@
+2007-05-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/FLAC/src/share/getopt/getopt.c
+ Fix Mac OSX / PowerPC compile warnings.
+
+ * configure.ac
+ Make sure WORDS_BIGENDIAN gets correctly defined for FLAC code.
+
+2007-05-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ Add Q/A about MP3 support.
+
+2007-05-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/new_file_type.HOWTO
+ Minor updates.
+
+2007-05-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wve.c
+ Fix a couple bad parameters with psf_log_printf.
+
+ * src/pcm.c
+ Improve error reporting.
+
+ * src/common.h src/common.c
+ Constify psf_hexdump.
+
+2007-04-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/FLAC
+ Ditch and re-import required FLAC code.
+
+ * configure.ac
+ Force FLAC__HAS_OGG variable to 1.
+
+ * src/FLAC/src/libFLAC/stream_encoder.c
+ Fix compiler warnings.
+
+2007-04-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac tests/win32_ordinal_test.c
+ Detect if win32 DLL is beging generated and only run win32_ordinal_test if
+ true.
+
+ * src/G72x/Makefile.am src/Makefile.am
+ Use $(EXEEXT) where possible.
+
+2007-04-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wve.c src/common.h src/sndfile.c
+ Complete definition of SfE_WVE_NO_WVE error message.
+
+ * src/wve.c
+ Fix error in files generated on big endian systems. Robustify parsing.
+
+2007-04-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/double64.c
+ Fix clipping of double to short conversions on 64 bit systems.
+
+ * src/flac.c regtest/database.c tests/cpp_test.cc
+ Fix compile warnings for 64 bit systems.
+
+2007-04-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c src/wav_w64.c
+ Use audio detect function when 'fmt ' chunk data is suspicious.
+
+ * configure.ac
+ Add ugly hack to remove -Werror from some Makefiles.
+
+2007-04-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-data-trim.c
+ New file. Program incomplete.
+
+ * src/GSM610/long_term.c src/macbinary3.c tests/cpp_test.cc
+ Add patch from André Pang to clean up compiles on OSX.
+
+ * src/wve.c src/common.h src/sndfile.c src/sndfile.h.in
+ examples/sndfile-convert.c
+ Merge changes from Reuben Thomas to improve WVE support.
+
+ * tests/lossy_comp_test.c tests/Makefile.am
+ Add tests for WVE files.
+
+2007-04-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.hh
+ Add a static SndfileHandle::formatCheck method as suggested by Jorge
+ Jiménez.
+
+2007-04-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed a bug in sf_error() where the function itself was being compared
+ against zero. Add a check for a NULL return from peak_info_calloc. Fix a
+ possible NULL dereference.
+
+2007-04-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/flac.c
+ Turn off seekable flag when writing, return SFE_BAD_RDWR_FORMAT when
+ opening file for RDWR.
+
+ * src/sndfile.c
+ Improve error message for SFE_BAD_RDWR_FORMAT.
+
+ * src/mat4.c
+ Fix array indexing issue. Thanks to Ben Allison (Nullsoft) for alerting me.
+
+2007-03-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ Add Q/A 19 on project files.
+
+2007-03-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Guard agains MacOSX universal binary compiles.
+
+ * doc/FAQ.html
+ Add Q/A 18 and clean up Q3.
+
+2007-02-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Add support for 'in24' files.
+
+2007-02-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c src/wav_w64.c src/wav_w64.h
+ Start work towards detecting ausio codec type from the actual audio data.
+
+ * src/audio_detect.c src/test_audio_detect.c
+ Add new file and its unit test.
+
+2007-02-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/cooledit-fixer.c examples/Makefile.am
+ Remove old broken example program.
+
+2007-02-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/sndfile.h.in src/create_symbols_file.py
+ Add function sf_get_info.
+
+2007-01-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ For ALSA, use the 'default' device instead of 'plughw:0'.
+
+2007-01-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Allow writing of WAV/WAVEX 'BEXT' chunks in SFM_RDWR mode.
+
+2007-01-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/development.html doc/embedded_files.html man/sndfile-play.1
+ Minor documentation fixes. Thanks Reuben Thomas.
+
+2006-12-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-convert.c
+ Add -override-sample-rate command line option.
+
+2006-11-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/misc_test.c
+ Force errno to zero at start of some tests.
+
+ * src/sndfile.c
+ Minor clean up of error handling.
+
+ * configure.ac
+ Remove an assembler test which was failing on OSX.
+
+2006-11-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Fix the definition of SF_PLATFORM_S64 for MinGW.
+
+ * src/FLAC/Makefile.am src/FLAC/share/grabbag/Makefile.am
+ Fix path problems for MinGW.
+
+2006-11-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sfendian.h
+ Add include guard.
+
+ * src/Makefile.am src/flac.c
+ Clean up include paths.
+
+ * src/test_conversions.c
+ New file to test psf_binheader_readf/writef functions.
+
+ * src/Makefile.am src/test_file_io.c src/test_log_printf.c src/common.c
+ Clean up unit testing.
+
+ * src/common.c
+ Fix a bug reading/writing 64 bit header fields. Thanks to Jonathan Woithe
+ for reporting this.
+
+ * src/test_conversions.c
+ Complete unit test for above fix.
+
+2006-11-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ More refactoring to clean up psf_open_file() and vairous sf_open()
+ functions.
+
+2006-11-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Apply a patch from Jonathan Woithe to allow opening of (malformed) WAV
+ files of over 4 gigabytes.
+
+2006-11-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Refactor function psf_open_file() to provide a single return point.
+
+ * tests/misc_test.c
+ Fix permission_test to ensure that read only file can be created.
+
+2006-11-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Add SF_PLATFORM_S64 macro as a platform independant way of doing signed 64
+ bit integers.
+
+ * src/aiff.c src/svx.c src/wav.c
+ Add warning in log if files are larger than 4 gigabytes in size.
+
+2006-11-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/FLAC src/OGG confgure.ac src/Makefile.am
+ Pull in all required FLAC and OGG code so external libraries are not
+ needed. This makes compiling on stupid fscking Windoze easier.
+
+2006-10-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sd2.c
+ Add workaround for switched sample rate and sample size.
+
+ * src/wav.c
+ Add workaround for excessively long coding history in the 'bext' chunk.
+
+2006-10-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/sndfile.c src/wav.c doc/command.html
+ Use SF_AMBISONIC_* instead of SF_TRUE/SF_FALSE.
+
+2006-10-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/wav.c src/wav_w64.c src/common.h doc/command.html
+ Apply a patch from Fons Adriaensen to allow writing on WAVEX Ambisonic
+ files. Still needs a little tweaking before its ready for release.
+
+ * src/*.c
+ Use the UNUSED macro to prevent compiler warnings.
+
+2006-10-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Fix a bug in parsing AIFF files with a slightly unusual 'basc' chunk. Thanks
+ to David Viens for providing two example files.
+
+ * src/common.(c|h) src/aiff.c
+ Add a function psf_sanitize_string and use it in aiff.c.
+
+2006-10-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_w64.c
+ Apply a patch from Fons Adriaensen which fixes a minor WAVEX GUID issue.
+
+2006-10-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/Makefile.am
+ Fix problem related to recent test coverage changes.
+
+2006-10-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac tests/Makefile.am
+ Add --enable-test-coverage configure option.
+
+2006-10-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.hh
+ Add an std::string SndfileHandle constructor.
+
+ * tests/scale_clip_test.tpl
+ Fix the 'make distcheck' target.
+
+2006-10-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/double64.c src/float32.c
+ Add optional clipping on float file data to int read data conversions.
+
+ * tests/tests/scale_clip_test.(def|tpl)
+ Add test for above new code.
+
+2006-09-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/aiff_rw_test.c
+ Add 'MARK' chunks to make sure they are parsed correctly.
+
+2006-09-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Fix parsing of MARK chunks. Many thanks to Sciss for generating files to
+ help debug the problem.
+
+2006-09-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Make the SF_MIN and SF_MAX macros at least partially type safe.
+
+ * tests/lossy_comp_test.c
+ Fix overflow problems when ensuring that signalis not zero.
+
+2006-08-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac docs/*.html
+ Changes for release 1.0.17.
+
+2006-08-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/flac.c
+ Remove inline from functions called by pointer. Thanks to Sampo Savolainen
+ for notifying me of this.
+
+2006-07-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.hh
+ Add writeSync method.
+ Add copy constructor and assignment operator (thanks Daniel Schmitt).
+ Add methods readRaw and writeRaw.
+ Make read/write/readf/writef simple overlaods instead of templates (thanks
+ to Trent Apted for suggesting this).
+
+ * tests/cpp_test.cc
+ Cleanup. Add tests.
+
+2006-07-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.hh
+ Templatize the read/write/readf/writef methods as suggested by Lars Luthman.
+ Prevent the potential leak of SNDFILE* pointers in the openRead/openWrite/
+ openReadWrite methods.
+ Add const to SF_INFO pointer in Sndfile constructor.
+ Make the destrictor call the close() method.
+
+ * tests/cpp_test.cc
+ Add more tests.
+
+2006-07-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/cpp_test.cc
+ Remove the generated file so "make distcheck" passes.
+
+ * src/Makefile.am
+ Add sndfile.hh to distributed header files.
+
+ * src/sndfile.hh
+ Change the license for the C++ wrapper to modified BSD.
+
+2006-07-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.hh
+ Complete it.
+
+ * tests/cpp_test.cc
+ Add more tests.
+
+2006-07-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/utils.tpl
+ Add extern C to generated header file.
+
+ * src/sndfile.hh
+ Work towards completing this.
+
+ * tests/cpp_test.cc tests/Makefile.am
+ Add a C++ test and hook into build.
+
+ * configure.ac
+ Add appropriate CXXFLAGS.
+
+2006-07-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Test if compiler supports -Wpointer-arith.
+
+ * src/common.c
+ Fix a warning resulting from -Wpointer-arith.
+
+2006-07-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Explicitly set endian-ness as well as setting 16 bit output.
+
+ * examples/sndfile-info.c
+ Make sure to parse info if file fails to open.
+
+ * src/sndfile.c
+ Handle parse error a little better.
+
+ * src/wav_w64.[ch]
+ Minor clean up, add detection of IPP ITU G723.1.
+
+2006-06-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Make sure psf->dataoffset gets reset to zero when openning headersless
+ files based on the file name extension.
+
+2006-06-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/(command|lossy_comp|pcm|scale_clip)_test.c tests/fix_this.c
+ tests/write_read_test.(tpl|def)
+ Fix gcc-4.1 compiler warnings about "dereferencing type-punned pointer will
+ break strict-aliasing rules".
+
+ * examples/cooledit-fixer.c
+ More fixes like above.
+
+2006-06-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Fix a windows bug where the syserr string of SF_PRIVATE was not being set
+ correctly.
+
+ * src/sndfile.c
+ Fixed a logic bug in sf_seek(). Thanks to Paul Davis for finding this.
+
+2006-06-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Fixed detection of S_IRGRP.
+
+2006-05-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * sndfile-convert.c
+ Add conversion SF_INSTRUMENT data when present.
+
+2006-05-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/development.html
+ Removed references to tla on windows.
+
+ * src/common.h src/sndfile.c
+ Add separate void pointers for file containter and file codec data to
+ SF_PRIVATE struct. Still need to move all existing fdata pointers.
+
+ * tests/write_read_test.tpl
+ Change the order of some tests.
+
+ * src/aiff.c
+ When writing 'AIFC' files, make sure get an 'FVER' gets added.
+
+ * src/common.h src/(dwvw|flac|g72x|gsm610|ima_adpcm|ms_adpcm|paf|sds).c
+ src/(sndfile|voc|vox_adpcm|xi).c
+ Remove fdata field from SF_PRIVATE struct and replace it with codec_data.
+
+2006-05-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/testprog.c Win32/Makefile.am
+ Add a minimal win32 test program.
+
+ * Win32/README-precompiled-dll.txt Mingw-make-dist.sh
+ Update readme and Mingw build script.
+
+2006-05-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac acinclude.m4
+ Minor fixes for Solaris.
+
+2006-05-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/test_endswap.(def|tpl)
+ Fix printf formatting for int64_t on 64 bit machines.
+
+2006-05-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/binhead_check.py
+ New file to check for bad parameters passed to psf_binheader_writef().
+
+ * src/Makefile.am
+ Hook into test suite.
+
+ * src/voc.c src/caf.c src/wav.c src/mat5.c src/mat4.c
+ Fix bugs found by new test program.
+
+ * src/double64.c
+ Clean up double64_get_capability().
+
+2006-05-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_w64.c
+ Fix a bug on x86_64 where an int was being passed via stdargs and being
+ read using size_t which is 64 bits. Thenks to John ffitch for giving me a
+ login on his box.
+
+2006-05-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/caf.c src/double64.c examples/sndfile-info.c tests/virtual_io_test.c
+ tests/utils.tpl
+ Fix a couple of signed/unsigned problems.
+
+2006-05-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/command_test.c
+ Add channel map tests.
+
+ * src/common.h src/sndfile.c
+ Add a pointer the the SF_PRIVATE struct and make sure it gets freed in
+ sf_close().
+
+2006-04-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac doc/(command|index|api).html NEWS README
+ Updates for 1.0.16 release.
+
+ * src/sndfile.h.in
+ Define enums for channel mapping.
+
+ * examples/sndfile-info.c
+ Clean up usage of SF_INFO struct.
+
+2006-04-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/util.tpl
+ Add function testing function exit_if_true().
+
+ * tests/floating_point_test.tpl
+ Fix a problem where the test program was not exiting when the test failed.
+
+2006-04-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/sndfile.c src/common.h src/command.c
+ Implement new commands SFC_GET_SIGNAL_MAX and SFC_GET_MAX_ALL_CHANNELS.
+
+ * doc/commands.html
+ Document new commands. Other minor updates.
+
+ * tests/peak_chunk_test.c
+ Update tests for new commands.
+
+2006-04-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/peak_chunk_test.c
+ Add test for RIFX and WAVEX files.
+ Try and confuse the PEAK chunk writing by enabling and disabling it.
+
+ * src/sndfile.c
+ Fix a bug where enabling and disabling PEAK chunk was screwing up.
+
+2006-03-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in
+ Add the block of 190 reserved bytes into this struct to allow for
+ future expansion.
+
+ * src/wav.c src/sndfile.c src/broadcast.c
+ Significant cleanup of broadcast wave stuff.
+
+ * examples/sndfile-info.c
+ Fix print message.
+
+ * tests/command_test.c tests/Makefile.am
+ Complete bext tests, hook test in test suite.
+
+2006-03-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in
+ Make coding_history field of SF_BROADCAST_INFO struct a char array instead
+ of a char pointer.
+
+ * src/sndfile.c src/common.h src/wav.c
+ Clean up knock on effects of above chnage.
+
+ * examples/sndfile-info.c
+ Add -b command line option to usage message.
+ Clean up output of broadcast wave info.
+
+ * src/wav.c
+ Ignore and skip the 'levl' chunk.
+
+2006-03-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Fix handling of --enable and --disable configure args. Thanks to Diego
+ 'Flameeyes' Pettenò who sent the patch.
+
+2006-03-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/win32.html
+ Make it really clear that although the MSVC++ cannot compile libsndfile,
+ the precompiled DLL can be used in C++ programs compiled with MSVC++.
+
+2006-03-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Fix bug in writing of INST chunk in AIFF files.
+ Fix potential bug in writing MARK chunks.
+
+ * src/sndfile.c
+ Make sure the instrument chunk can only be written at the start of the file.
+
+ * tests/command_test.c
+ Add check of log buffer.
+
+ * tests/utils.tpl
+ Add usage of space character to psf_binheader_writef.
+
+2006-03-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/Makefile.am tests/Makefile.am
+ Remove --source-time argument from autogen command lines.
+
+ * src/broadcast.c
+ New file for EBU Broadcast chunk in WAV files.
+
+ * src/sndfile.c src/sndfile.h.in src/wav.c src/common.h
+ Add patch from Paul Davis implementing read/write of the BEXT chunk.
+
+2006-03-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/README-precompiled-dll.txt
+ New file descibing how to use the precompiled DLL.
+
+ * Win32/Makefile.am
+ Add Win32/README-precompiled-dll.txt to EXTRA_DIST files.
+
+ * configure.ac
+ Bump version to 1.0.15.
+
+2006-03-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ On read, only add the endian flag if the file is big endian.
+
+ * src/ms_adpcm.c
+ Fixed writing of APDCM coeffs in RIFX files.
+
+ * tests/write_read_test.tpl tests/lossy_comp_test.c
+ Add tests for RIFX files.
+
+2006-03-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Mingw-make-dist.sh
+ Bunch of improvements.
+
+ * doc/win32.html
+ Update MinGW program versions.
+
+2006-03-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/create_symbols_file.py
+ Fix the library name in created win32 DEF file. Add correct DLL name for
+ Cygwin DLL.
+
+ * Win32/Makefile.am tests/Makefile.am
+ Remove redundant files, add win32_ordinal_test to test suite.
+
+ * tests/win32_ordinal_test.c
+ Update to do test in cygsndfile-1.dll as well.
+
+ * doc/win32.html
+ Fix typo, mention that -mno-cygwin with the Cygwin compiler does not work.
+
+ * src/wav.c src/wav_w64.c src/sndfile.c src/sndfile.h.in
+ Apply large patch from Jesse Chappell which adds support for RIFX files.
+
+2006-03-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Makefile.am
+ Add Mingw-make-dist.sh to the extra dist files.
+
+ * configure.ac
+ Fix setting SHLIB_VERSION_ARG for MinGW.
+
+ * tests/win32_ordinal_test.c
+ New test program to test that the win32 DLL ordinals agree with the DEF
+ file.
+
+2006-03-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Add a static inline function to convert an int to a size_t. This will be
+ a compile to nothing on 32 bit CPUs and a sign extension on 64 bit CPUs.
+
+ * src/aiff.c src/avr.c src/common.c src/xi.c src/gsm610.c
+ Fix an ia64 problem where a varargs function was being passed an int in
+ some places and a size_t in other places.
+
+ * src/sd2.c
+ Add a workaround for situations where OSX seems to add an extra 0x52 bytes
+ to the start of the resource fork.
+
+2006-02-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Mingw-make-dist.sh
+ Add a shell script to build the windows binary/source ZIP file.
+
+ * doc/index.html
+ Add download link for windows binary/source ZIP file. Add links for GPG
+ signatures.
+
+ * doc/win32.html
+ Remove info about building using microsoft compiler.
+
+ * configure.ac
+ Bump version to 1.0.14.
+
+2006-02-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sd2.c
+ Improve logging of errors in resource fork parser.
+
+2006-01-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/Makefile.msvc
+ Replace au_g72x.* with g72x.*. Thanks to ussell Borogove.
+
+2006-01-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Make sure return values are initialised header buffer is full.
+
+ * src/wav.c
+ Add workarounds for messed up WAV files.
+
+2006-01-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/config.h
+ Undef HAVE_INTTYPES_H for win32.
+
+ * tests/command_test.c
+ Don't exit on error in instrument test for XI files.
+
+ * configure.ac
+ Bump version to 1.0.13.
+
+ * doc/*.html NEWS README
+ Update version numbers.
+
+2006-01-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/xi.c
+ Start work on add read/write of instrument chunks.
+
+ * src/command_test.c
+ Add tests for XI instrument chunk.
+
+ * tests/largefile_test.c tests/Makefile.am
+ Add new test and hook it into the build system. This test will not be run
+ automatically because it requires 3 Gig of disk space and takes 3 minutes
+ to run.
+
+2006-01-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Fix calculation of samples remaining in win32 code. Thanks Axel Roebel.
+
+ * src/common.h
+ Make sure length of header buffer can hold header plus strings. Thanks Axel
+ Roebel.
+
+2006-01-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/aiff.c src/wav.c
+ Apply a patch from John Fitch (Csound project).
+ Add detune field to SF_INSTRUMENT struct.
+ Add reading/writing instrument chunks to WAV files.
+
+ * tests/command_test.c
+ Update SF_INSTRUMENT tests.
+
+ * tests/Makefile.am
+ Hook instrument tests into test suite.
+
+2006-01-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Check for <inttypes.h> because some broken systems (like Solaris) don't have
+ <stdint.h> which is the 1999 ISO C standard file containing int64_t.
+
+ * src/sfendian.h src/common.h
+ Use <inttypes.h> if <stdint.h> is not available.
+
+2005-12-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/peak_chunk_test.c
+ Extend and clean up tests.
+
+ * src/sndfile.c
+ Fix a bug that prevented the turning off of PEAK chunks.
+
+2005-12-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/error_test.c
+ Make the test distclean correct.
+
+ * src/file_io.c
+ Fix an SD2 MacOSX bug (reported by vince schwarzinger).
+
+2005-12-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c tests/command_test.c
+ Apply a big patch from John ffitch (Csound project) to add reading and
+ writing of instrument chunks to AIFF files. Also update the test.
+
+2005-12-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/aiff_rw_test.c tests/virtual_io_test.c tests/utils.tpl
+ Move test function dump_data_to_file() to utils.tpl.
+
+ * tests/error_test.c tests/Makefile.am
+ Updates, including a new test to test that sf_error() returns a valid error
+ number.
+
+2005-12-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/list_formats.c
+ Make sure the SF_INFO struct is memset to all zero before being used.
+ Thanks to Stephen F. Booth.
+
+ * src/sndfile.c
+ Make the return value of sf_error() match the API documentation.
+
+2005-11-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-convert.c
+ Allow conversion to raw gsm610.
+
+ * src/common.h src/sndfile.c src/au.c
+ Remove au_nh_open() and all references to it (wasn't working anyway).
+
+ * tests/headerless_test.c
+ Add new test for file extension based detection.
+
+ * src/sndfile.c
+ Rejig file extension based file type detection.
+
+2005-11-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Add "gsm" as a recognised file extension when no magic number can be found.
+
+ * tests/lossy_comp_test.c tests/Makefile.am
+ Test headerless GSM610.
+
+2005-11-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/api.html
+ Fix a minor typo and a minor error. Thanks Christoph Kobe and John Pavel.
+
+2005-10-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_w64.c
+ Add more reporting of 'fmt ' chunk for G721 encoded files.
+
+ * src/wav.c
+ Gernerate a more correct 20 byte 'fmt ' chunk rather than a 16 byte one.
+
+2005-10-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/G72x/g72x.[ch]
+ Minor cleanup of interface.
+
+2005-10-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/ogg.c
+ Removed the horribly broken and non-functional OGG implementation when
+ --enable-experimental was enabled. When OGG does finally work it will be
+ merged.
+
+ * src/caf.c
+ Fix a memory leak.
+
+2005-10-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/g72x.c src/G72x/*.(c|h) src/common.h src/sndfile.c src/wav.c src/au.c
+ Add support for G721 encoded WAV files.
+
+ * doc/index.html
+ Update support matrix.
+
+ * tests/lossy_comp_test.c
+ For file formats that support it, add string data after the audio data and
+ make sure it isn't treated as audio data on read.
+
+ * src/gsm610.c
+ Add code to ensure that the container close function (ie for WAV files) gets
+ called after the codec's close function. This allows GSM610 encoded WAV files
+ to have string data following the audio data.
+ Add an AIFF specific check on psf->datalength.
+
+ * src/wav.c
+ Simplify wav_close function.
+
+ * src/aiff.c
+ Make sure the tailer data gets written at an even file offset. Pad if
+ necessary.
+
+ * src/common.h
+ Replace the close function pointer in SF_PRIVATE with separate functions
+ codec_close and container_close. The former is always called first.
+
+ * src/*.c
+ Fix knock on effects of above.
+
+2005-10-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-info.c
+ Complete dumping SF_INSTRUMENT data.
+
+ * src/dwvw.c src/ima_adpcm.c src/gsm610.c src/ms_adpcm.c
+ Add extra checks in *_init function.
+
+ * tests/lossy_comp_test.c
+ Add a string comment to the end of the files to make sure that the decoder
+ doesn't decode beyond the end of the audio data section.
+
+2005-10-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-info.c
+ Minor code cleanup.
+ Start work on dumping SF_INSTRUMENT data.
+
+2005-10-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/common.h src/common.c
+ Update definition of SF_INSTRUMENT struct and create a function to allocate
+ and initialize the struct (input from David Viens).
+ Clean up definition of SF_INSTRUMENT struct.
+
+ * src/wav.c src/wav_w64.c
+ Add support for Ambisoncs B WAVEX files (David Viens).
+
+ * src/aiff.c src/wav.c src/wav_w64.c
+ Start work on reading/writing the SF_INSTRUMENT data.
+
+ * src/sndfile.c
+ Add code to get and set SF_INSTRUMENT data.
+
+ * tests/command_test.* tests/Makefile.am
+ Add test for set and getof SF_INSTRUMENT data.
+ The file command_test.c is no longer autogen generated.
+
+2005-10-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/gsm610.c
+ Minor cleanup.
+
+2005-10-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/lossy_comp_test.c
+ Minor cleanup.
+
+2005-10-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c
+ Ensure sfconfig.h is included before any other header file.
+
+ * src/file_io.c
+ Add comments documenting the three sections of the file.
+
+ * src/gsm610.c
+ Make sure SF_FORMAT_WAVEX are handled correctly.
+
+2005-10-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Add options to allow disabling of FLAC and ALSA. Suggested by Ben Greear.
+
+2005-09-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/locale_test.c
+ Modify the way the unicode strings were encoded so that older compilers
+ do not complain. Thanks Axel Roebel.
+
+ * configure.ac
+ Bump the version to 1.0.12 for release.
+
+ * NEWS README Win32/config.h doc/(FAQ|index.html|command|api).html
+ Update version numbers.
+
+2005-09-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/flac.c
+ Fix valgrind error and minor cleanup.
+
+2005-09-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/(au|paf|aiff|w64|wav|svx).c
+ Make sure structs are initialised.
+
+2005-09-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Make -Wdeclaration-after-statement work with --enable-gcc-werror configure
+ option.
+ Add -std=gnu99 (C99 plus posix style stuff like gmtime_r) to CFLAGS if the
+ compiler supports it.
+
+2005-09-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac acinclude.m4
+ Add -Wdeclaration-after-statement to CFLAGS if the compilers supports it.
+
+2005-09-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/util.(tpl|def)
+ Make the test_write_*_or_die() functions const safe.
+
+2005-09-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/nist.c
+ Make sure the data offset is read from the file header. Thanks to
+ David A. van Leeuwen for a patch.
+
+2005-09-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac src/sfconfig.h
+ Check for <locale.h> and the function setlocale().
+ Set config variables to zero if not found.
+
+ * tests/locale_test.c tests/Makefile.am
+ Add new test program and hook into build/test system.
+
+2005-09-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h src/file_io.c
+ On windows, use windows specific types for file handles.
+ Add functions psf_init_files() and psf_use_rsrc().
+
+ * src/sd2.c
+ Make resource fork handling independant of file desciptor/handles.
+
+ * src/sndfile.c src/test_file_io.c
+ Fix knock on effects.
+
+2005-09-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/float_cast.h
+ The lrint and lrintf implementations in Cygwin are both buggy and slow.
+ Add replacements which were pulled from the Public Domain MinGW math.h
+ header file.
+
+2005-09-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/(lossy_comp_test|virtual_io_test).c
+ More Valgrind fixups.
+
+ * configure.ac
+ Simplify and correct configuring for Cygwin.
+
+ * Win32/config.h Win32/sndfile.h Win32/Makefile.msvc
+ Update build for MSVC.
+
+2005-09-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/lossy_comp_test.c
+ Make sure to close SNDFILE when exiting test when file format is not seekable.
+
+ * tests/(aiff_rw_test|virtual_io_test).c
+ Do a few valgrind fix ups.
+
+2005-09-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/float32.c src/double64.c
+ Replace floating point equality comparisons with greater/less comparisons.
+ Found by John Pavel using the Intel compiler.
+
+ * src/sfconfig.h
+ New file to clean up issues surrounding autoconf generated preprocessor
+ symbols.
+
+ * src/*.(c|h) tests/*.(c|tpl) examples/*.c
+ Fixed a bunch of other stuff found by John Pavel using the Intel compiler.
+
+ * src/file_io.c
+ Remove Mac OS9 Metrowerks compiler specific hacks.
+
+2005-08-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/w64.c
+ Cast integer literal to sf_count_t in call to psf_binheader_writef() to
+ prevent Valgrind error.
+
+2005-08-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/command.html
+ Improve documentation of SF_GET_FORMAT_SUBTYPE.
+
+2005-08-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-convert.c
+ Allow files to be converted to SD2 format.
+
+ * src/sd2.c
+ Fix a bug in reading and writing of SD2 files on little endian CPUs.
+ Thanks to Matthew Willis for finding this.
+
+2005-08-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/api.html
+ Update Note2 to point to SFC_SET_SCALE_FLOAT_INT_READ.
+
+2005-08-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Use $host_os instead of $target_os (thanks to Mo De Jong).
+
+2005-08-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/Makefile.am
+ Apply a patch from Mo DeJong to allow building outside of the source dir.
+
+ * src/file_io.c
+ Fix psf_fsync() for win32.
+
+ * src/wav.c src/wav_w64.(c|h)
+ Move some code from wav.c to wav_w64.c to improve the log output of files of
+ type WAVE_FORMAT_EXTENSIBLE.
+
+2005-08-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/create_symbols_file.py
+ Make sure sf_write_fsync is an exported symbol.
+
+ * examples/sndfile-convert.c
+ Add support for writing VOX adpcm files.
+
+2005-07-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/api.html
+ Document the new function sf_write_sync().
+
+ * doc/FAQ.html
+ Do you plan to support XYZ codec.
+
+2005-07-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/sndfile.c
+ Add function sf_write_sync() to the API.
+
+ * src/common.h src/file_io.c
+ Low level implementation (win32 not done yet).
+
+ * tests/write_read_test.tpl
+ Use the new function in the tests.
+
+2005-07-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h src/double64.c src/float32.c src/sndfile.c
+ Change the way PEAK chunk info is stored. Peaks now stored as an sf_count_t
+ for position and a double as the value.
+
+ * src/aiff.c src/caf.c src/wav.c
+ Fix knock on effects of above changes.
+
+ * src/caf.c
+ Implement 'peak' chunk for file wuth data in SF_FORMAT_FLOAT or
+ SF_FORMAT_DOUBLE format.
+
+2005-07-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/nist.c
+ Fix a bug where a variable was being used without being initialized.
+
+ * src/flac.c
+ Add extra debug in sf_flac_meta_callback.
+ Make a bunch of private functions static.
+
+ * src/aiff.c src/wav.c
+ Fix allocation for PEAK_CHUNK (bug found using valgrind).
+
+2005-07-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Move the peak_loc field of SF_PRIVATE to the PEAK_CHUNK struct.
+ Remove had_peak field of SF_PRIVATE, use pchunk != NULL instead.
+ Rename PEAK_CHUNK and PEAK_POS to PEAK_CHUNK_32 and PEAK_POS_32.
+
+ * src/aiff.c src/caf.c src/wav.c src/float32.c src/double64.c
+ Fix knock on effects from above.
+
+2005-07-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Prevent files with unknown chunks from being opened read/write.
+
+2005-07-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/flac.c
+ Do not use psf->end_of_file because it never gets set to anything.
+
+ * src/common.h
+ Remove unused SF_PRIVATE field end_of_file.
+
+2005-07-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Change the 'S' format specifier of psf_binheader_writef() to write AIFF
+ style strings (no terminating character).
+
+ * src/aiff.c
+ Move to new (correct) AIFF string style. Thanks to Axel Roebel for being
+ so persistent on this issue.
+
+2005-07-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Allow SFE_UNSUPPORTED_FORMAT as an error from sf_open().
+
+ * doc/api.html doc/command.html
+ Documentation updates (thanks to Kyroz for promoting these updates).
+
+ * src/mat5.c
+ Modify the way the header is written.
+
+2005-07-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/caf.c
+ Add a 'free' chunk to the written file so that the audio data starts at
+ an offset of 0x1000.
+
+ * src/sndfile.c
+ Allow SFE_UNSUPPORTED_FORMAT as an error from sf_open().
+
+2005-07-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/caf.c src/sndfile.c
+ Add support for signed 8 bit integers.
+
+ * tests/write_read_test.tpl
+ Add test for signed 8 bit integers in CAF files.
+
+ * doc/index.html
+ Update matrix for signed 8 bit integers in CAF files.
+
+2005-07-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Update sf_check_format() to support CAF.
+
+ * examples/sndfile-convert.c
+ Add support for ".caf" file extension.
+
+ * doc/index.html
+ Add Apple CAF to the support matrix.
+
+ * src/caf.c
+ Add file write support.
+
+ * src/common.c
+ Fix printing of Frames.
+
+ * tests/Makefile.am tests/write_read_test.tpl tests/lossy_comp_test.c
+ tests/header_test.tpl misc_test.c
+ Add tests for CAF files.
+
+2005-07-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ Fix Q/A about reading/writing memory buffers.
+
+ * src/caf.c
+ Bunch of work to support reading of CAF files.
+
+2005-07-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/(aiff|ima_adpcm|mat4|mat5|ms_adpcm).c examples/sndfile-play.c
+ Fix sign conversion errors reported by gcc-4.0.
+
+ * src/caf.c
+ New file for Apple's Core Audio File format.
+
+ * src/sndfile.c src/common.h src/sndfile.h.in src/Makefile.am
+ Hook new file into build system.
+
+2005-06-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src_wav_w64.c
+ Fix handling of stupidly large 'fmt ' chunks. Thanks to Vadim Berezniker
+ for supplying an example file.
+
+ * src/common.h src/sndfile.c
+ Remove redundant error code SFE_WAV_FMT_TOO_BIG.
+
+2005-06-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/common.h src/sndfile.c
+ Add public error value SF_ERR_MALFORMED_FILE.
+
+ * src/sndfile.c
+ When parsing a file header fails and we don't have a system error, then set
+ the error number to SF_ERR_MALFORMED_FILE (suggested by Kyroz).
+
+ * configure.ac
+ Allow sqlite support to be disabled in configure script.
+
+ * regtest/database.c regtest/sndfile-regtest.c
+ Fix compiling when sqlite is missing.
+
+2005-06-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Fix psf_is_pipe() and return value of psf_fread() when using virtual i/o.
+
+ * src/sndfile.c
+ Fix VALIDATE_AND_ASSIGN_PSF macro for virtual i/o.
+
+ * tests/virtual_io_test.c
+ Fill in skeleton test program.
+
+ * tests/Makefile.am
+ Move virtual i/o tests to end of tests with stdio/pipe tests.
+
+ * src/(sndfile.h.in|file_io.c|common.h|sndfile.c) tests/virtual_io_test.c
+ Rename some of the virtual i/o functions and data types.
+
+2005-06-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fix the return values of sf_commands : SFC_SET_NORM_DOUBLE,
+ SFC_SET_NORM_FLOAT, SFC_GET_LIB_VERSION and SFC_GET_LOG_INFO. Thanks to
+ Kyroz for pointing out these errors.
+
+ * doc/command.html
+ Correct documented return values for SFC_SET_NORM_DOUBLE and
+ SFC_SET_NORM_FLOAT. Thanks to Kyroz again.
+
+2005-05-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * regtest/*
+ Add new files for sndfile-regtest program.
+
+ * configure.ac Makefile.am
+ Hook regetest into build.
+
+ * src/wav.c src/common.c
+ Fix a regression where long ICMT chunks were causing the WAV parser
+ to exit.
+
+2005-05-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * libsndfile.spec.in
+ Add html docs to the files section as suggested by Karsten Jeppesen.
+
+ * src/aiff.c
+ Fix parsing of odd length ANNO chunks.
+
+2005-05-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Change the include guard to prevent clashes with other code.
+
+2005-05-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Improve error handling in code for playback under Linux/ALSA.
+
+2005-05-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/ircam.c
+ Fix writing of IRCAM files on big endian systems (thanks to Axel Roebel).
+
+ * src/wav.c
+ Add workaround for files created by the Peak audio editor on Mac which can
+ produce files with very short LIST chunks (thanks to Jonathan Segel who
+ supplied the file).
+
+2005-04-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Apply a patch From David Viens to make the parsing of basc chunks more
+ robust.
+
+ * src/wav.c
+ Another patch from David Viens to write correct wavex channel masks for
+ the most common channel configurations.
+
+2005-04-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/command.c
+ Only allow FLAC in the format arrays if FLAC is enabled. Thanks to
+ Leigh Smith.
+
+2005-03-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Add a directory field for storing the file directory to the SF_PRIVATE
+ struct.
+
+ * src/sndfile.c
+ Grab the directory name when copying the file path.
+
+ * src/file_io.c
+ Cleanup psf_open_rsrc() and also check for resource fork in
+ .AppleDouble/filename.
+
+2005-03-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/svx.c
+ Fix a bug in the printing of the channel count. Bug reported by Michael
+ Schwendt. Thanks.
+
+2005-01-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/paf.c
+ Fix a seek bug for 24 bit PAF files.
+
+ * tests/write_read_test.tpl
+ Update write_read_test to trigger the previously hidden PAF seek bug.
+
+2005-01-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c src/w64.c src/wav.c
+ Do not return a header parse error when the log buffer overflows.
+ Continuing parsing works even on files where the log buffer does overflow.
+ This avoids a bug on some weirdo WAV (and other) files.
+
+ * src/common.h src/sndfile.c
+ Remove SFE_LOG_OVERRIN error and its associated error message.
+
+ * src/file_io.c
+ Fix a rsrc fork problem on MacOSX.
+
+2004-12-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile-play.c
+ In the ALSA output code, added call to snd_pcm_drain() just before
+ snd_pcm_close() as suggested by Thomas Kaeding.
+ In the OSS output code, added two ioctls (SNDCTL_DSP_POST and
+ SNDCTL_DSP_SYNC) just before the close of the audio device.
+
+ * tests/virtual_io_test.c tests/Makefile.am
+ Add a new test program (currently empty) and add it to the build.
+
+2004-12-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/sndfile.h src/common.h src/file_io.c
+ src/create_symbols_file.py
+ Apply patch from Steve Baker which is the beginnings of a virtual
+ I/O interface.
+
+2004-12-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c src/sndfile.h.in
+ Const-ify the write path throughout the library.
+
+2004-12-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/development.html
+ Minor improvements.
+
+2004-11-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/bugs.html
+ Minor improvements.
+
+2004-11-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Add workaround for Logic Platinum AIFF files with broken COMT chunks.
+
+2004-11-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ Remove some ambiguities in the SD2 FAQ answer.
+
+2004-11-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/sndfile.h Win32/config.h MacOS9/sndfile.h MacOS9/config.h
+ Updates from autoconfig versions.
+
+2004-11-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Fix parsing of COMT chunks. Store SF_STR_COMMENT data in ANNO chunks
+ instead of COMT chunk.
+
+2004-11-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c src/common.h
+ Change the ptr argument to psf_write() from "void*" to a "const void*".
+ Thanks to Tobias Gehrig for suggesting this.
+
+2004-10-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c src/common.h
+ Add functions psf_close_rsrc() and read length of resourse fork into
+ rsrclength field of SF_PRIVATE.
+
+ * src/sd2.c
+ Make sure resource fork gets closed.
+
+ * tests/util.tpl
+ Add functions to check for file descriptor leakage.
+
+ * src/write_read_test.tpl
+ Use the file descriptor leak checks.
+
+ * src/sndfile.h.in
+ Add SFC_GET_LOOP_INFO and SF_LOOP_INFO struct.
+
+ * src/common.h
+ Add SF_LOOP_INFO pointer to SF_PRIVATE.
+
+ * src/wav.c src/aiff.c
+ Improve and add parsing of 'ACID' and 'basc' chunks, filling in
+ SF_LOOP_INFO data in SF_PRIVATE.
+
+2004-10-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sd2.c
+ Further cleanup: remove printfs, change snprintf to LSF_SNPRINTF.
+
+ * Win32/config.h Win32/sndfile.h
+ Updates.
+
+ * tests/util.tpl
+ Add win32 macro for snprintf.
+
+2004-10-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sfendian.h
+ Add macros : H2BE_SHORT, H2BE_INT, H2LE_SHORT and H2LE_INT.
+
+ * src/sd2.c
+ Use macros to make sure writing SD2 files on little endian machines works
+ correctly.
+
+ * tests/util.tpl
+ Add a delete_file() function which also deletes the resource fork of SD2
+ files.
+
+ * tests/write_read_test.tpl
+ Use delete_file() so that "make distcheck" works.
+
+2004-10-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/file_io.c
+ Move resource filename construction and testing to psf_open_rsrc().
+
+ * src/common.h src/sndfile.c
+ Add error SFE_SD2_FD_DISALLOWED.
+
+ * tests/util.tpl tests/*.(c|tpl)
+ Add and allow_fd parameter to test_open_file_or_die() so that use of
+ sf_open_fd() can be avoided when opening SD2 files.
+
+2004-10-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Update ACID chunk parsing.
+
+ * src/sd2.c
+ More fixes for files with large resource forks.
+
+2004-10-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h src/sndfile.c
+ Add error numbers and messages for sd2 files.
+
+ * src/sd2.c
+ Reading of sd2 (resource fork version) now seems to be working.
+
+2004-10-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.h
+ Update file_io.c to include win32 psf_rsrc_open().
+
+ * tests/floating_point_test.tpl
+ Remove use of __func__ in test programs (MSVC++ doesn't grok this).
+
+ * Win32/(config|sndfile).h MacOS9/(config|sndfile).h
+ Updates.
+
+2004-10-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sfendian.h
+ Fix endswap_int64_t_(array|copy).
+
+ * src/test_endswap.(tpl|def)
+ Add tests for above and inprove all tests.
+
+2004-10-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sfendian.h
+ Improve type safety, add endswap_double_array().
+
+ * src/double64.c
+ Use endswap_double_array() instead of endswap_long_array().
+
+ * src/test_endswap.(tpl|def) src/Makefile.am
+ Add preliminary endswap tests and hook into build system.
+
+2004-10-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/configure.ac src/makefile.am
+ Finally fix the bulding of DLLs on Win32/MinGW.
+
+ * tests/makefile.am
+ Fix running of tests on Win32/MinGW.
+
+2004-10-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/sndfile.c tests/floating_point_test.tpl
+ Rename SFC_SET_FLOAT_INT_MULTIPLIER to SFC_SET_SCALE_FLOAT_INT_READ.
+
+ * doc/command.html
+ Document SFC_SET_SCALE_FLOAT_INT_READ.
+
+2004-09-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/floating_point_test.(tpl|def)
+ Derived from floating_point_test.c.
+ Add (float|double)_(short|int)_test functions.
+
+ * tests/util.(tpl|def)
+ Make separate float and double versions of gen_windowed_sine().
+
+ * tests/write_read_test.tpl
+ Fix after changes to gen_windowed_sine().
+
+ * src/(float32|double64).c
+ Implement SFC_SET_FLOAT_INT_MULTIPPLIER.
+
+2004-09-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * acinclude.m4
+ Fix warnings from automake 1.8 and later.
+
+ * examples/sndfile-info.c
+ Add a "fflush (stdout)" after printing Win32 message.
+
+2004-09-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/Makefile.mingw.in
+ Add a "make install" target.
+
+2004-09-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/common.h src/sndfile.c src/command.c
+ Start work on adding command SFC_SET_FLOAT_INT_MULTIPLIER.
+
+2004-09-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-convert.c
+ Fix a bug converting stereo integer PCM files to float.
+
+2004-09-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Appy patch from Conrad Parker to make Mac OSX error messages more
+ consistent and informative.
+
+ * doc/api.html
+ Fix a HTML HREF which was wrong.
+
+ * doc/win32.html
+ Add information about when nmake fails.
+
+2004-09-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Another patch from Denis Cote to prevent race conditions.
+
+2004-09-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h src/ms_adpcm.c src/ima_adpcm.c
+ Fix alternative to ISO standard flexible struct array feature for broken
+ compilers.
+
+2004-08-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h src/string.c src/sndfile.c
+ Make sf_set_string() return an error if trying to set a string when in
+ read mode.
+
+2004-08-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Change the unnamed union into a named union so gcc-2.95 will compile it.
+
+ * src/*.c
+ Fixes to allow for the above change.
+
+2004-08-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Fixes for Win32. Thanks to Denis Cote.
+
+ * Win32/Win32/Makefile.(msvc|mingw.in)
+ Fix build system after removal of sfendian.h.
+ Build sndfile-convert.
+
+ * src/Makefile.am
+ Remove sfendian.c from dependancies.
+
+2004-08-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in
+ Fix typo in comments (thanks Tommi Sakari Uimonen).
+
+2004-07-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/(a|u)law_test.c
+ Minor cleanup.
+
+2004-07-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/(pcm|float|double64|ulaw|alaw|xi).c
+ Optimise read/write loops by removing a redundant variable.
+
+2004-07-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Remove call to fsync() in psf_close().
+
+2004-07-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pcm.c
+ Inline x2y_array() functions where possible.
+
+ * configure.ac
+ Detect presence of type int64_t.
+
+ * src/sfendian.c src/sfendian.h
+ Move functions in the first file to the sfendian.h as static inline
+ functions.
+ Improve endswap_long_*() where possible.
+
+2004-07-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pcm.c
+ When converting from unsigned char to float or double, subtract 128 before
+ converting to float/double rather than after to save a floating point
+ operation as suggested by Stefan Briesenick.
+
+ * src/(pcm|sfendian|alaw|ulaw|double64|float32).c
+ Optimize inner loops by changing the loop counting slightly as suggested
+ by Stefan Briesenick.
+
+ * configure.ac
+ Detect presence of <byteswap.h>.
+
+ * src/sfendian.h
+ Use <byteswap.h> if present as suggested by Stefan Briesenick.
+
+ * src/pcm.c
+ Update bytewapping.
+
+2004-07-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h src/*.c
+ Change the psf->buffer field of SF_PRIVATE into a more type safe union with
+ double, float, int etc elements.
+
+2004-06-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Merge slightly modifed patch from Stanko Juzbasic which allows playback of
+ mono files on MacOSX.
+
+2004-06-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-convert.c
+ Move copy_metadata() after the second sf_open().
+
+2004-06-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-convert.c
+ Fix a bug which caused the program to go into an infinite loop if the source
+ file has no meta-data. Thanks to Ron Parker for reporting this.
+
+ * src/sndfile.h.in
+ Add SF_STR_FIRST and SF_STR_LAST to allow enumeration of string types.
+
+ * Win32/sndfile.h MacOS9/sndfile.h
+ Update these as per the above file.
+
+2004-06-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac src/common.h src/ogg.c src/sndfile.c src/sndfile.h.in
+ src/Makefile.am
+ Apply large patch from Conrad Parker implementing Ogg Vorbis, Ogg Speex and
+ Annodex support via liboggz and libfishsound. Thanks Conrad.
+
+2004-06-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/avr.c src/ircam.c src/nist.c src/paf.c src/xi.c
+ Add cast to size_t for some parameters passed to psf_binheader_writef. This
+ is Debian bug number 253490. Thanks to Anand Kumria and Andreas Jochens.
+
+ * src/w64.c
+ Found and fixed a bug resulting from use of size_t when writing W64 'fmt '
+ chunk.
+
+2004-06-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Bump version to 1.0.10 ready for release.
+
+ * Makefile.am
+ Remove redundant files (check_libsndfile.py libsndfile_version_convert.py)
+ from distribution tarball.
+
+ * tests/header_test.tpl
+ Fix uninitialised variable.
+
+ * src/GSM610/short_term.c
+ Fix compiler warning on MSVC++.
+
+2004-05-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Improve record keeping of chunks seen and return an error if a file with
+ unusual chunks is opened in mode SFM_RDWR.
+
+ * src/mmreg.h
+ This file not needed so remove it.
+
+2004-05-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/header_test.tpl
+ Add extra_header_test().
+
+ * src/common.h src/sndfile.c
+ Add SFE_RDWR_BAD_HEADER error number and string.
+
+2004-05-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/utils.tpl tests/*.c tests/*.tpl
+ Add a line number argument to check_log_buffer_or_die() and update all
+ files that use that function.
+
+ * tests/header_test.tpl
+ Modify/update tests for files opened SFM_RDWR and SFC_UPDATE_HEADER_AUTO.
+
+ * src/aiff.c src/wav.c
+ Fix another bug in AIFF and WAV files opened in SFM_RDWR and using
+ SFC_UPDATE_HEADER_AUTO.
+
+ * src/test_file_io.c
+ Add a test for psf_ftruncate() function.
+
+2004-05-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fix another weird corner case bug found by Martin Rumori. Thanks.
+
+ * tests/header_test.(tpl|def)
+ Two new files to test for the absence of the above bug and include tests
+ moved from tests/misc_test.c.
+
+ * tests/Makefile.am
+ Hook new tests into build/test system.
+
+ * tests/misc_test.c
+ Remove update_header_test() which has been moved to the new files above.
+
+2004-05-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Fixed a bug reported by Martin Rumori on the LAD list. If a file created
+ with a format of SF_FORMAT_FLOAT and then closed before any data is written
+ to it, the header can get screwed up (PEAK chunk gets overwritten).
+
+ * tests/write_read_test.tpl
+ Add a test (empty_file_test) for the above bug.
+
+2004-05-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/Makefile.mingw.in
+ Added a Makefile for MinGW (needs to be processed by configure).
+
+ * src/mmsystem.h src/mmreg.h
+ Add files from the Wine project (under the LGPL) to allow build of
+ sndfile-play.exe under MinGW.
+
+2004-05-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/GSM610/gsm610_priv.h
+ Replace ugly macros with inline functions.
+
+ * src/GSM610/*.c
+ Remove temporary variables used by macros and other minor fixes required by
+ above change.
+
+2004-05-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/pipe_test.tpl tests/stdio_test.c Win32/Makefile.msvc
+ Make sure these programs compile (even though they do nothing) on Win32
+ and add them to the "make check" target.
+
+ * src/sfendian.h
+ Fix warning on Sparc CPU and code cleanup.
+
+2004-05-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Fix warning messages when compiling under MinGW.
+
+2004-05-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Set HAVE_FLEXIBLE_ARRAY in src/config.h depending on whether the compiler
+ accepts the flexible array struct member as per 1999 ISO C standard.
+
+ * src/common.h src/ima_adpcm.c src/paf.c src/ms_adpcm.c
+ Added ugly #if HAVE_FLEXIBLE_ARRAY and provided a non-standards compliant
+ hack for non 1999 ISO C compliant compilers.
+
+2004-04-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/strings.c
+ If adding an SF_STR_SOFTWARE string, only append libsndfile-X.Y.Z if the
+ string does not already have libsndfile in the string. Thanks to Conrad
+ Parker.
+
+ * tests/string_test.c
+ Add test to verify the above.
+
+ * examples/sndfile-convert.c
+ Add ability to transcode meta data as well (Conrad Parker).
+
+2004-04-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/command.html
+ Fix minor error. Thanks to Simon Burton.
+
+ * doc/win32.html
+ Started adding instructions for compiling libsndfile under MinGW.
+
+ * configure.ac
+ Add --enable-bow-docs to enable black text on a white background HTML docs.
+
+ * doc/libsndfile.css.in
+ This is now a template file for configure which sets the foreground and
+ background colours.
+
+2004-04-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Do some MinGW fixes.
+
+ * configure.ac doc/Makefile.am
+ Install HTML docs when doing make install.
+
+2004-04-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-info.c
+ Print out the dB level with the signal max.
+
+2004-04-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Define S_ISSOCK in src/file_io.c if required.
+
+2004-04-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Improve printout configuration summary (as suggested by Axel Röbel).
+
+ * doc/index.html
+ Add link to pre-release location.
+
+ * src/sndfile.h.in
+ Remove comma after last element of enum.
+
+ * src/float32.c src/double64.c
+ Fix read/write of float/double encoded raw files to/from pipes.
+
+ * tests/pipe_test.c tests/pipe_test.tpl tests/pipe_test.def
+ Turn pipe_test.c into an autogenerated file and add tests for reading/
+ writing floats and doubles.
+
+ * tests/Makefile.am
+ Hook tests/pipe_test.* into build system.
+
+2004-04-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac acinclude.m4
+ Rename AC_C_STRUCT_HACK macro to AC_C99_FLEXIBLE_ARRAY.
+
+2004-03-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/misc_test.c
+ Perform update_header_test in RDWR mode as well.
+
+ * src/aiff.c
+ Fix problems when updating header in RDWR mode.
+
+2004-03-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c src/w64.c src/wav_w64.c
+ Integrate code supplied by David Viens for supporting microsoft's
+ WAVEFORMATEXTENSIBLE stuff. Thanks David for supplying this.
+
+ * configure.ac doc/*.html
+ Bump version to 1.0.9.
+
+2004-03-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/command.c src/sndfile.c src/sndfile.h.in src/wav.c
+ Started work on supporting microsoft's WAVEFORMATEXTENSIBLE gunk.
+
+2004-03-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/avr.c
+ New file to handle Audio Visual Resaerch files.
+
+ * src/sndfile.h.in src/common.h src/sndfile.c src/command.c
+ Hook AVR into everything else.
+
+ * tests/Makefile.am tests/write_read_test.tpl tests/misc_test.c
+ Add testing for AVR files.
+
+2004-03-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Fix psf_set_file() for win32. Thanks to Vincent Trussart (Plogue Art et
+ Technologie) for coming up with the solution.
+
+2004-03-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.tpl
+ Fixed a bug that was causing valgrind to report a memory leak. The bug was
+ in the test code itself, not the library.
+
+2004-03-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/generate.cs
+ An example showing how to use libsndfile from C#. Thanks to James Robson
+ for providing this.
+
+2004-03-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Fix problems with WAV files containing large chunks after the 'data'
+ chunk. Thanks to Koen Tanghe for providing a sample file.
+
+2004-03-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Detect presense of ALSA (Advanced Linux Sound Architecture).
+
+ * examples/sndfile-play.c
+ Add ALSA output support.
+
+ * examples/Makefile.am
+ Add ALSA_LIBS to link line of sndfile-play.c.
+
+2004-03-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * acinclude.m4
+ Add new macro (AC_C_STRUCT_HACK) to detect whether the C compiler allows
+ the use of the what is known as the struct hack introduced by the 1999 ISO
+ C Standard.
+
+ * configure.ac
+ The last release would not compile with gcc-2.95 due to the use of features
+ (ie struct hack) introduced by the 1999 ISO C Standard.
+ Add check to make sure compiler handles this and bomb out if it doesn't.
+
+2004-03-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.tpl
+ Fix compiler warning on Win32.
+
+ * src/file_io.c
+ Fix use of an un-initialised variable in Win32 stuff.
+
+ * Win32/config.h examples/sndfile-play.c
+ Win32 fixes.
+
+2004-03-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Fix bug which occurres when configuring for MinGW.
+ If compiler is gcc and cross compiling use -nostdinc.
+
+2004-03-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h src/aiff.c src/wav.c src/float32.c src/double64.c
+ src/sndfile.c
+ Fix a bug with PEAK chunk handling for files with more than 16 channels.
+ Thanks to Remy Bruno for finding this.
+
+2004-03-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Fix a bug which was preventing WAV files being openned correctly if the
+ file had a very large header. Thanks to Eldad Zack for finding this.
+
+2004-03-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac src/file_io.c
+ Fix cross-compiling from Linux to Win32 using the MinGW tools.
+
+2004-03-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/create_symbols_file.sh
+ Christian Weisgerber pointed out that the shell script did not run on a
+ real Bourne shell although it did run under Bash in Bourne shell mode.
+
+ * src/create_symbols_file.py
+ Rewrite of above in Python. Also add support for writing Win32 .def files.
+ The Python script generates Symbols.linux, Symbols.darwin and
+ libsndfile.def (Win32 version). These files get shipped with the tarball
+ so there should not be necessary to run the Python script when building
+ the code from the tarball.
+
+ * configure.ac src/Makefile.am Win32/Makefile.am
+ Hook new Python script into the build system.
+
+2004-02-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/configure.ac
+ Add --enable-gcc-werror option and move GCC specific stuff down.
+
+2004-02-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * acinclude.m4 configure.ac
+ Fix clip mode detection (tested in one of HP's testdrive Itanium II boxes).
+
+ * src/file_io.c
+ Added check for sizeof (off_t) != sizeof (sf_count_t) to prevent recurrence
+ of missing large file support on Linux and Solaris.
+
+2004-02-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Fix a MacOSX specific bug which was caused by a space being inserted in
+ the middle of a file name.
+
+ * configure.ac src/Makefile.am examples/Makefile.am
+ Fix a couple of MacOSX build issues.
+
+2004-02-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/command.html
+ Document SFC_SET_CLIPPING and SFC_GET_CLIPPING.
+
+2004-02-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/*.html
+ Applied patch from Frank Neumann (author of lakai) which fixes many minor
+ typos in documentation. Thanks Frank.
+
+2004-02-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * ChangeLog
+ Changed my email address throughout source and docs.
+
+2004-02-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Make sure config.h is included before stdio.h to make sure large file
+ support is enabled on Linux (and Solaris).
+
+ * tests/misc_test.c
+ Disable update_header test on Win32. This should work but doesn't and
+ I'm not sure why.
+
+ * Make.bat Win32/Makefile.msvc
+ Updates.
+
+2004-01-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Changed logindex, headindex and headend files of SF_PRIVATE from unsigned
+ int to int to prevent weird arithmetic bugs.
+
+ * src/common.c src/aiff.c src/wav.c src/w64.c
+ Fixed compiler warnings resulting from above change.
+
+2004-01-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Fixed a bug in header reader for some files with data after the sample data.
+
+2003-12-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/lossy_comp_test.c tests/Makefile.am
+ Add tests for AIFF/IMA files.
+
+2003-12-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/macbinary3.c src/macos.c
+ Two new files required for handling SD2 files.
+
+ * src/common.h
+ Add prototypes for functions in above two files.
+
+ * src/Makefile.am
+ Hook new files into build system.
+
+2003-12-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Add checks for mmap() and getpagesize() which might be used at some time
+ for faster file reads.
+ Add detection of MacOSX.
+
+2003-12-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ Minor mods to pkg-config section.
+
+2003-12-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/create_symbols_file.sh
+ Andre Pang (also known as Ozone) pointed out that on MacOSX, all non
+ static symbols are exported causing troubles when trying to link
+ libsndfile with another library which has any of the same symbols.
+ He fixed this by supplying the MacOSX linker with a file containing
+ all the public symbols so that only they would be exported and then
+ supplied a patch for libsndfile.
+ This wasn't quite ideal, because I would have to maintain two (3 if
+ you include Win32) separate files containing the exported symbols.
+ A better solution was to create this script which can generate a
+ Symbols file for Linux, MacoSX and any other OS that supports
+ minimising the number of exported symbols.
+
+ * configure.ac src/Makefile.am
+ Hook the new script into the build process.
+
+2003-12-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/index.html
+ Added comments about Steve Dekorte's SoundConverter scam.
+
+2003-12-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Axel Roebel pointed out that on Mac OSX a pipe is not considered a fifo
+ (S_ISFIFO (st.st_mode) is false) but a socket (S_ISSOCK (st.st_mode) is
+ true). The test has therefore been changed to is S_ISREG and anything
+ which which does not return true for S_ISREG is considered a pipe.
+
+2003-11-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/misc_test.c
+ Fix update_header_test to pass SDS.
+
+ * src/sds.c
+ More minor fixes.
+
+ * tests/floating_point_test.c
+ Add test for SDS files.
+
+ * src/command.c
+ Add SDS to major_formats array.
+
+2003-11-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.tpl tests/misc_test.c
+ Add tests for SDS files.
+
+ * src/sds.c
+ Fix a bug in header update code.
+
+2003-11-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sds.c
+ Get file write working.
+
+ * src/paf.c
+ Fix a potential bug in paf24_seek().
+
+2003-11-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ Add Q/A about u-law encoded WAV files.
+
+ * Win32/*.h
+ Updated so it compiles on Win32.
+
+2003-11-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-convert.c
+ Add -alaw and -ulaw command line arguments.
+
+ * configure.ac
+ Add library versioning comments.
+ Add arguments to AC_INIT.
+
+2003-10-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Ross Bencina has contributed code to replace all of the (mostly broken)
+ Win32 POSIX emulation calls with calls the native Win32 file I/O API.
+ This code still needs testing but is likely to be a huge improvemnt
+ of support for Win32. Thanks Ross.
+
+2003-10-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/dwvw.c
+ Removed filedes field from the DWVW_PRIVATE struct.
+
+ * src/file_io.c
+ Change psf_fopen() so it returns psf->error instead of the file descriptor.
+ Add new functions psf_set_stdio() and psf_set_file().
+
+ * src/sndfile.c
+ Change these to work with changed psf_fopen() return value.
+ Remove all uses of psf->filedes from sndfile, making it easier to slot native
+ Win32 API file handling functions.
+
+ * src/test_file_io.c
+ Minor changes to make it compile with new file_io.c stuff.
+
+2003-10-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/gsm610.h
+ Rename a variable from true to true_flag. As Ross Bencina points out,
+ true is defined in the C99 header <stdbool.h>.
+
+ * src/file_io.c
+ If fstat() fails, return SF_TRUE instead of -1 (Ross Bencina).
+
+2003-10-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Increase the size of SF_BUFFER_LEN and SF_HEADER_LEN.
+
+ * src/sndfile.c
+ Fix sf_read/write_raw which were dividing by psf->bytwidth and
+ psf->blockwidth which can both be zero.
+
+ * examples/sndfile-info.c
+ Increase size of BUFFER_LEN.
+
+2003-09-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Add checks for <sys/wait.h> and ssize_t.
+ Other Win32/MinGW checks.
+
+ * src/aiff.c src/au_g72x.c src/file_io.c src/gsm610.c src/interleave.c
+ src/paf.c src/sds.c src/svx.c src/voc.c src/w64.c src/wav.c src/xi.c
+ Fix compiler warnings.
+
+2003-09-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/scale_clip_test.tpl
+ Add definition of M_PI if needed.
+
+2003-09-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Detect if S_IRGRP is declared in <unistd.h>.
+
+ * src/file_io.c tests/*.tpl tests/*.c
+ More fixes for Win32/MSVC++ and MinGW. MinGW does have <unistd.h> but that
+ file doesn't declare S_IRGRP.
+
+2003-10-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/config.h.in
+ Add comment stating that the sf_count_t typedef is determined when
+ libsndfile is being compiled.
+
+ * tests/utils.tpl
+ Modified so that utils.c gets one copy of the GPL and not two.
+
+
+2003-09-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/unistd.h src/sf_unistd.h
+ Move first file to the second. This will help for Win32/MSVC++ and MinGW.
+
+ * Win32/Makefile.am src/Makefile.am
+ Changed in line with above.
+
+ * Win32/Makefile.msvc
+ Removed "/I Win32" which is no longer required.
+
+ * src/file_io.c src/test_file_io.c tests/*.tpl tests/*.c
+ If HAVE_UNISTD_H include <unistd.h> else include <sf_unistd.h>. This should
+ work for Win32, MinGW and other fakes Unix-like OSes.
+
+ * src/*.c
+ Removed #include <unistd.h> from files which didn't need it.
+
+2003-09-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * libsndfile.spec.in
+ Apply fix from Andrew Schultz.
+
+2003-09-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/vox_adpcm.c
+ Only set psf->sf.samplerate if the existing value is invalid.
+
+2003-09-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Started adding support for ALSA output.
+
+2003-09-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in
+ Removed <stdlib.h> from sndfile.h.
+
+ * src/*.c examples/*.c tests/*.c tests/*.tpl
+ Added <stdlib.h> where needed.
+
+2003-09-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Added ARRAY_LEN, SF_MAX and SF_MIN macros.
+
+2003-08-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/index.html
+ Remove statements about alternative licensing arrangements.
+
+2003-08-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * MacOS MacOS9 Makefile.am configure.ac
+ Change directory name from MacOS to MacOS9
+
+ * MacOS9/MacOS9-readme.txt
+ Change name to make it really obvious, add text to top of file to make it
+ still more obvious again.
+
+2003-08-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/test_log_printf.c
+ Add tests for %u conversions.
+
+ * src/common.c
+ Fix psf_log_printf() %u conversions.
+
+2003-08-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Fixed a bug where opening a file with a non-trival header in SFM_RDWR mode
+ would over-write part of the header. Thanks to Axel Roebel for pointing
+ this out. Axel also provided a patch to fix this but I came up with a
+ neater and more general solution.
+ Return error when openning an AIFF file with data after the SSND chunk
+ (Thanks Axel Roebel).
+
+ * tests/aiff_rw_test.c
+ Improvements to test program which will later allow it to be generalised to
+ test WAV, SVX and others as required.
+
+2003-08-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/pipe_test.c
+ Add useek_pipe_rw_test() submitted by Russell Francis.
+
+ * src/sndfile.c
+ In sf_open_fd(), check if input file descriptor is a pipe.
+
+ * src/sndfile.[ch]
+ Fix typo in variable name do_not_close_descriptor.
+
+2003-08-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/test_log_printf.c
+ Improve the tests for %d and %s conversions.
+
+ * src/common.c
+ Fixed a few problems in psf_log_printf() found using new tests.
+
+2003-08-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Add -Wwrite-strings warning to CFLAGS if the compiler is GCC. Thanks to
+ Peter Miller (Aegis author) for suggesting this and supplying a patch.
+
+ * src/*.c examples/*.c tests/*.c
+ Fix all compiler warnings arising from the above.
+
+2003-08-02
+
+ * tests/aiff_rw_test.c tests/Makefile.am
+ New test program to check for errors re-writing the headers of AIFC files
+ opened in mode SFM_RDWR.
+
+2003-07-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Applied a patch from Tero Pelander to allow this program to run on systems
+ using devfs which used /dev/sound/dsp instead of /dev/dsp.
+
+2003-07-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/new_file_type.HOWTO
+ Updated document. Still incomplete.
+
+2003-06-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fix VALIDATE_SNDFILE_AND_ASSIGN_PSF which was returning an error rather
+ than saving it and returning zero.
+
+2003-06-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Two fixes for Mac OS9.
+ Fix all casts from sf_count_t to ssize_t (not size_t).
+
+2003-06-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Fix for reading files with RIFF length of 8 and data length of 0.
+
+2003-06-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c tests/*.c tests/*.tpl
+ Added comments to mark code for removal when make Lite version of
+ libsndfile.
+
+2003-06-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-convert.c
+ Add extra error checking for unrecognised arguments.
+
+2003-06-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/ima_adpcm.c
+ Started adding code to write IMA ADPCM encoded AIFF files.
+
+ * src/test_log_printf.c src/Makefile.am
+ New file to test psf_log_printf() function and add hooks into build system.
+
+ * src/common.c
+ Move psf_log_printf() function to top of the file and only compile the rest
+ of the file if if PSF_LOG_PRINTF_ONLY is not defined.
+
+2003-06-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/config.h Win32/sndfile.h
+ Updated with new config variables.
+
+ * Win32/unistd.h src/file_io.c
+ Added implementation of S_ISFIFO macro which Win32 seems to lack and is
+ used in src/file_io.c.
+
+ * tests/utils.tpl
+ Added #include <unitstd.h> to pull in Win32/unistd.h so it compiles for
+ Win32.
+
+ * src/Makefile.msvc
+ Added src\test_file_io.exe build target and run this as the very first
+ test.
+
+ * tests/win32_test.c
+ Add support for testing Cygwin32.
+
+ * configure.ac
+ Detect POSIX fsync() and fdatasync() functions.
+
+ * src/file_io.c
+ If compiling for Cygwin, call fsync() before calling fstat() to retrieve
+ file length.
+
+ * tests/pcm_test.tpl
+ Add a test for lrintf() function. This was required to detect a really
+ broken lrint() and lrintf() on Cygwin.
+
+ * tests/misc_test.c
+ Don't run permission test when compiling under Cygwin.
+
+ * src/float_cast.h
+ Fix fallback macro for lrint() and lrintf() to cast to long instead of int
+ to match official function prototypes.
+
+2003-06-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-convert.c
+ Modifications to improve accuracy of conversions; use double data for
+ floating point and int for everything else.
+
+ * src/ima_apdcm.c
+ Completed work on decoding IMA ADPCM encoded AIFF files. Still need to
+ get encoding working.
+
+2003-05-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c src/ima_adpcm.c
+ Start working on getting IMA ADPCM encoded AIFF files working.
+
+2003-05-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Fixed the touch command for when the autogen program is not found (Matt
+ Flax).
+
+ * src/ulaw.c src/alaw.c
+ Made these pipe-able.
+
+2003-05-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/paf.c src/ircam.c
+ Fixed writing to pipe.
+
+ * src/wav.c src/aiff.c src/nist.c src/mat*.c src/svx.c src/w64.c
+ Return SFE_NO_PIPE_WRITE if an attempt is made to write to a pipe.
+
+2003-05-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-info.c
+ Modified to detect unknown file lengths.
+
+ * src/mat4.c
+ Fix reading from a pipe.
+
+2003-05-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/pipe_test.c
+ Add more file types to tests.
+
+ * src/mat4.c
+ Removed explicit setting of psf->sf.seekable to SF_TRUE.
+
+ * tests/utils.tpl
+ Add macro for generating and check data in the stdio and pipe tests.
+
+ * tests/stdout_test.c tests/stdin_test.c
+ Use the above macro to generate known data on output and check data on
+ input.
+
+ * src/voc.c src/htk.c common.h sndfile.c
+ Disallow reading/writing VOC and HTK files from/to pipes be returning new
+ error values.
+
+ * src/w64.c
+ Fixes to allow reading from a pipe.
+
+2003-05-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac src/sndfile.h.in
+ When the configure script determines the sizeof (sf_count_t), also set the
+ value of SF_COUNT_MAX in sndfile.h.
+
+ * configure.ac
+ Remove -pedantic flag from default GCC compiler flags.
+
+ * tests/pipe_test.c
+ Add a pipe_read_test() before doing pipe_write_test().
+
+ * tests/scale_clip_test.c
+ Add test to make sure non-normalized values also clip in the right way.
+
+2003-05-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Add test to detect processor clipping capabilities.
+
+ * tests/stdin_test.c tests/stdout_test.c
+ Fix a pair of compiler warnings.
+
+ * src/common.h
+ Add new pipeoffset field to SF_PRIVATE. This will contain the current file
+ offset when operating on a pipe.
+
+ * src/common.c
+ Removed direct calls to psf_fread()/psf_fseek()/psf_fgets() etc from
+ psf_binheader_readf and redirect them to new buffered versions
+ header_read(), header_seek() and header_gets().
+ Add "G" format specifier to emulate fgets() functionality with buffering.
+ This will allow reading some file types from pipes.
+
+ * src/file_io.c
+ When the file descriptor is a pipe, manintain psf->pipeoffset.
+
+ * src/pvf.c
+ Change use of psf_fgets() to psf_binheader_readf() as required but changes to header re
+
+ * src/au.c
+ Fix reading from a pipe.
+
+2003-05-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pcm.c
+ Add clipping versions of the f2XXX_array() functions to allow option of
+ clipping data that would otherwise overflow.
+
+ * tests/scale_clip_test.tpl tests/scale_clip_test.def
+ New files test that clipping option does actually work.
+
+2003-05-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/index.html
+ Fixed a typo ("OS(" instead of "OS9").
+
+2003-05-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/open_fail_test.c
+ Include <string.h> to prevent warning message of missing declaration of
+ memset().
+
+2003-05-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Add new "add_clipping" field to SF_PRIVATE.
+
+ * src/sndfile.h.in src/sndfile.c
+ Add command SFC_SET_CLIPPING which sets/resets add_clipping field.
+
+2003-05-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/api.html
+ Add docs for sf_set_string() and sf_get_string().
+
+ * src/common.h src/sndfile.c
+ Add new SFE_STR_BAD_STRING error.
+
+ * tests/stdin_test.c tests/stdout_test.c
+ Removed all non-error print statements.
+
+ * tests/stdio_test.c tests/pipe_test.c tests/Makefile.am
+ Add print statements removed from two files above.
+
+2003-05-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * libsndfile.spec.in
+ Fixed a coulpe of minor errors discovered by someone calling themselves
+ Agent Smith.
+
+ * src/common.c src/common.h src/file_io.h
+ Added is_pipe field to SF_PRIVATE and declaration of psf_is_pipe()
+ function. (Axel Roebel)
+
+ * src/sndfile.c
+ Fixed determination of whether the file is a pipe. (Axel Roebel)
+
+ * src/paf.c
+ Force paf24 to start with undefined mode. (Axel Roebel)
+
+ * tests/pipe_test.c
+ Mods to make this test work and actually do the test on RAW files. (Axel
+ Roebel).
+
+2003-05-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed a potential bug where psf->sf.seekable was being set to FALSE when
+ operating on stdin or stdout but then the default initialiser was reseting
+ it to TRUE. Thanks to Axel Roebel.
+
+ * src/aiff.c
+ Fixed a bug in the header parser where it was not handling an odd length
+ COMM chunk correctly. Thanks to Axel Roebel.
+
+ * src/test_file_io.c
+ Add more tests.
+
+ * tests/win32_test.c
+ New file for showing the bugs in the Win32 implementation of the POSIX API.
+ It also runs on Linux for sanity checking.
+
+ * tests/Makefile.am Win32/Makefile.msvc
+ Hook the new test program into the build system.
+
+2003-05-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/test_file_io.c
+ New test program to test operation of functions defined in file_io.c. This
+ should make supporting win32 significantly easier.
+
+ * src/Makefile.am
+ Hook new test program into the build system.
+
+ * src/file_io.c
+ Add compile/run time check that sizeof statbuf.st_size and sf_count_t are
+ the same.
+
+ * src/common.h src/sndfile.c
+ Added new error code and error message for new check.
+
+ * tests/benchmark.tpl
+ Fix to use frames instead of samples in SF_INFO.
+
+2003-05-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ More stuffing about working around PLAIN OLD-FASHIONED **BUGS** in Win32.
+
+ * examples/sndfile-info.c
+ Applied patch from Conrad Parker to add "--help" and "-h" options as
+ well as an improved usage message.
+
+2003-05-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/au.c
+ Added embedded file support.
+
+ * tests/multi_file_test.c
+ Added tests for embedded AU files.
+ Added verbose testing mode.
+
+ * src/common.h src/sndfile.c
+ Added an embedded AU specific error code and message.
+
+ * src/wav.c
+ Added patch from Conrad Parker which filled in a little more information
+ about ACIDized WAV files.
+
+2003-04-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Fixed Win32 version of psf_fseek() which was calling psf_get_filelen()
+ which was in turn calling psf_fseek() which in the end blew the stack.
+ Now of course this would have been easy to find on Linux, but this blow
+ up was happening in kernel32.dll and the fscking MSVC++ debugger couldn't
+ figure out what call caused this (it couldn't even tell me the stack had
+ overflowed) and was absolutley useless for this debugging exercise.
+ On top of that, the reason I got into this mess was that windoze doesn't
+ have a working fstat() function which can return file lengths > 2 Gig. It
+ HAS a fscking _fstati64() but the file length value is only updated AFTER
+ the bloody file is closed. That makes it completely useless.
+ How the hell do people stand working on this crap excuse of an OS?
+
+2003-04-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/unistd.h src/file_io.c
+ Moved definitions of S_IGRP etc from file_io.c to unistd.h so that these
+ can be used in the test programs.
+
+ * Win32/libsndfile.def
+ Added sf_open_fd.
+
+ * Win32/sndfile.h
+ Updated to match src/sndfile.h.in.
+
+ * Win32/Makefile.msvc
+ Added dither.c and htk.c to libsndfile.dll target.
+
+2003-04-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ First attempt at getting the Win32 versions of the these functions working.
+ They still need to be tested.
+
+2003-04-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/strings.c
+ Found and fixed a bug which was causing psf_store_string() to fail on
+ Motorola 68k processors. Many thanks fo Joshua Haberman (Debian maintainer
+ of libsndfile) for compiling and running debug code to help me debug the
+ problem.
+
+2003-04-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/file_io.c src/wav.c src/aiff.c
+ Much hacking to get reading and writing of embedded files working (ie sound
+ files at a non-zero files offset).
+
+ * doc/embedded_files.html
+ First pass atempt at documenting reading/writing embedded files.
+
+2003-04-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ Updated answer to "Why doesn't libsndfile do interleaving/de-interleaving?"
+
+2003-04-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c src/aiff.c
+ Fix retrieving and storing of string data from files. Need to be careful
+ about using psf->buffer for strings.
+
+2003-04-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Fix psf_fseek() for seeks withing embedded files.
+
+2003-04-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in
+ Changed the definition of SNDFILE slightly to produce warnings when it isn't
+ used correctly. This should have zero affect in code which uses the SNDFILE
+ type correctly.
+
+ * src/sndfile.c
+ Fixed a few compiler warnings cause by the changes to the SNDFILE type.
+
+2003-04-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ Added question and answer to the question "How about adding the ability
+ to write/read sound files to/from memory buffers?".
+
+2003-04-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.tpl
+ Removed un-needed enums declaring TRUE and FALSE and replaced usage of
+ these with SF_TRUE and SF_FALSE.
+
+ * tests/multi_file_test.c
+ New test program to test sf_open_fd() on files containing data other than
+ a single sound file.
+
+2003-04-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ When creating files, set the readable by others flag. This still allows
+ further restrictions to be enforced by use of the user's umask. Fix
+ suggested by Eric Lyon.
+
+2003-04-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/sndfile.c
+ Changed sf_open_fd(). Dropped offset parameter and added a close_desc
+ parameter. If close desc is TRUE, the file descritpor passed into the
+ library will be closed when sf_close() is called.
+
+ * tests/utils.tpl
+ Modified call to sf_open_fd() to set close_desc parameter to SF_TRUE.
+
+2003-04-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.tpl
+ Add a string (using sf_set_string() function) before and after data section
+ of all files. This will make sure that if string data can be added, it
+ doesn't overwrite real audio data.
+
+2003-04-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Started work on supporting a non-zero offset parameter for sf_open_fd ().
+
+ * src/<file header parsers>.c
+ Removed many uses of psf_fseek (SEEK_END) which to allow for future use of
+ sf_open_fd() with non-zero offset.
+ Associated refactoring.
+
+ * src/aiff.c
+ Implemented functionality required to get sf_get_string() and
+ sf_set_string() working for AIFF files.
+
+2003-04-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/utils.tpl
+ Modified test_open_file_or_die() to alternately use sf_open() and
+ sf_open_fd().
+
+ * src/svx.c
+ Fixed a bug which occurred when openning an existing file for read/write
+ using sf_open_fd(). In this case, the existing NAME chunk needs to be
+ read into psf->filename.
+ Fixed printing of sf_count_t types to logbuffer.
+
+2003-03-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in
+ Added prototype for new function sf_open_fd().
+
+ * src/sndfile.c
+ Moved most of the code in sf_open() to a new function psf_open_file().
+ Created new function sf_open_fd() which also uses psf_open_file() but
+ does not currently support the offset parameter.
+
+ * doc/api.html
+ Document sf_open_fd().
+
+2003-03-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed a memory leak reported by Evgeny Karpov. Memory leak only occurred
+ when an attempt was made to read and the open() call fails.
+
+2003-03-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/open_fail_test.c
+ New test program to check for memory leaks when sf_open fails on a valid
+ file. Currently this must be run manually under valgrid.
+
+ * tests/Makefile.am
+ Hook new test program into build.
+
+2003-03-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Octave/sndfile_save.m Octave/sndfile_play.m
+ Added a -mat-binary option to the octave save command to force the output
+ to binary mode even if the user has set ascii data as the default. Found
+ by Christopher Moore.
+
+2003-02-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/dither.html
+ New file which will document the interface which allows the addition of
+ audio dither when sample word sizes are being reduced.
+
+ * src/dither.c
+ More work.
+
+2003-02-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/misc_test.c
+ In update_header_test(), make HTK files a special case.
+
+ * doc/index.html
+ Added HTK to the feature matrix.
+
+2003-02-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/htk.c
+ New file for reading/writing HMM Tool Kit files.
+
+ * src/sndfile.h.in src/sndfile.c src/command.c src/Makefile.am
+ Hook in htk.c
+
+ * tests/write_read_test.tpl tests/misc_test.c tests/Makefile.am
+ Add tests for HTK files.
+
+2003-02-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Fixed a bug where the LIST chunk length was being written incorrectly.
+
+ * tests/string_test.c
+ Added call to check_log_buffer().
+ Minor cleanups.
+
+2003-02-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_w64.h
+ Applied patch from Antoine Mathys to add extra WAV format definitions and
+ a G72x_ADPCM_WAV_FMT struct definition.
+
+ * src/wav_w64.c
+ Applied patch from Antoine Mathys which converts wav_w64_format_str() from
+ one huge inefficient switch statement to a binary search.
+
+ * tests/string_test.c
+ Dump log buffer if tests fail.
+
+2003-02-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/string_test.c
+ David Viens supplied some modifications to this file which showed up a bug
+ when using sf_set_string() and the sf_writef_float() functions.
+
+ * src/sndfile.c
+ Fixed the above bug.
+
+2003-02-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ Added Q and A on how to detect libsndfile in configure.in (at the suggestion
+ of Davy Durham).
+
+2003-02-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in
+ Add enums and typedefs for dither.
+ Deprecate SFC_SET_ADD_DITHER_ON_WRITE and SFC_SET_ADD_DITHER_ON_READ, to be
+ replaced with SFC_SET_DITHER_ON_WRITE and SFC_SET_DITHER_ON_READ which will
+ allow different dither algorithms to be enabled.
+ Added SFC_GET_DITHER_INFO_COUNT and SFC_GET_DITHER_INFO.
+
+ * src/sndfile.h.in src/Version_script.in Win32/libsndfile.def.
+ Added public sf_dither_*() functions.
+
+ * src/sndfile.c
+ Implement commands above.
+
+ * src/dither.c
+ More work. Framework and external hooks into dither algorithms complete.
+
+2003-02-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/version-1.html libsndfile_version_convert.py
+ Remove redundant files.
+
+ * doc/index.html doc/api.html
+ Remove links to version-1.html.
+
+ * src/dither.c
+ New file to allow the addition of audio dither on input and output.
+
+ * src/common.h
+ Add prototype for dither_init() function.
+
+ * Makefile.am doc/Makefile.am
+ Changes for added and removed files.
+
+2003-02-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/Makefile.msvc
+ Changes to force example binaries to be placed in the top level directory
+ instead of the examples/ directory.
+ Add src/strings.c and src/xi.c to the build.
+ Add string_test to build and to tests on WAV files.
+
+ * doc/index.html
+ Added XI to support matrix.
+
+2003-01-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in
+ Added prototypes for sf_get_string() and sf_set_string() and SF_STR_*
+ enum values.
+
+ * src/sndfile.c
+ Added public interface to sf_get_string() and sf_set_string().
+
+ * src/wav.c
+ Added code for setting and getting strings in WAV files.
+
+ * tests/string_test.c
+ New test program for sf_get_string() and sf_set_string() functionality.
+
+ * tests/Makefile.am
+ Hook new test program into build and test framework.
+
+2003-01-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Added fields to SF_PRIVATE for string data needed to implement
+ sf_get_string() and sf_set_string().
+
+ * src/strings.c
+ New file for storing and retrieving strings to/from files.
+
+ * src/Makefile.am
+ Added strings.c to build.
+
+2003-01-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/xi.c
+ Read seems to be working so looking at write.
+
+ * src/sndfile.h.in
+ Added SF_FORMAT_XI, SF_FORMAT_DPCM_8 and SF_FORMAT_DPCM_16 enum values.
+
+ * tests/floating_point_test.c tests/lossy_comp_test.c tests/Makefile.am
+ Added test for 8 and 16 bit XI format files.
+
+2003-01-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/index.html
+ Added a non-lawyer readable summary of the licensing provisions as
+ suggested by Steve Dekorte.
+
+2003-01-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Fixed a compiler warning found by Alexander Lerch.
+
+2003-01-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Fixed the multiple linking of libm.
+
+2003-01-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/Makefile.mcvs
+ Added comments on the correct way to set up the MSVCDir environment
+ variable.
+
+ * doc/win32.html
+ Add on how to set up the MSVCDir environment variable.
+
+2003-01-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c examples/sndfile-info.c
+ When run on Win32 without any command line parameters print a message and
+ then sleep for 5 seconds. This means the when somebody double clicks on
+ these programs in explorer the user will actually see the message.
+
+2003-01-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/misc_test.c
+ Bypass permission test if running as root because root is allowed to open
+ a readonly file for write.
+
+2003-01-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/Makefile.msvc
+ Added pvf.c and xi.c source files to project.
+
+ * src/sndfile.h
+ Updated for PVF files.
+
+2003-01-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Modified validate_sfinfo() to force samplerate, channels and sections
+ to be >= 1.
+ In format_from_extension() replaced calls to does_extension_match()
+ with strcmp().
+
+ * src/xi.c
+ More work.
+
+2003-01-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/Makefile.am
+ Added octave.html which had been left out. Found by Jan Weil.
+
+2003-01-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pvf.c src/common.h src/sndfile.c
+ Fixed error handling for PVF files.
+
+ * src/xi.c
+ New file for handling Fasttracker 2 Extended Instrument files. Not working
+ yet and included when configured with --enable-experimental.
+
+ * src/sndfile.c src/common.h
+ Hooked in new file xi.c.
+
+2002-12-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/rx2.c
+ Added a patch from Marek Peteraj which sheds a little more light on the
+ slices within an RX2 file. Still need to find out data encoding.
+
+2002-12-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Started work on decoding 'acid' and 'strc' chunks.
+
+2002-12-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/peak_check_test.c
+ Minor cleanup.
+
+2002-12-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.tpl
+ Added check to make sure no error was generated when an attempt was made to
+ read past the end of the file.
+
+2002-12-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/lists.html
+ Added "mailto" links for all three lists.
+
+ * src/pvf.c
+ New file for Portable Voice Format files.
+
+ * src/sndfile.h.in src/sndfile.c src/common.h src/command.c src/Makefile.am
+ Added hooks for SF_FORMAT_PVF format files.
+
+ * tests/write_read_test.tpl tests/std*.c
+ Add tests for SF_FORMAT_PVF.
+
+ * doc/index.html
+ Add PVF to the compatibility matrix.
+
+ * src/pcm.c src/alaw.c src/ulaw.c src/float32.c src/double64.c
+ Previously, attempts to read beyond the end of a file would set psf->error
+ to SFE_SHORT_ERROR. This behaviour diverged from the behaviour of the POSIX
+ read() call but has now been fixed.
+ Attempts to read beyond the end of the file will return a short read count
+ but will not longer set any error.
+
+2002-12-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Add more sanity checking when opening a RAW file for read. When format is
+ not RAW, zero out all members of the SF_INFO struct.
+
+ * tests/raw_test.c
+ Add bad_raw_test() to check for above problem.
+
+ * tests/stdin_test.c examples/sndfile-info.c
+ Set the format field of the SF_INFO struct to zero before calling
+ sf_open().
+
+ * doc/api.html
+ Add information about the need to set the format field of the SF_INFO struct
+ to zero when opening non-RAW files for read.
+
+ * configure.ac
+ Removed use of conversion script on Solaris. Not all Solaris versions
+ support it.
+
+ * doc/lists.html
+ New file containg details of the mailing lists.
+
+ * doc/index.html
+ Add a link to the above new file.
+
+2002-12-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/dft_cmp.c
+ Fixed a SIGFPE on Alpha caused by a log10 (0.0). Thanks to Joshua Haberman
+ for providing the gdb traceback.
+
+2002-11-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Added more capabilities to 'smpl' chunk parser.
+
+ * src/sndfile.c
+ Fixed some (not all) possible problems found with Flawfinder.
+
+2002-11-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed a bug in sf_seek(). This bug could only occur when an attempt was
+ made to read beyond the end and then sf_seek() was called with a whence
+ parameter of SEEK_CUR.
+
+ * src/file_io.c
+ Win32's _fstati64() does not work, it returns BS. Re-implemented
+ psf_get_filelen() in terms of psf_fseek().
+
+ * tests/write_read_test.tpl
+ Add a test to detect above bug.
+
+ * src/float_cast.h
+ Modification to prevent compiler warnings on Mac OS X.
+
+ * src/file_io.c
+ Fixes for windows (what a f**ked OS).
+
+2002-11-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.ac
+ Disable use of native lrint()/lrintf() on Mac OSX. These functions exist on
+ Mac OSX 10.2 but not on 10.1. Forcing the use of the versions in
+ src/float_cast.h means that a library compiled on 10.2 will still work on
+ 10.1.
+
+2002-11-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in configure.ac
+ Renamed configure.in to configure.ac as expected by later versions of
+ autoconf.
+ Slight hacking of configure.ac to work with version 2.54 of autoconf.
+ Changed to using -dumpversion instead of --version for determining GCC
+ version numer as suggested by Anand Kumria.
+
+ * src/G72x/Makefile.am
+ Slight hacking required for operation with automake 1.6.3.
+
+2002-11-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ In psf_binheader_readf() changed type parameter type "b" type from size_t
+ to int to prevent errors on IA64 CPU where sizeof (size_t) != sizeof (int).
+ Thanks to Enrique Robledo Arnuncio for debugging this.
+
+2002-11-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * test/command_test.tpl
+ Changed test value so test would pass on Solaris.
+
+ * src/Version_script.in
+ Modified version numbering so that later versions of 1.0.X can replace
+ earlier versions without recompilation.
+
+ * src/vox_adpcm.c
+ Fixed bug causing short reads.
+
+2002-11-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * test/floating_point_test.c
+ Code cleanup using functions from util.c.
+ Add test for IEEE replacement floats and doubles.
+
+2002-11-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Fixed a possible divide by zero error when read the 'smpl' chunk. Thanks to
+ Serg Repalov for the example file.
+
+ * tests/pcm_test.tpl
+ Used sf_command (SFC_TEST_IEEE_FLOAT_REPLACE) to test IEEE replacement code.
+ Clean up pcm_double_test().
+
+ * src/float32.c src/double64.c
+ Force use of IEEE replacement code using psf->ieee_replace is TRUE,
+ Print message to log_buffer as well.
+ Rename all broken_read_* and broken_write* functions to replace_read_* and
+ replace_write_*.
+
+ * tests/util.tpl
+ Added string_in_log_buffer().
+
+ * tests/pcm_test.tpl
+ Use string_in_log_buffer() to ensure that IEEE replacement code has been
+ used.
+
+ * configure.in
+ Removed --enable-force-broken-float option. IEEE replacement code is now
+ always tested.
+
+2002-10-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/double64.c
+ Implement code for read/writing IEEE doubles on platforms where the native
+ double format is not IEEE.
+
+ * src/float32.c src/common.h
+ Remove float32_read() and float32_write(). Replace with float32_le_read(),
+ float32_be_read(), float32_le_write() and float32_be_write() to match stuff
+ in src/double64.c.
+
+ * src/common.c
+ Fix all usage of float32_write().
+
+ * src/sndfile.h.in
+ Added SFC_TEST_IEEE_FLOAT_REPLACE command (testing only).
+
+ * src/common.h
+ Added SF_PRIVATE field ieee_replace.
+
+ * src/sndfile.c
+ In sf_command() set/reset psf->ieee_replace.
+
+2002-10-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/pcm_test.tpl
+ Fixed a problem when testing with --enable-force-broken-float. The test was
+ generating a value of negative zero and the broken float code is not able
+ to write negative zero. Removing the negative zero fixed the test.
+
+2002-10-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Added fix for Cygwin (suggested by Maros Michalik).
+
+2002-10-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Improved error detection and handling.
+
+ * src/file_io.c src/common.h
+ Removed functions psf_ferror() and psf_clearerr() which were redundant
+ after above improvements.
+
+ * src/aiff.c src/svx.c src/w64.c src/wav.c
+ Removed all use of psf_ferror() and psf_clearerr().
+
+ * src/sndfile.c
+ Removed #include of <stdio.h>, <unistd.h>, <fcntl.h> and <math.h> which
+ are no longer needed.
+
+ * tests/misc_test.c
+ Added test to make sure the correct error message is returned with an
+ existing read-only file is openned for write.
+
+2002-10-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/index.html doc/api.html
+ Updated for OKI Dialogic ADPCM files.
+
+ * src/command.c
+ Added VOX ADPCM to sub_fomats.
+
+2002-10-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/vox_adpcm.c src/Makefile.am
+ New file for handling OKI Dialogic ADPCM files.
+
+ * src/sndfile.h
+ Add new subtype SF_FORMAT_VOX_ADPCM.
+
+ * src/sndfile.c
+ Renamed function is_au_snd_file () to format_from_extenstion () and expanded
+ its functionality to detect headerless VOX files.
+
+ * src/raw.c
+ Added hooks for SF_FORMAT_VOX_ADPCM.
+
+ * examples/sndfile-info.c
+ Print out file duration (suggested by Conrad Parker).
+
+ * libsndfile.spec.in
+ Force installation of sndfile.pc file (found by John Thompson).
+
+ * tests/Makefile.am tests/lossy_comp_test.c tests/floating_point_test.c
+ Add tests for SF_FORMAT_VOX_ADPCM.
+
+2002-10-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/misc_test.c
+ Add test which attempts to write to /dev/full (on Linux anyway) to check
+ for correct handling of writing to a full filesystem.
+
+ * src/sndfile.c
+ Return correct error message if the header cannot be written because the
+ filesystem is full.
+
+ * tests/util.tpl
+ Corrected printing of file mode in error reporting.
+
+ * src/mat5.c
+ Fixed a bug where a MAT5 file written by libsndfile could not be opened by
+ Octave 2.1.36.
+
+2002-10-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h src/file_io.c
+ All low level file I/O have been modified to be better able to report
+ system errors resulting from calling system level open/read/write etc.
+
+ * src/*.c
+ Updated for compatibility with above changes.
+
+ * examples/cooledit-fixer.c
+ New example program which fixes badly broken file created by Syntrillium's
+ Cooledit which are marked as containing PCM samples but actually contain
+ floating point data.
+
+ * examples/Makefile.am
+ Hooked cooledit-fixer into the build system.
+
+2002-10-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/command.html
+ Document SFC_GET_FORMAT_INFO.
+
+2002-10-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/wav32_aiff24.c examples/sndfile2oct.c examples/sfhexdump.c
+ examples/sfdump.c
+ Removed these files because they weren't interesting.
+
+ * examples/sfconvert.c examples/sndfile-convert.c
+ Renamed the first to the latter.
+
+ * examples/Makefile.am
+ Added sndfile-convert to the bin_PROGRAMS, so it is installed when the lib
+ is installed.
+ Removed old programs wav32_aiff24 and sndfile2oct.
+
+ * man/sndfile-convert.1
+ New man page.
+
+ * examples/sndfile-convert.c
+ Added some gloss now that sndfile-convert.c is an installed program.
+
+ * src/sndfile.h.in src/sndfile.c src/common.h src/command.h
+ Added command SFC_GET_FORMAT_INFO.
+
+ * tests/command_test.c
+ Added tests form SFC_GET_FORMAT_INFO.
+
+2002-10-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ In sf_format_check() return error if samplerate < 0.
+
+2002-10-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Fixed bug in handling of COMM chunks with a 4 byte encoding byte but no
+ encoding string.
+
+2002-10-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed repeated word in an error message.
+
+2002-10-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/index.html
+ Improved advertising in Features section.
+
+2002-10-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Added decoding of 'labl' chunks within 'LIST' chunks.
+
+ * src/common.h
+ Added (experimental only) SF_FORMAT_OGG and SF_FORMAT_VORBIS and definition
+ of ogg_open(). This is nowhere near working yet.
+
+ * src/sndfile.c
+ Added detection of 'OggS' file marker and added call to ogg_open() to
+ switch statement.
+
+ * src/ogg.c
+ New file. Very early start of Ogg Vorbis support.
+
+ * src/wav.c
+ Added handling of brain-damaged and broken Cooledit "32 bit 24.0 float
+ type 1" files. These files are marked as being 24 bit WAVE_FORMAT_PCM with
+ a block alignment of 4 times the numbers of channels but are in fact 32 bit
+ floating point.
+
+2002-10-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Modified option --enable-experimental to set ENABLE_EXPERIMENTAL_CODE in
+ config.h to either 0 or 1.
+
+ * src/sndfile.c
+ Modify sf_command (SFC_GET_LIB_VERSION) to append "-exp" to the version
+ string if experimental code has been enabled.
+
+2002-10-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/Makefile.am
+ Added -lm to libsndfile_la_LIBADD. This means that -lm is not longer needed
+ in the link line when linking something to libsndfile.
+
+ * tests/Makefile.am examples/Makefile.am
+ Removed -lm from all link lines.
+
+ * sndfile.pc.in
+ Removed -lm from Libs line.
+
+2002-09-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Removed all perror() calls.
+
+ * src/nist.c
+ Removed calls to exit() function.
+ Added check to detect NIST files dammaged from Unix CR -> Win32 CRLF
+ conversion process.
+
+2002-09-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/sndfile.c
+ New function sf_strerror() which will eventually replace functions
+ sf_perror() and sf_error_str().
+ Function sf_error_number() has also been changed, but this was documented
+ as being for testing only.
+
+ * doc/api.html
+ Documented above changes.
+
+ * tests/*.c examples/*.c
+ Changed to new error functions.
+
+2002-09-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Detect GCC version, and print a warning message about writeable strings
+ it GCC major version number is less than 3.
+
+2002-09-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in doc/api.html
+ Documentation fixes.
+
+2002-09-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/Version_script.in src/Makefile.am configure.in
+ Use the version script to prevent the exporting of all non public symbols.
+ This currently only works with Linux. Will test on Solaris as well.
+
+ * src/float_cast.h
+ Added #ifndef to prevent the #warning directives killing the SGI MIPSpro
+ compiler.
+
+ * src/au_g72x.c src/double64.c src/float32.c src/gsm610.c src/ima_adpcm.c
+ src/ms_adpcm.c
+ Fix benign compiler warnings arising from previously added compiler
+ flags.
+
+2002-09-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed a bug in sf_error_str() where errnum was used as the index instead
+ of k. Found by Tim Hockin.
+
+ * examples/sndfile-play.c
+ Fixed a compiler warning resulting from a variable shadowing a previously
+ defined local.
+
+2002-09-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in src/sndfile.c
+ Added command SFC_SET_RAW_START_OFFSET.
+
+ * doc/command.html
+ Document SFC_SET_RAW_START_OFFSET.
+
+ * tests/raw_test.c tests/Makefile.am
+ Add new file for for testing SF_FORMAT_RAW specific functionality.
+
+ * tests/dwvw_test.c
+ Updates.
+
+2002-09-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Modified reading of 'smpl' chunk to take account of the sampler data field.
+
+ * tests/utils.tpl tests/utils.h
+ Added function print_test_name().
+
+ * tests/misc_test.c tests/write_read_test.tpl tests/lossy_comp_test.c
+ tests/pcm_test.tpl tests/command_test.tpl tests/floating_point_test.c
+ Convert to use function print_test_name().
+
+2002-09-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/octave.html
+ Added a link to some other Octave scripts for reading and writing sound
+ files.
+
+ * src/paf.c
+ Change type of dummy data field to int. This should fix a benign compiler
+ warning on some CPUs.
+ Removed superfluous casts resulting from the above change.
+
+ * src/rx2.c
+ More hacking.
+
+2002-09-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/mat5.c src/common.c
+ Changed usage of snprintf() to LSF_SNPRINTF().
+
+ * Win32/Makefile.msvc
+ Updated to include new files and add new tests.
+
+ * Win32/config.h Win32/sndfile.h
+ Updated.
+
+ * doc/api.html
+ Added note about the possibility of "missing" features actually being
+ implemented as an sf_command().
+
+2002-09-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/misc_test.c
+ Added previously missing update_header_test and zero_data_tests for PAF,
+ MAT4 and MAT5 formats.
+
+ * src/paf.c src/mat4.c src/mat5.c
+ Fixed bugs uncovered by new tests above.
+
+ * src/mat5.c
+ Generalised parsing of name fields of MAT5 files.
+
+ * src/mat5.c src/sndfile.c
+ Added support for unsigned 8 bit PCM MAT5 files.
+
+ * tests/write_read_test.tpl
+ Added test for unsigned 8 bit PCM MAT5 files.
+
+ * doc/index.html
+ Added unsigned 8 bit PCM MAT5 to capabilities matrix.
+
+2002-09-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * test/update_header_test.c tests/misc_test.c
+ Renamed update_header_test.c to misc_test.c.
+ Added zero_data_test() to check for case where file is opened for write and
+ closed immediately. The resulting file can be left in a state where
+ libsndfile cannot open it. Problem reported by Werner Schweer, the author
+ of Muse.
+
+ * src/aiff.c
+ Removed superfluous cast.
+
+ * src/wav.c src/svx.c
+ Fixed case of file generated with no data.
+ Removed superfluous cast.
+
+ * src/sndfile.c
+ Fixed error on IA64 platform caused by incorrect termination of
+ SndfileErrors struct array. This problem was found in the Debian buildd
+ logs (http://buildd.debian.org/).
+
+ * configure.in
+ Added Octave directory.
+
+ * Octave/Makefile.ma
+ New Makfile.am for Octave directory.
+
+ * Octave/sndfile_load.m Octave/sndfile_save.m Octave/sndfile_play.m
+ New files for working with Octave.
+
+ * doc/octave.html
+ Document explaining the use of the above three Octave scripts.
+
+2002-09-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed bug in RDWR mode.
+
+2002-09-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Fixed psf_get_date_str() for systems which don't have gmtime_r() or
+ gmtime().
+
+ * src/file_io.c
+ Added #include <io.h> for Win32. Reported by Koen Tanghe.
+
+2002-09-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Added 'S' format specifier for psf_binheader_writef() which writes a C
+ string, including single null terminator to the header.
+ Added 'j' format specifier to allow jumping forwards or backwards in the
+ header.
+ Added function psf_get_date_str().
+
+ * src/mat5.c
+ Complete read and write support.
+
+ * doc/index.html
+ Added entries for MAT4 and MAT5 in capabilities matrix.
+
+2002-09-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/mat4.c
+ Completed read and write support.
+
+ * src/common.h src/sndfile.c
+ Added MAT4 and MAT5 specific error messages.
+
+ * tests/write_read_test.tpl tests/Makefile.am
+ Added tests for MAT4 and MAT5 files.
+
+ * tests/stdio_test.c tests/stdout_test.c tests/stdin_test.c
+ Added tests for MAT4 and MAT5 files.
+
+2002-09-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/command.c
+ Added elements for SF_FORMAT_MAT4 and SF_FORMAT_MAT5 to major_formats
+ array.
+
+ * examples/sfconvert.c
+ Added mat4 and mat5 output targets.
+
+2002-09-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Added check to prevent errors openning read only formats for read/write.
+
+ * src/interleave.c
+ New file for interleaving non-interleaved data. Non-interleaved data is
+ only supported on read.
+
+ * src/Makefile.am
+ Added src/interleave.c to build.
+
+2002-09-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/double64.c src/common.h
+ Added double64_be_read(), double64_le_read(), double64_be_write() and
+ double64_le_write() which replace double64_read() and double64_write().
+
+ * src/common.c
+ Cleanup of psf_binheader_readf() and add ability to read big and little
+ endian doubles (required by mat4.c and mat5.c).
+ Add ability for psf_binheader_writef() to write doubles to sound file
+ headers.
+
+2002-09-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/mat5.c
+ New file for reading Matlab (tm) version 5 data files. This is also the
+ native binary file format for version 2.1.X of GNU Octave which will be
+ used for testing.
+ Not complete yet.
+
+ * src/mat4.c
+ New file for reading Matlab (tm) version 4.2 data files. This is also the
+ native binary file format for version 2.0.X of GNU Octave which will be
+ used for testing.
+ Not complete yet.
+
+ * src/sndfile.h.in src/sndfile.c src/common.h src/command.c src/Makefile.am
+ Mods to add Matlab files.
+
+ * src/common.[ch]
+ Added readf_endian field to SF_PRIVATE struct allowing endianness to
+ remembered across calls to sf_binheader_readf().
+ Fixed bug in width_specifier behaviour for printing hex values.
+
+2002-08-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Check return value of close() call in psf_fclose().
+
+2002-08-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/ms_adpcm.c
+ Commented out some code where 0x10000 was being subtracted from a short
+ and the result assigned to a short again. Andrew Zaja found this.
+
+2002-08-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/command.html
+ Fixed typo found by Tommi Ilmonen.
+
+ * src/ima_adpcm.c
+ Changed type of diff from short to int to prevent errors which can occur
+ during very rare circumstances. Thanks to FUWAFUWA.
+
+2002-08-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/floating_point_test.c
+ Disable testing on machines without lrintf().
+
+ * Win32/Makefile.msvc
+ Added dwd.c and wve.c to build.
+
+ * configure.in
+ Bumped version to 1.0.0.
+
+2002-08-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Add a #include for Mac OS 9. Thanks to Stephane Letz.
+
+ * src/wav.c
+ Changed an snprintf to LSF_SNPRINTF.
+
+ * doc/Makefile.am
+ Added version-1.html.
+
+2002-08-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Bumped version to 1.0.rc6.
+
+ * src/*.c
+ Modified scaling of normalised floats and doubles to integers. Until now
+ this has been done by multiplying by 0x8000 for short output, 0x80000000
+ for 32 bit ints and so on. Unfortunately this can cause an overflow and
+ wrap around in the target value. All thes values have therefore been
+ reduced to 0x7FFF, 0x7FFFFFFF and so on. The conversion from ints to
+ normalised floats and doubles remains unchanged. This does mean that for
+ repeated conversions normalised float -> pcm16 -> normalised float would
+ result in a decrease in amplitude of 0x7FFF/0x8000 on every round trip.
+ This is undesirable but less undesireable than the wrap around I am trying
+ to avoid.
+
+ * tests/floating_point_test.c
+ Removed file hash checking because new float scaling procedure introduced
+ above prevented the ability to crate a has on both x86 and PowerPC systems.
+
+2002-08-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/txw.c
+ Completed reading of TXW files. Seek doesn't work yet.
+
+ * src/file_io.c
+ Added a MacOS 9 replacement for ftruncate().
+
+ * MacOS/sndfile.h
+ Added MacOS 9 header file. This should be copied into src/ to compile
+ libsndfile for MacOS9.
+
+2002-08-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed commands SF_SET_NORM_DOUBLE and SFC_SET_NORM_FLOAT to return their
+ values after being set. Reported by Jussi Laako.
+
+ * configure.in
+ If autogen is not found, touch all .c and .h files in tests/.
+
+ * src/common.c
+ Added format width specifier to psf_log_printf() for %u, %d, %D and %X.
+
+ * src/dwd.c
+ Completed implementation of read only access to these files.
+
+ * src/common.h src/*.c src/pcm.c
+ Removed redundant field chars from SF_PRIVATE struct and modified
+ pcm_init() to do without it.
+
+2002-08-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wve.c
+ New file implementing read of Psion Alaw files. This will be a read only
+ format. Implementation complete.
+
+ * src/dwd/c
+ Started implementation of DiamondWare Digitized files. Also read only, not
+ complete.
+
+ * src/wav.c
+ Add parsing of 'smpl' chunk.
+
+ * src/paf.c
+ Fixed reading on un-normalized doubles and floats from 24 bit PAF files.
+ This brings it into line with the reading of 8 bit files into
+ un-normalized doubles which returns values in the range [-128, 127].
+
+ * src/common.c
+ Modified psf_log_printf() to accept the %% conversion specifier to allow
+ printing of a single '%'.
+
+ * src/sds.c
+ Read only of 16 bit samples is working. Need to build a test harness for
+ this and other read only formats.
+
+2002-08-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Added --enable-experimental configure option.
+ Removed pkg-config message at the end of the configure process.
+
+ * src/sds.c src/txw.c src/rx2.c src/sd2.c
+ Moved all the code in these files inside #if ENABLE_EXPERIMENTAL_CODE
+ blocks and added new *_open() function for the case where experimental is
+ not enabled. These new functions just return SFE_UNIMPLMENTED.
+
+ * Win32/sndfile.h src/sndfile.h.in src/common.h
+ Removed un-necessary #pragma pack commands.
+
+ * src/file_io.c
+ Implemented psf_ftruncate() and much other hacking for Win32.
+
+ * Win32/Makefile.msvc
+ Updated.
+
+ * doc/win32.html
+ Updated to include the copying of the sndfile.h file from the Win32/
+ directory to the src/ directory.
+
+ * Make.bat
+ Batch file to make compiling on Wi32 a little easier. Implements "make" and
+ "make check".
+
+2002-08-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ Add place holder for ftruncate() on Win32 which doesn't have ftruncate().
+ This will need to be fixed later.
+
+ * src/sndfile.h.in
+ New file (copy of sndfile.h) with sets up @TYPEOF_SF_COUNT_T@ which will be
+ replaced by the correct type during configure.
+
+ * configure.in
+ Modified to find a good type for TYPEOF_SF_COUNT_T.
+
+ * src/aiff.c
+ Fixed a bug when reading malformed headers.
+
+ * src/common.c
+ Set read values to zero before performing read.
+
+2002-08-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/command.html
+ Fixed some HTML tags which were not allowing jumps to links within the
+ page.
+
+ * src/sds.c
+ Massive hacking on this.
+
+ * src/wav.c
+ Added recognition of 'clm ' tag.
+
+2002-08-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/index.html
+ Added beginning of a capabilities list beyond simple file formats which
+ can be read/written.
+
+ * src/aiff.c
+ Added parsing of INST and MARK chunks of AIFF files. At the moment this
+ data is simply recorded in the log buffer. Later it will be possible to
+ read this data from an application using sf_command().
+
+ * src/wav.c
+ Added parsing of 'cue ' chunk which contains loop information in WAV files.
+
+ * exampes/sndfile-info.c
+ Changed reporting of Samples to Frames.
+
+ * src/wav.c src/w64.c src/aiff.c src/wav_w64.h
+ Moved from a samples to a frames nomenclature to avoid confusion.
+
+ * doc/FAQ.html
+ What's the best format for storing temporary files?
+
+ * src/sds.c
+ New file for reading/writing Midi Sample Dump Standard files.
+
+ * src/Makefile.am src/sndfile.c src/common.[ch]
+ Added hooks for sds.c.
+
+ * examples/sndfile-info.c
+ Changed from using sf_perror() to using sf_error_str().
+
+2002-08-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/api.html
+ Added explanation of mode parameter for sf_open().
+ Added explanation of usage of SFM_* values in sf_seek().
+
+ * src/sndfile.[ch] src/command.c src/file_io.c src/common.h
+ Implemented SFC_FILE_TRUNCATE to allow a file to be truncated. File
+ truncation was suggested by James McCartney.
+
+ * src/command.html
+ Documented SFC_FILE_TRUNCATE.
+
+ * tests/command_test.c
+ Add tests for SFC_FILE_TRUNCATE.
+
+ * src/sndfile.c
+ Added a thrid parameter to the VALIDATE_SNDFILE_AND_ASSIGN_PSF macro to
+ make resetting the error number optional. All uses of the macro other than
+ in error reporting functions were changed to reset the error number.
+
+ * src/pcm.c
+ Fixed a bug were sf_read_* was logging an SFE_SHORT_READ even when no error
+ occurred.
+
+ * tests/write_read_test.tpl
+ Added tests of internal error state.
+
+2002-08-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/GSM610/private.h src/GSM610/*.c src/GSM610/Makefile.am
+ Renamed private.h to gsm610_priv.h to prevent clash with other headers
+ named private.h in other directories. (Probably only a problem on MacOS 9).
+
+ * src/G72x/private.h src/G72x/*.c src/G72x/Makefile.am
+ Renamed private.h to g72x_priv.h to prevent clash with other headers
+ named private.h in other directories. (Probably only a problem on MacOS 9).
+
+ * MacOS/config.h
+ Changed values of HAVE_LRINT and HAVE_LRINTF to force use of code in
+ float_cash.h.
+
+ * src/sndfile.h
+ Changes the name of samples field of the SF_INFO to frames. The old name
+ had caused too much confusion and it simply had to be changed. There will
+ be at least one more pre-release.
+
+2002-08-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/index.html
+ Updated formats matrix to include RAW (header-less) GSM 6.10.
+ Fix specificaltion of table and spelling mistakes.
+
+ * src/sndfile.c src/command.c
+ Fixed bug in SFC_CALC_MAX_SIGNAL family and psf_calc_signal_max ().
+
+ * tests/command.c
+ Removed cruft.
+ Added test for SFC_CALC_MAX_SIGNAL and SFC_CALC_NORM_MAX_SIGNAL.
+
+ * configure.in
+ Update version to 1.0.0rc5.
+
+ * sfendian.h
+ Removed inclusion of un-necessary header.
+
+2002-08-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Minor fixes of info written to log buffer.
+
+ * src/float_cast.h
+ Add definition of HAVE_LRINT_REPLACEMENT.
+
+ * tests/floating_point_test.c
+ Fix file hash check on systems without lrint/lrintf.
+
+ * tests/dft_cmp.c
+ Limit SNR to less than -500.0dB.
+
+ * examples/sndfile2oct.c
+ Fixed compiler warnings.
+
+ * doc/api.html
+ Fixed error where last parameter of sf_error_str() was sf_count_t instead
+ of size_t.
+
+2002-08-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ Why doesn't libsndfile do interleaving/de-interleaving.
+
+ * tests/pcm_test.tpl
+ On Win32 do not perform hash check on files containing doubles.
+
+2002-08-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Defined SF_COUNT_MAX_POSITIVE() macro, a portable way of setting variables
+ of type sf_count_t to their maximum positive value.
+
+ * src/dwvw.c src/w64.c
+ Used SF_COUNT_MAX_POSITIVE().
+
+2002-07-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/paf.c
+ Fixed bug in reading/writing of 24 bit PCM PAF files on big endian systems.
+
+ * tests/floating_point_tests.c
+ Fixed hash values for 24 bit PCM PAF files.
+ Disabled file has check if lrintf() function is not available and added
+ warning.
+ Decreased level of signal from a peak of 1.0 to a value of 0.95 to prevent
+ problems on platforms without lrintf() ie Solaris.
+
+2002-07-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Fixed a problem with two different kinds of mal-formed WAV file header. The
+ first had the 'fact' chunk before the 'fmt ' chunk, the other had an
+ incomplete 'INFO' chunk at the end of the file.
+
+ * src/w64.c
+ Added fix to allow differentiation between W64 files and ACID files.
+
+ * src/au_g72x.c src/common.h src/sndfile.c
+ Added error for G72x encoded files with more than one channel.
+
+ * tests/pcm_test.tpl tests/utils.tpl
+ Moved function check_file_hash_or_die() to utils.tpl. Function was then
+ modified to calculate the has of the whole file.
+
+ * src/wav.c
+ Fixed problem writing the 'fact' chunk on big endian systems.
+
+ * tests/sfconvert.c
+ Fixed bug where .paf files were being written as Sphere NIST.
+
+2002-07-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/voc.c
+ Fix for reading headers generated using SFC_UPDATE_HEADER_NOW.
+
+ * doc/command.html
+ Add docs for SFC_UPDATE_HEADER_NOW and SFC_SET_UPDATE_HEADER_AUTO.
+
+2002-07-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * man/sndfile-info.1 man/sndfile-play.1
+ Added manpages supplied by Joshua Haberman the Debian maintainer for
+ libsndfile. Additional tweaks by me.
+
+ * configure.in man/Makefile.am
+ Hooked manpages into autoconf/automake system.
+
+ * src/sndfile.c
+ Added hooks for SFC_SET_UPDATE_HEADER_AUTO.
+
+ * tests/update_header_test.c
+ Improved rigor of testing.
+
+ * src/*.c
+ Fixed problem with *_write_header() functions.
+
+2002-07-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/*.html
+ Updates to documentation to fix problems found by wdg-html-validator.
+
+ * src/common.h src/command.c
+ Added normalize parameter to calls to psf_calc_signal_max() and
+ psf_calc_max_all_channels().
+
+ * src/sndfile.c
+ Added handling for commands SFC_CALC_NORM_SIGNAL_MAX and
+ SFC_CALC_NORM_MAX_ALL_CHANNELS.
+
+ * doc/command.html
+ Added entry for SFC_CALC_NORM_SIGNAL_MAX and SFC_CALC_NORM_MAX_ALL_CHANNELS.
+
+2002-07-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c Win32/Makefile.msvc
+ Get sndfile-play program working on Win32. The Win32 PCM sample I/O API
+ sucks. The sndfile-play program now works on Linux, MacOSX, Solaris and
+ Win32.
+
+2002-07-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/FAQ.html
+ New file for frequently asked questsions.
+
+2002-07-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/api.html
+ Documentation fixes.
+
+ * src/au.[ch] src/au_g72x.c src/G72x/g72x.h
+ Add support of 40kbps G723 ADPCM encoding.
+
+ * tests/lossy_comp_test.c tests/floating_point_test.c
+ Add tests for 40kbps G723 ADPCM encoding.
+
+ * doc/index.html
+ Update support matrix.
+
+2002-07-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/command.html
+ Documented SFC_GET_SIMPLE_FORMAT_COUNT, SFC_GET_SIMPLE_FORMAT,
+ SFC_GET_FORMAT_* and SFC_SET_ADD_PEAK_CHUNK.
+
+ * src/sndfile.c src/pcm.c
+ Add ability to turn on and off the addition of a PEAK chunk for floating
+ point WAV and AIFF files.
+
+ * src/sndfile.[ch] src/common.h src/command.c
+ Added sf_command SFC_CALC_MAX_ALL_CHANNELS. Implemented by Maurizio Umberto
+ Puxeddu.
+
+ * doc/command.html
+ Docs for SFC_CALC_MAX_ALL_CHANNELS (assisted by Maurizio Umberto Puxeddu).
+
+2002-07-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/gsm610.c
+ Finalised support for GSM 6.10 AIFF files and added support for GSM 6.10
+ encoded RAW (header-less) files.
+
+ * src/wav.c
+ Add support for IBM_FORMAT_MULAW and IBM_FORMAT_ALAW encodings.
+
+ * src/api.html
+ Fixed more documentation bugs.
+
+2002-07-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h src/common.h
+ Moved some yet-to-be-implelmented values for SF_FORMAT_* from the public
+ header file sndfile.h to the private header file common.h to avoid
+ confusion about the actual capabilities of libsndfile.
+
+2002-07-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c src/wav.c
+ Fixed file parsing for WAV and AIFF files containing non-audio data after
+ the data chunk.
+
+ * src/aiff.c src/sndfile.c
+ Add support for GSM 6.10 encoded AIFF files.
+
+ * tests/lossy_comp_test.c tests/Makefile.am
+ Add tests for GSM 6.10 encoded AIFF files.
+
+ * src/*.c
+ Fix compiler warnings.
+
+2002-07-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/command_test.c
+ For SFC_SET_NORM_* tests, change the file format from SF_FORMAT_WAV to
+ SF_FORMAT_RAW.
+
+ * src/sndfile.c
+ Added sf_command(SFC_TEST_ADD_TRAILING_DATA) to allow testing of reading
+ from AIFF and WAV files with non-audio data after the audio chunk.
+
+ * src/common.h
+ Add test commands SFC_TEST_WAV_ADD_INFO_CHUNK and
+ SFC_TEST_AIFF_ADD_INST_CHUNK. When these commands are working, they will be
+ moved to src/sndfile.h
+
+ * src/aiff.c src/wav.c
+ Begin implementation of XXXX_command() hook for sf_command().
+
+ * tests/write_read_test.tpl
+ Added sf_command (SFC_TEST_ADD_TRAILING_DATA) to ensure above new code was
+ working.
+
+2002-07-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/update_header_test.c
+ Allow read sample count == write sample count - 1 to fix problems with VOC
+ files.
+
+ * tests/write_read_test.tpl tests/pcm_test.tpl
+ Fixed some problems in the test suite discovered by using Valgrind.
+
+2002-07-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/utils.[ch] tests/*.c
+ Renamed check_log_buffer() to check_log_buffer_or_die().
+
+ * src/sndfile.c
+ SFC_UPDATE_HEADER_NOW and SFC_SETUPDATE_HEADER_AUTO almost finished. Works
+ for all file formats other than VOC.
+
+2002-07-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.[ch] src/common.h
+ Started adding functionality to allow the file header to be updated before
+ the file is closed on files open for SFM_WRITE. This was requested by
+ Maurizio Umberto Puxeddu who is using libsndfile for file I/O in iCSound.
+
+ * tests/update_header_test.c
+ New test program to test that the above functionality is working correctly.
+
+ * tests/peak_chunk_test.c tests/floating_point_test.c
+ Cleanups.
+
+2002-07-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sfendian.[ch]
+ Changed length count parameters for all endswap_XXX() functions from
+ sf_count_t (which can be 64 bit even on 32 bit architectures) to int. These
+ functions are only called frin inside the library, are always called with
+ integer parameters and doing the actual calculation on 64 bit values is
+ slow in comparision to doing it on ints.
+
+ * examples/sndfile-play.c
+ More playback hacking for Win32.
+
+2002-07-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ In psf_log_printf(), changed %D format conversion specifier to %M (marker) and
+ added %D specifier for printing the sf_count_t type.
+
+ * src/*.c
+ Changed all usage of psf_log_printf() with %D format conversion specifiers
+ to use %M conversion instead.
+
+ * tests/pcm_test.tpl tests/pcm_test.def
+ New files to autogen pcm_test.c.
+
+ * src/pcm.c
+ Fixed bug in scaling floats and doubles to 24 bit PCM and vice versa.
+
+2002-07-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Fix setup of $ac_cv_sys_largefile_CFLAGS so that sndfile.pc gets valid
+ values for CFLAGS.
+
+ * examples/sndfile-play.c
+ Start adding playback support for Win32.
+
+2002-07-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c
+ Worked to removed compiler warnings.
+ Extensive refactoring.
+
+ * src/common.[ch]
+ Added function psf_memset() which works like the standard C function memset
+ but takes and sf_count_t as the length parameter.
+
+ * src/sndfile.c
+ Replaced calls to memset(0 with calls to psf_memset() as required.
+
+2002-07-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Added "libsndfile : " to the start of all error messages. This was suggested
+ by Conrad Parker author of Sweep ( http://sweep.sourceforge.net/ ).
+
+ * src/sfendian.[ch]
+ Added endswap_XXXX_copy() functions.
+
+ * src/pcm.c src/float32.c src/double64.c
+ Use endswap_XXXX_copy() functions and removed dead code.
+ Cleanups and optimisations.
+
+2002-07-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/sndfile.h
+ Gave values to all the SFC_* enum values to allow better control of the
+ interface as commands are added and removed.
+ Added new command SFC_SET_ADD_PEAK_CHUNK.
+
+ * src/wav.c src/aiff.c
+ Modified wav_write_header and aiff_write_header to make addition of a PEAK
+ chunk optional, even on floating point files.
+
+ * tests/benchmark.tpl
+ Added call to sf_command(SFC_SET_ADD_PEAK_CHUNK) to turn off addition of a
+ PEAK chunk for the benchmark where we are trying to miximize speed.
+
+ * src.pcm.c
+ Changed tribyte typedef to something more sensible.
+ Further conversion speed ups.
+
+2002-07-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/command.c
+ In major_formats rename "Sphere NIST" to "NIST Sphere".
+
+ * src/common.c src/sfendian.c
+ Moved all endswap_XXX_array() functions to sfendian.c. These functions will
+ be tweaked to provide maximum performance. Since maximum performance on one
+ platform does not guarantee maximum performance on another, a small set of
+ functions will be written and the optimal one chosen at compile time.
+
+ * src/common.h src/sfendian.h
+ Declarations of all endswap_XXX_array() functions moved to sfendian.h.
+
+ * src/Makefile.am
+ Add sfendian.c to build targets.
+
+2002-07-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pcm.c src/sfendian.h
+ Re-coded PCM encoders and decoders to match or better the speed of
+ libsndfile version 0.0.28.
+
+2002-06-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Add checking for WAVPACK data in standard PCM WAV file. Return error if
+ found. This WAVPACK is *WAY* broken. It uses the same PCM WAV file header
+ and then stores non-PCM data.
+
+ * tests/benchmark.tpl
+ Added more tests.
+
+2002-06-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/benchmark.tpl
+ Added conditional definition of M_PI.
+ For Win32, set WRITE_PERMS to 0777.
+
+ * Win32/Makefile.msvc
+ Added target to make generate program on Win32.
+
+ * src/samplitude.c
+ Removed handler for Samplitude RAP file format. This file type seems rarer
+ than hens teeth and is completely undocumented.
+
+ * src/common.h src/sndfile.c src/Makefile.am Win32/Makefile.msvc
+ Removed references to sampltiude RAP format.
+
+ * tests/benchmark.tpl
+ Benchmark program now prints the libsndfile version number when run. This
+ program was also backported to version 0 to compare results. Version
+ 1.0.0rc2 is faster than version 0.0.28 on most conversions but slower on
+ some. The slow ones need to be fixed before final release.
+
+2002-06-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/benchmark.def tests/benchmark.tpl
+ New files which generate tests/benchmark.c using Autogen. Added int ->
+ SF_FORMAT_PCM_24 test.
+
+ * tests/benchmark.c
+ Now and Autogen output file.
+
+ * tests/Makefile.am
+ Updated for above changes.
+
+2002-06-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/benchmark.c
+ Basic benchmark program complete. Need to convert it to Autogen.
+
+ * Win32/Makefile.msvc
+ Added benchmark.exe target.
+
+2002-06-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/generate.c
+ New program to generate a number of different output file formats from a
+ single input file. This allows testing of the created files.
+
+ * tests/benchmark.c
+ New test program to benchmark libsndfile. Nowhere near complete yet.
+
+ * examples/Makefile.am tests/Makefile.am
+ New make rules for the two new programs.
+
+2002-06-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/libsndfile.def
+ Removed definition for sf_signal_max().
+
+ * src/sndfile.c
+ Removed cruft.
+
+ * doc/index.html
+ A number of documentation bugs were fixed. Thanks to Anand Kumria.
+
+ * doc/version-1.html
+ Minor doc updates.
+
+ * configure.in
+ Bumped version to 1.0.0rc2.
+
+ * src/sf_command.h src/Makefile.am
+ Removed the header file as it was no longer being used. Thanks to Anand
+ Kunria for spotting this.
+
+ * doc/index.html
+ A number of documentation bugs were fixed. Thanks to Anand Kumria.
+
+2002-06-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Test for Win32 before testing SIZEOF_OFF_T so that it works correctly
+ on Win32..
+
+ * src/file_io.c
+ Win32 fixes to ensure O_BINARY is used for file open.
+
+ * doc/win32.html
+ New file documenting the building libsndfile on Win32.
+
+ * doc/*.html
+ Updating of documentation.
+
+2002-06-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/pcm_test.c
+ Minor changes to allow easier determination of test file name.
+
+ * src/sndfile.[ch]
+ Removed function sf_signal_max().
+
+ * examples/sndfile-play.c
+ Changed call to sf_signal_max() to a call to sf_command().
+
+2002-06-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/format.c src/command.c
+ Renamed format.c to command.c which will now include code for sf_command()
+ calls to perform operations other than format commands.
+
+ * src/sndfile.c src/sndfile.h
+ Removed function sf_get_signal_max() which is replaced by commands passed
+ to sf_command().
+
+ * src/command.c
+ Implement commands SFC_CALC_SIGNAL_MAX.
+
+ * doc/command.html
+ Documented SFC_CALC_SIGNAL_MAX.
+
+2002-06-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-play.c
+ Mods to make sndfile-play work on Solaris. The program sndfile-play now
+ runs on Linux, MaxOSX and Solaris. Win32 to come.
+
+ * src/format.c
+ Added SF_FORMAT_DWVW_* to subtype_formats array.
+
+ * src/nist.c
+ Added support for 8 bit NIST Sphere files. Example file supplied by Anand
+ Kumria.
+
+2002-06-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sndfile-info.c
+ Tidy up of output format.
+
+ * examnples/sndfile-play.c
+ Mods to make sndfile-play work on MacOSX using Apple's CoreAudio API.
+
+ * configure.in
+ Add new variables OS_SPECIFIC_INCLUDES and OS_SPECIFIC_LINKS which were
+ required to supply extra include paths and link parameters to get
+ sndfile-play working on MacOSX.
+
+ * examples/Makefile.am
+ Use OS_SPOECIFIC_INCLUDES and OS_SPECIFIC_LINKS to build commands for
+ sndfile-play.
+
+2002-06-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/nist.c
+ Added ability to read/write new NIST Sphere file types (A-law, u-law).
+ Header parser was re-written from scratch. Example files supplied by Anand
+ Kumria.
+
+ * src/sndfile.c
+ Support for A-law and u-law NIST files.
+
+ * tests/Makefile.am tests/lossy_comp_test.c
+ Tests for A-law and u-law NIST files.
+
+2002-06-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/utils.c
+ Fixed an error in error string.
+
+2002-06-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * acinclude.m4
+ Removed exit command to allow cross-compiling.
+
+ * Win32/unistd.h src/file_io.c
+ Moved contents of first file into the second file (enclosed in #ifdef).
+ Win32/unistd.h is now an empty file but still must be there for libsndfile
+ to compile on Win32.
+
+ * src/sd2.c, src/sndfile.c:
+ Fixes for Sound Designer II files on big endian systems.
+
+2002-06-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Modified to work around problems with crappy MacOSX version of sed.
+ Added sanity check for proper values for CFLAGS.
+
+2002-06-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Code clean up in sf_open ().
+
+ * Win32/Makefile.msvc
+ Michael Fink's contributed MSVC++ makefile was hacked to bits and put back
+ together in a new improved form.
+
+ * src/file_io.c
+ Fixes for Win32; _lseeki64() returns an invalid argument for calls like
+ _lseeki64(fd, 0, SEEK_CUR) so need to use _telli64 (fd) instead.
+
+ * src/common.h src/sndfile.c src/wav.c src/aiff.c
+ Added SFE_LOG_OVERRUN error.
+ Added termination for potential infinite loop when parsing file headers.
+
+ * src/wav.c src/w64.c
+ Fixed bug casuing incorrect header generation when opening file read/write.
+
+2002-06-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/api.html
+ Improved the documentation to make it clearer that the file read method
+ and the underlying file format are completely disconnected. Suggested
+ by Josh Green.
+
+ * doc/command.html
+ Started correcting docs to take into account changes made to the
+ operations of the sf_command () function. Not complete yet.
+
+ * src/sndfile.c
+ Reverted some changes which had broken the partially working SDII header
+ parsing. Now have access to an iBook with OS X so reading and writing SDII
+ files on all platforms should be a reality in the near future. On Mac this
+ will involve reading the resource fork via the standard MacOS API. To move
+ a file from Mac to another OS, the resource and data forks will need to be
+ combined before transfer. The combined file will be read on both Mac and
+ other OSes like any other file.
+
+2002-06-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * ltmain.sh
+ Applied a patch from http://fink.sourceforge.net/doc/porting/libtool.php
+ which allows libsndfile to compile on MacOSX 10.1. This patch should not
+ interfere with compiling on other OSes.
+
+ * src/GSM610/private.h
+ Changes to fix compile problems on MacOSX (see src/GSM610/ChangeLog).
+
+ * src/float_cast.h
+ Added MacOSX replacements for lrint() and lrintf().
+
+2002-06-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Replaced the code to print the filename to the log buffer when a file is
+ opened. This code seems to have been left out during the merge of
+ sf_open_read() and sf_open_write() to make a single functions sf_open().
+
+2002-06-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Fixed a bug where the WAV header parser was going into an infinite loop
+ on a badly formed LIST chunk. File supplied by David Viens.
+
+2002-05-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Added a message at the end of the configuration process to warn about the
+ need for the use of pkg-config when linking programs against version 1 of
+ libsndfile.
+
+ * doc/pkg-config.html
+ New documentation file containing details of how to use pkg-config to
+ retrieve settings for CFLAGS and library locations for linking files
+ against version 1 of libsndfile.
+
+2002-05-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Fixed minor bug in handling of so-called ACIDized WAV files.
+
+2002-05-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/libsndfile.def Win32/Makefile.msvc
+ Two new files contributed by Michael Fink (from the winLAME project)
+ which allows libsndfile to be built on windows in a MSDOS box by doing
+ "nmake -f Makefile.msvc". Way cool!
+
+2002-05-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ MacOSX is SSSOOOOOOO screwed up!!! I can't believe how hard it is to
+ generate a tarball which will configure and compile on that platform.
+ Joined the libtool mailing list to try and get some answers.
+
+2002-05-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Changed to autoconf version 2.50. MacOSX uses autoconf version 2.53 which
+ is incompatible with with version 2.13 which had been using until now.
+ The AC_SYS_LARGE_FILE macro distributed withe autoconf 2.50 is missing a
+ few features so AC_SYS_EXTRA_LARGE file was defined to replace it.
+
+ * configure.in
+ Changed to automake version 1.5 to try and make a tarball which will
+ work on MacOSX.
+
+2002-05-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_gsm610.c
+ Changed name to gsm610.c. Added reading/writing of headerless files.
+
+ * src/sndfile.c src/raw.c
+ Added ability to read/write headerless (SF_FORMAT_RAW) GSM 6.10 files.
+
+2002-05-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/lossy_comp_test.c
+ Clean up in preparation for Autogen-ing this file.
+
+ * src/GSM610/*.[ch]
+ Code cleanup and prepartion forgetting file seek working. Details in
+ src/GSM610/ChangeLog.
+
+ * sndfile.pc.in
+ Testing complete. Is sndfile.m4 still needed?
+
+2002-05-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.tpl tests/rdwr_test.tpl
+ Merged tests from these two programs into write_read_test.tpl and deleted
+ rdwr_test.tpl.
+
+2002-05-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/w64.c src/svx.c src/paf.c
+ Fixed bugs in read/write mode.
+
+2002-05-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/Makefile.am
+ Renamed sfplay.c to sndfile-play.c and sndfile_info.c to sndfile-info.c for
+ consistency when these programs become part of the Debian package
+ sndfile-programs.
+
+ * sndfile.pc.in
+ New file to replace sndfile-config.in. Libsndfile now uses the pkg-config
+ model for providing installation parameters to dependant programs.
+
+ * src/sndfile.c
+ Cleanup of code in sf_open().
+
+2002-05-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/utils.tpl tests/write_read_test.tpl
+ More conversion to Autogen fixes and enchancements.
+
+ * src/*.c
+ Read/write mode is now working for 16, 24 and 32 bit PCM as well as 32
+ bit float and 64 bit double data. More tests still required.
+
+ * src/Makefile.am
+ Added DISTCLEANFILES target to remove config.status and config.last.
+
+ * Win32/Makefile.am MacOS/Makefile.am
+ Added DISTCLEANFILES target to remove Makefile.
+
+2002-05-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.[ch] tests/rdwr_test.c
+ More verifying workings of read/write mode. Fixing bugs found.
+
+ * tests/utils.[ch]
+ Made these files Autogen generated files.
+
+ * tests/util.tpl tests/util.def
+ New Autogen files to generate utils.[ch]. Moved some generic test functions
+ into this file. Autogen is such a great tool!
+
+2002-05-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pcm.c src/float_cast.h Win32/config.h
+ Fixed a couple of Win32 specific bugs pointed out by Michael Fink
+ (maintainer of WinLAME) and David Viens.
+
+ * tests/check_log_buffer.[ch] tests/utils.[ch]
+ Moved check_log_buffer() to utils.[ch] and deleted old file.
+
+2002-05-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.[ch] src/sndfile.c
+ New function psf_default_seek() which will be the default seek function
+ for things like PCM and floating point data. This default is set for
+ both read and write in sf_open() but can be over-ridden by any codec
+ during it's initialisation.
+
+2002-05-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/au.c
+ AU files use a data size value of -1 to mean unknown. Fixed au_open_read()
+ to allow opening files like this.
+
+ * tests/rdwr_test .c
+ Added more tests.
+
+ * src/sndfile.c
+ Fixed bugs in read/write mode found due to improvements in the test
+ program.
+
+2002-04-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/rdwr_test .c
+ New file for testing read/write mode.
+
+2002-04-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * m4/*
+ Removed all m4 macros from this directory as they get concatenated to form
+ the file aclocal.m4 anyway.
+
+ * sndfile.m4
+ Moved this from the m4 directory to the root directory asn this is part of
+ the distribution and is installed during "make install".
+
+2002-04-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/float32.c
+ Removed logging of peaks for all file formats other than AIFF and WAV.
+
+ * tests/write_read_test.tpl tests/write_read_test.def
+ New files which autogen uses to generate write_read_test.c. Doing it this
+ way makes write_read_test.c far easier to maintain. Other test programs
+ will be converted to autogen in the near future.
+
+ * src/*.c
+ Fixed a few bugs found when testing on Sparc (bug endian) Solaris.
+
+2002-04-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * doc/*.html
+ Fixed documention versioning.
+
+ * configure.in
+ Fixed a bug in the routines which search for Large File Support on systems
+ which have large file support by defualt.
+
+2002-04-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.[ch]
+ Found and fixed an issue which can cause a bug in other software (I was
+ porting Conrad Parker's Sweep program from version 0 of the library to
+ version 1). When opening a file for write, the libsndfile code would
+ set the sfinfo.samples field to a maximum value.
+
+ * tests/write_read_test.c
+ Added tests to detect the above problem.
+
+2002-04-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.[ch]
+ Finished base implementation of read/write mode. Much more testing still
+ needed.
+
+ * m4/largefile.m4
+ Macro for detecting Large File Standard capabilities. This macro was ripped
+ out of the aclocal.m4 file of GNU tar-1.13.
+
+ * configure.in
+ Added detection of large file support. Files larger than 2 Gigabytes should
+ now be supported on 64 bit platforms and many 32 bit platforms including
+ Linux (2.4 kernel, glibc-2.2), *BSD, MacOS, Win32.
+
+ * libsndfile_convert_version.py
+ A Python script which attempts to autoconvert code written to use version 0
+ to version 1.
+
+2002-04-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.[ch]
+ Finished base implementation of read/write mode. Much more testing still
+ needed.
+
+ * tests/write_read_test.c
+ Preliminary tests for read/write mode added. More needed.
+
+2002-04-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.[ch]
+ Removed sf_open_read() and sf_open_write() functions,replacting them with
+ sf_open() which takes an extra mode parameter (SF_OPEN_READ, SF_OPEN_WRITE,
+ or SF_OPEN_RDWR). This new function sf_open can now be modified to allow
+ opening a file formodification (RDWR).
+
+2002-04-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c
+ Completed merging of separate xxx_open_read() and xxx_open_write()
+ functions. All tests pass.
+
+2002-04-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/au.c
+ Massive refactoring required to merge au_open_read() with au_open_write()
+ to create au_open().
+
+2002-04-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c
+ Started changes required to allow a sound file to be opened in read/write
+ mode, with separate file pointers for read and write. This involves merging
+ of encoder/decoder functions like pcm_read_init() and pcm_write_init()
+ int a new function pcm_init() as well as doing something similar for all
+ the file type specific functions ie aiff_open_read() and aiff_open_write()
+ were merged to make the function aiff_open().
+
+2002-04-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/file_io.c
+ New file containing psf_fopen(), psf_fread(), psf_fwrite(), psf_fseek() and
+ psf_ftell() functions. These function will replace use of fopen/fread/fwrite
+ etc and allow access to files larger than 2 gigabytes on a number of 32 bit
+ OSes (Linux on x86, 32 bit Solaris user space apps, Win32 and MacOS).
+
+ * src/*.c
+ Replaced all instances of fopen with psf_open, fread with psd_read, fwrite
+ with psf_write and so on.
+
+2002-03-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/dwvw.c
+ Finally fixed all known problems with 12, 16 and 24 bit DWVW encoding.
+
+ * tests/floating_point_test.c
+ Added tests for 12, 16 and 24 bit DWVW encoding.
+
+2002-03-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * m4/endian.m4
+ Defines a new m4 macro AC_C_FIND_ENDIAN, for determining the endian-ness of
+ the target CPU. It first checks for the definition of BYTE_ORDER in
+ <endian.h>, then in <sys/types.h> and <sys/param.h>. If none of these work
+ and the C compiler is not a cross compiler it compiles and runs a program
+ to test for endian-ness. If the compiler is a cross compiler it makes a
+ guess based on $target_cpu.
+
+ * configure.in
+ Modified to use AC_C_FIND_ENDIAN.
+
+ * src/sfendian.h
+ Simplified.
+
+2002-02-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/floating_point_test.c
+ Tests completely rewritten using the dft_cmp function. Now able to
+ calculate a quick guesstimate of the Signal to Noise Ratio of the encoder.
+
+2002-02-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/dft_cmp.[ch]
+ New files containing functions for comparing pre and post lossily
+ compressed data using a quickly hacked DFT.
+
+ * tests/utils.[ch]
+ New files containing functions for saving pre and post encoded data in a
+ file readable by the GNU Octave package.
+
+2002-02-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * m4/lrint.m4 m4/lrintf.m4
+ Fixed m4 macros to define HAVE_LRINT and HAVE_LRINTF even when the test
+ is cached.
+
+2002-02-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/floating_point_test.c
+ Fixed improper use of strncat ().
+
+2002-02-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/headerless_test.c
+ New test program to test the ability to open and read a known file type as a
+ RAW header-less file.
+
+2002-02-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/losy_comp_test.c
+ Added a test to ensure that the data read from a file is not all zeros.
+
+ * examples/sfconvert.c
+ Added "-gsm610" encoding types.
+
+2002-01-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sfconvert.c
+ Added "-dwvw12", "-dwvw16" and "-dwvw24" encoding types.
+
+ * tests/dwvw_test.c
+ New file for testing DWVW encoder/decoder.
+
+2002-01-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/dwvw.c
+ Implemented writing of DWVW. 12 bit seems to work, 16 and 24 bit still broken.
+
+ * src/aiff.c
+ Improved reporting of encoding types.
+
+ * src/voc.c
+ Clean up.
+
+2002-01-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/dwvw.c
+ New file implementing lossless Delta Word Variable Width (DWVW) encoding.
+ Reading 12 bit DWVW is now working.
+
+ * src/aiff.c common.h sndfile.c
+ Added hooks for DWVW encoded AIFF and RAW files.
+
+2002-01-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/w64.c
+ Robustify header parsing.
+
+ * src/wav_w64.h
+ Header file wav.h was renamed to wav_w64.h to signify sharing of
+ definitions across the two file types.
+
+ * src/wav.c src/w64.c src/wav_w64.c
+ Refactoring.
+ Modified and moved functions with a high degree of similarity between
+ wav.c and w64.c to wav_w64.c.
+
+2002-01-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/w64.c
+ Completed work on getting read and write working.
+
+ * examples/sfplay.c
+ Added code to scale floating point data so it plays at a reasonable volume.
+
+ * tests/Makefile.am tests/write_read_test.c
+ Added tests for W64 files.
+
+2002-01-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c
+ Modded all code in file header writing routines to use
+ psf_new_binheader_writef().
+ Removed psf_binheader_writef() from src/common.c.
+ Globally replaced psf_new_binheader_writef with psf_binheader_writef.
+
+2002-01-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c
+ Modded all code in file parsing routines to use psf_new_binheader_readf().
+ Removed psf_binheader_readf() from src/common.c.
+ Globally replaced psf_new_binheader_readf with psf_binheader_readf.
+
+ * src/common.[ch]
+ Added new function psf_new_binheader_writef () which will soon replace
+ psf_binheader_writef (). The new function has basically the same function
+ as the original but has a more flexible and capable interface. It also
+ allows the writing of 64 bit integer values for files contains 64 bit file
+ offsets.
+
+2002-01-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/formats.c src/sndfile.c src/sndfile.h
+ Added code allowing full enumeration of supported file formats via the
+ sf_command () interface.
+ This feature will allow applications to avoid needing recompilation when
+ support for new file formats are added to libsndfile.
+
+ * tests/command_test.c
+ Added test code for the above feature.
+
+ * examples/list_formats.c
+ New file. An example of the use of the supported file enumeration
+ interface. This program lists all the major formats and for each major
+ format the supported subformats.
+
+2002-01-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.[ch] tests/*.c
+ Changed command parameter of sf_command () function from a test string to
+ an int. The valid values for the command parameter begin with SFC_ and are
+ listed in src/sndfile.h.
+
+2001-12-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/formats.c src/sndfile.c
+ Added an way of enumerating a set of common file formats using the
+ sf_command () interface. This interface was suggested by Dominic Mazzoni,
+ one of the main authors of Audacity (http://audacity.sourceforge.net/).
+
+2001-12-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Added checking of filename parameter in sf_open_read (). Previousy, if a
+ NULL pointer was passed the library would segfault.
+
+2001-12-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c src/common.h
+ Changed the len parameter of the endswap_*_array () functions from type
+ int to type long.
+
+ * src/pcm.c
+ Fixed a problem which
+
+2001-12-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Added conditional #include <sys/types.h> for EMX/gcc on OS/2. Thanks to
+ Paul Hartman for pointing this out.
+
+ * tests/lossy_comp_test.c tests/floating_point_test.c
+ Added definitions for M_PI for when it isn't defined in <math.h>.
+
+2001-11-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/ircam.c
+ Re-implemented the header reader. Old version was making incorrect
+ assumptions about the endian-ness of the file from the magic number at the
+ start of the file. The new code looks at the integer which holds the
+ number of channels and determines the endian-ness from that.
+
+2001-11-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Added support for other AIFC types ('raw ', 'in32', '23ni').
+ Further work on IMA ADPCM encoding.
+
+2001-11-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/ima_adpcm.c
+ Renamed from wav_ima_adpcm.c. This file will soon handle IMA ADPCM
+ encodings for both WAV and AIFF files.
+
+ * src/aiff.c
+ Started adding IMA ADPCM support.
+
+2001-11-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/double.c
+ New file for handling double precision floating point (SF_FORMAT_DOUBLE)
+ data.
+
+ * src/wav.c src/aiff.c src/au.c src/raw.c
+ Added support for SF_FORMAT_DOUBLE data.
+
+ * src/common.[ch]
+ Addition of endswap_long_array () for endian swapping 64 bit integers. This
+ function will work correctly on processors with 32 bit and 64 bit longs.
+ Optimised endswap_short_array () and endswap_int_array ().
+
+ * tests/pcm_test.c
+ Added and extra check. After the first file of each type is written to disk
+ a checksum is performed of the first 64 bytes and checked against a pre-
+ calculated value. This will work whatever the endian-ness of the host
+ machine.
+
+2001-11-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Added handling of u-law, A-law encoded AIFF files. Thanks to Tom Erbe for
+ supplying example files.
+
+ * tests/lossy_comp_test.c
+ Added tests for above.
+
+ * src/common.h src/*.c
+ Removed function typedefs from common.h and function pointer casting in all
+ the other files. This allows the compiler to perform proper type checking.
+ Hopefully this will prevernt problems like the sf_seek bug for OpenBSD,
+ BeOS etc.
+
+ * src/common.[ch]
+ Added new function psf_new_binheader_readf () which will eventually replace
+ psf_binheader_readf (). The new function has basically the same function as
+ the original but has a more flexible and capable interface. It also allows
+ the reading of 64 bit integer values for files contains 64 bit file
+ offsets.
+
+2001-11-26 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/voc.c
+ Completed implementation of VOC file handling. Can now handle 8 and 16 bit
+ PCM, u-law and A-law files with one or two channels.
+
+ * src/write_read_test.c tests/lossy_comp_test.c
+ Added tests for VOC files.
+
+2001-11-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/float_cast.h
+ Added inline asm version of lrint/lrintf for MacOS. Solution provided by
+ Stephane Letz.
+
+ * src/voc.c
+ More work on this braindamaged format. The VOC files produced by SoX also
+ have a number of inconsistencies.
+
+2001-11-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/paf.c
+ Added support for 8 bit PCM PAF files.
+
+ * tests/write_read_test.c
+ Added tests for 8 bit PAF files.
+
+2001-11-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/pcm_test.c
+ New test program to test for correct scaling of integer values between
+ different sized integer containers (ie short -> int).
+ The new specs for libsndfile state that when the source and destination
+ containers are of a different size, the most significant bit of the source
+ value becomes the most significant bit of the destination container.
+
+ * src/pcm.c src/paf.c
+ Modified to pass the above test program.
+
+ * tests/write_read_test.c tests/lossy_comp_test.c
+ Modified to work with the new scaling rules.
+
+2001-11-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/raw.c tests/write_read_test.c tests/write_read_test.c
+ Added ability to do raw reads/writes of float, u-law and A-law files.
+
+ * src/*.[ch] examples/*.[ch] tests/*.[ch]
+ Removed dependance on pcmbitwidth field of SF_INFO struct and moved to new
+ SF_FORMAT_* types and use of SF_ENDIAN_BIG/LITTLE/CPU.
+
+2001-11-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.[ch]
+ Started implmentation of major changes documented in doc/version1.html.
+
+ Removed all usage of off_t which is not part of the ISO C standard. All
+ places which were using it are now using type long which is the type of
+ the offset parameter for the fseek function.
+ This should fix problems on BeOS, MacOS and *BSD like systems which were
+ failing "make check" because sizeof (long) != sizeof (off_t).
+
+--------------------------------------------------------------------------------
+This is the boundary between version 1 of the library above and version 0 below.
+--------------------------------------------------------------------------------
+
+2001-11-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sfplay_beos.cpp
+ Added BeOS version of sfplay.c. This needs to be compiled using a C++
+ compiler so is therefore not built by default. Thanks to Marcus Overhagen
+ for providing this.
+
+2001-11-10 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sfplay.c
+ New example file showing how libsndfile can be used to read and play a
+ sound file.
+ At the moment on Linux is supported. Others will follow in the near future.
+
+2001-11-09 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pcm.c
+ Fixed problem with normalisation code where a value of 1.0 could map to
+ a value greater than MAX_SHORT or MAX_INT. Thanks to Roger Dannenberg for
+ pointing this out.
+
+2001-11-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pcm.c
+ Fixed scaling issue when reading/writing 8 bit files using
+ sf_read/sf_write_short ().
+ On read, values are scaled so that the most significant bit in the char
+ ends up in the most significant bit of the short. On write, values are
+ scaled so that most significant bit in the short ends up as the most
+ significant bit in the char.
+
+2001-11-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/au.c src/sndfile.c
+ Added support for 32 bit float data in big and little endian AU files.
+
+ * tests/write_read_test.c
+ Added tests for 32 bit float data in AU files.
+
+2001-11-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/lossy_comp_test.c
+ Finalised testing of stereo files where possible.
+
+2001-11-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_ms_adpcm.c
+ Fixed bug in writing stereo MS ADPCM WAV files. Thanks to Xu Xin for
+ pointing out this problem.
+
+2001-10-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_ms_adpcm.c
+ Modified function srate2blocksize () to handle 44k1Hz stereo files.
+
+2001-10-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/w64.c
+ Added support for Sonic Foundry 64 bit WAV format. As Linux (my main
+ development platform) does not yet support 64 bit file offsets by default,
+ current handling of this file format treats everything as 32 bit and fails
+ openning the file, if it finds anything that goes beyond 32 bit values.
+
+ * src/sndfile.[hc] src/common.h src/Makefile.am
+ Added hooks for W64 support.
+
+2001-10-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Added more warnings options to CFLAGS when the gcc compiler is detected.
+
+ * src/*.[ch] tests/*.c examples/*.c
+ Started fixing the warning messages due to the new CFLASG.
+
+ * src/voc.c
+ More work on VOC file read/writing.
+
+ * src/paf.c
+ Found that PAF files were not checking the normalisation flag when reading
+ or writing floats and doubles. Fixed it.
+
+ * tests/floating_point_test.c
+ Added specific test for the above problem.
+
+ * src/float_cast.h src/pcm.c
+ Added a section for Win32 to define lrint () and lrintf () in the header
+ and implement it in the pcm.c
+
+2001-10-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * sndfile-config.in m4/sndfile.m4
+ These files were donated by Conrad Parker who also provided instructions
+ on how to install them using autoconf/automake.
+
+ * src/float_cast.h
+ Fiddled around with this file some more. On Linux and other gcc supported
+ OSes use the C99 functions lrintf() and lrint() for casting from floating
+ point to int without incurring the huge perfromance penalty (particularly
+ on the i386 family) caused by the regular C cast from float to int.
+ These new C99 functions replace the FLOAT_TO_* and DOUBLE_TO_* macros which
+ I had been playing with.
+
+ * configure.in m4/lrint.m4 m4/lrintf.m4
+ Add detection of these functions.
+
+2001-10-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/voc.c
+ Completed code for reading VOC files containing a single audio data
+ segment.
+ Started implementing code to handle files with multiple VOC_SOUND_DATA
+ segments but couldn't be bothered finishing it. Multiple segment files can
+ have different sample rates for different sections and other nasties like
+ silence and repeat segments.
+
+2001-10-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h src/*.c
+ Removed SF_PRIVATE struct field fdata and replaced it with extra_data.
+
+ * src/voc.c
+ Further development of the read part of this woefult file format.
+
+2001-10-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/float_cast.h
+ Implemented gcc and i386 floating point to int cast macros. Standard cast
+ will be used when not on gcc for i385.
+
+ * src/pcm.c
+ Modified all uses of FLOAT/DOUBLE_TO_INT and FLOAT/DOUBLE_TO_SHORT casts to
+ comply with macros in float_cast.h.
+
+2001-10-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/voc.c
+ Changed the TYPE_xxx enum names to VOC_TYPE_xxx to prevent name clashes
+ on MacOS with CodeWarrior 6.0.
+
+ * MacOS/MacOS-readme.txt
+ Updated the compile instructions. Probably still need work as I don't have
+ access to a Mac.
+
+2001-10-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c src/aiff.c common.c
+ Changed all references to snprintf to LSF_SNPRINTF and all vsnprintf to
+ LSF_VSNPRINTF. LSF_VSNPRINTF and LSF_VSNPRINTF are defined in common.h.
+
+ * src/common.h
+ Added checking of HAVE_SNPRINTF and HAVE_VSNPRINTF and defining
+ LSF_VSNPRINTF and LSF_VSNPRINTF to appropriate values.
+
+ * src/missing.c
+ New file containing a minimal implementation of snprintf and vsnprintf
+ functions named missing_snprintf and missing_vsnprintf respectively. These
+ are only compliled into the binary if snprintf and/or vsnprintf are not
+ available.
+
+2001-09-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/ircam.c
+ New file to handle Berkeley/IRCAM/CARL files.
+
+ * src/sndfile.c src/common.h
+ Modified for IRCAM handling.
+
+ * tests/*.c
+ Added tests for IRCAM files.
+
+2001-09-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Apparently microsoft windows (tm) doesn't like ulaw and Alaw WAV files with
+ 20 byte format chunks (contrary to ms's own documentation). Fixed the WAV
+ header writing code to generate smaller ms compliant ulaw and Alaw WAV
+ files.
+
+2001-09-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/stdio_test.sh tests/stdio_test.c
+ Shell script was rewritten as a C program due to incompatibilities of the
+ sh shell on Linux and Solaris.
+
+2001-09-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/stdio_test.sh tests/stdout_test.c tests/stdin_test.c
+ New test programs to verify the correct operation of reading from stdin and
+ writing to stdout.
+
+ * src/sndfile.c wav.c au.c nist.c paf.c
+ Fixed a bugs uncovered by the new test programs above.
+
+2001-09-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c wav.c
+ Fixed a bug preventing reading a file from stdin. Found by T. Narita.
+
+2001-09-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Fixed a problem on OpenBSD 2.9 which was causing sf_seek() to fail on IMA
+ WAV files. Root cause was the declaration of the func_seek typedef not
+ matching the functions it was actually being used to point to. In OpenBSD
+ sizeof (off_t) != sizeof (int). Thanks to Heikki Korpela for allowing me
+ to log into his OpenBSD machine to debug this problem.
+
+2001-09-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Implemented sf_command ("norm float").
+
+ * src/*.c
+ Implemented handling of sf_command ("set-norm-float"). Float normalization
+ can now be turned on and off.
+
+ * tests/double_test.c
+ Renamed to floating_point_test.c. Modified to include tests for all scaled
+ reads and writes of floats and doubles.
+
+ * src/au_g72x.c
+ Fixed bug in normalization code found with improved floating_point_test
+ program.
+
+ * src/wav.c
+ Added code for parsing 'INFO' and 'LIST' chunks. Will be used for extract
+ text annotations from WAV files.
+
+ * src/aiff.c
+ Added code for parsing '(c) ' and 'ANNO' chunks. Will be used for extract
+ text annotations from WAV files.
+
+2001-09-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sf_info.c example/Makefile.am
+ Renamed to sndfile_info.c. The program sndfile_info will now be installed
+ when the library is installed.
+
+ * src/float_cast.h
+ New file defining floating point to short and int casts. These casts will
+ eventually replace all flot and double casts to short and int. See comments
+ at the top of the file for the reasoning.
+
+ * src/*.c
+ Changed all default float and double casts to short or int with macros
+ defined in floatcast.h. At the moment these casts do nothing. They will be
+ replaced with faster float to int cast operations in the near future.
+
+2001-08-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/command_test.c
+ New file for testing sf_command () functionality.
+
+ * src/sndfile.c
+ Revisiting of error return values of some functions.
+ Started implementing sf_command () a new function will allow on-the-fly
+ modification of library behaviour, or instance, sample value scaling.
+
+ * src/common.h
+ Added hook for format specific sf_command () calls to SNDFILE struct.
+
+ * doc/api.html
+ Updated and errors corrected.
+
+ * doc/command.html
+ New documentation file explaining new sf_command () function.
+
+2001-08-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed error return values from sf_read*() and sf_write*(). There were
+ numerous instances of -1 being returned through size_t. These now all set
+ error int the SF_PRIVATE struct and return 0. Thanks to David Viens for
+ spotting this.
+
+2001-08-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Fixed use of va_arg() calls that were causing warning messages with the
+ latest version of gcc (thanks Maurizio Umberto Puxeddu).
+
+2001-07-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c src/sfendian.h
+ Moved definition of MAKE_MARKER macro to sfendian.h
+
+2001-07-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Modified sf_get_lib_version () so that version string will be visible using
+ the Unix strings command.
+
+ * examples/Makefile.am examples/sfinfo.c
+ Renamed sfinfo program and source code to sf_info. This prevents a name
+ clash with the program included with libaudiofile.
+
+2001-07-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/read_seek_test.c tests/lossy_comp_test.c
+ Added tests for sf_read_float () and sf_readf_float ().
+
+ * src/voc.c
+ New files for handling Creative Voice files (not complete).
+
+ * src/samplitude.c
+ New files for handling Samplitude files (not complete).
+
+2001-07-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c src/au.c src/paf.c src/svx.c src/wav.c
+ Converted these files to using psf_binheader_readf() function. Will soon be
+ ready to attempt to make reading writing from pipes work reliably.
+
+ * src/*.[ch]
+ Added code for sf_read_float () and sf_readf_float () methods of accessing
+ file data.
+
+2001-07-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/paf.c src/wav_gsm610.c
+ Removed two printf()s which had escaped notice for some time (thanks
+ Sigbjørn Skjæret).
+
+2001-07-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_gsm610.c
+ Fixed a bug which prevented GSM 6.10 encoded WAV files generated by
+ libsndfile from being played in Windoze (thanks klay).
+
+2001-07-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.[ch]
+ Implemented psf_binheader_readf() which will do for file header reading what
+ psf_binheader_writef() did for writing headers. Will eventually allow
+ libsndfile to read and write from pipes, including named pipes.
+
+2001-07-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * MacOS/config.h Win32/config.h
+ Attempted to bring these two files uptodate with src/config.h. As I don't
+ have access to either of these systems support for them may be completely
+ broken.
+
+2001-06-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/float32.c
+ Fixed bug for big endian processors that can't read 32 bit IEEE floats. Now
+ tested on Intel x86 and UltraSparc processors.
+
+2001-06-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Modified to allow REX files (from Propellorhead's Recycle and Reason
+ programs) to be read.
+ REX files are basically an AIFF file with slightly unusual sequence of
+ chunks (AIFF files are supposed to allow any sequence) and some extra
+ application specific information.
+ Not yet able to write a REX file as the details of the application specific
+ data is unknown.
+
+2001-06-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Fixed endian bug when reading PEAK chunk on big endian machines.
+
+ * src/common.c
+ Fixed endian bug when reading PEAK chunk on big endian machines with
+ --enable-force-broken-float configure option.
+ Fix psf_binheader_writef for (FORCE_BROKEN_FLOAT ||______)
+
+2001-06-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in src/config.h.in
+ Removed old CAN_READ_WRITE_x86_IEEE configure variable now that float
+ capabilities are detected at run time.
+ Added FORCE_BROKEN_FLOAT to allow testing of broken float code on machines
+ where the processor can in fact handle floats correctly.
+
+ * src/float32.c
+ Rejigged code reading and writing of floats on broken processors.
+
+ * m4/
+ Removed this directory and all its files as they are no longer needed.
+
+2001-06-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/peak_chunk_test.c
+ New test to validate reading and writing of peak chunk.
+
+ * examples/sfconvert
+ Added -float32 option.
+
+ * src/*.c
+ Changed all error return values to negative values (ie the negative of what
+ they were).
+
+ * src/sndfile.c tests/error_test.c
+ Modified to take account of the previous change.
+
+2001-06-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/float32.c
+ File renamed from wav_float.c and renamed function to something more
+ general.
+ Added runtime detection of floating point capabilities.
+ Added recording of peaks during write for generation of PEAK chunk.
+
+ * src/wav.c src/aiff.c
+ Added handing for PEAK chunk for floating point files. PEAK is read when the
+ file headers are read and generated when the file is closed. Logic is in
+ place for adding PEAK chunk to end of file when writing to a pipe (reading
+ and writing from/to pipe to be implemented soon).
+
+ * src/sndfile.c
+ Modified sf_signal_max () to use PEAK values if present.
+
+2001-06-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c
+ Added pcm_read_init () and pcm_write_init () to src/pcm.c and removed all
+ other calls to functions in this file from the filetype specific files.
+
+ * src/*.c
+ Added alaw_read_init (), alaw_write_int (), ulaw_read_init () and
+ ulaw_write_init () and removed all other calls to functions in alaw.c and
+ ulaw.c from the filetype specific files.
+
+ * tests/write_read_test.c
+ Added tests to validate sf_seek () on all file types.
+
+ * src/raw.c
+ Implemented raw_seek () function to fix a bug where
+ sf_seek (file, 0, SEEK_SET) on a RAW file failed.
+
+ * src/paf.c
+ Fixed a bug in paf24_seek () found due to added seeks tests in
+ tests/write_read_test.c
+
+2001-06-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/read_seek_test.c
+ Fixed a couple of broken binary files.
+
+ * src/aiff.c src/wav.c
+ Added handling of PEAK chunks on file read.
+
+2001-05-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * check_libsndfile.py
+ New file for the regression testing of libsndfile.
+ check_libsndfile.py is a Python script which reads in a file containing
+ filenames of audio files. Each file is checked by running the examples/sfinfo
+ program on them and checking for error or warning messages in the libsndfile
+ log buffer.
+
+ * check_libsndfile.list
+ This is an example list of audio files for use with check_libsndfile.py
+
+ * tests/lossy_comp_test.c
+ Changed the defined value of M_PI for math header files which don't have it.
+ This fixed validation test failures on MetroWerks compilers. Thanks to Lord
+ Praetor Satanus of Acheron for bringing this to my attention.
+
+2001-05-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.[ch]
+ Removed psf_header_setf () which was no longer required after refactoring
+ and simplification of header writing.
+ Added 'z' format specifier to psf_binheader_writef () for zero filling header
+ with N bytes. Used by paf.c and nist.c
+
+ * tests/check_log_buffer.c
+ New file implementing check_log_buffer () which reads the log buffer of a
+ SNDFILE* object and searches for error and warning messages. Calls exit ()
+ if any are found.
+
+ * tests/*.c
+ Added calls to check_log_buffer () after each call to sf_open_XXX ().
+
+2001-05-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c src/wav_ms_adpcm.c src/wav_gsm610.c
+ Major rehack of header writing using psf_binheader_writef ().
+
+2001-05-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c src/wav_ima_adpcm.c
+ Major rehack of header writing using psf_binheader_writef ().
+
+2001-05-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Changed return type of get_encoding_str () to prevent compiler warnings on
+ Mac OSX.
+
+ * src/aiff.c src/au.c
+ Major rehack of header writing using psf_binheader_writef ().
+
+2001-05-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h src/common.c
+ Added comments.
+ Name of log buffer changed from strbuffer to logbuffer.
+ Name of log buffer index variable changed from strindex to logindex.
+
+ * src/*.[ch]
+ Changed name of internal logging function from psf_sprintf () to
+ psf_log_printf ().
+ Changed name of internal header generation functions from
+ psf_[ab]h_printf () to psf_asciiheader_printf () and
+ psf_binheader_writef ().
+ Changed name of internal header manipulation function psf_hsetf () to
+ psf_header_setf ().
+
+2001-05-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/nist.c
+ Fixed reading and writing of sample_byte_format header. "01" means little
+ endian and "10" means big endian regardless of bit width.
+
+ * configure.in
+ Detect Mac OSX and disable -Wall and -pedantic gcc options. Mac OSX is
+ way screwed up and spews out buckets of warning messages from the system
+ headers.
+ Added --disable-gcc-opt configure option (sets gcc optimisation to -O0 ) for
+ easier debugging.
+ Made decision to harmonise source code version number and .so library
+ version number. Future releases will stick to this rule.
+
+ * doc/new_file_type.HOWTO
+ New file to document the addition of new file types to libsndfile.
+
+2001-05-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/nist.c
+ New file for reading/writing Sphere NIST audio file format.
+ Originally requested by Elis Pomales in 1999.
+ Retrieved from unstable (and untouched for 18 months) branch of libsndfile.
+ Some vital information gleaned from the source code to Bill Schottstaedt's
+ sndlib library : ftp://ccrma-ftp.stanford.edu/pub/Lisp/sndlib.tar.gz
+ Currently reading and writing 16, 24 and 32 bit, big-endian and little
+ endian, stereo and mono files.
+
+ * src/common.h src/common.c
+ Added psf_ah_printf () function to help construction of ASCII headers (ie NIST).
+
+ * configure.in
+ Added test for vsnprintf () required by psf_ah_printf ().
+
+ * tests/write_read_test.c
+ Added tests for supported NIST files.
+
+2001-05-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.c
+ Added tests for little endian AIFC files.
+
+ * src/aiff.c
+ Minor re-working of aiff_open_write ().
+ Added write support for little endian PCM encoded AIFC files.
+
+2001-05-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Minor re-working of aiff_open_read ().
+ Added read support for little endian PCM encoded AIFC files from the Mac
+ OSX CD ripper program. Guillaume Lessard provided a couple of sample files
+ and a working patch.
+ The patch was not used as is but gave a good guide as to what to do.
+
+2001-05-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h
+ Fixed comments about endian-ness of WAV and AIFF files. Guillaume Lessard
+ pointed out the error.
+
+2001-04-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/make_sine.c
+ Re-write of this example using sample rate and required frequency in Hz.
+
+2001-02-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed bug that prevented known file types from being read as RAW PCM data.
+
+2000-12-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Added handing of COMT chunk.
+
+2000-11-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sfconvert.c
+ Fixed bug in normalisatio code. Pointed out by Johnny Wu.
+
+2000-11-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/config.h
+ Fixed the incorrect setting of HAVE_ENDIAN_H parameter. Win32 only issue.
+
+2000-10-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/Makefile.am
+ Added -lm for write_read_test_LDADD.
+
+2000-10-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/au.c
+ Fixed bug which prevented writing of G723 24kbps AU files.
+
+ * tests/lossy_comp_test.c
+ Corrrection to options for G723 tests.
+
+ * configure.in
+ Added --disable-gcc-pipe option for DJGPP compiler (gcc on MS-DOS) which
+ doesn't allow gcc -pipe option.
+
+2000-09-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/ulaw.c src/alaw.c src/wav_imaadpcm.c src/msadpcm.c src/wav_gsm610.c
+ Fixed normailsation bugs shown up by new double_test program.
+
+2000-08-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pcm.c
+ Fixed bug in normalisation code (spotted by Steve Lhomme).
+
+ * tests/double_test.c
+ New file to test scaled and unscaled sf_read_double() and sf_write_double()
+ functions.
+
+2000-08-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * COPYING
+ Changed to the LGPL COPYING file (spotted by H. S. Teoh).
+
+2000-08-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h
+ Removed prototype of unimplemented function sf_get_info(). Added prototype
+ for sf_error_number() Thanks to Sigbjørn Skjæret for spotting these.
+
+2000-08-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/newpcm.h
+ New file to contain a complete rewrite of the PCM data handling.
+
+2000-08-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed a leak of FILE* pointers in sf_open_write(). Thanks to Sigbjørn
+ Skjæret for spotting this one.
+
+2000-08-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/au_g72x.c src/G72x/g72x.c
+ Added G723 encoded AU file support.
+
+ * tests/lossy_comp_test.c
+ Added tests for G721 and G723 encoded AU files.
+
+2000-08-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * all files
+ Changed the license to LGPL. Albert Faber who had copyright on
+ Win32/unistd.h gave his permission to change the license on that file. All
+ other files were either copyright erikd AT mega-nerd DOT com or copyright
+ under a GPL/LGPL compatible license.
+
+2000-08-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/lossy_comp_test.c
+ Fixed incorrect error message.
+
+ * src/au_g72x.c src/G72x/*
+ G721 encoded AU files now working.
+
+ * Win32/README-Win32.txt
+ Replaced this file with a new one which gives a full explanation
+ of how to build libsndfile under Win32. Thanks to Mike Ricos.
+
+2000-08-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.[ch]
+ Removed double leading underscores from the start of all variable and
+ function names. Identifiers with a leading underscores are reserved
+ for use by the compiler.
+
+ * src/au_g72x.c src/G72x/*
+ Continued work on G721 encoded AU files.
+
+2000-07-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/G72x/*
+ New files for reading/writing G721 and G723 ADPCM audio. These files
+ are from a Sun Microsystems reference implementation released under a
+ free software licence.
+ Extensive changes to this code to make it fit in with libsndfile.
+ See the ChangeLog in this directory for details.
+
+ * src/au_g72x.c
+ New file for G721 encoded AU files.
+
+2000-07-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * libsndfile.spec.in
+ Added a spec file for making RPMs. Thanks to Josh Green for supplying this.
+
+2000-06-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/sndfile.h
+ Add checking for and handling of header-less u-law encoded AU/SND files.
+ Any file with a ".au" or ".snd" file extension and without the normal
+ AU file header is treated as an 8kHz, u-law encoded file.
+
+ * src/au.h
+ New function for opening a headerless u-law encoded file for read.
+
+2000-06-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/paf.c
+ Add checking for files shorter than minimal PAF file header length.
+
+2000-06-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.c
+ Added extra sf_perror() calls when sf_write_XXXX fails.
+
+2000-05-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Modified usage of va_arg() macro to work correctly on PowerPC
+ Linux. Thanks to Kyle Wheeler for giving me ssh access to his
+ machine while I was trying to track this down.
+
+ * configure.in src/*.[ch]
+ Sorted out some endian-ness issues brought up by PowerPC Linux.
+
+ * tests/read_seek_test.c
+ Added extra debugging for when tests fail.
+
+2000-05-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Fixed bug in GSM 6.10 handling for big-endian machines. Thanks
+ to Sigbjørn Skjæret for reporting this.
+
+2000-04-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/wav.c src/wav_gsm610.c
+ Finallised writing of GSM 6.10 WAV files.
+
+ * tests/lossy_comp_test.c
+ Wrote new test code for GSM 6.10 files.
+
+ * examples/sfinfo.c
+ Fixed incorrect format in printf() statement.
+
+2000-04-06 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h.in
+ Fixed comments about sf_perror () and sf_error_str ().
+
+2000-03-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Fixed --enable-justsrc option.
+
+2000-03-07 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * wav.c
+ Fixed checking of bytespersec field of header. Still some weirdness
+ with some files.
+
+2000-03-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/lossy_comp_test.c
+ Added option to test PCM WAV files (sanity check).
+ Fixed bug in sf_seek() tests.
+
+2000-02-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/wav.c
+ Minor changes to allow writing of GSM 6.10 WAV files.
+
+2000-02-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in Makefile.am src/Makefile.am
+ Finally got around to figuring out how to build a single library from
+ multiple source directories.
+ Reading GSM 6.10 files now seems to work.
+
+2000-01-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Added more error reporting in read_fmt_chunk().
+
+1999-12-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sfinfo.c
+ Modified program to accept multiple filenames from the command line.
+
+1999-11-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_ima_adpcm.c
+ Moved code around in preparation to adding ability to read/write IMA ADPCM
+ encoded AIFF files.
+
+1999-11-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Fixed put_int() and put_short() macros used by _psf_hprintf() which were
+ causing seg. faults on Sparc Solaris.
+
+1999-11-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.c
+ Added string.h to includes. Thanks to Sigbjxrn Skjfret.
+
+ * src/svx.c
+ Fixed __svx_close() function to ensure FORM and BODY chunks are correctly
+ set.
+
+1999-10-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/au.c
+ Fixed handling of incorrect size field in AU header on read. Thanks to
+ Christoph Lauer for finding this problem.
+
+1999-09-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Fixed a bug with incorrect SSND chunk length being written. This also lead
+ to finding an minor error in AIFF header parsing. Thanks to Dan Timis for
+ pointing this out.
+
+1999-09-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/paf.c
+ Fixed a bug with reading and writing 24 bit stereo PAF files. This problem
+ came to light when implementing tests for the new functions which operate
+ in terms of frames rather than items.
+
+1999-09-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Modified file type detection to use first 12 bytes of file rather than
+ file name extension. Required this because NIST files use the same
+ filename extension as Microsoft WAV files.
+
+ * src/sndfile.c src/sndfile.h
+ Added short, int and double read/write functions which work in frames
+ rather than items. This was originally suggested by Maurizio Umberto
+ Puxeddu.
+
+1999-09-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/svx.c
+ Finished off implementation of write using __psf_hprintf().
+
+1999-09-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/common.h
+ Added a buffer to SF_PRIVATE for writing the header. This is required
+ to make generating headers for IFF/SVX files easier as well as making
+ it easier to do re-write the headers which will be required when
+ sf_rewrite_header() is implemented.
+
+ * src/common.c
+ Implemented __psf_hprintf() function. This is an internal function
+ which is documented briefly just above the code.
+
+1999-09-05 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed a bug in sf_write_raw() where it was returning incorrect values
+ (thanks to Richard Dobson for finding this one). Must put in a test
+ routine for sf_read_raw and sf_write_raw.
+
+ * src/aiff.c
+ Fixed default FORMsize in __aiff_open_write ().
+
+ * src/sndfile.c
+ Added copy of filename to internal data structure. IFF/SVX files
+ contain a NAME header chunk. Both sf_open_read() and sf_open_write()
+ copy the file name (less the leading path information) to the
+ filename field.
+
+ * src/svx.c
+ Started implementing writing of files.
+
+1999-08-04 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/svx.c
+ New file for reading/writing 8SVX and 16SVX files.
+
+ * src/sndfile.[ch] src/common.h
+ Changes for SVX files.
+
+ * src/aiff.c
+ Fixed header parsing when unknown chunk is found.
+
+1999-08-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/paf.c
+ New file for reading/writing Ensoniq PARIS audio file format.
+
+ * src/sndfile.[ch] src/common.h
+ Changes for PAF files.
+
+ * src/sndfile.[ch]
+ Added stuff for sf_get_lib_version() function.
+
+
+1999-07-31 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h MacOS/config.h
+ Fixed minor MacOS configuration issues.
+
+1999-07-30 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * MacOS/
+ Added a new directory for the MacOS config.h file and the
+ readme file.
+
+ * src/aiff.c
+ Fixed calculation of datalength when reading SSND chunk. Thanks to
+ Sigbjørn Skjæret for pointing out this error.
+
+1999-07-29 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/sndfile.h src/raw.c
+ Further fixing of #includes for MacOS.
+
+1999-07-25 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c src/aiff.c
+ Added call to ferror () in main header parsing loop of __XXX_open_read
+ functions. This should fix problems on platforms (MacOS, AmigaOS) where
+ fseek()ing or fread()ing beyond the end of the file puts the FILE*
+ stream in an error state until clearerr() is called.
+
+ * tests/write_read_test.c
+ Added tests for RAW header-less PCM files.
+
+ * src/common.h
+ Moved definition of struct tribyte to pcm.c which is the only place
+ which needs it.
+
+ * src/pcm.c
+ Modified all code which assumed sizeof (struct tribyte) == 3. This code
+ did not work on MacOS. Thanks to Ben "Jacobs" for pointing this out.
+
+ * src/au.c
+ Removed <sys/stat.h> from list of #includes (not being used).
+
+ * src/sndfile.c
+ Added MacOS specific #ifdef to replace <sys/stat.h>.
+
+ * src/sndfile.h
+ Added MacOS specific #ifdef to replace <sys/stat.h>.
+
+ * src/sndfile.h
+ Added MacOS specific typedef for off_t.
+
+ * MacOS-readme.txt
+ New file with instructions for building libsndfile under MacOS. Thanks
+ to Ben "Jacobs" for supplying these instructions.
+
+1999-07-24 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Removed sndfile.h from generated file list as there were no longer
+ any autoconf substitutions being made.
+
+ * src/raw.c
+ New file for handling raw header-less PCM files. In order to open these
+ for read, the user must specify format, pcmbitwidth and channels in the
+ SF_INFO struct when calling sf_open_read ().
+
+ * src/sndfile.c
+ Added support for raw header-less PCM files.
+
+1999-07-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * examples/sfinfo.c
+ Removed options so the sfinfo program always prints out all the information.
+
+1999-07-19 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/alaw.c
+ New file for A-law encoding (similar to u-law).
+
+ * tests/alaw_test.c
+ New test program to test the A-law encode/decode lookup tables.
+
+ * tests/lossy_comp_test.c
+ Added tests for a-law encoded WAV, AU and AULE files.
+
+1999-07-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c src/au.c
+ Removed second "#include <unistd.h>". Thanks to Ben "Jacobs" for pointing
+ this out.
+
+1999-07-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/ulaw_test.c
+ New test program to test the u-law encode/decode lookup tables.
+
+1999-07-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.h
+ Made corrections to comments on the return values from sf_seek ().
+
+ * src/sndfile.c
+ Fixed boundary condition checking bug and accounting bug in sf_read_raw ().
+
+1999-07-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/au.c src/ulaw.c
+ Finished implementation of u-law encoded AU files.
+
+ * src/wav.c
+ Implemented reading and writing of u-law encoded WAV files.
+
+ * tests/
+ Changed name of adpcm_test.c to lossy_comp_test.c. This test program
+ will now be used to test Ulaw and Alaw encoding as well as APDCM.
+ Added tests for Ulaw encoded WAV files.
+
+1999-07-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/adpcm_test.c
+ Initialised amp variable in gen_signal() to remove compiler warning.
+
+1999-07-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ In __aiff_open_read () prevented fseek()ing beyond end of file which
+ was causing trouble on MacOS with the MetroWerks compiler. Thanks to
+ Ben "Jacobs" for pointing this out.
+
+ *src/wav.c
+ Fixed as above in __wav_open_read ().
+
+1999-07-01 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_ms_adpcm.c
+ Implemented MS ADPCM encoding. Code cleanup of decoder.
+
+ * tests/adpcm_test.c
+ Added tests for MS ADPCM WAV files.
+
+ * src/wav_ima_adpcm.c
+ Fixed incorrect parameter in call to srate2blocksize () from
+ __ima_writer_init ().
+
+1999-06-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/read_seek_test.c
+ Added test for 8 bit AIFF files.
+
+1999-06-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.c
+ Removed test for IMA ADPCM WAV files which is now done in adpcm_test.c
+
+ * configure.in
+ Added -Wconversion to CFLAGS.
+
+ * src/*.c tests/*.c examples/*.c
+ Fixed all warnings resulting from use of -Wconversion.
+
+1999-06-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Added fact chunk handling on read and write for all non WAVE_FORMAT_PCM
+ WAV files.
+
+ * src/wav_ima.c
+ Changed block alignment to be dependant on sample rate. This should make
+ WAV files created with libsndfile compatible with the MS Windows media
+ players.
+
+ * tests/adpcm_test.c
+ Reimplemented adpcm_test_short and implemented adpcm_test_int and
+ adpcm_test_double.
+ Now have full testing of IMA ADPCM WAV file read, write and seek.
+
+1999-06-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_float.c
+ Fixed function prototype for x86f2d_array () which was causing ocassional
+ seg. faults on Sparc Solaris machines.
+
+1999-06-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c
+ Fixed bug in __aiff_close where the length fields in the header were
+ not being correctly calculated before writing.
+
+ * tests/write_read_test.c
+ Modified to detect the above bug in WAV, AIFF and AU files.
+
+1999-06-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * Win32/*
+ Added a contribution from Albert Faber to allow libsndfile to compile
+ under Win32 systems. libsndfile will now be used as part of LAME the
+ the MPEG 1 Layer 3 encoder (http://internet.roadrunner.com/~mt/mp3/).
+
+1999-06-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in
+ Changed to reflect previous changes.
+
+ * src/wav_ima_adpcm.c
+ Fixed incorrect calculation of bytespersec header field (IMA ADPCM only).
+
+ Fixed bug when writing from int or double data to IMA ADPCM file. Will need
+ to write test code for this.
+
+ Fixed bug in __ima_write () whereby the length of the current block was
+ calculated incorrectly. Thanks to Jongcheon Park for pointing this out.
+
+1999-03-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/*.c
+ Changed all read/write/lseek function calls to fread/fwrite/
+ fseek/ftell and added error checking of return values from
+ fread and fwrite in critical areas of the code.
+
+ * src/au.c
+ Fixed incorrect datasize element in AU header on write.
+
+ * tests/error_test.c
+ Add new test to check all error values have an associated error
+ string. This will avoid embarrassing real world core dumps.
+
+1999-03-23 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c src/aiff.c
+ Added handling for unknown chunk markers in the file.
+
+1999-03-22 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Filled in missing error strings in SndfileErrors array. Missing entries
+ can cause core dumps when calling sf_error-str (). Thanks to Sam
+ <mrsam at-sign geocities.com> for finding this problem.
+
+1999-03-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav_ima_adpcm.c
+ Work on wav_ms_adpcm.c uncovered a bug in __ima_read () when reading
+ stereo files. Caused by not adjusting offset into buffer of decoded
+ samples for 2 channels. A similar bug existed in __ima_write ().
+ Need a test for stereo ADPCM files.
+
+ * src/wav_ms_adpcm.c
+ Decoder working correctly.
+
+1999-03-18 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * configure.in Makefile.am
+ Added --enable-justsrc configuration variable sent by Sam
+ <mrsam at-sign geocities.com>.
+
+ * src/wav_ima_adpcm.c
+ Fixed bug when reading beyond end of data section due to not
+ checking pima->blockcount.
+ This uncovered __ima_seek () bug due to pima->blockcount being set
+ before calling __ima_init_block ().
+
+1999-03-17 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Started implementing MS ADPCM decoder.
+ If file is WAVE_FORMAT_ADPCM and length of data chunk is odd, this
+ encoder seems to add an extra byte. Why not just give an even data
+ length?
+
+1999-03-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Split code out of wav.c to create wav_float.c and wav_ima_adpcm.c.
+ This will make it easier to add and debug other kinds of WAV files
+ in future.
+
+1999-03-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/
+ Added adpcm_test.c which implements test functions for
+ IMA ADPCM reading/writing/seeking etc.
+
+ * src/wav.c
+ Fixed many bugs in IMA ADPCM encoder and decoder.
+
+1999-03-11 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Finished implementing IMA ADPCM encoder and decoder (what a bitch!).
+
+1999-03-03 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/wav.c
+ Started implementing IMA ADPCM decoder.
+
+1999-03-02 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/sndfile.c
+ Fixed bug where the sf_read_XXX functions were returning a
+ incorrect read count when reading past end of file.
+ Fixed bug in sf_seek () when seeking backwards from end of file.
+
+ * tests/read_seek_test.c
+ Added multiple read test to short_test(), int_test () and
+ double_test ().
+ Added extra chunk to all test WAV files to test that reading
+ stops at end of 'data' chunk.
+
+1999-02-21 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.c
+ Added tests for little DEC endian AU files.
+
+ * src/au.c
+ Add handling for DEC format little endian AU files.
+
+1999-02-20 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c src/au.c src/wav.c
+ Add __psf_sprintf calls during header parsing.
+
+ * src/sndfile.c src/common.c
+ Implement sf_header_info (sndfile.c) function and __psf_sprintf (common.c).
+
+ * tests/write_read_test.c
+ Added tests for 8 bit PCM files (WAV, AIFF and AU).
+
+ * src/au.c src/aiff.c
+ Add handling of 8 bit PCM data format.
+
+ * src/aiff.c
+ On write, set blocksize in SSND chunk to zero like everybody else.
+
+1999-02-16 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pcm.c:
+ Fixed bug in let2s_array (cptr was not being initialised).
+
+ * src/sndfile.c:
+ Fixed bug in sf_read_raw and sf_write_raw. sf_seek should
+ now work when using these functions.
+
+1999-02-15 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * tests/write_read_test.c:
+ Force test_buffer array to be double aligned. Sparc Solaris
+ requires this.
+
+1999-02-14 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/pcm.c:
+ Fixed a bug which was causing errors in the reading
+ and writing of 24 bit PCM files.
+
+ * doc/api.html
+ Finished of preliminary documentaion.
+
+1999-02-13 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * src/aiff.c:
+ Changed reading of 'COMM' chunk to avoid reading an int
+ which overlaps an int (4 byte) boundary.
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Make.bat b/Make.bat
new file mode 100644
index 0000000..62c167f
--- /dev/null
+++ b/Make.bat
@@ -0,0 +1,33 @@
+@echo off
+
+if "%1"=="check" GOTO CHECK
+if "%1"=="clean" GOTO CLEAN
+
+copy /y Win32\sndfile.h src\sndfile.h
+copy /y Win32\config.h src\config.h
+
+nmake -f Win32\Makefile.msvc
+goto END
+
+
+:CHECK
+nmake -f Win32\Makefile.msvc check
+goto END
+
+:CLEAN
+nmake -f Win32\Makefile.msvc clean
+goto END
+
+
+:END
+
+
+goto skipArchTag
+
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 8700080b-8d9a-4852-ad8a-8ecd027f1f61
+
+:skipArchTag
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..bae93e1
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,27 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = man doc Win32 Octave src examples regtest tests
+DIST_SUBDIRS = $(SUBDIRS)
+EXTRA_DIST = reconfigure.mk acinclude.m4 libsndfile.spec.in \
+ sndfile.pc.in Mingw-make-dist.sh
+
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = sndfile.pc
+
+m4datadir = $(datadir)/aclocal
+
+test: check-recursive
+
+# Target to make autogenerated files.
+genfiles :
+ (cd src ; make genfiles)
+ (cd tests ; make genfiles)
+
+
+## Do not edit or modify anything in this comment block.
+## The arch-tag line is a file identity tag for the GNU Arch
+## revision control system.
+##
+## arch-tag: e40c569e-8020-4e95-b774-6b0703614526
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..27517fd
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,131 @@
+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 offical release of 0.0.X series of the library.
+
+Version 0.0.8 (1999-02-16)
+ * First offical release.
diff --git a/Octave/Makefile.am b/Octave/Makefile.am
new file mode 100644
index 0000000..146cd29
--- /dev/null
+++ b/Octave/Makefile.am
@@ -0,0 +1,14 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = sndfile_load.m sndfile_save.m sndfile_play.m
+
+octconfigdir = $(exec_prefix)/share/octave/site/m
+octconfig_DATA = sndfile_load.m sndfile_save.m sndfile_play.m
+
+
+## Do not edit or modify anything in this comment block.
+## The arch-tag line is a file identity tag for the GNU Arch
+## revision control system.
+##
+## arch-tag: 56f1645a-3a13-4846-acc7-8b4abf2904ff
+
diff --git a/Octave/sndfile_load.m b/Octave/sndfile_load.m
new file mode 100644
index 0000000..a2371cc
--- /dev/null
+++ b/Octave/sndfile_load.m
@@ -0,0 +1,59 @@
+## Copyright (C) 2002 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 <erikd@mega-nerd.com>
+## 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
+
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: 9d7ed7ce-41fe-4efe-8bde-f5fc6f46bb03
+
diff --git a/Octave/sndfile_play.m b/Octave/sndfile_play.m
new file mode 100644
index 0000000..b1cccab
--- /dev/null
+++ b/Octave/sndfile_play.m
@@ -0,0 +1,66 @@
+## Copyright (C) 2002 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 <erikd@mega-nerd.com>
+## 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
+
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: 96fb14c8-2b5a-4b93-a576-ab83a6d9026b
+
diff --git a/Octave/sndfile_save.m b/Octave/sndfile_save.m
new file mode 100644
index 0000000..1b88842
--- /dev/null
+++ b/Octave/sndfile_save.m
@@ -0,0 +1,60 @@
+## Copyright (C) 2002 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 <erikd@mega-nerd.com>
+## 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
+
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: 5e44602b-940b-4927-af7c-47639769a40b
+
diff --git a/README b/README
new file mode 100644
index 0000000..134ae49
--- /dev/null
+++ b/README
@@ -0,0 +1,71 @@
+This is libsndfile, 1.0.17
+
+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. 'wav32_aiff24' converts a WAV file containing 32 bit floating
+point data into a 24 bit PCM AIFF file. 'sndfile2oct' dumps the audio
+data of a file in a human readable format. 'sfconvert' is the beginnings
+of a audio file format conversion utility. 'make_sine' generates a WAV
+file containing one cycle of a sine wave with 4096 sample points in
+32 bit floating point format. 'sfinfo' opens a sound file and prints
+out information about that file.
+
+The tests/ directory contains programs which link against libsndfile
+and test its functionality.
+
+The Win32/ directory contains files and documentation to allow libsndfile
+to compile under Win32 with the Microsoft Visual C++ compiler.
+
+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.
+
+
+Win32
+-----
+There are detailed instructions for building libsndfile on Win32 in the file
+
+ doc/win32.html
+
+
+MacOSX
+------
+Building on MacOSX should be the same as building it on any other Unix.
+
+
+OTHER PLATFORMS
+---------------
+To compile libsndfile on platforms which have a Bourne Shell compatible
+shell, an ANSI C compiler and a make utility should require no more that
+the following three commands :
+ ./configure
+ make
+ make install
+
+For platforms without the required shell, it is usually sufficient to
+create an approriate config.h file in the src/ directory with correct
+values for the following #defines (this would work for AmigaOS) :
+
+#define HAVE_ENDIAN_H 0
+#define GUESS_BIG_ENDIAN 1
+#define GUESS_LITTLE_ENDIAN 0
+#define FORCE_BROKEN_FLOAT 0
+
+
+CONTACTS
+--------
+
+libsndfile was written by Erik de Castro Lopo (erikd AT mega-nerd DOT com).
+The libsndfile home page is at :
+
+ http://www.mega-nerd.com/libsndfile/
+
diff --git a/Win32/Makefile.am b/Win32/Makefile.am
new file mode 100644
index 0000000..9ab93fa
--- /dev/null
+++ b/Win32/Makefile.am
@@ -0,0 +1,10 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = README-precompiled-dll.txt testprog.c
+
+## Do not edit or modify anything in this comment block.
+## The arch-tag line is a file identity tag for the GNU Arch
+## revision control system.
+##
+## arch-tag: c28c7540-67f6-47e7-8035-0abbc6a174bc
+
diff --git a/Win32/Makefile.mingw.in b/Win32/Makefile.mingw.in
new file mode 100644
index 0000000..5081cd2
--- /dev/null
+++ b/Win32/Makefile.mingw.in
@@ -0,0 +1,401 @@
+# MinGW specific Makefile for libsndfile.
+
+@SET_MAKE@
+
+PROGRAMS = sndfile-info.exe sndfile-play.exe sndfile-convert.exe
+TARGETS = libsndfile.dll $(PROGRAMS) sndfile.pc src/sndfile.h
+
+AR = @AR@
+CC = @CC@
+CFLAGS = @CFLAGS@ -Isrc
+COMPILER_IS_GCC = @COMPILER_IS_GCC@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+DLLTOOL = @DLLTOOL@
+DLLWRAP = @DLLWRAP@
+INSTALL = @INSTALL@
+INSTALL_DATA = ${INSTALL} -m 644
+install_sh = @install_sh@
+LDFLAGS = @LDFLAGS@
+LN_S = @LN_S@
+OS_SPECIFIC_CFLAGS = @OS_SPECIFIC_CFLAGS@
+OS_SPECIFIC_LINKS = @OS_SPECIFIC_LINKS@
+PEXPORTS = @PEXPORTS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+RANLIB = @RANLIB@
+STRIP = @STRIP@
+
+#====================================================================
+# Target directories.
+
+bindir = @bindir@
+exec_prefix = @exec_prefix@
+htmldocdir = @htmldocdir@
+includedir = @includedir@
+libdir = @libdir@
+pkgconfigdir = @libdir@/pkgconfig
+prefix = @prefix@
+
+#====================================================================
+# Targets
+
+all : $(TARGETS)
+
+clean :
+ rm -f $(TARGETS) *.del *.lib src/*.o src/G72x/*.o \
+ src/GSM610/*.o tests/*.o tests/*.exe
+
+install : $(TARGETS)
+ $(install_sh) -c libsndfile.dll $(libdir)
+ $(install_sh) -c sndfile.pc $(pkgconfigdir)
+ @for prog in $(PROGRAMS); do \
+ echo "installing ... $$prog" ; \
+ $(install_sh) -c "$$prog" $(bindir) ; \
+ done;
+ $(install_sh) -c src/sndfile.h $(includedir)
+
+uninstall :
+ rm -f $(libdir)/libsndfile.dll
+ rm -f $(pkgconfigdir)/sndfile.pc
+ @for prog in $(PROGRAMS); do \
+ rm -f $(bindir)/"$$prog" ; \
+ done;
+ rm -f $(includedir)/sndfile.h
+
+#====================================================================
+
+LINK_OBJS = \
+ src/GSM610/add.o \
+ src/GSM610/code.o \
+ src/GSM610/decode.o \
+ src/GSM610/gsm_create.o \
+ src/GSM610/gsm_decode.o \
+ src/GSM610/gsm_destroy.o \
+ src/GSM610/gsm_encode.o \
+ src/GSM610/gsm_option.o \
+ src/GSM610/long_term.o \
+ src/GSM610/lpc.o \
+ src/GSM610/preprocess.o \
+ src/GSM610/rpe.o \
+ src/GSM610/short_term.o \
+ src/GSM610/table.o \
+ src/G72x/g721.o \
+ src/G72x/g723_16.o \
+ src/G72x/g723_24.o \
+ src/G72x/g723_40.o \
+ src/G72x/g72x.o \
+ src/aiff.o \
+ src/alaw.o \
+ src/au.o \
+ src/au_g72x.o \
+ src/avr.o \
+ src/common.o \
+ src/double64.o \
+ src/dwvw.o \
+ src/file_io.o \
+ src/dither.o \
+ src/float32.o \
+ src/command.o \
+ src/strings.o \
+ src/ima_adpcm.o \
+ src/ms_adpcm.o \
+ src/nist.o \
+ src/ircam.o \
+ src/paf.o \
+ src/pcm.o \
+ src/raw.o \
+ src/rx2.o \
+ src/sd2.o \
+ src/sndfile.o \
+ src/svx.o \
+ src/txw.o \
+ src/sds.o \
+ src/ulaw.o \
+ src/voc.o \
+ src/w64.o \
+ src/wav.o \
+ src/gsm610.o \
+ src/wav_w64.o \
+ src/dwd.o \
+ src/wve.o \
+ src/mat4.o \
+ src/mat5.o \
+ src/vox_adpcm.o \
+ src/ogg.o \
+ src/pvf.o \
+ src/xi.o \
+ src/htk.o
+
+libsndfile.dll libsndfile.lib : $(LINK_OBJS)
+ $(DLLWRAP) --def src/libsndfile.def $(LINK_OBJS) --output-lib libsndfile.lib -o libsndfile.dll
+ $(STRIP) libsndfile.dll
+
+sndfile-info.exe : examples/sndfile-info.o libsndfile.lib
+ $(CC) $+ -o $@
+
+sndfile-convert.exe : examples/sndfile-convert.o libsndfile.lib
+ $(CC) $+ -o $@
+
+sndfile-play.exe : examples/sndfile-play.o libsndfile.lib
+ $(CC) $+ -lwinmm -o $@
+
+generate.exe : examples/generate.o libsndfile.lib
+ $(CC) $+ -o $@
+
+sndfile.pc : sndfile.pc.in config.status
+ @./config.status $@
+
+config.status :
+ ./configure
+
+#====================================================================
+# Testing programs.
+
+TEST_PROGS = \
+ src/test_file_io.exe \
+ src/test_log_printf.exe \
+ tests/sfversion.exe \
+ tests/error_test.exe \
+ tests/pcm_test.exe \
+ tests/ulaw_test.exe \
+ tests/alaw_test.exe \
+ tests/dwvw_test.exe \
+ tests/command_test.exe \
+ tests/floating_point_test.exe \
+ tests/headerless_test.exe \
+ tests/write_read_test.exe \
+ tests/lossy_comp_test.exe \
+ tests/peak_chunk_test.exe \
+ tests/misc_test.exe \
+ tests/string_test.exe \
+ tests/win32_test.exe \
+ tests/stdio_test.exe \
+ tests/stdin_test.exe \
+ tests/stdout_test.exe \
+ tests/pipe_test.exe \
+ tests/benchmark.exe
+
+check : $(TEST_PROGS)
+ @echo
+ @echo
+ @echo
+ @echo "============================================================"
+ src/test_file_io.exe
+ src/test_log_printf.exe
+ @echo "============================================================"
+ @echo
+ @echo
+ @echo
+ tests/error_test.exe
+ tests/pcm_test.exe
+ tests/ulaw_test.exe
+ tests/alaw_test.exe
+ tests/dwvw_test.exe
+ tests/command_test.exe ver
+ tests/command_test.exe norm
+ tests/command_test.exe format
+ tests/floating_point_test.exe
+ tests/headerless_test.exe
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo "passed common tests"
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test wav
+ tests/lossy_comp_test wav_ima
+ tests/lossy_comp_test wav_msadpcm
+ tests/lossy_comp_test wav_ulaw
+ tests/lossy_comp_test wav_alaw
+ tests/lossy_comp_test wav_gsm610
+ tests/peak_chunk_test wav
+ tests/misc_test wav
+ tests/string_test wav
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo "passed tests on WAV files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test aiff
+ tests/lossy_comp_test aiff_ulaw
+ tests/lossy_comp_test aiff_alaw
+ tests/peak_chunk_test aiff
+ tests/misc_test aiff
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on AIFF files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test au
+ tests/lossy_comp_test au_ulaw
+ tests/lossy_comp_test au_alaw
+ tests/lossy_comp_test au_g721
+ tests/lossy_comp_test au_g723
+ tests/misc_test au
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on AU files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test raw
+ tests/lossy_comp_test raw_ulaw
+ tests/lossy_comp_test raw_alaw
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on RAW (header-less) files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test paf
+ tests/misc_test paf
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on PAF files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test svx
+ tests/misc_test svx
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on SVX files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test nist
+ tests/misc_test nist
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on NIST files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test ircam
+ tests/lossy_comp_test ircam_ulaw
+ tests/lossy_comp_test ircam_alaw
+ tests/misc_test ircam
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on IRCAM files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test voc
+ tests/lossy_comp_test voc_ulaw
+ tests/lossy_comp_test voc_alaw
+ tests/misc_test voc
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on VOC files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test w64
+ tests/lossy_comp_test w64_ima
+ tests/lossy_comp_test w64_msadpcm
+ tests/lossy_comp_test w64_ulaw
+ tests/lossy_comp_test w64_alaw
+ tests/lossy_comp_test w64_gsm610
+ tests/misc_test w64
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on W64 files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test mat4
+ tests/misc_test mat4
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on MAT4 files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test mat5
+ tests/misc_test mat5
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on MAT5 files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test htk
+ tests/misc_test htk
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on HTK files."
+ @echo "----------------------------------------------------------------------"
+ tests/write_read_test avr
+ tests/misc_test avr
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed tests on AVR files."
+ @echo "----------------------------------------------------------------------"
+ @tests/stdio_test.exe
+ @tests/pipe_test.exe
+ @echo "----------------------------------------------------------------------"
+ @tests/sfversion.exe
+ @echo " passed all tests."
+ @echo "----------------------------------------------------------------------"
+
+#====================================================================
+# Test programs.
+
+src/test_file_io.exe : src/file_io.o src/test_file_io.o libsndfile.lib
+ $(CC) $+ -o $@
+
+# Special case : test_log_printf.c #includes common.c
+src/test_log_printf.exe : src/test_log_printf.c src/common.c libsndfile.lib
+ $(CC) $(CFLAGS) -c src/test_log_printf.c -o src/test_log_printf.o
+ $(CC) src/test_log_printf.o libsndfile.lib -o $@
+
+tests/sfversion.exe : tests/sfversion.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/error_test.exe : tests/error_test.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/pcm_test.exe : tests/pcm_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/ulaw_test.exe : tests/ulaw_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/alaw_test.exe : tests/alaw_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/dwvw_test.exe : tests/dwvw_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/command_test.exe : tests/command_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/floating_point_test.exe : tests/floating_point_test.o tests/utils.o tests/dft_cmp.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/headerless_test.exe : tests/headerless_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/write_read_test.exe : tests/write_read_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/lossy_comp_test.exe : tests/lossy_comp_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/peak_chunk_test.exe : tests/peak_chunk_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/misc_test.exe : tests/misc_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/string_test.exe : tests/string_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/win32_test.exe : tests/win32_test.o
+ $(CC) $+ -o $@
+
+tests/stdio_test.exe : tests/stdio_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/pipe_test.exe : tests/pipe_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/stdin_test.exe : tests/stdin_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/stdout_test.exe : tests/stdout_test.o tests/utils.o libsndfile.lib
+ $(CC) $+ -o $@
+
+tests/benchmark.exe : tests/benchmark.o libsndfile.lib
+ $(CC) $+ -o $@
+
+# End of Makefile
+#====================================================================
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: a588878f-6796-4a47-bbef-83a3aaac0983
diff --git a/Win32/Makefile.msvc b/Win32/Makefile.msvc
new file mode 100644
index 0000000..53e55af
--- /dev/null
+++ b/Win32/Makefile.msvc
@@ -0,0 +1,577 @@
+
+# Set the value of $(MSVCDir) for your installation.
+# Please note that none of the directory names are allowed to have spaces
+# in them. You must use the short name.
+#
+# "C:\Program Files\Microsoft Visual Studio\VC98" will not work.
+# "C:\Progra~1\Micros~1\VC98" will work.
+
+MSVCDir="C:\Progra~1\Micros~1\VC98"
+
+CPP=cl.exe
+LINK32=link.exe
+DLL_LINK_FLAGS=/nologo /dll /incremental:no /libpath:"$(MSVCDir)\Lib" /pdb:"libsndfile.pdb" /implib:".\libsndfile.lib" /machine:I386 /out:"libsndfile.dll"
+PROG_LINK_FLAGS=/nologo /incremental:no /libpath:"$(MSVCDir)\Lib" /pdb:"libsndfile.pdb" /machine:I386 /exetype:dynamic
+
+CFLAGS=/nologo /MD /W1 /GX /O2 /I "$(MSVCDir)\Include" /I "src" /D "WIN32" /D "_USRDLL" /D "inline=__inline" /YX /FD
+
+#====================================================================
+# Targets
+
+ALL : libsndfile.dll \
+ "sndfile-info.exe" \
+ "sndfile-convert.exe" \
+ "sndfile-play.exe" \
+ "generate.exe"
+
+CLEAN :
+ -@erase "src\*.obj"
+ -@erase "src\G72x\*.obj"
+ -@erase "src\GSM610\*.obj"
+ -@erase "tests\*.obj"
+ -@erase "tests\*.exe"
+
+#====================================================================
+
+LINK32_OBJS= \
+ ".\src\GSM610\add.obj" \
+ ".\src\GSM610\code.obj" \
+ ".\src\GSM610\decode.obj" \
+ ".\src\GSM610\gsm_create.obj" \
+ ".\src\GSM610\gsm_decode.obj" \
+ ".\src\GSM610\gsm_destroy.obj" \
+ ".\src\GSM610\gsm_encode.obj" \
+ ".\src\GSM610\gsm_option.obj" \
+ ".\src\GSM610\long_term.obj" \
+ ".\src\GSM610\lpc.obj" \
+ ".\src\GSM610\preprocess.obj" \
+ ".\src\GSM610\rpe.obj" \
+ ".\src\GSM610\short_term.obj" \
+ ".\src\GSM610\table.obj" \
+ ".\src\G72x\g721.obj" \
+ ".\src\G72x\g723_16.obj" \
+ ".\src\G72x\g723_24.obj" \
+ ".\src\G72x\g723_40.obj" \
+ ".\src\G72x\g72x.obj" \
+ ".\src\aiff.obj" \
+ ".\src\alaw.obj" \
+ ".\src\au.obj" \
+ ".\src\g72x.obj" \
+ ".\src\avr.obj" \
+ ".\src\common.obj" \
+ ".\src\double64.obj" \
+ ".\src\dwvw.obj" \
+ ".\src\file_io.obj" \
+ ".\src\dither.obj" \
+ ".\src\float32.obj" \
+ ".\src\command.obj" \
+ ".\src\strings.obj" \
+ ".\src\ima_adpcm.obj" \
+ ".\src\ms_adpcm.obj" \
+ ".\src\nist.obj" \
+ ".\src\ircam.obj" \
+ ".\src\paf.obj" \
+ ".\src\pcm.obj" \
+ ".\src\raw.obj" \
+ ".\src\rx2.obj" \
+ ".\src\sd2.obj" \
+ ".\src\sndfile.obj" \
+ ".\src\svx.obj" \
+ ".\src\txw.obj" \
+ ".\src\sds.obj" \
+ ".\src\ulaw.obj" \
+ ".\src\voc.obj" \
+ ".\src\w64.obj" \
+ ".\src\wav.obj" \
+ ".\src\gsm610.obj" \
+ ".\src\wav_w64.obj" \
+ ".\src\dwd.obj" \
+ ".\src\wve.obj" \
+ ".\src\mat4.obj" \
+ ".\src\mat5.obj" \
+ ".\src\vox_adpcm.obj" \
+ ".\src\ogg.obj" \
+ ".\src\pvf.obj" \
+ ".\src\xi.obj" \
+ ".\src\htk.obj" \
+ ".\src\flac.obj" \
+ ".\src\caf.obj"
+
+libsndfile.dll : $(LINK32_OBJS) ".\src\libsndfile.def"
+ $(LINK32) $(DLL_LINK_FLAGS) /def:".\src\libsndfile.def" $(LINK32_OBJS)
+
+"sndfile-info.exe" : ".\examples\sndfile-info.c"
+ $(CPP) $(CFLAGS) /Fo".\examples\sndfile-info.obj" /c ".\examples\sndfile-info.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:"sndfile-info.exe" ".\examples\sndfile-info.obj" libsndfile.lib
+
+"sndfile-convert.exe" : ".\examples\sndfile-convert.c"
+ $(CPP) $(CFLAGS) /Fo".\examples\sndfile-convert.obj" /c ".\examples\sndfile-convert.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:"sndfile-convert.exe" ".\examples\sndfile-convert.obj" libsndfile.lib
+
+"sndfile-play.exe" : ".\examples\sndfile-play.c"
+ $(CPP) $(CFLAGS) /Fo".\examples\sndfile-play.obj" /c ".\examples\sndfile-play.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:"sndfile-play.exe" ".\examples\sndfile-play.obj" libsndfile.lib winmm.lib
+
+"generate.exe" : ".\examples\generate.c"
+ $(CPP) $(CFLAGS) /Fo".\examples\generate.obj" /c ".\examples\generate.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:"generate.exe" ".\examples\generate.obj" libsndfile.lib
+
+TEST_PROGS= \
+ ".\src\test_file_io.exe" \
+ ".\tests\sfversion.exe" \
+ ".\tests\error_test.exe" \
+ ".\tests\pcm_test.exe" \
+ ".\tests\ulaw_test.exe" \
+ ".\tests\alaw_test.exe" \
+ ".\tests\dwvw_test.exe" \
+ ".\tests\command_test.exe" \
+ ".\tests\floating_point_test.exe" \
+ ".\tests\headerless_test.exe" \
+ ".\tests\write_read_test.exe" \
+ ".\tests\lossy_comp_test.exe" \
+ ".\tests\peak_chunk_test.exe" \
+ ".\tests\misc_test.exe" \
+ ".\tests\string_test.exe" \
+ ".\tests\win32_test.exe" \
+ ".\tests\stdio_test.exe" \
+ ".\tests\pipe_test.exe" \
+ ".\tests\benchmark.exe"
+
+CHECK: $(TEST_PROGS)
+ ".\src\test_file_io.exe"
+ ".\tests\error_test.exe"
+ ".\tests\pcm_test.exe"
+ ".\tests\ulaw_test.exe"
+ ".\tests\alaw_test.exe"
+ ".\tests\dwvw_test.exe"
+ ".\tests\command_test.exe" ver
+ ".\tests\command_test.exe" norm
+ ".\tests\command_test.exe" format
+ ".\tests\floating_point_test.exe"
+ ".\tests\headerless_test.exe"
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo passed common tests
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" wav
+ ".\tests\lossy_comp_test" wav_ima
+ ".\tests\lossy_comp_test" wav_msadpcm
+ ".\tests\lossy_comp_test" wav_ulaw
+ ".\tests\lossy_comp_test" wav_alaw
+ ".\tests\lossy_comp_test" wav_gsm610
+ ".\tests\peak_chunk_test" wav
+ ".\tests\misc_test" wav
+ ".\tests\string_test" wav
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo "passed tests on WAV files.
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" aiff
+ ".\tests\lossy_comp_test" aiff_ulaw
+ ".\tests\lossy_comp_test" aiff_alaw
+ ".\tests\peak_chunk_test" aiff
+ ".\tests\misc_test" aiff
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on AIFF files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" au
+ ".\tests\lossy_comp_test" au_ulaw
+ ".\tests\lossy_comp_test" au_alaw
+ ".\tests\lossy_comp_test" au_g721
+ ".\tests\lossy_comp_test" au_g723
+ ".\tests\misc_test" au
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on AU files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" caf
+ ".\tests\lossy_comp_test" caf_ulaw
+ ".\tests\lossy_comp_test" caf_alaw
+ ".\tests\misc_test" caf
+ -@echo ----------------------------------------------------------------------
+ -@echo `./sfversion` passed tests on CAF files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" raw
+ ".\tests\lossy_comp_test" raw_ulaw
+ ".\tests\lossy_comp_test" raw_alaw
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on RAW (header-less) files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" paf
+ ".\tests\misc_test" paf
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on PAF files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" svx
+ ".\tests\misc_test" svx
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on SVX files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" nist
+ ".\tests\misc_test" nist
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on NIST files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" ircam
+ ".\tests\lossy_comp_test" ircam_ulaw
+ ".\tests\lossy_comp_test" ircam_alaw
+ ".\tests\misc_test" ircam
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on IRCAM files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" voc
+ ".\tests\lossy_comp_test" voc_ulaw
+ ".\tests\lossy_comp_test" voc_alaw
+ ".\tests\misc_test" voc
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on VOC files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" w64
+ ".\tests\lossy_comp_test" w64_ima
+ ".\tests\lossy_comp_test" w64_msadpcm
+ ".\tests\lossy_comp_test" w64_ulaw
+ ".\tests\lossy_comp_test" w64_alaw
+ ".\tests\lossy_comp_test" w64_gsm610
+ ".\tests\misc_test" w64
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on W64 files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" mat4
+ ".\tests\misc_test" mat4
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on MAT4 files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" mat5
+ ".\tests\misc_test" mat5
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on MAT5 files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" htk
+ ".\tests\misc_test" htk
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on HTK files."
+ -@echo ----------------------------------------------------------------------
+ ".\tests\write_read_test" avr
+ ".\tests\misc_test" avr
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed tests on AVR files."
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\stdio_test.exe"
+ -@".\tests\pipe_test.exe"
+ -@echo ----------------------------------------------------------------------
+ -@".\tests\sfversion.exe"
+ -@echo " passed all tests."
+ -@echo ----------------------------------------------------------------------
+
+#====================================================================
+# C files in src\GSM610.
+
+".\src\GSM610\add.obj" : ".\src\Gsm610\add.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\add.obj" /c ".\src\Gsm610\add.c"
+
+".\src\GSM610\code.obj" : ".\src\Gsm610\code.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\code.obj" /c ".\src\Gsm610\code.c"
+
+".\src\GSM610\decode.obj" : ".\src\Gsm610\decode.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\decode.obj" /c ".\src\Gsm610\decode.c"
+
+".\src\GSM610\gsm_create.obj" : ".\src\Gsm610\gsm_create.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\gsm_create.obj" /c ".\src\Gsm610\gsm_create.c"
+
+".\src\GSM610\gsm_decode.obj" : ".\src\Gsm610\gsm_decode.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\gsm_decode.obj" /c ".\src\Gsm610\gsm_decode.c"
+
+".\src\GSM610\gsm_destroy.obj" : ".\src\Gsm610\gsm_destroy.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\gsm_destroy.obj" /c ".\src\Gsm610\gsm_destroy.c"
+
+".\src\GSM610\gsm_encode.obj" : ".\src\Gsm610\gsm_encode.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\gsm_encode.obj" /c ".\src\Gsm610\gsm_encode.c"
+
+".\src\GSM610\gsm_option.obj" : ".\src\Gsm610\gsm_option.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\gsm_option.obj" /c ".\src\Gsm610\gsm_option.c"
+
+".\src\GSM610\long_term.obj" : ".\src\Gsm610\long_term.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\long_term.obj" /c ".\src\Gsm610\long_term.c"
+
+".\src\GSM610\lpc.obj" : ".\src\Gsm610\lpc.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\lpc.obj" /c ".\src\Gsm610\lpc.c"
+
+".\src\GSM610\preprocess.obj" : ".\src\Gsm610\preprocess.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\preprocess.obj" /c ".\src\Gsm610\preprocess.c"
+
+".\src\GSM610\rpe.obj" : ".\src\Gsm610\rpe.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\rpe.obj" /c ".\src\Gsm610\rpe.c"
+
+".\src\GSM610\short_term.obj" : ".\src\Gsm610\short_term.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\short_term.obj" /c ".\src\Gsm610\short_term.c"
+
+".\src\GSM610\table.obj" : ".\src\Gsm610\table.c"
+ $(CPP) $(CFLAGS) /Fo".\src\Gsm610\table.obj" /c ".\src\Gsm610\table.c"
+
+#====================================================================
+# C files in src\G72x.
+
+".\src\G72x\g721.obj" : ".\src\G72x\g721.c"
+ $(CPP) $(CFLAGS) /Fo".\src\G72x\g721.obj" /c ".\src\G72x\g721.c"
+
+".\src\G72x\g723_16.obj" : ".\src\G72x\g723_16.c"
+ $(CPP) $(CFLAGS) /Fo".\src\G72x\g723_16.obj" /c ".\src\G72x\g723_16.c"
+
+".\src\G72x\g723_24.obj" : ".\src\G72x\g723_24.c"
+ $(CPP) $(CFLAGS) /Fo".\src\G72x\g723_24.obj" /c ".\src\G72x\g723_24.c"
+
+".\src\G72x\g723_40.obj" : ".\src\G72x\g723_40.c"
+ $(CPP) $(CFLAGS) /Fo".\src\G72x\g723_40.obj" /c ".\src\G72x\g723_40.c"
+
+".\src\G72x\g72x.obj" : ".\src\G72x\g72x.c"
+ $(CPP) $(CFLAGS) /Fo".\src\G72x\g72x.obj" /c ".\src\G72x\g72x.c"
+
+#====================================================================
+# C files in src.
+
+".\src\aiff.obj" : ".\src\aiff.c"
+ $(CPP) $(CFLAGS) /Fo".\src\aiff.obj" /c ".\src\aiff.c"
+
+".\src\alaw.obj" : ".\src\alaw.c"
+ $(CPP) $(CFLAGS) /Fo".\src\alaw.obj" /c ".\src\alaw.c"
+
+".\src\au.obj" : ".\src\au.c"
+ $(CPP) $(CFLAGS) /Fo".\src\au.obj" /c ".\src\au.c"
+
+".\src\g72x.obj" : ".\src\g72x.c"
+ $(CPP) $(CFLAGS) /Fo".\src\g72x.obj" /c ".\src\g72x.c"
+
+".\src\avr.obj" : ".\src\avr.c"
+ $(CPP) $(CFLAGS) /Fo".\src\avr.obj" /c ".\src\avr.c"
+
+".\src\common.obj" : ".\src\common.c"
+ $(CPP) $(CFLAGS) /Fo".\src\common.obj" /c ".\src\common.c"
+
+".\src\double64.obj" : ".\src\double64.c"
+ $(CPP) $(CFLAGS) /Fo".\src\double64.obj" /c ".\src\double64.c"
+
+".\src\dwvw.obj" : ".\src\dwvw.c"
+ $(CPP) $(CFLAGS) /Fo".\src\dwvw.obj" /c ".\src\dwvw.c"
+
+".\src\file_io.obj" : ".\src\file_io.c"
+ $(CPP) $(CFLAGS) /Fo".\src\file_io.obj" /c ".\src\file_io.c"
+
+".\src\dither.obj" : ".\src\dither.c"
+ $(CPP) $(CFLAGS) /Fo".\src\dither.obj" /c ".\src\dither.c"
+
+".\src\float32.obj" : ".\src\float32.c"
+ $(CPP) $(CFLAGS) /Fo".\src\float32.obj" /c ".\src\float32.c"
+
+".\src\command.obj" : ".\src\command.c"
+ $(CPP) $(CFLAGS) /Fo".\src\command.obj" /c ".\src\command.c"
+
+".\src\strings.obj" : ".\src\strings.c"
+ $(CPP) $(CFLAGS) /Fo".\src\strings.obj" /c ".\src\strings.c"
+
+".\src\ima_adpcm.obj" : ".\src\ima_adpcm.c"
+ $(CPP) $(CFLAGS) /Fo".\src\ima_adpcm.obj" /c ".\src\ima_adpcm.c"
+
+".\src\ircam.obj" : ".\src\ircam.c"
+ $(CPP) $(CFLAGS) /Fo".\src\ircam.obj" /c ".\src\ircam.c"
+
+".\src\ms_adpcm.obj" : ".\src\ms_adpcm.c"
+ $(CPP) $(CFLAGS) /Fo".\src\ms_adpcm.obj" /c ".\src\ms_adpcm.c"
+
+".\src\nist.obj" : ".\src\nist.c"
+ $(CPP) $(CFLAGS) /Fo".\src\nist.obj" /c ".\src\nist.c"
+
+".\src\paf.obj" : ".\src\paf.c"
+ $(CPP) $(CFLAGS) /Fo".\src\paf.obj" /c ".\src\paf.c"
+
+".\src\pcm.obj" : ".\src\pcm.c"
+ $(CPP) $(CFLAGS) /Fo".\src\pcm.obj" /c ".\src\pcm.c"
+
+".\src\raw.obj" : ".\src\raw.c"
+ $(CPP) $(CFLAGS) /Fo".\src\raw.obj" /c ".\src\raw.c"
+
+".\src\rx2.obj" : ".\src\rx2.c"
+ $(CPP) $(CFLAGS) /Fo".\src\rx2.obj" /c ".\src\rx2.c"
+
+".\src\sd2.obj" : ".\src\sd2.c"
+ $(CPP) $(CFLAGS) /Fo".\src\sd2.obj" /c ".\src\sd2.c"
+
+".\src\sndfile.obj" : ".\src\sndfile.c"
+ $(CPP) $(CFLAGS) /Fo".\src\sndfile.obj" /c ".\src\sndfile.c"
+
+".\src\svx.obj" : ".\src\svx.c"
+ $(CPP) $(CFLAGS) /Fo".\src\svx.obj" /c ".\src\svx.c"
+
+".\src\txw.obj" : ".\src\txw.c"
+ $(CPP) $(CFLAGS) /Fo".\src\txw.obj" /c ".\src\txw.c"
+
+".\src\sds.obj" : ".\src\sds.c"
+ $(CPP) $(CFLAGS) /Fo".\src\sds.obj" /c ".\src\sds.c"
+
+".\src\ulaw.obj" : ".\src\ulaw.c"
+ $(CPP) $(CFLAGS) /Fo".\src\ulaw.obj" /c ".\src\ulaw.c"
+
+".\src\voc.obj" : ".\src\voc.c"
+ $(CPP) $(CFLAGS) /Fo".\src\voc.obj" /c ".\src\voc.c"
+
+".\src\w64.obj" : ".\src\w64.c"
+ $(CPP) $(CFLAGS) /Fo".\src\w64.obj" /c ".\src\w64.c"
+
+".\src\wav.obj" : ".\src\wav.c"
+ $(CPP) $(CFLAGS) /Fo".\src\wav.obj" /c ".\src\wav.c"
+
+".\src\gsm610.obj" : ".\src\gsm610.c"
+ $(CPP) $(CFLAGS) /Fo".\src\gsm610.obj" /c ".\src\gsm610.c"
+
+".\src\wav_w64.obj" : ".\src\wav_w64.c"
+ $(CPP) $(CFLAGS) /Fo".\src\wav_w64.obj" /c ".\src\wav_w64.c"
+
+".\src\dwd.obj" : ".\src\dwd.c"
+ $(CPP) $(CFLAGS) /Fo".\src\dwd.obj" /c ".\src\dwd.c"
+
+".\src\wve.obj" : ".\src\wve.c"
+ $(CPP) $(CFLAGS) /Fo".\src\wve.obj" /c ".\src\wve.c"
+
+".\src\mat4.obj" : ".\src\mat4.c"
+ $(CPP) $(CFLAGS) /Fo".\src\mat4.obj" /c ".\src\mat4.c"
+
+".\src\mat5.obj" : ".\src\mat5.c"
+ $(CPP) $(CFLAGS) /Fo".\src\mat5.obj" /c ".\src\mat5.c"
+
+".\src\vox_adpcm.obj" : ".\src\vox_adpcm.c"
+ $(CPP) $(CFLAGS) /Fo".\src\vox_adpcm.obj" /c ".\src\vox_adpcm.c"
+
+".\src\ogg.obj" : ".\src\ogg.c"
+ $(CPP) $(CFLAGS) /Fo".\src\ogg.obj" /c ".\src\ogg.c"
+
+".\src\pvf.obj" : ".\src\pvf.c"
+ $(CPP) $(CFLAGS) /Fo".\src\pvf.obj" /c ".\src\pvf.c"
+
+".\src\xi.obj" : ".\src\xi.c"
+ $(CPP) $(CFLAGS) /Fo".\src\xi.obj" /c ".\src\xi.c"
+
+".\src\htk.obj" : ".\src\htk.c"
+ $(CPP) $(CFLAGS) /Fo".\src\htk.obj" /c ".\src\htk.c"
+
+".\src\flac.obj" : ".\src\flac.c"
+ $(CPP) $(CFLAGS) /Fo".\src\flac.obj" /c ".\src\flac.c"
+
+".\src\caf.obj" : ".\src\caf.c"
+ $(CPP) $(CFLAGS) /Fo".\src\caf.obj" /c ".\src\caf.c"
+
+#====================================================================
+# Object files for test programs.
+
+".\tests\utils.obj" : ".\tests\utils.c"
+ $(CPP) $(CFLAGS) /Fo".\tests\utils.obj" /c ".\tests\utils.c"
+
+".\tests\dft_cmp.obj" : ".\tests\dft_cmp.c"
+ $(CPP) $(CFLAGS) /Fo".\tests\dft_cmp.obj" /c ".\tests\dft_cmp.c"
+
+#====================================================================
+# Test programs.
+
+".\src\test_file_io.exe" : ".\src\file_io.obj" ".\src\test_file_io.c"
+ $(CPP) $(CFLAGS) /Fo".\src\test_file_io.obj" /c ".\src\test_file_io.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\src\test_file_io.exe" ".\src\test_file_io.obj" ".\src\file_io.obj"
+
+".\tests\sfversion.exe" : ".\tests\sfversion.c"
+ $(CPP) $(CFLAGS) /Fo".\tests\sfversion.obj" /c ".\tests\sfversion.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\sfversion.exe" ".\tests\sfversion.obj" libsndfile.lib
+
+".\tests\error_test.exe" : ".\tests\error_test.c"
+ $(CPP) $(CFLAGS) /Fo".\tests\error_test.obj" /c ".\tests\error_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\error_test.exe" ".\tests\error_test.obj" libsndfile.lib
+
+".\tests\pcm_test.exe" : ".\tests\pcm_test.c" ".\tests\utils.obj" "libsndfile.dll"
+ $(CPP) $(CFLAGS) /Fo".\tests\pcm_test.obj" /c ".\tests\pcm_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\pcm_test.exe" ".\tests\pcm_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\ulaw_test.exe" : ".\tests\ulaw_test.c" ".\tests\utils.obj" "libsndfile.dll"
+ $(CPP) $(CFLAGS) /Fo".\tests\ulaw_test.obj" /c ".\tests\ulaw_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\ulaw_test.exe" ".\tests\ulaw_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\alaw_test.exe" : ".\tests\alaw_test.c" ".\tests\utils.obj" "libsndfile.dll"
+ $(CPP) $(CFLAGS) /Fo".\tests\alaw_test.obj" /c ".\tests\alaw_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\alaw_test.exe" ".\tests\alaw_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\dwvw_test.exe" : ".\tests\dwvw_test.c" ".\tests\utils.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\dwvw_test.obj" /c ".\tests\dwvw_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\dwvw_test.exe" ".\tests\dwvw_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\command_test.exe" : ".\tests\command_test.c" ".\tests\utils.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\command_test.obj" /c ".\tests\command_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\command_test.exe" ".\tests\command_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\floating_point_test.exe" : ".\tests\floating_point_test.c" ".\tests\utils.obj" ".\tests\dft_cmp.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\floating_point_test.obj" /c ".\tests\floating_point_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\floating_point_test.exe" ".\tests\floating_point_test.obj" ".\tests\utils.obj" ".\tests\dft_cmp.obj" libsndfile.lib
+
+".\tests\headerless_test.exe" : ".\tests\headerless_test.c" ".\tests\utils.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\headerless_test.obj" /c ".\tests\headerless_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\headerless_test.exe" ".\tests\headerless_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\write_read_test.exe" : ".\tests\write_read_test.c" ".\tests\utils.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\write_read_test.obj" /c ".\tests\write_read_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\write_read_test.exe" ".\tests\write_read_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\lossy_comp_test.exe" : ".\tests\lossy_comp_test.c" ".\tests\utils.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\lossy_comp_test.obj" /c ".\tests\lossy_comp_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\lossy_comp_test.exe" ".\tests\lossy_comp_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\peak_chunk_test.exe" : ".\tests\peak_chunk_test.c" ".\tests\utils.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\peak_chunk_test.obj" /c ".\tests\peak_chunk_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\peak_chunk_test.exe" ".\tests\peak_chunk_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\misc_test.exe" : ".\tests\misc_test.c" ".\tests\utils.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\misc_test.obj" /c ".\tests\misc_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\misc_test.exe" ".\tests\misc_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\string_test.exe" : ".\tests\string_test.c" ".\tests\utils.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\string_test.obj" /c ".\tests\string_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\string_test.exe" ".\tests\string_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\win32_test.exe" : ".\tests\win32_test.c"
+ $(CPP) $(CFLAGS) /Fo".\tests\win32_test.obj" /c ".\tests\win32_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\win32_test.exe" ".\tests\win32_test.obj"
+
+".\tests\stdio_test.exe" : ".\tests\stdio_test.c" ".\tests\utils.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\stdio_test.obj" /c ".\tests\stdio_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\stdio_test.exe" ".\tests\stdio_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\pipe_test.exe" : ".\tests\pipe_test.c" ".\tests\utils.obj"
+ $(CPP) $(CFLAGS) /Fo".\tests\pipe_test.obj" /c ".\tests\pipe_test.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\pipe_test.exe" ".\tests\pipe_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+# ".\tests\stdin_test.exe" : ".\tests\stdin_test.c" ".\tests\utils.obj"
+# $(CPP) $(CFLAGS) /Fo".\tests\stdin_test.obj" /c ".\tests\stdin_test.c"
+# $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\stdin_test.exe" ".\tests\stdin_test.obj" ".\tests\utils.obj" libsndfile.lib
+#
+# ".\tests\stdout_test.exe" : ".\tests\stdout_test.c" ".\tests\utils.obj"
+# $(CPP) $(CFLAGS) /Fo".\tests\stdout_test.obj" /c ".\tests\stdout_test.c"
+# $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\stdout_test.exe" ".\tests\stdout_test.obj" ".\tests\utils.obj" libsndfile.lib
+
+".\tests\benchmark.exe" : ".\tests\benchmark.c"
+ $(CPP) $(CFLAGS) /Fo".\tests\benchmark.obj" /c ".\tests\benchmark.c"
+ $(LINK32) $(PROG_LINK_FLAGS) /out:".\tests\benchmark.exe" ".\tests\benchmark.obj" ".\tests\utils.obj" libsndfile.lib
+
+# End of Makefile
+#====================================================================
+
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: 9a46d08e-921f-49f7-961e-3f21ea67851e
+
diff --git a/Win32/README-Win32.txt b/Win32/README-Win32.txt
new file mode 100644
index 0000000..975bfe9
--- /dev/null
+++ b/Win32/README-Win32.txt
@@ -0,0 +1,96 @@
+NOTE: This is not the way the author builds libsndfile on Win32
+so this desciption may be out of date. For the authors method
+of building libsndfile on Win32 have a look at the file named
+win32.html in the doc\ directory of the source code distribution.
+
+*****************************************************************
+
+This is the readme-Win32.txt file associated with the LibSndFile
+library. It describes how the included workspace and project
+was created for Microsoft Visual C++ developer's studio (MSVC),
+version 5.0. Skip to point 7 if you wish to create a new
+project for building an executable.
+
+1. Extracted libsndfile.zip to d:\files\msvc\
+
+2. It created (replace X.Y.Z with the libsndfile version number)
+ d:\files\msvc\libsndfile-X.Y.Z\Win32 *
+ d:\files\msvc\libsndfile-X.Y.Z\src *
+ d:\files\msvc\libsndfile-X.Y.Z\tests *
+ d:\files\msvc\libsndfile-X.Y.Z\examples
+ d:\files\msvc\libsndfile-X.Y.Z\doc
+ d:\files\msvc\libsndfile-X.Y.Z\m4
+ d:\files\msvc\libsndfile-X.Y.Z\MacOS
+
+ * are needed for this example
+
+3. From MSVC:New->Workspace, I created LibSndFileWorkspace at:
+ d:\files\msvc\libsndfile-X.Y.Z\Win32\
+ (workspace files have the extension .dsw)
+
+3. In MSVC, rt-click on "Workspace LibSndFileWorkspace" and add project:
+ Project type: Win32 Static Library
+ Project Name: LibSndFile
+ Project Location: D:\files\msvc\libsndfile-X.Y.Z\Win32
+ Select button: 'Add to current workspace'
+ Platforms: Win32
+
+4. Rt-click newly formed "LibSndFile files" and add files:
+ d:\files\msvc\libsndfile-X.Y.Z\src\*.*
+ d:\files\msvc\libsndfile-X.Y.Z\src\Gsm610\*.*
+ d:\files\msvc\libsndfile-X.Y.Z\src\G72x\*.*
+
+5. Rt-click 'LibSndFile files' and go to Settings
+ a. Select all configurations on the left hand side
+ b. Then select C/C++/Preprocessor and add
+ "..\" (no quotes) to 'Additional include directories'
+ (This allows ..Win32\config.h and unistd.h to be found.)
+
+6. At this point you should be able to build the library. The output
+ will be found in ..\Win32\LibSndFile\Debug\LibSndFile.lib. You can
+ change the LibSndFile project to Release and a similar release
+ path will be created.
+
+The following describes how to add an application project to the
+workspace. You may add as many as you wish. In general, you will
+need one project for each executable you want to create.
+
+7. Rt-click LibSndFileWorkspace and select 'Add project'
+ Project type: Win32 Console Application
+ Project Name: sfversion
+ Location: d:\files\msvc\libsndfile-X.Y.Z\Win32\sfversion
+ Select button: 'Add to current workspace'
+ Platforms: Win32
+
+ Notes:
+ - MSVC will create a directory ..\Win32\sfversion\
+ - MSVC will create the file sfversion.dsp in this directory
+
+8. Rt-click 'sfversion files' and add file:
+ d:\files\msvc\libsndfile-X.Y.Z\tests\sfversion.c
+
+9. Rt-click 'sfversion files' and go to Settings:
+ a. Select 'All configurations' on the left hand side
+ b. Then select C/C++/Preprocessor and add
+ "..\..\src,..\" (no quotes) to 'Additional include directories'
+
+9. Rt-click 'sfversion files' and go to Settings:
+ a. Select 'Debug Configuration' on left hand side
+ b. Then select Link tab and add
+ "..\LibSndFile\Debug\LibSndFile.lib " (no quotes) to
+ the list of 'Object/library modules'. Leave a space between new
+ addition existing lib files.
+
+10. Repeat above for Release build adding Release path info.
+
+11. Build your application, it should link and create an .exe
+
+Final notes:
+
+Files created during build by msvc but are not needed for archive:
+*ncb *.plg *.opt *.obj *.idb *.pch *.lib *.exe
+
+Files associated with LibSndFile but not used by msvc:
+Makefile.in
+Makefile.am
+ - End -
diff --git a/Win32/README-precompiled-dll.txt b/Win32/README-precompiled-dll.txt
new file mode 100644
index 0000000..bde8124
--- /dev/null
+++ b/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/Win32/config.h b/Win32/config.h
new file mode 100644
index 0000000..b6ed4b7
--- /dev/null
+++ b/Win32/config.h
@@ -0,0 +1,290 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 Win32 version of the file config.h which is autogenerated
+** on Unix systems.
+*/
+
+#pragma warning (disable : 4244)
+#pragma warning (disable : 4761)
+
+/* Set to 1 if the compile is GNU GCC. */
+/* #undef COMPILER_IS_GCC */
+
+/* Target processor clips on negative float to int conversion. */
+#define CPU_CLIPS_NEGATIVE 1
+
+/* Target processor clips on positive float to int conversion. */
+#define CPU_CLIPS_POSITIVE 0
+
+/* Target processor is big endian. */
+#define CPU_IS_BIG_ENDIAN 0
+
+/* Target processor is little endian. */
+#define CPU_IS_LITTLE_ENDIAN 1
+
+/* Set to 1 to enable experimental code. */
+#define ENABLE_EXPERIMENTAL_CODE 0
+
+/* Major version of GCC or 3 otherwise. */
+/* #undef GCC_MAJOR_VERSION */
+
+/* Define to 1 if you have the <alsa/asoundlib.h> header file. */
+/* #undef HAVE_ALSA_ASOUNDLIB_H */
+
+/* Define to 1 if you have the <byteswap.h> header file. */
+/* #undef HAVE_BYTESWAP_H */
+
+/* Define to 1 if you have the `calloc' function. */
+#define HAVE_CALLOC 1
+
+/* Define to 1 if you have the `ceil' function. */
+#define HAVE_CEIL 1
+
+/* Set to 1 if S_IRGRP is defined. */
+#define HAVE_DECL_S_IRGRP 0
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define to 1 if you have the <endian.h> header file. */
+/* #undef HAVE_ENDIAN_H */
+
+/* Define to 1 if you have the `fdatasync' function. */
+
+/* #undef HAVE_FDATASYNC */
+
+/* Define to 1 if you have libflac 1.1.1 */
+/* #undef HAVE_FLAC_1_1_1 1 */
+
+/* Define to 1 if you have the <FLAC/all.h> header file. */
+/* #undef HAVE_FLAC_ALL_H 1 */
+
+/* Set to 1 if the compile supports the struct hack. */
+#define HAVE_FLEXIBLE_ARRAY 1
+
+/* Define to 1 if you have the `floor' function. */
+#define HAVE_FLOOR 1
+
+/* Define to 1 if you have the `fmod' function. */
+#define HAVE_FMOD 1
+
+/* Define to 1 if you have the `free' function. */
+#define HAVE_FREE 1
+
+/* Define to 1 if you have the `fstat' function. */
+#define HAVE_FSTAT 1
+
+/* Define to 1 if you have the `fsync' function. */
+/* #undef HAVE_FSYNC */
+
+/* Define to 1 if you have the `ftruncate' function. */
+/* #undef HAVE_FTRUNCATE */
+
+/* Define to 1 if you have the `getpagesize' function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define to 1 if you have the `gmtime' function. */
+#define HAVE_GMTIME 1
+
+/* Define to 1 if you have the `gmtime_r' function. */
+/* #undef HAVE_GMTIME_R */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+/* #undef HAVE_INTTYPES_H */
+
+/* Define to 1 if you have the `m' library (-lm). */
+#define HAVE_LIBM 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+/* #undef HAVE_LOCALE_H */
+
+/* Define if you have C99's lrint function. */
+/* #undef HAVE_LRINT */
+
+/* Define if you have C99's lrintf function. */
+/* #undef HAVE_LRINTF */
+
+/* Define to 1 if you have the `lseek' function. */
+#define HAVE_LSEEK 1
+
+/* Define to 1 if you have the `malloc' function. */
+#define HAVE_MALLOC 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mmap' function. */
+/* #undef HAVE_MMAP */
+
+/* Define to 1 if you have the `open' function. */
+#define HAVE_OPEN 1
+
+/* Define to 1 if you have the `pread' function. */
+/* #undef HAVE_PREAD */
+
+/* Define to 1 if you have the `pwrite' function. */
+/* #undef HAVE_PWRITE */
+
+/* Define to 1 if you have the `read' function. */
+#define HAVE_READ 1
+
+/* Define to 1 if you have the `realloc' function. */
+#define HAVE_REALLOC 1
+
+/* Define to 1 if you have the `setlocale' function. */
+/* #undef HAVE_SETLOCALE */
+
+/* Define to 1 if you have the `snprintf' function. */
+#define HAVE_SNPRINTF 1
+
+/* Set to 1 if you have libsqlite3. */
+/* #undef HAVE_SQLITE3 */
+
+/* Define to 1 if the system has the type `ssize_t'. */
+/* #undef HAVE_SSIZE_T */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #undef HAVE_STDINT_H */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+/* #undef HAVE_SYS_WAIT_H */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+/* #undef HAVE_UNISTD_H */
+
+/* Define to 1 if you have the `vsnprintf' function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define to 1 if you have the `write' function. */
+#define HAVE_WRITE 1
+
+/* Set to 1 if compiling for MacOSX */
+#define OS_IS_MACOSX 0
+
+/* Set to 1 if compiling for Win32 */
+#define OS_IS_WIN32 1
+
+/* Name of package */
+#define PACKAGE "libsndfile"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "erikd@mega-nerd.com"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libsndfile"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libsndfile 1.0.13"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libsndfile"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.0.13"
+
+/* Set to maximum allowed value of sf_count_t type. */
+#define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFi64
+
+/* The size of a `double', as computed by sizeof. */
+#define SIZEOF_DOUBLE 8
+
+/* The size of a `float', as computed by sizeof. */
+#define SIZEOF_FLOAT 4
+
+/* The size of a `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `int64_t', as computed by sizeof. */
+#define SIZEOF_INT64_T 0
+
+/* The size of a `loff_t', as computed by sizeof. */
+#define SIZEOF_LOFF_T 0
+
+/* The size of a `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of a `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 0
+
+/* The size of a `off64_t', as computed by sizeof. */
+/* #undef SIZEOF_OFF64_T */
+
+/* The size of a `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 4
+
+/* Set to sizeof (long) if unknown. */
+#define SIZEOF_SF_COUNT_T 8
+
+/* The size of a `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of a `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of a `ssize_t', as computed by sizeof. */
+#define SIZEOF_SSIZE_T 4
+
+/* The size of a `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Set to long if unknown. */
+#define TYPEOF_SF_COUNT_T loff_t
+
+/* Set to 1 to use the native windows API */
+#define USE_WINDOWS_API 1
+
+/* Version number of package */
+#define VERSION "1.0.13"
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define to make fseeko etc. visible, on some hosts. */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 78a733c0-a430-46bd-81ab-4e479fbcffac
+*/
+
diff --git a/Win32/libtool.mingw b/Win32/libtool.mingw
new file mode 100644
index 0000000..aee89ba
--- /dev/null
+++ b/Win32/libtool.mingw
@@ -0,0 +1,7273 @@
+#! /bin/sh
+
+# libtoolT - Provide generalized library-building support services.
+# Generated automatically by (GNU glib 2.2.3)
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+#
+# This file is part of GNU Libtool:
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# 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.
+
+# A sed program that does not truncate output.
+SED="/bin/sed"
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="/bin/sed -e s/^X//"
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test "X${CDPATH+set}" = Xset; then CDPATH=:; export CDPATH; fi
+
+# The names of the tagged configurations supported by this script.
+available_tags=" CXX F77"
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Libtool was configured on host QWEST-WKCH1I7I3:
+
+# Shell to use when invoking shell scripts.
+SHELL="/bin/sh"
+
+# Whether or not to build shared libraries.
+build_libtool_libs=yes
+
+# Whether or not to build static libraries.
+build_old_libs=no
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=yes
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=yes
+
+# Whether or not to optimize for fast installation.
+fast_install=yes
+
+# The host system.
+host_alias=
+host=i686-pc-mingw32
+
+# An echo program that does not interpret backslashes.
+echo="echo"
+
+# The archiver.
+AR="ar"
+AR_FLAGS="cru"
+
+# A C compiler.
+LTCC="gcc"
+
+# A language-specific compiler.
+CC="gcc"
+
+# Is the compiler the GNU C compiler?
+with_gcc=yes
+
+# An ERE matcher.
+EGREP="grep -E"
+
+# The linker used to build libraries.
+LD="c:/mnt/opt/mingw/mingw32/bin/ld.exe"
+
+# Whether we need hard or soft links.
+LN_S="ln -s"
+
+# A BSD-compatible nm program.
+NM="/bin/nm -B"
+
+# A symbol stripping program
+STRIP=strip
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=file
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="dlltool"
+
+# Used on cygwin: object dumper.
+OBJDUMP="objdump"
+
+# Used on cygwin: assembler.
+AS="as"
+
+# The name of the directory that contains temporary libtool files.
+objdir=.libs
+
+# How to create reloadable object files.
+reload_flag=" -r"
+reload_cmds="\$LD\$reload_flag -o \$output\$reload_objs"
+
+# How to pass a linker flag through the compiler.
+wl="-Wl,"
+
+# Object file suffix (normally "o").
+objext="o"
+
+# Old archive suffix (normally "a").
+libext="a"
+
+# Shared library suffix (normally ".so").
+shrext='.dll'
+
+# Executable file suffix (normally "").
+exeext=""
+
+# Additional compiler flags for building library objects.
+pic_flag=" -DDLL_EXPORT -DPIC"
+pic_mode=default
+
+# What is the maximum length of a command?
+max_cmd_len=8192
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o="yes"
+
+# Must we lock files when doing compilation ?
+need_locks="no"
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=no
+
+# Do we need a version for libraries?
+need_version=no
+
+# Whether dlopen is supported.
+dlopen_support=unknown
+
+# Whether dlopen of programs is supported.
+dlopen_self=unknown
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=unknown
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag="-static"
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=" -fno-builtin -fno-rtti -fno-exceptions"
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec="\${wl}--export-dynamic"
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec="\${wl}--whole-archive\$convenience \${wl}--no-whole-archive"
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=""
+
+# Library versioning type.
+version_type=windows
+
+# Format of library name prefix.
+libname_spec="lib\$name"
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec="\$libname.dll.a"
+
+# The coded name of the library, if different from the real name.
+soname_spec="\${libname}\`echo \${release} | \$SED -e s/[.]/-/g\`\${versuffix}\${shared_ext}"
+
+# Commands used to build and install an old-style archive.
+RANLIB="ranlib"
+old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs\$old_deplibs~\$RANLIB \$oldlib"
+old_postinstall_cmds="\$RANLIB \$oldlib~chmod 644 \$oldlib"
+old_postuninstall_cmds=""
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=""
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=""
+
+# Commands used to build and install a shared archive.
+archive_cmds="\$CC -shared \$libobjs \$deplibs \$compiler_flags -o \$output_objdir/\$soname \${wl}--image-base=0x10000000 \${wl}--out-implib,\$lib"
+archive_expsym_cmds="if test \\\"x\\\`\$SED 1q \$export_symbols\\\`\\\" = xEXPORTS; then
+ cp \$export_symbols \$output_objdir/\$soname.def;
+ else
+ echo EXPORTS > \$output_objdir/\$soname.def;
+ cat \$export_symbols >> \$output_objdir/\$soname.def;
+ fi~
+ \$CC -shared \$output_objdir/\$soname.def \$libobjs \$deplibs \$compiler_flags -o \$output_objdir/\$soname \${wl}--image-base=0x10000000 \${wl}--out-implib,\$lib"
+postinstall_cmds="base_file=\\\`basename \\\${file}\\\`~
+ dlpath=\\\`\$SHELL 2>&1 -c '. \$dir/'\\\${base_file}'i;echo \\\$dlname'\\\`~
+ dldir=\$destdir/\\\`dirname \\\$dlpath\\\`~
+ test -d \\\$dldir || mkdir -p \\\$dldir~
+ \$install_prog \$dir/\$dlname \\\$dldir/\$dlname"
+postuninstall_cmds="dldll=\\\`\$SHELL 2>&1 -c '. \$file; echo \\\$dlname'\\\`~
+ dlpath=\$dir/\\\$dldll~
+ \$rm \\\$dlpath"
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=""
+module_expsym_cmds=""
+
+# Commands to strip libraries.
+old_striplib="strip --strip-debug"
+striplib="strip --strip-unneeded"
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=""
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=""
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=""
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=""
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=""
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method="file_magic ^x86 archive import|^x86 DLL"
+deplibs_check_method=pass_all
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd="win32_libid"
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag="supported"
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=""
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=""
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=""
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe="sed -n -e 's/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\(_\\)\\([_A-Za-z][_A-Za-z0-9]*\\) \\{0,1\\}\$/\\1 \\2\\3 \\3/p'"
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl="sed -n -e 's/^. .* \\(.*\\)\$/extern int \\1;/p'"
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address="sed -n -e 's/^: \\([^ ]*\\) \$/ {\\\"\\1\\\", (lt_ptr) 0},/p' -e 's/^[BCDEGRST] \\([^ ]*\\) \\([^ ]*\\)\$/ {\"\\2\", (lt_ptr) \\&\\2},/p'"
+
+# This is the shared library runtime path variable.
+runpath_var=LD_RUN_PATH
+
+# This is the shared library path variable.
+shlibpath_var=PATH
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=yes
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=immediate
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=no
+
+# Flag to hardcode $libdir into a binary during linking.
+# This must work even if $libdir does not exist.
+hardcode_libdir_flag_spec="\${wl}--rpath \${wl}\$libdir"
+
+# If ld is used when linking, flag to hardcode $libdir into
+# a binary during linking. This must work even if $libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=""
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=""
+
+# Set to yes if using DIR/libNAME during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=no
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=no
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=unsupported
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=no
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=unknown
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=" =c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/ /mingw/lib/gcc-lib/mingw32/3.2.3/ /usr/lib/gcc/mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/mingw32/3.2.3/ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../mingw32/3.2.3/ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../ /lib/mingw32/3.2.3/ /lib/ /usr/lib/mingw32/3.2.3/ /usr/lib/"
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+
+# Fix the shell variable $srcfile for the compiler.
+fix_srcfile_path=""
+
+# Set to yes if exported symbols are required.
+always_export_symbols=no
+
+# The commands to list exported symbols.
+export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED -e '/^[BCDGS] /s/.* \\\\([^ ]*\\\\)/\\\\1 DATA/' | \$SED -e '/^[AITW] /s/.* //' | sort | uniq > \$export_symbols"
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=""
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
+
+# Symbols that must always be exported.
+include_expsyms=""
+
+# ### END LIBTOOL CONFIG
+
+# ltmain.sh - Provide generalized library-building support services.
+# NOTE: Changing this file will not affect anything until you rerun configure.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003
+# Free Software Foundation, Inc.
+# Originally by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+#
+# 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.
+
+# Check that we have a working $echo.
+if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+elif test "X$1" = X--fallback-echo; then
+ # Avoid inline document here, it may be left over
+ :
+elif test "X`($echo '\t') 2>/dev/null`" = 'X\t'; then
+ # Yippee, $echo works!
+ :
+else
+ # Restart under the correct shell, and then maybe $echo will work.
+ exec $SHELL "$0" --no-reexec ${1+"$@"}
+fi
+
+if test "X$1" = X--fallback-echo; then
+ # used as fallback echo
+ shift
+ cat <<EOF
+$*
+EOF
+ exit 0
+fi
+
+# define SED for historic ltconfig's generated by Libtool 1.3
+test -z "$SED" && SED=sed
+
+# The name of this program.
+progname=`$echo "$0" | ${SED} 's%^.*/%%'`
+modename="$progname"
+
+# Constants.
+PROGRAM=ltmain.sh
+PACKAGE=libtool
+VERSION=1.5
+TIMESTAMP=" (1.1220.2.1 2003/04/14 22:48:00)"
+
+default_mode=
+help="Try \`$progname --help' for more information."
+magic="%%%MAGIC variable%%%"
+mkdir="mkdir"
+mv="mv -f"
+rm="rm -f"
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([\\`\\"$\\\\]\)/\\\1/g'
+# test EBCDIC or ASCII
+case `echo A|od -x` in
+ *[Cc]1*) # EBCDIC based system
+ SP2NL="tr '\100' '\n'"
+ NL2SP="tr '\r\n' '\100\100'"
+ ;;
+ *) # Assume ASCII based system
+ SP2NL="tr '\040' '\012'"
+ NL2SP="tr '\015\012' '\040\040'"
+ ;;
+esac
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+# We save the old values to restore during execute mode.
+if test "${LC_ALL+set}" = set; then
+ save_LC_ALL="$LC_ALL"; LC_ALL=C; export LC_ALL
+fi
+if test "${LANG+set}" = set; then
+ save_LANG="$LANG"; LANG=C; export LANG
+fi
+
+# Make sure IFS has a sensible default
+: ${IFS=" "}
+
+if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ $echo "$modename: not configured to build any kind of library" 1>&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit 1
+fi
+
+# Global variables.
+mode=$default_mode
+nonopt=
+prev=
+prevopt=
+run=
+show="$echo"
+show_help=
+execute_dlfiles=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+
+#####################################
+# Shell function definitions:
+# This seems to be the best place for them
+
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+win32_libid () {
+ win32_libid_type="unknown"
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | \
+ grep -E 'file format pe-i386(.*architecture: i386)?' >/dev/null ; then
+ win32_nmres=`eval $NM -f posix -A $1 | \
+ sed -n -e '1,100{/ I /{x;/import/!{s/^/import/;h;p;};x;};}'`
+ if test "X$win32_nmres" = "Ximport" ; then
+ win32_libid_type="x86 archive import"
+ else
+ win32_libid_type="x86 archive static"
+ fi
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $echo $win32_libid_type
+}
+
+# End of Shell function definitions
+#####################################
+
+# Parse our command line options once, thoroughly.
+while test "$#" -gt 0
+do
+ arg="$1"
+ shift
+
+ case $arg in
+ -*=*) optarg=`$echo "X$arg" | $Xsed -e 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ execute_dlfiles)
+ execute_dlfiles="$execute_dlfiles $arg"
+ ;;
+ tag)
+ tagname="$arg"
+
+ # Check whether tagname contains only valid characters
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ $echo "$progname: invalid tag name: $tagname" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case $tagname in
+ CC)
+ # Don't test for the "default" C tag, as we know, it's there, but
+ # not specially marked.
+ ;;
+ *)
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$" < "$0" > /dev/null; then
+ taglist="$taglist $tagname"
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$tagname'$/,/^# ### END LIBTOOL TAG CONFIG: '$tagname'$/p' < $0`"
+ else
+ $echo "$progname: ignoring unknown tag $tagname" 1>&2
+ fi
+ ;;
+ esac
+ ;;
+ *)
+ eval "$prev=\$arg"
+ ;;
+ esac
+
+ prev=
+ prevopt=
+ continue
+ fi
+
+ # Have we seen a non-optional argument yet?
+ case $arg in
+ --help)
+ show_help=yes
+ ;;
+
+ --version)
+ $echo "$PROGRAM (GNU $PACKAGE) $VERSION$TIMESTAMP"
+ $echo
+ $echo "Copyright (C) 2003 Free Software Foundation, Inc."
+ $echo "This is free software; see the source for copying conditions. There is NO"
+ $echo "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+ exit 0
+ ;;
+
+ --config)
+ ${SED} -e '1,/^# ### BEGIN LIBTOOL CONFIG/d' -e '/^# ### END LIBTOOL CONFIG/,$d' $0
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ ${SED} -n -e "/^# ### BEGIN LIBTOOL TAG CONFIG: $tagname$/,/^# ### END LIBTOOL TAG CONFIG: $tagname$/p" < "$0"
+ done
+ exit 0
+ ;;
+
+ --debug)
+ $echo "$progname: enabling shell trace mode"
+ set -x
+ ;;
+
+ --dry-run | -n)
+ run=:
+ ;;
+
+ --features)
+ $echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ $echo "enable shared libraries"
+ else
+ $echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ $echo "enable static libraries"
+ else
+ $echo "disable static libraries"
+ fi
+ exit 0
+ ;;
+
+ --finish) mode="finish" ;;
+
+ --mode) prevopt="--mode" prev=mode ;;
+ --mode=*) mode="$optarg" ;;
+
+ --preserve-dup-deps) duplicate_deps="yes" ;;
+
+ --quiet | --silent)
+ show=:
+ ;;
+
+ --tag) prevopt="--tag" prev=tag ;;
+ --tag=*)
+ set tag "$optarg" ${1+"$@"}
+ shift
+ prev=tag
+ ;;
+
+ -dlopen)
+ prevopt="-dlopen"
+ prev=execute_dlfiles
+ ;;
+
+ -*)
+ $echo "$modename: unrecognized option \`$arg'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+
+ *)
+ nonopt="$arg"
+ break
+ ;;
+ esac
+done
+
+if test -n "$prevopt"; then
+ $echo "$modename: option \`$prevopt' requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+fi
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+if test -z "$show_help"; then
+
+ # Infer the operation mode.
+ if test -z "$mode"; then
+ $echo "*** Warning: inferring the mode of operation is deprecated." 1>&2
+ $echo "*** Future versions of Libtool will require -mode=MODE be specified." 1>&2
+ case $nonopt in
+ *cc | cc* | *++ | gcc* | *-gcc* | g++* | xlc*)
+ mode=link
+ for arg
+ do
+ case $arg in
+ -c)
+ mode=compile
+ break
+ ;;
+ esac
+ done
+ ;;
+ *db | *dbx | *strace | *truss)
+ mode=execute
+ ;;
+ *install*|cp|mv)
+ mode=install
+ ;;
+ *rm)
+ mode=uninstall
+ ;;
+ *)
+ # If we have no mode, but dlfiles were specified, then do execute mode.
+ test -n "$execute_dlfiles" && mode=execute
+
+ # Just use the default operation mode.
+ if test -z "$mode"; then
+ if test -n "$nonopt"; then
+ $echo "$modename: warning: cannot infer operation mode from \`$nonopt'" 1>&2
+ else
+ $echo "$modename: warning: cannot infer operation mode without MODE-ARGS" 1>&2
+ fi
+ fi
+ ;;
+ esac
+ fi
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$execute_dlfiles" && test "$mode" != execute; then
+ $echo "$modename: unrecognized option \`-dlopen'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$modename --help --mode=$mode' for more information."
+
+ # These modes are in order of execution frequency so that they run quickly.
+ case $mode in
+ # libtool compile mode
+ compile)
+ modename="$modename: compile"
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ suppress_output=
+ arg_mode=normal
+ libobj=
+
+ for arg
+ do
+ case "$arg_mode" in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg="$arg"
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj="$arg"
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ if test -n "$libobj" ; then
+ $echo "$modename: you cannot specify \`-o' more than once" 1>&2
+ exit 1
+ fi
+ arg_mode=target
+ continue
+ ;;
+
+ -static)
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "s/^-Wc,//"`
+ lastarg=
+ save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ lastarg="$lastarg $arg"
+ done
+ IFS="$save_ifs"
+ lastarg=`$echo "X$lastarg" | $Xsed -e "s/^ //"`
+
+ # Add the arguments to base_compile.
+ base_compile="$base_compile $lastarg"
+ continue
+ ;;
+
+ * )
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg="$srcfile"
+ srcfile="$arg"
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ lastarg=`$echo "X$lastarg" | $Xsed -e "$sed_quote_subst"`
+
+ case $lastarg in
+ # Double-quote args containing other shell metacharacters.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ lastarg="\"$lastarg\""
+ ;;
+ esac
+
+ base_compile="$base_compile $lastarg"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ $echo "$modename: you must specify an argument for -Xcompile"
+ exit 1
+ ;;
+ target)
+ $echo "$modename: you must specify a target with \`-o'" 1>&2
+ exit 1
+ ;;
+ *)
+ # Get the name of the library object.
+ [ -z "$libobj" ] && libobj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%'`
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ xform='[cCFSifmso]'
+ case $libobj in
+ *.ada) xform=ada ;;
+ *.adb) xform=adb ;;
+ *.ads) xform=ads ;;
+ *.asm) xform=asm ;;
+ *.c++) xform=c++ ;;
+ *.cc) xform=cc ;;
+ *.ii) xform=ii ;;
+ *.class) xform=class ;;
+ *.cpp) xform=cpp ;;
+ *.cxx) xform=cxx ;;
+ *.f90) xform=f90 ;;
+ *.for) xform=for ;;
+ *.java) xform=java ;;
+ esac
+
+ libobj=`$echo "X$libobj" | $Xsed -e "s/\.$xform$/.lo/"`
+
+ case $libobj in
+ *.lo) obj=`$echo "X$libobj" | $Xsed -e "$lo2o"` ;;
+ *)
+ $echo "$modename: cannot determine name of library object from \`$libobj'" 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Infer tagged configuration to use if any are available and
+ # if one wasn't chosen via the "--tag" command line option.
+ # Only attempt this if the compiler in the base compile
+ # command doesn't match the default compiler.
+ if test -n "$available_tags" && test -z "$tagname"; then
+ case $base_compile in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " `$echo $CC` "* | "`$echo $CC` "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`"
+ case "$base_compile " in
+ "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ $echo "$modename: unable to infer tagged configuration"
+ $echo "$modename: specify a tag with \`--tag'" 1>&2
+ exit 1
+# else
+# $echo "$modename: using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+
+ objname=`$echo "X$obj" | $Xsed -e 's%^.*/%%'`
+ xdir=`$echo "X$obj" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$obj"; then
+ xdir=
+ else
+ xdir=$xdir/
+ fi
+ lobj=${xdir}$objdir/$objname
+
+ if test -z "$base_compile"; then
+ $echo "$modename: you must specify a compilation command" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ $run $rm $removelist
+ trap "$run $rm $removelist; exit 1" 1 2 15
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2*)
+ pic_mode=default
+ ;;
+ esac
+ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$echo "X$srcfile" | $Xsed -e 's%^.*/%%' -e 's%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ removelist="$removelist $output_obj $lockfile"
+ trap "$run $rm $removelist; exit 1" 1 2 15
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $run ln "$0" "$lockfile" 2>/dev/null; do
+ $show "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ $echo "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+ $echo $srcfile > "$lockfile"
+ fi
+
+ if test -n "$fix_srcfile_path"; then
+ eval srcfile=\"$fix_srcfile_path\"
+ fi
+
+ $run $rm "$libobj" "${libobj}T"
+
+ # Create a libtool object file (analogous to a ".la" file),
+ # but don't create it if we're doing a dry run.
+ test -z "$run" && cat > ${libobj}T <<EOF
+# $libobj - a libtool object file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+EOF
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test "$pic_mode" != no; then
+ command="$base_compile $srcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $srcfile"
+ fi
+
+ if test ! -d "${xdir}$objdir"; then
+ $show "$mkdir ${xdir}$objdir"
+ $run $mkdir ${xdir}$objdir
+ status=$?
+ if test "$status" -ne 0 && test ! -d "${xdir}$objdir"; then
+ exit $status
+ fi
+ fi
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ command="$command -o $lobj"
+ fi
+
+ $run $rm "$lobj" "$output_obj"
+
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ test -n "$output_obj" && $run $rm $removelist
+ exit 1
+ fi
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ $show "$mv $output_obj $lobj"
+ if $run $mv $output_obj $lobj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the PIC object to the libtool object file.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object='$objdir/$objname'
+
+EOF
+
+ # Allow error messages only from the first compilation.
+ suppress_output=' >/dev/null 2>&1'
+ else
+ # No PIC object so indicate it doesn't exist in the libtool
+ # object file.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+pic_object=none
+
+EOF
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ if test "$pic_mode" != yes; then
+ # Don't build PIC code
+ command="$base_compile $srcfile"
+ else
+ command="$base_compile $srcfile $pic_flag"
+ fi
+ if test "$compiler_c_o" = yes; then
+ command="$command -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ command="$command$suppress_output"
+ $run $rm "$obj" "$output_obj"
+ $show "$command"
+ if $run eval "$command"; then :
+ else
+ $run $rm $removelist
+ exit 1
+ fi
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $echo "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $run $rm $removelist
+ exit 1
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ $show "$mv $output_obj $obj"
+ if $run $mv $output_obj $obj; then :
+ else
+ error=$?
+ $run $rm $removelist
+ exit $error
+ fi
+ fi
+
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object='$objname'
+
+EOF
+ else
+ # Append the name of the non-PIC object the libtool object file.
+ # Only append if the libtool object file exists.
+ test -z "$run" && cat >> ${libobj}T <<EOF
+# Name of the non-PIC object.
+non_pic_object=none
+
+EOF
+ fi
+
+ $run $mv "${libobj}T" "${libobj}"
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ $run $rm "$lockfile"
+ fi
+
+ exit 0
+ ;;
+
+ # libtool link mode
+ link | relink)
+ modename="$modename: link"
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args="$nonopt"
+ base_compile="$nonopt"
+ compile_command="$nonopt"
+ finalize_command="$nonopt"
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+
+ avoid_version=no
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ non_pic_objects=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -all-static | -static)
+ if test "X$arg" = "X-all-static"; then
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ $echo "$modename: warning: complete static linking is impossible in this configuration" 1>&2
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ else
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ fi
+ build_libtool_libs=no
+ build_old_libs=yes
+ prefer_static_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg="$1"
+ base_compile="$base_compile $arg"
+ shift
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ qarg=\"`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`\" ### testsuite: skip nested quoting test
+ ;;
+ *) qarg=$arg ;;
+ esac
+ libtool_args="$libtool_args $qarg"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ compile_command="$compile_command @OUTPUT@"
+ finalize_command="$finalize_command @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ compile_command="$compile_command @SYMFILE@"
+ finalize_command="$finalize_command @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ dlfiles="$dlfiles $arg"
+ else
+ dlprefiles="$dlprefiles $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ if test ! -f "$arg"; then
+ $echo "$modename: symbol file \`$arg' does not exist"
+ exit 1
+ fi
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat $save_arg`
+ do
+# moreargs="$moreargs $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit 1
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit 1
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ done
+ else
+ $echo "$modename: link input file \`$save_arg' does not exist"
+ exit 1
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit 1
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) rpath="$rpath $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) xrpath="$xrpath $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ xcompiler)
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ xlinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $wl$qarg"
+ prev=
+ compile_command="$compile_command $wl$qarg"
+ finalize_command="$finalize_command $wl$qarg"
+ continue
+ ;;
+ xcclinker)
+ linker_flags="$linker_flags $qarg"
+ compiler_flags="$compiler_flags $qarg"
+ prev=
+ compile_command="$compile_command $qarg"
+ finalize_command="$finalize_command $qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ compile_command="$compile_command $link_static_flag"
+ finalize_command="$finalize_command $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ $echo "$modename: \`-allow-undefined' is deprecated because it is the default" 1>&2
+ continue
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: more than one -exported-symbols argument is not allowed"
+ exit 1
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-L//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: cannot determine absolute directory name of \`$dir'" 1>&2
+ exit 1
+ fi
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "*) ;;
+ *)
+ deplibs="$deplibs -L$dir"
+ lib_search_path="$lib_search_path $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$dir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-pw32* | *-*-beos*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-mingw* | *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ deplibs="$deplibs -framework System"
+ continue
+ esac
+ elif test "X$arg" = "X-lc_r"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ deplibs="$deplibs $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # gcc -m* arguments should be passed to the linker via $compiler_flags
+ # in order to pass architecture information to the linker
+ # (e.g. 32 vs 64-bit). This may also be accomplished via -Wl,-mfoo
+ # but this is not reliable with gcc because gcc may use -mfoo to
+ # select a different linker, different libraries, etc, while
+ # -Wl,-mfoo simply passes -mfoo to the linker.
+ -m*)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ if test "$with_gcc" = "yes" ; then
+ compiler_flags="$compiler_flags $arg"
+ fi
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # in order for the loader to find any dlls it needs.
+ $echo "$modename: warning: \`-no-install' is ignored for $host" 1>&2
+ $echo "$modename: warning: assuming \`-no-fast-install' instead" 1>&2
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ dir=`$echo "X$arg" | $Xsed -e 's/^-R//'`
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ $echo "$modename: only absolute run-paths are allowed" 1>&2
+ exit 1
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ continue
+ ;;
+
+ -static)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -Wc,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wc,//'`
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Wl,*)
+ args=`$echo "X$arg" | $Xsed -e "$sed_quote_subst" -e 's/^-Wl,//'`
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ case $flag in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ flag="\"$flag\""
+ ;;
+ esac
+ arg="$arg $wl$flag"
+ compiler_flags="$compiler_flags $wl$flag"
+ linker_flags="$linker_flags $flag"
+ done
+ IFS="$save_ifs"
+ arg=`$echo "X$arg" | $Xsed -e "s/^ //"`
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+
+ *.$objext)
+ # A standard object.
+ objs="$objs $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if (${SED} -e '2q' $arg | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ # If there is no directory component, then add one.
+ case $arg in
+ */* | *\\*) . $arg ;;
+ *) . ./$arg ;;
+ esac
+
+ if test -z "$pic_object" || \
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none && \
+ test "$non_pic_object" = none; then
+ $echo "$modename: cannot find name of object for \`$arg'" 1>&2
+ exit 1
+ fi
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ dlfiles="$dlfiles $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ dlprefiles="$dlprefiles $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ libobjs="$libobjs $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if test -z "$run"; then
+ $echo "$modename: \`$arg' is not a valid libtool object" 1>&2
+ exit 1
+ else
+ # Dry-run case.
+
+ # Extract subdirectory from the argument.
+ xdir=`$echo "X$arg" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$xdir" = "X$arg"; then
+ xdir=
+ else
+ xdir="$xdir/"
+ fi
+
+ pic_object=`$echo "X${xdir}${objdir}/${arg}" | $Xsed -e "$lo2o"`
+ non_pic_object=`$echo "X${xdir}${arg}" | $Xsed -e "$lo2o"`
+ libobjs="$libobjs $pic_object"
+ non_pic_objects="$non_pic_objects $non_pic_object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ deplibs="$deplibs $arg"
+ old_deplibs="$old_deplibs $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ dlfiles="$dlfiles $arg"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ dlprefiles="$dlprefiles $arg"
+ prev=
+ else
+ deplibs="$deplibs $arg"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ arg="\"$arg\""
+ ;;
+ esac
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+ done # argument parsing loop
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prevarg' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Infer tagged configuration to use if any are available and
+ # if one wasn't chosen via the "--tag" command line option.
+ # Only attempt this if the compiler in the base link
+ # command doesn't match the default compiler.
+ if test -n "$available_tags" && test -z "$tagname"; then
+ case $base_compile in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if grep "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$0" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $0`"
+ case $base_compile in
+ "$CC "* | " $CC "* | "`$echo $CC` "* | " `$echo $CC` "*)
+ # The compiler in $compile_command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ $echo "$modename: unable to infer tagged configuration"
+ $echo "$modename: specify a tag with \`--tag'" 1>&2
+ exit 1
+# else
+# $echo "$modename: using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ compile_command="$compile_command $arg"
+ finalize_command="$finalize_command $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ outputname=`$echo "X$output" | $Xsed -e 's%^.*/%%'`
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$echo \"X\${$shlibpath_var}\" \| \$Xsed -e \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ output_objdir=`$echo "X$output" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$output_objdir" = "X$output"; then
+ output_objdir="$objdir"
+ else
+ output_objdir="$output_objdir/$objdir"
+ fi
+ # Create the object directory.
+ if test ! -d "$output_objdir"; then
+ $show "$mkdir $output_objdir"
+ $run $mkdir $output_objdir
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$output_objdir"; then
+ exit $status
+ fi
+ fi
+
+ # Determine the type of output
+ case $output in
+ "")
+ $echo "$modename: you must specify an output file" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ case $host in
+ *cygwin* | *mingw* | *pw32*)
+ # don't eliminate duplcations in $postdeps and $predeps
+ duplicate_compiler_generated_deps=yes
+ ;;
+ *)
+ duplicate_compiler_generated_deps=$duplicate_deps
+ ;;
+ esac
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ libs="$libs $deplib"
+ done
+
+ if test "$linkmode" = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if test "X$duplicate_compiler_generated_deps" = "Xyes" ; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;;
+ esac
+ pre_post_deps="$pre_post_deps $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+ case $linkmode in
+ lib)
+ passes="conv link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ $echo "$modename: libraries can \`-dlopen' only libtool libraries: $file" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+ for pass in $passes; do
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan"; then
+ libs="$deplibs"
+ deplibs=
+ fi
+ if test "$linkmode" = prog; then
+ case $pass in
+ dlopen) libs="$dlfiles" ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+ esac
+ fi
+ if test "$pass" = dlopen; then
+ # Collect dlpreopened libraries
+ save_deplibs="$deplibs"
+ deplibs=
+ fi
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -l*)
+ if test "$linkmode" != lib && test "$linkmode" != prog; then
+ $echo "$modename: warning: \`-l' is ignored for archives/objects" 1>&2
+ continue
+ fi
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ name=`$echo "X$deplib" | $Xsed -e 's/^-l//'`
+ for searchdir in $newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}.la"
+ if test -f "$lib"; then
+ found=yes
+ break
+ fi
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ else # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if (${SED} -e '2q' $lib |
+ grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ library_names=
+ old_library=
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ for l in $old_library $library_names; do
+ ll="$l"
+ done
+ if test "X$ll" = "X$old_library" ; then # only static version available
+ found=no
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+ lib=$ladir/$old_library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ fi
+ ;; # -l
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test "$pass" = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ ;;
+ prog)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test "$pass" = scan; then
+ deplibs="$deplib $deplibs"
+ newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ ;;
+ *)
+ $echo "$modename: warning: \`-L' is ignored for archives/objects" 1>&2
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test "$pass" = link; then
+ dir=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) xrpath="$xrpath $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la) lib="$deplib" ;;
+ *.$libext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ if test "$deplibs_check_method" != pass_all; then
+ $echo
+ $echo "*** Warning: Trying to link with static lib archive $deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because the file extensions .$libext of this argument makes me believe"
+ $echo "*** that it is just a static archive that I should not used here."
+ else
+ $echo
+ $echo "*** Warning: Linking the shared library $output against the"
+ $echo "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ continue
+ ;;
+ prog)
+ if test "$pass" != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ elif test "$linkmode" = prog; then
+ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ newdlprefiles="$newdlprefiles $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ newdlfiles="$newdlfiles $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+ if test "$found" = yes || test -f "$lib"; then :
+ else
+ $echo "$modename: cannot find the library \`$lib'" 1>&2
+ exit 1
+ fi
+
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $lib | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+
+ ladir=`$echo "X$lib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$ladir" = "X$lib" && ladir="."
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+
+ # Read the .la file
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ test -n "$dlopen" && dlfiles="$dlfiles $dlopen"
+ test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen"
+ fi
+
+ if test "$pass" = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit 1
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ convenience="$convenience $ladir/$objdir/$old_library"
+ old_convenience="$old_convenience $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+ elif test "$linkmode" != prog && test "$linkmode" != lib; then
+ $echo "$modename: \`$lib' is not a convenience library" 1>&2
+ exit 1
+ fi
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ if test -z "$linklib"; then
+ $echo "$modename: cannot find name of link library for \`$lib'" 1>&2
+ exit 1
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$pass" = dlopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlopen a convenience library: \`$lib'" 1>&2
+ exit 1
+ fi
+ if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ dlprefiles="$dlprefiles $lib $dependency_libs"
+ else
+ newdlfiles="$newdlfiles $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$ladir'" 1>&2
+ $echo "$modename: passing it literally to the linker, although it might fail" 1>&2
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ laname=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ $echo "$modename: warning: library \`$lib' was moved." 1>&2
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$libdir"
+ absdir="$libdir"
+ fi
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ notinst_path="$notinst_path $abs_ladir"
+ fi # $installed = yes
+ name=`$echo "X$laname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+
+ # This library was specified with -dlpreopen.
+ if test "$pass" = dlpreopen; then
+ if test -z "$libdir"; then
+ $echo "$modename: cannot -dlpreopen a convenience library: \`$lib'" 1>&2
+ exit 1
+ fi
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ newdlprefiles="$newdlprefiles $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ newdlprefiles="$newdlprefiles $dir/$dlname"
+ else
+ newdlprefiles="$newdlprefiles $dir/$linklib"
+ fi
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test "$linkmode" = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test "$linkmode" = prog && test "$pass" != link; then
+ newlib_search_path="$newlib_search_path $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) newlib_search_path="$newlib_search_path "`$echo "X$deplib" | $Xsed -e 's/^-L//'`;; ### testsuite: skip nested quoting test
+ esac
+ # Need to link against all dependency_libs?
+ if test "$linkalldeplibs" = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test "$linkmode,$pass" = "prog,link"; then
+ if test -n "$library_names" &&
+ { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var"; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath " in
+ *" $dir "*) ;;
+ *" $absdir "*) ;;
+ *) temp_rpath="$temp_rpath $dir" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ if test -n "$library_names" &&
+ { test "$prefer_static_libs" = no || test -z "$old_library"; }; then
+ if test "$installed" = no; then
+ notinst_deplibs="$notinst_deplibs $lib"
+ need_relink=yes
+ fi
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on some systems (darwin)
+ if test "$shouldnotlink" = yes && test "$pass" = link ; then
+ $echo
+ if test "$linkmode" = prog; then
+ $echo "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $echo "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $echo "*** $linklib is not portable!"
+ fi
+ if test "$linkmode" = lib &&
+ test "$hardcode_into_libs" = yes; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) compile_rpath="$compile_rpath $absdir"
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir"
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+ libname=`eval \\$echo \"$libname_spec\"`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw*)
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ soname=`$echo $soroot | ${SED} -e 's/^.*\///'`
+ newlib="libimp-`$echo $soname | ${SED} 's/^lib//;s/\.dll$//'`.a"
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ $show "extracting exported symbol list from \`$soname'"
+ save_ifs="$IFS"; IFS='~'
+ eval cmds=\"$extract_expsyms_cmds\"
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ $show "generating import library for \`$soname'"
+ save_ifs="$IFS"; IFS='~'
+ eval cmds=\"$old_archive_from_expsyms_cmds\"
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test "$linkmode" = prog || test "$mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ case $host in
+ *-*-sco3.2v5* ) add_dir="-L$dir" ;;
+ *-*-darwin* )
+ # if the lib is a module then we can not link against it, someone
+ # is ignoring the new warnings I added
+ if /usr/bin/file -L $add 2> /dev/null | grep "bundle" >/dev/null ; then
+ $echo "** Warning, lib $linklib is a module, not a shared library"
+ if test -z "$old_library" ; then
+ $echo
+ $echo "** And there doesn't seem to be a static archive available"
+ $echo "** The link will probably fail, sorry"
+ else
+ add="$dir/$old_library"
+ fi
+ fi
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$dir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case "$libdir" in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ $echo "$modename: configuration error: unsupported hardcode properties"
+ exit 1
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;;
+ esac
+ fi
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes && \
+ test "$hardcode_minus_L" != yes && \
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test "$linkmode" = prog || test "$mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;;
+ esac
+ add="-l$name"
+ elif test "$hardcode_automatic" = yes; then
+ if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ add="$inst_prefix_dir$libdir/$linklib"
+ else
+ add="$libdir/$linklib"
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case "$libdir" in
+ [\\/]*)
+ add_dir="$add_dir -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ fi
+
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test "$linkmode" = prog; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ $echo
+ $echo "*** Warning: This system can not link to static lib archive $lib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ $echo "*** But as you try to build a module library, libtool will still create "
+ $echo "*** a static module, that should work as long as the dlopening application"
+ $echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ $echo
+ $echo "*** However, this would only work if libtool was able to extract symbol"
+ $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $echo "*** not find such a program. So, this module is probably useless."
+ $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ convenience="$convenience $dir/$old_library"
+ old_convenience="$old_convenience $dir/$old_library"
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test "$linkmode" = lib; then
+ if test -n "$dependency_libs" &&
+ { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes ||
+ test "$link_static" = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) temp_xrpath=`$echo "X$libdir" | $Xsed -e 's/^-R//'`
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) xrpath="$xrpath $temp_xrpath";;
+ esac;;
+ *) temp_deplibs="$temp_deplibs $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ newlib_search_path="$newlib_search_path $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ if test "X$duplicate_deps" = "Xyes" ; then
+ case "$tmp_libs " in
+ *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;;
+ esac
+ fi
+ tmp_libs="$tmp_libs $deplib"
+ done
+
+ if test "$link_all_deplibs" != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ dir=`$echo "X$deplib" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$deplib" && dir="."
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ $echo "$modename: warning: cannot determine absolute directory name of \`$dir'" 1>&2
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if grep "^installed=no" $deplib > /dev/null; then
+ path="$absdir/$objdir"
+ else
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ if test "$absdir" != "$libdir"; then
+ $echo "$modename: warning: \`$deplib' seems to be moved" 1>&2
+ fi
+ path="$absdir"
+ fi
+ depdepl=
+ case $host in
+ *-*-darwin*)
+ # we do not want to link against static libs, but need to link against shared
+ eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names" ; then
+ for tmp in $deplibrary_names ; do
+ depdepl=$tmp
+ done
+ if test -f "$path/$depdepl" ; then
+ depdepl="$path/$depdepl"
+ fi
+ newlib_search_path="$newlib_search_path $path"
+ path=""
+ fi
+ ;;
+ *)
+ path="-L$path"
+ ;;
+ esac
+
+ ;;
+ -l*)
+ case $host in
+ *-*-darwin*)
+ # Again, we only want to link against shared libraries
+ eval tmp_libs=`$echo "X$deplib" | $Xsed -e "s,^\-l,,"`
+ for tmp in $newlib_search_path ; do
+ if test -f "$tmp/lib$tmp_libs.dylib" ; then
+ eval depdepl="$tmp/lib$tmp_libs.dylib"
+ break
+ fi
+ done
+ path=""
+ ;;
+ *) continue ;;
+ esac
+ ;;
+ *) continue ;;
+ esac
+ case " $deplibs " in
+ *" $depdepl "*) ;;
+ *) deplibs="$deplibs $depdepl" ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$deplibs $path" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ dependency_libs="$newdependency_libs"
+ if test "$pass" = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test "$pass" != dlopen; then
+ if test "$pass" != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) lib_search_path="$lib_search_path $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ ;;
+ *) tmp_libs="$tmp_libs $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+ # Last step: remove runtime libs from dependency_libs (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs ; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=""
+ ;;
+ esac
+ if test -n "$i" ; then
+ tmp_libs="$tmp_libs $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test "$linkmode" = prog; then
+ dlfiles="$newdlfiles"
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for archives" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info/-version-number' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for archives" 1>&2
+ fi
+
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ $echo "$modename: warning: \`-export-symbols' is ignored for archives" 1>&2
+ fi
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ objs="$objs$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//' -e 's/^lib//'`
+ eval shared_ext=\"$shrext\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ if test "$module" = no; then
+ $echo "$modename: libtool library \`$output' must begin with \`lib'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ name=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ eval shared_ext=\"$shrext\"
+ eval libname=\"$libname_spec\"
+ else
+ libname=`$echo "X$outputname" | $Xsed -e 's/\.la$//'`
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ $echo "$modename: cannot build libtool library \`$output' from non-libtool objects on this host:$objs" 2>&1
+ exit 1
+ else
+ $echo
+ $echo "*** Warning: Linking the shared library $output against the non-libtool"
+ $echo "*** objects $objs is not portable!"
+ libobjs="$libobjs $objs"
+ fi
+ fi
+
+ if test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen self' is ignored for libtool libraries" 1>&2
+ fi
+
+ set dummy $rpath
+ if test "$#" -gt 2; then
+ $echo "$modename: warning: ignoring multiple \`-rpath's for a libtool library" 1>&2
+ fi
+ install_libdir="$2"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info/-version-number' is ignored for convenience libraries" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for convenience libraries" 1>&2
+ fi
+ else
+
+ # Parse the version information argument.
+ save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ IFS="$save_ifs"
+
+ if test -n "$8"; then
+ $echo "$modename: too many parameters to \`-version-info'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major="$2"
+ number_minor="$3"
+ number_revision="$4"
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # which has an extra 1 added just for fun
+ #
+ case $version_type in
+ darwin|linux|osf|windows)
+ current=`expr $number_major + $number_minor`
+ age="$number_minor"
+ revision="$number_revision"
+ ;;
+ freebsd-aout|freebsd-elf|sunos)
+ current="$number_major"
+ revision="$number_minor"
+ age="0"
+ ;;
+ irix|nonstopux)
+ current=`expr $number_major + $number_minor - 1`
+ age="$number_minor"
+ revision="$number_minor"
+ ;;
+ esac
+ ;;
+ no)
+ current="$2"
+ revision="$3"
+ age="$4"
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ [0-9]*) ;;
+ *)
+ $echo "$modename: CURRENT \`$current' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case $revision in
+ [0-9]*) ;;
+ *)
+ $echo "$modename: REVISION \`$revision' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ case $age in
+ [0-9]*) ;;
+ *)
+ $echo "$modename: AGE \`$age' is not a nonnegative integer" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ $echo "$modename: AGE \`$age' is greater than the current interface number \`$current'" 1>&2
+ $echo "$modename: \`$vinfo' is not valid version information" 1>&2
+ exit 1
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ minor_current=`expr $current + 1`
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current";
+ ;;
+
+ irix | nonstopux)
+ major=`expr $current - $age + 1`
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring="$verstring_prefix$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test "$loop" -ne 0; do
+ iface=`expr $revision - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring_prefix$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux)
+ major=.`expr $current - $age`
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ major=.`expr $current - $age`
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test "$loop" -ne 0; do
+ iface=`expr $current - $loop`
+ loop=`expr $loop - 1`
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ verstring="$verstring:${current}.0"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ major=`expr $current - $age`
+ versuffix="-$major"
+ ;;
+
+ *)
+ $echo "$modename: unknown library version type \`$version_type'" 1>&2
+ $echo "Fatal configuration error. See the $PACKAGE docs for more information." 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring="0.0"
+ ;;
+ esac
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ $echo "$modename: warning: undefined symbols not allowed in $host shared libraries" 1>&2
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+ fi
+
+ if test "$mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$echo "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ removelist="$removelist $p"
+ ;;
+ *) ;;
+ esac
+ done
+ if test -n "$removelist"; then
+ $show "${rm}r $removelist"
+ $run ${rm}r $removelist
+ fi
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ oldlibs="$oldlibs $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}'$/d' -e "$lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ for path in $notinst_path; do
+ lib_search_path=`$echo "$lib_search_path " | ${SED} -e 's% $path % %g'`
+ deplibs=`$echo "$deplibs " | ${SED} -e 's% -L$path % %g'`
+ dependency_libs=`$echo "$dependency_libs " | ${SED} -e 's% -L$path % %g'`
+ done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ temp_xrpath="$temp_xrpath -R$libdir"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) dlfiles="$dlfiles $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) dlprefiles="$dlprefiles $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ deplibs="$deplibs -framework System"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test "$build_libtool_need_lc" = "yes"; then
+ deplibs="$deplibs -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $rm conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $rm conftest
+ $LTCC -o conftest conftest.c $deplibs
+ if test "$?" -eq 0 ; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ name="`expr $i : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" -ne "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: dynamic linker does not accept needed library $i."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which I believe you do not have"
+ $echo "*** because a test_compile did reveal that the linker did not use it for"
+ $echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ name="`expr $i : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" != "0"; then
+ $rm conftest
+ $LTCC -o conftest conftest.c $i
+ # Did it work?
+ if test "$?" -eq 0 ; then
+ ldd_output=`ldd conftest`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ newdeplibs="$newdeplibs $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ deplib_matches=`eval \\$echo \"$library_names_spec\"`
+ set dummy $deplib_matches
+ deplib_match=$2
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ newdeplibs="$newdeplibs $i"
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: dynamic linker does not accept needed library $i."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because a test_compile did reveal that the linker did not use this one"
+ $echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning! Library $i is needed by this library but I was not able to"
+ $echo "*** make it link in! You will probably need to install it or some"
+ $echo "*** library that it depends on before this library will be fully"
+ $echo "*** functional. Installing it before continuing would be even better."
+ fi
+ else
+ newdeplibs="$newdeplibs $i"
+ fi
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method
+ file_magic_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name="`expr $a_deplib : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test "$name" != "" && test "$name" != "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null \
+ | grep " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$echo "X$potlib" | $Xsed -e 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null \
+ | ${SED} 10q \
+ | $EGREP "$file_magic_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: linker path does not have real file for library $a_deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $echo "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $echo "*** with $libname and none of the candidates passed a file format test"
+ $echo "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method
+ match_pattern_regex=`expr "$deplibs_check_method" : "$2 \(.*\)"`
+ for a_deplib in $deplibs; do
+ name="`expr $a_deplib : '-l\(.*\)'`"
+ # If $name is empty we are operating on a -L argument.
+ if test -n "$name" && test "$name" != "0"; then
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval \\$echo \"$libname_spec\"`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib="$potent_lib" # see symlink-check above in file_magic test
+ if eval $echo \"$potent_lib\" 2>/dev/null \
+ | ${SED} 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ newdeplibs="$newdeplibs $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ $echo
+ $echo "*** Warning: linker path does not have real file for library $a_deplib."
+ $echo "*** I have the capability to make that library automatically link in when"
+ $echo "*** you link to this library. But I can only do this if you have a"
+ $echo "*** shared version of the library, which you do not appear to have"
+ $echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $echo "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $echo "*** with $libname and none of the candidates passed a file format test"
+ $echo "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ else
+ # Add a -L argument.
+ newdeplibs="$newdeplibs $a_deplib"
+ fi
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ tmp_deplibs=`$echo "X $deplibs" | $Xsed -e 's/ -lc$//' \
+ -e 's/ -[LR][^ ]*//g'`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ for i in $predeps $postdeps ; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$echo "X $tmp_deplibs" | ${SED} -e "1s,^X,," -e "s,$i,,"`
+ done
+ fi
+ if $echo "X $tmp_deplibs" | $Xsed -e 's/[ ]//g' \
+ | grep . >/dev/null; then
+ $echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ $echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ $echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ $echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ fi
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ newdeplibs=`$echo "X $newdeplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ $echo
+ $echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $echo "*** dependencies of module $libname. Therefore, libtool will create"
+ $echo "*** a static module, that should work as long as the dlopening"
+ $echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ $echo
+ $echo "*** However, this would only work if libtool was able to extract symbol"
+ $echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ $echo "*** not find such a program. So, this module is probably useless."
+ $echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ $echo "*** The inter-library dependencies that have been dropped here will be"
+ $echo "*** automatically added whenever a program is linked with this library"
+ $echo "*** or is declared to -dlopen it."
+
+ if test "$allow_undefined" = no; then
+ $echo
+ $echo "*** Since this library must not contain undefined symbols,"
+ $echo "*** because either the platform does not support them or"
+ $echo "*** it was explicitly requested with -no-undefined,"
+ $echo "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ if test "$hardcode_into_libs" = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ dep_rpath="$dep_rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ if test -n "$hardcode_libdir_flag_spec_ld"; then
+ eval dep_rpath=\"$hardcode_libdir_flag_spec_ld\"
+ else
+ eval dep_rpath=\"$hardcode_libdir_flag_spec\"
+ fi
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ realname="$2"
+ shift; shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib="$output_objdir/$realname"
+ for link
+ do
+ linknames="$linknames $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$echo "X$libobjs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ eval cmds=\"$export_symbols_cmds\"
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ if len=`expr "X$cmd" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ $show "using reloadable object file for export list..."
+ skipped_export=:
+ fi
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex"; then
+ $show "$EGREP -e \"$export_symbols_regex\" \"$export_symbols\" > \"${export_symbols}T\""
+ $run eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ $show "$mv \"${export_symbols}T\" \"$export_symbols\""
+ $run eval '$mv "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $run eval '$echo "X$include_expsyms" | $SP2NL >> "$export_symbols"'
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ tmp_deplibs="$tmp_deplibs $test_deplib"
+ ;;
+ esac
+ done
+ deplibs="$tmp_deplibs"
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${outputname}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ for xlib in $convenience; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ # We will extract separately just the conflicting names and we will no
+ # longer touch any unique names. It is faster to leave these extract
+ # automatically by $AR in one run.
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+ if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+ $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+ $AR t "$xabs" | sort | uniq -cd | while read -r count name
+ do
+ i=1
+ while test "$i" -le "$count"
+ do
+ # Put our $i before any first dot (extension)
+ # Never overwrite any file
+ name_to="$name"
+ while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+ do
+ name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+ done
+ $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+ $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+ i=`expr $i + 1`
+ done
+ done
+ fi
+
+ libobjs="$libobjs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ linker_flags="$linker_flags $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}U && $mv $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval cmds=\"$module_expsym_cmds\"
+ else
+ eval cmds=\"$module_cmds\"
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval cmds=\"$archive_expsym_cmds\"
+ else
+ eval cmds=\"$archive_cmds\"
+ fi
+ fi
+
+ if test "X$skipped_export" != "X:" && len=`expr "X$cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise.
+ $echo "creating reloadable object files..."
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ delfiles=
+ last_robj=
+ k=1
+ output=$output_objdir/$save_output-${k}.$objext
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ eval test_cmds=\"$reload_cmds $objlist $last_robj\"
+ if test "X$objlist" = X ||
+ { len=`expr "X$test_cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len"; }; then
+ objlist="$objlist $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test "$k" -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ eval concat_cmds=\"$reload_cmds $objlist $last_robj\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds $objlist $last_robj\"
+ fi
+ last_robj=$output_objdir/$save_output-${k}.$objext
+ k=`expr $k + 1`
+ output=$output_objdir/$save_output-${k}.$objext
+ objlist=$obj
+ len=1
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$reload_cmds $objlist $last_robj\"
+
+ if ${skipped_export-false}; then
+ $show "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $run $rm $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ eval concat_cmds=\"\$concat_cmds~$export_symbols_cmds\"
+ fi
+
+ # Set up a command to remove the reloadale object files
+ # after they are used.
+ i=0
+ while test "$i" -lt "$k"
+ do
+ i=`expr $i + 1`
+ delfiles="$delfiles $output_objdir/$save_output-${i}.$objext"
+ done
+
+ $echo "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval cmds=\"$archive_expsym_cmds\"
+ else
+ eval cmds=\"$archive_cmds\"
+ fi
+
+ # Append the command to remove the reloadable object files
+ # to the just-reset $cmds.
+ eval cmds=\"\$cmds~$rm $delfiles\"
+ fi
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$mode" = relink; then
+ $run eval '(cd $output_objdir && $rm ${realname}T && $mv $realname ${realname}T && $mv "$realname"U $realname)' || exit $?
+ exit 0
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ $show "(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval '(cd $output_objdir && $rm $linkname && $LN_S $realname $linkname)' || exit $?
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$deplibs"; then
+ $echo "$modename: warning: \`-l' and \`-L' are ignored for objects" 1>&2
+ fi
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ $echo "$modename: warning: \`-dlopen' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$rpath"; then
+ $echo "$modename: warning: \`-rpath' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$xrpath"; then
+ $echo "$modename: warning: \`-R' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for objects" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for objects" 1>&2
+ fi
+
+ case $output in
+ *.lo)
+ if test -n "$objs$old_deplibs"; then
+ $echo "$modename: cannot build library object \`$output' from non-libtool objects" 1>&2
+ exit 1
+ fi
+ libobj="$output"
+ obj=`$echo "X$output" | $Xsed -e "$lo2o"`
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $run $rm $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval reload_conv_objs=\"\$reload_objs $whole_archive_flag_spec\"
+ else
+ gentop="$output_objdir/${obj}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ for xlib in $convenience; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ # We will extract separately just the conflicting names and we will no
+ # longer touch any unique names. It is faster to leave these extract
+ # automatically by $AR in one run.
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+ if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+ $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+ $AR t "$xabs" | sort | uniq -cd | while read -r count name
+ do
+ i=1
+ while test "$i" -le "$count"
+ do
+ # Put our $i before any first dot (extension)
+ # Never overwrite any file
+ name_to="$name"
+ while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+ do
+ name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+ done
+ $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+ $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+ i=`expr $i + 1`
+ done
+ done
+ fi
+
+ reload_conv_objs="$reload_objs "`find $xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+ fi
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$echo "X$libobjs" | $SP2NL | $Xsed -e '/\.'${libext}$'/d' -e '/\.lib$/d' -e "$lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ eval cmds=\"$reload_cmds\"
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit 0
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $run eval "echo timestamp > $libobj" || exit $?
+ exit 0
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ eval cmds=\"$reload_cmds\"
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$gentop"; then
+ $show "${rm}r $gentop"
+ $run ${rm}r $gentop
+ fi
+
+ exit 0
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) output=`$echo $output | ${SED} -e 's,.exe$,,;s,$,.exe,'` ;;
+ esac
+ if test -n "$vinfo"; then
+ $echo "$modename: warning: \`-version-info' is ignored for programs" 1>&2
+ fi
+
+ if test -n "$release"; then
+ $echo "$modename: warning: \`-release' is ignored for programs" 1>&2
+ fi
+
+ if test "$preload" = yes; then
+ if test "$dlopen_support" = unknown && test "$dlopen_self" = unknown &&
+ test "$dlopen_self_static" = unknown; then
+ $echo "$modename: warning: \`AC_LIBTOOL_DLOPEN' not used. Assuming no dlopen support."
+ fi
+ fi
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$echo "X $compile_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ finalize_deplibs=`$echo "X $finalize_deplibs" | $Xsed -e 's/ -lc / -framework System /'`
+ ;;
+ esac
+
+ case $host in
+ *darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ if test "$tagname" = CXX ; then
+ compile_command="$compile_command ${wl}-bind_at_load"
+ finalize_command="$finalize_command ${wl}-bind_at_load"
+ fi
+ ;;
+ esac
+
+ compile_command="$compile_command $compile_deplibs"
+ finalize_command="$finalize_command $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_rpath="$finalize_rpath $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) perm_rpath="$perm_rpath $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2*)
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ *) dllsearchpath="$dllsearchpath:$libdir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ rpath="$rpath $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$echo "X$compile_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ finalize_command=`$echo "X$finalize_command" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ fi
+
+ dlsyms=
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ dlsyms="${outputname}S.c"
+ else
+ $echo "$modename: not configured to extract global symbols from dlpreopened files" 1>&2
+ fi
+ fi
+
+ if test -n "$dlsyms"; then
+ case $dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${outputname}.nm"
+
+ $show "$rm $nlist ${nlist}S ${nlist}T"
+ $run $rm "$nlist" "${nlist}S" "${nlist}T"
+
+ # Parse the name list into a source file.
+ $show "creating $output_objdir/$dlsyms"
+
+ test -z "$run" && $echo > "$output_objdir/$dlsyms" "\
+/* $dlsyms - symbol resolution table for \`$outputname' dlsym emulation. */
+/* Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+/* Prevent the only kind of declaration conflicts we can make. */
+#define lt_preloaded_symbols some_other_symbol
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ $show "generating symbol list for \`$output'"
+
+ test -z "$run" && $echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$echo "X$objs$old_deplibs" | $SP2NL | $Xsed -e "$lo2o" | $NL2SP`
+ for arg in $progfiles; do
+ $show "extracting global C symbols from \`$arg'"
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $run eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $run eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ $run eval '$mv "$nlist"T "$nlist"'
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$output.exp"
+ $run $rm $export_symbols
+ $run eval "${SED} -n -e '/^: @PROGRAM@$/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ else
+ $run eval "${SED} -e 's/\([][.*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$output.exp"'
+ $run eval 'grep -f "$output_objdir/$output.exp" < "$nlist" > "$nlist"T'
+ $run eval 'mv "$nlist"T "$nlist"'
+ fi
+ fi
+
+ for arg in $dlprefiles; do
+ $show "extracting global C symbols from \`$arg'"
+ name=`$echo "$arg" | ${SED} -e 's%^.*/%%'`
+ $run eval '$echo ": $name " >> "$nlist"'
+ $run eval "$NM $arg | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -z "$run"; then
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $mv "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if grep -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ grep -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$dlsyms"'
+ else
+ $echo '/* NONE */' >> "$output_objdir/$dlsyms"
+ fi
+
+ $echo >> "$output_objdir/$dlsyms" "\
+
+#undef lt_preloaded_symbols
+
+#if defined (__STDC__) && __STDC__
+# define lt_ptr void *
+#else
+# define lt_ptr char *
+# define const
+#endif
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ lt_ptr address;
+}
+lt_preloaded_symbols[] =
+{\
+"
+
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$dlsyms"
+
+ $echo >> "$output_objdir/$dlsyms" "\
+ {0, (lt_ptr) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ fi
+
+ pic_flag_for_symtable=
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND";;
+ esac;;
+ *-*-hpux*)
+ case "$compile_command " in
+ *" -static "*) ;;
+ *) pic_flag_for_symtable=" $pic_flag";;
+ esac
+ esac
+
+ # Now compile the dynamic symbol file.
+ $show "(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable \"$dlsyms\")"
+ $run eval '(cd $output_objdir && $LTCC -c$no_builtin_flag$pic_flag_for_symtable "$dlsyms")' || exit $?
+
+ # Clean up the generated files.
+ $show "$rm $output_objdir/$dlsyms $nlist ${nlist}S ${nlist}T"
+ $run $rm "$output_objdir/$dlsyms" "$nlist" "${nlist}S" "${nlist}T"
+
+ # Transform the symbol file into the correct name.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s%@SYMFILE@%$output_objdir/${outputname}S.${objext}%"`
+ ;;
+ *)
+ $echo "$modename: unknown suffix for \`$dlsyms'" 1>&2
+ exit 1
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$echo "X$compile_command" | $Xsed -e "s% @SYMFILE@%%"`
+ finalize_command=`$echo "X$finalize_command" | $Xsed -e "s% @SYMFILE@%%"`
+ fi
+
+ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+ # Replace the output file specification.
+ compile_command=`$echo "X$compile_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ $show "$link_command"
+ $run eval "$link_command"
+ status=$?
+
+ # Delete the generated files.
+ if test -n "$dlsyms"; then
+ $show "$rm $output_objdir/${outputname}S.${objext}"
+ $run $rm "$output_objdir/${outputname}S.${objext}"
+ fi
+
+ exit $status
+ fi
+
+ if test -n "$shlibpath_var"; then
+ # We should set the shlibpath_var
+ rpath=
+ for dir in $temp_rpath; do
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*)
+ # Absolute path.
+ rpath="$rpath$dir:"
+ ;;
+ *)
+ # Relative path: add a thisdir entry.
+ rpath="$rpath\$thisdir/$dir:"
+ ;;
+ esac
+ done
+ temp_rpath="$rpath"
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ rpath="$rpath$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $run $rm $output
+ # Link the executable and exit
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+ exit 0
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ $echo "$modename: warning: this platform does not like uninstalled shared libraries" 1>&2
+ $echo "$modename: \`$output' will be relinked during installation" 1>&2
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$echo "X$compile_var$compile_command$compile_rpath" | $Xsed -e 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$echo "X$link_command" | $Xsed -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $run $rm $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ $show "$link_command"
+ $run eval "$link_command" || exit $?
+
+ # Now create the wrapper script.
+ $show "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Quote $echo for shipping.
+ if test "X$echo" = "X$SHELL $0 --fallback-echo"; then
+ case $0 in
+ [\\/]* | [A-Za-z]:[\\/]*) qecho="$SHELL $0 --fallback-echo";;
+ *) qecho="$SHELL `pwd`/$0 --fallback-echo";;
+ esac
+ qecho=`$echo "X$qecho" | $Xsed -e "$sed_quote_subst"`
+ else
+ qecho=`$echo "X$echo" | $Xsed -e "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if our run command is non-null.
+ if test -z "$run"; then
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) output=`$echo $output|${SED} 's,.exe$,,'` ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ outputname=`$echo $outputname|${SED} 's,.exe$,,'` ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ cwrappersource=`$echo ${objdir}/lt-${output}.c`
+ cwrapper=`$echo ${output}.exe`
+ $rm $cwrappersource $cwrapper
+ trap "$rm $cwrappersource $cwrapper; exit 1" 1 2 15
+
+ cat > $cwrappersource <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+
+ Currently, it simply execs the wrapper *script* "/bin/sh $output",
+ but could eventually absorb all of the scripts functionality and
+ exec $objdir/$outputname directly.
+*/
+EOF
+ cat >> $cwrappersource<<"EOF"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef DIR_SEPARATOR
+#define DIR_SEPARATOR '/'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+ defined (__OS2__)
+#define HAVE_DOS_BASED_FILE_SYSTEM
+#ifndef DIR_SEPARATOR_2
+#define DIR_SEPARATOR_2 '\\'
+#endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+const char *program_name = NULL;
+
+void * xmalloc (size_t num);
+char * xstrdup (const char *string);
+char * basename (const char *name);
+char * fnqualify(const char *path);
+char * strendzap(char *str, const char *pat);
+void lt_fatal (const char *message, ...);
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int i;
+
+ program_name = (char *) xstrdup ((char *) basename (argv[0]));
+ newargz = XMALLOC(char *, argc+2);
+EOF
+
+ cat >> $cwrappersource <<EOF
+ newargz[0] = "$SHELL";
+EOF
+
+ cat >> $cwrappersource <<"EOF"
+ newargz[1] = fnqualify(argv[0]);
+ /* we know the script has the same name, without the .exe */
+ /* so make sure newargz[1] doesn't end in .exe */
+ strendzap(newargz[1],".exe");
+ for (i = 1; i < argc; i++)
+ newargz[i+1] = xstrdup(argv[i]);
+ newargz[argc+1] = NULL;
+EOF
+
+ cat >> $cwrappersource <<EOF
+ execv("$SHELL",newargz);
+EOF
+
+ cat >> $cwrappersource <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void * p = (void *) malloc (num);
+ if (!p)
+ lt_fatal ("Memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1), string) : NULL
+;
+}
+
+char *
+basename (const char *name)
+{
+ const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha (name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return (char *) base;
+}
+
+char *
+fnqualify(const char *path)
+{
+ size_t size;
+ char *p;
+ char tmp[LT_PATHMAX + 1];
+
+ assert(path != NULL);
+
+ /* Is it qualified already? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (isalpha (path[0]) && path[1] == ':')
+ return xstrdup (path);
+#endif
+ if (IS_DIR_SEPARATOR (path[0]))
+ return xstrdup (path);
+
+ /* prepend the current directory */
+ /* doesn't handle '~' */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal ("getcwd failed");
+ size = strlen(tmp) + 1 + strlen(path) + 1; /* +2 for '/' and '\0' */
+ p = XMALLOC(char, size);
+ sprintf(p, "%s%c%s", tmp, DIR_SEPARATOR, path);
+ return p;
+}
+
+char *
+strendzap(char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert(str != NULL);
+ assert(pat != NULL);
+
+ len = strlen(str);
+ patlen = strlen(pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (strcmp(str, pat) == 0)
+ *str = '\0';
+ }
+ return str;
+}
+
+static void
+lt_error_core (int exit_status, const char * mode,
+ const char * message, va_list ap)
+{
+ fprintf (stderr, "%s: %s: ", program_name, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, "FATAL", message, ap);
+ va_end (ap);
+}
+EOF
+ # we should really use a build-platform specific compiler
+ # here, but OTOH, the wrappers (shell script and this C one)
+ # are only useful if you want to execute the "real" binary.
+ # Since the "real" binary is built for $host, then this
+ # wrapper might as well be built for $host, too.
+ $run $LTCC -s -o $cwrapper $cwrappersource
+ ;;
+ esac
+ $rm $output
+ trap "$rm $output; exit 1" 1 2 15
+
+ $echo > $output "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='${SED} -e 1s/^X//'
+sed_quote_subst='$sed_quote_subst'
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+if test \"\${CDPATH+set}\" = set; then CDPATH=:; export CDPATH; fi
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variable:
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$echo are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ echo=\"$qecho\"
+ file=\"\$0\"
+ # Make sure echo works.
+ if test \"X\$1\" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+ elif test \"X\`(\$echo '\t') 2>/dev/null\`\" = 'X\t'; then
+ # Yippee, \$echo works!
+ :
+ else
+ # Restart under the correct shell, and then maybe \$echo will work.
+ exec $SHELL \"\$0\" --no-reexec \${1+\"\$@\"}
+ fi
+ fi\
+"
+ $echo >> $output "\
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | ${SED} -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$echo \"X\$file\" | \$Xsed -e 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$echo \"X\$file\" | \$Xsed -e 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | ${SED} -n 's/.*-> //p'\`
+ done
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ $echo >> $output "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" || \\
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $mkdir \"\$progdir\"
+ else
+ $rm \"\$progdir/\$file\"
+ fi"
+
+ $echo >> $output "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ $echo \"\$relink_command_output\" >&2
+ $rm \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $rm \"\$progdir/\$program\";
+ $mv \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $rm \"\$progdir/\$file\"
+ fi"
+ else
+ $echo >> $output "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $echo >> $output "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $echo >> $output "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$echo \"X\$$shlibpath_var\" | \$Xsed -e 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ # fixup the dll searchpath if we need to.
+ if test -n "$dllsearchpath"; then
+ $echo >> $output "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ $echo >> $output "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2*)
+ $echo >> $output "\
+ exec \$progdir\\\\\$program \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $echo >> $output "\
+ exec \$progdir/\$program \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $echo >> $output "\
+ \$echo \"\$0: cannot exec \$program \${1+\"\$@\"}\"
+ exit 1
+ fi
+ else
+ # The program doesn't exist.
+ \$echo \"\$0: error: \$progdir/\$program does not exist\" 1>&2
+ \$echo \"This script is just a wrapper for \$program.\" 1>&2
+ $echo \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+ chmod +x $output
+ fi
+ exit 0
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$old_deplibs $non_pic_objects"
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ $show "${rm}r $gentop"
+ $run ${rm}r "$gentop"
+ $show "$mkdir $gentop"
+ $run $mkdir "$gentop"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$gentop"; then
+ exit $status
+ fi
+ generated="$generated $gentop"
+
+ # Add in members from convenience archives.
+ for xlib in $addlibs; do
+ # Extract the objects.
+ case $xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) xabs="$xlib" ;;
+ *) xabs=`pwd`"/$xlib" ;;
+ esac
+ xlib=`$echo "X$xlib" | $Xsed -e 's%^.*/%%'`
+ xdir="$gentop/$xlib"
+
+ $show "${rm}r $xdir"
+ $run ${rm}r "$xdir"
+ $show "$mkdir $xdir"
+ $run $mkdir "$xdir"
+ status=$?
+ if test "$status" -ne 0 && test ! -d "$xdir"; then
+ exit $status
+ fi
+ # We will extract separately just the conflicting names and we will no
+ # longer touch any unique names. It is faster to leave these extract
+ # automatically by $AR in one run.
+ $show "(cd $xdir && $AR x $xabs)"
+ $run eval "(cd \$xdir && $AR x \$xabs)" || exit $?
+ if ($AR t "$xabs" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; renaming object files" 1>&2
+ $echo "$modename: warning: to ensure that they will not overwrite" 1>&2
+ $AR t "$xabs" | sort | uniq -cd | while read -r count name
+ do
+ i=1
+ while test "$i" -le "$count"
+ do
+ # Put our $i before any first dot (extension)
+ # Never overwrite any file
+ name_to="$name"
+ while test "X$name_to" = "X$name" || test -f "$xdir/$name_to"
+ do
+ name_to=`$echo "X$name_to" | $Xsed -e "s/\([^.]*\)/\1-$i/"`
+ done
+ $show "(cd $xdir && $AR xN $i $xabs '$name' && $mv '$name' '$name_to')"
+ $run eval "(cd \$xdir && $AR xN $i \$xabs '$name' && $mv '$name' '$name_to')" || exit $?
+ i=`expr $i + 1`
+ done
+ done
+ fi
+
+ oldobjs="$oldobjs "`find $xdir -name \*.${objext} -print -o -name \*.lo -print | $NL2SP`
+ done
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ eval cmds=\"$old_archive_from_new_cmds\"
+ else
+ eval cmds=\"$old_archive_cmds\"
+
+ if len=`expr "X$cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # the command line is too long to link in one step, link in parts
+ $echo "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ # GNU ar 2.10+ was changed to match POSIX; thus no paths are
+ # encoded into archives. This makes 'ar r' malfunction in
+ # this piecewise linking case whenever conflicting object
+ # names appear in distinct ar calls; check, warn and compensate.
+ if (for obj in $save_oldobjs
+ do
+ $echo "X$obj" | $Xsed -e 's%^.*/%%'
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ $echo "$modename: warning: object name conflicts; overriding AR_FLAGS to 'cq'" 1>&2
+ $echo "$modename: warning: to ensure that POSIX-compatible ar will work" 1>&2
+ AR_FLAGS=cq
+ fi
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ for obj in $save_oldobjs
+ do
+ oldobjs="$objlist $obj"
+ objlist="$objlist $obj"
+ eval test_cmds=\"$old_archive_cmds\"
+ if len=`expr "X$test_cmds" : ".*"` &&
+ test "$len" -le "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj" ; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ objlist=
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test "X$oldobjs" = "X" ; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~$old_archive_cmds\"
+ fi
+ fi
+ fi
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$generated"; then
+ $show "${rm}r$generated"
+ $run ${rm}r$generated
+ fi
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ $show "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ var_value=`$echo "X$var_value" | $Xsed -e "$sed_quote_subst"`
+ relink_command="$var=\"$var_value\"; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL $0 --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$echo "X$relink_command" | $Xsed -e "$sed_quote_subst"`
+
+ # Only create the output if not a dry run.
+ if test -z "$run"; then
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ name=`$echo "X$deplib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$deplib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ newdependency_libs="$newdependency_libs $libdir/$name"
+ ;;
+ *) newdependency_libs="$newdependency_libs $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+ for lib in $dlfiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ newdlfiles="$newdlfiles $libdir/$name"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ name=`$echo "X$lib" | $Xsed -e 's%^.*/%%'`
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ if test -z "$libdir"; then
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ exit 1
+ fi
+ newdlprefiles="$newdlprefiles $libdir/$name"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $rm $output
+ # place dlname in correct position for cygwin
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll) tdlname=../bin/$dlname ;;
+ esac
+ $echo > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM - GNU $PACKAGE $VERSION$TIMESTAMP
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test "$need_relink" = yes; then
+ $echo >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ fi
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ $show "(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)"
+ $run eval '(cd $output_objdir && $rm $outputname && $LN_S ../$outputname $outputname)' || exit $?
+ ;;
+ esac
+ exit 0
+ ;;
+
+ # libtool install mode
+ install)
+ modename="$modename: install"
+
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ $echo "X$nonopt" | $Xsed | grep shtool > /dev/null; then
+ # Aesthetically quote it.
+ arg=`$echo "X$nonopt" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$arg "
+ arg="$1"
+ shift
+ else
+ install_prog=
+ arg="$nonopt"
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog$arg"
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ for arg
+ do
+ if test -n "$dest"; then
+ files="$files $dest"
+ dest="$arg"
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f) prev="-f" ;;
+ -g) prev="-g" ;;
+ -m) prev="-m" ;;
+ -o) prev="-o" ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*) ;;
+
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ prev=
+ else
+ dest="$arg"
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ arg=`$echo "X$arg" | $Xsed -e "$sed_quote_subst"`
+ case $arg in
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*)
+ arg="\"$arg\""
+ ;;
+ esac
+ install_prog="$install_prog $arg"
+ done
+
+ if test -z "$install_prog"; then
+ $echo "$modename: you must specify an install program" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ if test -n "$prev"; then
+ $echo "$modename: the \`$prev' option requires an argument" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ $echo "$modename: no file or destination specified" 1>&2
+ else
+ $echo "$modename: you must specify a destination" 1>&2
+ fi
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Strip any trailing slash from the destination.
+ dest=`$echo "X$dest" | $Xsed -e 's%/$%%'`
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ destdir=`$echo "X$dest" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$destdir" = "X$dest" && destdir=.
+ destname=`$echo "X$dest" | $Xsed -e 's%^.*/%%'`
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files
+ if test "$#" -gt 2; then
+ $echo "$modename: \`$dest' is not a directory" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ $echo "$modename: \`$destdir' must be an absolute directory name" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ staticlibs="$staticlibs $file"
+ ;;
+
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$file' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ library_names=
+ old_library=
+ relink_command=
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) current_libdirs="$current_libdirs $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) future_libdirs="$future_libdirs $libdir" ;;
+ esac
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`/
+ test "X$dir" = "X$file/" && dir=
+ dir="$dir$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$echo "$destdir" | $SED "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ if test "$inst_prefix_dir" = "$destdir"; then
+ $echo "$modename: error: cannot install \`$file' to a directory not ending in $libdir" 1>&2
+ exit 1
+ fi
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$echo "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ $echo "$modename: warning: relinking \`$file'" 1>&2
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ exit 1
+ fi
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names
+ if test -n "$2"; then
+ realname="$2"
+ shift
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ $show "$install_prog $dir/$srcname $destdir/$realname"
+ $run eval "$install_prog $dir/$srcname $destdir/$realname" || exit $?
+ if test -n "$stripme" && test -n "$striplib"; then
+ $show "$striplib $destdir/$realname"
+ $run eval "$striplib $destdir/$realname" || exit $?
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ for linkname
+ do
+ if test "$linkname" != "$realname"; then
+ $show "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ $run eval "(cd $destdir && $rm $linkname && $LN_S $realname $linkname)"
+ fi
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ eval cmds=\"$postinstall_cmds\"
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ fi
+
+ # Install the pseudo-library for information purposes.
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ instname="$dir/$name"i
+ $show "$install_prog $instname $destdir/$name"
+ $run eval "$install_prog $instname $destdir/$name" || exit $?
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ staticdest=`$echo "X$destfile" | $Xsed -e "$lo2o"`
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ $echo "$modename: cannot copy a libtool object to \`$destfile'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ if test -n "$destfile"; then
+ $show "$install_prog $file $destfile"
+ $run eval "$install_prog $file $destfile" || exit $?
+ fi
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ staticobj=`$echo "X$file" | $Xsed -e "$lo2o"`
+
+ $show "$install_prog $staticobj $staticdest"
+ $run eval "$install_prog \$staticobj \$staticdest" || exit $?
+ fi
+ exit 0
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ destfile=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ destfile="$destdir/$destfile"
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=""
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ file=`$echo $file|${SED} 's,.exe$,,'`
+ stripped_ext=".exe"
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin*|*mingw*)
+ wrapper=`$echo $file | ${SED} -e 's,.exe$,,'`
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if (${SED} -e '4q' $wrapper | grep "^# Generated by .*$PACKAGE")>/dev/null 2>&1; then
+ notinst_deplibs=
+ relink_command=
+
+ # To insure that "foo" is sourced, and not "foo.exe",
+ # finese the cygwin/MSYS system by explicitly sourcing "foo."
+ # which disallows the automatic-append-.exe behavior.
+ case $build in
+ *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
+ *) wrapperdot=${wrapper} ;;
+ esac
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . ${wrapperdot} ;;
+ *) . ./${wrapperdot} ;;
+ esac
+
+ # Check the variables that should have been set.
+ if test -z "$notinst_deplibs"; then
+ $echo "$modename: invalid libtool wrapper script \`$wrapper'" 1>&2
+ exit 1
+ fi
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ # If there is no directory component, then add one.
+ case $lib in
+ */* | *\\*) . $lib ;;
+ *) . ./$lib ;;
+ esac
+ fi
+ libfile="$libdir/"`$echo "X$lib" | $Xsed -e 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ $echo "$modename: warning: \`$lib' has not been installed in \`$libdir'" 1>&2
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ # To insure that "foo" is sourced, and not "foo.exe",
+ # finese the cygwin/MSYS system by explicitly sourcing "foo."
+ # which disallows the automatic-append-.exe behavior.
+ case $build in
+ *cygwin* | *mingw*) wrapperdot=${wrapper}. ;;
+ *) wrapperdot=${wrapper} ;;
+ esac
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . ${wrapperdot} ;;
+ *) . ./${wrapperdot} ;;
+ esac
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ if test "$finalize" = yes && test -z "$run"; then
+ tmpdir="/tmp"
+ test -n "$TMPDIR" && tmpdir="$TMPDIR"
+ tmpdir_mktemp=`mktemp -d $tmpdir/libtool-XXXXXX 2> /dev/null`
+ if test "$?" = 0 ; then
+ tmpdir="$tmpdir_mktemp"
+ unset tmpdir_mktemp
+ else
+ tmpdir="$tmpdir/libtool-$$"
+ fi
+ if $mkdir -p "$tmpdir" && chmod 700 "$tmpdir"; then :
+ else
+ $echo "$modename: error: cannot create temporary directory \`$tmpdir'" 1>&2
+ continue
+ fi
+ file=`$echo "X$file$stripped_ext" | $Xsed -e 's%^.*/%%'`
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$echo "X$relink_command" | $Xsed -e 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $show "$relink_command"
+ if $run eval "$relink_command"; then :
+ else
+ $echo "$modename: error: relink \`$file' with the above command before installing it" 1>&2
+ ${rm}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ $echo "$modename: warning: cannot relink \`$file'" 1>&2
+ fi
+ else
+ # Install the binary that we compiled earlier.
+ file=`$echo "X$file$stripped_ext" | $Xsed -e "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyways
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ destfile=`$echo $destfile | ${SED} -e 's,.exe$,,'`
+ ;;
+ esac
+ ;;
+ esac
+ $show "$install_prog$stripme $file $destfile"
+ $run eval "$install_prog\$stripme \$file \$destfile" || exit $?
+ test -n "$outputname" && ${rm}r "$tmpdir"
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+
+ $show "$install_prog $file $oldlib"
+ $run eval "$install_prog \$file \$oldlib" || exit $?
+
+ if test -n "$stripme" && test -n "$striplib"; then
+ $show "$old_striplib $oldlib"
+ $run eval "$old_striplib $oldlib" || exit $?
+ fi
+
+ # Do each command in the postinstall commands.
+ eval cmds=\"$old_postinstall_cmds\"
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || exit $?
+ done
+ IFS="$save_ifs"
+ done
+
+ if test -n "$future_libdirs"; then
+ $echo "$modename: warning: remember to run \`$progname --finish$future_libdirs'" 1>&2
+ fi
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ test -n "$run" && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $0 --finish$current_libdirs'
+ else
+ exit 0
+ fi
+ ;;
+
+ # libtool finish mode
+ finish)
+ modename="$modename: finish"
+ libdirs="$nonopt"
+ admincmds=
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for dir
+ do
+ libdirs="$libdirs $dir"
+ done
+
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ eval cmds=\"$finish_cmds\"
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd" || admincmds="$admincmds
+ $cmd"
+ done
+ IFS="$save_ifs"
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $run eval "$cmds" || admincmds="$admincmds
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ test "$show" = : && exit 0
+
+ $echo "----------------------------------------------------------------------"
+ $echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $echo " $libdir"
+ done
+ $echo
+ $echo "If you ever happen to want to link against installed libraries"
+ $echo "in a given directory, LIBDIR, you must either use libtool, and"
+ $echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ $echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ $echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ $echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ $echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ $echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $echo " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $echo " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ $echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ $echo
+ $echo "See any operating system documentation about shared libraries for"
+ $echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ $echo "----------------------------------------------------------------------"
+ exit 0
+ ;;
+
+ # libtool execute mode
+ execute)
+ modename="$modename: execute"
+
+ # The first argument is the command name.
+ cmd="$nonopt"
+ if test -z "$cmd"; then
+ $echo "$modename: you must specify a COMMAND" 1>&2
+ $echo "$help"
+ exit 1
+ fi
+
+ # Handle -dlopen flags immediately.
+ for file in $execute_dlfiles; do
+ if test ! -f "$file"; then
+ $echo "$modename: \`$file' is not a file" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ dir=
+ case $file in
+ *.la)
+ # Check to see that this really is a libtool archive.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then :
+ else
+ $echo "$modename: \`$lib' is not a valid libtool archive" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && $echo "$modename: warning: \`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+
+ if test -f "$dir/$objdir/$dlname"; then
+ dir="$dir/$objdir"
+ else
+ $echo "$modename: cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" 1>&2
+ exit 1
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "X$dir" = "X$file" && dir=.
+ ;;
+
+ *)
+ $echo "$modename: warning \`-dlopen' is ignored for non-libtool libraries and objects" 1>&2
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -*) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ # If there is no directory component, then add one.
+ case $file in
+ */* | *\\*) . $file ;;
+ *) . ./$file ;;
+ esac
+
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ file=`$echo "X$file" | $Xsed -e "$sed_quote_subst"`
+ args="$args \"$file\""
+ done
+
+ if test -z "$run"; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ if test "${save_LC_ALL+set}" = set; then
+ LC_ALL="$save_LC_ALL"; export LC_ALL
+ fi
+ if test "${save_LANG+set}" = set; then
+ LANG="$save_LANG"; export LANG
+ fi
+
+ # Now prepare to actually exec the command.
+ exec_cmd="\$cmd$args"
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$echo \"\$shlibpath_var=\$$shlibpath_var\""
+ $echo "export $shlibpath_var"
+ fi
+ $echo "$cmd$args"
+ exit 0
+ fi
+ ;;
+
+ # libtool clean and uninstall mode
+ clean | uninstall)
+ modename="$modename: $mode"
+ rm="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) rm="$rm $arg"; rmforce=yes ;;
+ -*) rm="$rm $arg" ;;
+ *) files="$files $arg" ;;
+ esac
+ done
+
+ if test -z "$rm"; then
+ $echo "$modename: you must specify an RM program" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ fi
+
+ rmdirs=
+
+ origobjdir="$objdir"
+ for file in $files; do
+ dir=`$echo "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ if test "X$dir" = "X$file"; then
+ dir=.
+ objdir="$origobjdir"
+ else
+ objdir="$dir/$origobjdir"
+ fi
+ name=`$echo "X$file" | $Xsed -e 's%^.*/%%'`
+ test "$mode" = uninstall && objdir="$dir"
+
+ # Remember objdir for removal later, being careful to avoid duplicates
+ if test "$mode" = clean; then
+ case " $rmdirs " in
+ *" $objdir "*) ;;
+ *) rmdirs="$rmdirs $objdir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if (test -L "$file") >/dev/null 2>&1 \
+ || (test -h "$file") >/dev/null 2>&1 \
+ || test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ . $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ rmfiles="$rmfiles $objdir/$n"
+ done
+ test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library"
+ test "$mode" = clean && rmfiles="$rmfiles $objdir/$name $objdir/${name}i"
+
+ if test "$mode" = uninstall; then
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ eval cmds=\"$postuninstall_cmds\"
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test "$?" -ne 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ eval cmds=\"$old_postuninstall_cmds\"
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ $show "$cmd"
+ $run eval "$cmd"
+ if test "$?" -ne 0 && test "$rmforce" != yes; then
+ exit_status=1
+ fi
+ done
+ IFS="$save_ifs"
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if (${SED} -e '2q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+
+ # Read the .lo file
+ . $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" \
+ && test "$pic_object" != none; then
+ rmfiles="$rmfiles $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" \
+ && test "$non_pic_object" != none; then
+ rmfiles="$rmfiles $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test "$mode" = clean ; then
+ noexename=$name
+ case $file in
+ *.exe)
+ file=`$echo $file|${SED} 's,.exe$,,'`
+ noexename=`$echo $name|${SED} 's,.exe$,,'`
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ rmfiles="$rmfiles $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if (${SED} -e '4q' $file | grep "^# Generated by .*$PACKAGE") >/dev/null 2>&1; then
+ relink_command=
+ . $dir/$noexename
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ rmfiles="$rmfiles $objdir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name" ; then
+ rmfiles="$rmfiles $objdir/lt-${noexename}.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ $show "$rm $rmfiles"
+ $run $rm $rmfiles || exit_status=1
+ done
+ objdir="$origobjdir"
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ $show "rmdir $dir"
+ $run rmdir $dir >/dev/null 2>&1
+ fi
+ done
+
+ exit $exit_status
+ ;;
+
+ "")
+ $echo "$modename: you must specify a MODE" 1>&2
+ $echo "$generic_help" 1>&2
+ exit 1
+ ;;
+ esac
+
+ if test -z "$exec_cmd"; then
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$generic_help" 1>&2
+ exit 1
+ fi
+fi # test -z "$show_help"
+
+if test -n "$exec_cmd"; then
+ eval exec $exec_cmd
+ exit 1
+fi
+
+# We need to display help for each of the modes.
+case $mode in
+"") $echo \
+"Usage: $modename [OPTION]... [MODE-ARG]...
+
+Provide generalized library-building support services.
+
+ --config show all configuration variables
+ --debug enable verbose shell tracing
+-n, --dry-run display commands without modifying any files
+ --features display basic configuration information and exit
+ --finish same as \`--mode=finish'
+ --help display this help message and exit
+ --mode=MODE use operation mode MODE [default=inferred from MODE-ARGS]
+ --quiet same as \`--silent'
+ --silent don't print informational messages
+ --tag=TAG use configuration variables from tag TAG
+ --version print version information
+
+MODE must be one of the following:
+
+ clean remove files from the build directory
+ compile compile a source file into a libtool object
+ execute automatically set library path, then run a program
+ finish complete the installation of libtool libraries
+ install install libraries or executables
+ link create a library or an executable
+ uninstall remove libraries from an installed directory
+
+MODE-ARGS vary depending on the MODE. Try \`$modename --help --mode=MODE' for
+a more detailed description of MODE.
+
+Report bugs to <bug-libtool@gnu.org>."
+ exit 0
+ ;;
+
+clean)
+ $echo \
+"Usage: $modename [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+compile)
+ $echo \
+"Usage: $modename [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -prefer-pic try to building PIC objects only
+ -prefer-non-pic try to building non-PIC objects only
+ -static always build a \`.o' file suitable for static linking
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+execute)
+ $echo \
+"Usage: $modename [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+finish)
+ $echo \
+"Usage: $modename [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+install)
+ $echo \
+"Usage: $modename [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+link)
+ $echo \
+"Usage: $modename [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -static do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+uninstall)
+ $echo \
+"Usage: $modename [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+*)
+ $echo "$modename: invalid operation mode \`$mode'" 1>&2
+ $echo "$help" 1>&2
+ exit 1
+ ;;
+esac
+
+$echo
+$echo "Try \`$modename --help' for more information about other modes."
+
+exit 0
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) $echo no;; *) $echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# ### BEGIN LIBTOOL TAG CONFIG: CXX
+
+# Libtool was configured on host QWEST-WKCH1I7I3:
+
+# Shell to use when invoking shell scripts.
+SHELL="/bin/sh"
+
+# Whether or not to build shared libraries.
+build_libtool_libs=yes
+
+# Whether or not to build static libraries.
+build_old_libs=no
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=no
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=yes
+
+# Whether or not to optimize for fast installation.
+fast_install=needless
+
+# The host system.
+host_alias=
+host=i686-pc-mingw32
+
+# An echo program that does not interpret backslashes.
+echo="echo"
+
+# The archiver.
+AR="ar"
+AR_FLAGS="cru"
+
+# A C compiler.
+LTCC="gcc"
+
+# A language-specific compiler.
+CC="c++"
+
+# Is the compiler the GNU C compiler?
+with_gcc=yes
+
+# An ERE matcher.
+EGREP="grep -E"
+
+# The linker used to build libraries.
+LD="c:/mnt/opt/mingw/mingw32/bin/ld.exe"
+
+# Whether we need hard or soft links.
+LN_S="ln -s"
+
+# A BSD-compatible nm program.
+NM="/bin/nm -B"
+
+# A symbol stripping program
+STRIP=strip
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=file
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="dlltool"
+
+# Used on cygwin: object dumper.
+OBJDUMP="objdump"
+
+# Used on cygwin: assembler.
+AS="as"
+
+# The name of the directory that contains temporary libtool files.
+objdir=.libs
+
+# How to create reloadable object files.
+reload_flag=" -r"
+reload_cmds="\$LD\$reload_flag -o \$output\$reload_objs"
+
+# How to pass a linker flag through the compiler.
+wl="-Wl,"
+
+# Object file suffix (normally "o").
+objext="o"
+
+# Old archive suffix (normally "a").
+libext="a"
+
+# Shared library suffix (normally ".so").
+shrext='.dll'
+
+# Executable file suffix (normally "").
+exeext=""
+
+# Additional compiler flags for building library objects.
+pic_flag=" -DDLL_EXPORT -DPIC"
+pic_mode=default
+
+# What is the maximum length of a command?
+max_cmd_len=8192
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o="yes"
+
+# Must we lock files when doing compilation ?
+need_locks="no"
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=no
+
+# Do we need a version for libraries?
+need_version=no
+
+# Whether dlopen is supported.
+dlopen_support=unknown
+
+# Whether dlopen of programs is supported.
+dlopen_self=unknown
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=unknown
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag="-static"
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=" -fno-builtin"
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec="\${wl}--export-dynamic"
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=""
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=""
+
+# Library versioning type.
+version_type=windows
+
+# Format of library name prefix.
+libname_spec="lib\$name"
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec="\$libname.dll.a"
+
+# The coded name of the library, if different from the real name.
+soname_spec="\${libname}\`echo \${release} | \$SED -e s/[.]/-/g\`\${versuffix}\${shared_ext}"
+
+# Commands used to build and install an old-style archive.
+RANLIB="ranlib"
+old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs\$old_deplibs~\$RANLIB \$oldlib"
+old_postinstall_cmds="\$RANLIB \$oldlib~chmod 644 \$oldlib"
+old_postuninstall_cmds=""
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=""
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=""
+
+# Commands used to build and install a shared archive.
+archive_cmds="\$CC -shared -nostdlib \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags -o \$output_objdir/\$soname \${wl}--image-base=0x10000000 \${wl}--out-implib,\$lib"
+archive_expsym_cmds="if test \\\"x\\\`\$SED 1q \$export_symbols\\\`\\\" = xEXPORTS; then
+ cp \$export_symbols \$output_objdir/\$soname.def;
+ else
+ echo EXPORTS > \$output_objdir/\$soname.def;
+ cat \$export_symbols >> \$output_objdir/\$soname.def;
+ fi~
+ \$CC -shared -nostdlib \$output_objdir/\$soname.def \$predep_objects \$libobjs \$deplibs \$postdep_objects \$compiler_flags -o \$output_objdir/\$soname \${wl}--image-base=0x10000000 \${wl}--out-implib,\$lib"
+postinstall_cmds="base_file=\\\`basename \\\${file}\\\`~
+ dlpath=\\\`\$SHELL 2>&1 -c '. \$dir/'\\\${base_file}'i;echo \\\$dlname'\\\`~
+ dldir=\$destdir/\\\`dirname \\\$dlpath\\\`~
+ test -d \\\$dldir || mkdir -p \\\$dldir~
+ \$install_prog \$dir/\$dlname \\\$dldir/\$dlname"
+postuninstall_cmds="dldll=\\\`\$SHELL 2>&1 -c '. \$file; echo \\\$dlname'\\\`~
+ dlpath=\$dir/\\\$dldll~
+ \$rm \\\$dlpath"
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=""
+module_expsym_cmds=""
+
+# Commands to strip libraries.
+old_striplib="strip --strip-debug"
+striplib="strip --strip-unneeded"
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects="c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../dllcrt2.o c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/crtbegin.o"
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects="c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/crtend.o"
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=""
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps="-lstdc++ -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt -luser32 -lkernel32 -ladvapi32 -lshell32 -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt"
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path="-Lc:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3 -Lc:/mnt/opt/mingw/bin/../lib/gcc-lib -Lc:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib -Lc:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../.."
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method="file_magic ^x86 archive import|^x86 DLL"
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd="win32_libid"
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag="supported"
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=""
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=""
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=""
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe="sed -n -e 's/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\(_\\)\\([_A-Za-z][_A-Za-z0-9]*\\) \\{0,1\\}\$/\\1 \\2\\3 \\3/p'"
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl="sed -n -e 's/^. .* \\(.*\\)\$/extern int \\1;/p'"
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address="sed -n -e 's/^: \\([^ ]*\\) \$/ {\\\"\\1\\\", (lt_ptr) 0},/p' -e 's/^[BCDEGRST] \\([^ ]*\\) \\([^ ]*\\)\$/ {\"\\2\", (lt_ptr) \\&\\2},/p'"
+
+# This is the shared library runtime path variable.
+runpath_var=LD_RUN_PATH
+
+# This is the shared library path variable.
+shlibpath_var=PATH
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=yes
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=immediate
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=no
+
+# Flag to hardcode $libdir into a binary during linking.
+# This must work even if $libdir does not exist.
+hardcode_libdir_flag_spec="-L\$libdir"
+
+# If ld is used when linking, flag to hardcode $libdir into
+# a binary during linking. This must work even if $libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=""
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=""
+
+# Set to yes if using DIR/libNAME during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=no
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=no
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=no
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="PATH PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=unknown
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=" =c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/ /mingw/lib/gcc-lib/mingw32/3.2.3/ /usr/lib/gcc/mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/mingw32/3.2.3/ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../mingw32/3.2.3/ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../ /lib/mingw32/3.2.3/ /lib/ /usr/lib/mingw32/3.2.3/ /usr/lib/"
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+
+# Fix the shell variable $srcfile for the compiler.
+fix_srcfile_path=""
+
+# Set to yes if exported symbols are required.
+always_export_symbols=no
+
+# The commands to list exported symbols.
+export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED -e '/^[BCDGS] /s/.* \\\\([^ ]*\\\\)/\\\\1 DATA/' | \$SED -e '/^[AITW] /s/.* //' | sort | uniq > \$export_symbols"
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=""
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=""
+
+# Symbols that must always be exported.
+include_expsyms=""
+
+# ### END LIBTOOL TAG CONFIG: CXX
+
+# ### BEGIN LIBTOOL TAG CONFIG: F77
+
+# Libtool was configured on host QWEST-WKCH1I7I3:
+
+# Shell to use when invoking shell scripts.
+SHELL="/bin/sh"
+
+# Whether or not to build shared libraries.
+build_libtool_libs=yes
+
+# Whether or not to build static libraries.
+build_old_libs=no
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=no
+
+# Whether or not to disallow shared libs when runtime libs are static
+allow_libtool_libs_with_static_runtimes=yes
+
+# Whether or not to optimize for fast installation.
+fast_install=needless
+
+# The host system.
+host_alias=
+host=i686-pc-mingw32
+
+# An echo program that does not interpret backslashes.
+echo="echo"
+
+# The archiver.
+AR="ar"
+AR_FLAGS="cru"
+
+# A C compiler.
+LTCC="gcc"
+
+# A language-specific compiler.
+CC="g77"
+
+# Is the compiler the GNU C compiler?
+with_gcc=yes
+
+# An ERE matcher.
+EGREP="grep -E"
+
+# The linker used to build libraries.
+LD="c:/mnt/opt/mingw/mingw32/bin/ld.exe"
+
+# Whether we need hard or soft links.
+LN_S="ln -s"
+
+# A BSD-compatible nm program.
+NM="/bin/nm -B"
+
+# A symbol stripping program
+STRIP=strip
+
+# Used to examine libraries when file_magic_cmd begins "file"
+MAGIC_CMD=file
+
+# Used on cygwin: DLL creation program.
+DLLTOOL="dlltool"
+
+# Used on cygwin: object dumper.
+OBJDUMP="objdump"
+
+# Used on cygwin: assembler.
+AS="as"
+
+# The name of the directory that contains temporary libtool files.
+objdir=.libs
+
+# How to create reloadable object files.
+reload_flag=" -r"
+reload_cmds="\$LD\$reload_flag -o \$output\$reload_objs"
+
+# How to pass a linker flag through the compiler.
+wl="-Wl,"
+
+# Object file suffix (normally "o").
+objext="o"
+
+# Old archive suffix (normally "a").
+libext="a"
+
+# Shared library suffix (normally ".so").
+shrext='.dll'
+
+# Executable file suffix (normally "").
+exeext=""
+
+# Additional compiler flags for building library objects.
+pic_flag=" -DDLL_EXPORT"
+pic_mode=default
+
+# What is the maximum length of a command?
+max_cmd_len=8192
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o="yes"
+
+# Must we lock files when doing compilation ?
+need_locks="no"
+
+# Do we need the lib prefix for modules?
+need_lib_prefix=no
+
+# Do we need a version for libraries?
+need_version=no
+
+# Whether dlopen is supported.
+dlopen_support=unknown
+
+# Whether dlopen of programs is supported.
+dlopen_self=unknown
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=unknown
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag="-static"
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=""
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec="\${wl}--export-dynamic"
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec="\${wl}--whole-archive\$convenience \${wl}--no-whole-archive"
+
+# Compiler flag to generate thread-safe objects.
+thread_safe_flag_spec=""
+
+# Library versioning type.
+version_type=windows
+
+# Format of library name prefix.
+libname_spec="lib\$name"
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME.
+library_names_spec="\$libname.dll.a"
+
+# The coded name of the library, if different from the real name.
+soname_spec="\${libname}\`echo \${release} | \$SED -e s/[.]/-/g\`\${versuffix}\${shared_ext}"
+
+# Commands used to build and install an old-style archive.
+RANLIB="ranlib"
+old_archive_cmds="\$AR \$AR_FLAGS \$oldlib\$oldobjs\$old_deplibs~\$RANLIB \$oldlib"
+old_postinstall_cmds="\$RANLIB \$oldlib~chmod 644 \$oldlib"
+old_postuninstall_cmds=""
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=""
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=""
+
+# Commands used to build and install a shared archive.
+archive_cmds="\$CC -shared \$libobjs \$deplibs \$compiler_flags -o \$output_objdir/\$soname \${wl}--image-base=0x10000000 \${wl}--out-implib,\$lib"
+archive_expsym_cmds="if test \\\"x\\\`\$SED 1q \$export_symbols\\\`\\\" = xEXPORTS; then
+ cp \$export_symbols \$output_objdir/\$soname.def;
+ else
+ echo EXPORTS > \$output_objdir/\$soname.def;
+ cat \$export_symbols >> \$output_objdir/\$soname.def;
+ fi~
+ \$CC -shared \$output_objdir/\$soname.def \$libobjs \$deplibs \$compiler_flags -o \$output_objdir/\$soname \${wl}--image-base=0x10000000 \${wl}--out-implib,\$lib"
+postinstall_cmds="base_file=\\\`basename \\\${file}\\\`~
+ dlpath=\\\`\$SHELL 2>&1 -c '. \$dir/'\\\${base_file}'i;echo \\\$dlname'\\\`~
+ dldir=\$destdir/\\\`dirname \\\$dlpath\\\`~
+ test -d \\\$dldir || mkdir -p \\\$dldir~
+ \$install_prog \$dir/\$dlname \\\$dldir/\$dlname"
+postuninstall_cmds="dldll=\\\`\$SHELL 2>&1 -c '. \$file; echo \\\$dlname'\\\`~
+ dlpath=\$dir/\\\$dldll~
+ \$rm \\\$dlpath"
+
+# Commands used to build a loadable module (assumed same as above if empty)
+module_cmds=""
+module_expsym_cmds=""
+
+# Commands to strip libraries.
+old_striplib="strip --strip-debug"
+striplib="strip --strip-unneeded"
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predep_objects=""
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdep_objects=""
+
+# Dependencies to place before the objects being linked to create a
+# shared library.
+predeps=""
+
+# Dependencies to place after the objects being linked to create a
+# shared library.
+postdeps=""
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=""
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method="file_magic ^x86 archive import|^x86 DLL"
+
+# Command to use when deplibs_check_method == file_magic.
+file_magic_cmd="win32_libid"
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag="supported"
+
+# Flag that forces no undefined symbols.
+no_undefined_flag=""
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=""
+
+# Same as above, but a single script fragment to be evaled but not shown.
+finish_eval=""
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe="sed -n -e 's/^.*[ ]\\([ABCDGIRSTW][ABCDGIRSTW]*\\)[ ][ ]*\\(_\\)\\([_A-Za-z][_A-Za-z0-9]*\\) \\{0,1\\}\$/\\1 \\2\\3 \\3/p'"
+
+# Transform the output of nm in a proper C declaration
+global_symbol_to_cdecl="sed -n -e 's/^. .* \\(.*\\)\$/extern int \\1;/p'"
+
+# Transform the output of nm in a C name address pair
+global_symbol_to_c_name_address="sed -n -e 's/^: \\([^ ]*\\) \$/ {\\\"\\1\\\", (lt_ptr) 0},/p' -e 's/^[BCDEGRST] \\([^ ]*\\) \\([^ ]*\\)\$/ {\"\\2\", (lt_ptr) \\&\\2},/p'"
+
+# This is the shared library runtime path variable.
+runpath_var=LD_RUN_PATH
+
+# This is the shared library path variable.
+shlibpath_var=PATH
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=yes
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=immediate
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=no
+
+# Flag to hardcode $libdir into a binary during linking.
+# This must work even if $libdir does not exist.
+hardcode_libdir_flag_spec="\${wl}--rpath \${wl}\$libdir"
+
+# If ld is used when linking, flag to hardcode $libdir into
+# a binary during linking. This must work even if $libdir does
+# not exist.
+hardcode_libdir_flag_spec_ld=""
+
+# Whether we need a single -rpath flag with a separated argument.
+hardcode_libdir_separator=""
+
+# Set to yes if using DIR/libNAME during linking hardcodes DIR into the
+# resulting binary.
+hardcode_direct=no
+
+# Set to yes if using the -LDIR flag during linking hardcodes DIR into the
+# resulting binary.
+hardcode_minus_L=no
+
+# Set to yes if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into
+# the resulting binary.
+hardcode_shlibpath_var=unsupported
+
+# Set to yes if building a shared library automatically hardcodes DIR into the library
+# and all subsequent libraries and executables linked against it.
+hardcode_automatic=no
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at relink time.
+variables_saved_for_relink="PATH PATH LD_RUN_PATH GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=unknown
+
+# Compile-time system search path for libraries
+sys_lib_search_path_spec=" =c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/ /mingw/lib/gcc-lib/mingw32/3.2.3/ /usr/lib/gcc/mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/mingw32/3.2.3/ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../../mingw32/lib/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../mingw32/3.2.3/ c:/mnt/opt/mingw/bin/../lib/gcc-lib/mingw32/3.2.3/../../../ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../mingw32/3.2.3/ /mingw/lib/gcc-lib/mingw32/3.2.3/../../../ /lib/mingw32/3.2.3/ /lib/ /usr/lib/mingw32/3.2.3/ /usr/lib/"
+
+# Run-time system search path for libraries
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+
+# Fix the shell variable $srcfile for the compiler.
+fix_srcfile_path=""
+
+# Set to yes if exported symbols are required.
+always_export_symbols=no
+
+# The commands to list exported symbols.
+export_symbols_cmds="\$NM \$libobjs \$convenience | \$global_symbol_pipe | \$SED -e '/^[BCDGS] /s/.* \\\\([^ ]*\\\\)/\\\\1 DATA/' | \$SED -e '/^[AITW] /s/.* //' | sort | uniq > \$export_symbols"
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=""
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms="_GLOBAL_OFFSET_TABLE_"
+
+# Symbols that must always be exported.
+include_expsyms=""
+
+# ### END LIBTOOL TAG CONFIG: F77
+
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: f284401a-dcf1-41ea-97ea-c51edee14a27
diff --git a/Win32/sndfile.h b/Win32/sndfile.h
new file mode 100644
index 0000000..23d2d12
--- /dev/null
+++ b/Win32/sndfile.h
@@ -0,0 +1,539 @@
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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.
+*/
+
+/*
+** sndfile.h -- system-wide definitions
+**
+** API documentation is in the doc/ directory of the source code tarball
+** and at http://www.mega-nerd.com/libsndfile/api.html.
+*/
+
+#ifndef SNDFILE_H
+#define SNDFILE_H
+
+/* This is the version 1.0.X header file. */
+#define SNDFILE_1
+
+#include <stdio.h>
+
+/* For the Metrowerks CodeWarrior Pro Compiler (mainly MacOS) */
+
+#if (defined (__MWERKS__))
+#include <unix.h>
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* The following file types can be read and written.
+** A file type would consist of a major type (ie SF_FORMAT_WAV) bitwise
+** ORed with a minor type (ie SF_FORMAT_PCM). SF_FORMAT_TYPEMASK and
+** SF_FORMAT_SUBMASK can be used to separate the major and minor file
+** types.
+*/
+
+enum
+{ /* 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 */
+
+ /* 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
+} ;
+
+/*
+** The following are the valid command numbers for the sf_command()
+** interface. The use of these commands is documented in the file
+** command.html in the doc directory of the source code distribution.
+*/
+
+enum
+{ SFC_GET_LIB_VERSION = 0x1000,
+ SFC_GET_LOG_INFO = 0x1001,
+
+ SFC_GET_NORM_DOUBLE = 0x1010,
+ SFC_GET_NORM_FLOAT = 0x1011,
+ SFC_SET_NORM_DOUBLE = 0x1012,
+ SFC_SET_NORM_FLOAT = 0x1013,
+ SFC_SET_SCALE_FLOAT_INT_READ = 0x1014,
+
+ SFC_GET_SIMPLE_FORMAT_COUNT = 0x1020,
+ SFC_GET_SIMPLE_FORMAT = 0x1021,
+
+ SFC_GET_FORMAT_INFO = 0x1028,
+
+ SFC_GET_FORMAT_MAJOR_COUNT = 0x1030,
+ SFC_GET_FORMAT_MAJOR = 0x1031,
+ SFC_GET_FORMAT_SUBTYPE_COUNT = 0x1032,
+ SFC_GET_FORMAT_SUBTYPE = 0x1033,
+
+ SFC_CALC_SIGNAL_MAX = 0x1040,
+ SFC_CALC_NORM_SIGNAL_MAX = 0x1041,
+ SFC_CALC_MAX_ALL_CHANNELS = 0x1042,
+ SFC_CALC_NORM_MAX_ALL_CHANNELS = 0x1043,
+
+ SFC_SET_ADD_PEAK_CHUNK = 0x1050,
+
+ SFC_UPDATE_HEADER_NOW = 0x1060,
+ SFC_SET_UPDATE_HEADER_AUTO = 0x1061,
+
+ SFC_FILE_TRUNCATE = 0x1080,
+
+ SFC_SET_RAW_START_OFFSET = 0x1090,
+
+ SFC_SET_DITHER_ON_WRITE = 0x10A0,
+ SFC_SET_DITHER_ON_READ = 0x10A1,
+
+ SFC_GET_DITHER_INFO_COUNT = 0x10A2,
+ SFC_GET_DITHER_INFO = 0x10A3,
+
+ SFC_GET_EMBED_FILE_INFO = 0x10B0,
+
+ SFC_SET_CLIPPING = 0x10C0,
+ SFC_GET_CLIPPING = 0x10C1,
+
+ SFC_GET_INSTRUMENT = 0x10D0,
+ SFC_SET_INSTRUMENT = 0x10D1,
+
+ SFC_GET_LOOP_INFO = 0x10E0,
+
+ /* Following commands for testing only. */
+ SFC_TEST_IEEE_FLOAT_REPLACE = 0x6001,
+
+ /*
+ ** SFC_SET_ADD_* values are deprecated and will disappear at some
+ ** time in the future. They are guaranteed to be here up to and
+ ** including version 1.0.8 to avoid breakage of existng software.
+ ** They currently do nothing and will continue to do nothing.
+ */
+ SFC_SET_ADD_DITHER_ON_WRITE = 0x1070,
+ SFC_SET_ADD_DITHER_ON_READ = 0x1071
+} ;
+
+
+/*
+** String types that can be set and read from files. Not all file types
+** support this and even the file types which support one, may not support
+** all string types.
+*/
+
+enum
+{ SF_STR_TITLE = 0x01,
+ SF_STR_COPYRIGHT = 0x02,
+ SF_STR_SOFTWARE = 0x03,
+ SF_STR_ARTIST = 0x04,
+ SF_STR_COMMENT = 0x05,
+ SF_STR_DATE = 0x06
+} ;
+
+/*
+** Use the following as the start and end index when doing metadata
+** transcoding.
+*/
+
+#define SF_STR_FIRST SF_STR_TITLE
+#define SF_STR_LAST SF_STR_DATE
+
+enum
+{ /* True and false */
+ SF_FALSE = 0,
+ SF_TRUE = 1,
+
+ /* Modes for opening files. */
+ SFM_READ = 0x10,
+ SFM_WRITE = 0x20,
+ SFM_RDWR = 0x30
+} ;
+
+/* Public error values. These are guaranteed to remain unchanged for the duration
+** of the library major version number.
+** There are also a large number of private error numbers which are internal to
+** the library which can change at any time.
+*/
+
+enum
+{ SF_ERR_NO_ERROR = 0,
+ SF_ERR_UNRECOGNISED_FORMAT = 1,
+ SF_ERR_SYSTEM = 2,
+ SF_ERR_MALFORMED_FILE = 3,
+ SF_ERR_UNSUPPORTED_ENCODING = 4
+} ;
+
+/* A SNDFILE* pointer can be passed around much like stdio.h's FILE* pointer. */
+
+typedef struct SNDFILE_tag SNDFILE ;
+
+/* The following typedef is system specific and is defined when libsndfile is.
+** compiled. sf_count_t can be one of loff_t (Linux), off_t (*BSD),
+** off64_t (Solaris), __int64_t (Win32) etc.
+*/
+
+typedef __int64 sf_count_t ;
+
+#define SF_COUNT_MAX 0x7FFFFFFFFFFFFFFFi64
+
+/* A pointer to a SF_INFO structure is passed to sf_open_read () and filled in.
+** On write, the SF_INFO structure is filled in by the user and passed into
+** sf_open_write ().
+*/
+
+struct SF_INFO
+{ sf_count_t frames ; /* Used to be called samples. Changed to avoid confusion. */
+ int samplerate ;
+ int channels ;
+ int format ;
+ int sections ;
+ int seekable ;
+} ;
+
+typedef struct SF_INFO SF_INFO ;
+
+/* The SF_FORMAT_INFO struct is used to retrieve information about the sound
+** file formats libsndfile supports using the sf_command () interface.
+**
+** Using this interface will allow applications to support new file formats
+** and encoding types when libsndfile is upgraded, without requiring
+** re-compilation of the application.
+**
+** Please consult the libsndfile documentation (particularly the information
+** on the sf_command () interface) for examples of its use.
+*/
+
+typedef struct
+{ int format ;
+ const char *name ;
+ const char *extension ;
+} SF_FORMAT_INFO ;
+
+/*
+** Enums and typedefs for adding dither on read and write.
+** See the html documentation for sf_command(), SFC_SET_DITHER_ON_WRITE
+** and SFC_SET_DITHER_ON_READ.
+*/
+
+enum
+{ SFD_DEFAULT_LEVEL = 0,
+ SFD_CUSTOM_LEVEL = 0x40000000,
+
+ SFD_NO_DITHER = 500,
+ SFD_WHITE = 501,
+ SFD_TRIANGULAR_PDF = 502
+} ;
+
+typedef struct
+{ int type ;
+ double level ;
+ const char *name ;
+} SF_DITHER_INFO ;
+
+/* Struct used to retrieve information about a file embedded within a
+** larger file. See SFC_GET_EMBED_FILE_INFO.
+*/
+
+typedef struct
+{ sf_count_t offset ;
+ sf_count_t length ;
+} SF_EMBED_FILE_INFO ;
+
+/*
+** Structs used to retrieve music sample information from a file.
+*/
+
+enum
+{ /*
+ ** The loop mode field in SF_INSTRUMENT will be one of the following.
+ */
+ SF_LOOP_NONE = 800,
+ SF_LOOP_FORWARD,
+ SF_LOOP_BACKWARD,
+ SF_LOOP_ALTERNATING
+} ;
+
+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 ;
+
+
+
+/* Struct used to retrieve loop information from a file.*/
+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 lenght, 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 ;
+
+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) ;
+
+struct SF_VIRTUAL_IO
+{ sf_vio_get_filelen get_filelen ;
+ sf_vio_seek seek ;
+ sf_vio_read read ;
+ sf_vio_write write ;
+ sf_vio_tell tell ;
+} ;
+
+typedef struct SF_VIRTUAL_IO SF_VIRTUAL_IO ;
+
+/* Open the specified file for read, write or both. On error, this will
+** return a NULL pointer. To find the error number, pass a NULL SNDFILE
+** to sf_perror () or sf_error_str ().
+** All calls to sf_open() should be matched with a call to sf_close().
+*/
+
+SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo) ;
+
+/* Use the existing file descriptor to create a SNDFILE object. If close_desc
+** is TRUE, the file descriptor will be closed when sf_close() is called. If
+** it is FALSE, the descritor will not be closed.
+** When passed a descriptor like this, the library will assume that the start
+** of file header is at the current file offset. This allows sound files within
+** larger container files to be read and/or written.
+** On error, this will return a NULL pointer. To find the error number, pass a
+** NULL SNDFILE to sf_perror () or sf_error_str ().
+** All calls to sf_open_fd() should be matched with a call to sf_close().
+
+*/
+
+SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ;
+
+SNDFILE* sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data) ;
+
+/* sf_error () returns a error number which can be translated to a text
+** string using sf_error_number().
+*/
+
+int sf_error (SNDFILE *sndfile) ;
+
+/* sf_strerror () returns to the caller a pointer to the current error message for
+** the given SNDFILE.
+*/
+
+const char* sf_strerror (SNDFILE *sndfile) ;
+
+/* sf_error_number () allows the retrieval of the error string for each internal
+** error number.
+**
+*/
+
+const char* sf_error_number (int errnum) ;
+
+/* The following three error functions are deprecated but they will remain in the
+** library for the forseeable future. The function sf_strerror() should be used
+** in their place.
+*/
+
+int sf_perror (SNDFILE *sndfile) ;
+int sf_error_str (SNDFILE *sndfile, char* str, size_t len) ;
+
+
+/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */
+
+int sf_command (SNDFILE *sndfile, int command, void *data, int datasize) ;
+
+/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */
+
+int sf_format_check (const SF_INFO *info) ;
+
+/* Seek within the waveform data chunk of the SNDFILE. sf_seek () uses
+** the same values for whence (SEEK_SET, SEEK_CUR and SEEK_END) as
+** stdio.h function fseek ().
+** An offset of zero with whence set to SEEK_SET will position the
+** read / write pointer to the first data sample.
+** On success sf_seek returns the current position in (multi-channel)
+** samples from the start of the file.
+** Please see the libsndfile documentation for moving the read pointer
+** separately from the write pointer on files open in mode SFM_RDWR.
+** On error all of these functions return -1.
+*/
+
+sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence) ;
+
+/* Functions for retrieving and setting string data within sound files.
+** Not all file types support this features; AIFF and WAV do. For both
+** functions, the str_type parameter must be one of the SF_STR_* values
+** defined above.
+** On error, sf_set_string() returns non-zero while sf_get_string()
+** returns NULL.
+*/
+
+int sf_set_string (SNDFILE *sndfile, int str_type, const char* str) ;
+
+const char* sf_get_string (SNDFILE *sndfile, int str_type) ;
+
+/* Functions for reading/writing the waveform data of a sound file.
+*/
+
+sf_count_t sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ;
+sf_count_t sf_write_raw (SNDFILE *sndfile, const void *ptr, sf_count_t bytes) ;
+
+/* Functions for reading and writing the data chunk in terms of frames.
+** The number of items actually read/written = frames * number of channels.
+** sf_xxxx_raw read/writes the raw data bytes from/to the file
+** sf_xxxx_short passes data in the native short format
+** sf_xxxx_int passes data in the native int format
+** sf_xxxx_float passes data in the native float format
+** sf_xxxx_double passes data in the native double format
+** All of these read/write function return number of frames read/written.
+*/
+
+sf_count_t sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) ;
+sf_count_t sf_writef_short (SNDFILE *sndfile, const short *ptr, sf_count_t frames) ;
+
+sf_count_t sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) ;
+sf_count_t sf_writef_int (SNDFILE *sndfile, const int *ptr, sf_count_t frames) ;
+
+sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) ;
+sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames) ;
+
+sf_count_t sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ;
+sf_count_t sf_writef_double (SNDFILE *sndfile, const double *ptr, sf_count_t frames) ;
+
+/* Functions for reading and writing the data chunk in terms of items.
+** Otherwise similar to above.
+** All of these read/write function return number of items read/written.
+*/
+
+sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
+sf_count_t sf_write_short (SNDFILE *sndfile, const short *ptr, sf_count_t items) ;
+
+sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
+sf_count_t sf_write_int (SNDFILE *sndfile, const int *ptr, sf_count_t items) ;
+
+sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
+sf_count_t sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t items) ;
+
+sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
+sf_count_t sf_write_double (SNDFILE *sndfile, const double *ptr, sf_count_t items) ;
+
+/* Close the SNDFILE and clean up all memory allocations associated with this
+** file.
+** Returns 0 on success, or an error number.
+*/
+
+int sf_close (SNDFILE *sndfile) ;
+
+/* If the file is opened SFM_WRITE or SFM_RDWR, call fsync() on the file
+** to force the writing of data to disk. If the file is opened SFM_READ
+** no action is taken.
+*/
+
+void sf_write_sync (SNDFILE *sndfile) ;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* SNDFILE_H */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 906bb197-18f2-4f66-a395-b4722bab5114
+*/
+
diff --git a/Win32/testprog.c b/Win32/testprog.c
new file mode 100644
index 0000000..add3034
--- /dev/null
+++ b/Win32/testprog.c
@@ -0,0 +1,24 @@
+/* Simple test program to make sure that Win32 linking to libsndfile is
+** working.
+*/
+
+#include <stdio.h>
+
+#include "sndfile.h"
+
+int
+main (void)
+{ static char strbuffer [256] ;
+ sf_command (NULL, SFC_GET_LIB_VERSION, strbuffer, sizeof (strbuffer)) ;
+ puts (strbuffer) ;
+ return 0 ;
+}
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The following line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 31165fd8-9d91-4e5d-8b31-8efd42ef7645
+*/
diff --git a/acinclude.m4 b/acinclude.m4
new file mode 100644
index 0000000..33d9129
--- /dev/null
+++ b/acinclude.m4
@@ -0,0 +1,569 @@
+dnl By default, many hosts won't let programs access large files;
+dnl one must use special compiler options to get large-file access to work.
+dnl For more details about this brain damage please see:
+dnl http://www.sas.com/standards/large.file/x_open.20Mar96.html
+
+dnl Written by Paul Eggert <eggert@twinsun.com>.
+
+dnl Internal subroutine of AC_SYS_EXTRA_LARGEFILE.
+dnl AC_SYS_EXTRA_LARGEFILE_FLAGS(FLAGSNAME)
+AC_DEFUN([AC_SYS_EXTRA_LARGEFILE_FLAGS],
+ [AC_CACHE_CHECK([for $1 value to request large file support],
+ ac_cv_sys_largefile_$1,
+ [ac_cv_sys_largefile_$1=`($GETCONF LFS_$1) 2>/dev/null` || {
+ ac_cv_sys_largefile_$1=no
+ ifelse($1, CFLAGS,
+ [case "$host_os" in
+ # IRIX 6.2 and later require cc -n32.
+changequote(, )dnl
+ irix6.[2-9]* | irix6.1[0-9]* | irix[7-9].* | irix[1-9][0-9]*)
+changequote([, ])dnl
+ if test "$GCC" != yes; then
+ ac_cv_sys_largefile_CFLAGS=-n32
+ fi
+ ac_save_CC="$CC"
+ CC="$CC $ac_cv_sys_largefile_CFLAGS"
+ AC_TRY_LINK(, , , ac_cv_sys_largefile_CFLAGS=no)
+ CC="$ac_save_CC"
+ esac])
+ }])])
+
+dnl Internal subroutine of AC_SYS_EXTRA_LARGEFILE.
+dnl AC_SYS_EXTRA_LARGEFILE_SPACE_APPEND(VAR, VAL)
+AC_DEFUN([AC_SYS_EXTRA_LARGEFILE_SPACE_APPEND],
+ [case $2 in
+ no) ;;
+ ?*)
+ case "[$]$1" in
+ '') $1=$2 ;;
+ *) $1=[$]$1' '$2 ;;
+ esac ;;
+ esac])
+
+dnl Internal subroutine of AC_SYS_EXTRA_LARGEFILE.
+dnl AC_SYS_EXTRA_LARGEFILE_MACRO_VALUE(C-MACRO, CACHE-VAR, COMMENT, CODE-TO-SET-DEFAULT)
+AC_DEFUN([AC_SYS_EXTRA_LARGEFILE_MACRO_VALUE],
+ [AC_CACHE_CHECK([for $1], $2,
+ [$2=no
+changequote(, )dnl
+ $4
+ for ac_flag in $ac_cv_sys_largefile_CFLAGS no; do
+ case "$ac_flag" in
+ -D$1)
+ $2=1 ;;
+ -D$1=*)
+ $2=`expr " $ac_flag" : '[^=]*=\(.*\)'` ;;
+ esac
+ done
+changequote([, ])dnl
+ ])
+ if test "[$]$2" != no; then
+ AC_DEFINE_UNQUOTED([$1], [$]$2, [$3])
+ fi])
+
+AC_DEFUN([AC_SYS_EXTRA_LARGEFILE],
+ [AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_ARG_ENABLE(largefile,
+ [ --disable-largefile omit support for large files])
+ if test "$enable_largefile" != no; then
+ AC_CHECK_TOOL(GETCONF, getconf)
+ AC_SYS_EXTRA_LARGEFILE_FLAGS(CFLAGS)
+ AC_SYS_EXTRA_LARGEFILE_FLAGS(LDFLAGS)
+ AC_SYS_EXTRA_LARGEFILE_FLAGS(LIBS)
+
+ for ac_flag in $ac_cv_sys_largefile_CFLAGS no; do
+ case "$ac_flag" in
+ no) ;;
+ -D_FILE_OFFSET_BITS=*) ;;
+ -D_LARGEFILE_SOURCE | -D_LARGEFILE_SOURCE=*) ;;
+ -D_LARGE_FILES | -D_LARGE_FILES=*) ;;
+ -D?* | -I?*)
+ AC_SYS_EXTRA_LARGEFILE_SPACE_APPEND(CPPFLAGS, "$ac_flag") ;;
+ *)
+ AC_SYS_EXTRA_LARGEFILE_SPACE_APPEND(CFLAGS, "$ac_flag") ;;
+ esac
+ done
+ AC_SYS_EXTRA_LARGEFILE_SPACE_APPEND(LDFLAGS, "$ac_cv_sys_largefile_LDFLAGS")
+ AC_SYS_EXTRA_LARGEFILE_SPACE_APPEND(LIBS, "$ac_cv_sys_largefile_LIBS")
+ AC_SYS_EXTRA_LARGEFILE_MACRO_VALUE(_FILE_OFFSET_BITS,
+ ac_cv_sys_file_offset_bits,
+ [Number of bits in a file offset, on hosts where this is settable.])
+ [case "$host_os" in
+ # HP-UX 10.20 and later
+ hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
+ ac_cv_sys_file_offset_bits=64 ;;
+ esac]
+ AC_SYS_EXTRA_LARGEFILE_MACRO_VALUE(_LARGEFILE_SOURCE,
+ ac_cv_sys_largefile_source,
+ [Define to make fseeko etc. visible, on some hosts.],
+ [case "$host_os" in
+ # HP-UX 10.20 and later
+ hpux10.[2-9][0-9]* | hpux1[1-9]* | hpux[2-9][0-9]*)
+ ac_cv_sys_largefile_source=1 ;;
+ esac])
+ AC_SYS_EXTRA_LARGEFILE_MACRO_VALUE(_LARGE_FILES,
+ ac_cv_sys_large_files,
+ [Define for large files, on AIX-style hosts.],
+ [case "$host_os" in
+ # AIX 4.2 and later
+ aix4.[2-9]* | aix4.1[0-9]* | aix[5-9].* | aix[1-9][0-9]*)
+ ac_cv_sys_large_files=1 ;;
+ esac])
+ fi
+ ])
+
+
+
+
+
+
+dnl @synopsis AC_C_FIND_ENDIAN
+dnl
+dnl Determine endian-ness of target processor.
+dnl @version 1.1 Mar 03 2002
+dnl @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+dnl
+dnl Majority written from scratch to replace the standard autoconf macro
+dnl AC_C_BIGENDIAN. Only part remaining from the original it the invocation
+dnl of the AC_TRY_RUN macro.
+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 endian-ness in the following way:
+dnl 1) Look in <endian.h>.
+dnl 2) If 1) fails, look in <sys/types.h> and <sys/param.h>.
+dnl 3) If 1) and 2) fails and not cross compiling run a test program.
+dnl 4) If 1) and 2) fails and cross compiling then guess based on target.
+
+AC_DEFUN([AC_C_FIND_ENDIAN],
+[AC_CACHE_CHECK(processor byte ordering,
+ ac_cv_c_byte_order,
+
+# Initialize to unknown
+ac_cv_c_byte_order=unknown
+
+if test x$ac_cv_header_endian_h = xyes ; then
+
+ # First try <endian.h> which should set BYTE_ORDER.
+
+ [AC_TRY_LINK([
+ #include <endian.h>
+ #if BYTE_ORDER != LITTLE_ENDIAN
+ not big endian
+ #endif
+ ], return 0 ;,
+ ac_cv_c_byte_order=little
+ )]
+
+ [AC_TRY_LINK([
+ #include <endian.h>
+ #if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+ #endif
+ ], return 0 ;,
+ ac_cv_c_byte_order=big
+ )]
+
+ fi
+
+if test $ac_cv_c_byte_order = unknown ; then
+
+ [AC_TRY_LINK([
+ #include <sys/types.h>
+ #include <sys/param.h>
+ #if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+ #endif
+ ], return 0 ;,
+
+ [AC_TRY_LINK([
+ #include <sys/types.h>
+ #include <sys/param.h>
+ #if BYTE_ORDER != LITTLE_ENDIAN
+ not big endian
+ #endif
+ ], return 0 ;,
+ ac_cv_c_byte_order=little
+ )]
+
+ [AC_TRY_LINK([
+ #include <sys/types.h>
+ #include <sys/param.h>
+ #if BYTE_ORDER != LITTLE_ENDIAN
+ not big endian
+ #endif
+ ], return 0 ;,
+ ac_cv_c_byte_order=little
+ )]
+
+ )]
+
+ fi
+
+if test $ac_cv_c_byte_order = unknown ; then
+ if test $cross_compiling = yes ; then
+ # This is the last resort. Try to guess the target processor endian-ness
+ # by looking at the target CPU type.
+ [
+ case "$target_cpu" in
+ alpha* | i?86* | mipsel* | ia64*)
+ ac_cv_c_big_endian=0
+ ac_cv_c_little_endian=1
+ ;;
+
+ m68* | mips* | powerpc* | hppa* | sparc*)
+ ac_cv_c_big_endian=1
+ ac_cv_c_little_endian=0
+ ;;
+
+ esac
+ ]
+ else
+ AC_TRY_RUN(
+ [[
+ int main (void)
+ { /* Are we little or big endian? From Harbison&Steele. */
+ union
+ { long l ;
+ char c [sizeof (long)] ;
+ } u ;
+ u.l = 1 ;
+ return (u.c [sizeof (long) - 1] == 1);
+ }
+ ]], , ac_cv_c_byte_order=big,
+ ac_cv_c_byte_order=unknown
+ )
+
+ AC_TRY_RUN(
+ [[int main (void)
+ { /* Are we little or big endian? From Harbison&Steele. */
+ union
+ { long l ;
+ char c [sizeof (long)] ;
+ } u ;
+ u.l = 1 ;
+ return (u.c [0] == 1);
+ }]], , ac_cv_c_byte_order=little,
+ ac_cv_c_byte_order=unknown
+ )
+ fi
+ fi
+
+)
+]
+
+if test $ac_cv_c_byte_order = big ; then
+ ac_cv_c_big_endian=1
+ ac_cv_c_little_endian=0
+elif test $ac_cv_c_byte_order = little ; then
+ ac_cv_c_big_endian=0
+ ac_cv_c_little_endian=1
+else
+ ac_cv_c_big_endian=0
+ ac_cv_c_little_endian=0
+
+ AC_MSG_WARN([[*****************************************************************]])
+ AC_MSG_WARN([[*** Not able to determine endian-ness of target processor. ]])
+ AC_MSG_WARN([[*** The constants CPU_IS_BIG_ENDIAN and CPU_IS_LITTLE_ENDIAN in ]])
+ AC_MSG_WARN([[*** src/config.h may need to be hand editied. ]])
+ AC_MSG_WARN([[*****************************************************************]])
+ fi
+
+)# AC_C_FIND_ENDIAN
+
+
+
+
+
+dnl @synopsis AC_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 <erikd AT mega-nerd DOT com>
+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_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 <stdlib.h>
+ 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
+ ))]
+) # AC_C99_FLEXIBLE_ARRAY
+
+
+
+
+
+dnl @synopsis AC_C99_FUNC_LRINT
+dnl
+dnl Check whether C99's lrint function is available.
+dnl @version 1.3 Feb 12 2002
+dnl @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+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_C99_FUNC_LRINT],
+[AC_CACHE_CHECK(for lrint,
+ ac_cv_c99_lrint,
+[
+lrint_save_CFLAGS=$CFLAGS
+CFLAGS="-lm"
+AC_TRY_LINK([
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+#define __USE_ISOC99 1
+#define __USE_ISOC9X 1
+
+#include <math.h>
+], if (!lrint(3.14159)) lrint(2.7183);, ac_cv_c99_lrint=yes, ac_cv_c99_lrint=no)
+
+CFLAGS=$lrint_save_CFLAGS
+
+])
+
+if test "$ac_cv_c99_lrint" = yes; then
+ AC_DEFINE(HAVE_LRINT, 1,
+ [Define if you have C99's lrint function.])
+fi
+])# AC_C99_FUNC_LRINT
+dnl @synopsis AC_C99_FUNC_LRINTF
+dnl
+dnl Check whether C99's lrintf function is available.
+dnl @version 1.3 Feb 12 2002
+dnl @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+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_C99_FUNC_LRINTF],
+[AC_CACHE_CHECK(for lrintf,
+ ac_cv_c99_lrintf,
+[
+AC_TRY_LINK([
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+#define __USE_ISOC99 1
+#define __USE_ISOC9X 1
+
+#include <math.h>
+], if (!lrintf(3.14159)) lrintf(2.7183);, ac_cv_c99_lrintf=yes, ac_cv_c99_lrintf=no)
+])
+
+if test "$ac_cv_c99_lrintf" = yes; then
+ AC_DEFINE(HAVE_LRINTF, 1,
+ [Define if you have C99's lrintf function.])
+fi
+])# AC_C99_FUNC_LRINTF
+
+
+
+
+dnl @synopsis AC_C99_FUNC_LLRINT
+dnl
+dnl Check whether C99's llrint function is available.
+dnl @version 1.1 Sep 30 2002
+dnl @author Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+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_C99_FUNC_LLRINT],
+[AC_CACHE_CHECK(for llrint,
+ ac_cv_c99_llrint,
+[
+AC_TRY_LINK([
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+#define __USE_ISOC99 1
+#define __USE_ISOC9X 1
+
+#include <math.h>
+#include <stdint.h>
+], int64_t x ; x = llrint(3.14159) ;, ac_cv_c99_llrint=yes, ac_cv_c99_llrint=no)
+])
+
+if test "$ac_cv_c99_llrint" = yes; then
+ AC_DEFINE(HAVE_LLRINT, 1,
+ [Define if you have C99's llrint function.])
+fi
+])# AC_C99_FUNC_LLRINT
+
+
+
+dnl @synopsis AC_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 <erikd AT mega-nerd DOT com>
+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([AC_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 <math.h>
+ 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 <math.h>
+ 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
+ ]]
+
+)
+]
+
+)# AC_C_CLIP_MODE
+
+
+dnl @synopsis AC_ADD_CFLAGS
+dnl
+dnl Add the given option to CFLAGS, if it doesn't break the compiler
+
+AC_DEFUN([AC_ADD_CFLAGS],
+[AC_MSG_CHECKING([if $CC accepts $1])
+ ac_add_cflags__old_cflags="$CFLAGS"
+ CFLAGS="$CFLAGS $1"
+ AC_TRY_LINK([#include <stdio.h>],
+ [printf("Hello, World!\n"); return 0;],
+ AC_MSG_RESULT([yes]),
+ AC_MSG_RESULT([no])
+ CFLAGS="$ac_add_cflags__old_cflags")
+])
+
+
+
+
+ifelse(dnl
+
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: bc38294d-bb5c-42ad-90b9-779def5eaab7
+
+)dnl
diff --git a/binheader_readf_check.py b/binheader_readf_check.py
new file mode 100644
index 0000000..abbc7cc
--- /dev/null
+++ b/binheader_readf_check.py
@@ -0,0 +1,69 @@
+#!/usr/bin/python
+
+import re, string, sys
+
+def trim_function_and_params (section):
+ k = string.find (section, "(") + 1
+ brackets = 1
+ section_len = len (section)
+ while k < section_len:
+ if section [k] == '(':
+ brackets += 1
+ elif section [k] == ')':
+ brackets -= 1
+ if brackets < 1:
+ return section [:k+1]
+ k += 1
+ print "Whoops!!!!"
+ sys.exit (1)
+
+def get_function_calls (filedata):
+ filedata = string.split (filedata, "psf_binheader_readf")
+ filedata = filedata [1:]
+
+ func_calls = []
+ for section in filedata:
+ section = "psf_binheader_readf" + section
+ func_calls.append (trim_function_and_params (section))
+
+ return func_calls
+
+def search_for_problems (filename):
+ filedata = open (filename, "r").read ()
+
+ if len (filedata) < 1:
+ print "Error : file '%s' contains no data." % filename
+ sys.exit (1)
+
+ count = 0
+
+ calls = get_function_calls (filedata)
+ for call in calls:
+ if string.find (call, "sizeof") > 0:
+ print "Found : ", call
+ count += 1
+
+ if count == 0:
+ print "%-20s : No problems found." % filename
+ else:
+ print "\n%-20s : Found %d errors." % (filename, count)
+ sys.exit (1)
+ return
+
+
+#-------------------------------------------------------------------------------
+
+if len (sys.argv) < 2:
+ print "Usage : %s <file>" % sys.argv [0]
+ sys.exit (1)
+
+for file in sys.argv [1:]:
+ search_for_problems (file)
+
+
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: 64d2d700-a787-4843-a342-2bafd0761645
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..0f640b2
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,673 @@
+# Copyright (C) 1999-2006 Erik de Castro Lopo (erikd AT mega-nerd DOT com).
+
+dnl Require autoconf version
+AC_PREREQ(2.57)
+
+AC_INIT([libsndfile],[1.0.18pre9],[erikd@mega-nerd.com])
+AC_CONFIG_SRCDIR([src/sndfile.c])
+AC_CANONICAL_TARGET([])
+
+AM_INIT_AUTOMAKE($PACKAGE_NAME,$PACKAGE_VERSION)
+AC_CONFIG_HEADERS([src/config.h])
+
+AC_LANG([C])
+
+#------------------------------------------------------------------------------------
+# Rules for library version information:
+#
+# 1. Start with version information of `0:0:0' for each libtool library.
+# 2. Update the version information only immediately before a public release of
+# your software. More frequent updates are unnecessary, and only guarantee
+# that the current interface number gets larger faster.
+# 3. If the library source code has changed at all since the last update, then
+# increment revision (`c:r:a' becomes `c:r+1:a').
+# 4. If any interfaces have been added, removed, or changed since the last update,
+# increment current, and set revision to 0.
+# 5. If any interfaces have been added since the last public release, then increment
+# age.
+# 6. If any interfaces have been removed since the last public release, then set age
+# to 0.
+
+SHARED_VERSION_INFO="1:18:0"
+
+AC_PROG_CC
+AM_PROG_LIBTOOL
+
+AC_CHECK_PROG(autogen, autogen, yes, no)
+
+AC_PROG_INSTALL
+AC_PROG_LN_S
+
+AC_HEADER_STDC
+
+AC_CHECK_HEADERS(endian.h)
+AC_CHECK_HEADERS(byteswap.h)
+AC_CHECK_HEADERS(locale.h)
+AC_CHECK_HEADERS(inttypes.h)
+
+AC_HEADER_SYS_WAIT
+
+AC_CHECK_DECLS(S_IRGRP)
+if test x$ac_cv_have_decl_S_IRGRP = xyes ; then
+ AC_DEFINE_UNQUOTED([HAVE_DECL_S_IRGRP],1,[Set to 1 if S_IRGRP is defined.])
+else
+ AC_DEFINE_UNQUOTED([HAVE_DECL_S_IRGRP],0)
+ fi
+
+#====================================================================================
+# Check for support of the struct hack.
+
+AC_C99_FLEXIBLE_ARRAY
+
+if test x$ac_cv_c99_flexible_array = xyes ; then
+ AC_DEFINE([HAVE_FLEXIBLE_ARRAY],1, [Set to 1 if the compile supports the struct hack.])
+else
+ AC_MSG_WARN([[*** This compiler does not support the 1999 ISO C Standard ***]])
+ AC_MSG_WARN([[*** feature known as the flexible array struct member. ***]])
+ AC_DEFINE([HAVE_FLEXIBLE_ARRAY],0)
+ fi
+
+#====================================================================================
+# Couple of initializations here. Fill in real values later.
+
+SHLIB_VERSION_ARG=""
+
+#====================================================================================
+# Finished checking, handle options.
+
+AC_ARG_ENABLE(experimental,
+ AC_HELP_STRING([--enable-experimental], [enable experimental code]))
+
+EXPERIMENTAL_CODE=0
+if test x$enable_experimental = xyes ; then
+ EXPERIMENTAL_CODE=1
+ fi
+AC_DEFINE_UNQUOTED([ENABLE_EXPERIMENTAL_CODE],${EXPERIMENTAL_CODE}, [Set to 1 to enable experimental code.])
+
+AC_ARG_ENABLE(gcc-werror,
+ AC_HELP_STRING([--enable-gcc-werror], [enable -Werror in all Makefiles]))
+
+AC_ARG_ENABLE(gcc-pipe,
+ AC_HELP_STRING([--disable-gcc-pipe], [disable gcc -pipe option]))
+
+AC_ARG_ENABLE(gcc-opt,
+ AC_HELP_STRING([--disable-gcc-opt], [disable gcc optimisations]))
+
+AC_ARG_ENABLE(cpu-clip,
+ AC_HELP_STRING([--disable-cpu-clip], [disable tricky cpu specific clipper]))
+
+AC_ARG_ENABLE(bow-docs,
+ AC_HELP_STRING([--enable-bow-docs], [enable black-on-white html docs]))
+
+AC_ARG_ENABLE(sqlite,
+ AC_HELP_STRING([--disable-sqlite], [disable use of sqlite]))
+
+AC_ARG_ENABLE(flac,
+ AC_HELP_STRING([--disable-flac], [disable use of FLAC]))
+
+AC_ARG_ENABLE(alsa,
+ AC_HELP_STRING([--disable-alsa], [disable use of ALSA]))
+
+AC_ARG_ENABLE(test-coverage,
+ AC_HELP_STRING([--enable-test-coverage], [enable test coverage]))
+AM_CONDITIONAL([ENABLE_TEST_COVERAGE], [test "$enable_test_coverage" = yes])
+
+#====================================================================================
+# Check types and their sizes.
+
+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)
+
+#====================================================================================
+# Find an appropriate type for sf_count_t.
+# On systems supporting files larger than 2 Gig, sf_count_t must be a 64 bit value.
+# Unfortunately there is more than one way of ensuring this so need to do some
+# pretty rigourous testing here.
+
+unset ac_cv_sizeof_off_t
+
+AC_CHECK_SIZEOF(off_t,1) # Fake default value.
+
+case "$host_os" in
+ mingw*)
+ TYPEOF_SF_COUNT_T="__int64"
+ SF_COUNT_MAX="0x7FFFFFFFFFFFFFFFLL"
+ SIZEOF_SF_COUNT_T=8
+ ;;
+ *)
+ if test "x$ac_cv_sizeof_off_t" = "x8" ; then
+ # If sizeof (off_t) is 8, no further checking is needed.
+ TYPEOF_SF_COUNT_T="off_t"
+ SF_COUNT_MAX="0x7FFFFFFFFFFFFFFFLL"
+ SIZEOF_SF_COUNT_T=8
+ else
+ # Check for common 64 bit file offset types.
+ AC_CHECK_SIZEOF(loff_t,1) # Fake default value.
+ AC_CHECK_SIZEOF(off64_t,1) # Fake default value.
+
+ TYPEOF_SF_COUNT_T="unknown"
+ if test "x$ac_cv_sizeof_loff_t" = "x8" ; then
+ TYPEOF_SF_COUNT_T="loff_t"
+ SIZEOF_SF_COUNT_T=8
+ elif test "x$ac_cv_sizeof_off64_t" = "x8" ; then
+ TYPEOF_SF_COUNT_T="off64_t"
+ SIZEOF_SF_COUNT_T=8
+ fi
+
+ # Save the old sizeof (off_t) value and then unset it to see if it
+ # 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_EXTRA_LARGEFILE
+
+ if test "x$ac_cv_sys_largefile_CFLAGS" = "xno" ; then
+ ac_cv_sys_largefile_CFLAGS=""
+ fi
+ if test "x$ac_cv_sys_largefile_LDFLAGS" = "xno" ; then
+ ac_cv_sys_largefile_LDFLAGS=""
+ fi
+ if test "x$ac_cv_sys_largefile_LIBS" = "xno" ; then
+ ac_cv_sys_largefile_LIBS=""
+ fi
+
+ AC_CHECK_SIZEOF(off_t,1) # Fake default value.
+
+ if test "x$ac_cv_sizeof_off_t" = "x8" ; then
+ SF_COUNT_MAX="0x7FFFFFFFFFFFFFFFLL"
+ elif test "x$ac_cv_sizeof_off_t" = "x$pre_largefile_sizeof_off_t" ; then
+ AC_MSG_WARN([[This machine does not seem to support 64 bit file offsets.]])
+ TYPEOF_SF_COUNT_T="off_t"
+ SIZEOF_SF_COUNT_T=$ac_cv_sizeof_off_t
+ elif test "x$TYPEOF_SF_COUNT_T" = "xunknown" ; then
+ echo
+ echo "*** The configure process has determined that this system is capable"
+ echo "*** of Large File Support but has not been able to find a type which"
+ echo "*** is an unambiguous 64 bit file offset."
+ echo "*** Please contact the author to help resolve this problem."
+ echo
+ AC_MSG_ERROR([[Bad file offset type.]])
+ fi
+ fi
+ ;;
+ esac
+
+if test $SIZEOF_SF_COUNT_T = 4 ; then
+ SF_COUNT_MAX="0x7FFFFFFF"
+ fi
+
+AC_DEFINE_UNQUOTED([TYPEOF_SF_COUNT_T],${TYPEOF_SF_COUNT_T}, [Set to long if unknown.])
+AC_SUBST(TYPEOF_SF_COUNT_T)
+
+AC_DEFINE_UNQUOTED([SIZEOF_SF_COUNT_T],${SIZEOF_SF_COUNT_T}, [Set to sizeof (long) if unknown.])
+AC_SUBST(SIZEOF_SF_COUNT_T)
+
+AC_DEFINE_UNQUOTED([SF_COUNT_MAX],${SF_COUNT_MAX}, [Set to maximum allowed value of sf_count_t type.])
+AC_SUBST(SF_COUNT_MAX)
+
+AC_CHECK_TYPES(ssize_t)
+AC_CHECK_SIZEOF(ssize_t,4)
+
+#====================================================================================
+# Determine endian-ness of target processor.
+
+AC_C_FIND_ENDIAN
+
+AC_DEFINE_UNQUOTED(CPU_IS_BIG_ENDIAN, ${ac_cv_c_big_endian},
+ [Target processor is big endian.])
+AC_DEFINE_UNQUOTED(CPU_IS_LITTLE_ENDIAN, ${ac_cv_c_little_endian},
+ [Target processor is little endian.])
+AC_DEFINE_UNQUOTED(WORDS_BIGENDIAN, ${ac_cv_c_big_endian},
+ [Target processor is big endian.])
+
+#====================================================================================
+# Check for functions.
+
+AC_CHECK_FUNCS(malloc calloc realloc free)
+AC_CHECK_FUNCS(open read write lseek pread pwrite)
+AC_CHECK_FUNCS(fstat ftruncate fsync)
+AC_CHECK_FUNCS(snprintf vsnprintf)
+AC_CHECK_FUNCS(gmtime gmtime_r)
+AC_CHECK_FUNCS(mmap getpagesize)
+AC_CHECK_FUNCS(setlocale)
+
+AC_CHECK_LIB([m],floor)
+AC_CHECK_FUNCS(floor ceil fmod)
+
+case "$host_os" in
+ cygwin*)
+ AC_MSG_WARN([[Not using built-in lrint() and lrintf() because they are broken on Cygwin.]])
+ ;;
+ *)
+ AC_C99_FUNC_LRINT
+ AC_C99_FUNC_LRINTF
+
+ if test "x$ac_cv_c99_lrint" = "xno" ; then
+ if test "x$ac_cv_c99_lrintf" = "xno" ; then
+ AC_MSG_WARN([[*** Missing C99 standard functions lrint() and lrintf().]])
+ AC_MSG_WARN([[*** This may cause benign compiler warnings on some systems (ie Solaris).]])
+ fi
+ fi
+ ;;
+ esac
+
+#====================================================================================
+# Check for libsqlite3 (only used in regtest).
+
+ac_cv_sqlite3=no
+if test x$enable_sqlite != xno ; then
+ PKG_CHECK_MODULES(SQLITE3, sqlite3 >= 3.2, ac_cv_sqlite3=yes, ac_cv_sqlite3=no)
+ fi
+
+if test x$ac_cv_sqlite3 = "xyes" ; then
+ HAVE_SQLITE3=1
+else
+ HAVE_SQLITE3=0
+ fi
+
+AC_DEFINE_UNQUOTED([HAVE_SQLITE3],$HAVE_SQLITE3,[Set to 1 if you have libsqlite3.])
+
+#====================================================================================
+# Determine if the processor can do clipping on float to int conversions.
+
+if test x$enable_cpu_clip != "xno" ; then
+ AC_C_CLIP_MODE
+else
+ echo "checking processor clipping capabilities... disabled"
+ ac_cv_c_clip_positive=0
+ ac_cv_c_clip_negative=0
+ fi
+
+AC_DEFINE_UNQUOTED(CPU_CLIPS_POSITIVE, ${ac_cv_c_clip_positive},
+ [Target processor clips on positive float to int conversion.])
+AC_DEFINE_UNQUOTED(CPU_CLIPS_NEGATIVE, ${ac_cv_c_clip_negative},
+ [Target processor clips on negative float to int conversion.])
+
+
+#====================================================================================
+# FLAC defines.
+
+AC_DEFINE(FLAC__HAS_OGG, 1, [This is always true.])
+
+case "$host_cpu" in
+ i*86)
+ cpu_ia32=true
+ AC_DEFINE(FLAC__CPU_IA32)
+ AH_TEMPLATE(FLAC__CPU_IA32, [define if building for ia32/i386])
+ ;;
+ powerpc)
+ cpu_ppc=true
+ AC_DEFINE(FLAC__CPU_PPC)
+ AH_TEMPLATE(FLAC__CPU_PPC, [define if building for PowerPC])
+ ;;
+ sparc)
+ cpu_sparc=true
+ AC_DEFINE(FLAC__CPU_SPARC)
+ AH_TEMPLATE(FLAC__CPU_SPARC, [define if building for SPARC])
+ ;;
+ esac
+
+AM_CONDITIONAL(FLaC__CPU_IA32, test "x$cpu_ia32" = xtrue)
+AM_CONDITIONAL(FLaC__CPU_PPC, test "x$cpu_ppc" = xtrue)
+AM_CONDITIONAL(FLaC__CPU_SPARC, test "x$cpu_sparc" = xtrue)
+
+case "$host" in
+ *-pc-linux-gnu)
+ sys_linux=true
+ AC_DEFINE(FLAC__SYS_LINUX)
+ AH_TEMPLATE(FLAC__SYS_LINUX, [define if building for Linux])
+ ;;
+ *-*-darwin*)
+ sys_darwin=true
+ AC_DEFINE(FLAC__SYS_DARWIN)
+ AH_TEMPLATE(FLAC__SYS_DARWIN, [define if building for Darwin / MacOS X])
+ ;;
+ esac
+
+AM_CONDITIONAL(FLaC__SYS_DARWIN, test "x$sys_darwin" = xtrue)
+AM_CONDITIONAL(FLaC__SYS_LINUX, test "x$sys_linux" = xtrue)
+
+AC_ARG_ENABLE(asm-optimizations, AC_HELP_STRING([--disable-asm-optimizations], [Don't use any assembly optimization routines]), asm_opt=no, asm_opt=yes)
+AM_CONDITIONAL(FLaC__NO_ASM, test "x$asm_opt" = xno)
+
+if test "x$asm_opt" = xno ; then
+ AC_DEFINE(FLAC__NO_ASM)
+ AH_TEMPLATE(FLAC__NO_ASM, [define to disable use of assembly code])
+ fi
+
+AC_CHECK_PROGS(NASM, nasm)
+AM_CONDITIONAL(FLaC__HAS_NASM, test -n "$NASM")
+
+if test -n "$NASM" ; then
+ AC_DEFINE(FLAC__HAS_NASM)
+ AH_TEMPLATE(FLAC__HAS_NASM, [define if you are compiling for x86 and have the NASM assembler])
+ fi
+
+# Only matters for PowerPC
+AC_CHECK_PROGS(AS, as, as)
+AC_CHECK_PROGS(GAS, gas, gas)
+
+AM_CONDITIONAL(FLaC__HAS_AS, test "$AS" = "as")
+AM_CONDITIONAL(FLaC__HAS_GAS, test "$AS" = "gas")
+
+if test "$AS" = "as" ; then
+ AC_DEFINE(FLAC__HAS_AS)
+ AH_TEMPLATE(FLAC__HAS_AS, [define if you are compiling for PowerPC and have the 'as' assembler])
+ fi
+
+if test "$AS" = "gas" ; then
+ # funniest. macro. ever.
+ AC_DEFINE(FLAC__HAS_GAS)
+ AH_TEMPLATE(FLAC__HAS_GAS, [define if you are compiling for PowerPC and have the 'gas' assembler])
+ fi
+
+case "$host" in
+ i386-*-openbsd3.[[0-3]]) OBJ_FORMAT=aoutb ;;
+ *-*-cygwin|*mingw*) OBJ_FORMAT=win32 ;;
+ *) OBJ_FORMAT=elf ;;
+ esac
+
+AC_SUBST(OBJ_FORMAT)
+
+#====================================================================================
+# Target OS specific stuff.
+
+OS_SPECIFIC_CFLAGS=""
+OS_SPECIFIC_LINKS=""
+os_is_win32=0
+os_is_macosx=0
+use_windows_api=0
+
+case "$host_os" in
+ darwin* | rhapsody*)
+ os_is_macosx=1
+ OS_SPECIFIC_CFLAGS="-fpascal-strings -I/Developer/Headers/FlatCarbon"
+ OS_SPECIFIC_LINKS="-framework CoreAudio"
+ ;;
+ mingw*)
+ os_is_win32=1
+ use_windows_api=1
+ OS_SPECIFIC_LINKS="-lwinmm"
+ ;;
+ cygwin*)
+ os_is_win32=1
+ OS_SPECIFIC_LINKS="-lwinmm"
+ ;;
+ esac
+
+AC_DEFINE_UNQUOTED(OS_IS_WIN32, ${os_is_win32}, [Set to 1 if compiling for Win32])
+AC_DEFINE_UNQUOTED(OS_IS_MACOSX, ${os_is_macosx}, [Set to 1 if compiling for MacOSX])
+AC_DEFINE_UNQUOTED(USE_WINDOWS_API, ${use_windows_api}, [Set to 1 to use the native windows API])
+
+#====================================================================================
+# Check for ALSA.
+
+ALSA_LIBS=""
+
+if test x$enable_alsa != xno ; then
+ AC_CHECK_HEADERS(alsa/asoundlib.h)
+ if test x$ac_cv_header_alsa_asoundlib_h = xyes ; then
+ ALSA_LIBS="-lasound"
+ fi
+ fi
+
+#====================================================================================
+# Test for sanity when cross-compiling.
+
+if test x$cross_compiling = xyes ; then
+ AC_MSG_WARN([[******************************************************************]])
+ AC_MSG_WARN([[*** We are cross-compiling, so have to assume sizeof (short) == 2 ]])
+ AC_MSG_WARN([[*** and sizeof (int) == 4. If this is not the case there is no ]])
+ AC_MSG_WARN([[*** chance of this working. Please contact the mantainer. ]])
+ AC_MSG_WARN([[******************************************************************]])
+ fi
+
+if test $ac_cv_sizeof_short != 2 ; then
+ AC_MSG_WARN([[******************************************************************]])
+ AC_MSG_WARN([[*** sizeof (short) != 2. ]])
+ AC_MSG_WARN([[******************************************************************]])
+ fi
+
+if test $ac_cv_sizeof_int != 4 ; then
+ AC_MSG_WARN([[******************************************************************]])
+ AC_MSG_WARN([[*** sizeof (int) != 4 ]])
+ AC_MSG_WARN([[******************************************************************]])
+ fi
+
+if test $ac_cv_sizeof_float != 4 ; then
+ AC_MSG_WARN([[******************************************************************]])
+ AC_MSG_WARN([[*** sizeof (float) != 4. ]])
+ AC_MSG_WARN([[******************************************************************]])
+ fi
+
+if test $ac_cv_sizeof_double != 8 ; then
+ AC_MSG_WARN([[******************************************************************]])
+ AC_MSG_WARN([[*** sizeof (double) != 8. ]])
+ AC_MSG_WARN([[******************************************************************]])
+ fi
+
+if test x"$ac_cv_prog_autogen" = "xno" ; then
+ AC_MSG_WARN([[Touching files in directory tests/.]])
+ touch tests/*.c tests/*.h
+ fi
+
+#====================================================================================
+# Settings for the HTML documentation.
+
+htmldocdir=$prefix/share/doc/libsndfile1-dev/html
+
+if test $prefix = "NONE" ; then
+ htmldocdir=/usr/local/share/doc/libsndfile1-dev/html
+else
+ htmldocdir=$prefix/share/doc/libsndfile1-dev/html
+ fi
+
+if test x$enable_bow_docs = "xyes" ; then
+ HTML_BGCOLOUR="white"
+ HTML_FGCOLOUR="black"
+else
+ HTML_BGCOLOUR="black"
+ HTML_FGCOLOUR="white"
+ fi
+
+#====================================================================================
+# Now use the information from the checking stage.
+
+win32_target_dll=0
+
+if test x$ac_cv_c_compiler_gnu = xyes ; then
+ AC_ADD_CFLAGS(-std=gnu99)
+
+ CFLAGS="$CFLAGS -W -Wall"
+ CXXFLAGS="$CXXFLAGS -W -Wall"
+
+ AC_ADD_CFLAGS([-Wdeclaration-after-statement])
+ AC_ADD_CFLAGS([-Wpointer-arith])
+
+ if test x$enable_gcc_werror = "xyes" ; then
+ CFLAGS="-Werror $CFLAGS"
+ CXXFLAGS="-Werror $CXXFLAGS"
+ fi
+
+ if test x$enable_test_coverage = "xyes" ; then
+ # AC_ADD_CFLAGS([-ftest-coverage])
+ AC_ADD_CFLAGS([-coverage])
+ fi
+
+ CFLAGS="$CFLAGS -Wstrict-prototypes -Wmissing-prototypes -Waggregate-return -Wcast-align -Wcast-qual -Wnested-externs -Wshadow -Wbad-function-cast -Wwrite-strings "
+ # -Wundef -Wmissing-declarations -Winline -Wconversion"
+ CXXFLAGS="$CXXFLAGS -Wcast-align -Wcast-qual -Wshadow -Wwrite-strings -Wctor-dtor-privacy -Wnon-virtual-dtor -Woverloaded-virtual -Wreorder -Wsign-promo "
+
+ if test "x$enable_gcc_opt" = "xno" ; then
+ temp_CFLAGS=`echo $CFLAGS | sed "s/O2/O0/"`
+ CFLAGS=$temp_CFLAGS
+ AC_MSG_WARN([[*** Compiler optimisations switched off. ***]])
+ fi
+
+ # OS specific tweaks.
+ case "$host_os" in
+ darwin* | rhapsody*)
+ # Disable -Wall, -pedantic and -Wshadow for Apple Darwin/Rhapsody.
+ # 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,\$(srcdir)/Symbols.darwin"
+ ;;
+ linux*)
+ SHLIB_VERSION_ARG="-Wl,--version-script=\$(srcdir)/Symbols.linux"
+ ;;
+ mingw*)
+ SHLIB_VERSION_ARG="-Wl,\$(srcdir)/libsndfile.def"
+ win32_target_dll=1
+ if test x"$enable_shared" = xno ; then
+ win32_target_dll=0
+ fi
+ ;;
+ cygwin*)
+ SHLIB_VERSION_ARG="-Wl,\$(srcdir)/cygsndfile.def"
+ win32_target_dll=1
+ if test x"$enable_shared" = xno ; then
+ win32_target_dll=0
+ fi
+ ;;
+ *)
+ ;;
+ esac
+ if test x$enable_gcc_pipe != "xno" ; then
+ CFLAGS="$CFLAGS -pipe"
+ fi
+
+ AC_DEFINE([COMPILER_IS_GCC],1, [Set to 1 if the compile is GNU GCC.])
+ GCC_MAJOR_VERSION=`$CC -dumpversion | sed "s/\..*//"`
+ AC_DEFINE_UNQUOTED([GCC_MAJOR_VERSION],${GCC_MAJOR_VERSION}, [Major version of GCC or 3 otherwise.])
+ fi
+
+AC_DEFINE_UNQUOTED(WIN32_TARGET_DLL, ${win32_target_dll}, [Set to 1 if windows DLL is being built.])
+
+CFLAGS="$CFLAGS $OS_SPECIFIC_CFLAGS"
+
+if test x"$CFLAGS" = x ; then
+ echo "Error in configure script. CFLAGS has been screwed up."
+ exit
+ fi
+
+#-------------------------------------------------------------------------------
+
+AC_SUBST(htmldocdir)
+AC_SUBST(HTML_BGCOLOUR)
+AC_SUBST(HTML_FGCOLOUR)
+
+AC_SUBST(SHLIB_VERSION_ARG)
+AC_SUBST(SHARED_VERSION_INFO)
+AC_SUBST(OS_SPECIFIC_CFLAGS)
+AC_SUBST(OS_SPECIFIC_LINKS)
+AC_SUBST(ALSA_LIBS)
+AC_SUBST(ENABLE_EXPERIMENTAL_CODE)
+
+AC_SUBST(COMPILER_IS_GCC)
+AC_SUBST(GCC_MAJOR_VERSION)
+
+dnl The following line causes the libtool distributed with the source
+dnl to be replaced if the build system has a more recent version.
+AC_SUBST(LIBTOOL_DEPS)
+
+AC_CONFIG_FILES([ \
+ src/sndfile.h src/Makefile src/GSM610/Makefile src/G72x/Makefile \
+ \
+ src/FLAC/Makefile src/FLAC/include/FLAC/Makefile src/FLAC/include/Makefile \
+ src/FLAC/include/share/grabbag/Makefile src/FLAC/include/share/Makefile \
+ src/FLAC/include/test_libs_common/Makefile src/FLAC/src/Makefile \
+ src/FLAC/src/libFLAC/ia32/Makefile src/FLAC/src/libFLAC/Makefile \
+ src/FLAC/src/libFLAC/include/private/Makefile \
+ src/FLAC/src/libFLAC/include/Makefile \
+ src/FLAC/src/libFLAC/include/protected/Makefile \
+ src/FLAC/src/libFLAC/ppc/as/Makefile src/FLAC/src/libFLAC/ppc/Makefile \
+ src/FLAC/src/libFLAC/ppc/gas/Makefile src/FLAC/src/share/Makefile \
+ src/FLAC/src/share/getopt/Makefile src/FLAC/src/share/grabbag/Makefile \
+ src/FLAC/src/share/replaygain_anal/Makefile \
+ src/FLAC/src/share/replaygain_syn/include/private/Makefile \
+ src/FLAC/src/share/replaygain_syn/include/Makefile \
+ src/FLAC/src/share/replaygain_syn/Makefile \
+ src/FLAC/src/share/utf8/Makefile src/FLAC/src/test_libFLAC/Makefile \
+ src/FLAC/src/test_libs_common/Makefile src/FLAC/src/test_seeking/Makefile \
+ src/FLAC/src/test_streams/Makefile src/FLAC/test/Makefile \
+ src/FLAC/src/monkeys_audio_utilities/Makefile \
+ src/FLAC/src/monkeys_audio_utilities/flac_mac/Makefile \
+ src/FLAC/src/monkeys_audio_utilities/flac_ren/Makefile \
+ src/FLAC/src/test_grabbag/Makefile src/FLAC/src/test_grabbag/cuesheet/Makefile \
+ src/FLAC/src/test_grabbag/picture/Makefile \
+ \
+ src/OGG/include/ogg/Makefile src/OGG/include/Makefile src/OGG/Makefile \
+ man/Makefile examples/Makefile tests/Makefile regtest/Makefile \
+ doc/Makefile doc/libsndfile.css \
+ Win32/Makefile Octave/Makefile \
+ Makefile libsndfile.spec sndfile.pc \
+ ])
+AC_OUTPUT
+
+#====================================================================================
+
+AC_MSG_RESULT([
+-=-=-=-=-=-=-=-=-=-= Configuration Complete =-=-=-=-=-=-=-=-=-=-
+
+ Configuration summary :
+
+ Version : ..................... ${VERSION}
+ Experimental code : ........... ${enable_experimental:-no}
+])
+
+if test x$ac_cv_c_compiler_gnu = xyes ; then
+ echo -e " Tools :\n"
+ echo " Compiler is GCC : ............. ${ac_cv_c_compiler_gnu}"
+ echo " GCC major version : ........... ${GCC_MAJOR_VERSION}"
+ if test $GCC_MAJOR_VERSION -lt 3 ; then
+ echo -e "\n ** This compiler version allows applications to write"
+ echo " ** to static strings within the library."
+ echo " ** Compile with GCC version 3.X to avoid this problem."
+ fi
+ fi
+
+if test $libdir = "\${exec_prefix}/lib" ; then
+ libdir="$prefix/lib"
+ fi
+
+if test $bindir = "\${exec_prefix}/bin" ; then
+ bindir="$prefix/bin"
+ fi
+
+AC_MSG_RESULT([[
+ Installation directories :
+
+ Library directory : ........... $libdir
+ Program directory : ........... $bindir
+ Pkgconfig directory : ......... $libdir/pkgconfig
+ HTML docs directory : ......... $htmldocdir
+]])
+
+if test x$prefix != "x/usr" ; then
+ echo "Compiling some other packages against libsndfile may require"
+ echo -e "the addition of \"$libdir/pkgconfig\" to the"
+ echo -e "PKG_CONFIG_PATH environment variable.\n"
+ fi
+
+#==================================================================================
+# Ugly hack to remove -Werror from some Makefiles.
+
+TMPFILE=/tmp/strchange$$
+
+for f in "src/FLAC/src/libFLAC/Makefile" ; do
+ tmp=`grep -l "\-Werror" "$f"`
+ if test -n "$tmp" ; then
+ if sed -e "s!\-Werror!!g" "$f" > $TMPFILE ; then
+ cp -f $TMPFILE "$f"
+ fi
+ fi
+ done
diff --git a/doc/FAQ.html b/doc/FAQ.html
new file mode 100644
index 0000000..afa25ea
--- /dev/null
+++ b/doc/FAQ.html
@@ -0,0 +1,720 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ libsndfile : Frequently Asked Questions.
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <META NAME="Description" CONTENT="The libsndfile FAQ.">
+ <META NAME="Keywords" CONTENT="WAV AIFF AU libsndfile sound audio dsp Linux">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+
+<H1><B>libsndfile : Frequently Asked Questions.</B></H1>
+<P>
+<A HREF="#Q001">Q1 : Do you plan to support XYZ codec in libsndfile?</A><BR>
+<A HREF="#Q002">Q2 : In version 0 the SF_INFO struct had a pcmbitwidth field
+ but version 1 does not. Why?</A><BR>
+<A HREF="#Q003">Q3 : Compiling is really slow on MacOSX. Why?</A><BR>
+<A HREF="#Q004">Q4 : When trying to compile libsndfile on Solaris I get a "bad
+ substitution" error during linking. What can I do to fix this?</A><BR>
+<A HREF="#Q005">Q5 : Why doesn't libsndfile do interleaving/de-interleaving?</A><BR>
+<A HREF="#Q006">Q6 : What's the best format for storing temporary files?</A><BR>
+<A HREF="#Q007">Q7 : On Linux/Unix/MacOSX, what's the best way of detecting the
+ presence of libsndfile?</A><BR>
+<A HREF="#Q008">Q8 : But I just want a simple Makefile! What do I do?</A><BR>
+<A HREF="#Q009">Q9 : How about adding the ability to write/read sound files to/from
+ memory buffers?</A><BR>
+<A HREF="#Q010">Q10 : Reading a 16 bit PCM file as normalised floats and then
+ writing them back changes some sample values. Why?</A><BR>
+<A HREF="#Q011">Q11 : I'm having problems with u-law encoded WAV files generated by
+ libsndfile in Winamp. Why?</A><BR>
+<A HREF="#Q012">Q12 : I'm looking at sf_read*. What are items? What are frames?</A><BR>
+<A HREF="#Q013">Q13 : Why can't libsndfile open this Sound Designer II (SD2)
+ file?</A><BR>
+<A HREF="#Q014">Q14 : I'd like to statically link libsndfile to my closed source
+ application. Can I buy a license so that this is possible?</A><BR>
+<A HREF="#Q015">Q15 : My program is crashing during a call to a function in libsndfile.
+ Is this a bug in libsndfile?</A><BR>
+<A HREF="#Q016">Q16 : Will you accept a fix for compiling libsndfile with compiler X?
+ </A><BR>
+<A HREF="#Q017">Q17 : Can libsndfile read/write files from/to UNIX pipes?
+ </A><BR>
+<A HREF="#Q018">Q18 : Is it possible to build a Universal Binary on Mac OSX?
+ </A><BR>
+<A HREF="#Q019">Q19 : I have project files for Visual Studio / XCode / Whatever. Why
+ don't you distribute them with libsndfile?
+ </A><BR>
+<A HREF="#Q020">Q20 : Why doesn't libsndfile support MP3? Lots of other Open Source
+ projects support it!
+ </A><BR>
+<HR>
+
+<!-- ========================================================================= -->
+<A NAME="Q001"></A>
+<H2><BR><B>Q1 : Do you plan to support XYZ codec in libsnfile?</B></H2>
+<P>
+If source code for XYZ codec is available under a suitable license (LGPL, BSD,
+MIT etc) then yes, I'd like to add it.
+</P>
+<P>
+If suitable documentation is available on how to decode and enocde the format
+then maybe, depending on how much work is involved.
+</P>
+<P>
+If XYZ is some proprietary codec where no source code or documentation is
+available then no.
+</P>
+<P>
+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.
+</P>
+<!-- ========================================================================= -->
+<A NAME="Q002"></A>
+<H2><BR><B>Q2 : In version 0 the SF_INFO struct had a pcmbitwidth field
+ but version 1 does not. Why?</B></H2>
+<P>
+ This was dropped for a number of reasons:
+</P>
+<UL>
+ <LI> pcmbitwidth makes little sense on compressed or floating point formats
+ <LI> with the new API you really don't need to know it
+</UL>
+<P>
+As documented
+ <A HREF="http://www.mega-nerd.com/libsndfile/api.html#note1">here</A>
+there is now a well defined behavior 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 behavior.
+</P>
+
+<!-- ========================================================================= -->
+<A NAME="Q003"></A>
+<H2><BR><B>Q3 : Compiling is really slow on MacOSX. Why?</B></H2>
+<P>
+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 OSX (10.2?) shipped a a really crappy Bourne shell as /bin/sh
+which resulted in <b>really</b> slow compiles.
+New version of OSX ship GNU BASh as /bin/sh and this answer doesn't apply in that
+case.
+</P>
+<P>
+To fix this I suggest that you install the GNU Bash shell, rename /bin/sh to
+/bin/sh.old and make a softlink from /bin/sh to the bash shell.
+Bash is designed to behave as a Bourne shell when is is called as /bin/sh.
+</P>
+<P>
+When I did this on my iBook running MacOSX, compile times dropped from 13 minutes
+to 3 minutes.
+</P>
+
+<!-- ========================================================================= -->
+<A NAME="Q004"></A>
+<H2><BR><B>Q4 : When trying to compile libsndfile on Solaris I get a "bad
+ substitution" error on linking. Why?</B></H2>
+<P>
+It seems that the Solaris Bourne shell disagrees with GNU libtool.
+</P>
+<P>
+To fix this I suggest that you install the GNU Bash shell, rename /bin/sh to
+/bin/sh.old and make a softlink from /bin/sh to the bash shell.
+Bash is designed to behave as a Bourne shell when is is called as /bin/sh.
+</P>
+
+<!-- ========================================================================= -->
+<A NAME="Q005"></A>
+<H2><BR><B>Q5 : Why doesn't libsndfile do interleaving/de-interleaving?</B></H2>
+<P>
+This problem is bigger than it may seem at first.
+</P>
+<P>
+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 two channels or they want some mixed combination
+of the 4 channels.
+</P>
+<P>
+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.
+</P>
+
+<!-- ========================================================================= -->
+<A NAME="Q006"></A>
+<H2><BR><B>Q6 : What's the best format for storing temporary files?</B></H2>
+
+<P>
+When you want to store temporary data there are a number of requirements;
+</P>
+<UL>
+ <LI> A simple, easy to parse header.
+ <LI> The format must provide the fastest possible read and write rates (ie
+ avoid conversions and encoding/decoding).
+ <LI> The file format must be reasonably common and playable by most players.
+ <LI> Able to store data in either endian-ness.
+</UL>
+<P>
+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.
+</P>
+<P>
+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.
+</P>
+
+<!-- ========================================================================= -->
+
+<A NAME="Q007"></A>
+<H2><BR><B>Q7 : On Linux/Unix/MaxOSX, what's the best way of detecting the presence
+ of libsndfile using autoconf?</B></H2>
+
+<P>
+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):
+</P>
+<PRE>
+ 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)
+</PRE>
+<P>
+This will automatically set the <B>SNDFILE_CFLAGS</B> and <B>SNDFILE_LIBS</B>
+variables which can be used in Makefile.am like this:
+</P>
+<PRE>
+ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
+ SNDFILE_LIBS = @SNDFILE_LIBS@
+</PRE>
+<P>
+If you install libsndfile from source, you will probably need to set the
+<B>PKG_CONFIG_PATH</B> environment variable as suggested at the end of the
+libsndfile configure process. For instance on my system I get this:
+</P>
+<PRE>
+ -=-=-=-=-=-=-=-=-=-= 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.
+</PRE>
+
+<!-- ========================================================================= -->
+
+<A NAME="Q008"></A>
+<H2><BR><B>Q8 : But I just want a simple Makefile! What do I do?</B></H2>
+
+<P>
+The <B>pkg-config</B> program makes finding the correct compiler flag values and
+library location far easier.
+During the installation of libsndfile, a file named <B>sndfile.pc</B> is installed
+in the directory <B>${libdir}/pkgconfig</B> (ie if libsndfile is installed in
+<B>/usr/local/lib</B>, <B>sndfile.pc</B> will be installed in
+<B>/usr/local/lib/pkgconfig/</B>).
+</P>
+<P>
+In order for pkg-config to find sndfile.pc it may be necessary to point the
+environment variable <B>PKG_CONFIG_PATH</B> in the right direction.
+</P>
+<PRE>
+ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
+</PRE>
+
+<P>
+Then, to compile a C file into an object file, the command would be:
+</P>
+<PRE>
+ gcc `pkg-config --cflags sndfile` -c somefile.c
+</PRE>
+<P>
+and to link a number of objects into an executable that links against libsndfile,
+the command would be:
+</P>
+<PRE>
+ gcc `pkg-config --libs sndfile` obj1.o obj2.o -o program
+</PRE>
+
+<!-- ========================================================================= -->
+
+<A NAME="Q009"></A>
+<H2><BR><B>Q9 : How about adding the ability to write/read sound files to/from
+ memory buffers?</B></H2>
+
+<P>
+This has been added for version 1.0.13.
+</P>
+
+<!-- ========================================================================= -->
+
+<A NAME="Q010"></A>
+<H2><BR><B>Q10 : Reading a 16 bit PCM file as normalised floats and then
+ writing them back changes some sample values. Why?</B></H2>
+
+<P>
+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.
+</P>
+<P>
+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 <B>lrintf</B> and <B>lrint</B> (or a replacement has
+been supplied) then the maximum possible error is 1 in 16369 or about 0.006%.
+</P>
+<P>
+Regardless of the size of the error, the reason why this is done is rather
+subtle.
+</P>
+<P>
+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.
+</P>
+<P>
+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.
+</P>
+<P>
+The correct 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).
+</P>
+
+<!-- ========================================================================= -->
+
+<A NAME="Q011"></A>
+<H2><BR><B>Q11 : I'm having problems with u-law encoded WAV files generated by
+ libsndfile in Winamp. Why?
+</B></H2>
+
+<P>
+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.
+</P>
+<P>
+Michael Lee did some experimenting and found that:
+</P>
+<PRE>
+ 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.
+</PRE>
+
+<P>
+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.
+</P>
+
+<!-- ========================================================================= -->
+
+<A NAME="Q012"></A>
+<H2><BR><B>Q12 : I'm looking at sf_read*. What are items? What are frames?
+</B></H2>
+
+<P>
+For a sound file with only one channel, a frame is the same as a item.
+</P>
+<P>
+For multi channel sound files, a single frame contains a single item for
+each channel.
+</P>
+
+<!-- ========================================================================= -->
+
+<A NAME="Q013"></A>
+<H2><BR><B>Q13 : Why can't libsndfile open this Sound Designer II (SD2) file?
+</B></H2>
+
+<P>
+This is somewhat complicated.
+First some background.
+</P>
+
+<P>
+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 OSX it looks like
+this:
+</P>
+
+<PRE>
+ -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
+</PRE>
+
+<P>
+Notice how the file itself looks like a directory containing a single file
+named <B>rsrc</B>.
+When libsndfile is compiled for MacOSX, 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.
+</P>
+
+<P>
+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.
+</P>
+
+<P>
+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 MacOSX to a windows
+shared directory or a Samba share (ie Linux), MacOSX is clever enough to
+store the resource fork of the file in a separate hidden file in the
+same directory like this:
+</P>
+<PRE>
+ -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
+</PRE>
+
+<P>
+Regardless of what platform it is running on, when libsndfile is asked to
+open a file named <B>"foo"</B> 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 <B>"._foo"</B> 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.
+</P>
+
+<P>
+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.
+</P>
+
+<P>
+Occasionally, when SD2 files are moved to other systems, the file is
+ <A HREF="http://www.macdisk.com/binhexen.php3">BinHexed</A>
+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.
+</P>
+
+<!-- ========================================================================= -->
+<A NAME="Q014"></A>
+<H2><BR><B>Q14 : I'd like to statically link libsndfile to my closed source
+ application. Can I buy a license so that this is possible?
+</B></H2>
+
+<P>
+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.
+</P>
+
+<P>
+The <B>only</B> way you can legally use libsndfile as a statically linked
+library is if your application is released under the GNU GPL or LGPL.
+</P>
+
+<!-- ========================================================================= -->
+<A NAME="Q015"></A>
+<H2><BR><B>Q15 : My program is crashing during a call to a function in libsndfile.
+ Is this a bug in libsndfile?
+</B></H2>
+
+<P>
+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.
+</P>
+<P>
+To figure out whether it is your code or libsndfile you should do the
+following:
+</P>
+ <UL>
+ <LI>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
+ <B>-W -Wall -Werror</B> which will force you to fix all warnings
+ before you can run the code.
+ <LI>Try using a memory debugger.
+ <A HREF="http://valgrind.kde.org/">Valgrind</A> on x86 Linux is excellent.
+ <A HREF="http://www.ibm.com/software/awdtools/purify/">Purify</A> also
+ has a good reputation.
+ <LI>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.
+ </UL>
+
+<!-- ========================================================================= -->
+<A NAME="Q016"></A>
+<H2><BR><B>Q16 : Will you accept a fix for compiling libsndfile with compiler X?
+</B></H2>
+
+<P>
+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.
+</P>
+
+<P>
+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.
+</P>
+
+<!-- ========================================================================= -->
+<A NAME="Q017"></A>
+<H2><BR><B>Q17 : Can libsndfile read/write files from/to UNIX pipes?
+</B></H2>
+
+<P>
+Yes, libsndfile can read files from pipes.
+Unfortunately, the write case is much more complicated.
+</P>
+
+<P>
+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.
+</P>
+
+<P>
+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.
+</P>
+
+<P>
+See also <A HREF="#Q006">FAQ Q6</A>.
+</P>
+
+<!-- ========================================================================= -->
+<A NAME="Q018"></A>
+<H2><BR><B>Q18 : Is it possible to build a Universal Binary on Mac OSX?
+</B></H2>
+
+<P>
+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.
+</P>
+
+<P>
+It is <b>not</b> possible to build a working universal binary via a single
+compile/build run on a single CPU.
+</P>
+
+<P>
+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.
+</P>
+
+<P>
+Part of the problem is the 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.
+</P>
+
+<P>
+In addition, 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.
+</P>
+
+<P>
+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.
+</p>
+
+
+<!-- ========================================================================= -->
+<A NAME="Q019"></A>
+<H2><BR><B>Q19 : I have project files for Visual Studio / XCode / Whatever. Why
+ don't you distribute them with libsndfile?
+</B></H2>
+
+<P>
+There's a very good reason for this.
+I will only distribute things that I actually have an ability to test and
+maintain.
+Project files for a bunch of different compilers and Integrated Development
+Environments are simply too difficult to maintain.
+</P>
+
+<P>
+The problem is that every time I add a new file to libsndfile or rename an
+existing file I would have to modify all the project files and then test that
+libsndfile still built with all the different compilers.
+</P>
+
+<P>
+Maintaining these project files is also rather difficult if I don't have access
+to the required compiler/IDE.
+If I just edit the project files without testing them I will almost certainly
+get it wrong.
+If I release a version of libsndfile with broken project files, I'll get a bunch
+of emails from people complaining about it not building and have no way of
+fixing or even testing it.
+</P>
+
+<P>
+I currently release sources that I personally test on Win32, Linux and
+MacOSX (PowerPC) using the compiler I trust (GNU GCC).
+Supporting one compiler on three (actually much more because GCC is available
+almost everywhere) platforms is doable without too much pain.
+I also release binaries for Win32 with instructions on how to use those
+binaries with Visual Studio.
+As a guy who is mainly interested in Linux, I'm not to keen to jump through
+a bunch of hoops to support compilers and operating systems I don't use.
+</P>
+
+<P>
+So, I hear you want to volunteer to maintain the project files for Some Crappy
+Compiler 2007?
+Well sorry, that won't work either.
+I have had numerous people over the years offer to maintaining the project
+files for Microsoft's Visual Studio.
+Every single time that happened, they maintained it for a release or two and
+then disappeared off the face of the earth.
+Hence, I'm not willing to enter into an arrangement like that again.
+</P>
+
+<!-- ========================================================================= -->
+<A NAME="Q020"></A>
+<H2><BR><B>Q20 : Why doesn't libsndfile support MP3? Lots of other Open Source
+ projects support it!
+</B></H2>
+
+<P>
+MP3 is not supported for one very good reason; doing so requires the payment
+of licensing fees.
+As can be seen from
+ <a href="http://www.mp3licensing.com/royalty/software.html">
+ mp3licensing.com</a>
+the required royalty payments are not cheap.
+</P>
+
+<p>
+Yes, I know other libraries ignore the licensing requirements, but their legal
+status is extremely dubious.
+At any time, the body selling the licenses could go after the authors of those
+libraries.
+Some of those authors may be students and hence wouldn't be worth pursuing.
+</P>
+
+<p>
+However, libsndfile is released under the name of a company, Mega Nerd Pty Ltd;
+a company which has income from from libsamplerate licensing, libsndfile based
+consulting income and other unrelated consulting income.
+Adding MP3 support to libsndfile could place that income would be under legal
+threat.
+</p>
+
+<p>
+Fortunately, Ogg Vorbis exists as an alternative to MP3.
+Support for Ogg Vorbis in libsndfile is currently been worked on.
+</p>
+
+<!-- ========================================================================= -->
+<HR>
+<P>
+ The libsndfile home page is here :
+ <A HREF="http://www.mega-nerd.com/libsndfile/">
+ http://www.mega-nerd.com/libsndfile/</A>.
+<BR>
+Version : 1.0.17
+</P>
+
+</BODY>
+</HTML>
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..71ae9d5
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,16 @@
+## Process this file with automake to produce Makefile.in
+
+htmldir = $(htmldocdir)
+html_DATA = index.html libsndfile.jpg libsndfile.css api.html command.html \
+ bugs.html sndfile_info.html new_file_type.HOWTO pkgconfig.html \
+ win32.html FAQ.html lists.html embedded_files.html octave.html \
+ dither.html
+
+EXTRA_DIST = $(html_DATA)
+
+## Do not edit or modify anything in this comment block.
+## The arch-tag line is a file identity tag for the GNU Arch
+## revision control system.
+##
+## arch-tag: 2f7e97fe-5ef8-49a1-ae12-14ebab69c048
+
diff --git a/doc/api.html b/doc/api.html
new file mode 100644
index 0000000..340989f
--- /dev/null
+++ b/doc/api.html
@@ -0,0 +1,703 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ The libsndfile API.
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <META NAME="Description" CONTENT="The libsndfile API.">
+ <META NAME="Keywords" CONTENT="WAV AIFF AU libsndfile sound audio dsp Linux">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+
+<BR>
+<H1><B>libsndfile</B></H1>
+<P>
+ 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.
+</P>
+<!-- pepper -->
+<P>
+ 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 <A HREF="#note1">Note 1</A> and
+ <A HREF="#note2">Note 2</A>.
+</P>
+<!-- pepper -->
+<P>
+ 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 library.
+ If any errors omissions or ambiguities are found, please notify
+ <A HREF="m&#97;ilt&#111;:&#101;rikd&#64;z&#105;p.&#99;om.au">
+ Erik de Castro Lopo</a>.
+</P>
+<!-- pepper -->
+<P>
+ <B> Finally, if you think there is some feature missing from libsndfile, check that
+ it isn't already implemented (and documented)
+ <A HREF="command.html">here</A>.
+ </B>
+</P>
+
+<H2><B>SYNOPSIS</B></H2>
+<P>
+The functions of libsndfile are defined as follows:
+</P>
+<!-- pepper -->
+<PRE>
+ #include &lt;stdio.h&gt;
+ #include &lt;sndfile.h&gt;
+
+ SNDFILE* <A HREF="#open">sf_open</A> (const char *path, int mode, SF_INFO *sfinfo) ;
+ SNDFILE* <A HREF="#open_fd">sf_open_fd</A> (int fd, int mode, SF_INFO *sfinfo, int close_desc) ;
+
+ int <A HREF="#check">sf_format_check</A> (const SF_INFO *info) ;
+
+ sf_count_t <A HREF="#seek">sf_seek</A> (SNDFILE *sndfile, sf_count_t frames, int whence) ;
+
+ int <A HREF="#command">sf_command</A> (SNDFILE *sndfile, int cmd, void *data, int datasize) ;
+
+ int <A HREF="#error">sf_error</A> (SNDFILE *sndfile) ;
+ const char* <A HREF="#error">sf_strerror</A> (SNDFILE *sndfile) ;
+ const char* <A HREF="#error">sf_error_number</A> (int errnum) ;
+
+ int <A HREF="#error">sf_perror</A> (SNDFILE *sndfile) ;
+ int <A HREF="#error">sf_error_str</A> (SNDFILE *sndfile, char* str, size_t len) ;
+
+ int <A HREF="#close">sf_close</A> (SNDFILE *sndfile) ;
+ void <A HREF="#write_sync">sf_write_sync</A> (SNDFILE *sndfile) ;
+
+ sf_count_t <A HREF="#read">sf_read_short</A> (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
+ sf_count_t <A HREF="#read">sf_read_int</A> (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
+ sf_count_t <A HREF="#read">sf_read_float</A> (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
+ sf_count_t <A HREF="#read">sf_read_double</A> (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
+
+ sf_count_t <A HREF="#readf">sf_readf_short</A> (SNDFILE *sndfile, short *ptr, sf_count_t frames) ;
+ sf_count_t <A HREF="#readf">sf_readf_int</A> (SNDFILE *sndfile, int *ptr, sf_count_t frames) ;
+ sf_count_t <A HREF="#readf">sf_readf_float</A> (SNDFILE *sndfile, float *ptr, sf_count_t frames) ;
+ sf_count_t <A HREF="#readf">sf_readf_double</A> (SNDFILE *sndfile, double *ptr, sf_count_t frames) ;
+
+ sf_count_t <A HREF="#write">sf_write_short</A> (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
+ sf_count_t <A HREF="#write">sf_write_int</A> (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
+ sf_count_t <A HREF="#write">sf_write_float</A> (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
+ sf_count_t <A HREF="#write">sf_write_double</A> (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
+
+ sf_count_t <A HREF="#writef">sf_writef_short</A> (SNDFILE *sndfile, short *ptr, sf_count_t frames) ;
+ sf_count_t <A HREF="#writef">sf_writef_int</A> (SNDFILE *sndfile, int *ptr, sf_count_t frames) ;
+ sf_count_t <A HREF="#writef">sf_writef_float</A> (SNDFILE *sndfile, float *ptr, sf_count_t frames) ;
+ sf_count_t <A HREF="#writef">sf_writef_double</A> (SNDFILE *sndfile, double *ptr, sf_count_t frames) ;
+
+ sf_count_t <A HREF="#raw">sf_read_raw</A> (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ;
+ sf_count_t <A HREF="#raw">sf_write_raw</A> (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ;
+
+ const char* <A HREF="#string">sf_get_string</A> (SNDFILE *sndfile, int str_type) ;
+ int <A HREF="#string">sf_set_string</A> (SNDFILE *sndfile, int str_type, const char* str) ;
+
+</PRE>
+<!-- pepper -->
+<P>
+SNDFILE* is an anonymous pointer to data which is private to the library.
+</P>
+
+
+<A NAME="open"></A>
+<H2><B>File Open Function</B></H2>
+
+<PRE>
+ SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo) ;
+</PRE>
+
+<P>
+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:
+</P>
+<!-- pepper -->
+<PRE>
+ typedef struct
+ { sf_count_t frames ; /* Used to be called samples. */
+ int samplerate ;
+ int channels ;
+ int format ;
+ int sections ;
+ int seekable ;
+ } SF_INFO ;
+</PRE>
+
+<P>
+The mode parameter for this function can be any one of the following three values:
+</P>
+<!-- pepper -->
+<PRE>
+ SFM_READ - read only mode
+ SFM_WRITE - write only mode
+ SFM_RDWR - read/write mode
+</PRE>
+
+<P>
+When opening a file for read, the <b>format</B> 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.
+</P>
+<!-- pepper -->
+<P>
+When opening a file for write, the caller must fill in structure members samplerate,
+channels, and format.
+</P>
+<!-- pepper -->
+<P>
+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.
+</P>
+<!-- pepper -->
+<PRE>
+ enum
+ { /* 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 */
+
+ /* 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 Dialogic ADPCM 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) */
+
+ /* 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
+ } ;
+</PRE>
+<!-- pepper -->
+<P>
+Every call to sf_open() should be matched with a call to sf_close() to free up
+memory allocated during the call to sf_open().
+</P>
+<!-- pepper -->
+<P>
+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.
+</P>
+
+<A NAME="open_fd"></A>
+<H3><B>File Descriptor Open</B></H3>
+
+<PRE>
+ SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ;
+</PRE>
+
+<P>
+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:
+</P>
+
+<UL>
+ <LI>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).
+ <LI>Opening files with file names using OS specific character encodings
+ and then passing the file descriptor to sf_open_fd().
+ <LI>Opening sound files embedded within larger files.
+ <A HREF="embedded_files.html">More info</A>.
+</UL>
+
+<P>
+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().
+</P>
+
+<P>
+When sf_close() is called, the file descriptor is only closed if the <B>close_desc</B>
+parameter was TRUE when the sf_open_fd() function was called.
+</P>
+
+<P>
+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.
+</P>
+
+<A NAME="check"></A>
+<BR><H2><B>Format Check Function</B></H2>
+
+<PRE>
+ int sf_format_check (const SF_INFO *info) ;
+</PRE>
+<!-- pepper -->
+<P>
+This function allows the caller to check if a set of parameters in the SF_INFO struct
+is valid before calling sf_open (SFM_WRITE).
+</P>
+<P>
+sf_format_check returns TRUE if the parameters are valid and FALSE otherwise.
+</P>
+
+<A NAME="seek"></A>
+<BR><H2><B>File Seek Functions</B></H2>
+
+<PRE>
+ sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence) ;
+</PRE>
+
+<P>
+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.
+</P>
+
+<P>
+like lseek(), the whence parameter can be any one of the following three values:
+</P>
+
+<PRE>
+ 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.
+</PRE>
+<!-- pepper -->
+<P>
+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.
+</P>
+
+<P>
+Note that the frames offset can be negative and in fact should be when SEEK_END is used for the
+whence parameter.
+</P>
+<P>
+sf_seek will return the offset in (multichannel) frames from the start of the audio data
+or -1 if an error occured (ie an attempt is made to seek beyond the start or end of the file).
+</P>
+
+<A NAME="command"></A>
+<H2><BR><B>Command Interface</B></H2>
+
+<PRE>
+ int sf_command (SNDFILE *sndfile, int cmd, void *data, int datasize) ;
+</PRE>
+
+<P>
+This function allows the caller to retrieve information from or change aspects of the
+library behaviour on a per file basis. Examples include reading or writing text descriptions
+to a file or changing the scaling applied to sample data during read and write.
+</P>
+<!-- pepper -->
+<P>
+The cmd parameter is a short null terminated string which specifies which command
+to execute. 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.
+</P>
+<P>
+The return value of sf_command () depends on the value of the cmd parameter, but it is
+usually non-zero for success and zero on error.
+</P>
+<P>
+This function is explained more fully <A HREF="command.html">here</A>.
+</P>
+
+<A NAME="error"></A>
+<H2><BR><B>Error Reporting Functions</B></H2>
+
+
+<PRE>
+ int sf_error (SNDFILE *sndfile) ;
+</PRE>
+<P>
+This function returns the current error number for the given SNDFILE.
+The error number may be one of the following:
+</P>
+<PRE>
+ enum
+ { SF_ERR_NO_ERROR = 0,
+ SF_ERR_UNRECOGNISED_FORMAT = 1,
+ SF_ERR_SYSTEM = 2,
+ SF_ERR_MALFORMED_FILE = 3,
+ SF_ERR_UNSUPPORTED_ENCODING = 4
+ } ;
+</PRE>
+<!-- pepper -->
+<P>
+or any one of many other internal error values.
+Applications should only test the return value against error values defined in
+&lt;sndfile.h&gt; 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.
+</P>
+
+<PRE>
+ const char* sf_strerror (SNDFILE *sndfile) ;
+ const char* sf_error_number (int errnum) ;
+</PRE>
+
+<P>
+The error functions sf_strerror() and sf_error_number() convert the library's internal
+error enumerations into text strings.
+</P>
+<PRE>
+ int sf_perror (SNDFILE *sndfile) ;
+ int sf_error_str (SNDFILE *sndfile, char* str, size_t len) ;
+</PRE>
+
+<P>
+The functions sf_perror() and sf_error_str() are deprecated and will be dropped
+from the library at some later date.
+</P>
+
+<A NAME="close"></A>
+<H2><BR><B>File Close Function</B></H2>
+
+<PRE>
+ int sf_close (SNDFILE *sndfile) ;
+</PRE>
+<!-- pepper -->
+<P>
+The close function closes the file, deallocates its internal buffers and returns
+0 on success or an error value otherwise.
+</P>
+<BR>
+
+<A NAME="write_sync"></A>
+<H2><BR><B>Write Sync Function</B></H2>
+
+<PRE>
+ void sf_write_sync (SNDFILE *sndfile) ;
+</PRE>
+<!-- pepper -->
+<P>
+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.
+</P>
+<BR>
+
+
+<A NAME="read"></A>
+<H2><BR><B>File Read Functions (Items)</B></H2>
+
+<PRE>
+ 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) ;
+</PRE>
+
+<P>
+The file read items functions fill the array pointed to by ptr with the requested
+number of items. The items parameter must be an integer product of the number
+of channels or an error will occur.
+</P>
+<!-- pepper -->
+<P>
+It is important to note that 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
+<A HREF="#note1">Note 1</A>.
+</P>
+<!-- pepper -->
+<P>
+The sf_read_XXXX functions return the number of items read.
+Unless the end of the file was reached during the read, the return value should
+equal the number of items requested.
+Attempts to read beyond the end of the file will not result in an error but will
+cause the sf_read_XXXX functions to return less than the number of items requested
+or 0 if already at the end of the file.
+</P>
+
+<A NAME="readf"></A>
+<H2><BR><B>File Read Functions (Frames)</B></H2>
+
+<PRE>
+ 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) ;
+</PRE>
+<!-- pepper -->
+<P>
+The file read frames functions fill the array pointed to by ptr with the requested
+number of frames of data. The array must be large enough to hold the product of
+frames and the number of channels.
+</P>
+
+<P><B>
+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).
+</B></P>
+
+<P>
+The sf_readf_XXXX functions return the number of frames read.
+Unless the end of the file was reached during the read, the return value should equal
+the number of frames requested.
+Attempts to read beyond the end of the file will not result in an error but will cause
+the sf_readf_XXXX functions to return less than the number of frames requested or 0 if
+already at the end of the file.
+</P>
+
+<A NAME="write"></A>
+<H2><BR><B>File Write Functions (Items)</B></H2>
+
+<PRE>
+ 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) ;
+</PRE>
+
+<P>
+The file write items functions write the data in the array pointed to by ptr to the file.
+The items parameter must be an integer product of the number of channels or an error
+will occur.
+</P>
+<!-- pepper -->
+<P>
+It is important to note that 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 write the data using sf_write_float(). The library
+seamlessly converts between the two formats on-the-fly. See
+<A HREF="#note1">Note 1</A>.
+</P>
+<P>
+The sf_write_XXXX functions return the number of items written (which should be the
+same as the items parameter).
+</P>
+
+<A NAME="writef"></A>
+<H2><BR><B>File Write Functions (Frames)</B></H2>
+
+<PRE>
+ 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) ;
+</PRE>
+
+<P>
+The file write frames functions write the data in the array pointed to by ptr to the file.
+The array must be large enough to hold the product of frames and the number of channels.
+</P>
+<P>
+The sf_writef_XXXX functions return the number of frames written (which should be the
+same as the frames parameter).
+</P>
+
+<A NAME="raw"></A>
+<H2><BR><B>Raw File Read and Write Functions</B></H2>
+<!-- pepper -->
+<PRE>
+ 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) ;
+</PRE>
+
+<P>
+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.
+</P>
+<!-- pepper -->
+<P>
+The raw read and write functions return the number of bytes read or written (which
+should be the same as the bytes parameter).
+</P>
+
+<P>
+<B>
+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.
+</B>
+</P>
+
+<A NAME="string"></A>
+<H2><BR><B>Functions for Reading and Writing String Data</B></H2>
+
+
+<PRE>
+ const char* sf_get_string (SNDFILE *sndfile, int str_type) ;
+ int sf_set_string (SNDFILE *sndfile, int str_type, const char* str) ;
+</PRE>
+
+<P>
+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 <B>str_type</B> parameter can be any one of the following string types:
+</P>
+
+<PRE>
+ enum
+ { SF_STR_TITLE,
+ SF_STR_COPYRIGHT,
+ SF_STR_SOFTWARE,
+ SF_STR_ARTIST,
+ SF_STR_COMMENT,
+ SF_STR_DATE
+ } ;
+</PRE>
+
+<P>
+The sf_get_string() function returns the specificed 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.
+</P>
+
+<P>
+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().
+</P>
+
+
+<P>
+
+</P>
+
+<HR>
+
+<A NAME="note1"></A>
+<H2><BR><B>Note 1</B></H2>
+<!-- pepper -->
+<P>
+When converting between integer PCM formats of differing size (ie using sf_read_int()
+to read a 16 bit PCM encoded WAV file) libsndfile obeys one simple rule:
+</P>
+
+<P CLASS=indent_block>
+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.
+</P>
+
+<P>
+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 <A HREF="command.html">sf_command</A> interface.
+</P>
+
+<A NAME="note2"></A>
+<H2><BR><B>Note 2</B></H2>
+
+<P>
+Reading a file containg 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 &lt; 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
+ <A HREF="command.html">sf_command</A>
+interface a command of
+ <A HREF="command.html#SFC_SET_SCALE_FLOAT_INT_READ">SFC_SET_SCALE_FLOAT_INT_READ</A>
+and a parameter of SF_TRUE to force correct scaling.
+</P>
+<!-- pepper -->
+<HR>
+<!-- pepper -->
+<P>
+ The libsndfile home page is
+ <A HREF="http://www.mega-nerd.com/libsndfile/">here</A>.
+</P>
+<P>
+Version : 1.0.17
+</P>
+<!-- pepper -->
+<!-- pepper -->
+<!-- pepper -->
+<!-- pepper -->
+
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: f6d3aa8f-983a-4ad3-9681-346e122d815e
+-->
diff --git a/doc/bugs.html b/doc/bugs.html
new file mode 100644
index 0000000..7a7575c
--- /dev/null
+++ b/doc/bugs.html
@@ -0,0 +1,84 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ Bug Reporting
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+
+<CENTER>
+ <H1><B>Reporting Bugs in libsndfile</B></H1>
+</CENTER>
+<P>
+ Before even attempting to report a bug in libsndfile please make sure you have
+ read the
+ <A HREF="FAQ.html">Frequently Asked Questions</A>.
+ If you are having a problem writing code using libsndfile make sure you read
+ the
+ <A HREF="api.html">Application Programming Interface</A>
+ documentation.
+</P>
+<P>
+ 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) :
+</P>
+ <UL>
+ <LI> Compilation problems on new platforms.
+ <LI> Errors being detected during the `make check' process.
+ <LI> Segmentation faults occuring inside libsndfile.
+ <LI> libsndfile hanging when opening a file.
+ <LI> Supported sound file types being incorrectly read or written.
+ <LI> Omissions, errors or spelling mistakes in the documentation.
+ </UL>
+
+<P>
+ When submitting a bug report you must include :
+</P>
+ <UL>
+ <LI> Your system (CPU and memory size should be enough).
+ <LI> The operating system you are using.
+ <LI> Whether you are using a package provided by your distribution or you
+ compiled it youself.
+ <LI> If you compiled it yourself, the compiler you are using. (Also make
+ sure to run "make check".)
+ <LI> A description of the problem.
+ <LI> Information generated by the sndfile-info program (see next paragraph).
+ <LI> 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.
+ </UL>
+
+<P>
+ If libsndfile compiles and installs correctly but has difficulty reading a particular
+ file or type of file you should run the <B>sndfile-info</B> program (from the examples
+ directory of the libsndfile distribution) on the file. See
+ <A HREF="sndfile_info.html">here</A>
+ for an example of the use of the <B>sndfile-info</B> program.
+</P>
+<P>
+ 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.
+</P>
+<P>
+ Once you have the above information you should email it to one of the
+ <A HREF="lists.html">mailing lists</a>
+ (posting to these lists is limited to the list subscribers).
+
+</P>
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 1533a2ca-489c-4190-b602-ecae1cc992e4
+-->
diff --git a/doc/command.html b/doc/command.html
new file mode 100644
index 0000000..ee5bf59
--- /dev/null
+++ b/doc/command.html
@@ -0,0 +1,1245 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ libsndfile : the sf_command function.
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <!-- Another version at the bottom of the page. -->
+ <META NAME="Description" CONTENT="The libsndfile API.">
+ <META NAME="Keywords" CONTENT="WAV AIFF AU libsndfile sound audio dsp Linux">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+
+<H1><B>sf_command</B></H1>
+<PRE>
+
+ int sf_command (SNDFILE *sndfile, int cmd, void *data, int datasize) ;
+</PRE>
+<P>
+ 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.
+</P>
+<P>
+ The cmd parameter is a integer identifier which is defined in &lt;sndfile.h&gt;.
+ 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.
+</P>
+<P>
+ The available commands are as follows:
+</P>
+
+<CENTER>
+<TABLE BORDER="0" WIDTH="90%" CELLPADDING="4">
+<TR>
+ <TD><A HREF="#SFC_GET_LIB_VERSION">SFC_GET_LIB_VERSION</A></TD>
+ <TD>Retrieve the version of the library.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_LOG_INFO">SFC_GET_LOG_INFO</A></TD>
+ <TD>Retrieve the internal per-file operation log.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_CALC_SIGNAL_MAX">SFC_CALC_SIGNAL_MAX</A></TD>
+ <TD>Calculate the measured maximum signal value.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_CALC_NORM_SIGNAL_MAX">SFC_CALC_NORM_SIGNAL_MAX</A></TD>
+ <TD>Calculate the measured normalised maximum signal value.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_CALC_MAX_ALL_CHANNELS">SFC_CALC_MAX_ALL_CHANNELS</A></TD>
+ <TD>Calculate the peak value for each channel.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_CALC_NORM_MAX_ALL_CHANNELS">SFC_CALC_NORM_MAX_ALL_CHANNELS</A></TD>
+ <TD>Calculate the normalised peak for each channel.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_GET_SIGNAL_MAX">SFC_GET_SIGNAL_MAX</A></TD>
+ <TD>Retrieve the peak value for the file (as stored in the file header).</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_MAX_ALL_CHANNELS">SFC_GET_MAX_ALL_CHANNELS</A></TD>
+ <TD>Retrieve the peak value for each channel (as stored in the file header).</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_SET_NORM_FLOAT">SFC_SET_NORM_FLOAT</A></TD>
+ <TD>Modify the normalisation behaviour of the floating point reading and writing functions.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_SET_NORM_DOUBLE">SFC_SET_NORM_DOUBLE</A></TD>
+ <TD>Modify the normalisation behaviour of the double precision floating point reading and writing functions.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_NORM_FLOAT">SFC_GET_NORM_FLOAT</A></TD>
+ <TD>Retrieve the current normalisation behaviour of the floating point reading and writing functions.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_NORM_DOUBLE">SFC_GET_NORM_DOUBLE</A></TD>
+ <TD>Retrieve the current normalisation behaviour of the double precision floating point reading and writing functions.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_SET_SCALE_FLOAT_INT_READ">SFC_SET_SCALE_FLOAT_INT_READ</A></TD>
+ <TD>Set/clear the scale factor when integer (short/int) data is read from a file
+ containing floating point data.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_SIMPLE_FORMAT_COUNT">SFC_GET_SIMPLE_FORMAT_COUNT</A></TD>
+ <TD>Retrieve the number of simple formats supported by libsndfile.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_SIMPLE_FORMAT">SFC_GET_SIMPLE_FORMAT</A></TD>
+ <TD>Retrieve information about a simple format.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_GET_FORMAT_INFO">SFC_GET_FORMAT_INFO</A></TD>
+ <TD>Retrieve information about a major or subtype format.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_GET_FORMAT_MAJOR_COUNT">SFC_GET_FORMAT_MAJOR_COUNT</A></TD>
+ <TD>Retrieve the number of major formats.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_FORMAT_MAJOR">SFC_GET_FORMAT_MAJOR</A></TD>
+ <TD>Retrieve information about a major format type.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_FORMAT_SUBTYPE_COUNT">SFC_GET_FORMAT_SUBTYPE_COUNT</A></TD>
+ <TD>Retrieve the number of subformats.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_FORMAT_SUBTYPE">SFC_GET_FORMAT_SUBTYPE</A></TD>
+ <TD>Retrieve information about a subformat.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_SET_ADD_PEAK_CHUNK">SFC_SET_ADD_PEAK_CHUNK</A></TD>
+ <TD>Switch the code for adding the PEAK chunk to WAV and AIFF files on or off.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_UPDATE_HEADER_NOW">SFC_UPDATE_HEADER_NOW</A></TD>
+ <TD>Used when a file is open for write, this command will update the file
+ header to reflect the data written so far.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_SET_UPDATE_HEADER_AUTO">SFC_SET_UPDATE_HEADER_AUTO</A></TD>
+ <TD>Used when a file is open for write, this command will cause the file header
+ to be updated after each write to the file.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_FILE_TRUNCATE">SFC_FILE_TRUNCATE</A></TD>
+ <TD>Truncate a file open for write or for read/write.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_SET_RAW_START_OFFSET">SFC_SET_RAW_START_OFFSET</A></TD>
+ <TD>Change the data start offset for files opened up as SF_FORMAT_RAW.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_SET_CLIPPING">SFC_SET_CLIPPING</A></TD>
+ <TD>Turn on/off automatic clipping when doing floating point to integer
+ conversion.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_GET_CLIPPING">SFC_GET_CLIPPING</A></TD>
+ <TD>Retreive current clipping setting.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_GET_EMBED_FILE_INFO">SFC_GET_EMBED_FILE_INFO</A></TD>
+ <TD>Retreive information about audio files embedded inside other files.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_WAVEX_GET_AMBISONIC">SFC_GET_AMBISONIC</A></TD>
+ <TD>Test a WAVEX file for Ambisonic format</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_WAVEX_SET_AMBISONIC">SFC_SET_AMBISONIC</A></TD>
+ <TD>Modify a WAVEX header for Ambisonic format</TD>
+</TR>
+
+<!--
+<TR>
+ <TD><A HREF="#add-dither">add dither</A></TD>
+ <TD>Add dither to output on write.</TD>
+</TR>
+-->
+</TABLE>
+</CENTER>
+
+<BR><BR>
+
+<HR>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_LIB_VERSION"></A>
+<H2><BR><B>SFC_GET_LIB_VERSION</B></H2>
+<P>
+Retrieve the version of the library as a string.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : Not used
+ cmd : SFC_GET_LIB_VERSION
+ data : A pointer to a char buffer
+ datasize : The size of the the buffer
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ char buffer [128] ;
+ sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ;
+</PRE>
+
+<DL>
+<DT>Return value:</DT>
+ <DD><DD>This call will return the length of the retrieved version string.
+</DL>
+<DL>
+<DT>Notes:</DT>
+<DD>
+The string returned in the buffer passed to this function will not overflow
+the buffer and will always be null terminated .
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_LOG_INFO"></A>
+<H2><BR><B>SFC_GET_LOG_INFO</B></H2>
+<P>
+Retrieve the log buffer generated when opening a file as a string. This log
+buffer can often contain a good reason for why libsndfile failed to open a
+particular file.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_GET_LOG_INFO
+ data : A pointer to a char buffer
+ datasize : The size of the the buffer
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ char buffer [2048] ;
+ sf_command (sndfile, SFC_GET_LOG_INFO, buffer, sizeof (buffer)) ;
+</PRE>
+
+<DL>
+<DT>Return value:</DT>
+ <DD><DD>This call will return the length of the retrieved version string.
+</DL>
+<DL>
+<DT>Notes:</DT>
+<DD>
+The string returned in the buffer passed to this function will not overflow
+the buffer and will always be null terminated .
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_CALC_SIGNAL_MAX"></A>
+<H2><BR><B>SFC_CALC_SIGNAL_MAX</B></H2>
+<P>
+Retrieve the measured maximum signal value. This involves reading through
+the whole file which can be slow on large files.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_CALC_SIGNAL_MAX
+ data : A pointer to a double
+ datasize : sizeof (double)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ double max_val ;
+ sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &amp;max_val, sizeof (max_val)) ;
+</PRE>
+
+<DL>
+<DT>Return value:</DT>
+ <DD><DD>Zero on success, non-zero otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_CALC_NORM_SIGNAL_MAX"></A>
+<H2><BR><B>SFC_CALC_NORM_SIGNAL_MAX</B></H2>
+<P>
+Retrieve the measured normalised maximum signal value. This involves reading
+through the whole file which can be slow on large files.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_CALC_NORM_SIGNAL_MAX
+ data : A pointer to a double
+ datasize : sizeof (double)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ double max_val ;
+ sf_command (sndfile, SFC_CALC_NORM_SIGNAL_MAX, &amp;max_val, sizeof (max_val)) ;
+</PRE>
+
+<DL>
+<DT>Return value:</DT>
+ <DD><DD>Zero on success, non-zero otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_CALC_MAX_ALL_CHANNELS"></A>
+<H2><BR><B>SFC_CALC_MAX_ALL_CHANNELS</B></H2>
+<P>
+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.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_CALC_MAX_ALL_CHANNELS
+ data : A pointer to a double
+ datasize : sizeof (double) * number_of_channels
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ double peaks [number_of_channels] ;
+ sf_command (sndfile, SFC_CALC_MAX_ALL_CHANNELS, peaks, sizeof (peaks)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>Zero if peaks have been calculated successfully and non-zero otherwise.
+</DL>
+
+
+<!-- ========================================================================= -->
+<A NAME="SFC_CALC_NORM_MAX_ALL_CHANNELS"></A>
+<H2><BR><B>SFC_CALC_NORM_MAX_ALL_CHANNELS</B></H2>
+<P>
+Calculate the normalised peak for each channel.
+This involves reading through the whole file which can be slow on large files.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_CALC_NORM_MAX_ALL_CHANNELS
+ data : A pointer to a double
+ datasize : sizeof (double) * number_of_channels
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ double peaks [number_of_channels] ;
+ sf_command (sndfile, SFC_CALC_NORM_MAX_ALL_CHANNELS, peaks, sizeof (peaks)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>Zero if peaks have been calculated successfully and non-zero otherwise.
+</DL>
+
+
+
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_SIGNAL_MAX"></A>
+<H2><BR><B>SFC_GET_SIGNAL_MAX</B></H2>
+<P>
+Retrieve the peak value for the file as stored in the file header.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_GET_SIGNAL_MAX
+ data : A pointer to a double
+ datasize : sizeof (double)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ double max_peak ;
+ sf_command (sndfile, SFC_GET_SIGNAL_MAX, &amp;max_peak, sizeof (max_peak)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>SF_TRUE if the file header contained the peak value. SF_FALSE otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_MAX_ALL_CHANNELS"></A>
+<H2><BR><B>SFC_GET_MAX_ALL_CHANNELS</B></H2>
+<P>
+Retrieve the peak value for the file as stored in the file header.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_GET_SIGNAL_MAX
+ data : A pointer to an array of doubles
+ datasize : sizeof (double) * number_of_channels
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ double peaks [number_of_channels] ;
+ sf_command (sndfile, SFC_GET_MAX_ALL_CHANNELS, peaks, sizeof (peaks)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>SF_TRUE if the file header contains per channel peak values for the file.
+ SF_FALSE otherwise.
+</DL>
+
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_NORM_FLOAT"></A>
+<H2><BR><B>SFC_SET_NORM_FLOAT</B></H2>
+<P>
+This command only affects data read from or written to using the floating point functions:
+</P>
+<PRE>
+ size_t <A HREF="api.html#read">sf_read_float</A> (SNDFILE *sndfile, float *ptr, size_t items) ;
+ size_t <A HREF="api.html#readf">sf_readf_float</A> (SNDFILE *sndfile, float *ptr, size_t frames) ;
+
+ size_t <A HREF="api.html#write">sf_write_float</A> (SNDFILE *sndfile, float *ptr, size_t items) ;
+ size_t <A HREF="api.html#writef">sf_writef_float</A> (SNDFILE *sndfile, float *ptr, size_t frames) ;
+</PRE>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_SET_NORM_FLOAT
+ data : NULL
+ datasize : SF_TRUE or SF_FALSE
+</PRE>
+<P>
+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].
+</P>
+<P>
+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.
+</P>
+<P>
+For both cases, setting normalisation to SF_FALSE means that no scaling will take place.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ sf_command (sndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE) ;
+
+ sf_command (sndfile, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>Returns the previous float normalisation mode.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_NORM_DOUBLE"></A>
+<H2><BR><B>SFC_SET_NORM_DOUBLE</B></H2>
+<P>
+This command only affects data read from or written to using the double precision
+floating point functions:
+</P>
+<PRE>
+ size_t <A HREF="api.html#read">sf_read_double</A> (SNDFILE *sndfile, double *ptr, size_t items) ;
+ size_t <A HREF="api.html#readf">sf_readf_double</A> (SNDFILE *sndfile, double *ptr, size_t frames) ;
+
+ size_t <A HREF="api.html#write">sf_write_double</A> (SNDFILE *sndfile, double *ptr, size_t items) ;
+ size_t <A HREF="api.html#writef">sf_writef_double</A> (SNDFILE *sndfile, double *ptr, size_t frames) ;
+</PRE>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_SET_NORM_DOUBLE
+ data : NULL
+ datasize : SF_TRUE or SF_FALSE
+</PRE>
+<P>
+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].
+</P>
+<P>
+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.
+</P>
+<P>
+For both cases, setting normalisation to SF_FALSE means that no scaling will take place.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ sf_command (sndfile, SFC_SET_NORM_DOUBLE, NULL, SF_TRUE) ;
+
+ sf_command (sndfile, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>Returns the previous double normalisation mode.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_NORM_FLOAT"></A>
+<H2><BR><B>SFC_GET_NORM_FLOAT</B></H2>
+<P>
+Retrieve the current float normalisation mode.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_GET_NORM_FLOAT
+ data : NULL
+ datasize : anything
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ normalisation = sf_command (sndfile, SFC_GET_NORM_FLOAT, NULL, 0) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>Returns TRUE if normalisation is on and FALSE otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_NORM_DOUBLE"></A>
+<H2><BR><B>SFC_GET_NORM_DOUBLE</B></H2>
+<P>
+Retrieve the current float normalisation mode.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_GET_NORM_DOUBLE
+ data : NULL
+ datasize : anything
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ normalisation = sf_command (sndfile, SFC_GET_NORM_DOUBLE, NULL, 0) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>Returns TRUE if normalisation is on and FALSE otherwise.
+</DL>
+
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_SCALE_FLOAT_INT_READ"></A>
+<H2><BR><B>SFC_SET_SCALE_FLOAT_INT_READ</B></H2>
+<P>
+Set/clear the scale factor when integer (short/int) data is read from a file
+containing floating point data.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_SET_SCALE_FLOAT_INT_READ
+ data : NULL
+ datasize : TRUE or FALSE
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ sf_command (sndfile, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>Returns the previous SFC_SET_SCALE_FLOAT_INT_READ setting for this file.
+</DL>
+
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_SIMPLE_FORMAT_COUNT"></A>
+<H2><BR><B>SFC_GET_SIMPLE_FORMAT_COUNT</B></H2>
+<P>
+Retrieve the number of simple formats supported by libsndfile.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_SIMPLE_FORMAT_COUNT
+ data : a pointer to an int
+ datasize : sizeof (int)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ int count ;
+ sf_command (sndfile, SFC_GET_SIMPLE_FORMAT_COUNT, &amp;count, sizeof (int)) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_SIMPLE_FORMAT"></A>
+<H2><BR><B>SFC_GET_SIMPLE_FORMAT</B></H2>
+<P>
+Retrieve information about a simple format.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_SIMPLE_FORMAT
+ data : a pointer to an SF_FORMAT_INFO struct
+ datasize : sizeof (SF_FORMAT_INFO)
+</PRE>
+<P>
+The SF_FORMAT_INFO struct is defined in &lt;sndfile.h&gt; as:
+</P>
+<PRE>
+ typedef struct
+ { int format ;
+ const char *name ;
+ const char *extension ;
+ } SF_FORMAT_INFO ;
+</PRE>
+<P>
+When sf_command() is called with SF_GET_SIMPLE_FORMAT, the value of the format
+field should be the format number (ie 0 &lt;= format &lt;= count value obtained using
+SF_GET_SIMPLE_FORMAT_COUNT).
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ SF_FORMAT_INFO format_info ;
+ int k, count ;
+
+ sf_command (sndfile, SFC_GET_SIMPLE_FORMAT_COUNT, &amp;count, sizeof (int)) ;
+
+ for (k = 0 ; k &lt; count ; k++)
+ { format_info.format = k ;
+ sf_command (sndfile, SFC_GET_SIMPLE_FORMAT, &amp;format_info, sizeof (format_info)) ;
+ printf ("%08x %s %s\n", format_info.format, format_info.name, format_info.extension) ;
+ } ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0 on success and non-zero otherwise.
+ <DD>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.
+ <DD>The name field will contain a char* pointer to the name of the string, eg. "WAV (Microsoft 16 bit PCM)".
+ <DD>The extension field will contain the most commonly used file extension for that file type.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_FORMAT_INFO"></A>
+<H2><BR><B>SFC_GET_FORMAT_INFO</B></H2>
+<P>
+Retrieve information about a major or subtype format.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_FORMAT_INFO
+ data : a pointer to an SF_FORMAT_INFO struct
+ datasize : sizeof (SF_FORMAT_INFO)
+</PRE>
+<P>
+The SF_FORMAT_INFO struct is defined in &lt;sndfile.h&gt; as:
+</P>
+<PRE>
+ typedef struct
+ { int format ;
+ const char *name ;
+ const char *extension ;
+ } SF_FORMAT_INFO ;
+</PRE>
+<P>
+When sf_command() is called with SF_GET_FORMAT_INFO, the format field is
+examined and if (format &amp; SF_FORMAT_TYPEMASK) is a valid format then the struct
+is filled in with information about the given major type.
+If (format &amp; SF_FORMAT_TYPEMASK) is FALSE and (format &amp; SF_FORMAT_SUBMASK) is a
+valid subtype format then the struct is filled in with information about the given
+subtype.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ SF_FORMAT_INFO format_info ;
+
+ format_info.format = SF_FORMAT_WAV ;
+ sf_command (sndfile, SFC_GET_FORMAT_INFO, &amp;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, &amp;format_info, sizeof (format_info)) ;
+ printf ("%08x %s\n", format_info.format, format_info.name) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0 on success and non-zero otherwise.
+</DL>
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_FORMAT_MAJOR_COUNT"></A>
+<H2><BR><B>SFC_GET_FORMAT_MAJOR_COUNT</B></H2>
+<P>
+Retrieve the number of major formats.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_FORMAT_MAJOR_COUNT
+ data : a pointer to an int
+ datasize : sizeof (int)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ int count ;
+ sf_command (sndfile, SFC_GET_FORMAT_MAJOR_COUNT, &amp;count, sizeof (int)) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_FORMAT_MAJOR"></A>
+<H2><BR><B>SFC_GET_FORMAT_MAJOR</B></H2>
+<P>
+Retrieve information about a major format type.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_FORMAT_MAJOR
+ data : a pointer to an SF_FORMAT_INFO struct
+ datasize : sizeof (SF_FORMAT_INFO)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ SF_FORMAT_INFO format_info ;
+ int k, count ;
+
+ sf_command (sndfile, SFC_GET_FORMAT_MAJOR_COUNT, &amp;count, sizeof (int)) ;
+
+ for (k = 0 ; k &lt; count ; k++)
+ { format_info.format = k ;
+ sf_command (sndfile, SFC_GET_FORMAT_MAJOR, &amp;format_info, sizeof (format_info)) ;
+ printf ("%08x %s %s\n", format_info.format, format_info.name, format_info.extension) ;
+ } ;
+</PRE>
+<P>
+For a more comprehensive example, see the program list_formats.c in the examples/
+directory of the libsndfile source code distribution.
+</P>
+<DL>
+<DT>Return value: </DT>
+ <DD>0 on success and non-zero otherwise.
+ <DD>The value of the format field will be one of the major format identifiers such as
+ SF_FORMAT_WAV or SF_FORMAT_AIFF.
+ <DD>The name field will contain a char* pointer to the name of the string, eg. "WAV (Microsoft)".
+ <DD>The extension field will contain the most commonly used file extension for that file type.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_FORMAT_SUBTYPE_COUNT"></A>
+<H2><BR><B>SFC_GET_FORMAT_SUBTYPE_COUNT</B></H2>
+<P>
+Retrieve the number of subformats.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_FORMAT_SUBTYPE_COUNT
+ data : a pointer to an int
+ datasize : sizeof (int)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ int count ;
+ sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE_COUNT, &amp;count, sizeof (int)) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_FORMAT_SUBTYPE"></A>
+<H2><BR><B>SFC_GET_FORMAT_SUBTYPE</B></H2>
+<P>
+Enumerate the subtypes (this function does not translate a sub type 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.
+</P>
+<P>
+
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_FORMAT_SUBTYPE
+ data : a pointer to an SF_FORMAT_INFO struct
+ datasize : sizeof (SF_FORMAT_INFO)
+</PRE>
+<P>
+Example 1: Retrieve all subytpes supported by the WAV format.
+</P>
+<PRE>
+ SF_FORMAT_INFO format_info ;
+ int k, count ;
+
+ sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE_COUNT, &amp;count, sizeof (int)) ;
+
+ for (k = 0 ; k &lt; count ; k++)
+ { format_info.format = k ;
+ sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE, &amp;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) ;
+ } ;
+</PRE>
+<P>
+Example 2: Print a string describing the SF_FORMAT_PCM_16 subtype.
+</P>
+<PRE>
+ SF_FORMAT_INFO format_info ;
+ int k, count ;
+
+ sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE_COUNT, &amp;count, sizeof (int)) ;
+
+ for (k = 0 ; k &lt; count ; k++)
+ { format_info.format = k ;
+ sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE, &amp;format_info, sizeof (format_info)) ;
+ if (format_info.format == SF_FORMAT_PCM_16)
+ { printf ("%08x %s\n", format_info.format, format_info.name) ;
+ break ;
+ } ;
+ } ;
+</PRE>
+<P>
+For a more comprehensive example, see the program list_formats.c in the examples/
+directory of the libsndfile source code distribution.
+</P>
+<DL>
+<DT>Return value: </DT>
+ <DD>0 on success and non-zero otherwise.
+ <DD>The value of the format field will be one of the major format identifiers such as
+ SF_FORMAT_WAV or SF_FORMAT_AIFF.
+ <DD>The name field will contain a char* pointer to the name of the string; for instance
+ "WAV (Microsoft)" or "AIFF (Apple/SGI)".
+ <DD>The extension field will be a NULL pointer.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_ADD_PEAK_CHUNK"></A>
+<H2><BR><B>SFC_SET_ADD_PEAK_CHUNK</B></H2>
+<P>
+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.
+</P>
+<P>
+Note : This call must be made before any data is written to the file.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_SET_ADD_PEAK_CHUNK
+ data : Not used (should be NULL)
+ datasize : TRUE or FALSE.
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ /* 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) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+<DD>Returns SF_TRUE if the peak chunk will be written after this call.
+<DD>Returns SF_FALSE if the peak chunk will not be written after this call.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_UPDATE_HEADER_NOW"></A>
+<H2><BR><B>SFC_UPDATE_HEADER_NOW</B></H2>
+<P>
+The header of an audio file is normally written by libsndfile when the file is
+closed using <B>sf_close()</B>.
+</P>
+<P>
+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.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_UPDATE_HEADER_NOW
+ data : Not used (should be NULL)
+ datasize : Not used.
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ /* Update the header now. */
+ sf_command (sndfile, SFC_UPDATE_HEADER_NOW, NULL, 0) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+<DD>0
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_UPDATE_HEADER_AUTO"></A>
+<H2><BR><B>SFC_SET_UPDATE_HEADER_AUTO</B></H2>
+<P>
+Similar to SFC_UPDATE_HEADER_NOW but updates the header at the end of every call
+to the <B>sf_write*</B> functions.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_UPDATE_HEADER_NOW
+ data : Not used (should be NULL)
+ datasize : SF_TRUE or SF_FALSE
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ /* 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) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+<DD>TRUE if auto update header is now on; FALSE otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_FILE_TRUNCATE"></A>
+<H2><BR><B>SFC_FILE_TRUNCATE</B></H2>
+<P>
+Truncate a file that was opened for write or read/write.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_FILE_TRUNCATE
+ data : A pointer to an sf_count_t.
+ datasize : sizeof (sf_count_t)
+</PRE>
+
+<P>
+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.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ /* Truncate the file to a length of 20 frames. */
+ sf_count_t frames = 20 ;
+ sf_command (sndfile, SFC_FILE_TRUNCATE, &amp;frames, sizeof (frames)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>Zero on sucess, non-zero otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_RAW_START_OFFSET"></A>
+<H2><BR><B>SFC_SET_RAW_START_OFFSET</B></H2>
+<P>
+Change the data start offset for files opened up as SF_FORMAT_RAW.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_SET_RAW_START_OFFSET
+ data : A pointer to an sf_count_t.
+ datasize : sizeof (sf_count_t)
+</PRE>
+
+<P>
+For a file opened as format SF_FORMAT_RAW, set the data offset to the value
+given by data.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ /* 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, &amp;offset, sizeof (offset)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>Zero on sucess, non-zero otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_CLIPPING"></A>
+<H2><BR><B>SFC_SET_CLIPPING</B></H2>
+<P>
+Turn on/off automatic clipping when doing floating point to integer conversion.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_SET_CLIPPING
+ data : NULL
+ datasize : SF_TRUE or SF_FALSE.
+</PRE>
+
+<P>
+Turn on (datasize == SF_TRUE) or off (datasize == SF_FALSE) clipping.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ sf_command (sndfile, SFC_SET_CLIPPING, NULL, SF_TRUE) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>Clipping mode (SF_TRUE or SF_FALSE).
+</DL>
+
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_CLIPPING"></A>
+<H2><BR><B>SFC_GET_CLIPPING</B></H2>
+<P>
+Turn on/off automatic clipping when doing floating point to integer conversion.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_GET_CLIPPING
+ data : NULL
+ datasize : 0
+</PRE>
+
+<P>
+Retrieve the current cliiping setting.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ sf_command (sndfile, SFC_GET_CLIPPING, NULL, 0) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>Clipping mode (SF_TRUE or SF_FALSE).
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_EMBED_FILE_INFO"></A>
+<H2><BR><B>SFC_GET_EMBED_FILE_INFO</B></H2>
+<P>
+Get the file offset and file length of a file enbedded within another
+larger file.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_GET_CLIPPING
+ data : a pointer to an SF_EMBED_FILE_INFO struct
+ datasize : sizeof (SF_EMBED_FILE_INFO)
+</PRE>
+<P>
+The SF_FORMAT_INFO struct is defined in &lt;sndfile.h&gt; as:
+</P>
+<PRE>
+ typedef struct
+ { sf_count_t offset ;
+ sf_count_t length ;
+ } SF_EMBED_FILE_INFO ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0 on success and non-zero otherwise.
+ <DD>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.
+ <DD>The value of the offset field of the SF_EMBED_FILE_INFO struct will be
+ the length in bytes of the embedded file.
+</DL>
+
+
+
+<!-- ========================================================================= -->
+<A NAME="SFC_WAVEX_GET_AMBISONIC"></A>
+<H2><BR><B>SFC_WAVEX_GET_AMBISONIC</B></H2>
+<P>
+Test if the current file has the GUID of a WAVEX file for any of the Ambisonic
+formats.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_WAVEX_GET_AMBISONIC
+ data : NULL
+ datasize : 0
+</PRE>
+<P>
+ The Ambisonic WAVEX formats are defined here :
+ <A HREF="http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html">
+ http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html</A>.
+</P>
+<DL>
+<DT>Return value: </DT>
+ <DD>SF_AMBISONIC_NONE or SF_AMBISONIC_B_FORMAT or zero if the file format
+ does not support ambisonic formats.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_WAVEX_SET_AMBISONIC"></A>
+<H2><BR><B>SFC_WAVEX_SET_AMBISONIC</B></H2>
+<P>
+Set the GUID of a new WAVEX file to indicate an Ambisonics format.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_WAVEX_SET_AMBISONIC
+ data : NULL
+ datasize : SF_AMBISONIC_NONE or SF_AMBISONIC_B_FORMAT
+</PRE>
+<P>
+Turn on (SF_AMBISONIC_B_FORMAT) or off (SF_AMBISONIC_NONE) encoding.
+This command is currently only supported for files with SF_FORMAT_WAVEX format.
+</P>
+<P>
+ The Ambisonic WAVEX formats are defined here :
+ <A HREF="http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html">
+ http://dream.cs.bath.ac.uk/researchdev/wave-ex/bformat.html</A>.
+</P>
+<DL>
+<DT>Return value: </DT>
+ <DD>Return the ambisonic value that has just been set or zero if the file
+ format does not support ambisonic encoding.
+</DL>
+
+<!-- ========================================================================= -->
+
+
+<HR>
+<P>
+ The libsndfile home page is here :
+ <A HREF="http://www.mega-nerd.com/libsndfile/">
+ http://www.mega-nerd.com/libsndfile/</A>.
+<BR>
+Version : 1.0.17
+</P>
+
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 6ee72f74-0fb3-42b6-a85c-d3331d7145b5
+-->
diff --git a/doc/development.html b/doc/development.html
new file mode 100644
index 0000000..81397fe
--- /dev/null
+++ b/doc/development.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ libsndfile Development
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+<!-- pepper -->
+<H1><BR>libsndfile Development</H1>
+<!-- pepper -->
+<P>
+libsndfile is being developed by a small but growing community of users
+and hackers led by Erik de Castro Lopo.
+People interested in helping should join the libsndfile-devel
+ <A HREF="lists.html">mailing list</A>
+where most of the discussion about new features takes place.
+</P>
+<!-- pepper -->
+<P>
+libsndfile is being developed using the
+ <A HREF="http://bazaar-vcs.org/">Bzr</A>
+revision control system which is especially well suited to distributed
+development.
+In most respects, Bzr is significantly better than most other revision
+control systems.
+It is even available for windows, but I (Erik) have not personally used
+it on windows.
+</P>
+<!-- pepper -->
+<P>
+The main archive archive can be found at:
+<A HREF="http://www.mega-nerd.com/Bzr/libsndfile-mdev/">
+ http://www.mega-nerd.com/Bzr/libsndfile-mdev/</A>
+</P>
+<!-- pepper -->
+<P>
+Assuming that you have Bzr installed (on Debian GNU/Linux "apt-get install bzr")
+you can do:
+</P>
+<!-- pepper -->
+<PRE>
+ bzr get http://www.mega-nerd.com/Bzr/libsndfile-mdev/
+</PRE>
+<!-- pepper -->
+<P>
+to retreive a copy of whats currently in the public archive.
+To configure, build and verify the build you can do:
+</P>
+<!-- pepper -->
+<PRE>
+ ./reconfigure.mk
+ ./configure
+ make
+ make check
+</PRE>
+<!-- pepper -->
+
+<P>
+During the configuration stage, some later versions of aclocal (I see this
+with 1.9.X) may spew out a bunch of warning messages about underquoted
+defintions in AC_WHATEVER, but these can safely be ignored.
+</P>
+<P>
+In order to build the sources from the Bzr archive, you will need the
+Python interpreter and GNU Autogen which is available
+ <A HREF="http://autogen.sf.net">here</A>.
+</P>
+<!-- pepper -->
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 81e947c2-fb8c-4d8b-93b4-57682d2787b5
+-->
diff --git a/doc/dither.html b/doc/dither.html
new file mode 100644
index 0000000..16ca2de
--- /dev/null
+++ b/doc/dither.html
@@ -0,0 +1,1024 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ libsndfile : the sf_command function.
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <!-- Another version at the bottom of the page. -->
+ <META NAME="Description" CONTENT="The libsndfile API.">
+ <META NAME="Keywords" CONTENT="WAV AIFF AU libsndfile sound audio dsp Linux">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+
+<H1><B>sf_command</B></H1>
+<PRE>
+
+ int sf_command (SNDFILE *sndfile, int cmd, void *data, int datasize) ;
+</PRE>
+<P>
+ 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.
+</P>
+<P>
+ The cmd parameter is a integer identifier which is defined in &lt;sndfile.h&gt;.
+ All of the valid command identifiers have names begining 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.
+</P>
+<P>
+ The available commands are as follows:
+</P>
+
+<CENTER>
+<TABLE BORDER="0" WIDTH="90%" CELLPADDING="4">
+<TR>
+ <TD><A HREF="#SFC_GET_LIB_VERSION">SFC_GET_LIB_VERSION</A></TD>
+ <TD>Retrieve the version of the library.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_LOG_INFO">SFC_GET_LOG_INFO</A></TD>
+ <TD>Retrieve the internal per-file operation log.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_CALC_SIGNAL_MAX">SFC_CALC_SIGNAL_MAX</A></TD>
+ <TD>Retrieve the measured maximum signal value.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_CALC_NORM_SIGNAL_MAX">SFC_CALC_NORM_SIGNAL_MAX</A></TD>
+ <TD>Retrieve the measured normalised maximum signal value.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_CALC_MAX_ALL_CHANNELS">SFC_CALC_MAX_ALL_CHANNELS</A></TD>
+ <TD>Calculate peaks for all channels.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_CALC_NORM_MAX_ALL_CHANNELS">SFC_CALC_NORM_MAX_ALL_CHANNELS</A></TD>
+ <TD>Calculate normalised peaks for all channels.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_SET_NORM_FLOAT">SFC_SET_NORM_FLOAT</A></TD>
+ <TD>Modify the normalisation behaviour of the floating point reading and writing functions.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_SET_NORM_DOUBLE">SFC_SET_NORM_DOUBLE</A></TD>
+ <TD>Modify the normalisation behaviour of the double precision floating point reading and writing functions.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_NORM_FLOAT">SFC_GET_NORM_FLOAT</A></TD>
+ <TD>Retrieve the current normalisation behaviour of the floating point reading and writing functions.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_NORM_DOUBLE">SFC_GET_NORM_DOUBLE</A></TD>
+ <TD>Retrieve the current normalisation behaviour of the double precision floating point reading and writing functions.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_SIMPLE_FORMAT_COUNT">SFC_GET_SIMPLE_FORMAT_COUNT</A></TD>
+ <TD>Retrieve the number of simple formats supported by libsndfile.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_SIMPLE_FORMAT">SFC_GET_SIMPLE_FORMAT</A></TD>
+ <TD>Retrieve information about a simple format.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_GET_FORMAT_INFO">SFC_GET_FORMAT_INFO</A></TD>
+ <TD>Retrieve information about a major or subtype format.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_GET_FORMAT_MAJOR_COUNT">SFC_GET_FORMAT_MAJOR_COUNT</A></TD>
+ <TD>Retrieve the number of major formats.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_FORMAT_MAJOR">SFC_GET_FORMAT_MAJOR</A></TD>
+ <TD>Retrieve information about a major format type.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_FORMAT_SUBTYPE_COUNT">SFC_GET_FORMAT_SUBTYPE_COUNT</A></TD>
+ <TD>Retrieve the number of subformats.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_GET_FORMAT_SUBTYPE">SFC_GET_FORMAT_SUBTYPE</A></TD>
+ <TD>Retrieve information about a subformat.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_SET_ADD_PEAK_CHUNK">SFC_SET_ADD_PEAK_CHUNK</A></TD>
+ <TD>Switch the code for adding the PEAK chunk to WAV and AIFF files on or off.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_UPDATE_HEADER_NOW">SFC_UPDATE_HEADER_NOW</A></TD>
+ <TD>Used when a file is open for write, this command will update the file
+ header to reflect the data written so far.</TD>
+</TR>
+<TR>
+ <TD><A HREF="#SFC_SET_UPDATE_HEADER_AUTO">SFC_SET_UPDATE_HEADER_AUTO</A></TD>
+ <TD>Used when a file is open for write, this command will cause the file header
+ to be updated after each write to the file.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_FILE_TRUNCATE">SFC_FILE_TRUNCATE</A></TD>
+ <TD>Truncate a file open for write or for read/write.</TD>
+</TR>
+
+<TR>
+ <TD><A HREF="#SFC_SET_RAW_START_OFFSET">SFC_SET_RAW_START_OFFSET</A></TD>
+ <TD>Change the data start offset for files opened up as SF_FORMAT_RAW.</TD>
+</TR>
+
+
+
+<!--
+<TR>
+ <TD><A HREF="#add-dither">add dither</A></TD>
+ <TD>Add dither to output on write.</TD>
+</TR>
+-->
+</TABLE>
+</CENTER>
+
+<BR><BR>
+
+<HR>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_LIB_VERSION"></A>
+<H2><BR><B>SFC_GET_LIB_VERSION</B></H2>
+<P>
+Retrieve the version of the library as a string.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : Not used
+ cmd : SFC_GET_LIB_VERSION
+ data : A pointer to a char buffer
+ datasize : The size of the the buffer
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ char buffer [128] ;
+ sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ;
+</PRE>
+
+<DL>
+<DT>Return value:</DT>
+ <DD><DD>This call will return the length of the retrieved version string.
+</DL>
+<DL>
+<DT>Notes:</DT>
+<DD>
+The string returned in the buffer passed to this function will not overflow
+the buffer and will always be null terminated .
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_LOG_INFO"></A>
+<H2><BR><B>SFC_GET_LOG_INFO</B></H2>
+<P>
+Retrieve the log buffer generated when opening a file as a string. This log
+buffer can often contain a good reason for why libsndfile failed to open a
+particular file.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_GET_LOG_INFO
+ data : A pointer to a char buffer
+ datasize : The size of the the buffer
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ char buffer [2048] ;
+ sf_command (sndfile, SFC_GET_LOG_INFO, buffer, sizeof (buffer)) ;
+</PRE>
+
+<DL>
+<DT>Return value:</DT>
+ <DD><DD>This call will return the length of the retrieved version string.
+</DL>
+<DL>
+<DT>Notes:</DT>
+<DD>
+The string returned in the buffer passed to this function will not overflow
+the buffer and will always be null terminated .
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_CALC_SIGNAL_MAX"></A>
+<H2><BR><B>SFC_CALC_SIGNAL_MAX</B></H2>
+<P>
+Retrieve the measured maximum signal value. This involves reading through
+the whole file which can be slow on large files.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_CALC_SIGNAL_MAX
+ data : A pointer to a double
+ datasize : sizeof (double)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ double max_val ;
+ sf_command (sndfile, SFC_CALC_SIGNAL_MAX, &amp;max_val, sizeof (max_val)) ;
+</PRE>
+
+<DL>
+<DT>Return value:</DT>
+ <DD><DD>Zero on success, non-zero otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_CALC_NORM_SIGNAL_MAX"></A>
+<H2><BR><B>SFC_CALC_NORM_SIGNAL_MAX</B></H2>
+<P>
+Retrieve the measured normailised maximum signal value. This involves reading
+through the whole file which can be slow on large files.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_CALC_NORM_SIGNAL_MAX
+ data : A pointer to a double
+ datasize : sizeof (double)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ double max_val ;
+ sf_command (sndfile, SFC_CALC_NORM_SIGNAL_MAX, &amp;max_val, sizeof (max_val)) ;
+</PRE>
+
+<DL>
+<DT>Return value:</DT>
+ <DD><DD>Zero on success, non-zero otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_CALC_MAX_ALL_CHANNELS"></A>
+<H2><BR><B>SFC_CALC_MAX_ALL_CHANNELS</B></H2>
+<P>
+Calculate peaks for all channels. This involves reading through
+the whole file which can be slow on large files.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_CALC_MAX_ALL_CHANNELS
+ data : A pointer to a double
+ datasize : sizeof (double) * number_of_channels
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ double peaks [number_of_channels] ;
+ sf_command (sndfile, SFC_CALC_MAX_ALL_CHANNELS, peaks, sizeof (peaks)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>Zero if peaks have been calculated successfully and non-zero otherwise.
+</DL>
+
+
+<!-- ========================================================================= -->
+<A NAME="SFC_CALC_NORM_MAX_ALL_CHANNELS"></A>
+<H2><BR><B>SFC_CALC_NORM_MAX_ALL_CHANNELS</B></H2>
+<P>
+Calculate normalised peaks for all channels. This involves reading through
+the whole file which can be slow on large files.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_CALC_NORM_MAX_ALL_CHANNELS
+ data : A pointer to a double
+ datasize : sizeof (double) * number_of_channels
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ double peaks [number_of_channels] ;
+ sf_command (sndfile, SFC_CALC_NORM_MAX_ALL_CHANNELS, peaks, sizeof (peaks)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>Zero if peaks have been calculated successfully and non-zero otherwise.
+</DL>
+
+
+
+
+
+<!-- ========================================================================= -->
+<!--
+<A NAME="read-text"></A>
+<H2><BR><B>Read text</B></H2>
+<P>
+Many sound file formats contain allow the inclusion of a text string describing the nature
+of the file. If a file contains such a string, this functions will return it to the caller.
+</P>
+<P>
+It should be noted that the way the string is added to the file is file format dependant
+but that any string added with <A HREF="#write-text">write text</A> will be returned by
+<A HREF="#read-text">read text</A>.
+</P>
+<P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : The text string "read text".
+ data : A pointer to a char buffer.
+ datasize : The size of the the buffer.
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ char buffer [128] ;
+ sf_command (sndfile, "read text", buffer, sizeof (buffer)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+<DD>If a text string is found, this call will return the length of the retrieved text
+ string.
+ <DD>If no text string is found, zero will be returned and the first element in the
+ buffer will be set to the null character.
+<DT>Notes:</DT>
+<DD>The string returned in the buffer passed to this function will not overflow
+ the buffer and will be correctly null terminated .
+</DL>
+
+<A NAME="write-text"></A>
+<H2><BR><B>Write text</B></H2>
+<P>
+Add a text string to a file. The text string added can be retrieved when the file is
+read using <A HREF="#read-text">read text</A>.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : The text string "write text".
+ data : A pointer to the string to be added.
+ datasize : Not used.
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ char text = "The sound of one hand clapping." ;
+ sf_command (sndfile, "write text", text, strlen (text)) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>If the current file format allows the addition of text strings, the string will
+ be added and the length of the string will be returned.
+ <DD>If the file format does not allow the addition of text strings zero will be returned.
+ <DD>If this function is called after the file is openned but before
+</DL>
+-->
+
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_NORM_FLOAT"></A>
+<H2><BR><B>SFC_SET_NORM_FLOAT</B></H2>
+<P>
+This command only affects data read from or written to using the floating point functions:
+</P>
+<PRE>
+ size_t <A HREF="api.html#read">sf_read_float</A> (SNDFILE *sndfile, float *ptr, size_t items) ;
+ size_t <A HREF="api.html#readf">sf_readf_float</A> (SNDFILE *sndfile, float *ptr, size_t frames) ;
+
+ size_t <A HREF="api.html#write">sf_write_float</A> (SNDFILE *sndfile, float *ptr, size_t items) ;
+ size_t <A HREF="api.html#writef">sf_writef_float</A> (SNDFILE *sndfile, float *ptr, size_t frames) ;
+</PRE>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_SET_NORM_FLOAT
+ data : NULL
+ datasize : SF_TRUE or SF_FALSE
+</PRE>
+<P>
+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].
+</P>
+<P>
+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.
+</P>
+<P>
+For both cases, setting normalisation to SF_FALSE means that no scaling will take place.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ sf_command (sndfile, SFC_SET_NORM_FLOAT, NULL, SF_TRUE) ;
+
+ sf_command (sndfile, SFC_SET_NORM_FLOAT, NULL, SF_FALSE) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>Returns 1 on success or 0 for failure.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_NORM_DOUBLE"></A>
+<H2><BR><B>SFC_SET_NORM_DOUBLE</B></H2>
+<P>
+This command only affects data read from or written to using the double precision
+floating point functions:
+</P>
+<PRE>
+ size_t <A HREF="api.html#read">sf_read_double</A> (SNDFILE *sndfile, double *ptr, size_t items) ;
+ size_t <A HREF="api.html#readf">sf_readf_double</A> (SNDFILE *sndfile, double *ptr, size_t frames) ;
+
+ size_t <A HREF="api.html#write">sf_write_double</A> (SNDFILE *sndfile, double *ptr, size_t items) ;
+ size_t <A HREF="api.html#writef">sf_writef_double</A> (SNDFILE *sndfile, double *ptr, size_t frames) ;
+</PRE>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_SET_NORM_DOUBLE
+ data : NULL
+ datasize : SF_TRUE or SF_FALSE
+</PRE>
+<P>
+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].
+</P>
+<P>
+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.
+</P>
+<P>
+For both cases, setting normalisation to SF_FALSE means that no scaling will take place.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ sf_command (sndfile, SFC_SET_NORM_DOUBLE, NULL, SF_TRUE) ;
+
+ sf_command (sndfile, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>Returns 1 on success or 0 for failure.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_NORM_FLOAT"></A>
+<H2><BR><B>SFC_GET_NORM_FLOAT</B></H2>
+<P>
+Retrieve the current float normalisation mode.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_GET_NORM_FLOAT
+ data : NULL
+ datasize : anything
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ normalisation = sf_command (sndfile, SFC_GET_NORM_FLOAT, NULL, 0) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>Returns TRUE if normaisation is on and FALSE otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_NORM_DOUBLE"></A>
+<H2><BR><B>SFC_GET_NORM_DOUBLE</B></H2>
+<P>
+Retrieve the current float normalisation mode.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_GET_NORM_DOUBLE
+ data : NULL
+ datasize : anything
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ normalisation = sf_command (sndfile, SFC_GET_NORM_DOUBLE, NULL, 0) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>Returns TRUE if normalisation is on and FALSE otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_SIMPLE_FORMAT_COUNT"></A>
+<H2><BR><B>SFC_GET_SIMPLE_FORMAT_COUNT</B></H2>
+<P>
+Retrieve the number of simple formats supported by libsndfile.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_SIMPLE_FORMAT_COUNT
+ data : a pointer to an int
+ datasize : sizeof (int)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ int count ;
+ sf_command (sndfile, SFC_GET_SIMPLE_FORMAT_COUNT, &amp;count, sizeof (int)) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_SIMPLE_FORMAT"></A>
+<H2><BR><B>SFC_GET_SIMPLE_FORMAT</B></H2>
+<P>
+Retrieve information about a simple format.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_SIMPLE_FORMAT
+ data : a pointer to an SF_FORMAT_INFO struct
+ datasize : sizeof (SF_FORMAT_INFO)
+</PRE>
+<P>
+The SF_FORMAT_INFO struct is defined in &lt;sndfile.h&gt; as:
+</P>
+<PRE>
+ typedef struct
+ { int format ;
+ const char *name ;
+ const char *extension ;
+ } SF_FORMAT_INFO ;
+</PRE>
+<P>
+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).
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ SF_FORMAT_INFO format_info ;
+ int k, count ;
+
+ sf_command (sndfile, SFC_GET_SIMPLE_FORMAT_COUNT, &amp;count, sizeof (int)) ;
+
+ for (k = 0 ; k < count ; k++)
+ { format_info.format = k ;
+ sf_command (sndfile, SFC_GET_SIMPLE_FORMAT, &amp;format_info, sizeof (format_info)) ;
+ printf ("%08x %s %s\n", format_info.format, format_info.name, format_info.extension) ;
+ } ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0 on success and non-zero otherwise.
+ <DD>The value of the format field of the SF_FORMAT_INFO struct will be an value which
+ can be placed in the format field of an SF_INFO struct when a file is to be opened
+ for write.
+ <DD>The name field will contain a char* pointer to the name of the string ie "WAV (Microsoft 16 bit PCM)".
+ <DD>The extention field will contain the most commonly used file extension for that file type.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_FORMAT_INFO"></A>
+<H2><BR><B>SFC_GET_FORMAT_INFO</B></H2>
+<P>
+Retrieve information about a major or subtype format.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_FORMAT_INFO
+ data : a pointer to an SF_FORMAT_INFO struct
+ datasize : sizeof (SF_FORMAT_INFO)
+</PRE>
+<P>
+The SF_FORMAT_INFO struct is defined in &lt;sndfile.h&gt; as:
+</P>
+<PRE>
+ typedef struct
+ { int format ;
+ const char *name ;
+ const char *extension ;
+ } SF_FORMAT_INFO ;
+</PRE>
+<P>
+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.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ SF_FORMAT_INFO format_info ;
+
+ format_info.format = SF_FORMAT_WAV ;
+ sf_command (sndfile, SFC_GET_FORMAT_INFO, &amp;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, &amp;format_info, sizeof (format_info)) ;
+ printf ("%08x %s\n", format_info.format, format_info.name) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0 on success and non-zero otherwise.
+</DL>
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_FORMAT_MAJOR_COUNT"></A>
+<H2><BR><B>SFC_GET_FORMAT_MAJOR_COUNT</B></H2>
+<P>
+Retrieve the number of major formats.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_FORMAT_MAJOR_COUNT
+ data : a pointer to an int
+ datasize : sizeof (int)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ int count ;
+ sf_command (sndfile, SFC_GET_FORMAT_MAJOR_COUNT, &amp;count, sizeof (int)) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_FORMAT_MAJOR"></A>
+<H2><BR><B>SFC_GET_FORMAT_MAJOR</B></H2>
+<P>
+Retrieve information about a major format type.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_FORMAT_MAJOR
+ data : a pointer to an SF_FORMAT_INFO struct
+ datasize : sizeof (SF_FORMAT_INFO)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ SF_FORMAT_INFO format_info ;
+ int k, count ;
+
+ sf_command (sndfile, SFC_GET_FORMAT_MAJOR_COUNT, &amp;count, sizeof (int)) ;
+
+ for (k = 0 ; k < count ; k++)
+ { format_info.format = k ;
+ sf_command (sndfile, SFC_GET_FORMAT_MAJOR, &amp;format_info, sizeof (format_info)) ;
+ printf ("%08x %s %s\n", format_info.format, format_info.name, format_info.extension) ;
+ } ;
+</PRE>
+<P>
+For a more comprehensive example, see the program list_formats.c in the examples/
+directory of the libsndfile source code distribution.
+</P>
+<DL>
+<DT>Return value: </DT>
+ <DD>0 on success and non-zero otherwise.
+ <DD>The value of the format field will one of the major format identifiers suc as SF_FORMAT_WAV
+ SF_FORMAT_AIFF.
+ <DD>The name field will contain a char* pointer to the name of the string ie "WAV (Microsoft)".
+ <DD>The extention field will contain the most commonly used file extension for that file type.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_FORMAT_SUBTYPE_COUNT"></A>
+<H2><BR><B>SFC_GET_FORMAT_SUBTYPE_COUNT</B></H2>
+<P>
+Retrieve the number of subformats.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_FORMAT_SUBTYPE_COUNT
+ data : a pointer to an int
+ datasize : sizeof (int)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ int count ;
+ sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE_COUNT, &amp;count, sizeof (int)) ;
+</PRE>
+<DL>
+<DT>Return value: </DT>
+ <DD>0
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_GET_FORMAT_SUBTYPE"></A>
+<H2><BR><B>SFC_GET_FORMAT_SUBTYPE</B></H2>
+<P>
+Retrieve information about a subformat.
+</P>
+<P>
+Parameters:
+</P>
+<PRE>
+ sndfile : Not used.
+ cmd : SFC_GET_FORMAT_SUBTYPE
+ data : a pointer to an SF_FORMAT_INFO struct
+ datasize : sizeof (SF_FORMAT_INFO)
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ SF_FORMAT_INFO format_info ;
+ int k, count ;
+
+ sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE_COUNT, &amp;count, sizeof (int)) ;
+
+ /* Retrieve all the subtypes supported by the WAV format. */
+ for (k = 0 ; k < count ; k++)
+ { format_info.format = k ;
+ sf_command (sndfile, SFC_GET_FORMAT_SUBTYPE, &amp;format_info, sizeof (format_info)) ;
+ if (! sf_format_check (format.info | SF_FORMAT_WAV))
+ continue ;
+ printf ("%08x %s\n", format_info.format, format_info.name) ;
+ } ;
+</PRE>
+<P>
+For a more comprehensive example, see the program list_formats.c in the examples/
+directory of the libsndfile source code distribution.
+</P>
+<DL>
+<DT>Return value: </DT>
+ <DD>0 on success and non-zero otherwise.
+ <DD>The value of the format field will one of the major format identifiers such as SF_FORMAT_WAV
+ SF_FORMAT_AIFF.
+ <DD>The name field will contain a char* pointer to the name of the string; for instance
+ "WAV (Microsoft)" or "AIFF (Apple/SGI)".
+ <DD>The extention field will be a NULL pointer.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_ADD_PEAK_CHUNK"></A>
+<H2><BR><B>SFC_SET_ADD_PEAK_CHUNK</B></H2>
+<P>
+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.
+</P>
+<P>
+Note : This call must be made before any data is written to the file.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_SET_ADD_PEAK_CHUNK
+ data : Not used (should be NULL)
+ datasize : TRUE or FALSE.
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ /* 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) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+<DD>Returns SF_TRUE if the peak chunk will be written after this call.
+<DD>Returns SF_FALSE if the peak chunk will not be written after this call.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_UPDATE_HEADER_NOW"></A>
+<H2><BR><B>SFC_UPDATE_HEADER_NOW</B></H2>
+<P>
+The header of an audio file is normally written by libsndfile when the file is
+closed using <B>sf_close()</B>.
+</P>
+<P>
+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.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_UPDATE_HEADER_NOW
+ data : Not used (should be NULL)
+ datasize : Not used.
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ /* Update the header now. */
+ sf_command (sndfile, SFC_UPDATE_HEADER_NOW, NULL, 0) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+<DD>0
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_UPDATE_HEADER_AUTO"></A>
+<H2><BR><B>SFC_SET_UPDATE_HEADER_AUTO</B></H2>
+<P>
+Similar to SFC_UPDATE_HEADER_NOW but updates the header at the end of every call
+to the <B>sf_write*</B> functions.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_UPDATE_HEADER_NOW
+ data : Not used (should be NULL)
+ datasize : SF_TRUE or SF_FALSE
+</PRE>
+<P>
+Example:
+</P>
+<PRE>
+ /* 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) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+<DD>TRUE if auto update header is now on; FALSE otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_FILE_TRUNCATE"></A>
+<H2><BR><B>SFC_FILE_TRUNCATE</B></H2>
+<P>
+Truncate a file open for write or for read/write.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_FILE_TRUNCATE
+ data : A pointer to an sf_count_t.
+ datasize : sizeof (sf_count_t)
+</PRE>
+
+<P>
+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.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ /* Truncate the file to a length of 20 frames. */
+ sf_count_t frames = 20 ;
+ sf_command (sndfile, SFC_FILE_TRUNCATE, &amp;frames, sizeof (frames)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>Zero on sucess, non-zero otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+<A NAME="SFC_SET_RAW_START_OFFSET"></A>
+<H2><BR><B>SFC_SET_RAW_START_OFFSET</B></H2>
+<P>
+Change the data start offset for files opened up as SF_FORMAT_RAW.
+</P>
+<P>
+Parameters:
+<PRE>
+ sndfile : A valid SNDFILE* pointer
+ cmd : SFC_SET_RAW_START_OFFSET
+ data : A pointer to an sf_count_t.
+ datasize : sizeof (sf_count_t)
+</PRE>
+
+<P>
+For a file opened as format SF_FORMAT_RAW, set the data offset to the value
+given by data.
+</P>
+<P>
+Example:
+</P>
+<PRE>
+ /* 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, &amp;offset, sizeof (offset)) ;
+</PRE>
+<DL>
+<DT>Return value:</DT>
+ <DD>Zero on sucess, non-zero otherwise.
+</DL>
+
+<!-- ========================================================================= -->
+
+<HR>
+<P>
+ The libsndfile home page is here :
+ <A HREF="http://www.mega-nerd.com/libsndfile/">
+ http://www.mega-nerd.com/libsndfile/</A>.
+<BR>
+Version : 1.0.17
+</P>
+
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: e610e74b-9ac0-4255-aff8-97ed229a6a3d
+-->
diff --git a/doc/embedded_files.html b/doc/embedded_files.html
new file mode 100644
index 0000000..e9a84e8
--- /dev/null
+++ b/doc/embedded_files.html
@@ -0,0 +1,54 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ libsndfile : Embedded Sound Files.
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <META NAME="Description" CONTENT="The libsndfile API.">
+ <META NAME="Keywords" CONTENT="WAV AIFF AU libsndfile sound audio dsp Linux">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+<!-- pepper -->
+<BODY>
+<!-- pepper -->
+<H1><B>Embedded Sound Files.</B></H1>
+
+<P>
+By using the open SNDFILE with a file descriptor function:
+</P>
+<!-- pepper -->
+<PRE>
+ SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ;
+</PRE>
+<!-- pepper -->
+<P>
+it is possible to open sound files embedded within larger files.
+There are however a couple of caveats:
+<P>
+<!-- pepper -->
+<UL>
+ <LI> Read/Write mode (SFM_RDWR) is not supported.
+ <LI> Writing of embedded files is only supported at the end of the file.
+ <LI> Reading of embedded files is only supported at file offsets greater
+ than zero.
+ <LI> Not all file formats are supported (currently only WAV, AIFF and AU).
+</UL>
+<!-- pepper -->
+<P>
+The test program <B>multi_file_test.c</B> in the <B>tests/</B> directory of the
+source code tarball shows how this functionality is used to read and write
+embedded files.
+</P>
+<!-- pepper -->
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 25bcfcfc-231d-4c31-bded-e4184bcaa815
+-->
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 0000000..fce8c4f
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,476 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ libsndfile
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <META NAME="Version" CONTENT="libsndfile-1.0.17">
+ <META NAME="Description" CONTENT="The libsndfile Home Page">
+ <META NAME="Keywords" CONTENT="WAV AIFF AU SVX PAF NIST W64 libsndfile sound audio dsp Linux">
+ <META NAME="ROBOTS" CONTENT="NOFOLLOW">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+<!-- pepper -->
+<CENTER>
+ <IMG SRC="libsndfile.jpg" HEIGHT=98 WIDTH=367 ALT="libsndfile.jpg">
+</CENTER>
+<!-- pepper -->
+<CENTER>
+ <A HREF="#History">History</A> -+-
+ <A HREF="#Features">Features</A> -+-
+ <A HREF="#Similar">Similar or Related Projects</A> -+-
+ <A HREF="NEWS">News</A>
+ <BR>
+ <A HREF="development.html">Development</A> -+-
+ <A HREF="api.html">Programming Interface</A> -+-
+ <A HREF="bugs.html">Bug Reporting</A> -+-
+ <A HREF="#Download">Download</A>
+ <BR>
+ <A HREF="FAQ.html">FAQ</A> -+-
+ <A HREF="lists.html">Mailing Lists</A> -+-
+ <A HREF="ChangeLog">Change Log</A> -+-
+ <A HREF="#Licensing">Licensing Information</A>
+</CENTER>
+
+<BR><BR>
+<P>
+ 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
+ <A HREF="http://www.gnu.org/copyleft/lesser.html">Gnu Lesser General Public License</A>.
+</P>
+<!-- pepper -->
+<P>
+ The library was written to compile and run on a Linux system but should compile
+ and run on just about any Unix (including MacOSX).
+ It can also be compiled and run on Win32 systems using the Microsoft compiler and
+ MacOS (OS9 and earlier) using the Metrowerks compiler.
+ There are directions for compiling libsndfile on these platforms in the Win32 and
+ MacOS directories of the source code distribution.
+</P>
+<P>
+ 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.
+</P>
+<!-- pepper -->
+<P>
+ It has been compiled and tested (at one time or another) on the following systems:
+</P>
+<!-- pepper -->
+<UL>
+ <LI>i586-pc-linux-gnu (Linux on PC hardware)
+ <LI>powerpc-unknown-linux-gnu (Linux on Apple Mac hardware)
+ <LI>powerpc-apple-darwin7.0 (Mac OS X 10.3)
+ <LI>sparc-sun-solaris2.8 (using gcc)
+ <LI>mips-sgi-irix5.3 (using gcc)
+ <LI>QNX 6.0
+ <LI>i386-unknown-openbsd2.9
+ <BR>
+ <LI>Win32 (Microsoft Visual C++)
+</UL>
+<!-- pepper -->
+<P>
+ At the moment, each new release is being tested on i386 Linux, PowerPC Linux,
+ MacOSX on PowerPC and Win32.
+</P>
+<!-- pepper -->
+
+<A NAME="Capabilities"></A>
+<A NAME="Features"></A>
+<H1><B>Features</B></H1>
+<P>
+ libsndfile has the following main features :
+</P>
+ <UL>
+ <lI> Ability to read and write a large number of file formats.
+ <LI> A simple, elegant and easy to use Applications Programming Interface.
+ <LI> Usable on Unix, Win32, MacOS and others.
+ <LI> On the fly format conversion, including endian-ness swapping, type conversion
+ and bitwidth scaling.
+ <LI> Optional normalisation when reading floating point data from files containing
+ integer data.
+ <LI> Ability to open files in read/write mode.
+ <LI> The ability to write the file header without closing the file (only on files
+ open for write or read/write).
+ <LI> Ability to query the library about all supported formats and retrieve text
+ strings describing each format.
+ </UL>
+<P>
+ 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.
+ </P>
+<P>
+ 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.
+</P>
+<BR>
+
+<TABLE BORDER="1" cellpadding="2">
+ <TR><TD>&nbsp;</TD>
+ <TD ALIGN="center">Micro- soft<BR>WAV</TD>
+ <TD ALIGN="center">SGI / Apple<BR>AIFF / AIFC</TD>
+ <TD ALIGN="center">Sun / DEC /<BR>NeXT<BR>AU / SND</TD>
+ <TD ALIGN="center">Header- less<BR>RAW</TD>
+ <TD ALIGN="center">Paris Audio<BR>File<BR>PAF</TD>
+ <TD ALIGN="center">Commo- dore<BR>Amiga<BR>IFF / SVX</TD>
+ <TD ALIGN="center">Sphere<BR>Nist<BR>WAV</TD>
+ <TD ALIGN="center">IRCAM<BR>SF</TD>
+ <TD ALIGN="center">Creative<BR>VOC</TD>
+ <TD ALIGN="center">Sound forge<BR>W64</TD>
+ <TD ALIGN="center"><A HREF="octave.html">GNU Octave 2.0</A><BR>MAT4</TD>
+ <TD ALIGN="center"><A HREF="octave.html">GNU Octave 2.1</A><BR>MAT5</TD>
+ <TD ALIGN="center">Portable Voice Format<BR>PVF</TD>
+ <TD ALIGN="center">Fasttracker 2<BR>XI</TD>
+ <TD ALIGN="center">HMM Tool Kit<BR>HTK</TD>
+ <TD ALIGN="center">Apple<BR>CAF</TD>
+ <!-- TD ALIGN="center">Sound<BR>Designer II<BR>SD2</TD -->
+ </TR>
+<TR><TD>Unsigned 8 bit PCM</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD>
+ <TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+
+<TR><TD>Signed 8 bit PCM</TD>
+ <TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>R/W</TD>
+</TR>
+
+<TR><TD>Signed 16 bit PCM</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+</TR>
+
+<TR><TD>Signed 24 bit PCM</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD>
+</TR>
+
+<TR><TD>Signed 32 bit PCM</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD>
+</TR>
+
+<TR><TD>32 bit float</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD>
+</TR>
+
+<TR><TD>64 bit double</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD>
+</TR>
+
+<TR><TD>u-law encoding</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD ALIGN="center">R/W</TD>
+</TR>
+<TR><TD>A-law encoding</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD>
+ <TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD ALIGN="center">R/W</TD>
+</TR>
+
+<TR><TD>IMA ADPCM</TD>
+ <TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+
+<TR><TD>MS ADPCM</TD>
+ <TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+
+<TR><TD>GSM 6.10</TD>
+ <TD ALIGN="center">R/W</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+
+<TR><TD>G721 ADPCM 32kbps</TD>
+ <TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+
+<TR><TD>G723 ADPCM 24kbps</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+
+<TR><TD>G723 ADPCM 40kbps</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+
+<TR><TD>12 bit DWVW</TD>
+ <TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+
+<TR><TD>16 bit DWVW</TD>
+ <TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+
+<TR><TD>24 bit DWVW</TD>
+ <TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+<TR><TD>Ok Dialogic ADPCM</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+<TR><TD>8 bit DPCM</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+<TR><TD>16 bit DPCM</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+ <TD>&nbsp;</TD><TD ALIGN="center">R/W</TD><TD>&nbsp;</TD><TD>&nbsp;</TD>
+</TR>
+</TABLE>
+<!-- pepper -->
+
+<P>
+ Some of the file formats I am also interested in adding are:
+</P>
+ <UL>
+ <LI> Kurzweil K2000 sampler files.
+ <LI> Ogg Vorbis.
+ <LI> Ogg Speex.
+ <LI> FLAC.
+ </UL>
+<P>
+ I have decided that I will not be adding support for MPEG Layer 3 due to the
+ patent issues surrounding this file format.
+</P>
+<P>
+ Other file formats may also be added on request.
+</P>
+
+<!-- pepper -->
+
+<A NAME="History"></A>
+<H1><B>History</B></H1>
+<P>
+ 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
+ <A HREF="http://www.vaxxine.com/ve3wwg/gnuwave.html">wavplay</A>
+ 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.
+</P>
+<P>
+ Here is the release history for libsndfile :
+</P>
+ <UL>
+ <LI>Version 0.0.8 (Feb 15 1999) First official release.
+ <LI>Version 0.0.28 (Apr 26 2002) Final release of version 0 of libsndfile.
+ <LI>Version 1.0.0rc1 (Jun 24 2002) Release candidate 1 of version 1 of libsndfile.
+ <LI>Version 1.0.0rc6 (Aug 14 2002) MacOS 9 fixes.
+ <LI>Version 1.0.0 (Aug 16 2002) First 1.0.X release.
+ <LI>Version 1.0.1 (Sep 14 2002) Added MAT4 and MAT5 file formats.
+ <LI>Version 1.0.2 (Nov 24 2002) Added VOX ADPCM format.
+ <LI>Version 1.0.3 (Dec 09 2002) Fixes for Linux on ia64 CPUs.
+ <LI>Version 1.0.4 (Feb 02 2003) New file formats and functionality.
+ <LI>Version 1.0.5 (May 03 2003) One new file format and new functionality.
+ <LI>Version 1.0.6 (Feb 08 2004) Large file fix for Linux/Solaris, new functionality
+ and Win32 improvements.
+ <LI>Version 1.0.7 (Feb 24 2004) Fix build problems on MacOSX and fix ia64/MIPS etc
+ clip mode detction.
+ <LI>Version 1.0.8 (Mar 14 2004) Minor bug fixes.
+ <LI>Version 1.0.9 (Mar 30 2004) Add AVR format. Improve handling of some WAV files.
+ <LI>Version 1.0.10 (Jun 15 2004) Minor bug fixes. Fix support for Win32 MinGW compiler.
+ <LI>Version 1.0.11 (Nov 15 2004) Add SD2 file support, reading of loop data in WAV and AIFF.
+ Minor bug fixes.
+ <LI>Version 1.0.12 (Sep 30 2005) Add FLAC and CAF file support, virtual I/O interface.
+ Minor bug fixes and cleanups.
+ <LI>Version 1.0.13 (Jan 21 2006) Add read/write of instrument chunks. Minor bug fixes.
+ <LI>Version 1.0.14 (Feb 19 2006) Minor bug fixes. Start shipping windows binary/source ZIP.
+ <LI>Version 1.0.15 (Mar 16 2006) Minor bug fixes.
+ <LI>Version 1.0.16 (Apr 30 2006) Add support for RIFX. Other minor feature enhancements and
+ bug fixes.
+ <LI>Version 1.0.17 (Aug 31 2006) Add C++ wrapper sndfile.hh. Minor bug fixes and cleanups.
+ </UL>
+
+<A NAME="Similar"></A>
+<H1><B>Similar or Related Projects</B></H1>
+
+ <UL>
+ <LI><A HREF="http://home.sprynet.com/~cbagwell/sox.html">SoX</A> is a program for
+ converting between sound file formats.
+ <LI><A HREF="http://members.home.com/ve3wwg/gnuwave.html">Wavplay</A> 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.
+ <LI><A HREF="http://www.68k.org/~michael/audiofile/">Audiofile</A> (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.
+ <LI><A HREF="ftp://ccrma-ftp.stanford.edu/pub/Lisp/sndlib.tar.gz">sndlib.tar.gz</A> is
+ another library written by Bill Schottstaedt of CCRMA.
+ </UL>
+
+<A NAME="Licensing"></A>
+<H1><B>Licensing</B></H1>
+<P>
+ libsndfile is released under the terms of the GNU Lesser General Public License. You may
+ read the license
+ <A HREF="http://www.gnu.org/copyleft/lesser.html">here</A>
+ or read a simple explanation of the ideas behind the GPL and the LGPL
+ <A HREF="http://www.gnu.org/copyleft/copyleft.html">here</A>.
+</P>
+<P>
+ You can use libsndfile with
+ <A HREF="http://www.gnu.org/">Free Software</A>,
+ <A HREF="http://www.opensource.org/">Open Source</A>,
+ 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.
+</P>
+<P>
+ I would like to see libsndfile used as widely as possible but I would prefer it
+ if you released software that uses libsndfile as
+ <A HREF="http://www.gnu.org/">Free Software</A>
+ or
+ <A HREF="http://www.opensource.org/">Open Source</A>.
+ However, if you put in a great deal of effort building a huge 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 <A HREF="http://www.gnu.org/copyleft/lesser.html">the license</A>.
+</P>
+<A NAME="Download"></A>
+<P>
+ What I don't like to see is things like Steve Dekorte's
+ <A HREF="http://www.dekorte.com/Software/OSX/SoundConverter/">SoundConverter</A>
+ for Mac OSX.
+ Mr Dekorte has grabbed a number of Free Software packages and wrapped them in a
+ rather amateurish, buggy GUI and released the result as shareware.
+ He charges US$10 for the full version when his contribution to the whole is, by
+ his own
+ <A HREF="http://groups.google.com/groups?selm=3F9B8F8B.7853300B@mega-nerd.com">
+ admission</A>,
+ less than 10%.
+</P>
+
+<H1><B>Download</B></H1>
+<P>
+ Here is the latest version. It is available in the following formats (I am no longer
+ distributing RPMs).
+</P>
+ <UL>
+ <LI>Source code as a .tar.gz :
+ <A HREF="libsndfile-1.0.17.tar.gz">libsndfile-1.0.17.tar.gz</A>
+ and
+ <A HREF="libsndfile-1.0.17.tar.gz.asc">(GPG signature)</A>.
+ <LI>Windows .zip file including precompiled binaries and all source code :
+ <A HREF="libsndfile-1_0_17.zip">libsndfile-1_0_17.zip</A>
+ and
+ <A HREF="libsndfile-1_0_17.zip.asc">(GPG signature)</A>.
+ </UL>
+<P>
+ Compiling libsndfile is relatively easy. The INSTALL file in the top level directory
+ gives instructions on compiling and installing libsndfile on Unix-like systems
+ (including MacOSX). For Win32 there are instructions in the doc/ directory of the
+ tarball. These instructions are mirrored
+ <A HREF="win32.html">here</A>.
+</P>
+<P>
+ Pre-release versions of libsndfile are available
+ <A HREF="http://www.mega-nerd.com/tmp/">here</A>
+ and are announced on the
+ <A HREF="lists.html">libsndfile-devel</A>
+ mailing list.
+</P>
+<BR><BR>
+
+<HR>
+
+<P>
+ The latest version of this document can be found
+ <A HREF="http://www.mega-nerd.com/libsndfile/">here</A>.
+</P>
+<P>
+Author :
+ <A HREF="m&#97;ilt&#111;:&#101;rikd&#64;&#109;eg&#97;-&#110;erd.&#99;om">
+ Erik de Castro Lopo</a>
+</P>
+<!-- pepper -->
+<P>
+This page has been accessed
+ <IMG SRC=
+ "/cgi-bin/Count.cgi?ft=6|frgb=55;55;55|tr=0|trgb=0;0;0|wxh=15;20|md=6|dd=B|st=1|sh=1|df=libsndfile.dat"
+ HEIGHT=30 WIDTH=100 ALT="counter.gif">
+times.
+</P>
+<!-- pepper -->
+<!-- pepper -->
+<!-- pepper -->
+
+<BR><BR>
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: a96adffb-3017-46e2-82a0-6d77832b14d5
+-->
diff --git a/doc/libsndfile.css.in b/doc/libsndfile.css.in
new file mode 100644
index 0000000..027d2c7
--- /dev/null
+++ b/doc/libsndfile.css.in
@@ -0,0 +1,81 @@
+body {
+ background : @HTML_BGCOLOUR@ ;
+ color : @HTML_FGCOLOUR@ ;
+ font-family : arial, helvetica, sans-serif ;
+}
+td {
+ font-family : arial, helvetica, sans-serif ;
+ background : @HTML_BGCOLOUR@ ;
+ color : @HTML_FGCOLOUR@ ;
+}
+center {
+ font-family : arial, helvetica, sans-serif ;
+}
+p {
+ font-family : arial, helvetica, sans-serif ;
+ text-align : left ;
+ margin-left : 3% ;
+ margin-right : 3% ;
+}
+.indent_block {
+ font-family : arial, helvetica, sans-serif ;
+ text-align : left ;
+ margin-left : 10% ;
+ margin-right : 10% ;
+}
+br {
+ font-family : arial, helvetica, sans-serif ;
+}
+form {
+ font-family : arial, helvetica, sans-serif ;
+}
+ul {
+ font-family : arial, helvetica, sans-serif ;
+ text-align : left ;
+ margin-left : 3% ;
+ margin-right : 6% ;
+}
+ol {
+ font-family : arial, helvetica, sans-serif ;
+ text-align : left ;
+ margin-left : 3% ;
+ margin-right : 6% ;
+}
+dl {
+ font-family : arial, helvetica, sans-serif ;
+ text-align : left ;
+ margin-left : 3% ;
+ margin-right : 3% ;
+}
+h1 {
+ font-size : xx-large ;
+ background : @HTML_BGCOLOUR@ ;
+ color : #5050FF ;
+ text-align : left ;
+ margin-left : 3% ;
+ margin-right : 3% ;
+}
+h2 {
+ font-size : x-large ;
+ background : @HTML_BGCOLOUR@ ;
+ color : #5050FF ;
+ text-align : left ;
+ margin-left : 3% ;
+ margin-right : 3% ;
+}
+h3 {
+ font-size : large ;
+ background : @HTML_BGCOLOUR@ ;
+ color : #5050FF ;
+ text-align : left ;
+ margin-left : 3% ;
+ margin-right : 3% ;
+}
+pre {
+ font-family : courier, monospace ;
+ font-size : medium ;
+}
+a:link { color : #9090FF ; }
+a:visited { color : #5050FF ; }
+a:active { color : #FF00FF ; }
+a:hover { background-color : #202080 ; }
diff --git a/doc/libsndfile.jpg b/doc/libsndfile.jpg
new file mode 100644
index 0000000..7855b92
--- /dev/null
+++ b/doc/libsndfile.jpg
Binary files differ
diff --git a/doc/linux_games_programming.txt b/doc/linux_games_programming.txt
new file mode 100644
index 0000000..576f86b
--- /dev/null
+++ b/doc/linux_games_programming.txt
@@ -0,0 +1,440 @@
+# Here are some some emails I exchanged with a guy trying to use
+# libsndfile version 1 with code from the book "Linux Games Programming"
+# by John Hall. The email addresses have been changed to foil the spam
+# bots.
+
+Date: Tue, 20 Jul 2004 22:49:21 +0100
+From: Paul <paul@fake-domain-name.co.uk>
+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 <erikd@fake-domain-name.com>
+To: Paul <paul@fake-domain-name.co.uk>
+Subject: Re: Can you help with a problem?
+
+On Tue, 20 Jul 2004 22:49:21 +0100
+Paul <paul@fake-domain-name.co.uk> 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 <paul@fake-domain-name.co.uk>
+To: Erik de Castro Lopo <erikd@fake-domain-name.com>
+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 <erikd@fake-domain-name.com>
+To: PFJ <paul@fake-domain-name.co.uk>
+Subject: Re: Can you help with a problem?
+
+On Wed, 21 Jul 2004 09:07:39 +0100
+PFJ <paul@fake-domain-name.co.uk> 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. Thats 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 <paul@fake-domain-name.co.uk>
+To: Erik de Castro Lopo <erikd@fake-domain-name.com>
+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;
+ }
+
+<minor snip>
+
+ /* 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 <erikd@fake-domain-name.com>
+To: PFJ <paul@fake-domain-name.co.uk>
+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 <paul@fake-domain-name.co.uk> 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...
+
+
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: 78d64eac-20f0-4d71-a4e2-3e1b8821596f
diff --git a/doc/lists.html b/doc/lists.html
new file mode 100644
index 0000000..73e318f
--- /dev/null
+++ b/doc/lists.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ libsndfile Mailing Lists
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+<!-- pepper -->
+<H1><BR>libsndfile Mailing Lists</H1>
+<!-- pepper -->
+<P>
+There are three mailing lists for libsndfile:
+</P>
+<!-- pepper -->
+<UL>
+ <LI> <B>libsndfile-announce&#64;mega-nerd.com</B>&nbsp;&nbsp;<!-- pepper -->
+ <A HREF="m&#97;ilt&#111;:li&#98;sndfile-announce-request@meg&#97;-nerd.&#99;om?subject=subscribe">Subscribe</A>
+ <BR>
+ A list which will announce each new release of libsndfile.
+ Noone can post to this list except the author.
+ <BR><BR>
+
+ <LI> <B>libsndfile-devel&#64;mega-nerd.com</B>&nbsp;&nbsp;<!-- pepper -->
+ <A HREF="m&#97;ilt&#111;:li&#98;sndfile-devel-request@meg&#97;-nerd.&#99;om?subject=subscribe">Subscribe</A>
+ <BR>
+ A list for discussing bugs, porting issues and feature requests.
+ Posting is restricted to subscribers.
+ <BR><BR>
+
+ <LI> <B>libsndfile-users&#64;mega-nerd.com</B>&nbsp;&nbsp;<!-- pepper -->
+ <A HREF="m&#97;ilt&#111;:li&#98;sndfile-users-request@meg&#97;-nerd.&#99;om?subject=subscribe">Subscribe</A>
+ <BR>
+ A list for discussing the use of libsndfile in other programs.
+ Posting is restricted to subscribers.
+ <!-- pepper -->
+ <BR><BR>
+</UL>
+<!-- pepper -->
+<P>
+The libsndfile-devel and libsndfile-users list will automatically receive a
+copy of all emails to the libsndfile-announce list.
+</P>
+<BR>
+<!-- pepper -->
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 71a13776-1e29-47ae-8eee-e376e73dc4db
+-->
diff --git a/doc/new_file_type.HOWTO b/doc/new_file_type.HOWTO
new file mode 100644
index 0000000..a6da80a
--- /dev/null
+++ b/doc/new_file_type.HOWTO
@@ -0,0 +1,135 @@
+new_file_type.HOWTO
+===================
+
+ 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: ftp://ftp.gnu.org/pub/gnu/.
+
+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.in 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 ;
+
+Setp 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/doc/octave.html b/doc/octave.html
new file mode 100644
index 0000000..afe013f
--- /dev/null
+++ b/doc/octave.html
@@ -0,0 +1,125 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ libsndfile and GNU Octave
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+
+<BR>
+<H1><B>libsndfile and GNU Octave</B></H1>
+<P>
+ <A HREF="http://www.octave.org/">GNU Octave</A> 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
+ <A HREF="http://www.mathworks.com/">MATLAB</A>.
+ 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.
+</P>
+<P>
+ 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.
+</P>
+<P>
+ For instance it is now possible to do the following:
+</P>
+
+ <UL>
+ <LI> Load a WAV file into a sound file editor such as
+ <A HREF="http://www.metadecks.org/software/sweep/">Sweep</A>.
+ <LI> Save it as a MAT4 file.
+ <LI> Load the data into Octave for manipulation.
+ <LI> Save the modified data.
+ <LI> Reload it in Sweep.
+ </UL>
+<P>
+ 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.
+</P>
+
+<H2><B>Details</B></H2>
+<P>
+ 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.
+</P>
+<P>
+ For example, to generate a sine wave and store it as a binary file which
+ is compatible with libsndfile, do the following:
+</P>
+<PRE>
+ octave:1 > samplerate = 44100 ;
+ octave:2 > wavedata = sin ((0:1023)*2*pi/1024) ;
+ octave:3 > save sine.mat samplerate wavedata
+</PRE>
+
+<P>
+ The process of reading and writing files compatible with libsndfile can be
+ made easier by use of two Octave script files :
+</P>
+<PRE>
+ octave:4 > [data fs] = sndfile_load ("sine.mat") ;
+ octave:5 > sndfile_save ("sine2.mat", data, fs) ;
+</PRE>
+<P>
+ 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 <B>sndfile-play</B> and a third Octave script
+ file allows Octave data to be played from within Octave on any of the platforms
+ which <B>sndfile-play</B> supports (at the moment: Linux, MacOSX, Solaris and
+ Win32).
+</P>
+<PRE>
+ octave:6 > sndfile_play (data, fs) ;
+</PRE>
+<P>
+ 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/.
+</P>
+
+<P>
+ There are some other Octave scripts for audio to be found
+ <A HREF="http://octave.sourceforge.net/index/audio.html">here</A>.
+</P>
+
+<BR>
+<!-- ========================================================================= -->
+
+<HR>
+<P>
+ The libsndfile home page is here :
+ <A HREF="http://www.mega-nerd.com/libsndfile/">
+ http://www.mega-nerd.com/libsndfile/</A>.
+</P>
+
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 6e99f38b-e2ad-4fdd-bc0f-94bf0c66d243
+-->
diff --git a/doc/pkgconfig.html b/doc/pkgconfig.html
new file mode 100644
index 0000000..40d15c3
--- /dev/null
+++ b/doc/pkgconfig.html
@@ -0,0 +1,78 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ libsndfile : pkg-config
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+
+<BR>
+<H1>libsndfile and pkg-config</H1>
+
+<P>
+ From version 1.0.0 libsndfile has had the ability to read and write files of
+ greater than 2 Gig in size on most OSes even if sizeof (long) == 4.
+ OSes which support this feature include Linux (2.4 kernel, glibc6) on x86, PPC and
+ probably others, Win32, MacOSX, *BSD, Solaris and probably others.
+ OSes on 64 bit processors where the default compile environment is LP64 (longs and
+ pointers are 64 bit ie Linux on DEC/Compaq/HP Alpha processors) automatically
+ support large file access.
+</P>
+<P>
+ Other OSes including Linux on 32 bit processors, 32 bit Solaris and others require
+ special compiler flags to add large file support.
+ This applies to both the compilation of the library itself and the compilation of
+ programs which link to the library.
+</P>
+<P>
+ Note : People using Win32, MacOS (both OSX and pre-OSX) or *BSD can disregard the
+ rest of this document as it does not apply to either of these OSes.
+</P>
+<P>
+ The <B>pkg-config</B> program makes finding the correct compiler flag values and
+ library location far easier.
+ During the installation of libsndfile, a file named <B>sndfile.pc</B> is installed
+ in the directory <B>${libdir}/pkgconfig</B> (ie if libsndfile is installed in
+ <B>/usr/local/lib</B>, <B>sndfile.pc</B> will be installed in
+ <B>/usr/local/lib/pkgconfig/</B>).
+</P>
+<P>
+ In order for pkg-config to find sndfile.pc it may be necessary to point the
+ environment variable <B>PKG_CONFIG_PATH</B> in the right direction.
+</P>
+ <PRE>
+ export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
+ </PRE>
+
+<P>
+ Then, to compile a C file into an object file, the command would be:
+</P>
+ <PRE>
+ gcc `pkg-config --cflags sndfile` -c somefile.c
+ </PRE>
+<P>
+ and to link a number of objects into an executable that links against libsndfile,
+ the command would be:
+</P>
+ <PRE>
+ gcc `pkg-config --libs sndfile` obj1.o obj2.o -o program
+ </PRE>
+
+<P>
+ Obviously all this can be rolled into a Makefile for easier maintenance.
+</P>
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 3c1ed1be-9875-47f9-90f3-015da975d622
+-->
diff --git a/doc/sndfile_info.html b/doc/sndfile_info.html
new file mode 100644
index 0000000..2ac0e5f
--- /dev/null
+++ b/doc/sndfile_info.html
@@ -0,0 +1,60 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ sndfile-info
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+
+<P>
+ Here is an example of the output from the <B>sndfile-info</B> program distributed with
+ libsndfile.
+</P>
+
+<P>
+ This file was opened and parsed correctly but had been truncated so that the values
+ in the <B>FORM</B> and <B>SSND</B> chunks were incorrect.
+</P>
+<PRE>
+ <B>erikd@hendrix ></B> 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
+
+</PRE>
+
+
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: a7ae18b0-bf27-4c50-b8b2-e209d0cd36c5
+-->
diff --git a/doc/win32.html b/doc/win32.html
new file mode 100644
index 0000000..4222d1f
--- /dev/null
+++ b/doc/win32.html
@@ -0,0 +1,141 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+
+<HEAD>
+ <TITLE>
+ Building libsndfile on Win32
+ </TITLE>
+ <META NAME="Author" CONTENT="Erik de Castro Lopo (erikd AT mega-nerd DOT com)">
+ <LINK REL=StyleSheet HREF="libsndfile.css" TYPE="text/css" MEDIA="all">
+</HEAD>
+
+<BODY>
+<!-- pepper -->
+<H1><BR>Building libsndfile on Win32</H1>
+
+<P><B>
+Note : For pre-compiled binaries for windows, see the main web page.
+</B></P>
+
+<P>
+There are currently two ways of building libsndfile under Win32:
+</P>
+<UL>
+ <LI> Using the free <A HREF="#MinGW">MinGW</A> tools.
+ <LI> Using Cygwin (this is the full Cygwin without the -mno-cygwin option).
+</UL>
+
+<P><B>
+Building libsndfile using the microsoft compiler does not currently work.
+Microsoft's compiler is a C++ compiler and does not compile a number of ISO
+C99 Standard constructs.
+If you insist on compiling libsndfile with the microsoft compiler you are
+on your own.
+</B></P>
+<P><B>
+However, even though the libsndfile source code cannot be compiled with
+the microsoft compiler, the pre-compiled windows DLL distributed on the
+main web page can be used with C++ projects compiled with the microsoft
+compiler.
+</B></P>
+
+<P>
+The free MinGW tools are the preferred option because they are a free (as in
+beer and speech), easily obtainable and much closer to the Linux/GCC
+environment on which libsndfile is developed.
+</P>
+
+<A NAME="MinGW"></A>
+<H2><BR>Building libsndfile using MinGW.</H2>
+<P>
+The MinGW tools are available from <A HREF="http://www.mingw.org/">
+http://www.mingw.org/</A>.
+The files you will need will be named something like:
+</P>
+<UL>
+ <LI> msysDTK-1.0.1.exe
+ <LI> MSYS-1.0.10.exe
+ <LI> gcc-core-3.4.2-20040916-1.tar.gz
+ <LI> gcc-g++-3.4.2-20040916-1.tar.gz
+ <LI> binutils-2.15.91-20040901-1.tar.gz
+ <LI> mingw-runtime-3.9.tar.gz
+ <LI> w32api-3.6.tar.gz
+ <LI> mingw-utils-0.3.tar.gz
+</UL>
+
+<P>
+They should be installed using the directions on the MinGW site.
+I know the instructions aren't great, but I don't have the time or expertise
+to write better ones.
+</P>
+
+<P>
+Once you have the tools installed you will get an icon named <B>MSYS</B> on
+your desktop.
+Clicking on that icon will bring up something that looks a little like an
+xterm.
+</P>
+
+<P>
+Assuming that you have downloaded the <B>.tar.gz</B> file into the
+<B>C:\temp\</B> directory you should now be able to execute the following
+commands:
+</P>
+
+<PRE>
+ tar zxf /c/temp/libsndfile.X.Y.Z.tar.gz
+ cd libsndfile-X.Y.Z
+ ./configure
+ make
+ make check
+</PRE>
+
+<P>
+If there is a failure during compiling or the "make check" stage, you should
+check that you are using the current stable version of the MinGW tools, and
+the latest version of libsndfile before sending the author a bug report.
+</P>
+
+<P>
+Once this is done, anyone interested in using libsndfile in other projects
+will be interested in the following files:
+</P>
+<UL>
+ <LI> libsndfile.dll
+ <LI> libsndfile.lib
+ <LI> libsndfile.def
+ <LI> src/sndfile.h
+ <LI> doc/*.html
+</UL>
+
+<!--===========================================================================-->
+
+<!-- pepper -->
+<H2><BR>Compile Problems</H2>
+<!-- pepper -->
+<P>
+Compile problems using the above method of building the libsndfile DLL on Win32 should
+be emailed to
+ <A HREF="m&#97;ilt&#111;:&#101;rikd&#64;&#109;eg&#97;-&#110;erd.&#99;om">
+ Erik de Castro Lopo</a>.
+</P>
+<!-- pepper -->
+<P>
+If you are using some other method to compile the libsndfile DLL you are on your own.
+</P>
+<BR>
+<!-- pepper -->
+<!-- pepper -->
+<!-- pepper -->
+<!-- pepper -->
+
+</BODY>
+</HTML>
+
+<!--
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: b32ddb11-eb51-425f-9d39-b8b66284f129
+-->
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..94b170c
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,46 @@
+## Process this file with automake to produce Makefile.in
+
+bin_PROGRAMS = sndfile-info sndfile-play sndfile-convert
+
+noinst_PROGRAMS = sndfile-data-trim make_sine sfprocess list_formats generate
+
+# This is the BeOS version of sndfile-play. It needs to be compiled with the C++
+# compiler.
+EXTRA_DIST = sndfile-play-beos.cpp
+
+OS_SPECIFIC_CFLAGS = @OS_SPECIFIC_CFLAGS@
+OS_SPECIFIC_LINKS = @OS_SPECIFIC_LINKS@
+
+SNDFILEDIR =../src
+INCLUDES = -I$(srcdir)/$(SNDFILEDIR) $(OS_SPECIFIC_CFLAGS)
+
+sndfile_info_SOURCES = sndfile-info.c
+sndfile_info_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+sndfile_play_SOURCES = sndfile-play.c
+sndfile_play_LDADD = $(SNDFILEDIR)/libsndfile.la $(OS_SPECIFIC_LINKS) $(ALSA_LIBS)
+
+sndfile_convert_SOURCES = sndfile-convert.c
+sndfile_convert_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+sndfile_data_trim_SOURCES = sndfile-data-trim.c
+sndfile_data_trim_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+make_sine_SOURCES = make_sine.c
+make_sine_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+sfprocess_SOURCES = sfprocess.c
+sfprocess_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+list_formats_SOURCES = list_formats.c
+list_formats_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+generate_SOURCES = generate.c
+generate_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+## Do not edit or modify anything in this comment block.
+## The arch-tag line is a file identity tag for the GNU Arch
+## revision control system.
+##
+## arch-tag: faeb8674-e417-4162-9ac9-05f2b8369b57
+
diff --git a/examples/generate.c b/examples/generate.c
new file mode 100644
index 0000000..1b0eec7
--- /dev/null
+++ b/examples/generate.c
@@ -0,0 +1,125 @@
+/*
+** Copyright (C) 2002-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <sndfile.h>
+
+#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 <filename>\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) ;
+
+ 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 = sf_read_float (infile, buffer, BUFFER_LEN)) > 0)
+ sf_write_float (outfile, buffer, BUFFER_LEN) ;
+
+ sf_close (infile) ;
+ sf_close (outfile) ;
+
+ printf ("ok\n") ;
+
+ return ;
+} /* encode_file */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: fe28ef37-ae89-4f61-966b-0b1f68e37425
+*/
diff --git a/examples/generate.cs b/examples/generate.cs
new file mode 100644
index 0000000..9262e5b
--- /dev/null
+++ b/examples/generate.cs
@@ -0,0 +1,255 @@
+/* (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 {}
+
+// Do not edit or modify anything in this comment block.
+// The arch-tag line is a file identity tag for the GNU Arch
+// revision control system.
+//
+// arch-tag: 61a46c48-431c-4a16-97a3-b5485ca0e157
diff --git a/examples/list_formats.c b/examples/list_formats.c
new file mode 100644
index 0000000..0b6db49
--- /dev/null
+++ b/examples/list_formats.c
@@ -0,0 +1,76 @@
+/*
+** Copyright (C) 2001-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <sndfile.h>
+
+int
+main (void)
+{ SF_FORMAT_INFO info ;
+ SF_INFO sfinfo ;
+ char buffer [128] ;
+ int format, major_count, subtype_count, m, s ;
+
+ memset (&sfinfo, 0, sizeof (sfinfo)) ;
+ 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) ;
+ } ;
+ printf ("Version : %s\n\n", buffer) ;
+
+ 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 58127a0c-93a2-46cf-b615-fcb9adacf3f1
+*/
diff --git a/examples/make_sine.c b/examples/make_sine.c
new file mode 100644
index 0000000..3a50c26
--- /dev/null
+++ b/examples/make_sine.c
@@ -0,0 +1,89 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include <sndfile.h>
+
+#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 ("Malloc failed.\n") ;
+ exit (0) ;
+ } ;
+
+ 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") ;
+ return 1 ;
+ } ;
+
+ if (sfinfo.channels == 1)
+ { for (k = 0 ; k < SAMPLE_COUNT ; k++)
+ buffer [k] = AMPLITUDE * sin (LEFT_FREQ * 2 * k * M_PI) ;
+ }
+ else if (sfinfo.channels == 2)
+ { for (k = 0 ; k < SAMPLE_COUNT ; k++)
+ { buffer [2 * k] = AMPLITUDE * sin (LEFT_FREQ * 2 * k * M_PI) ;
+ buffer [2 * k + 1] = AMPLITUDE * sin (RIGHT_FREQ * 2 * k * M_PI) ;
+ } ;
+ }
+ else
+ { printf ("makesine can only generate mono or stereo files.\n") ;
+ exit (1) ;
+ } ;
+
+ if (sf_write_int (file, buffer, sfinfo.channels * SAMPLE_COUNT) !=
+ sfinfo.channels * SAMPLE_COUNT)
+ puts (sf_strerror (file)) ;
+
+ sf_close (file) ;
+ return 0 ;
+} /* main */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: fd945a2c-a306-49ef-a262-6336ced15246
+*/
diff --git a/examples/paf_write.c b/examples/paf_write.c
new file mode 100644
index 0000000..394b2a3
--- /dev/null
+++ b/examples/paf_write.c
@@ -0,0 +1,88 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include <sndfile.h>
+
+#define SAMPLE_RATE 8000
+#define SAMPLE_COUNT 100
+
+int
+main (void)
+{ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ char *filename ;
+ int k, buffer [SAMPLE_COUNT] ;
+
+ for (k = 0 ; k < SAMPLE_COUNT ; k++)
+ buffer [k] = ((3 * k + 2) << 24) + ((3 * k + 1) << 16) + ((3 * k) << 8) ;
+
+ /* Big endian first. */
+ sfinfo.samplerate = SAMPLE_RATE ;
+ sfinfo.frames = SAMPLE_COUNT ;
+ sfinfo.channels = 1 ;
+ sfinfo.format = (SF_ENDIAN_BIG | SF_FORMAT_PAF | SF_FORMAT_PCM_24) ;
+
+ filename = "be-pcm24.paf" ;
+
+ if (! (file = sf_open (filename, SFM_WRITE, &sfinfo)))
+ { printf ("Error : Not able to open output file.\n") ;
+ return 1 ;
+ } ;
+
+ printf ("Writing data to '%s'\n", filename) ;
+
+ if (sf_write_int (file, buffer, SAMPLE_COUNT) != SAMPLE_COUNT)
+ puts (sf_strerror (file)) ;
+
+ sf_close (file) ;
+
+ /* Little endian first. */
+ sfinfo.samplerate = SAMPLE_RATE ;
+ sfinfo.frames = SAMPLE_COUNT ;
+ sfinfo.channels = 1 ;
+ sfinfo.format = (SF_ENDIAN_LITTLE | SF_FORMAT_PAF | SF_FORMAT_PCM_24) ;
+
+ filename = "le-pcm24.paf" ;
+
+ if (! (file = sf_open (filename, SFM_WRITE, &sfinfo)))
+ { printf ("Error : Not able to open output file.\n") ;
+ return 1 ;
+ } ;
+
+ printf ("Writing data to '%s'\n", filename) ;
+
+ if (sf_write_int (file, buffer, SAMPLE_COUNT) != SAMPLE_COUNT)
+ puts (sf_strerror (file)) ;
+
+ sf_close (file) ;
+
+ return 0 ;
+} /* main */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 62025b88-1f3f-46fb-994a-8220bf915772
+*/
diff --git a/examples/sfprocess.c b/examples/sfprocess.c
new file mode 100644
index 0000000..e48fcfb
--- /dev/null
+++ b/examples/sfprocess.c
@@ -0,0 +1,131 @@
+/*
+** Copyright (C) 2001-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include <stdio.h>
+
+/* Include this header file to use functions from libsndfile. */
+#include <sndfile.h>
+
+/* 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 stutct 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" ;
+
+ /* 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) ;
+ 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)) ;
+ return 1 ;
+ } ;
+
+ /* While there are.frames in the input file, read them, process
+ ** them and write them to the output file.
+ */
+ while ((readcount = 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 */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: de9fdd1e-b807-41ef-9d51-075ba383e536
+*/
diff --git a/examples/sndfile-convert.c b/examples/sndfile-convert.c
new file mode 100644
index 0000000..7072382
--- /dev/null
+++ b/examples/sndfile-convert.c
@@ -0,0 +1,395 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sndfile.h>
+
+#define BUFFER_LEN 1024
+
+
+typedef struct
+{ char *infilename, *outfilename ;
+ SF_INFO infileinfo, outfileinfo ;
+} OptionData ;
+
+typedef struct
+{ const char *ext ;
+ int len ;
+ int format ;
+} OUTPUT_FORMAT_MAP ;
+
+static void copy_metadata (SNDFILE *outfile, SNDFILE *infile) ;
+static void copy_data_fp (SNDFILE *outfile, SNDFILE *infile, int channels) ;
+static void copy_data_int (SNDFILE *outfile, SNDFILE *infile, int channels) ;
+
+static OUTPUT_FORMAT_MAP format_map [] =
+{
+ { "aif", 3, SF_FORMAT_AIFF },
+ { "wav", 0, SF_FORMAT_WAV },
+ { "au", 0, SF_FORMAT_AU },
+ { "caf", 0, SF_FORMAT_CAF },
+ { "flac", 0, SF_FORMAT_FLAC },
+ { "snd", 0, SF_FORMAT_AU },
+ { "svx", 0, SF_FORMAT_SVX },
+ { "paf", 0, SF_ENDIAN_BIG | SF_FORMAT_PAF },
+ { "fap", 0, SF_ENDIAN_LITTLE | SF_FORMAT_PAF },
+ { "gsm", 0, SF_FORMAT_RAW },
+ { "nist", 0, SF_FORMAT_NIST },
+ { "ircam", 0, SF_FORMAT_IRCAM },
+ { "sf", 0, SF_FORMAT_IRCAM },
+ { "voc", 0, SF_FORMAT_VOC },
+ { "w64", 0, SF_FORMAT_W64 },
+ { "raw", 0, SF_FORMAT_RAW },
+ { "mat4", 0, SF_FORMAT_MAT4 },
+ { "mat5", 0, SF_FORMAT_MAT5 },
+ { "mat", 0, SF_FORMAT_MAT4 },
+ { "pvf", 0, SF_FORMAT_PVF },
+ { "sds", 0, SF_FORMAT_SDS },
+ { "sd2", 0, SF_FORMAT_SD2 },
+ { "vox", 0, SF_FORMAT_RAW },
+ { "xi", 0, SF_FORMAT_XI },
+ { "wve", 0, SF_FORMAT_WVE }
+} ; /* format_map */
+
+static int
+guess_output_file_type (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])) ;
+
+ if (strcmp (buffer, "gsm") == 0)
+ return SF_FORMAT_RAW | SF_FORMAT_GSM610 ;
+
+ if (strcmp (buffer, "vox") == 0)
+ return SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM ;
+
+ 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)
+ return format_map [k].format | format ;
+ else if (strcmp (buffer, format_map [k].ext) == 0)
+ return format_map [k].format | format ;
+ } ;
+
+ return 0 ;
+} /* guess_output_file_type */
+
+
+static void
+print_usage (char *progname)
+{ SF_FORMAT_INFO info ;
+
+ int k ;
+
+ printf ("\nUsage : %s [options] [encoding] <input file> <output file>\n", progname) ;
+ puts ("\n"
+ " where [option] may be:\n\n"
+ " -override-sample-rate=X : force sample rate of input to X\n\n"
+ ) ;
+
+ puts ("\n"
+ " where [encoding] may be one of the following:\n\n"
+ " -pcms8 : force the output to signed 8 bit pcm\n"
+ " -pcmu8 : force the output to unsigned 8 bit pcm\n"
+ " -pcm16 : force the output to 16 bit pcm\n"
+ " -pcm24 : force the output to 24 bit pcm\n"
+ " -pcm32 : force the output to 32 bit pcm\n"
+ " -float32 : force the output to 32 bit floating point"
+ ) ;
+ puts (
+ " -ulaw : force the output ULAW\n"
+ " -alaw : force the output ALAW\n"
+ " -ima-adpcm : force the output to IMA ADPCM (WAV only)\n"
+ " -ms-adpcm : force the output to MS ADPCM (WAV only)\n"
+ " -gsm610 : force the GSM6.10 (WAV only)\n"
+ " -dwvw12 : force the output to 12 bit DWVW (AIFF only)\n"
+ " -dwvw16 : force the output to 16 bit DWVW (AIFF only)\n"
+ " -dwvw24 : force the output to 24 bit DWVW (AIFF only)\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"
+ ) ;
+
+ for (k = 0 ; k < (int) (sizeof (format_map) / sizeof (format_map [0])) ; k++)
+ { info.format = format_map [k].format ;
+ sf_command (NULL, SFC_GET_FORMAT_INFO, &info, sizeof (info)) ;
+ printf (" %-10s : %s\n", format_map [k].ext, info.name) ;
+ } ;
+
+ puts ("") ;
+} /* print_usage */
+
+int
+main (int argc, char * argv [])
+{ 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. */
+
+ progname = strrchr (argv [0], '/') ;
+ progname = progname ? progname + 1 : argv [0] ;
+
+ if (argc < 3 || argc > 5)
+ { print_usage (progname) ;
+ return 1 ;
+ } ;
+
+ infilename = argv [argc-2] ;
+ outfilename = argv [argc-1] ;
+
+ if (strcmp (infilename, outfilename) == 0)
+ { printf ("Error : Input and output filenames are the same.\n\n") ;
+ print_usage (progname) ;
+ return 1 ;
+ } ;
+
+ if (infilename [0] == '-')
+ { printf ("Error : Input filename (%s) looks like an option.\n\n", infilename) ;
+ print_usage (progname) ;
+ return 1 ;
+ } ;
+
+ if (outfilename [0] == '-')
+ { printf ("Error : Output filename (%s) looks like an option.\n\n", outfilename) ;
+ print_usage (progname) ;
+ return 1 ;
+ } ;
+
+ 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], "-ulaw"))
+ { outfileminor = SF_FORMAT_ULAW ;
+ continue ;
+ } ;
+ if (! strcmp (argv [k], "-alaw"))
+ { outfileminor = SF_FORMAT_ALAW ;
+ 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], "-override-sample-rate="))
+ { char *ptr ;
+
+ ptr = argv [k] + strlen ("-override-sample-rate=") ;
+ override_sample_rate = atoi (ptr) ;
+ continue ;
+ } ;
+
+ printf ("Error : Not able to decode argunment '%s'.\n", argv [k]) ;
+ exit (1) ;
+ } ;
+
+ 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 = guess_output_file_type (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) ;
+
+ 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)
+ { printf ("Error : output file format is invalid (0x%08X).\n", sfinfo.format) ;
+ return 1 ;
+ } ;
+
+ /* 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) ;
+
+ if ((outfileminor == SF_FORMAT_DOUBLE) || (outfileminor == SF_FORMAT_FLOAT) ||
+ (infileminor == SF_FORMAT_DOUBLE) || (infileminor == SF_FORMAT_FLOAT))
+ copy_data_fp (outfile, infile, sfinfo.channels) ;
+ else
+ copy_data_int (outfile, infile, sfinfo.channels) ;
+
+ sf_close (infile) ;
+ sf_close (outfile) ;
+
+ return 0 ;
+} /* main */
+
+static void
+copy_metadata (SNDFILE *outfile, SNDFILE *infile)
+{ SF_INSTRUMENT inst ;
+ const char *str ;
+ int k, err = 0 ;
+
+ for (k = SF_STR_FIRST ; k <= SF_STR_LAST ; k++)
+ { str = sf_get_string (infile, k) ;
+ if (str != NULL)
+ err = sf_set_string (outfile, k, str) ;
+ } ;
+
+ memset (&inst, 0, sizeof (inst)) ;
+ if (sf_command (infile, SFC_GET_INSTRUMENT, &inst, sizeof (inst)) == SF_TRUE)
+ sf_command (outfile, SFC_SET_INSTRUMENT, &inst, sizeof (inst)) ;
+
+} /* copy_metadata */
+
+static void
+copy_data_fp (SNDFILE *outfile, SNDFILE *infile, int channels)
+{ static double data [BUFFER_LEN], max ;
+ int frames, readcount, k ;
+
+ frames = BUFFER_LEN / channels ;
+ readcount = frames ;
+
+ sf_command (infile, SFC_CALC_SIGNAL_MAX, &max, sizeof (max)) ;
+
+ if (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 ;
+ sf_writef_double (outfile, data, readcount) ;
+ } ;
+ } ;
+
+ return ;
+} /* copy_data_fp */
+
+static void
+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 = sf_readf_int (infile, data, frames) ;
+ sf_writef_int (outfile, data, readcount) ;
+ } ;
+
+ return ;
+} /* copy_data_int */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 259682b3-2887-48a6-b5bb-3cde00521ba3
+*/
diff --git a/examples/sndfile-data-trim.c b/examples/sndfile-data-trim.c
new file mode 100644
index 0000000..25b8f92
--- /dev/null
+++ b/examples/sndfile-data-trim.c
@@ -0,0 +1,65 @@
+/*
+** Copyright (C) 2007 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <sndfile.h>
+
+static void
+usage_exit (const char * progname)
+{
+ printf ("\nUsage : %s <infile> <outfile>\n\n", progname) ;
+ exit (0) ;
+} /* usage_exit */
+
+int
+main (int argc, char * argv [])
+{ char *progname, *infilename, *outfilename ;
+ SNDFILE *infile = NULL ;
+ SF_INFO sfinfo ;
+
+ progname = strrchr (argv [0], '/') ;
+ progname = progname ? progname + 1 : argv [0] ;
+
+ if (argc != 3)
+ 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 ((infile = sf_open (infilename, SFM_READ, &sfinfo)) == NULL)
+ { printf ("Not able to open input file %s.\n", infilename) ;
+ puts (sf_strerror (NULL)) ;
+ return 1 ;
+ } ;
+
+ sf_close (infile) ;
+
+ return 0 ;
+} /* main */
+
diff --git a/examples/sndfile-info.c b/examples/sndfile-info.c
new file mode 100644
index 0000000..44e2ec1
--- /dev/null
+++ b/examples/sndfile-info.c
@@ -0,0 +1,354 @@
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+
+#include <sndfile.h>
+
+#define BUFFER_LEN (1 << 16)
+
+#if (defined (WIN32) || defined (_WIN32))
+#define snprintf _snprintf
+#endif
+
+static void print_version (void) ;
+static void print_usage (const char *progname) ;
+
+static void info_dump (const char *filename) ;
+static void instrument_dump (const char *filename) ;
+static void broadcast_dump (const char *filename) ;
+
+int
+main (int argc, char *argv [])
+{ int k ;
+
+ print_version () ;
+
+ if (argc < 2 || strcmp (argv [1], "--help") == 0 || strcmp (argv [1], "-h") == 0)
+ { char *progname ;
+
+ progname = strrchr (argv [0], '/') ;
+ progname = progname ? progname + 1 : argv [0] ;
+
+ print_usage (progname) ;
+ return 1 ;
+ } ;
+
+ if (strcmp (argv [1], "-i") == 0)
+ { instrument_dump (argv [2]) ;
+ return 0 ;
+ } ;
+
+ if (strcmp (argv [1], "-b") == 0)
+ { broadcast_dump (argv [2]) ;
+ return 0 ;
+ } ;
+
+ for (k = 1 ; k < argc ; k++)
+ info_dump (argv [k]) ;
+
+ return 0 ;
+} /* main */
+
+/*==============================================================================
+** Print version and usage.
+*/
+
+static double data [BUFFER_LEN] ;
+
+static void
+print_version (void)
+{ char buffer [256] ;
+
+ sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ;
+ printf ("\nVersion : %s\n\n", buffer) ;
+} /* print_version */
+
+
+static void
+print_usage (const char *progname)
+{ printf ("Usage :\n %s <file> ...\n", progname) ;
+ printf (" Prints out information about one or more sound files.\n\n") ;
+ printf (" %s -i <file>\n", progname) ;
+ printf (" Prints out the instrument data for the given file.\n\n") ;
+ printf (" %s -b <file>\n", progname) ;
+ printf (" Prints out the broadcast WAV info for the given file.\n\n") ;
+#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) ;
+
+ /* This is the officially blessed by microsoft way but I can't get
+ ** it to link.
+ ** Sleep (15) ;
+ ** Instead, use this:
+ */
+ _sleep (5 * 1000) ;
+#endif
+} /* print_usage */
+
+/*==============================================================================
+** Dumping of sndfile info.
+*/
+
+static double data [BUFFER_LEN] ;
+
+static double
+get_signal_max (SNDFILE *file)
+{ double max, temp ;
+ int readcount, k, save_state ;
+
+ save_state = sf_command (file, SFC_GET_NORM_DOUBLE, NULL, 0) ;
+ sf_command (file, SFC_SET_NORM_DOUBLE, NULL, SF_FALSE) ;
+
+ max = 0.0 ;
+ while ((readcount = sf_read_double (file, data, BUFFER_LEN)))
+ { for (k = 0 ; k < readcount ; k++)
+ { temp = fabs (data [k]) ;
+ if (temp > max)
+ max = temp ;
+ } ;
+ } ;
+
+ sf_command (file, SFC_SET_NORM_DOUBLE, NULL, save_state) ;
+
+ return max ;
+} /* get_signal_max */
+
+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 :
+ decibels = max / 1.0 ;
+ break ;
+
+ default :
+ decibels = max / 0x8000 ;
+ break ;
+ } ;
+
+ return 20.0 * log10 (decibels) ;
+} /* calc_decibels */
+
+static const char *
+generate_duration_str (SF_INFO *sfinfo)
+{ static char str [128] ;
+
+ int seconds ;
+
+ memset (str, 0, sizeof (str)) ;
+
+ if (sfinfo->samplerate < 1)
+ return NULL ;
+
+ if (sfinfo->frames / sfinfo->samplerate > 0x7FFFFFFF)
+ return "unknown" ;
+
+ seconds = sfinfo->frames / sfinfo->samplerate ;
+
+ snprintf (str, sizeof (str) - 1, "%02d:", seconds / 60 / 60) ;
+
+ seconds = seconds % (60 * 60) ;
+ snprintf (str + strlen (str), sizeof (str) - strlen (str) - 1, "%02d:", seconds / 60) ;
+
+ seconds = seconds % 60 ;
+ snprintf (str + strlen (str), sizeof (str) - strlen (str) - 1, "%02d.", seconds) ;
+
+ seconds = ((1000 * sfinfo->frames) / sfinfo->samplerate) % 1000 ;
+ snprintf (str + strlen (str), sizeof (str) - strlen (str) - 1, "%03d", seconds) ;
+
+ return str ;
+} /* 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") ;
+
+ if (file == NULL)
+ { printf ("Error : Not able to open input file %s.\n", filename) ;
+ fflush (stdout) ;
+ memset (data, 0, sizeof (data)) ;
+ puts (sf_strerror (NULL)) ;
+ }
+ else
+ { printf ("Sample Rate : %d\n", sfinfo.samplerate) ;
+ if (sfinfo.frames > 0x7FFFFFFF)
+ printf ("Frames : unknown\n") ;
+ else
+ printf ("Frames : %ld\n", (long) 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)) ;
+
+ /* Do not use sf_signal_max because it doesn work for non-seekable files . */
+ signal_max = get_signal_max (file) ;
+ decibels = calc_decibels (&sfinfo, signal_max) ;
+ printf ("Signal Max : %g (%4.2f dB)\n\n", signal_max, decibels) ;
+ } ;
+
+ 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 void
+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 ;
+ } ;
+
+ 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 ;
+ } ;
+
+ 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 : %6d End : %6d Count : %6d\n", k, str_of_type (inst.loops [k].mode), inst.loops [k].start, inst.loops [k].end, inst.loops [k].count) ;
+
+ putchar ('\n') ;
+} /* instrument_dump */
+
+static void
+broadcast_dump (const char *filename)
+{ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ SF_BROADCAST_INFO bext ;
+ 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 ;
+ } ;
+
+ memset (&bext, 0, sizeof (SF_BROADCAST_INFO)) ;
+
+ 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 ;
+ } ;
+
+ 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) ;
+ printf ("BWF version : %d\n", bext.version) ;
+ printf ("UMID : %.*s\n", (int) sizeof (bext.umid), bext.umid) ;
+ printf ("Coding history : %.*s\n", bext.coding_history_size, bext.coding_history) ;
+
+} /* broadcast_dump */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: f59a05db-a182-41de-aedd-d717ce2bb099
+*/
diff --git a/examples/sndfile-play-beos.cpp b/examples/sndfile-play-beos.cpp
new file mode 100644
index 0000000..56f7415
--- /dev/null
+++ b/examples/sndfile-play-beos.cpp
@@ -0,0 +1,153 @@
+/*
+** Copyright (C) 2001 Marcus Overhagen <marcus@overhagen.de>
+**
+** 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 <stdio.h>
+
+#include <Application.h>
+#include <SoundPlayer.h>
+#include <string.h>
+
+#include <sndfile.h>
+
+#define BUFFER_LEN 1024
+
+/*------------------------------------------------------------------------------
+** BeOS functions for playing a sound.
+*/
+
+#if defined (__BEOS__)
+
+struct shared_data
+{
+ BSoundPlayer *player;
+ SNDFILE *sndfile;
+ SF_INFO sfinfo;
+ sem_id finished;
+};
+
+static void
+buffer_callback(void *theCookie, void *buf, size_t size, const media_raw_audio_format &format)
+{
+ shared_data *data = (shared_data *)theCookie;
+ short *buffer = (short *)buf;
+ int count = size / sizeof(short);
+ int m, readcount;
+
+ if (!data->player->HasData())
+ return;
+
+ readcount = sf_read_short(data->sndfile, buffer, count);
+ if (readcount == 0)
+ { data->player->SetHasData(false);
+ release_sem(data->finished);
+ }
+ if (readcount < count)
+ { for (m = readcount ; m < count ; m++)
+ buffer [m] = 0 ;
+ }
+ if (data->sfinfo.pcmbitwidth < 16)
+ { for (m = 0 ; m < count ; m++)
+ buffer [m] *= 256 ;
+ }
+}
+
+static void
+beos_play (int argc, char *argv [])
+{
+ shared_data data;
+ status_t status;
+ int k;
+
+ /* BSoundPlayer requires a BApplication object */
+ BApplication app("application/x-vnd.MarcusOverhagen-sfplay");
+
+ for (k = 1 ; k < argc ; k++)
+ { printf ("Playing %s\n", argv [k]) ;
+ if (! (data.sndfile = sf_open_read (argv [k], &data.sfinfo)))
+ { sf_perror (NULL) ;
+ continue ;
+ } ;
+
+ if (data.sfinfo.channels < 1 || data.sfinfo.channels > 2)
+ { printf ("Error : channels = %d.\n", data.sfinfo.channels) ;
+ sf_close (data.sndfile) ;
+ continue ;
+ } ;
+
+ data.finished = create_sem(0,"finished");
+
+ media_raw_audio_format format =
+ { data.sfinfo.samplerate,
+ data.sfinfo.channels,
+ media_raw_audio_format::B_AUDIO_SHORT,
+ B_HOST_IS_LENDIAN ? B_MEDIA_LITTLE_ENDIAN : B_MEDIA_BIG_ENDIAN,
+ BUFFER_LEN * sizeof(short)
+ };
+
+ BSoundPlayer player(&format,"player",buffer_callback,NULL,&data);
+ data.player = &player;
+
+ if ((status = player.InitCheck()) != B_OK)
+ {
+ printf ("Error : BSoundPlayer init failed, %s.\n", strerror(status)) ;
+ delete_sem(data.finished);
+ sf_close (data.sndfile) ;
+ continue ;
+ }
+
+ player.SetVolume(1.0);
+ player.Start();
+ player.SetHasData(true);
+ acquire_sem(data.finished);
+ player.Stop();
+ delete_sem(data.finished);
+
+ sf_close (data.sndfile) ;
+
+ } ;
+
+} /* beos_play */
+
+#endif
+
+/*==============================================================================
+** Main function.
+*/
+
+int
+main (int argc, char *argv [])
+{
+ if (argc < 2)
+ { printf ("Usage : %s <input sound file>\n\n", argv [0]) ;
+ return 1 ;
+ } ;
+
+ beos_play (argc, argv) ;
+
+ return 0 ;
+} /* main */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 5407a79d-88de-41c7-8d8e-9acf2cf13cc1
+*/
+
diff --git a/examples/sndfile-play.c b/examples/sndfile-play.c
new file mode 100644
index 0000000..60ebf93
--- /dev/null
+++ b/examples/sndfile-play.c
@@ -0,0 +1,960 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_ALSA_ASOUNDLIB_H
+ #define ALSA_PCM_NEW_HW_PARAMS_API
+ #define ALSA_PCM_NEW_SW_PARAMS_API
+ #include <alsa/asoundlib.h>
+ #include <sys/time.h>
+#endif
+
+#if defined (__linux__)
+ #include <fcntl.h>
+ #include <sys/ioctl.h>
+ #include <sys/soundcard.h>
+
+#elif (defined (__MACH__) && defined (__APPLE__))
+ #include <Carbon.h>
+ #include <CoreAudio/AudioHardware.h>
+
+#elif (defined (sun) && defined (unix))
+ #include <fcntl.h>
+ #include <sys/ioctl.h>
+ #include <sys/audioio.h>
+
+#elif (OS_IS_WIN32 == 1)
+ #include <windows.h>
+ #include <mmsystem.h>
+
+#endif
+
+#include <sndfile.h>
+
+#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 < 1e-10)
+ scale = 1.0 ;
+ else
+ scale = 32700.0 / scale ;
+
+ 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, xfer_align, start_threshold ;
+ 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_get_xfer_align (sw_params, &xfer_align)) < 0)
+ { fprintf (stderr, "cannot get xfer align (%s)\n", snd_strerror (err)) ;
+ goto catch_error ;
+ } ;
+
+ /* round up to closest transfer boundary */
+ start_threshold = (buffer_size / xfer_align) * xfer_align ;
+ if (start_threshold < 1)
+ start_threshold = 1 ;
+ if ((err = snd_pcm_sw_params_set_start_threshold (alsa_dev, sw_params, start_threshold)) < 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 ;
+
+ snd_pcm_status_t *status ;
+ 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)
+ { 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") ;
+ } ;
+
+ snd_pcm_prepare (alsa_dev) ;
+ break ;
+
+ case -EBADFD :
+ fprintf (stderr, "alsa_write_float: Bad PCM state.n") ;
+ return 0 ;
+ break ;
+
+ case -ESTRPIPE :
+ fprintf (stderr, "alsa_write_float: Suspend event.n") ;
+ return 0 ;
+ break ;
+
+ 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 (__linux__)
+
+static int linux_open_dsp_device (int channels, int srate) ;
+
+static void
+linux_play (int argc, char *argv [])
+{ static short buffer [BUFFER_LEN] ;
+ SNDFILE *sndfile ;
+ SF_INFO sfinfo ;
+ int k, audio_device, 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 ;
+ } ;
+
+ audio_device = linux_open_dsp_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] ;
+ write (audio_device, buffer, readcount * sizeof (short)) ;
+ } ;
+ }
+ else
+ { while ((readcount = sf_read_short (sndfile, buffer, BUFFER_LEN)))
+ 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 ;
+} /* linux_play */
+
+static int
+linux_open_dsp_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 ("linux_open_dsp_device : open ") ;
+ exit (1) ;
+ } ;
+
+ stereo = 0 ;
+ if (ioctl (fd, SNDCTL_DSP_STEREO, &stereo) == -1)
+ { /* Fatal error */
+ perror ("linux_open_dsp_device : stereo ") ;
+ exit (1) ;
+ } ;
+
+ if (ioctl (fd, SNDCTL_DSP_RESET, 0))
+ { perror ("linux_open_dsp_device : reset ") ;
+ exit (1) ;
+ } ;
+
+ fmt = CPU_IS_BIG_ENDIAN ? AFMT_S16_BE : AFMT_S16_LE ;
+ if (ioctl (fd, SOUND_PCM_SETFMT, &fmt) != 0)
+ { perror ("linux_open_dsp_device : set format ") ;
+ exit (1) ;
+ } ;
+
+ if (ioctl (fd, SOUND_PCM_WRITE_CHANNELS, &channels) != 0)
+ { perror ("linux_open_dsp_device : channels ") ;
+ exit (1) ;
+ } ;
+
+ if (ioctl (fd, SOUND_PCM_WRITE_RATE, &srate) != 0)
+ { perror ("linux_open_dsp_device : sample rate ") ;
+ exit (1) ;
+ } ;
+
+ if (ioctl (fd, SNDCTL_DSP_SYNC, 0) != 0)
+ { perror ("linux_open_dsp_device : sync ") ;
+ exit (1) ;
+ } ;
+
+ return fd ;
+} /* linux_open_dsp_device */
+
+#endif /* __linux__ */
+
+/*------------------------------------------------------------------------------
+** Mac OS X functions for playing a sound.
+*/
+
+#if (defined (__MACH__) && defined (__APPLE__)) /* MacOSX */
+
+typedef struct
+{ AudioStreamBasicDescription format ;
+
+ UInt32 buf_size ;
+ AudioDeviceID device ;
+
+ SNDFILE *sndfile ;
+ SF_INFO sfinfo ;
+
+ int fake_stereo ;
+ int done_playing ;
+} MacOSXAudioData ;
+
+#include <math.h>
+
+static OSStatus
+macosx_audio_out_callback (AudioDeviceID device, const AudioTimeStamp* current_time,
+ const AudioBufferList* data_in, const AudioTimeStamp* time_in,
+ AudioBufferList* data_out, const AudioTimeStamp* time_out,
+ void* client_data)
+{ MacOSXAudioData *audio_data ;
+ int size, sample_count, read_count, k ;
+ float *buffer ;
+
+ /* Prevent compiler warnings. */
+ device = device ;
+ current_time = current_time ;
+ data_in = data_in ;
+ time_in = time_in ;
+ time_out = time_out ;
+
+ audio_data = (MacOSXAudioData*) client_data ;
+
+ size = data_out->mBuffers [0].mDataByteSize ;
+ sample_count = size / sizeof (float) ;
+
+ buffer = (float*) data_out->mBuffers [0].mData ;
+
+ if (audio_data->fake_stereo != 0)
+ { read_count = sf_read_float (audio_data->sndfile, buffer, sample_count / 2) ;
+
+ for (k = read_count - 1 ; k >= 0 ; k--)
+ { buffer [2 * k ] = buffer [k] ;
+ buffer [2 * k + 1] = buffer [k] ;
+ } ;
+ read_count *= 2 ;
+ }
+ else
+ read_count = sf_read_float (audio_data->sndfile, buffer, sample_count) ;
+
+ /* Fill the remainder with zeroes. */
+ if (read_count < sample_count)
+ { if (audio_data->fake_stereo == 0)
+ memset (&(buffer [read_count]), 0, (sample_count - read_count) * sizeof (float)) ;
+ /* Tell the main application to terminate. */
+ audio_data->done_playing = SF_TRUE ;
+ } ;
+
+ return noErr ;
+} /* macosx_audio_out_callback */
+
+static void
+macosx_play (int argc, char *argv [])
+{ MacOSXAudioData audio_data ;
+ OSStatus err ;
+ UInt32 count, buffer_size ;
+ int k ;
+
+ audio_data.fake_stereo = 0 ;
+ audio_data.device = kAudioDeviceUnknown ;
+
+ /* get the default output device for the HAL */
+ count = sizeof (AudioDeviceID) ;
+ if ((err = AudioHardwareGetProperty (kAudioHardwarePropertyDefaultOutputDevice,
+ &count, (void *) &(audio_data.device))) != noErr)
+ { printf ("AudioHardwareGetProperty (kAudioDevicePropertyDefaultOutputDevice) failed.\n") ;
+ return ;
+ } ;
+
+ /* get the buffersize that the default device uses for IO */
+ count = sizeof (UInt32) ;
+ if ((err = AudioDeviceGetProperty (audio_data.device, 0, false, kAudioDevicePropertyBufferSize,
+ &count, &buffer_size)) != noErr)
+ { printf ("AudioDeviceGetProperty (kAudioDevicePropertyBufferSize) failed.\n") ;
+ return ;
+ } ;
+
+ /* get a description of the data format used by the default device */
+ count = sizeof (AudioStreamBasicDescription) ;
+ if ((err = AudioDeviceGetProperty (audio_data.device, 0, false, kAudioDevicePropertyStreamFormat,
+ &count, &(audio_data.format))) != noErr)
+ { printf ("AudioDeviceGetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
+ return ;
+ } ;
+
+ /* Base setup completed. Now play files. */
+ 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 ;
+ } ;
+
+ if (audio_data.sfinfo.channels < 1 || audio_data.sfinfo.channels > 2)
+ { printf ("Error : channels = %d.\n", audio_data.sfinfo.channels) ;
+ continue ;
+ } ;
+
+ audio_data.format.mSampleRate = audio_data.sfinfo.samplerate ;
+
+ if (audio_data.sfinfo.channels == 1)
+ { audio_data.format.mChannelsPerFrame = 2 ;
+ audio_data.fake_stereo = 1 ;
+ }
+ else
+ audio_data.format.mChannelsPerFrame = audio_data.sfinfo.channels ;
+
+ if ((err = AudioDeviceSetProperty (audio_data.device, NULL, 0, false, kAudioDevicePropertyStreamFormat,
+ sizeof (AudioStreamBasicDescription), &(audio_data.format))) != noErr)
+ { printf ("AudioDeviceSetProperty (kAudioDevicePropertyStreamFormat) failed.\n") ;
+ return ;
+ } ;
+
+ /* we want linear pcm */
+ if (audio_data.format.mFormatID != kAudioFormatLinearPCM)
+ return ;
+
+ /* Fire off the device. */
+ if ((err = AudioDeviceAddIOProc (audio_data.device, macosx_audio_out_callback,
+ (void *) &audio_data)) != noErr)
+ { printf ("AudioDeviceAddIOProc failed.\n") ;
+ return ;
+ } ;
+
+ err = AudioDeviceStart (audio_data.device, macosx_audio_out_callback) ;
+ if (err != noErr)
+ return ;
+
+ audio_data.done_playing = SF_FALSE ;
+
+ while (audio_data.done_playing == SF_FALSE)
+ usleep (10 * 1000) ; /* 10 000 milliseconds. */
+
+ if ((err = AudioDeviceStop (audio_data.device, macosx_audio_out_callback)) != noErr)
+ { printf ("AudioDeviceStop failed.\n") ;
+ return ;
+ } ;
+
+ err = AudioDeviceRemoveIOProc (audio_data.device, macosx_audio_out_callback) ;
+ if (err != noErr)
+ { printf ("AudioDeviceRemoveIOProc failed.\n") ;
+ return ;
+ } ;
+
+ sf_close (audio_data.sndfile) ;
+ } ;
+
+ return ;
+} /* macosx_play */
+
+#endif /* MacOSX */
+
+
+/*------------------------------------------------------------------------------
+** Win32 functions for playing a sound.
+**
+** This API sucks. Its needlessly complicated and is *WAY* too loose with
+** passing pointers arounf in integers and 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 ;
+
+ thisread = (int) sf_read_short (audio_data->sndfile, (short *) (audio_data->whdr [audio_data->current].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 data, DWORD param1, DWORD param2)
+{ Win32_Audio_Data *audio_data ;
+
+ /* Prevent compiler warnings. */
+ hwave = hwave ;
+ param1 = 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 */
+
+/* This is needed for earlier versions of the M$ development tools. */
+#ifndef DWORD_PTR
+#define DWORD_PTR DWORD
+#endif
+
+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 */
+
+/*------------------------------------------------------------------------------
+** Solaris.
+*/
+
+#if (defined (sun) && defined (unix)) /* ie Solaris */
+
+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 ;
+ audio_info.play.gain = AUDIO_MAX_GAIN ;
+ audio_info.play.balance = AUDIO_MID_BALANCE ;
+
+ 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 */
+
+/*==============================================================================
+** Main function.
+*/
+
+int
+main (int argc, char *argv [])
+{
+ if (argc < 2)
+ {
+ printf ("\nUsage : %s <input sound file>\n\n", argv [0]) ;
+#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") ;
+
+ /* This is the officially blessed by microsoft way but I can't get
+ ** it to link.
+ ** Sleep (15) ;
+ ** Instead, use this:
+ */
+ _sleep (5 * 1000) ;
+#endif
+ return 1 ;
+ } ;
+
+#if defined (__linux__)
+ #if HAVE_ALSA_ASOUNDLIB_H
+ if (access ("/proc/asound/cards", R_OK) == 0)
+ alsa_play (argc, argv) ;
+ else
+ #endif
+ linux_play (argc, argv) ;
+#elif (defined (__MACH__) && defined (__APPLE__))
+ macosx_play (argc, argv) ;
+#elif (defined (sun) && defined (unix))
+ solaris_play (argc, argv) ;
+#elif (OS_IS_WIN32 == 1)
+ win32_play (argc, argv) ;
+#elif defined (__BEOS__)
+ printf ("This program cannot be compiled on BeOS.\n") ;
+ printf ("Instead, compile the file sfplay_beos.cpp.\n") ;
+ return 1 ;
+#else
+ puts ("*** Playing sound not yet supported on this platform.") ;
+ puts ("*** Please feel free to submit a patch.") ;
+ return 1 ;
+#endif
+
+ return 0 ;
+} /* main */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 8fc4110d-6cec-4e03-91df-0f384cabedac
+*/
diff --git a/libsndfile.spec.in b/libsndfile.spec.in
new file mode 100644
index 0000000..ad47a5f
--- /dev/null
+++ b/libsndfile.spec.in
@@ -0,0 +1,69 @@
+
+%define name @PACKAGE@
+%define version @VERSION@
+%define release 1
+
+Summary: A library to handle various audio file formats.
+Name: %{name}
+Version: %{version}
+Release: %{release}
+Copyright: LGPL
+Group: Libraries/Sound
+Source: http://www.mega-nerd.com/libsndfile/libsndfile-%{version}.tar.gz
+URL: http://www.mega-nerd.com/libsndfile/
+BuildRoot: /var/tmp/%{name}-%{version}
+
+%description
+libsndfile is a C library for reading and writing sound files such as
+AIFF, AU and WAV files through one standard interface. It can currently
+read/write 8, 16, 24 and 32-bit PCM files as well as 32-bit floating
+point WAV files and a number of compressed formats.
+
+%package devel
+Summary: Libraries, includes, etc to develop libsndfile applications
+Group: Libraries
+
+%description devel
+Libraries, include files, etc you can use to develop libsndfile applications.
+
+%prep
+%setup
+
+%build
+%configure
+make
+
+%install
+if [ -d $RPM_BUILD_ROOT ]; then rm -rf $RPM_BUILD_ROOT; fi
+mkdir -p $RPM_BUILD_ROOT
+make DESTDIR=$RPM_BUILD_ROOT install
+%clean
+if [ -d $RPM_BUILD_ROOT ]; then rm -rf $RPM_BUILD_ROOT; fi
+
+%files
+%defattr(-,root,root)
+%doc AUTHORS COPYING ChangeLog INSTALL NEWS README TODO doc
+%{_libdir}/libsndfile.so.*
+%{_bindir}/*
+%{_mandir}/man1/*
+%{_datadir}/octave/site/m/*
+%{_defaultdocdir}/libsndfile1-dev/html/*
+
+%files devel
+%defattr(-,root,root)
+%{_libdir}/libsndfile.a
+%{_libdir}/libsndfile.la
+%{_libdir}/libsndfile.so
+%{_includedir}/sndfile.h
+%{_libdir}/pkgconfig/sndfile.pc
+
+%changelog
+* Sun May 15 2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+- Add html files to the files section.
+* Tue Sep 16 2003 Erik de Castro Lopo <erikd@mega-nerd.com>
+- Apply corrections from Andrew Schultz.
+* Mon Oct 21 2002 Erik de Castro Lopo <erikd@mega-nerd.com>
+- Force installation of sndfile.pc file.
+* Thu Jul 6 2000 Josh Green <jgreen@users.sourceforge.net>
+- Created libsndfile.spec.in
+
diff --git a/make_lite.py b/make_lite.py
new file mode 100644
index 0000000..56e79e3
--- /dev/null
+++ b/make_lite.py
@@ -0,0 +1,499 @@
+#!/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"', '<math.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."
+
+
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: 4aa63c4d-930b-4ef8-a0f2-d1c63992b60b
+
diff --git a/man/Makefile.am b/man/Makefile.am
new file mode 100644
index 0000000..6ad00bf
--- /dev/null
+++ b/man/Makefile.am
@@ -0,0 +1,12 @@
+## Process this file with automake to produce Makefile.in
+
+man_MANS = sndfile-info.1 sndfile-play.1 sndfile-convert.1
+
+EXTRA_DIST = sndfile-info.1 sndfile-play.1 sndfile-convert.1
+
+## Do not edit or modify anything in this comment block.
+## The arch-tag line is a file identity tag for the GNU Arch
+## revision control system.
+##
+## arch-tag: a7e49b1a-d2f1-414d-aa5a-3a91ef566d9f
+
diff --git a/man/sndfile-convert.1 b/man/sndfile-convert.1
new file mode 100644
index 0000000..105c9e0
--- /dev/null
+++ b/man/sndfile-convert.1
@@ -0,0 +1,28 @@
+.TH SNDFILE-CONVERT 1 "October 09, 2002"
+.SH NAME
+sndfile-convert \- convert a sound files from one format to another
+.SH SYNOPSIS
+.B sndfile-convert
+.RI "[encoding] input_file output_file"
+.LP
+.B sndfile-convert
+.RI --help
+.SH DESCRIPTION
+sndfile-convert converts sound files from one format to another using
+libsndfile (http://www.mega-nerd.com/libsndfile/) to read and write
+the data.
+.LP
+The format of the output file is determined by the filename extension
+of the output file.
+.LP
+The optional encoding parameter allows setting of the data encoding for
+the output file. Run "sndfile-convert --help" for more information.
+.SH AUTHOR
+This manual page was written by Erik de Castro Lopo <erikd@mega-nerd.com>.
+
+.\" Do not edit or modify anything in this comment block.
+.\" The following line is a file identity tag for the GNU Arch
+.\" revision control system.
+
+.\" arch-tag: 23aa443e-f38d-488b-b7e3-290fc5c77d20
+
diff --git a/man/sndfile-info.1 b/man/sndfile-info.1
new file mode 100644
index 0000000..744a701
--- /dev/null
+++ b/man/sndfile-info.1
@@ -0,0 +1,22 @@
+.TH SNDFILE-INFO 1 "July 28, 2002"
+.SH NAME
+sndfile-info \- display information about a sound file
+.SH SYNOPSIS
+.B sndfile-info
+.RI file
+.SH DESCRIPTION
+sndfile-info will display basic information about a sound file such as
+its format, its sample rate, and the number of channels. This information
+is obtained using libsndfile (http://www.mega-nerd.com/libsndfile/).
+.SH AUTHOR
+This manual page was originally written by Joshua Haberman
+<joshua@debian.org>, for the Debian GNU/Linux system (but may be used by
+others). Further additions have been made by Erik de Castro Lopo
+<erikd@mega-nerd.com>.
+
+.\" Do not edit or modify anything in this comment block.
+.\" The following line is a file identity tag for the GNU Arch
+.\" revision control system.
+
+.\" arch-tag: f9eca35e-5519-434d-bc55-fe845df977cd
+
diff --git a/man/sndfile-play.1 b/man/sndfile-play.1
new file mode 100644
index 0000000..1e50e65
--- /dev/null
+++ b/man/sndfile-play.1
@@ -0,0 +1,41 @@
+.de EX
+.ne 5
+.if n .sp 1
+.if t .sp .5
+.nf
+.in +.5i
+..
+.de EE
+.fi
+.in -.5i
+.if n .sp 1
+.if t .sp .5
+..
+.TH SNDFILE-PLAY 1 "July 28, 2002"
+.SH NAME
+sndfile-play \- play a sound file
+.SH SYNOPSIS
+.B sndfile-play
+.RI file
+.SH DESCRIPTION
+sndfile-play plays the specified sound file using :
+.EX
+ALSA on Linux
+/dev/dsp on systems supporting OSS (including Linux)
+/dev/audio on Sun Solaris
+CoreAudio on Apple MacOSX
+waveOut on Microsoft Win32
+.EE
+sndfile-play uses libsndfile (http://www.mega-nerd.com/libsndfile/)
+to read the file.
+.SH AUTHOR
+This manual page was originally written by Joshua Haberman
+<joshua@debian.org>, for the Debian GNU/Linux system (but may be used by
+others). Further additions have been made by Erik de Castro Lopo
+<erikd@mega-nerd.com>.
+
+.\" Do not edit or modify anything in this comment block.
+.\" The arch-tag line is a file identity tag for the GNU Arch
+.\" revision control system.
+
+.\" arch-tag: 5a0120d9-040c-464e-b01e-89dc2c2428c9
diff --git a/reconfigure.mk b/reconfigure.mk
new file mode 100755
index 0000000..1cc9cfb
--- /dev/null
+++ b/reconfigure.mk
@@ -0,0 +1,58 @@
+#!/usr/bin/make -f
+
+# The auto tools MUST be run in the following order:
+#
+# 1. aclocal
+# 2. libtoolize (if you use libtool)
+# 3. autoconf
+# 4. autoheader (if you use autoheader)
+# 5. automake (if you use automake)
+#
+# The following makefile runs these in the correct order according to their
+# dependancies. It also makes up for Mac OSX's fucked-upped-ness.
+
+ACLOCAL = aclocal
+
+ifneq ($(shell uname -s), Darwin)
+ LIBTOOLIZE = libtoolize
+else
+ # Fuck Apple! Why the hell did they rename libtoolize????
+ LIBTOOLIZE = glibtoolize
+ # Fink (and DarwinPorts/MacPorts) sucks as well, but this seems necessary.
+ ACLOCAL_INC = -I /opt/local/share/aclocal
+endif
+
+genfiles : config.status
+ (cd src && make genfiles)
+ (cd tests && make genfiles)
+
+config.status: configure src/config.h.in Makefile.in src/Makefile.in tests/Makefile.in
+ ./configure --enable-gcc-werror
+
+configure: ltmain.sh
+ autoconf
+
+Makefile.in: Makefile.am
+ automake --copy --add-missing
+
+src/Makefile.in: src/Makefile.am
+ automake --copy --add-missing
+
+tests/Makefile.in: tests/Makefile.am
+ automake --copy --add-missing
+
+src/config.h.in: configure
+ autoheader
+
+libtool ltmain.sh: aclocal.m4
+ $(LIBTOOLIZE) --copy --force
+
+# Need to re-run aclocal whenever acinclude.m4 is modified.
+aclocal.m4: acinclude.m4
+ $(ACLOCAL) $(ACLOCAL_INC)
+
+clean:
+ rm -f libtool ltmain.sh aclocal.m4 Makefile.in src/config.h.in config.cache config.status
+ find . -name .deps -type d -exec rm -rf {} \;
+
+
diff --git a/regtest/Makefile.am b/regtest/Makefile.am
new file mode 100644
index 0000000..ad53986
--- /dev/null
+++ b/regtest/Makefile.am
@@ -0,0 +1,18 @@
+## Process this file with automake to produce Makefile.in
+
+bin_PROGRAMS = sndfile-regtest
+
+noinst_HEADERS = regtest.h
+
+SNDFILEDIR =../src
+INCLUDES = -I$(srcdir)/$(SNDFILEDIR) $(OS_SPECIFIC_CFLAGS)
+
+sndfile_regtest_SOURCES = sndfile-regtest.c database.c checksum.c
+sndfile_regtest_LDADD = $(SNDFILEDIR)/libsndfile.la $(SQLITE3_LIBS)
+
+
+## Do not edit or modify anything in this comment block.
+## The arch-tag line is a file identity tag for the GNU Arch
+## revision control system.
+##
+## arch-tag: ac4a9626-49ce-4bb4-9fb6-e43de0a23432
diff --git a/regtest/Readme.txt b/regtest/Readme.txt
new file mode 100644
index 0000000..5102cb8
--- /dev/null
+++ b/regtest/Readme.txt
@@ -0,0 +1,114 @@
+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.
+
+
+--------------------------------------------------------------------------
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: 174661f1-9874-424e-8d8b-301d0322dfdb
diff --git a/regtest/checksum.c b/regtest/checksum.c
new file mode 100644
index 0000000..033a156
--- /dev/null
+++ b/regtest/checksum.c
@@ -0,0 +1,125 @@
+/*
+** Copyright (C) 2005 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 "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sndfile.h>
+
+#include "float_cast.h"
+
+#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 (0x7FFFFFFF * data.f [k]) ;
+ }
+ while (count > 0) ;
+
+ return start ;
+} /* float_checksum */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The following line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 6ae999d1-dd5a-4306-9e11-d4cfc9e8ae27
+*/
diff --git a/regtest/database.c b/regtest/database.c
new file mode 100644
index 0000000..7830d68
--- /dev/null
+++ b/regtest/database.c
@@ -0,0 +1,502 @@
+/*
+** Copyright (C) 2005 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <sndfile.h>
+
+#include "regtest.h"
+
+#if HAVE_SQLITE3
+
+#include <sqlite3.h>
+
+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) ;
+
+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 ;
+ const char * cptr ;
+ char * errmsg ;
+ int err ;
+
+ db = (REGTEST_DB *) db_handle ;
+
+ if ((cptr = strrchr (filename, '/')) != NULL)
+ filename = cptr + 1 ;
+
+ 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 (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\n", db->filename, sf_strerror (NULL)) ;
+ 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__, db_handle) ;
+ return 0 ;
+} /* db_list_all */
+
+int
+db_del_entry (REG_DB * db_handle, const char * entry)
+{
+ printf ("%s : %p %s\n", __func__, 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) ;
+ } ;
+
+ strncpy (db->filename, result [2], sizeof (db->filename)) ;
+ strncpy (db->pathname, result [3], sizeof (db->pathname)) ;
+
+ 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 * cptr ;
+
+ if (filepath [0] != '/')
+ { memset (db->pathname, 0, sizeof (db->pathname)) ;
+ if (getcwd (db->pathname, sizeof (db->pathname)) == NULL)
+ { perror ("\ngetcwd failed") ;
+ exit (1) ;
+ } ;
+
+ db->pathname [strlen (db->pathname)] = '/' ;
+ strncat (db->pathname, filepath, sizeof (db->pathname)) ;
+ }
+ else
+ strncpy (db->pathname, filepath, sizeof (db->pathname)) ;
+
+ if ((cptr = strrchr (db->pathname, '/')) == NULL)
+ { printf ("\nError : bad pathname %s\n", filepath) ;
+ exit (1) ;
+ } ;
+
+ strncpy (db->filename, cptr + 1, sizeof (db->filename)) ;
+} /* 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 ++ ;
+
+ argc = 0 ;
+ argv = NULL ;
+ colname = NULL ;
+ return 0 ;
+} /* count_callback */
+
+static int
+ekey_max_callback (REGTEST_DB * db, int argc, char **argv, char **unused)
+{ int ekey ;
+
+ argc = 0 ;
+ unused = NULL ;
+
+ 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 ;
+
+ unused = NULL ;
+
+ for (k = 0 ; k < argc ; k++)
+ printf ("%s = %s\n", colname [k], argv [k] ? argv [k] : "NULL") ;
+
+ printf ("\n") ;
+
+ return 0 ;
+} /* callback */
+
+#else
+
+int dummy (void) ;
+
+int
+dummy (void)
+{ /*
+ ** Empty dummy fnction so tha compiler doesn't winge about an
+ ** empty file.
+ */
+ return 0 ;
+} /* dummy */
+
+#endif
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The following line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: c6bcb7cb-0d9e-47b6-a89a-66304df4d462
+*/
diff --git a/regtest/regtest.h b/regtest/regtest.h
new file mode 100644
index 0000000..cc8ecaa
--- /dev/null
+++ b/regtest/regtest.h
@@ -0,0 +1,45 @@
+/*
+** Copyright (C) 2005 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) ;
+
+/*
+** Do not edit or modify anything in this comment block.
+** The following line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 80138e38-f373-48d3-8152-7f7882a62cd7
+*/
diff --git a/regtest/sndfile-regtest.c b/regtest/sndfile-regtest.c
new file mode 100644
index 0000000..ee7eaa9
--- /dev/null
+++ b/regtest/sndfile-regtest.c
@@ -0,0 +1,128 @@
+/*
+** Copyright (C) 2005 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sndfile.h>
+
+#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
+
+/*
+** Do not edit or modify anything in this comment block.
+** The following line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 7f318f08-9bfa-4249-856d-fe994819bdce
+*/
diff --git a/sndfile.pc.in b/sndfile.pc.in
new file mode 100644
index 0000000..f2a833b
--- /dev/null
+++ b/sndfile.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: sndfile
+Description: A library for reading and writing audio files
+Requires:
+Version: @VERSION@
+Libs: -L${libdir} -lsndfile
+Cflags: -I${includedir}
diff --git a/src/FLAC/AUTHORS b/src/FLAC/AUTHORS
new file mode 100644
index 0000000..217baf4
--- /dev/null
+++ b/src/FLAC/AUTHORS
@@ -0,0 +1,41 @@
+/* FLAC - Free Lossless Audio Codec
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * This file is part the FLAC project. FLAC is comprised of several
+ * components distributed under difference licenses. The codec libraries
+ * are distributed under Xiph.Org's BSD-like license (see the file
+ * COPYING.Xiph in this distribution). All other programs, libraries, and
+ * plugins are distributed under the GPL (see COPYING.GPL). The documentation
+ * is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
+ * FLAC distribution contains at the top the terms under which it may be
+ * distributed.
+ *
+ * Since this particular file is relevant to all components of FLAC,
+ * it may be distributed under the Xiph.Org license, which is the least
+ * restrictive of those mentioned above. See the file COPYING.Xiph in this
+ * distribution.
+ */
+
+
+FLAC (http://flac.sourceforge.net/) is an Open Source lossless audio
+codec developed by Josh Coalson <jcoalson@users.sourceforge.net>.
+
+Other major contributors and their contributions:
+"Andrey Astafiev" <andrei@tvcell.ru>
+* Russian translation of the HTML documentation
+
+"Miroslav Lichvar" <lichvarm@phoenix.inf.upol.cz>
+* IA-32 assembly versions of several libFLAC routines
+
+"Brady Patterson" <bpat@users.sourceforge.net>
+* AIFF file support, PPC assembly versions of libFLAC routines
+
+"Daisuke Shimamura" <Daisuke_Shimamura@nifty.com>
+* i18n support in the XMMS plugin
+
+"X-Fixer" <x-fixer@narod.ru>
+* Configuration system, tag editing, and file info in the Winamp2 plugin
+
+"Matt Zimmerman" <mdz@debian.org>
+* Libtool/autoconf/automake make system, flac man page
+
diff --git a/src/FLAC/COPYING.FDL b/src/FLAC/COPYING.FDL
new file mode 100644
index 0000000..4a0fe1c
--- /dev/null
+++ b/src/FLAC/COPYING.FDL
@@ -0,0 +1,397 @@
+ GNU Free Documentation License
+ Version 1.2, November 2002
+
+
+ Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The "Document", below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as "you". You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject. (Thus, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification. Examples of
+transparent image formats include PNG, XCF and JPG. Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".) To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions
+ (which should, if there were any, be listed in the History section
+ of the Document). You may use the same title as a previous version
+ if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has fewer than five),
+ unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+ to it an item stating at least the title, year, new authors, and
+ publisher of the Modified Version as given on the Title Page. If
+ there is no section Entitled "History" in the Document, create one
+ stating the title, year, authors, and publisher of the Document as
+ given on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise
+ the network locations given in the Document for previous versions
+ it was based on. These may be placed in the "History" section.
+ You may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+ Preserve the Title of the section, and preserve in the section all
+ the substance and tone of each of the contributor acknowledgements
+ and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+ or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications". You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License. Any other attempt to
+copy, modify, sublicense or distribute the Document 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.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation 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. See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.2
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/src/FLAC/COPYING.GPL b/src/FLAC/COPYING.GPL
new file mode 100644
index 0000000..c3c7a9e
--- /dev/null
+++ b/src/FLAC/COPYING.GPL
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 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.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, 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 or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+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 give any other recipients of the Program a copy of this License
+along with the Program.
+
+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 Program or any portion
+of it, thus forming a work based on the Program, 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) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+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 Program, 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 Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) 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; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, 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 executable. However, as a
+special exception, the source code 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.
+
+If distribution of executable or 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 counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program 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.
+
+ 5. 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 Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program 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 to
+this License.
+
+ 7. 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 Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program 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 Program.
+
+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.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program 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.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 Program
+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 Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, 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
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "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 PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. 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 PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), 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 Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/src/FLAC/COPYING.LGPL b/src/FLAC/COPYING.LGPL
new file mode 100644
index 0000000..5ab7695
--- /dev/null
+++ b/src/FLAC/COPYING.LGPL
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/src/FLAC/COPYING.Xiph b/src/FLAC/COPYING.Xiph
new file mode 100644
index 0000000..0a104a9
--- /dev/null
+++ b/src/FLAC/COPYING.Xiph
@@ -0,0 +1,28 @@
+Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+
+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.
diff --git a/src/FLAC/Makefile.am b/src/FLAC/Makefile.am
new file mode 100644
index 0000000..2b9a80e
--- /dev/null
+++ b/src/FLAC/Makefile.am
@@ -0,0 +1,39 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under difference licenses. The codec libraries
+# are distributed under Xiph.Org's BSD-like license (see the file
+# COPYING.Xiph in this distribution). All other programs, libraries, and
+# plugins are distributed under the GPL (see COPYING.GPL). The documentation
+# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
+# FLAC distribution contains at the top the terms under which it may be
+# distributed.
+#
+# Since this particular file is relevant to all components of FLAC,
+# it may be distributed under the Xiph.Org license, which is the least
+# restrictive of those mentioned above. See the file COPYING.Xiph in this
+# distribution.
+
+#
+# automake provides the following useful targets:
+#
+# all: build all programs and libraries using the current
+# configuration (set by configure)
+#
+# check: build and run all self-tests
+#
+# clean: remove everything except what's required to build everything
+#
+# distclean: remove everything except what goes in the distribution
+#
+
+SUBDIRS = include src test
+
+EXTRA_DIST = \
+ COPYING.FDL \
+ COPYING.GPL \
+ COPYING.LGPL \
+ COPYING.Xiph \
+ README \
+ strip_non_asm_libtool_args.sh
diff --git a/src/FLAC/README b/src/FLAC/README
new file mode 100644
index 0000000..aa162b2
--- /dev/null
+++ b/src/FLAC/README
@@ -0,0 +1,269 @@
+/* FLAC - Free Lossless Audio Codec
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * This file is part the FLAC project. FLAC is comprised of several
+ * components distributed under difference licenses. The codec libraries
+ * are distributed under Xiph.Org's BSD-like license (see the file
+ * COPYING.Xiph in this distribution). All other programs, libraries, and
+ * plugins are distributed under the LGPL or GPL (see COPYING.LGPL and
+ * COPYING.GPL). The documentation is distributed under the Gnu FDL (see
+ * COPYING.FDL). Each file in the FLAC distribution contains at the top the
+ * terms under which it may be distributed.
+ *
+ * Since this particular file is relevant to all components of FLAC,
+ * it may be distributed under the Xiph.Org license, which is the least
+ * restrictive of those mentioned above. See the file COPYING.Xiph in this
+ * distribution.
+ */
+
+
+FLAC (http://flac.sourceforge.net/) is an Open Source lossless audio
+codec developed by Josh Coalson.
+
+FLAC is comprised of
+ * `libFLAC', a library which implements reference encoders and
+ decoders for native FLAC and Ogg FLAC, and a metadata interface
+ * `libFLAC++', a C++ object wrapper library around libFLAC
+ * `flac', a command-line program for encoding and decoding files
+ * `metaflac', a command-line program for viewing and editing FLAC
+ metadata
+ * player plugins for XMMS and Winamp
+ * user and API documentation
+
+The libraries (libFLAC, libFLAC++) are
+licensed under Xiph.org's BSD-like license (see COPYING.Xiph). All other
+programs and plugins are licensed under the GNU General Public License
+(see COPYING.GPL). The documentation is licensed under the GNU Free
+Documentation License (see COPYING.FDL).
+
+
+===============================================================================
+FLAC - 1.1.4 - Contents
+===============================================================================
+
+- Introduction
+- Prerequisites
+- Building in a GNU environment
+- Building with Makefile.lite
+- Building with MSVC
+- Building on Mac OS X
+- Note to embedded developers
+
+
+===============================================================================
+Introduction
+===============================================================================
+
+This is the source release for the FLAC project. See
+
+ doc/html/index.html
+
+for full documentation.
+
+A brief description of the directory tree:
+
+ doc/ the HTML documentation
+ flac.pbproj/ the Mac OS X Project Builder project
+ include/ public include files for libFLAC and libFLAC++
+ man/ the man page for `flac'
+ src/ the source code and private headers
+ test/ the test scripts
+
+
+===============================================================================
+Prerequisites
+===============================================================================
+
+To build FLAC with support for Ogg FLAC you must have built and installed
+libogg according to the specific instructions below. You must have
+libogg 1.1.2 or greater, or there will be seeking problems with Ogg FLAC.
+
+If you are building on x86 and want the assembly optimizations, you will
+need to have NASM >= 0.98.30 installed according to the specific instructions
+below.
+
+
+===============================================================================
+Building in a GNU environment
+===============================================================================
+
+FLAC uses autoconf and libtool for configuring and building.
+Better documentation for these will be forthcoming, but in
+general, this should work:
+
+./configure && make && make check && make install
+
+The 'make check' step is optional; omit it to skip all the tests,
+which can take several hours and use around 70-80 megs of disk space.
+Even though it will stop with an explicit message on any failure, it
+does print out a lot of stuff so you might want to capture the output
+to a file if you're having a problem. Also, don't run 'make check'
+as root because it confuses some of the tests.
+
+NOTE: Despite our best efforts it's entirely possible to have
+problems when using older versions of autoconf, automake, or
+libtool. If you have the latest versions and still can't get it
+to work, see the next section on Makefile.lite.
+
+There are a few FLAC-specific arguments you can give to
+`configure':
+
+--enable-debug : Builds everything with debug symbols and some
+extra (and more verbose) error checking.
+
+--disable-asm-optimizations : Disables the compilation of the
+assembly routines. Many routines have assembly versions for
+speed and `configure' is pretty good about knowing what is
+supported, but you can use this option to build only from the
+C sources.
+
+--enable-sse : If you are building for an x86 CPU that supports
+SSE instructions, you can enable some of the faster routines
+if your operating system also supports SSE instructions. flac
+can tell if the CPU supports the instructions but currently has
+no way to test if the OS does, so if it does, you must pass
+this argument to configure to use the SSE routines. If flac
+crashes when built with this option you will have to go back and
+configure without --enable-sse. Note that
+--disable-asm-optimizations implies --disable-sse.
+
+--enable-local-xmms-plugin : Installs the FLAC XMMS plugin in
+$HOME/.xmms/Plugins, instead of the global XMMS plugin area
+(usually /usr/lib/xmms/Input).
+
+--with-ogg=
+--with-xmms-prefix=
+--with-libiconv-prefix=
+Use these if you have these packages but configure can't find them.
+
+If you want to build completely from scratch (i.e. starting with just
+configure.in and Makefile.am) you should be able to just run 'autogen.sh'
+but make sure and read the comments in that file first.
+
+
+===============================================================================
+Building with Makefile.lite
+===============================================================================
+
+There is a more lightweight build system for do-it-yourself-ers.
+It is also useful if configure isn't working, which may be the
+case since lately we've had some problems with different versions
+of automake and libtool. The Makefile.lite system should work
+on GNU systems with few or no adjustments.
+
+From the top level just 'make -f Makefile.lite'. You can
+specify zero or one optional target from 'release', 'debug',
+'test', or 'clean'. The default is 'release'. There is no
+'install' target but everything you need will end up in the
+obj/ directory.
+
+If you are not on an x86 system or you don't have nasm, you
+may have to change the DEFINES in src/libFLAC/Makefile.lite. If
+you don't have nasm, remove -DFLAC__HAS_NASM. If your target is
+not an x86, change -DFLAC__CPU_IA32 to -DFLAC__CPU_UNKNOWN.
+
+
+===============================================================================
+Building with MSVC
+===============================================================================
+
+There are .dsp projects and a master FLAC.dsw workspace to build all
+the libraries and executables with MSVC6. There are also .vcproj
+projects and a master FLAC.sln solution to build all the libraries and
+executables with VC++ 2005.
+
+Prerequisite: you must have the Ogg libraries installed as described
+later.
+
+Prerequisite: you must have nasm installed, and nasmw.exe must be in
+your PATH, or the path to nasmw.exe must be added to the list of
+directories for executable files in the MSVC global options.
+
+MSVC6:
+To build everything, run Developer Studio, do File|Open Workspace,
+and open FLAC.dsw. Select "Build | Set active configuration..."
+from the menu, then in the dialog, select "All - Win32 Release" (or
+Debug if you prefer). Click "Ok" then hit F7 to build.
+
+VC++ 2005:
+To build everything, run Visual Studio, do File|Open and open FLAC.sln.
+From the dropdown in the toolbar, select "Release" instead of "Debug",
+then hit F7 to build.
+
+Either way, this will build all libraries both statically (e.g.
+obj\release\lib\libFLAC_static.lib) and as DLLs (e.g.
+obj\release\lib\libFLAC.dll), and it will build all binaries, statically
+linked (e.g. obj\release\bin\flac.exe).
+
+Everything will end up in the "obj" directory. DLLs and .exe files
+are all that are needed and can be copied to an installation area and
+added to the PATH. The plugins have to be copied to their appropriate
+place in the player area. For Winamp2 this is <winamp2-dir>\Plugins.
+
+By default the code is configured with Ogg support. Before building FLAC
+you will need to get the Ogg source distribution
+(see http://xiph.org/ogg/vorbis/download/), build ogg_static.lib (load and
+build win32\ogg_static.dsp), copy ogg_static.lib into FLAC's
+'obj\release\lib' directory, and copy the entire include\ogg tree into
+FLAC's 'include' directory (so that there is an 'ogg' directory in FLAC's
+'include' directory with the files ogg.h, os_types.h and config_types.h).
+
+If you want to build without Ogg support, instead edit all .dsp or
+.vcproj files and remove any occurrences of "/D FLAC__HAS_OGG".
+
+
+===============================================================================
+Building on Mac OS X
+===============================================================================
+
+If you have Fink, the GNU flow above should work. Otherwise,
+there is a Project Builder project in the top-level source
+directory to build libFLAC and the command-line utilities on
+Mac OS X. In a terminal, cd to the top-level directory (the
+one that contains this README file) and type:
+
+ pbxbuild -alltargets
+
+This will create everything and leave it in the build/ directory.
+Don't worry about the rest of the stuff that is in build/ or
+the stuff that was already there before building.
+
+The Project Builder project requires that you have libiconv and
+libogg in /sw, ala fink. If you don't, you'll need to install
+them somewhere and change the path to them in the Library Paths
+section of several targets.
+
+It also assumes the CPU supports Altivec instructions. If it does
+not, you will also have to add -DFLAC__NO_ASM to the CFLAGS in the
+libFLAC target.
+
+There currently is no install procedure; you will have to
+manually copy the tools to wherever you need them.
+
+
+===============================================================================
+Note to embedded developers
+===============================================================================
+
+libFLAC has grown larger over time as more functionality has been
+included, but much of it may be unnecessary for a particular embedded
+implementation. Unused parts may be pruned by some simple editing of
+configure.in and src/libFLAC/Makefile.am; the following dependency
+graph shows which modules may be pruned without breaking things
+further down:
+
+stream_encoder.h
+ stream_decoder.h
+ format.h
+
+stream_decoder.h
+ format.h
+
+metadata.h
+ format.h
+
+In other words, for pure decoding applications, both the stream encoder
+and metadata editing interfaces can be safely removed.
+
+There is a section dedicated to embedded use in the libFLAC API
+HTML documentation (see doc/html/api/index.html).
diff --git a/src/FLAC/include/FLAC/Makefile.am b/src/FLAC/include/FLAC/Makefile.am
new file mode 100644
index 0000000..19f49b1
--- /dev/null
+++ b/src/FLAC/include/FLAC/Makefile.am
@@ -0,0 +1,42 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+flaccincludedir = $(includedir)/FLAC
+
+flaccinclude_HEADERS = \
+ all.h \
+ assert.h \
+ callback.h \
+ export.h \
+ format.h \
+ metadata.h \
+ ordinals.h \
+ stream_decoder.h \
+ stream_encoder.h
diff --git a/src/FLAC/include/FLAC/all.h b/src/FLAC/include/FLAC/all.h
new file mode 100644
index 0000000..22d0d44
--- /dev/null
+++ b/src/FLAC/include/FLAC/all.h
@@ -0,0 +1,344 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__ALL_H
+#define FLAC__ALL_H
+
+#include "export.h"
+
+#include "assert.h"
+#include "callback.h"
+#include "format.h"
+#include "metadata.h"
+#include "ordinals.h"
+#include "stream_decoder.h"
+#include "stream_encoder.h"
+
+/** \mainpage
+ *
+ * \section intro Introduction
+ *
+ * This is the documentation for the FLAC C and C++ APIs. It is
+ * highly interconnected; this introduction should give you a top
+ * level idea of the structure and how to find the information you
+ * need. As a prerequisite you should have at least a basic
+ * knowledge of the FLAC format, documented
+ * <A HREF="../format.html">here</A>.
+ *
+ * \section c_api FLAC C API
+ *
+ * The FLAC C API is the interface to libFLAC, a set of structures
+ * describing the components of FLAC streams, and functions for
+ * encoding and decoding streams, as well as manipulating FLAC
+ * metadata in files. The public include files will be installed
+ * in your include area (for example /usr/include/FLAC/...).
+ *
+ * By writing a little code and linking against libFLAC, it is
+ * relatively easy to add FLAC support to another program. The
+ * library is licensed under <A HREF="../license.html">Xiph's BSD license</A>.
+ * Complete source code of libFLAC as well as the command-line
+ * encoder and plugins is available and is a useful source of
+ * examples.
+ *
+ * Aside from encoders and decoders, libFLAC provides a powerful
+ * metadata interface for manipulating metadata in FLAC files. It
+ * allows the user to add, delete, and modify FLAC metadata blocks
+ * and it can automatically take advantage of PADDING blocks to avoid
+ * rewriting the entire FLAC file when changing the size of the
+ * metadata.
+ *
+ * libFLAC usually only requires the standard C library and C math
+ * library. In particular, threading is not used so there is no
+ * dependency on a thread library. However, libFLAC does not use
+ * global variables and should be thread-safe.
+ *
+ * libFLAC also supports encoding to and decoding from Ogg FLAC.
+ * However the metadata editing interfaces currently have limited
+ * read-only support for Ogg FLAC files.
+ *
+ * \section cpp_api FLAC C++ API
+ *
+ * The FLAC C++ API is a set of classes that encapsulate the
+ * structures and functions in libFLAC. They provide slightly more
+ * functionality with respect to metadata but are otherwise
+ * equivalent. For the most part, they share the same usage as
+ * their counterparts in libFLAC, and the FLAC C API documentation
+ * can be used as a supplement. The public include files
+ * for the C++ API will be installed in your include area (for
+ * example /usr/include/FLAC++/...).
+ *
+ * libFLAC++ is also licensed under
+ * <A HREF="../license.html">Xiph's BSD license</A>.
+ *
+ * \section getting_started Getting Started
+ *
+ * A good starting point for learning the API is to browse through
+ * the <A HREF="modules.html">modules</A>. Modules are logical
+ * groupings of related functions or classes, which correspond roughly
+ * to header files or sections of header files. Each module includes a
+ * detailed description of the general usage of its functions or
+ * classes.
+ *
+ * From there you can go on to look at the documentation of
+ * individual functions. You can see different views of the individual
+ * functions through the links in top bar across this page.
+ *
+ * \section porting_guide Porting Guide
+ *
+ * Starting with FLAC 1.1.3 a \link porting Porting Guide \endlink
+ * has been introduced which gives detailed instructions on how to
+ * port your code to newer versions of FLAC.
+ *
+ * \section embedded_developers Embedded Developers
+ *
+ * libFLAC has grown larger over time as more functionality has been
+ * included, but much of it may be unnecessary for a particular embedded
+ * implementation. Unused parts may be pruned by some simple editing of
+ * src/libFLAC/Makefile.am. In general, the decoders, encoders, and
+ * metadata interface are all independent from each other.
+ *
+ * It is easiest to just describe the dependencies:
+ *
+ * - All modules depend on the \link flac_format Format \endlink module.
+ * - The decoders and encoders depend on the bitbuffer.
+ * - The decoder is independent of the encoder. The encoder uses the
+ * decoder because of the verify feature, but this can be removed if
+ * not needed.
+ * - Parts of the metadata interface require the stream decoder (but not
+ * the encoder).
+ * - Ogg support is selectable through the compile time macro
+ * \c FLAC__HAS_OGG.
+ *
+ * For example, if your application only requires the stream decoder, no
+ * encoder, and no metadata interface, you can remove the stream encoder
+ * and the metadata interface, which will greatly reduce the size of the
+ * library.
+ */
+
+/** \defgroup porting Porting Guide for New Versions
+ *
+ * This module describes differences in the library interfaces from
+ * version to version. It assists in the porting of code that uses
+ * the libraries to newer versions of FLAC.
+ *
+ * One simple facility for making porting easier that has been added
+ * in FLAC 1.1.3 is a set of \c #defines in \c export.h of each
+ * library's includes (e.g. \c include/FLAC/export.h). The
+ * \c #defines mirror the libraries'
+ * <A HREF="http://www.gnu.org/software/libtool/manual.html#Libtool-versioning">libtool version numbers</A>,
+ * e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT,
+ * \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE.
+ * These can be used to support multiple versions of an API during the
+ * transition phase, e.g.
+ *
+ * \code
+ * #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7
+ * legacy code
+ * #else
+ * new code
+ * #endif
+ * \endcode
+ *
+ * The the source will work for multiple versions and the legacy code can
+ * easily be removed when the transition is complete.
+ *
+ * Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in
+ * include/FLAC/export.h), which can be used to determine whether or not
+ * the library has been compiled with support for Ogg FLAC. This is
+ * simpler than trying to call an Ogg init function and catching the
+ * error.
+ */
+
+/** \defgroup porting_1_1_2_to_1_1_3 Porting from FLAC 1.1.2 to 1.1.3
+ * \ingroup porting
+ *
+ * \brief
+ * This module describes porting from FLAC 1.1.2 to FLAC 1.1.3.
+ *
+ * The main change between the APIs in 1.1.2 and 1.1.3 is that they have
+ * been simplified. First, libOggFLAC has been merged into libFLAC and
+ * libOggFLAC++ has been merged into libFLAC++. Second, both the three
+ * decoding layers and three encoding layers have been merged into a
+ * single stream decoder and stream encoder. That is, the functionality
+ * of FLAC__SeekableStreamDecoder and FLAC__FileDecoder has been merged
+ * into FLAC__StreamDecoder, and FLAC__SeekableStreamEncoder and
+ * FLAC__FileEncoder into FLAC__StreamEncoder. Only the
+ * FLAC__StreamDecoder and FLAC__StreamEncoder remain. What this means
+ * is there is now a single API that can be used to encode or decode
+ * streams to/from native FLAC or Ogg FLAC and the single API can work
+ * on both seekable and non-seekable streams.
+ *
+ * Instead of creating an encoder or decoder of a certain layer, now the
+ * client will always create a FLAC__StreamEncoder or
+ * FLAC__StreamDecoder. The old layers are now differentiated by the
+ * initialization function. For example, for the decoder,
+ * FLAC__stream_decoder_init() has been replaced by
+ * FLAC__stream_decoder_init_stream(). This init function takes
+ * callbacks for the I/O, and the seeking callbacks are optional. This
+ * allows the client to use the same object for seekable and
+ * non-seekable streams. For decoding a FLAC file directly, the client
+ * can use FLAC__stream_decoder_init_file() and pass just a filename
+ * and fewer callbacks; most of the other callbacks are supplied
+ * internally. For situations where fopen()ing by filename is not
+ * possible (e.g. Unicode filenames on Windows) the client can instead
+ * open the file itself and supply the FILE* to
+ * FLAC__stream_decoder_init_FILE(). The init functions now returns a
+ * FLAC__StreamDecoderInitStatus instead of FLAC__StreamDecoderState.
+ * Since the callbacks and client data are now passed to the init
+ * function, the FLAC__stream_decoder_set_*_callback() functions and
+ * FLAC__stream_decoder_set_client_data() are no longer needed. The
+ * rest of the calls to the decoder are the same as before.
+ *
+ * There are counterpart init functions for Ogg FLAC, e.g.
+ * FLAC__stream_decoder_init_ogg_stream(). All the rest of the calls
+ * and callbacks are the same as for native FLAC.
+ *
+ * As an example, in FLAC 1.1.2 a seekable stream decoder would have
+ * been set up like so:
+ *
+ * \code
+ * FLAC__SeekableStreamDecoder *decoder = FLAC__seekable_stream_decoder_new();
+ * if(decoder == NULL) do_something;
+ * FLAC__seekable_stream_decoder_set_md5_checking(decoder, true);
+ * [... other settings ...]
+ * FLAC__seekable_stream_decoder_set_read_callback(decoder, my_read_callback);
+ * FLAC__seekable_stream_decoder_set_seek_callback(decoder, my_seek_callback);
+ * FLAC__seekable_stream_decoder_set_tell_callback(decoder, my_tell_callback);
+ * FLAC__seekable_stream_decoder_set_length_callback(decoder, my_length_callback);
+ * FLAC__seekable_stream_decoder_set_eof_callback(decoder, my_eof_callback);
+ * FLAC__seekable_stream_decoder_set_write_callback(decoder, my_write_callback);
+ * FLAC__seekable_stream_decoder_set_metadata_callback(decoder, my_metadata_callback);
+ * FLAC__seekable_stream_decoder_set_error_callback(decoder, my_error_callback);
+ * FLAC__seekable_stream_decoder_set_client_data(decoder, my_client_data);
+ * if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) do_something;
+ * \endcode
+ *
+ * In FLAC 1.1.3 it is like this:
+ *
+ * \code
+ * FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+ * if(decoder == NULL) do_something;
+ * FLAC__stream_decoder_set_md5_checking(decoder, true);
+ * [... other settings ...]
+ * if(FLAC__stream_decoder_init_stream(
+ * decoder,
+ * my_read_callback,
+ * my_seek_callback, // or NULL
+ * my_tell_callback, // or NULL
+ * my_length_callback, // or NULL
+ * my_eof_callback, // or NULL
+ * my_write_callback,
+ * my_metadata_callback, // or NULL
+ * my_error_callback,
+ * my_client_data
+ * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
+ * \endcode
+ *
+ * or you could do;
+ *
+ * \code
+ * [...]
+ * FILE *file = fopen("somefile.flac","rb");
+ * if(file == NULL) do_somthing;
+ * if(FLAC__stream_decoder_init_FILE(
+ * decoder,
+ * file,
+ * my_write_callback,
+ * my_metadata_callback, // or NULL
+ * my_error_callback,
+ * my_client_data
+ * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
+ * \endcode
+ *
+ * or just:
+ *
+ * \code
+ * [...]
+ * if(FLAC__stream_decoder_init_file(
+ * decoder,
+ * "somefile.flac",
+ * my_write_callback,
+ * my_metadata_callback, // or NULL
+ * my_error_callback,
+ * my_client_data
+ * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something;
+ * \endcode
+ *
+ * Another small change to the decoder is in how it handles unparseable
+ * streams. Before, when the decoder found an unparseable stream
+ * (reserved for when the decoder encounters a stream from a future
+ * encoder that it can't parse), it changed the state to
+ * \c FLAC__STREAM_DECODER_UNPARSEABLE_STREAM. Now the decoder instead
+ * drops sync and calls the error callback with a new error code
+ * \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM. This is
+ * more robust. If your error callback does not discriminate on the the
+ * error state, your code does not need to be changed.
+ *
+ * The encoder now has a new setting:
+ * FLAC__stream_encoder_set_apodization(). This is for setting the
+ * method used to window the data before LPC analysis. You only need to
+ * add a call to this function if the default is not suitable. There
+ * are also two new convenience functions that may be useful:
+ * FLAC__metadata_object_cuesheet_calculate_cddb_id() and
+ * FLAC__metadata_get_cuesheet().
+ *
+ * The \a bytes parameter to FLAC__StreamDecoderReadCallback,
+ * FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback
+ * is now \c size_t instead of \c unsigned.
+ */
+
+/** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4
+ * \ingroup porting
+ *
+ * \brief
+ * This module describes porting from FLAC 1.1.3 to FLAC 1.1.4.
+ *
+ * There were no changes to any of the interfaces from 1.1.3 to 1.1.4.
+ * There was a slight change in the implementation of
+ * FLAC__stream_encoder_set_metadata(); the function now makes a copy
+ * of the \a metadata array of pointers so the client no longer needs
+ * to maintain it after the call. The objects themselves that are
+ * pointed to by the array are still not copied though and must be
+ * maintained until the call to FLAC__stream_encoder_finish().
+ */
+
+/** \defgroup flac FLAC C API
+ *
+ * The FLAC C API is the interface to libFLAC, a set of structures
+ * describing the components of FLAC streams, and functions for
+ * encoding and decoding streams, as well as manipulating FLAC
+ * metadata in files.
+ *
+ * You should start with the format components as all other modules
+ * are dependent on it.
+ */
+
+#endif
diff --git a/src/FLAC/include/FLAC/assert.h b/src/FLAC/include/FLAC/assert.h
new file mode 100644
index 0000000..3fc03f3
--- /dev/null
+++ b/src/FLAC/include/FLAC/assert.h
@@ -0,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__ASSERT_H
+#define FLAC__ASSERT_H
+
+/* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */
+#ifdef DEBUG
+#include <assert.h>
+#define FLAC__ASSERT(x) assert(x)
+#define FLAC__ASSERT_DECLARATION(x) x
+#else
+#define FLAC__ASSERT(x)
+#define FLAC__ASSERT_DECLARATION(x)
+#endif
+
+#endif
diff --git a/src/FLAC/include/FLAC/callback.h b/src/FLAC/include/FLAC/callback.h
new file mode 100644
index 0000000..c954121
--- /dev/null
+++ b/src/FLAC/include/FLAC/callback.h
@@ -0,0 +1,184 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__CALLBACK_H
+#define FLAC__CALLBACK_H
+
+#include "ordinals.h"
+#include <stdlib.h> /* for size_t */
+
+/** \file include/FLAC/callback.h
+ *
+ * \brief
+ * This module defines the structures for describing I/O callbacks
+ * to the other FLAC interfaces.
+ *
+ * See the detailed documentation for callbacks in the
+ * \link flac_callbacks callbacks \endlink module.
+ */
+
+/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures
+ * \ingroup flac
+ *
+ * \brief
+ * This module defines the structures for describing I/O callbacks
+ * to the other FLAC interfaces.
+ *
+ * The purpose of the I/O callback functions is to create a common way
+ * for the metadata interfaces to handle I/O.
+ *
+ * Originally the metadata interfaces required filenames as the way of
+ * specifying FLAC files to operate on. This is problematic in some
+ * environments so there is an additional option to specify a set of
+ * callbacks for doing I/O on the FLAC file, instead of the filename.
+ *
+ * In addition to the callbacks, a FLAC__IOHandle type is defined as an
+ * opaque structure for a data source.
+ *
+ * The callback function prototypes are similar (but not identical) to the
+ * stdio functions fread, fwrite, fseek, ftell, feof, and fclose. If you use
+ * stdio streams to implement the callbacks, you can pass fread, fwrite, and
+ * fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or
+ * FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle
+ * is required. \warning You generally CANNOT directly use fseek or ftell
+ * for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems
+ * these use 32-bit offsets and FLAC requires 64-bit offsets to deal with
+ * large files. You will have to find an equivalent function (e.g. ftello),
+ * or write a wrapper. The same is true for feof() since this is usually
+ * implemented as a macro, not as a function whose address can be taken.
+ *
+ * \{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** This is the opaque handle type used by the callbacks. Typically
+ * this is a \c FILE* or address of a file descriptor.
+ */
+typedef void* FLAC__IOHandle;
+
+/** Signature for the read callback.
+ * The signature and semantics match POSIX fread() implementations
+ * and can generally be used interchangeably.
+ *
+ * \param ptr The address of the read buffer.
+ * \param size The size of the records to be read.
+ * \param nmemb The number of records to be read.
+ * \param handle The handle to the data source.
+ * \retval size_t
+ * The number of records read.
+ */
+typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
+
+/** Signature for the write callback.
+ * The signature and semantics match POSIX fwrite() implementations
+ * and can generally be used interchangeably.
+ *
+ * \param ptr The address of the write buffer.
+ * \param size The size of the records to be written.
+ * \param nmemb The number of records to be written.
+ * \param handle The handle to the data source.
+ * \retval size_t
+ * The number of records written.
+ */
+typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle);
+
+/** Signature for the seek callback.
+ * The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT
+ * EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long'
+ * and 32-bits wide.
+ *
+ * \param handle The handle to the data source.
+ * \param offset The new position, relative to \a whence
+ * \param whence \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END
+ * \retval int
+ * \c 0 on success, \c -1 on error.
+ */
+typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence);
+
+/** Signature for the tell callback.
+ * The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT
+ * EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long'
+ * and 32-bits wide.
+ *
+ * \param handle The handle to the data source.
+ * \retval FLAC__int64
+ * The current position on success, \c -1 on error.
+ */
+typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle);
+
+/** Signature for the EOF callback.
+ * The signature and semantics mostly match POSIX feof() but WATCHOUT:
+ * on many systems, feof() is a macro, so in this case a wrapper function
+ * must be provided instead.
+ *
+ * \param handle The handle to the data source.
+ * \retval int
+ * \c 0 if not at end of file, nonzero if at end of file.
+ */
+typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle);
+
+/** Signature for the close callback.
+ * The signature and semantics match POSIX fclose() implementations
+ * and can generally be used interchangeably.
+ *
+ * \param handle The handle to the data source.
+ * \retval int
+ * \c 0 on success, \c EOF on error.
+ */
+typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle);
+
+/** A structure for holding a set of callbacks.
+ * Each FLAC interface that requires a FLAC__IOCallbacks structure will
+ * describe which of the callbacks are required. The ones that are not
+ * required may be set to NULL.
+ *
+ * If the seek requirement for an interface is optional, you can signify that
+ * a data sorce is not seekable by setting the \a seek field to \c NULL.
+ */
+typedef struct {
+ FLAC__IOCallback_Read read;
+ FLAC__IOCallback_Write write;
+ FLAC__IOCallback_Seek seek;
+ FLAC__IOCallback_Tell tell;
+ FLAC__IOCallback_Eof eof;
+ FLAC__IOCallback_Close close;
+} FLAC__IOCallbacks;
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/FLAC/include/FLAC/export.h b/src/FLAC/include/FLAC/export.h
new file mode 100644
index 0000000..98d2d28
--- /dev/null
+++ b/src/FLAC/include/FLAC/export.h
@@ -0,0 +1,87 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__EXPORT_H
+#define FLAC__EXPORT_H
+
+/** \file include/FLAC/export.h
+ *
+ * \brief
+ * This module contains #defines and symbols for exporting function
+ * calls, and providing version information and compiled-in features.
+ *
+ * See the \link flac_export export \endlink module.
+ */
+
+/** \defgroup flac_export FLAC/export.h: export symbols
+ * \ingroup flac
+ *
+ * \brief
+ * This module contains #defines and symbols for exporting function
+ * calls, and providing version information and compiled-in features.
+ *
+ * \{
+ */
+
+#if defined(FLAC__NO_DLL) || !defined(_MSC_VER)
+#define FLAC_API
+
+#else
+
+#ifdef FLAC_API_EXPORTS
+#define FLAC_API _declspec(dllexport)
+#else
+#define FLAC_API _declspec(dllimport)
+
+#endif
+#endif
+
+/** These #defines will mirror the libtool-based library version number, see
+ * http://www.gnu.org/software/libtool/manual.html#Libtool-versioning
+ */
+#define FLAC_API_VERSION_CURRENT 8
+#define FLAC_API_VERSION_REVISION 1 /**< see above */
+#define FLAC_API_VERSION_AGE 0 /**< see above */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \c 1 if the library has been compiled with support for Ogg FLAC, else \c 0. */
+extern FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC;
+
+#ifdef __cplusplus
+}
+#endif
+
+/* \} */
+
+#endif
diff --git a/src/FLAC/include/FLAC/format.h b/src/FLAC/include/FLAC/format.h
new file mode 100644
index 0000000..9e744cd
--- /dev/null
+++ b/src/FLAC/include/FLAC/format.h
@@ -0,0 +1,995 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__FORMAT_H
+#define FLAC__FORMAT_H
+
+#include "export.h"
+#include "ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file include/FLAC/format.h
+ *
+ * \brief
+ * This module contains structure definitions for the representation
+ * of FLAC format components in memory. These are the basic
+ * structures used by the rest of the interfaces.
+ *
+ * See the detailed documentation in the
+ * \link flac_format format \endlink module.
+ */
+
+/** \defgroup flac_format FLAC/format.h: format components
+ * \ingroup flac
+ *
+ * \brief
+ * This module contains structure definitions for the representation
+ * of FLAC format components in memory. These are the basic
+ * structures used by the rest of the interfaces.
+ *
+ * First, you should be familiar with the
+ * <A HREF="../format.html">FLAC format</A>. Many of the values here
+ * follow directly from the specification. As a user of libFLAC, the
+ * interesting parts really are the structures that describe the frame
+ * header and metadata blocks.
+ *
+ * The format structures here are very primitive, designed to store
+ * information in an efficient way. Reading information from the
+ * structures is easy but creating or modifying them directly is
+ * more complex. For the most part, as a user of a library, editing
+ * is not necessary; however, for metadata blocks it is, so there are
+ * convenience functions provided in the \link flac_metadata metadata
+ * module \endlink to simplify the manipulation of metadata blocks.
+ *
+ * \note
+ * It's not the best convention, but symbols ending in _LEN are in bits
+ * and _LENGTH are in bytes. _LENGTH symbols are \#defines instead of
+ * global variables because they are usually used when declaring byte
+ * arrays and some compilers require compile-time knowledge of array
+ * sizes when declared on the stack.
+ *
+ * \{
+ */
+
+
+/*
+ Most of the values described in this file are defined by the FLAC
+ format specification. There is nothing to tune here.
+*/
+
+/** The largest legal metadata type code. */
+#define FLAC__MAX_METADATA_TYPE_CODE (126u)
+
+/** The minimum block size, in samples, permitted by the format. */
+#define FLAC__MIN_BLOCK_SIZE (16u)
+
+/** The maximum block size, in samples, permitted by the format. */
+#define FLAC__MAX_BLOCK_SIZE (65535u)
+
+/** The maximum block size, in samples, permitted by the FLAC subset for
+ * sample rates up to 48kHz. */
+#define FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ (4608u)
+
+/** The maximum number of channels permitted by the format. */
+#define FLAC__MAX_CHANNELS (8u)
+
+/** The minimum sample resolution permitted by the format. */
+#define FLAC__MIN_BITS_PER_SAMPLE (4u)
+
+/** The maximum sample resolution permitted by the format. */
+#define FLAC__MAX_BITS_PER_SAMPLE (32u)
+
+/** The maximum sample resolution permitted by libFLAC.
+ *
+ * \warning
+ * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format. However,
+ * the reference encoder/decoder is currently limited to 24 bits because
+ * of prevalent 32-bit math, so make sure and use this value when
+ * appropriate.
+ */
+#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (24u)
+
+/** The maximum sample rate permitted by the format. The value is
+ * ((2 ^ 16) - 1) * 10; see <A HREF="../format.html">FLAC format</A>
+ * as to why.
+ */
+#define FLAC__MAX_SAMPLE_RATE (655350u)
+
+/** The maximum LPC order permitted by the format. */
+#define FLAC__MAX_LPC_ORDER (32u)
+
+/** The maximum LPC order permitted by the FLAC subset for sample rates
+ * up to 48kHz. */
+#define FLAC__SUBSET_MAX_LPC_ORDER_48000HZ (12u)
+
+/** The minimum quantized linear predictor coefficient precision
+ * permitted by the format.
+ */
+#define FLAC__MIN_QLP_COEFF_PRECISION (5u)
+
+/** The maximum quantized linear predictor coefficient precision
+ * permitted by the format.
+ */
+#define FLAC__MAX_QLP_COEFF_PRECISION (15u)
+
+/** The maximum order of the fixed predictors permitted by the format. */
+#define FLAC__MAX_FIXED_ORDER (4u)
+
+/** The maximum Rice partition order permitted by the format. */
+#define FLAC__MAX_RICE_PARTITION_ORDER (15u)
+
+/** The maximum Rice partition order permitted by the FLAC Subset. */
+#define FLAC__SUBSET_MAX_RICE_PARTITION_ORDER (8u)
+
+/** The version string of the release, stamped onto the libraries and binaries.
+ *
+ * \note
+ * This does not correspond to the shared library version number, which
+ * is used to determine binary compatibility.
+ */
+extern FLAC_API const char *FLAC__VERSION_STRING;
+
+/** The vendor string inserted by the encoder into the VORBIS_COMMENT block.
+ * This is a NUL-terminated ASCII string; when inserted into the
+ * VORBIS_COMMENT the trailing null is stripped.
+ */
+extern FLAC_API const char *FLAC__VENDOR_STRING;
+
+/** The byte string representation of the beginning of a FLAC stream. */
+extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */
+
+/** The 32-bit integer big-endian representation of the beginning of
+ * a FLAC stream.
+ */
+extern FLAC_API const unsigned FLAC__STREAM_SYNC; /* = 0x664C6143 */
+
+/** The length of the FLAC signature in bits. */
+extern FLAC_API const unsigned FLAC__STREAM_SYNC_LEN; /* = 32 bits */
+
+/** The length of the FLAC signature in bytes. */
+#define FLAC__STREAM_SYNC_LENGTH (4u)
+
+
+/*****************************************************************************
+ *
+ * Subframe structures
+ *
+ *****************************************************************************/
+
+/*****************************************************************************/
+
+/** An enumeration of the available entropy coding methods. */
+typedef enum {
+ FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0
+ /**< Residual is coded by partitioning into contexts, each with it's own
+ * Rice parameter. */
+} FLAC__EntropyCodingMethodType;
+
+/** Maps a FLAC__EntropyCodingMethodType to a C string.
+ *
+ * Using a FLAC__EntropyCodingMethodType as the index to this array will
+ * give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[];
+
+
+/** Contents of a Rice partitioned residual
+ */
+typedef struct {
+
+ unsigned *parameters;
+ /**< The Rice parameters for each context. */
+
+ unsigned *raw_bits;
+ /**< Widths for escape-coded partitions. */
+
+ unsigned capacity_by_order;
+ /**< The capacity of the \a parameters and \a raw_bits arrays
+ * specified as an order, i.e. the number of array elements
+ * allocated is 2 ^ \a capacity_by_order.
+ */
+} FLAC__EntropyCodingMethod_PartitionedRiceContents;
+
+/** Header for a Rice partitioned residual. (c.f. <A HREF="../format.html#partitioned_rice">format specification</A>)
+ */
+typedef struct {
+
+ unsigned order;
+ /**< The partition order, i.e. # of contexts = 2 ^ \a order. */
+
+ const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents;
+ /**< The context's Rice parameters and/or raw bits. */
+
+} FLAC__EntropyCodingMethod_PartitionedRice;
+
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
+
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+/**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+
+/** Header for the entropy coding method. (c.f. <A HREF="../format.html#residual">format specification</A>)
+ */
+typedef struct {
+ FLAC__EntropyCodingMethodType type;
+ union {
+ FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice;
+ } data;
+} FLAC__EntropyCodingMethod;
+
+extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
+
+/*****************************************************************************/
+
+/** An enumeration of the available subframe types. */
+typedef enum {
+ FLAC__SUBFRAME_TYPE_CONSTANT = 0, /**< constant signal */
+ FLAC__SUBFRAME_TYPE_VERBATIM = 1, /**< uncompressed signal */
+ FLAC__SUBFRAME_TYPE_FIXED = 2, /**< fixed polynomial prediction */
+ FLAC__SUBFRAME_TYPE_LPC = 3 /**< linear prediction */
+} FLAC__SubframeType;
+
+/** Maps a FLAC__SubframeType to a C string.
+ *
+ * Using a FLAC__SubframeType as the index to this array will
+ * give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__SubframeTypeString[];
+
+
+/** CONSTANT subframe. (c.f. <A HREF="../format.html#subframe_constant">format specification</A>)
+ */
+typedef struct {
+ FLAC__int32 value; /**< The constant signal value. */
+} FLAC__Subframe_Constant;
+
+
+/** VERBATIM subframe. (c.f. <A HREF="../format.html#subframe_verbatim">format specification</A>)
+ */
+typedef struct {
+ const FLAC__int32 *data; /**< A pointer to verbatim signal. */
+} FLAC__Subframe_Verbatim;
+
+
+/** FIXED subframe. (c.f. <A HREF="../format.html#subframe_fixed">format specification</A>)
+ */
+typedef struct {
+ FLAC__EntropyCodingMethod entropy_coding_method;
+ /**< The residual coding method. */
+
+ unsigned order;
+ /**< The polynomial order. */
+
+ FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER];
+ /**< Warmup samples to prime the predictor, length == order. */
+
+ const FLAC__int32 *residual;
+ /**< The residual signal, length == (blocksize minus order) samples. */
+} FLAC__Subframe_Fixed;
+
+
+/** LPC subframe. (c.f. <A HREF="../format.html#subframe_lpc">format specification</A>)
+ */
+typedef struct {
+ FLAC__EntropyCodingMethod entropy_coding_method;
+ /**< The residual coding method. */
+
+ unsigned order;
+ /**< The FIR order. */
+
+ unsigned qlp_coeff_precision;
+ /**< Quantized FIR filter coefficient precision in bits. */
+
+ int quantization_level;
+ /**< The qlp coeff shift needed. */
+
+ FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
+ /**< FIR filter coefficients. */
+
+ FLAC__int32 warmup[FLAC__MAX_LPC_ORDER];
+ /**< Warmup samples to prime the predictor, length == order. */
+
+ const FLAC__int32 *residual;
+ /**< The residual signal, length == (blocksize minus order) samples. */
+} FLAC__Subframe_LPC;
+
+extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
+
+
+/** FLAC subframe structure. (c.f. <A HREF="../format.html#subframe">format specification</A>)
+ */
+typedef struct {
+ FLAC__SubframeType type;
+ union {
+ FLAC__Subframe_Constant constant;
+ FLAC__Subframe_Fixed fixed;
+ FLAC__Subframe_LPC lpc;
+ FLAC__Subframe_Verbatim verbatim;
+ } data;
+ unsigned wasted_bits;
+} FLAC__Subframe;
+
+extern FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */
+extern FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */
+
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */
+extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Frame structures
+ *
+ *****************************************************************************/
+
+/** An enumeration of the available channel assignments. */
+typedef enum {
+ FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, /**< independent channels */
+ FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, /**< left+side stereo */
+ FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, /**< right+side stereo */
+ FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 /**< mid+side stereo */
+} FLAC__ChannelAssignment;
+
+/** Maps a FLAC__ChannelAssignment to a C string.
+ *
+ * Using a FLAC__ChannelAssignment as the index to this array will
+ * give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__ChannelAssignmentString[];
+
+/** An enumeration of the possible frame numbering methods. */
+typedef enum {
+ FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, /**< number contains the frame number */
+ FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER /**< number contains the sample number of first sample in frame */
+} FLAC__FrameNumberType;
+
+/** Maps a FLAC__FrameNumberType to a C string.
+ *
+ * Using a FLAC__FrameNumberType as the index to this array will
+ * give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__FrameNumberTypeString[];
+
+
+/** FLAC frame header structure. (c.f. <A HREF="../format.html#frame_header">format specification</A>)
+ */
+typedef struct {
+ unsigned blocksize;
+ /**< The number of samples per subframe. */
+
+ unsigned sample_rate;
+ /**< The sample rate in Hz. */
+
+ unsigned channels;
+ /**< The number of channels (== number of subframes). */
+
+ FLAC__ChannelAssignment channel_assignment;
+ /**< The channel assignment for the frame. */
+
+ unsigned bits_per_sample;
+ /**< The sample resolution. */
+
+ FLAC__FrameNumberType number_type;
+ /**< The numbering scheme used for the frame. */
+
+ union {
+ FLAC__uint32 frame_number;
+ FLAC__uint64 sample_number;
+ } number;
+ /**< The frame number or sample number of first sample in frame;
+ * use the \a number_type value to determine which to use. */
+
+ FLAC__uint8 crc;
+ /**< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0)
+ * of the raw frame header bytes, meaning everything before the CRC byte
+ * including the sync code.
+ */
+} FLAC__FrameHeader;
+
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 2 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
+
+
+/** FLAC frame footer structure. (c.f. <A HREF="../format.html#frame_footer">format specification</A>)
+ */
+typedef struct {
+ FLAC__uint16 crc;
+ /**< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with
+ * 0) of the bytes before the crc, back to and including the frame header
+ * sync code.
+ */
+} FLAC__FrameFooter;
+
+extern FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
+
+
+/** FLAC frame structure. (c.f. <A HREF="../format.html#frame">format specification</A>)
+ */
+typedef struct {
+ FLAC__FrameHeader header;
+ FLAC__Subframe subframes[FLAC__MAX_CHANNELS];
+ FLAC__FrameFooter footer;
+} FLAC__Frame;
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Meta-data structures
+ *
+ *****************************************************************************/
+
+/** An enumeration of the available metadata block types. */
+typedef enum {
+
+ FLAC__METADATA_TYPE_STREAMINFO = 0,
+ /**< <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block */
+
+ FLAC__METADATA_TYPE_PADDING = 1,
+ /**< <A HREF="../format.html#metadata_block_padding">PADDING</A> block */
+
+ FLAC__METADATA_TYPE_APPLICATION = 2,
+ /**< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block */
+
+ FLAC__METADATA_TYPE_SEEKTABLE = 3,
+ /**< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block */
+
+ FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
+ /**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
+
+ FLAC__METADATA_TYPE_CUESHEET = 5,
+ /**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
+
+ FLAC__METADATA_TYPE_PICTURE = 6,
+ /**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
+
+ FLAC__METADATA_TYPE_UNDEFINED = 7
+ /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
+
+} FLAC__MetadataType;
+
+/** Maps a FLAC__MetadataType to a C string.
+ *
+ * Using a FLAC__MetadataType as the index to this array will
+ * give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__MetadataTypeString[];
+
+
+/** FLAC STREAMINFO structure. (c.f. <A HREF="../format.html#metadata_block_streaminfo">format specification</A>)
+ */
+typedef struct {
+ unsigned min_blocksize, max_blocksize;
+ unsigned min_framesize, max_framesize;
+ unsigned sample_rate;
+ unsigned channels;
+ unsigned bits_per_sample;
+ FLAC__uint64 total_samples;
+ FLAC__byte md5sum[16];
+} FLAC__StreamMetadata_StreamInfo;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
+
+/** The total stream length of the STREAMINFO block in bytes. */
+#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u)
+
+/** FLAC PADDING structure. (c.f. <A HREF="../format.html#metadata_block_padding">format specification</A>)
+ */
+typedef struct {
+ int dummy;
+ /**< Conceptually this is an empty struct since we don't store the
+ * padding bytes. Empty structs are not allowed by some C compilers,
+ * hence the dummy.
+ */
+} FLAC__StreamMetadata_Padding;
+
+
+/** FLAC APPLICATION structure. (c.f. <A HREF="../format.html#metadata_block_application">format specification</A>)
+ */
+typedef struct {
+ FLAC__byte id[4];
+ FLAC__byte *data;
+} FLAC__StreamMetadata_Application;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
+
+/** SeekPoint structure used in SEEKTABLE blocks. (c.f. <A HREF="../format.html#seekpoint">format specification</A>)
+ */
+typedef struct {
+ FLAC__uint64 sample_number;
+ /**< The sample number of the target frame. */
+
+ FLAC__uint64 stream_offset;
+ /**< The offset, in bytes, of the target frame with respect to
+ * beginning of the first frame. */
+
+ unsigned frame_samples;
+ /**< The number of samples in the target frame. */
+} FLAC__StreamMetadata_SeekPoint;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
+
+/** The total stream length of a seek point in bytes. */
+#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u)
+
+/** The value used in the \a sample_number field of
+ * FLAC__StreamMetadataSeekPoint used to indicate a placeholder
+ * point (== 0xffffffffffffffff).
+ */
+extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+
+
+/** FLAC SEEKTABLE structure. (c.f. <A HREF="../format.html#metadata_block_seektable">format specification</A>)
+ *
+ * \note From the format specification:
+ * - The seek points must be sorted by ascending sample number.
+ * - Each seek point's sample number must be the first sample of the
+ * target frame.
+ * - Each seek point's sample number must be unique within the table.
+ * - Existence of a SEEKTABLE block implies a correct setting of
+ * total_samples in the stream_info block.
+ * - Behavior is undefined when more than one SEEKTABLE block is
+ * present in a stream.
+ */
+typedef struct {
+ unsigned num_points;
+ FLAC__StreamMetadata_SeekPoint *points;
+} FLAC__StreamMetadata_SeekTable;
+
+
+/** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ *
+ * For convenience, the APIs maintain a trailing NUL character at the end of
+ * \a entry which is not counted toward \a length, i.e.
+ * \code strlen(entry) == length \endcode
+ */
+typedef struct {
+ FLAC__uint32 length;
+ FLAC__byte *entry;
+} FLAC__StreamMetadata_VorbisComment_Entry;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
+
+
+/** FLAC VORBIS_COMMENT structure. (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+ */
+typedef struct {
+ FLAC__StreamMetadata_VorbisComment_Entry vendor_string;
+ FLAC__uint32 num_comments;
+ FLAC__StreamMetadata_VorbisComment_Entry *comments;
+} FLAC__StreamMetadata_VorbisComment;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
+
+
+/** FLAC CUESHEET track index structure. (See the
+ * <A HREF="../format.html#cuesheet_track_index">format specification</A> for
+ * the full description of each field.)
+ */
+typedef struct {
+ FLAC__uint64 offset;
+ /**< Offset in samples, relative to the track offset, of the index
+ * point.
+ */
+
+ FLAC__byte number;
+ /**< The index point number. */
+} FLAC__StreamMetadata_CueSheet_Index;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
+
+
+/** FLAC CUESHEET track structure. (See the
+ * <A HREF="../format.html#cuesheet_track">format specification</A> for
+ * the full description of each field.)
+ */
+typedef struct {
+ FLAC__uint64 offset;
+ /**< Track offset in samples, relative to the beginning of the FLAC audio stream. */
+
+ FLAC__byte number;
+ /**< The track number. */
+
+ char isrc[13];
+ /**< Track ISRC. This is a 12-digit alphanumeric code plus a trailing \c NUL byte */
+
+ unsigned type:1;
+ /**< The track type: 0 for audio, 1 for non-audio. */
+
+ unsigned pre_emphasis:1;
+ /**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */
+
+ FLAC__byte num_indices;
+ /**< The number of track index points. */
+
+ FLAC__StreamMetadata_CueSheet_Index *indices;
+ /**< NULL if num_indices == 0, else pointer to array of index points. */
+
+} FLAC__StreamMetadata_CueSheet_Track;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
+
+
+/** FLAC CUESHEET structure. (See the
+ * <A HREF="../format.html#metadata_block_cuesheet">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+ char media_catalog_number[129];
+ /**< Media catalog number, in ASCII printable characters 0x20-0x7e. In
+ * general, the media catalog number may be 0 to 128 bytes long; any
+ * unused characters should be right-padded with NUL characters.
+ */
+
+ FLAC__uint64 lead_in;
+ /**< The number of lead-in samples. */
+
+ FLAC__bool is_cd;
+ /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */
+
+ unsigned num_tracks;
+ /**< The number of tracks. */
+
+ FLAC__StreamMetadata_CueSheet_Track *tracks;
+ /**< NULL if num_tracks == 0, else pointer to array of tracks. */
+
+} FLAC__StreamMetadata_CueSheet;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
+
+
+/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */
+typedef enum {
+ FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */
+ FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED
+} FLAC__StreamMetadata_Picture_Type;
+
+/** Maps a FLAC__StreamMetadata_Picture_Type to a C string.
+ *
+ * Using a FLAC__StreamMetadata_Picture_Type as the index to this array
+ * will give the string equivalent. The contents should not be
+ * modified.
+ */
+extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[];
+
+/** FLAC PICTURE structure. (See the
+ * <A HREF="../format.html#metadata_block_picture">format specification</A>
+ * for the full description of each field.)
+ */
+typedef struct {
+ FLAC__StreamMetadata_Picture_Type type;
+ /**< The kind of picture stored. */
+
+ char *mime_type;
+ /**< Picture data's MIME type, in ASCII printable characters
+ * 0x20-0x7e, NUL terminated. For best compatibility with players,
+ * use picture data of MIME type \c image/jpeg or \c image/png. A
+ * MIME type of '-->' is also allowed, in which case the picture
+ * data should be a complete URL. In file storage, the MIME type is
+ * stored as a 32-bit length followed by the ASCII string with no NUL
+ * terminator, but is converted to a plain C string in this structure
+ * for convenience.
+ */
+
+ FLAC__byte *description;
+ /**< Picture's description in UTF-8, NUL terminated. In file storage,
+ * the description is stored as a 32-bit length followed by the UTF-8
+ * string with no NUL terminator, but is converted to a plain C string
+ * in this structure for convenience.
+ */
+
+ FLAC__uint32 width;
+ /**< Picture's width in pixels. */
+
+ FLAC__uint32 height;
+ /**< Picture's height in pixels. */
+
+ FLAC__uint32 depth;
+ /**< Picture's color depth in bits-per-pixel. */
+
+ FLAC__uint32 colors;
+ /**< For indexed palettes (like GIF), picture's number of colors (the
+ * number of palette entries), or \c 0 for non-indexed (i.e. 2^depth).
+ */
+
+ FLAC__uint32 data_length;
+ /**< Length of binary picture data in bytes. */
+
+ FLAC__byte *data;
+ /**< Binary picture data. */
+
+} FLAC__StreamMetadata_Picture;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */
+
+
+/** Structure that is used when a metadata block of unknown type is loaded.
+ * The contents are opaque. The structure is used only internally to
+ * correctly handle unknown metadata.
+ */
+typedef struct {
+ FLAC__byte *data;
+} FLAC__StreamMetadata_Unknown;
+
+
+/** FLAC metadata block structure. (c.f. <A HREF="../format.html#metadata_block">format specification</A>)
+ */
+typedef struct {
+ FLAC__MetadataType type;
+ /**< The type of the metadata block; used determine which member of the
+ * \a data union to dereference. If type >= FLAC__METADATA_TYPE_UNDEFINED
+ * then \a data.unknown must be used. */
+
+ FLAC__bool is_last;
+ /**< \c true if this metadata block is the last, else \a false */
+
+ unsigned length;
+ /**< Length, in bytes, of the block data as it appears in the stream. */
+
+ union {
+ FLAC__StreamMetadata_StreamInfo stream_info;
+ FLAC__StreamMetadata_Padding padding;
+ FLAC__StreamMetadata_Application application;
+ FLAC__StreamMetadata_SeekTable seek_table;
+ FLAC__StreamMetadata_VorbisComment vorbis_comment;
+ FLAC__StreamMetadata_CueSheet cue_sheet;
+ FLAC__StreamMetadata_Picture picture;
+ FLAC__StreamMetadata_Unknown unknown;
+ } data;
+ /**< Polymorphic block data; use the \a type value to determine which
+ * to use. */
+} FLAC__StreamMetadata;
+
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
+extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
+
+/** The total stream length of a metadata block header in bytes. */
+#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u)
+
+/*****************************************************************************/
+
+
+/*****************************************************************************
+ *
+ * Utility functions
+ *
+ *****************************************************************************/
+
+/** Tests that a sample rate is valid for FLAC.
+ *
+ * \param sample_rate The sample rate to test for compliance.
+ * \retval FLAC__bool
+ * \c true if the given sample rate conforms to the specification, else
+ * \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate);
+
+/** Tests that a sample rate is valid for the FLAC subset. The subset rules
+ * for valid sample rates are slightly more complex since the rate has to
+ * be expressible completely in the frame header.
+ *
+ * \param sample_rate The sample rate to test for compliance.
+ * \retval FLAC__bool
+ * \c true if the given sample rate conforms to the specification for the
+ * subset, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate);
+
+/** Check a Vorbis comment entry name to see if it conforms to the Vorbis
+ * comment specification.
+ *
+ * Vorbis comment names must be composed only of characters from
+ * [0x20-0x3C,0x3E-0x7D].
+ *
+ * \param name A NUL-terminated string to be checked.
+ * \assert
+ * \code name != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name);
+
+/** Check a Vorbis comment entry value to see if it conforms to the Vorbis
+ * comment specification.
+ *
+ * Vorbis comment values must be valid UTF-8 sequences.
+ *
+ * \param value A string to be checked.
+ * \param length A the length of \a value in bytes. May be
+ * \c (unsigned)(-1) to indicate that \a value is a plain
+ * UTF-8 NUL-terminated string.
+ * \assert
+ * \code value != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length);
+
+/** Check a Vorbis comment entry to see if it conforms to the Vorbis
+ * comment specification.
+ *
+ * Vorbis comment entries must be of the form 'name=value', and 'name' and
+ * 'value' must be legal according to
+ * FLAC__format_vorbiscomment_entry_name_is_legal() and
+ * FLAC__format_vorbiscomment_entry_value_is_legal() respectively.
+ *
+ * \param entry An entry to be checked.
+ * \param length The length of \a entry in bytes.
+ * \assert
+ * \code value != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if entry name is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length);
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+/** Check a seek table to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * seek table.
+ *
+ * \param seek_table A pointer to a seek table to be checked.
+ * \assert
+ * \code seek_table != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if seek table is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table);
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+/** Sort a seek table's seek points according to the format specification.
+ * This includes a "unique-ification" step to remove duplicates, i.e.
+ * seek points with identical \a sample_number values. Duplicate seek
+ * points are converted into placeholder points and sorted to the end of
+ * the table.
+ *
+ * \param seek_table A pointer to a seek table to be sorted.
+ * \assert
+ * \code seek_table != NULL \endcode
+ * \retval unsigned
+ * The number of duplicate seek points converted into placeholders.
+ */
+FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * cue sheet.
+ *
+ * \param cue_sheet A pointer to an existing cue sheet to be checked.
+ * \param check_cd_da_subset If \c true, check CUESHEET against more
+ * stringent requirements for a CD-DA (audio) disc.
+ * \param violation Address of a pointer to a string. If there is a
+ * violation, a pointer to a string explanation of the
+ * violation will be returned here. \a violation may be
+ * \c NULL if you don't need the returned string. Do not
+ * free the returned string; it will always point to static
+ * data.
+ * \assert
+ * \code cue_sheet != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation);
+
+/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */
+/** Check picture data to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * PICTURE block.
+ *
+ * \param picture A pointer to existing picture data to be checked.
+ * \param violation Address of a pointer to a string. If there is a
+ * violation, a pointer to a string explanation of the
+ * violation will be returned here. \a violation may be
+ * \c NULL if you don't need the returned string. Do not
+ * free the returned string; it will always point to static
+ * data.
+ * \assert
+ * \code picture != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if picture data is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/FLAC/include/FLAC/metadata.h b/src/FLAC/include/FLAC/metadata.h
new file mode 100644
index 0000000..f9796ae
--- /dev/null
+++ b/src/FLAC/include/FLAC/metadata.h
@@ -0,0 +1,2112 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__METADATA_H
+#define FLAC__METADATA_H
+
+#include "export.h"
+#include "callback.h"
+#include "format.h"
+
+/* --------------------------------------------------------------------
+ (For an example of how all these routines are used, see the source
+ code for the unit tests in src/test_libFLAC/metadata_*.c, or
+ metaflac in src/metaflac/)
+ ------------------------------------------------------------------*/
+
+/** \file include/FLAC/metadata.h
+ *
+ * \brief
+ * This module provides functions for creating and manipulating FLAC
+ * metadata blocks in memory, and three progressively more powerful
+ * interfaces for traversing and editing metadata in FLAC files.
+ *
+ * See the detailed documentation for each interface in the
+ * \link flac_metadata metadata \endlink module.
+ */
+
+/** \defgroup flac_metadata FLAC/metadata.h: metadata interfaces
+ * \ingroup flac
+ *
+ * \brief
+ * This module provides functions for creating and manipulating FLAC
+ * metadata blocks in memory, and three progressively more powerful
+ * interfaces for traversing and editing metadata in native FLAC files.
+ * Note that currently only the Chain interface (level 2) supports Ogg
+ * FLAC files, and it is read-only i.e. no writing back changed
+ * metadata to file.
+ *
+ * There are three metadata interfaces of increasing complexity:
+ *
+ * Level 0:
+ * Read-only access to the STREAMINFO, VORBIS_COMMENT, CUESHEET, and
+ * PICTURE blocks.
+ *
+ * Level 1:
+ * Read-write access to all metadata blocks. This level is write-
+ * efficient in most cases (more on this below), and uses less memory
+ * than level 2.
+ *
+ * Level 2:
+ * Read-write access to all metadata blocks. This level is write-
+ * efficient in all cases, but uses more memory since all metadata for
+ * the whole file is read into memory and manipulated before writing
+ * out again.
+ *
+ * What do we mean by efficient? Since FLAC metadata appears at the
+ * beginning of the file, when writing metadata back to a FLAC file
+ * it is possible to grow or shrink the metadata such that the entire
+ * file must be rewritten. However, if the size remains the same during
+ * changes or PADDING blocks are utilized, only the metadata needs to be
+ * overwritten, which is much faster.
+ *
+ * Efficient means the whole file is rewritten at most one time, and only
+ * when necessary. Level 1 is not efficient only in the case that you
+ * cause more than one metadata block to grow or shrink beyond what can
+ * be accomodated by padding. In this case you should probably use level
+ * 2, which allows you to edit all the metadata for a file in memory and
+ * write it out all at once.
+ *
+ * All levels know how to skip over and not disturb an ID3v2 tag at the
+ * front of the file.
+ *
+ * All levels access files via their filenames. In addition, level 2
+ * has additional alternative read and write functions that take an I/O
+ * handle and callbacks, for situations where access by filename is not
+ * possible.
+ *
+ * In addition to the three interfaces, this module defines functions for
+ * creating and manipulating various metadata objects in memory. As we see
+ * from the Format module, FLAC metadata blocks in memory are very primitive
+ * structures for storing information in an efficient way. Reading
+ * information from the structures is easy but creating or modifying them
+ * directly is more complex. The metadata object routines here facilitate
+ * this by taking care of the consistency and memory management drudgery.
+ *
+ * Unless you will be using the level 1 or 2 interfaces to modify existing
+ * metadata however, you will not probably not need these.
+ *
+ * From a dependency standpoint, none of the encoders or decoders require
+ * the metadata module. This is so that embedded users can strip out the
+ * metadata module from libFLAC to reduce the size and complexity.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \defgroup flac_metadata_level0 FLAC/metadata.h: metadata level 0 interface
+ * \ingroup flac_metadata
+ *
+ * \brief
+ * The level 0 interface consists of individual routines to read the
+ * STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring
+ * only a filename.
+ *
+ * They try to skip any ID3v2 tag at the head of the file.
+ *
+ * \{
+ */
+
+/** Read the STREAMINFO metadata block of the given FLAC file. This function
+ * will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename The path to the FLAC file to read.
+ * \param streaminfo A pointer to space for the STREAMINFO block. Since
+ * FLAC__StreamMetadata is a simple structure with no
+ * memory allocation involved, you pass the address of
+ * an existing structure. It need not be initialized.
+ * \assert
+ * \code filename != NULL \endcode
+ * \code streaminfo != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid STREAMINFO block was read from \a filename. Returns
+ * \c false if there was a memory allocation error, a file decoder error,
+ * or the file contained no STREAMINFO block. (A memory allocation error
+ * is possible because this function must set up a file decoder.)
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo);
+
+/** Read the VORBIS_COMMENT metadata block of the given FLAC file. This
+ * function will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename The path to the FLAC file to read.
+ * \param tags The address where the returned pointer will be
+ * stored. The \a tags object must be deleted by
+ * the caller using FLAC__metadata_object_delete().
+ * \assert
+ * \code filename != NULL \endcode
+ * \code tags != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid VORBIS_COMMENT block was read from \a filename,
+ * and \a *tags will be set to the address of the metadata structure.
+ * Returns \c false if there was a memory allocation error, a file
+ * decoder error, or the file contained no VORBIS_COMMENT block, and
+ * \a *tags will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags);
+
+/** Read the CUESHEET metadata block of the given FLAC file. This
+ * function will try to skip any ID3v2 tag at the head of the file.
+ *
+ * \param filename The path to the FLAC file to read.
+ * \param cuesheet The address where the returned pointer will be
+ * stored. The \a cuesheet object must be deleted by
+ * the caller using FLAC__metadata_object_delete().
+ * \assert
+ * \code filename != NULL \endcode
+ * \code cuesheet != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid CUESHEET block was read from \a filename,
+ * and \a *cuesheet will be set to the address of the metadata
+ * structure. Returns \c false if there was a memory allocation
+ * error, a file decoder error, or the file contained no CUESHEET
+ * block, and \a *cuesheet will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet);
+
+/** Read a PICTURE metadata block of the given FLAC file. This
+ * function will try to skip any ID3v2 tag at the head of the file.
+ * Since there can be more than one PICTURE block in a file, this
+ * function takes a number of parameters that act as constraints to
+ * the search. The PICTURE block with the largest area matching all
+ * the constraints will be returned, or \a *picture will be set to
+ * \c NULL if there was no such block.
+ *
+ * \param filename The path to the FLAC file to read.
+ * \param picture The address where the returned pointer will be
+ * stored. The \a picture object must be deleted by
+ * the caller using FLAC__metadata_object_delete().
+ * \param type The desired picture type. Use \c -1 to mean
+ * "any type".
+ * \param mime_type The desired MIME type, e.g. "image/jpeg". The
+ * string will be matched exactly. Use \c NULL to
+ * mean "any MIME type".
+ * \param description The desired description. The string will be
+ * matched exactly. Use \c NULL to mean "any
+ * description".
+ * \param max_width The maximum width in pixels desired. Use
+ * \c (unsigned)(-1) to mean "any width".
+ * \param max_height The maximum height in pixels desired. Use
+ * \c (unsigned)(-1) to mean "any height".
+ * \param max_depth The maximum color depth in bits-per-pixel desired.
+ * Use \c (unsigned)(-1) to mean "any depth".
+ * \param max_colors The maximum number of colors desired. Use
+ * \c (unsigned)(-1) to mean "any number of colors".
+ * \assert
+ * \code filename != NULL \endcode
+ * \code picture != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid PICTURE block was read from \a filename,
+ * and \a *picture will be set to the address of the metadata
+ * structure. Returns \c false if there was a memory allocation
+ * error, a file decoder error, or the file contained no PICTURE
+ * block, and \a *picture will be set to \c NULL.
+ */
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_level1 FLAC/metadata.h: metadata level 1 interface
+ * \ingroup flac_metadata
+ *
+ * \brief
+ * The level 1 interface provides read-write access to FLAC file metadata and
+ * operates directly on the FLAC file.
+ *
+ * The general usage of this interface is:
+ *
+ * - Create an iterator using FLAC__metadata_simple_iterator_new()
+ * - Attach it to a file using FLAC__metadata_simple_iterator_init() and check
+ * the exit code. Call FLAC__metadata_simple_iterator_is_writable() to
+ * see if the file is writable, or only read access is allowed.
+ * - Use FLAC__metadata_simple_iterator_next() and
+ * FLAC__metadata_simple_iterator_prev() to traverse the blocks.
+ * This is does not read the actual blocks themselves.
+ * FLAC__metadata_simple_iterator_next() is relatively fast.
+ * FLAC__metadata_simple_iterator_prev() is slower since it needs to search
+ * forward from the front of the file.
+ * - Use FLAC__metadata_simple_iterator_get_block_type() or
+ * FLAC__metadata_simple_iterator_get_block() to access the actual data at
+ * the current iterator position. The returned object is yours to modify
+ * and free.
+ * - Use FLAC__metadata_simple_iterator_set_block() to write a modified block
+ * back. You must have write permission to the original file. Make sure to
+ * read the whole comment to FLAC__metadata_simple_iterator_set_block()
+ * below.
+ * - Use FLAC__metadata_simple_iterator_insert_block_after() to add new blocks.
+ * Use the object creation functions from
+ * \link flac_metadata_object here \endlink to generate new objects.
+ * - Use FLAC__metadata_simple_iterator_delete_block() to remove the block
+ * currently referred to by the iterator, or replace it with padding.
+ * - Destroy the iterator with FLAC__metadata_simple_iterator_delete() when
+ * finished.
+ *
+ * \note
+ * The FLAC file remains open the whole time between
+ * FLAC__metadata_simple_iterator_init() and
+ * FLAC__metadata_simple_iterator_delete(), so make sure you are not altering
+ * the file during this time.
+ *
+ * \note
+ * Do not modify the \a is_last, \a length, or \a type fields of returned
+ * FLAC__StreamMetadata objects. These are managed automatically.
+ *
+ * \note
+ * If any of the modification functions
+ * (FLAC__metadata_simple_iterator_set_block(),
+ * FLAC__metadata_simple_iterator_delete_block(),
+ * FLAC__metadata_simple_iterator_insert_block_after(), etc.) return \c false,
+ * you should delete the iterator as it may no longer be valid.
+ *
+ * \{
+ */
+
+struct FLAC__Metadata_SimpleIterator;
+/** The opaque structure definition for the level 1 iterator type.
+ * See the
+ * \link flac_metadata_level1 metadata level 1 module \endlink
+ * for a detailed description.
+ */
+typedef struct FLAC__Metadata_SimpleIterator FLAC__Metadata_SimpleIterator;
+
+/** Status type for FLAC__Metadata_SimpleIterator.
+ *
+ * The iterator's current status can be obtained by calling FLAC__metadata_simple_iterator_status().
+ */
+typedef enum {
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK = 0,
+ /**< The iterator is in the normal OK state */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT,
+ /**< The data passed into a function violated the function's usage criteria */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE,
+ /**< The iterator could not open the target file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE,
+ /**< The iterator could not find the FLAC signature at the start of the file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE,
+ /**< The iterator tried to write to a file that was not writable */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA,
+ /**< The iterator encountered input that does not conform to the FLAC metadata specification */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR,
+ /**< The iterator encountered an error while reading the FLAC file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR,
+ /**< The iterator encountered an error while seeking in the FLAC file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR,
+ /**< The iterator encountered an error while writing the FLAC file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR,
+ /**< The iterator encountered an error renaming the FLAC file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR,
+ /**< The iterator encountered an error removing the temporary file */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR,
+ /**< Memory allocation failed */
+
+ FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR
+ /**< The caller violated an assertion or an unexpected error occurred */
+
+} FLAC__Metadata_SimpleIteratorStatus;
+
+/** Maps a FLAC__Metadata_SimpleIteratorStatus to a C string.
+ *
+ * Using a FLAC__Metadata_SimpleIteratorStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[];
+
+
+/** Create a new iterator instance.
+ *
+ * \retval FLAC__Metadata_SimpleIterator*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void);
+
+/** Free an iterator instance. Deletes the object pointed to by \a iterator.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the current status of the iterator. Call this after a function
+ * returns \c false to get the reason for the error. Also resets the status
+ * to FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \retval FLAC__Metadata_SimpleIteratorStatus
+ * The current status of the iterator.
+ */
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Initialize the iterator to point to the first metadata block in the
+ * given FLAC file.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \param filename The path to the FLAC file.
+ * \param read_only If \c true, the FLAC file will be opened
+ * in read-only mode; if \c false, the FLAC
+ * file will be opened for edit even if no
+ * edits are performed.
+ * \param preserve_file_stats If \c true, the owner and modification
+ * time will be preserved even if the FLAC
+ * file is written to.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \code filename != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if a memory allocation error occurs, the file can't be
+ * opened, or another error occurs, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats);
+
+/** Returns \c true if the FLAC file is writable. If \c false, calls to
+ * FLAC__metadata_simple_iterator_set_block() and
+ * FLAC__metadata_simple_iterator_insert_block_after() will fail.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \retval FLAC__bool
+ * See above.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Moves the iterator forward one metadata block, returning \c false if
+ * already at the end.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ * \c false if already at the last metadata block of the chain, else
+ * \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Moves the iterator backward one metadata block, returning \c false if
+ * already at the beginning.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ * \c false if already at the first metadata block of the chain, else
+ * \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the type of the metadata block at the current position. This
+ * avoids reading the actual block data which can save time for large
+ * blocks.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__MetadataType
+ * The type of the metadata block at the current iterator position.
+ */
+
+FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator);
+
+/** Get the metadata block at the current position. You can modify the
+ * block but must use FLAC__metadata_simple_iterator_set_block() to
+ * write it back to the FLAC file.
+ *
+ * You must call FLAC__metadata_object_delete() on the returned object
+ * when you are finished with it.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__StreamMetadata*
+ * The current metadata block.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator);
+
+/** Write a block back to the FLAC file. This function tries to be
+ * as efficient as possible; how the block is actually written is
+ * shown by the following:
+ *
+ * Existing block is a STREAMINFO block and the new block is a
+ * STREAMINFO block: the new block is written in place. Make sure
+ * you know what you're doing when changing the values of a
+ * STREAMINFO block.
+ *
+ * Existing block is a STREAMINFO block and the new block is a
+ * not a STREAMINFO block: this is an error since the first block
+ * must be a STREAMINFO block. Returns \c false without altering the
+ * file.
+ *
+ * Existing block is not a STREAMINFO block and the new block is a
+ * STREAMINFO block: this is an error since there may be only one
+ * STREAMINFO block. Returns \c false without altering the file.
+ *
+ * Existing block and new block are the same length: the existing
+ * block will be replaced by the new block, written in place.
+ *
+ * Existing block is longer than new block: if use_padding is \c true,
+ * the existing block will be overwritten in place with the new
+ * block followed by a PADDING block, if possible, to make the total
+ * size the same as the existing block. Remember that a padding
+ * block requires at least four bytes so if the difference in size
+ * between the new block and existing block is less than that, the
+ * entire file will have to be rewritten, using the new block's
+ * exact size. If use_padding is \c false, the entire file will be
+ * rewritten, replacing the existing block by the new block.
+ *
+ * Existing block is shorter than new block: if use_padding is \c true,
+ * the function will try and expand the new block into the following
+ * PADDING block, if it exists and doing so won't shrink the PADDING
+ * block to less than 4 bytes. If there is no following PADDING
+ * block, or it will shrink to less than 4 bytes, or use_padding is
+ * \c false, the entire file is rewritten, replacing the existing block
+ * with the new block. Note that in this case any following PADDING
+ * block is preserved as is.
+ *
+ * After writing the block, the iterator will remain in the same
+ * place, i.e. pointing to the new block.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param block The block to set.
+ * \param use_padding See above.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \code block != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding);
+
+/** This is similar to FLAC__metadata_simple_iterator_set_block()
+ * except that instead of writing over an existing block, it appends
+ * a block after the existing block. \a use_padding is again used to
+ * tell the function to try an expand into following padding in an
+ * attempt to avoid rewriting the entire file.
+ *
+ * This function will fail and return \c false if given a STREAMINFO
+ * block.
+ *
+ * After writing the block, the iterator will be pointing to the
+ * new block.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param block The block to set.
+ * \param use_padding See above.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \code block != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding);
+
+/** Deletes the block at the current position. This will cause the
+ * entire FLAC file to be rewritten, unless \a use_padding is \c true,
+ * in which case the block will be replaced by an equal-sized PADDING
+ * block. The iterator will be left pointing to the block before the
+ * one just deleted.
+ *
+ * You may not delete the STREAMINFO block.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param use_padding See above.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_simple_iterator_init()
+ * \retval FLAC__bool
+ * \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_level2 FLAC/metadata.h: metadata level 2 interface
+ * \ingroup flac_metadata
+ *
+ * \brief
+ * The level 2 interface provides read-write access to FLAC file metadata;
+ * all metadata is read into memory, operated on in memory, and then written
+ * to file, which is more efficient than level 1 when editing multiple blocks.
+ *
+ * Currently Ogg FLAC is supported for read only, via
+ * FLAC__metadata_chain_read_ogg() but a subsequent
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * The general usage of this interface is:
+ *
+ * - Create a new chain using FLAC__metadata_chain_new(). A chain is a
+ * linked list of FLAC metadata blocks.
+ * - Read all metadata into the the chain from a FLAC file using
+ * FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and
+ * check the status.
+ * - Optionally, consolidate the padding using
+ * FLAC__metadata_chain_merge_padding() or
+ * FLAC__metadata_chain_sort_padding().
+ * - Create a new iterator using FLAC__metadata_iterator_new()
+ * - Initialize the iterator to point to the first element in the chain
+ * using FLAC__metadata_iterator_init()
+ * - Traverse the chain using FLAC__metadata_iterator_next and
+ * FLAC__metadata_iterator_prev().
+ * - Get a block for reading or modification using
+ * FLAC__metadata_iterator_get_block(). The pointer to the object
+ * inside the chain is returned, so the block is yours to modify.
+ * Changes will be reflected in the FLAC file when you write the
+ * chain. You can also add and delete blocks (see functions below).
+ * - When done, write out the chain using FLAC__metadata_chain_write().
+ * Make sure to read the whole comment to the function below.
+ * - Delete the chain using FLAC__metadata_chain_delete().
+ *
+ * \note
+ * Even though the FLAC file is not open while the chain is being
+ * manipulated, you must not alter the file externally during
+ * this time. The chain assumes the FLAC file will not change
+ * between the time of FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg()
+ * and FLAC__metadata_chain_write().
+ *
+ * \note
+ * Do not modify the is_last, length, or type fields of returned
+ * FLAC__StreamMetadata objects. These are managed automatically.
+ *
+ * \note
+ * The metadata objects returned by FLAC__metadata_iterator_get_block()
+ * are owned by the chain; do not FLAC__metadata_object_delete() them.
+ * In the same way, blocks passed to FLAC__metadata_iterator_set_block()
+ * become owned by the chain and they will be deleted when the chain is
+ * deleted.
+ *
+ * \{
+ */
+
+struct FLAC__Metadata_Chain;
+/** The opaque structure definition for the level 2 chain type.
+ */
+typedef struct FLAC__Metadata_Chain FLAC__Metadata_Chain;
+
+struct FLAC__Metadata_Iterator;
+/** The opaque structure definition for the level 2 iterator type.
+ */
+typedef struct FLAC__Metadata_Iterator FLAC__Metadata_Iterator;
+
+typedef enum {
+ FLAC__METADATA_CHAIN_STATUS_OK = 0,
+ /**< The chain is in the normal OK state */
+
+ FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT,
+ /**< The data passed into a function violated the function's usage criteria */
+
+ FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE,
+ /**< The chain could not open the target file */
+
+ FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE,
+ /**< The chain could not find the FLAC signature at the start of the file */
+
+ FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE,
+ /**< The chain tried to write to a file that was not writable */
+
+ FLAC__METADATA_CHAIN_STATUS_BAD_METADATA,
+ /**< The chain encountered input that does not conform to the FLAC metadata specification */
+
+ FLAC__METADATA_CHAIN_STATUS_READ_ERROR,
+ /**< The chain encountered an error while reading the FLAC file */
+
+ FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR,
+ /**< The chain encountered an error while seeking in the FLAC file */
+
+ FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR,
+ /**< The chain encountered an error while writing the FLAC file */
+
+ FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR,
+ /**< The chain encountered an error renaming the FLAC file */
+
+ FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR,
+ /**< The chain encountered an error removing the temporary file */
+
+ FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR,
+ /**< Memory allocation failed */
+
+ FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR,
+ /**< The caller violated an assertion or an unexpected error occurred */
+
+ FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS,
+ /**< One or more of the required callbacks was NULL */
+
+ FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH,
+ /**< FLAC__metadata_chain_write() was called on a chain read by
+ * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ * or
+ * FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile()
+ * was called on a chain read by
+ * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+ * Matching read/write methods must always be used. */
+
+ FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL
+ /**< FLAC__metadata_chain_write_with_callbacks() was called when the
+ * chain write requires a tempfile; use
+ * FLAC__metadata_chain_write_with_callbacks_and_tempfile() instead.
+ * Or, FLAC__metadata_chain_write_with_callbacks_and_tempfile() was
+ * called when the chain write does not require a tempfile; use
+ * FLAC__metadata_chain_write_with_callbacks() instead.
+ * Always check FLAC__metadata_chain_check_if_tempfile_needed()
+ * before writing via callbacks. */
+
+} FLAC__Metadata_ChainStatus;
+
+/** Maps a FLAC__Metadata_ChainStatus to a C string.
+ *
+ * Using a FLAC__Metadata_ChainStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__Metadata_ChainStatusString[];
+
+/*********** FLAC__Metadata_Chain ***********/
+
+/** Create a new chain instance.
+ *
+ * \retval FLAC__Metadata_Chain*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void);
+
+/** Free a chain instance. Deletes the object pointed to by \a chain.
+ *
+ * \param chain A pointer to an existing chain.
+ * \assert
+ * \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain);
+
+/** Get the current status of the chain. Call this after a function
+ * returns \c false to get the reason for the error. Also resets the
+ * status to FLAC__METADATA_CHAIN_STATUS_OK.
+ *
+ * \param chain A pointer to an existing chain.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__Metadata_ChainStatus
+ * The current status of the chain.
+ */
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain);
+
+/** Read all metadata from a FLAC file into the chain.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param filename The path to the FLAC file to read.
+ * \assert
+ * \code chain != NULL \endcode
+ * \code filename != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid list of metadata blocks was read from
+ * \a filename, else \c false. On failure, check the status with
+ * FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename);
+
+/*@@@@ add to unit tests*/
+/** Read all metadata from an Ogg FLAC file into the chain.
+ *
+ * \note Ogg FLAC metadata data writing is not supported yet and
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param filename The path to the Ogg FLAC file to read.
+ * \assert
+ * \code chain != NULL \endcode
+ * \code filename != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid list of metadata blocks was read from
+ * \a filename, else \c false. On failure, check the status with
+ * FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename);
+
+/** Read all metadata from a FLAC stream into the chain via I/O callbacks.
+ *
+ * The \a handle need only be open for reading, but must be seekable.
+ * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ * for Windows).
+ *
+ * \param chain A pointer to an existing chain.
+ * \param handle The I/O handle of the FLAC stream to read. The
+ * handle will NOT be closed after the metadata is read;
+ * that is the duty of the caller.
+ * \param callbacks
+ * A set of callbacks to use for I/O. The mandatory
+ * callbacks are \a read, \a seek, and \a tell.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid list of metadata blocks was read from
+ * \a handle, else \c false. On failure, check the status with
+ * FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/*@@@@ add to unit tests*/
+/** Read all metadata from an Ogg FLAC stream into the chain via I/O callbacks.
+ *
+ * The \a handle need only be open for reading, but must be seekable.
+ * The equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ * for Windows).
+ *
+ * \note Ogg FLAC metadata data writing is not supported yet and
+ * FLAC__metadata_chain_write() will fail.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param handle The I/O handle of the Ogg FLAC stream to read. The
+ * handle will NOT be closed after the metadata is read;
+ * that is the duty of the caller.
+ * \param callbacks
+ * A set of callbacks to use for I/O. The mandatory
+ * callbacks are \a read, \a seek, and \a tell.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if a valid list of metadata blocks was read from
+ * \a handle, else \c false. On failure, check the status with
+ * FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Checks if writing the given chain would require the use of a
+ * temporary file, or if it could be written in place.
+ *
+ * Under certain conditions, padding can be utilized so that writing
+ * edited metadata back to the FLAC file does not require rewriting the
+ * entire file. If rewriting is required, then a temporary workfile is
+ * required. When writing metadata using callbacks, you must check
+ * this function to know whether to call
+ * FLAC__metadata_chain_write_with_callbacks() or
+ * FLAC__metadata_chain_write_with_callbacks_and_tempfile(). When
+ * writing with FLAC__metadata_chain_write(), the temporary file is
+ * handled internally.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param use_padding
+ * Whether or not padding will be allowed to be used
+ * during the write. The value of \a use_padding given
+ * here must match the value later passed to
+ * FLAC__metadata_chain_write_with_callbacks() or
+ * FLAC__metadata_chain_write_with_callbacks_with_tempfile().
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if writing the current chain would require a tempfile, or
+ * \c false if metadata can be written in place.
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding);
+
+/** Write all metadata out to the FLAC file. This function tries to be as
+ * efficient as possible; how the metadata is actually written is shown by
+ * the following:
+ *
+ * If the current chain is the same size as the existing metadata, the new
+ * data is written in place.
+ *
+ * If the current chain is longer than the existing metadata, and
+ * \a use_padding is \c true, and the last block is a PADDING block of
+ * sufficient length, the function will truncate the final padding block
+ * so that the overall size of the metadata is the same as the existing
+ * metadata, and then just rewrite the metadata. Otherwise, if not all of
+ * the above conditions are met, the entire FLAC file must be rewritten.
+ * If you want to use padding this way it is a good idea to call
+ * FLAC__metadata_chain_sort_padding() first so that you have the maximum
+ * amount of padding to work with, unless you need to preserve ordering
+ * of the PADDING blocks for some reason.
+ *
+ * If the current chain is shorter than the existing metadata, and
+ * \a use_padding is \c true, and the final block is a PADDING block, the padding
+ * is extended to make the overall size the same as the existing data. If
+ * \a use_padding is \c true and the last block is not a PADDING block, a new
+ * PADDING block is added to the end of the new data to make it the same
+ * size as the existing data (if possible, see the note to
+ * FLAC__metadata_simple_iterator_set_block() about the four byte limit)
+ * and the new data is written in place. If none of the above apply or
+ * \a use_padding is \c false, the entire FLAC file is rewritten.
+ *
+ * If \a preserve_file_stats is \c true, the owner and modification time will
+ * be preserved even if the FLAC file is written.
+ *
+ * For this write function to be used, the chain must have been read with
+ * FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg(), not
+ * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks().
+ *
+ * \param chain A pointer to an existing chain.
+ * \param use_padding See above.
+ * \param preserve_file_stats See above.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if the write succeeded, else \c false. On failure,
+ * check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats);
+
+/** Write all metadata out to a FLAC stream via callbacks.
+ *
+ * (See FLAC__metadata_chain_write() for the details on how padding is
+ * used to write metadata in place if possible.)
+ *
+ * The \a handle must be open for updating and be seekable. The
+ * equivalent minimum stdio fopen() file mode is \c "r+" (or \c "r+b"
+ * for Windows).
+ *
+ * For this write function to be used, the chain must have been read with
+ * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+ * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
+ * \c false.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param use_padding See FLAC__metadata_chain_write()
+ * \param handle The I/O handle of the FLAC stream to write. The
+ * handle will NOT be closed after the metadata is
+ * written; that is the duty of the caller.
+ * \param callbacks A set of callbacks to use for I/O. The mandatory
+ * callbacks are \a write and \a seek.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if the write succeeded, else \c false. On failure,
+ * check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks);
+
+/** Write all metadata out to a FLAC stream via callbacks.
+ *
+ * (See FLAC__metadata_chain_write() for the details on how padding is
+ * used to write metadata in place if possible.)
+ *
+ * This version of the write-with-callbacks function must be used when
+ * FLAC__metadata_chain_check_if_tempfile_needed() returns true. In
+ * this function, you must supply an I/O handle corresponding to the
+ * FLAC file to edit, and a temporary handle to which the new FLAC
+ * file will be written. It is the caller's job to move this temporary
+ * FLAC file on top of the original FLAC file to complete the metadata
+ * edit.
+ *
+ * The \a handle must be open for reading and be seekable. The
+ * equivalent minimum stdio fopen() file mode is \c "r" (or \c "rb"
+ * for Windows).
+ *
+ * The \a temp_handle must be open for writing. The
+ * equivalent minimum stdio fopen() file mode is \c "w" (or \c "wb"
+ * for Windows). It should be an empty stream, or at least positioned
+ * at the start-of-file (in which case it is the caller's duty to
+ * truncate it on return).
+ *
+ * For this write function to be used, the chain must have been read with
+ * FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
+ * not FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
+ * Also, FLAC__metadata_chain_check_if_tempfile_needed() must have returned
+ * \c true.
+ *
+ * \param chain A pointer to an existing chain.
+ * \param use_padding See FLAC__metadata_chain_write()
+ * \param handle The I/O handle of the original FLAC stream to read.
+ * The handle will NOT be closed after the metadata is
+ * written; that is the duty of the caller.
+ * \param callbacks A set of callbacks to use for I/O on \a handle.
+ * The mandatory callbacks are \a read, \a seek, and
+ * \a eof.
+ * \param temp_handle The I/O handle of the FLAC stream to write. The
+ * handle will NOT be closed after the metadata is
+ * written; that is the duty of the caller.
+ * \param temp_callbacks
+ * A set of callbacks to use for I/O on temp_handle.
+ * The only mandatory callback is \a write.
+ * \assert
+ * \code chain != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if the write succeeded, else \c false. On failure,
+ * check the status with FLAC__metadata_chain_status().
+ */
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks);
+
+/** Merge adjacent PADDING blocks into a single block.
+ *
+ * \note This function does not write to the FLAC file, it only
+ * modifies the chain.
+ *
+ * \warning Any iterator on the current chain will become invalid after this
+ * call. You should delete the iterator and get a new one.
+ *
+ * \param chain A pointer to an existing chain.
+ * \assert
+ * \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain);
+
+/** This function will move all PADDING blocks to the end on the metadata,
+ * then merge them into a single block.
+ *
+ * \note This function does not write to the FLAC file, it only
+ * modifies the chain.
+ *
+ * \warning Any iterator on the current chain will become invalid after this
+ * call. You should delete the iterator and get a new one.
+ *
+ * \param chain A pointer to an existing chain.
+ * \assert
+ * \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain);
+
+
+/*********** FLAC__Metadata_Iterator ***********/
+
+/** Create a new iterator instance.
+ *
+ * \retval FLAC__Metadata_Iterator*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void);
+
+/** Free an iterator instance. Deletes the object pointed to by \a iterator.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator);
+
+/** Initialize the iterator to point to the first metadata block in the
+ * given chain.
+ *
+ * \param iterator A pointer to an existing iterator.
+ * \param chain A pointer to an existing and initialized (read) chain.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \code chain != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain);
+
+/** Moves the iterator forward one metadata block, returning \c false if
+ * already at the end.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ * \c false if already at the last metadata block of the chain, else
+ * \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator);
+
+/** Moves the iterator backward one metadata block, returning \c false if
+ * already at the beginning.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ * \c false if already at the first metadata block of the chain, else
+ * \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator);
+
+/** Get the type of the metadata block at the current position.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__MetadataType
+ * The type of the metadata block at the current iterator position.
+ */
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator);
+
+/** Get the metadata block at the current position. You can modify
+ * the block in place but must write the chain before the changes
+ * are reflected to the FLAC file. You do not need to call
+ * FLAC__metadata_iterator_set_block() to reflect the changes;
+ * the pointer returned by FLAC__metadata_iterator_get_block()
+ * points directly into the chain.
+ *
+ * \warning
+ * Do not call FLAC__metadata_object_delete() on the returned object;
+ * to delete a block use FLAC__metadata_iterator_delete_block().
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__StreamMetadata*
+ * The current metadata block.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator);
+
+/** Set the metadata block at the current position, replacing the existing
+ * block. The new block passed in becomes owned by the chain and it will be
+ * deleted when the chain is deleted.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param block A pointer to a metadata block.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \code block != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the conditions in the above description are not met, or
+ * a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/** Removes the current block from the chain. If \a replace_with_padding is
+ * \c true, the block will instead be replaced with a padding block of equal
+ * size. You can not delete the STREAMINFO block. The iterator will be
+ * left pointing to the block before the one just "deleted", even if
+ * \a replace_with_padding is \c true.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param replace_with_padding See above.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ * \c false if the conditions in the above description are not met,
+ * otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding);
+
+/** Insert a new block before the current block. You cannot insert a block
+ * before the first STREAMINFO block. You cannot insert a STREAMINFO block
+ * as there can be only one, the one that already exists at the head when you
+ * read in a chain. The chain takes ownership of the new block and it will be
+ * deleted when the chain is deleted. The iterator will be left pointing to
+ * the new block.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param block A pointer to a metadata block to insert.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ * \c false if the conditions in the above description are not met, or
+ * a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/** Insert a new block after the current block. You cannot insert a STREAMINFO
+ * block as there can be only one, the one that already exists at the head when
+ * you read in a chain. The chain takes ownership of the new block and it will
+ * be deleted when the chain is deleted. The iterator will be left pointing to
+ * the new block.
+ *
+ * \param iterator A pointer to an existing initialized iterator.
+ * \param block A pointer to a metadata block to insert.
+ * \assert
+ * \code iterator != NULL \endcode
+ * \a iterator has been successfully initialized with
+ * FLAC__metadata_iterator_init()
+ * \retval FLAC__bool
+ * \c false if the conditions in the above description are not met, or
+ * a memory allocation error occurs, otherwise \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block);
+
+/* \} */
+
+
+/** \defgroup flac_metadata_object FLAC/metadata.h: metadata object methods
+ * \ingroup flac_metadata
+ *
+ * \brief
+ * This module contains methods for manipulating FLAC metadata objects.
+ *
+ * Since many are variable length we have to be careful about the memory
+ * management. We decree that all pointers to data in the object are
+ * owned by the object and memory-managed by the object.
+ *
+ * Use the FLAC__metadata_object_new() and FLAC__metadata_object_delete()
+ * functions to create all instances. When using the
+ * FLAC__metadata_object_set_*() functions to set pointers to data, set
+ * \a copy to \c true to have the function make it's own copy of the data, or
+ * to \c false to give the object ownership of your data. In the latter case
+ * your pointer must be freeable by free() and will be free()d when the object
+ * is FLAC__metadata_object_delete()d. It is legal to pass a null pointer as
+ * the data pointer to a FLAC__metadata_object_set_*() function as long as
+ * the length argument is 0 and the \a copy argument is \c false.
+ *
+ * The FLAC__metadata_object_new() and FLAC__metadata_object_clone() function
+ * will return \c NULL in the case of a memory allocation error, otherwise a new
+ * object. The FLAC__metadata_object_set_*() functions return \c false in the
+ * case of a memory allocation error.
+ *
+ * We don't have the convenience of C++ here, so note that the library relies
+ * on you to keep the types straight. In other words, if you pass, for
+ * example, a FLAC__StreamMetadata* that represents a STREAMINFO block to
+ * FLAC__metadata_object_application_set_data(), you will get an assertion
+ * failure.
+ *
+ * For convenience the FLAC__metadata_object_vorbiscomment_*() functions
+ * maintain a trailing NUL on each Vorbis comment entry. This is not counted
+ * toward the length or stored in the stream, but it can make working with plain
+ * comments (those that don't contain embedded-NULs in the value) easier.
+ * Entries passed into these functions have trailing NULs added if missing, and
+ * returned entries are guaranteed to have a trailing NUL.
+ *
+ * The FLAC__metadata_object_vorbiscomment_*() functions that take a Vorbis
+ * comment entry/name/value will first validate that it complies with the Vorbis
+ * comment specification and return false if it does not.
+ *
+ * There is no need to recalculate the length field on metadata blocks you
+ * have modified. They will be calculated automatically before they are
+ * written back to a file.
+ *
+ * \{
+ */
+
+
+/** Create a new metadata object instance of the given type.
+ *
+ * The object will be "empty"; i.e. values and data pointers will be \c 0,
+ * with the exception of FLAC__METADATA_TYPE_VORBIS_COMMENT, which will have
+ * the vendor string set (but zero comments).
+ *
+ * Do not pass in a value greater than or equal to
+ * \a FLAC__METADATA_TYPE_UNDEFINED unless you really know what you're
+ * doing.
+ *
+ * \param type Type of object to create
+ * \retval FLAC__StreamMetadata*
+ * \c NULL if there was an error allocating memory or the type code is
+ * greater than FLAC__MAX_METADATA_TYPE_CODE, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type);
+
+/** Create a copy of an existing metadata object.
+ *
+ * The copy is a "deep" copy, i.e. dynamically allocated data within the
+ * object is also copied. The caller takes ownership of the new block and
+ * is responsible for freeing it with FLAC__metadata_object_delete().
+ *
+ * \param object Pointer to object to copy.
+ * \assert
+ * \code object != NULL \endcode
+ * \retval FLAC__StreamMetadata*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object);
+
+/** Free a metadata object. Deletes the object pointed to by \a object.
+ *
+ * The delete is a "deep" delete, i.e. dynamically allocated data within the
+ * object is also deleted.
+ *
+ * \param object A pointer to an existing object.
+ * \assert
+ * \code object != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object);
+
+/** Compares two metadata objects.
+ *
+ * The compare is "deep", i.e. dynamically allocated data within the
+ * object is also compared.
+ *
+ * \param block1 A pointer to an existing object.
+ * \param block2 A pointer to an existing object.
+ * \assert
+ * \code block1 != NULL \endcode
+ * \code block2 != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if objects are identical, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2);
+
+/** Sets the application data of an APPLICATION block.
+ *
+ * If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ * takes ownership of the pointer. The existing data will be freed if this
+ * function is successful, otherwise the original data will remain if \a copy
+ * is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
+ * \param object A pointer to an existing APPLICATION object.
+ * \param data A pointer to the data to set.
+ * \param length The length of \a data in bytes.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_APPLICATION \endcode
+ * \code (data != NULL && length > 0) ||
+ * (data == NULL && length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy);
+
+/** Resize the seekpoint array.
+ *
+ * If the size shrinks, elements will truncated; if it grows, new placeholder
+ * points will be added to the end.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param new_num_points The desired length of the array; may be \c 0.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code (object->data.seek_table.points == NULL && object->data.seek_table.num_points == 0) ||
+ * (object->data.seek_table.points != NULL && object->data.seek_table.num_points > 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points);
+
+/** Set a seekpoint in a seektable.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param point_num Index into seekpoint array to set.
+ * \param point The point to set.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code object->data.seek_table.num_points > point_num \endcode
+ */
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
+
+/** Insert a seekpoint into a seektable.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param point_num Index into seekpoint array to set.
+ * \param point The point to set.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code object->data.seek_table.num_points >= point_num \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
+
+/** Delete a seekpoint from a seektable.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param point_num Index into seekpoint array to set.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code object->data.seek_table.num_points > point_num \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num);
+
+/** Check a seektable to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * seektable.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ * \c false if seek table is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object);
+
+/** Append a number of placeholder points to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param num The number of placeholder points to append.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num);
+
+/** Append a specific seek point template to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param sample_number The sample number of the seek point template.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number);
+
+/** Append specific seek point templates to the end of a seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param sample_numbers An array of sample numbers for the seek points.
+ * \param num The number of seek point templates to append.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num);
+
+/** Append a set of evenly-spaced seek point templates to the end of a
+ * seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param num The number of placeholder points to append.
+ * \param total_samples The total number of samples to be encoded;
+ * the seekpoints will be spaced approximately
+ * \a total_samples / \a num samples apart.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code total_samples > 0 \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples);
+
+/** Append a set of evenly-spaced seek point templates to the end of a
+ * seek table.
+ *
+ * \note
+ * As with the other ..._seektable_template_... functions, you should
+ * call FLAC__metadata_object_seektable_template_sort() when finished
+ * to make the seek table legal.
+ *
+ * \param object A pointer to an existing SEEKTABLE object.
+ * \param samples The number of samples apart to space the placeholder
+ * points. The first point will be at sample \c 0, the
+ * second at sample \a samples, then 2*\a samples, and
+ * so on. As long as \a samples and \a total_samples
+ * are greater than \c 0, there will always be at least
+ * one seekpoint at sample \c 0.
+ * \param total_samples The total number of samples to be encoded;
+ * the seekpoints will be spaced
+ * \a samples samples apart.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \code samples > 0 \endcode
+ * \code total_samples > 0 \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples);
+
+/** Sort a seek table's seek points according to the format specification,
+ * removing duplicates.
+ *
+ * \param object A pointer to a seek table to be sorted.
+ * \param compact If \c false, behaves like FLAC__format_seektable_sort().
+ * If \c true, duplicates are deleted and the seek table is
+ * shrunk appropriately; the number of placeholder points
+ * present in the seek table will be the same after the call
+ * as before.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact);
+
+/** Sets the vendor string in a VORBIS_COMMENT block.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param entry The entry to set the vendor string to.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Resize the comment array.
+ *
+ * If the size shrinks, elements will truncated; if it grows, new empty
+ * fields will be added to the end.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param new_num_comments The desired length of the array; may be \c 0.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code (object->data.vorbis_comment.comments == NULL && object->data.vorbis_comment.num_comments == 0) ||
+ * (object->data.vorbis_comment.comments != NULL && object->data.vorbis_comment.num_comments > 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments);
+
+/** Sets a comment in a VORBIS_COMMENT block.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num Index into comment array to set.
+ * \param entry The entry to set the comment to.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code comment_num < object->data.vorbis_comment.num_comments \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Insert a comment in a VORBIS_COMMENT block at the given index.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num The index at which to insert the comment. The comments
+ * at and after \a comment_num move right one position.
+ * To append a comment to the end, set \a comment_num to
+ * \c object->data.vorbis_comment.num_comments .
+ * \param entry The comment to insert.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code object->data.vorbis_comment.num_comments >= comment_num \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Appends a comment to a VORBIS_COMMENT block.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param entry The comment to insert.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+
+/** Replaces comments in a VORBIS_COMMENT block with a new one.
+ *
+ * For convenience, a trailing NUL is added to the entry if it doesn't have
+ * one already.
+ *
+ * Depending on the the value of \a all, either all or just the first comment
+ * whose field name(s) match the given entry's name will be replaced by the
+ * given entry. If no comments match, \a entry will simply be appended.
+ *
+ * If \a copy is \c true, a copy of the entry is stored; otherwise, the object
+ * takes ownership of the \c entry.entry pointer.
+ *
+ * \note If this function returns \c false, the caller still owns the
+ * pointer.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param entry The comment to insert.
+ * \param all If \c true, all comments whose field name matches
+ * \a entry's field name will be removed, and \a entry will
+ * be inserted at the position of the first matching
+ * comment. If \c false, only the first comment whose
+ * field name matches \a entry's field name will be
+ * replaced with \a entry.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code (entry.entry != NULL && entry.length > 0) ||
+ * (entry.entry == NULL && entry.length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy);
+
+/** Delete a comment in a VORBIS_COMMENT block at the given index.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param comment_num The index of the comment to delete.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code object->data.vorbis_comment.num_comments > comment_num \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num);
+
+/** Creates a Vorbis comment entry from NUL-terminated name and value strings.
+ *
+ * On return, the filled-in \a entry->entry pointer will point to malloc()ed
+ * memory and shall be owned by the caller. For convenience the entry will
+ * have a terminating NUL.
+ *
+ * \param entry A pointer to a Vorbis comment entry. The entry's
+ * \c entry pointer should not point to allocated
+ * memory as it will be overwritten.
+ * \param field_name The field name in ASCII, \c NUL terminated.
+ * \param field_value The field value in UTF-8, \c NUL terminated.
+ * \assert
+ * \code entry != NULL \endcode
+ * \code field_name != NULL \endcode
+ * \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if malloc() fails, or if \a field_name or \a field_value does
+ * not comply with the Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value);
+
+/** Splits a Vorbis comment entry into NUL-terminated name and value strings.
+ *
+ * The returned pointers to name and value will be allocated by malloc()
+ * and shall be owned by the caller.
+ *
+ * \param entry An existing Vorbis comment entry.
+ * \param field_name The address of where the returned pointer to the
+ * field name will be stored.
+ * \param field_value The address of where the returned pointer to the
+ * field value will be stored.
+ * \assert
+ * \code (entry.entry != NULL && entry.length > 0) \endcode
+ * \code memchr(entry.entry, '=', entry.length) != NULL \endcode
+ * \code field_name != NULL \endcode
+ * \code field_value != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation fails or \a entry does not comply with the
+ * Vorbis comment specification, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value);
+
+/** Check if the given Vorbis comment entry's field name matches the given
+ * field name.
+ *
+ * \param entry An existing Vorbis comment entry.
+ * \param field_name The field name to check.
+ * \param field_name_length The length of \a field_name, not including the
+ * terminating \c NUL.
+ * \assert
+ * \code (entry.entry != NULL && entry.length > 0) \endcode
+ * \retval FLAC__bool
+ * \c true if the field names match, else \c false
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length);
+
+/** Find a Vorbis comment with the given field name.
+ *
+ * The search begins at entry number \a offset; use an offset of 0 to
+ * search from the beginning of the comment array.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param offset The offset into the comment array from where to start
+ * the search.
+ * \param field_name The field name of the comment to find.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \code field_name != NULL \endcode
+ * \retval int
+ * The offset in the comment array of the first comment whose field
+ * name matches \a field_name, or \c -1 if no match was found.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name);
+
+/** Remove first Vorbis comment matching the given field name.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name The field name of comment to delete.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ * \c -1 for memory allocation error, \c 0 for no matching entries,
+ * \c 1 for one matching entry deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/** Remove all Vorbis comments matching the given field name.
+ *
+ * \param object A pointer to an existing VORBIS_COMMENT object.
+ * \param field_name The field name of comments to delete.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT \endcode
+ * \retval int
+ * \c -1 for memory allocation error, \c 0 for no matching entries,
+ * else the number of matching entries deleted.
+ */
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name);
+
+/** Create a new CUESHEET track instance.
+ *
+ * The object will be "empty"; i.e. values and data pointers will be \c 0.
+ *
+ * \retval FLAC__StreamMetadata_CueSheet_Track*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void);
+
+/** Create a copy of an existing CUESHEET track object.
+ *
+ * The copy is a "deep" copy, i.e. dynamically allocated data within the
+ * object is also copied. The caller takes ownership of the new object and
+ * is responsible for freeing it with
+ * FLAC__metadata_object_cuesheet_track_delete().
+ *
+ * \param object Pointer to object to copy.
+ * \assert
+ * \code object != NULL \endcode
+ * \retval FLAC__StreamMetadata_CueSheet_Track*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object);
+
+/** Delete a CUESHEET track object
+ *
+ * \param object A pointer to an existing CUESHEET track object.
+ * \assert
+ * \code object != NULL \endcode
+ */
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object);
+
+/** Resize a track's index point array.
+ *
+ * If the size shrinks, elements will truncated; if it grows, new blank
+ * indices will be added to the end.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index of the track to modify. NOTE: this is not
+ * necessarily the same as the track's \a number field.
+ * \param new_num_indices The desired length of the array; may be \c 0.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \code (object->data.cue_sheet.tracks[track_num].indices == NULL && object->data.cue_sheet.tracks[track_num].num_indices == 0) ||
+ * (object->data.cue_sheet.tracks[track_num].indices != NULL && object->data.cue_sheet.tracks[track_num].num_indices > 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices);
+
+/** Insert an index point in a CUESHEET track at the given index.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index of the track to modify. NOTE: this is not
+ * necessarily the same as the track's \a number field.
+ * \param index_num The index into the track's index array at which to
+ * insert the index point. NOTE: this is not necessarily
+ * the same as the index point's \a number field. The
+ * indices at and after \a index_num move right one
+ * position. To append an index point to the end, set
+ * \a index_num to
+ * \c object->data.cue_sheet.tracks[track_num].num_indices .
+ * \param index The index point to insert.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index);
+
+/** Insert a blank index point in a CUESHEET track at the given index.
+ *
+ * A blank index point is one in which all field values are zero.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index of the track to modify. NOTE: this is not
+ * necessarily the same as the track's \a number field.
+ * \param index_num The index into the track's index array at which to
+ * insert the index point. NOTE: this is not necessarily
+ * the same as the index point's \a number field. The
+ * indices at and after \a index_num move right one
+ * position. To append an index point to the end, set
+ * \a index_num to
+ * \c object->data.cue_sheet.tracks[track_num].num_indices .
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \code object->data.cue_sheet.tracks[track_num].num_indices >= index_num \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+
+/** Delete an index point in a CUESHEET track at the given index.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index into the track array of the track to
+ * modify. NOTE: this is not necessarily the same
+ * as the track's \a number field.
+ * \param index_num The index into the track's index array of the index
+ * to delete. NOTE: this is not necessarily the same
+ * as the index's \a number field.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \code object->data.cue_sheet.tracks[track_num].num_indices > index_num \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+
+/** Resize the track array.
+ *
+ * If the size shrinks, elements will truncated; if it grows, new blank
+ * tracks will be added to the end.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param new_num_tracks The desired length of the array; may be \c 0.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code (object->data.cue_sheet.tracks == NULL && object->data.cue_sheet.num_tracks == 0) ||
+ * (object->data.cue_sheet.tracks != NULL && object->data.cue_sheet.num_tracks > 0) \endcode
+ * \retval FLAC__bool
+ * \c false if memory allocation error, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks);
+
+/** Sets a track in a CUESHEET block.
+ *
+ * If \a copy is \c true, a copy of the track is stored; otherwise, the object
+ * takes ownership of the \a track pointer.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num Index into track array to set. NOTE: this is not
+ * necessarily the same as the track's \a number field.
+ * \param track The track to set the track to. You may safely pass in
+ * a const pointer if \a copy is \c true.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code track_num < object->data.cue_sheet.num_tracks \endcode
+ * \code (track->indices != NULL && track->num_indices > 0) ||
+ * (track->indices == NULL && track->num_indices == 0)
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+
+/** Insert a track in a CUESHEET block at the given index.
+ *
+ * If \a copy is \c true, a copy of the track is stored; otherwise, the object
+ * takes ownership of the \a track pointer.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index at which to insert the track. NOTE: this
+ * is not necessarily the same as the track's \a number
+ * field. The tracks at and after \a track_num move right
+ * one position. To append a track to the end, set
+ * \a track_num to \c object->data.cue_sheet.num_tracks .
+ * \param track The track to insert. You may safely pass in a const
+ * pointer if \a copy is \c true.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks >= track_num \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+
+/** Insert a blank track in a CUESHEET block at the given index.
+ *
+ * A blank track is one in which all field values are zero.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index at which to insert the track. NOTE: this
+ * is not necessarily the same as the track's \a number
+ * field. The tracks at and after \a track_num move right
+ * one position. To append a track to the end, set
+ * \a track_num to \c object->data.cue_sheet.num_tracks .
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks >= track_num \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num);
+
+/** Delete a track in a CUESHEET block at the given index.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param track_num The index into the track array of the track to
+ * delete. NOTE: this is not necessarily the same
+ * as the track's \a number field.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \code object->data.cue_sheet.num_tracks > track_num \endcode
+ * \retval FLAC__bool
+ * \c false if realloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num);
+
+/** Check a cue sheet to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * cue sheet.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \param check_cd_da_subset If \c true, check CUESHEET against more
+ * stringent requirements for a CD-DA (audio) disc.
+ * \param violation Address of a pointer to a string. If there is a
+ * violation, a pointer to a string explanation of the
+ * violation will be returned here. \a violation may be
+ * \c NULL if you don't need the returned string. Do not
+ * free the returned string; it will always point to static
+ * data.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__bool
+ * \c false if cue sheet is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation);
+
+/* @@@@ add to unit tests */
+/** Calculate and return the CDDB/freedb ID for a cue sheet. The function
+ * assumes the cue sheet corresponds to a CD; the result is undefined
+ * if the cuesheet's is_cd bit is not set.
+ *
+ * \param object A pointer to an existing CUESHEET object.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_CUESHEET \endcode
+ * \retval FLAC__uint32
+ * The unsigned integer representation of the CDDB/freedb ID
+ */
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object);
+
+/** Sets the MIME type of a PICTURE block.
+ *
+ * If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ * takes ownership of the pointer. The existing string will be freed if this
+ * function is successful, otherwise the original string will remain if \a copy
+ * is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a mime_type if \a copy is \c true.
+ *
+ * \param object A pointer to an existing PICTURE object.
+ * \param mime_type A pointer to the MIME type string. The string must be
+ * ASCII characters 0x20-0x7e, NUL-terminated. No validation
+ * is done.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \code (mime_type != NULL) \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, const char *mime_type, FLAC__bool copy);
+
+/** Sets the description of a PICTURE block.
+ *
+ * If \a copy is \c true, a copy of the string is stored; otherwise, the object
+ * takes ownership of the pointer. The existing string will be freed if this
+ * function is successful, otherwise the original string will remain if \a copy
+ * is \c true and malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a description if \a copy is \c true.
+ *
+ * \param object A pointer to an existing PICTURE object.
+ * \param description A pointer to the description string. The string must be
+ * valid UTF-8, NUL-terminated. No validation is done.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \code (description != NULL) \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, const FLAC__byte *description, FLAC__bool copy);
+
+/** Sets the picture data of a PICTURE block.
+ *
+ * If \a copy is \c true, a copy of the data is stored; otherwise, the object
+ * takes ownership of the pointer. Also sets the \a data_length field of the
+ * metadata object to what is passed in as the \a length parameter. The
+ * existing data will be freed if this function is successful, otherwise the
+ * original data and data_length will remain if \a copy is \c true and
+ * malloc() fails.
+ *
+ * \note It is safe to pass a const pointer to \a data if \a copy is \c true.
+ *
+ * \param object A pointer to an existing PICTURE object.
+ * \param data A pointer to the data to set.
+ * \param length The length of \a data in bytes.
+ * \param copy See above.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \code (data != NULL && length > 0) ||
+ * (data == NULL && length == 0 && copy == false) \endcode
+ * \retval FLAC__bool
+ * \c false if \a copy is \c true and malloc() fails, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, const FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy);
+
+/** Check a PICTURE block to see if it conforms to the FLAC specification.
+ * See the format specification for limits on the contents of the
+ * PICTURE block.
+ *
+ * \param object A pointer to existing PICTURE block to be checked.
+ * \param violation Address of a pointer to a string. If there is a
+ * violation, a pointer to a string explanation of the
+ * violation will be returned here. \a violation may be
+ * \c NULL if you don't need the returned string. Do not
+ * free the returned string; it will always point to static
+ * data.
+ * \assert
+ * \code object != NULL \endcode
+ * \code object->type == FLAC__METADATA_TYPE_PICTURE \endcode
+ * \retval FLAC__bool
+ * \c false if PICTURE block is illegal, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/FLAC/include/FLAC/ordinals.h b/src/FLAC/include/FLAC/ordinals.h
new file mode 100644
index 0000000..a7a5cd9
--- /dev/null
+++ b/src/FLAC/include/FLAC/ordinals.h
@@ -0,0 +1,80 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__ORDINALS_H
+#define FLAC__ORDINALS_H
+
+#if !(defined(_MSC_VER) || defined(__BORLANDC__) || defined(__EMX__))
+#include <inttypes.h>
+#endif
+
+typedef signed char FLAC__int8;
+typedef unsigned char FLAC__uint8;
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int16 FLAC__int16;
+typedef __int32 FLAC__int32;
+typedef __int64 FLAC__int64;
+typedef unsigned __int16 FLAC__uint16;
+typedef unsigned __int32 FLAC__uint32;
+typedef unsigned __int64 FLAC__uint64;
+#elif defined(__EMX__)
+typedef short FLAC__int16;
+typedef long FLAC__int32;
+typedef long long FLAC__int64;
+typedef unsigned short FLAC__uint16;
+typedef unsigned long FLAC__uint32;
+typedef unsigned long long FLAC__uint64;
+#else
+typedef int16_t FLAC__int16;
+typedef int32_t FLAC__int32;
+typedef int64_t FLAC__int64;
+typedef uint16_t FLAC__uint16;
+typedef uint32_t FLAC__uint32;
+typedef uint64_t FLAC__uint64;
+#endif
+
+typedef int FLAC__bool;
+
+typedef FLAC__uint8 FLAC__byte;
+
+#ifdef true
+#undef true
+#endif
+#ifdef false
+#undef false
+#endif
+#ifndef __cplusplus
+#define true 1
+#define false 0
+#endif
+
+#endif
diff --git a/src/FLAC/include/FLAC/stream_decoder.h b/src/FLAC/include/FLAC/stream_decoder.h
new file mode 100644
index 0000000..9ac1594
--- /dev/null
+++ b/src/FLAC/include/FLAC/stream_decoder.h
@@ -0,0 +1,1559 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__STREAM_DECODER_H
+#define FLAC__STREAM_DECODER_H
+
+#include <stdio.h> /* for FILE */
+#include "export.h"
+#include "format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/stream_decoder.h
+ *
+ * \brief
+ * This module contains the functions which implement the stream
+ * decoder.
+ *
+ * See the detailed documentation in the
+ * \link flac_stream_decoder stream decoder \endlink module.
+ */
+
+/** \defgroup flac_decoder FLAC/ \*_decoder.h: decoder interfaces
+ * \ingroup flac
+ *
+ * \brief
+ * This module describes the decoder layers provided by libFLAC.
+ *
+ * The stream decoder can be used to decode complete streams either from
+ * the client via callbacks, or directly from a file, depending on how
+ * it is initialized. When decoding via callbacks, the client provides
+ * callbacks for reading FLAC data and writing decoded samples, and
+ * handling metadata and errors. If the client also supplies seek-related
+ * callback, the decoder function for sample-accurate seeking within the
+ * FLAC input is also available. When decoding from a file, the client
+ * needs only supply a filename or open \c FILE* and write/metadata/error
+ * callbacks; the rest of the callbacks are supplied internally. For more
+ * info see the \link flac_stream_decoder stream decoder \endlink module.
+ */
+
+/** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface
+ * \ingroup flac_decoder
+ *
+ * \brief
+ * This module contains the functions which implement the stream
+ * decoder.
+ *
+ * The stream decoder can decode native FLAC, and optionally Ogg FLAC
+ * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files.
+ *
+ * The basic usage of this decoder is as follows:
+ * - The program creates an instance of a decoder using
+ * FLAC__stream_decoder_new().
+ * - The program overrides the default settings using
+ * FLAC__stream_decoder_set_*() functions.
+ * - The program initializes the instance to validate the settings and
+ * prepare for decoding using
+ * - FLAC__stream_decoder_init_stream() or FLAC__stream_decoder_init_FILE()
+ * or FLAC__stream_decoder_init_file() for native FLAC,
+ * - FLAC__stream_decoder_init_ogg_stream() or FLAC__stream_decoder_init_ogg_FILE()
+ * or FLAC__stream_decoder_init_ogg_file() for Ogg FLAC
+ * - The program calls the FLAC__stream_decoder_process_*() functions
+ * to decode data, which subsequently calls the callbacks.
+ * - The program finishes the decoding with FLAC__stream_decoder_finish(),
+ * which flushes the input and output and resets the decoder to the
+ * uninitialized state.
+ * - The instance may be used again or deleted with
+ * FLAC__stream_decoder_delete().
+ *
+ * In more detail, the program will create a new instance by calling
+ * FLAC__stream_decoder_new(), then call FLAC__stream_decoder_set_*()
+ * functions to override the default decoder options, and call
+ * one of the FLAC__stream_decoder_init_*() functions.
+ *
+ * There are three initialization functions for native FLAC, one for
+ * setting up the decoder to decode FLAC data from the client via
+ * callbacks, and two for decoding directly from a FLAC file.
+ *
+ * For decoding via callbacks, use FLAC__stream_decoder_init_stream().
+ * You must also supply several callbacks for handling I/O. Some (like
+ * seeking) are optional, depending on the capabilities of the input.
+ *
+ * For decoding directly from a file, use FLAC__stream_decoder_init_FILE()
+ * or FLAC__stream_decoder_init_file(). Then you must only supply an open
+ * \c FILE* or filename and fewer callbacks; the decoder will handle
+ * the other callbacks internally.
+ *
+ * There are three similarly-named init functions for decoding from Ogg
+ * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the
+ * library has been built with Ogg support.
+ *
+ * Once the decoder is initialized, your program will call one of several
+ * functions to start the decoding process:
+ *
+ * - FLAC__stream_decoder_process_single() - Tells the decoder to process at
+ * most one metadata block or audio frame and return, calling either the
+ * metadata callback or write callback, respectively, once. If the decoder
+ * loses sync it will return with only the error callback being called.
+ * - FLAC__stream_decoder_process_until_end_of_metadata() - Tells the decoder
+ * to process the stream from the current location and stop upon reaching
+ * the first audio frame. The client will get one metadata, write, or error
+ * callback per metadata block, audio frame, or sync error, respectively.
+ * - FLAC__stream_decoder_process_until_end_of_stream() - Tells the decoder
+ * to process the stream from the current location until the read callback
+ * returns FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM or
+ * FLAC__STREAM_DECODER_READ_STATUS_ABORT. The client will get one metadata,
+ * write, or error callback per metadata block, audio frame, or sync error,
+ * respectively.
+ *
+ * When the decoder has finished decoding (normally or through an abort),
+ * the instance is finished by calling FLAC__stream_decoder_finish(), which
+ * ensures the decoder is in the correct state and frees memory. Then the
+ * instance may be deleted with FLAC__stream_decoder_delete() or initialized
+ * again to decode another stream.
+ *
+ * Seeking is exposed through the FLAC__stream_decoder_seek_absolute() method.
+ * At any point after the stream decoder has been initialized, the client can
+ * call this function to seek to an exact sample within the stream.
+ * Subsequently, the first time the write callback is called it will be
+ * passed a (possibly partial) block starting at that sample.
+ *
+ * If the client cannot seek via the callback interface provided, but still
+ * has another way of seeking, it can flush the decoder using
+ * FLAC__stream_decoder_flush() and start feeding data from the new position
+ * through the read callback.
+ *
+ * The stream decoder also provides MD5 signature checking. If this is
+ * turned on before initialization, FLAC__stream_decoder_finish() will
+ * report when the decoded MD5 signature does not match the one stored
+ * in the STREAMINFO block. MD5 checking is automatically turned off
+ * (until the next FLAC__stream_decoder_reset()) if there is no signature
+ * in the STREAMINFO block or when a seek is attempted.
+ *
+ * The FLAC__stream_decoder_set_metadata_*() functions deserve special
+ * attention. By default, the decoder only calls the metadata_callback for
+ * the STREAMINFO block. These functions allow you to tell the decoder
+ * explicitly which blocks to parse and return via the metadata_callback
+ * and/or which to skip. Use a FLAC__stream_decoder_set_metadata_respond_all(),
+ * FLAC__stream_decoder_set_metadata_ignore() ... or FLAC__stream_decoder_set_metadata_ignore_all(),
+ * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify
+ * which blocks to return. Remember that metadata blocks can potentially
+ * be big (for example, cover art) so filtering out the ones you don't
+ * use can reduce the memory requirements of the decoder. Also note the
+ * special forms FLAC__stream_decoder_set_metadata_respond_application(id)
+ * and FLAC__stream_decoder_set_metadata_ignore_application(id) for
+ * filtering APPLICATION blocks based on the application ID.
+ *
+ * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but
+ * they still can legally be filtered from the metadata_callback.
+ *
+ * \note
+ * The "set" functions may only be called when the decoder is in the
+ * state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after
+ * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but
+ * before FLAC__stream_decoder_init_*(). If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__stream_decoder_finish() resets all settings to the constructor
+ * defaults, including the callbacks.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__StreamDecoder
+ *
+ * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state().
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0,
+ /**< The decoder is ready to search for metadata. */
+
+ FLAC__STREAM_DECODER_READ_METADATA,
+ /**< The decoder is ready to or is in the process of reading metadata. */
+
+ FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC,
+ /**< The decoder is ready to or is in the process of searching for the
+ * frame sync code.
+ */
+
+ FLAC__STREAM_DECODER_READ_FRAME,
+ /**< The decoder is ready to or is in the process of reading a frame. */
+
+ FLAC__STREAM_DECODER_END_OF_STREAM,
+ /**< The decoder has reached the end of the stream. */
+
+ FLAC__STREAM_DECODER_OGG_ERROR,
+ /**< An error occurred in the underlying Ogg layer. */
+
+ FLAC__STREAM_DECODER_SEEK_ERROR,
+ /**< An error occurred while seeking. The decoder must be flushed
+ * with FLAC__stream_decoder_flush() or reset with
+ * FLAC__stream_decoder_reset() before decoding can continue.
+ */
+
+ FLAC__STREAM_DECODER_ABORTED,
+ /**< The decoder was aborted by the read callback. */
+
+ FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
+ /**< An error occurred allocating memory. The decoder is in an invalid
+ * state and can no longer be used.
+ */
+
+ FLAC__STREAM_DECODER_UNINITIALIZED
+ /**< The decoder is in the uninitialized state; one of the
+ * FLAC__stream_decoder_init_*() functions must be called before samples
+ * can be processed.
+ */
+
+} FLAC__StreamDecoderState;
+
+/** Maps a FLAC__StreamDecoderState to a C string.
+ *
+ * Using a FLAC__StreamDecoderState as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderStateString[];
+
+
+/** Possible return values for the FLAC__stream_decoder_init_*() functions.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_INIT_STATUS_OK = 0,
+ /**< Initialization was successful. */
+
+ FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER,
+ /**< The library was not compiled with support for the given container
+ * format.
+ */
+
+ FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS,
+ /**< A required callback was not supplied. */
+
+ FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR,
+ /**< An error occurred allocating memory. */
+
+ FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE,
+ /**< fopen() failed in FLAC__stream_decoder_init_file() or
+ * FLAC__stream_decoder_init_ogg_file(). */
+
+ FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED
+ /**< FLAC__stream_decoder_init_*() was called when the decoder was
+ * already initialized, usually because
+ * FLAC__stream_decoder_finish() was not called.
+ */
+
+} FLAC__StreamDecoderInitStatus;
+
+/** Maps a FLAC__StreamDecoderInitStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderInitStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderInitStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder read callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_READ_STATUS_CONTINUE,
+ /**< The read was OK and decoding can continue. */
+
+ FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM,
+ /**< The read was attempted while at the end of the stream. Note that
+ * the client must only return this value when the read callback was
+ * called when already at the end of the stream. Otherwise, if the read
+ * itself moves to the end of the stream, the client should still return
+ * the data and \c FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, and then on
+ * the next read callback it should return
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM with a byte count
+ * of \c 0.
+ */
+
+ FLAC__STREAM_DECODER_READ_STATUS_ABORT
+ /**< An unrecoverable error occurred. The decoder will return from the process call. */
+
+} FLAC__StreamDecoderReadStatus;
+
+/** Maps a FLAC__StreamDecoderReadStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderReadStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder seek callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_SEEK_STATUS_OK,
+ /**< The seek was OK and decoding can continue. */
+
+ FLAC__STREAM_DECODER_SEEK_STATUS_ERROR,
+ /**< An unrecoverable error occurred. The decoder will return from the process call. */
+
+ FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ /**< Client does not support seeking. */
+
+} FLAC__StreamDecoderSeekStatus;
+
+/** Maps a FLAC__StreamDecoderSeekStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderSeekStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder tell callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_TELL_STATUS_OK,
+ /**< The tell was OK and decoding can continue. */
+
+ FLAC__STREAM_DECODER_TELL_STATUS_ERROR,
+ /**< An unrecoverable error occurred. The decoder will return from the process call. */
+
+ FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ /**< Client does not support telling the position. */
+
+} FLAC__StreamDecoderTellStatus;
+
+/** Maps a FLAC__StreamDecoderTellStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderTellStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderTellStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder length callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_LENGTH_STATUS_OK,
+ /**< The length call was OK and decoding can continue. */
+
+ FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR,
+ /**< An unrecoverable error occurred. The decoder will return from the process call. */
+
+ FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ /**< Client does not support reporting the length. */
+
+} FLAC__StreamDecoderLengthStatus;
+
+/** Maps a FLAC__StreamDecoderLengthStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderLengthStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[];
+
+
+/** Return values for the FLAC__StreamDecoder write callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE,
+ /**< The write was OK and decoding can continue. */
+
+ FLAC__STREAM_DECODER_WRITE_STATUS_ABORT
+ /**< An unrecoverable error occurred. The decoder will return from the process call. */
+
+} FLAC__StreamDecoderWriteStatus;
+
+/** Maps a FLAC__StreamDecoderWriteStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderWriteStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[];
+
+
+/** Possible values passed back to the FLAC__StreamDecoder error callback.
+ * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC is the generic catch-
+ * all. The rest could be caused by bad sync (false synchronization on
+ * data that is not the start of a frame) or corrupted data. The error
+ * itself is the decoder's best guess at what happened assuming a correct
+ * sync. For example \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER
+ * could be caused by a correct sync on the start of a frame, but some
+ * data in the frame header was corrupted. Or it could be the result of
+ * syncing on a point the stream that looked like the starting of a frame
+ * but was not. \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+ * could be because the decoder encountered a valid frame made by a future
+ * version of the encoder which it cannot parse, or because of a false
+ * sync making it appear as though an encountered frame was generated by
+ * a future encoder.
+ */
+typedef enum {
+
+ FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC,
+ /**< An error in the stream caused the decoder to lose synchronization. */
+
+ FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER,
+ /**< The decoder encountered a corrupted frame header. */
+
+ FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH,
+ /**< The frame's data did not match the CRC in the footer. */
+
+ FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+ /**< The decoder encountered reserved fields in use in the stream. */
+
+} FLAC__StreamDecoderErrorStatus;
+
+/** Maps a FLAC__StreamDecoderErrorStatus to a C string.
+ *
+ * Using a FLAC__StreamDecoderErrorStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__StreamDecoder
+ *
+ ***********************************************************************/
+
+struct FLAC__StreamDecoderProtected;
+struct FLAC__StreamDecoderPrivate;
+/** The opaque structure definition for the stream decoder type.
+ * See the \link flac_stream_decoder stream decoder module \endlink
+ * for a detailed description.
+ */
+typedef struct {
+ struct FLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+ struct FLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__StreamDecoder;
+
+/** Signature for the read callback.
+ *
+ * A function pointer matching this signature must be passed to
+ * FLAC__stream_decoder_init*_stream(). The supplied function will be
+ * called when the decoder needs more input data. The address of the
+ * buffer to be filled is supplied, along with the number of bytes the
+ * buffer can hold. The callback may choose to supply less data and
+ * modify the byte count but must be careful not to overflow the buffer.
+ * The callback then returns a status code chosen from
+ * FLAC__StreamDecoderReadStatus.
+ *
+ * Here is an example of a read callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * if(*bytes > 0) {
+ * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file);
+ * if(ferror(file))
+ * return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ * else if(*bytes == 0)
+ * return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ * else
+ * return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ * }
+ * else
+ * return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param buffer A pointer to a location for the callee to store
+ * data to be decoded.
+ * \param bytes A pointer to the size of the buffer. On entry
+ * to the callback, it contains the maximum number
+ * of bytes that may be stored in \a buffer. The
+ * callee must set it to the actual number of bytes
+ * stored (0 in case of error or end-of-stream) before
+ * returning.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderReadStatus
+ * The callee's return status. Note that the callback should return
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if
+ * zero bytes were read and there is no more data to be read.
+ */
+typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/** Signature for the seek callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_decoder_init*_stream(). The supplied function will be
+ * called when the decoder needs to seek the input stream. The decoder
+ * will pass the absolute byte offset to seek to, 0 meaning the
+ * beginning of the stream.
+ *
+ * Here is an example of a seek callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * if(file == stdin)
+ * return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+ * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+ * return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ * else
+ * return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param absolute_byte_offset The offset from the beginning of the stream
+ * to seek to.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderSeekStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+
+/** Signature for the tell callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_decoder_init*_stream(). The supplied function will be
+ * called when the decoder wants to know the current position of the
+ * stream. The callback should return the byte offset from the
+ * beginning of the stream.
+ *
+ * Here is an example of a tell callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * off_t pos;
+ * if(file == stdin)
+ * return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+ * else if((pos = ftello(file)) < 0)
+ * return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ * else {
+ * *absolute_byte_offset = (FLAC__uint64)pos;
+ * return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ * }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param absolute_byte_offset A pointer to storage for the current offset
+ * from the beginning of the stream.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderTellStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
+/** Signature for the length callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_decoder_init*_stream(). The supplied function will be
+ * called when the decoder wants to know the total length of the stream
+ * in bytes.
+ *
+ * Here is an example of a length callback for stdio streams:
+ * \code
+ * FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * struct stat filestats;
+ *
+ * if(file == stdin)
+ * return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+ * else if(fstat(fileno(file), &filestats) != 0)
+ * return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ * else {
+ * *stream_length = (FLAC__uint64)filestats.st_size;
+ * return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ * }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param stream_length A pointer to storage for the length of the stream
+ * in bytes.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderLengthStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+
+/** Signature for the EOF callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_decoder_init*_stream(). The supplied function will be
+ * called when the decoder needs to know if the end of the stream has
+ * been reached.
+ *
+ * Here is an example of a EOF callback for stdio streams:
+ * FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data)
+ * \code
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * return feof(file)? true : false;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__bool
+ * \c true if the currently at the end of the stream, else \c false.
+ */
+typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data);
+
+/** Signature for the write callback.
+ *
+ * A function pointer matching this signature must be passed to one of
+ * the FLAC__stream_decoder_init_*() functions.
+ * The supplied function will be called when the decoder has decoded a
+ * single audio frame. The decoder will pass the frame metadata as well
+ * as an array of pointers (one for each channel) pointing to the
+ * decoded audio.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param frame The description of the decoded frame. See
+ * FLAC__Frame.
+ * \param buffer An array of pointers to decoded channels of data.
+ * Each pointer will point to an array of signed
+ * samples of length \a frame->header.blocksize.
+ * Channels will be ordered according to the FLAC
+ * specification; see the documentation for the
+ * <A HREF="../format.html#frame_header">frame header</A>.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ * \retval FLAC__StreamDecoderWriteStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+
+/** Signature for the metadata callback.
+ *
+ * A function pointer matching this signature must be passed to one of
+ * the FLAC__stream_decoder_init_*() functions.
+ * The supplied function will be called when the decoder has decoded a
+ * metadata block. In a valid FLAC file there will always be one
+ * \c STREAMINFO block, followed by zero or more other metadata blocks.
+ * These will be supplied by the decoder in the same order as they
+ * appear in the stream and always before the first audio frame (i.e.
+ * write callback). The metadata block that is passed in must not be
+ * modified, and it doesn't live beyond the callback, so you should make
+ * a copy of it with FLAC__metadata_object_clone() if you will need it
+ * elsewhere. Since metadata blocks can potentially be large, by
+ * default the decoder only calls the metadata callback for the
+ * \c STREAMINFO block; you can instruct the decoder to pass or filter
+ * other blocks with FLAC__stream_decoder_set_metadata_*() calls.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param metadata The decoded metadata block.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ */
+typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+/** Signature for the error callback.
+ *
+ * A function pointer matching this signature must be passed to one of
+ * the FLAC__stream_decoder_init_*() functions.
+ * The supplied function will be called whenever an error occurs during
+ * decoding.
+ *
+ * \note In general, FLAC__StreamDecoder functions which change the
+ * state should not be called on the \a decoder while in the callback.
+ *
+ * \param decoder The decoder instance calling the callback.
+ * \param status The error encountered by the decoder.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_decoder_init_*().
+ */
+typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new stream decoder instance. The instance is created with
+ * default settings; see the individual FLAC__stream_decoder_set_*()
+ * functions for each setting's default.
+ *
+ * \retval FLAC__StreamDecoder*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void);
+
+/** Free a decoder instance. Deletes the object pointed to by \a decoder.
+ *
+ * \param decoder A pointer to an existing decoder.
+ * \assert
+ * \code decoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the serial number for the FLAC stream within the Ogg container.
+ * The default behavior is to use the serial number of the first Ogg
+ * page. Setting a serial number here will explicitly specify which
+ * stream is to be decoded.
+ *
+ * \note
+ * This does not need to be set for native FLAC decoding.
+ *
+ * \default \c use serial number of first page
+ * \param decoder A decoder instance to set.
+ * \param serial_number See above.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number);
+
+/** Set the "MD5 signature checking" flag. If \c true, the decoder will
+ * compute the MD5 signature of the unencoded audio data while decoding
+ * and compare it to the signature from the STREAMINFO block, if it
+ * exists, during FLAC__stream_decoder_finish().
+ *
+ * MD5 signature checking will be turned off (until the next
+ * FLAC__stream_decoder_reset()) if there is no signature in the
+ * STREAMINFO block or when a seek is attempted.
+ *
+ * Clients that do not use the MD5 check should leave this off to speed
+ * up decoding.
+ *
+ * \default \c false
+ * \param decoder A decoder instance to set.
+ * \param value Flag value (see above).
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value);
+
+/** Direct the decoder to pass on all metadata blocks of type \a type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \param type See above.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \a type is valid
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type);
+
+/** Direct the decoder to pass on all APPLICATION metadata blocks of the
+ * given \a id.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \param id See above.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \code id != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** Direct the decoder to pass on all metadata blocks of any type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder);
+
+/** Direct the decoder to filter out all metadata blocks of type \a type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \param type See above.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \a type is valid
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type);
+
+/** Direct the decoder to filter out all APPLICATION metadata blocks of
+ * the given \a id.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \param id See above.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \code id != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]);
+
+/** Direct the decoder to filter out all metadata blocks of any type.
+ *
+ * \default By default, only the \c STREAMINFO block is returned via the
+ * metadata callback.
+ * \param decoder A decoder instance to set.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the decoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder);
+
+/** Get the current decoder state.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ * The current decoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder);
+
+/** Get the current decoder state as a C string.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval const char *
+ * The decoder state as a C string. Do not modify the contents.
+ */
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder);
+
+/** Get the "MD5 signature checking" flag.
+ * This is the value of the setting, not whether or not the decoder is
+ * currently checking the MD5 (remember, it can be turned off automatically
+ * by a seek). When the decoder is reset the flag will be restored to the
+ * value returned by this function.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * See above.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder);
+
+/** Get the total number of samples in the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the \c STREAMINFO block. A value of \c 0 means "unknown".
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval unsigned
+ * See above.
+ */
+FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder);
+
+/** Get the current number of channels in the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the most recently decoded frame header.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval unsigned
+ * See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
+
+/** Get the current channel assignment in the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the most recently decoded frame header.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__ChannelAssignment
+ * See above.
+ */
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder);
+
+/** Get the current sample resolution in the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the most recently decoded frame header.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval unsigned
+ * See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
+
+/** Get the current sample rate in Hz of the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the most recently decoded frame header.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval unsigned
+ * See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
+
+/** Get the current blocksize of the stream being decoded.
+ * Will only be valid after decoding has started and will contain the
+ * value from the most recently decoded frame header.
+ *
+ * \param decoder A decoder instance to query.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval unsigned
+ * See above.
+ */
+FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
+
+/** Returns the decoder's current read position within the stream.
+ * The position is the byte offset from the start of the stream.
+ * Bytes before this position have been fully decoded. Note that
+ * there may still be undecoded bytes in the decoder's read FIFO.
+ * The returned position is correct even after a seek.
+ *
+ * \warning This function currently only works for native FLAC,
+ * not Ogg FLAC streams.
+ *
+ * \param decoder A decoder instance to query.
+ * \param position Address at which to return the desired position.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \code position != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, \c false if the stream is not native FLAC,
+ * or there was an error from the 'tell' callback or it returned
+ * \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position);
+
+/** Initialize the decoder instance to decode native FLAC streams.
+ *
+ * This flavor of initialization sets up the decoder to decode from a
+ * native FLAC stream. I/O is performed via callbacks to the client.
+ * For decoding from a plain file via filename or open FILE*,
+ * FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE()
+ * provide a simpler interface.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param read_callback See FLAC__StreamDecoderReadCallback. This
+ * pointer must not be \c NULL.
+ * \param seek_callback See FLAC__StreamDecoderSeekCallback. This
+ * pointer may be \c NULL if seeking is not
+ * supported. If \a seek_callback is not \c NULL then a
+ * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
+ * Alternatively, a dummy seek callback that just
+ * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param tell_callback See FLAC__StreamDecoderTellCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a tell_callback must also be supplied.
+ * Alternatively, a dummy tell callback that just
+ * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param length_callback See FLAC__StreamDecoderLengthCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a length_callback must also be supplied.
+ * Alternatively, a dummy length callback that just
+ * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param eof_callback See FLAC__StreamDecoderEofCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a eof_callback must also be supplied.
+ * Alternatively, a dummy length callback that just
+ * returns \c false
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC streams.
+ *
+ * This flavor of initialization sets up the decoder to decode from a
+ * FLAC stream in an Ogg container. I/O is performed via callbacks to the
+ * client. For decoding from a plain file via filename or open FILE*,
+ * FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE()
+ * provide a simpler interface.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \note Support for Ogg FLAC in the library is optional. If this
+ * library has been built without support for Ogg FLAC, this function
+ * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param read_callback See FLAC__StreamDecoderReadCallback. This
+ * pointer must not be \c NULL.
+ * \param seek_callback See FLAC__StreamDecoderSeekCallback. This
+ * pointer may be \c NULL if seeking is not
+ * supported. If \a seek_callback is not \c NULL then a
+ * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied.
+ * Alternatively, a dummy seek callback that just
+ * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param tell_callback See FLAC__StreamDecoderTellCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a tell_callback must also be supplied.
+ * Alternatively, a dummy tell callback that just
+ * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param length_callback See FLAC__StreamDecoderLengthCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a length_callback must also be supplied.
+ * Alternatively, a dummy length callback that just
+ * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param eof_callback See FLAC__StreamDecoderEofCallback. This
+ * pointer may be \c NULL if not supported by the client. If
+ * \a seek_callback is not \c NULL then a
+ * \a eof_callback must also be supplied.
+ * Alternatively, a dummy length callback that just
+ * returns \c false
+ * may also be supplied, all though this is slightly
+ * less efficient for the decoder.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Initialize the decoder instance to decode native FLAC files.
+ *
+ * This flavor of initialization sets up the decoder to decode from a
+ * plain native FLAC file. For non-stdio streams, you must use
+ * FLAC__stream_decoder_init_stream() and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param file An open FLAC file. The file should have been
+ * opened with mode \c "rb" and rewound. The file
+ * becomes owned by the decoder and should not be
+ * manipulated by the client while decoding.
+ * Unless \a file is \c stdin, it will be closed
+ * when FLAC__stream_decoder_finish() is called.
+ * Note however that seeking will not work when
+ * decoding from \c stdout since it is not seekable.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \code file != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
+ FLAC__StreamDecoder *decoder,
+ FILE *file,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC files.
+ *
+ * This flavor of initialization sets up the decoder to decode from a
+ * plain Ogg FLAC file. For non-stdio streams, you must use
+ * FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \note Support for Ogg FLAC in the library is optional. If this
+ * library has been built without support for Ogg FLAC, this function
+ * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param file An open FLAC file. The file should have been
+ * opened with mode \c "rb" and rewound. The file
+ * becomes owned by the decoder and should not be
+ * manipulated by the client while decoding.
+ * Unless \a file is \c stdin, it will be closed
+ * when FLAC__stream_decoder_finish() is called.
+ * Note however that seeking will not work when
+ * decoding from \c stdout since it is not seekable.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \code file != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
+ FLAC__StreamDecoder *decoder,
+ FILE *file,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Initialize the decoder instance to decode native FLAC files.
+ *
+ * This flavor of initialization sets up the decoder to decode from a plain
+ * native FLAC file. If POSIX fopen() semantics are not sufficient, (for
+ * example, with Unicode filenames on Windows), you must use
+ * FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream()
+ * and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param filename The name of the file to decode from. The file will
+ * be opened with fopen(). Use \c NULL to decode from
+ * \c stdin. Note that \c stdin is not seekable.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
+ FLAC__StreamDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Initialize the decoder instance to decode Ogg FLAC files.
+ *
+ * This flavor of initialization sets up the decoder to decode from a plain
+ * Ogg FLAC file. If POSIX fopen() semantics are not sufficient, (for
+ * example, with Unicode filenames on Windows), you must use
+ * FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream()
+ * and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_decoder_new() and
+ * FLAC__stream_decoder_set_*() but before any of the
+ * FLAC__stream_decoder_process_*() functions. Will set and return the
+ * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA
+ * if initialization succeeded.
+ *
+ * \note Support for Ogg FLAC in the library is optional. If this
+ * library has been built without support for Ogg FLAC, this function
+ * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER.
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \param filename The name of the file to decode from. The file will
+ * be opened with fopen(). Use \c NULL to decode from
+ * \c stdin. Note that \c stdin is not seekable.
+ * \param write_callback See FLAC__StreamDecoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param error_callback See FLAC__StreamDecoderErrorCallback. This
+ * pointer must not be \c NULL.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__StreamDecoderInitStatus
+ * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamDecoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
+ FLAC__StreamDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+);
+
+/** Finish the decoding process.
+ * Flushes the decoding buffer, releases resources, resets the decoder
+ * settings to their defaults, and returns the decoder state to
+ * FLAC__STREAM_DECODER_UNINITIALIZED.
+ *
+ * In the event of a prematurely-terminated decode, it is not strictly
+ * necessary to call this immediately before FLAC__stream_decoder_delete()
+ * but it is good practice to match every FLAC__stream_decoder_init_*()
+ * with a FLAC__stream_decoder_finish().
+ *
+ * \param decoder An uninitialized decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if MD5 checking is on AND a STREAMINFO block was available
+ * AND the MD5 signature in the STREAMINFO block was non-zero AND the
+ * signature does not match the one computed by the decoder; else
+ * \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder);
+
+/** Flush the stream input.
+ * The decoder's input buffer will be cleared and the state set to
+ * \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC. This will also turn
+ * off MD5 checking.
+ *
+ * \param decoder A decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false if a memory allocation
+ * error occurs (in which case the state will be set to
+ * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder);
+
+/** Reset the decoding process.
+ * The decoder's input buffer will be cleared and the state set to
+ * \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA. This is similar to
+ * FLAC__stream_decoder_finish() except that the settings are
+ * preserved; there is no need to call FLAC__stream_decoder_init_*()
+ * before decoding again. MD5 checking will be restored to its original
+ * setting.
+ *
+ * If the decoder is seekable, or was initialized with
+ * FLAC__stream_decoder_init*_FILE() or FLAC__stream_decoder_init*_file(),
+ * the decoder will also attempt to seek to the beginning of the file.
+ * If this rewind fails, this function will return \c false. It follows
+ * that FLAC__stream_decoder_reset() cannot be used when decoding from
+ * \c stdin.
+ *
+ * If the decoder was initialized with FLAC__stream_encoder_init*_stream()
+ * and is not seekable (i.e. no seek callback was provided or the seek
+ * callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it
+ * is the duty of the client to start feeding data from the beginning of
+ * the stream on the next FLAC__stream_decoder_process() or
+ * FLAC__stream_decoder_process_interleaved() call.
+ *
+ * \param decoder A decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false if a memory allocation occurs
+ * (in which case the state will be set to
+ * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) or a seek error
+ * occurs (the state will be unchanged).
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder);
+
+/** Decode one metadata block or audio frame.
+ * This version instructs the decoder to decode a either a single metadata
+ * block or a single frame and stop, unless the callbacks return a fatal
+ * error or the read callback returns
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ * As the decoder needs more input it will call the read callback.
+ * Depending on what was decoded, the metadata or write callback will be
+ * called with the decoded metadata block or audio frame.
+ *
+ * Unless there is a fatal read error or end of stream, this function
+ * will return once one whole frame is decoded. In other words, if the
+ * stream is not synchronized or points to a corrupt frame header, the
+ * decoder will continue to try and resync until it gets to a valid
+ * frame, then decode one frame, then return. If the decoder points to
+ * a frame whose frame CRC in the frame footer does not match the
+ * computed frame CRC, this function will issue a
+ * FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the
+ * error callback, and return, having decoded one complete, although
+ * corrupt, frame. (Such corrupted frames are sent as silence of the
+ * correct length to the write callback.)
+ *
+ * \param decoder An initialized decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if any fatal read, write, or memory allocation error
+ * occurred (meaning decoding must stop), else \c true; for more
+ * information about the decoder, check the decoder state with
+ * FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder);
+
+/** Decode until the end of the metadata.
+ * This version instructs the decoder to decode from the current position
+ * and continue until all the metadata has been read, or until the
+ * callbacks return a fatal error or the read callback returns
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ * As the decoder needs more input it will call the read callback.
+ * As each metadata block is decoded, the metadata callback will be called
+ * with the decoded metadata.
+ *
+ * \param decoder An initialized decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if any fatal read, write, or memory allocation error
+ * occurred (meaning decoding must stop), else \c true; for more
+ * information about the decoder, check the decoder state with
+ * FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder);
+
+/** Decode until the end of the stream.
+ * This version instructs the decoder to decode from the current position
+ * and continue until the end of stream (the read callback returns
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the
+ * callbacks return a fatal error.
+ *
+ * As the decoder needs more input it will call the read callback.
+ * As each metadata block and frame is decoded, the metadata or write
+ * callback will be called with the decoded metadata or frame.
+ *
+ * \param decoder An initialized decoder instance.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if any fatal read, write, or memory allocation error
+ * occurred (meaning decoding must stop), else \c true; for more
+ * information about the decoder, check the decoder state with
+ * FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder);
+
+/** Skip one audio frame.
+ * This version instructs the decoder to 'skip' a single frame and stop,
+ * unless the callbacks return a fatal error or the read callback returns
+ * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM.
+ *
+ * The decoding flow is the same as what occurs when
+ * FLAC__stream_decoder_process_single() is called to process an audio
+ * frame, except that this function does not decode the parsed data into
+ * PCM or call the write callback. The integrity of the frame is still
+ * checked the same way as in the other process functions.
+ *
+ * This function will return once one whole frame is skipped, in the
+ * same way that FLAC__stream_decoder_process_single() will return once
+ * one whole frame is decoded.
+ *
+ * This function can be used in more quickly determining FLAC frame
+ * boundaries when decoding of the actual data is not needed, for
+ * example when an application is separating a FLAC stream into frames
+ * for editing or storing in a container. To do this, the application
+ * can use FLAC__stream_decoder_skip_single_frame() to quickly advance
+ * to the next frame, then use
+ * FLAC__stream_decoder_get_decode_position() to find the new frame
+ * boundary.
+ *
+ * This function should only be called when the stream has advanced
+ * past all the metadata, otherwise it will return \c false.
+ *
+ * \param decoder An initialized decoder instance not in a metadata
+ * state.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if any fatal read, write, or memory allocation error
+ * occurred (meaning decoding must stop), or if the decoder
+ * is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or
+ * FLAC__STREAM_DECODER_READ_METADATA state, else \c true; for more
+ * information about the decoder, check the decoder state with
+ * FLAC__stream_decoder_get_state().
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder);
+
+/** Flush the input and seek to an absolute sample.
+ * Decoding will resume at the given sample. Note that because of
+ * this, the next write callback may contain a partial block. The
+ * client must support seeking the input or this function will fail
+ * and return \c false. Furthermore, if the decoder state is
+ * \c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed
+ * with FLAC__stream_decoder_flush() or reset with
+ * FLAC__stream_decoder_reset() before decoding can continue.
+ *
+ * \param decoder A decoder instance.
+ * \param sample The target sample number to seek to.
+ * \assert
+ * \code decoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false.
+ */
+FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/FLAC/include/FLAC/stream_encoder.h b/src/FLAC/include/FLAC/stream_encoder.h
new file mode 100644
index 0000000..bf389d2
--- /dev/null
+++ b/src/FLAC/include/FLAC/stream_encoder.h
@@ -0,0 +1,1769 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__STREAM_ENCODER_H
+#define FLAC__STREAM_ENCODER_H
+
+#include <stdio.h> /* for FILE */
+#include "export.h"
+#include "format.h"
+#include "stream_decoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** \file include/FLAC/stream_encoder.h
+ *
+ * \brief
+ * This module contains the functions which implement the stream
+ * encoder.
+ *
+ * See the detailed documentation in the
+ * \link flac_stream_encoder stream encoder \endlink module.
+ */
+
+/** \defgroup flac_encoder FLAC/ \*_encoder.h: encoder interfaces
+ * \ingroup flac
+ *
+ * \brief
+ * This module describes the encoder layers provided by libFLAC.
+ *
+ * The stream encoder can be used to encode complete streams either to the
+ * client via callbacks, or directly to a file, depending on how it is
+ * initialized. When encoding via callbacks, the client provides a write
+ * callback which will be called whenever FLAC data is ready to be written.
+ * If the client also supplies a seek callback, the encoder will also
+ * automatically handle the writing back of metadata discovered while
+ * encoding, like stream info, seek points offsets, etc. When encoding to
+ * a file, the client needs only supply a filename or open \c FILE* and an
+ * optional progress callback for periodic notification of progress; the
+ * write and seek callbacks are supplied internally. For more info see the
+ * \link flac_stream_encoder stream encoder \endlink module.
+ */
+
+/** \defgroup flac_stream_encoder FLAC/stream_encoder.h: stream encoder interface
+ * \ingroup flac_encoder
+ *
+ * \brief
+ * This module contains the functions which implement the stream
+ * encoder.
+ *
+ * The stream encoder can encode to native FLAC, and optionally Ogg FLAC
+ * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files.
+ *
+ * The basic usage of this encoder is as follows:
+ * - The program creates an instance of an encoder using
+ * FLAC__stream_encoder_new().
+ * - The program overrides the default settings using
+ * FLAC__stream_encoder_set_*() functions. At a minimum, the following
+ * functions should be called:
+ * - FLAC__stream_encoder_set_channels()
+ * - FLAC__stream_encoder_set_bits_per_sample()
+ * - FLAC__stream_encoder_set_sample_rate()
+ * - FLAC__stream_encoder_set_ogg_serial_number() (if encoding to Ogg FLAC)
+ * - FLAC__stream_encoder_set_total_samples_estimate() (if known)
+ * - If the application wants to control the compression level or set its own
+ * metadata, then the following should also be called:
+ * - FLAC__stream_encoder_set_compression_level()
+ * - FLAC__stream_encoder_set_verify()
+ * - FLAC__stream_encoder_set_metadata()
+ * - The rest of the set functions should only be called if the client needs
+ * exact control over how the audio is compressed; thorough understanding
+ * of the FLAC format is necessary to achieve good results.
+ * - The program initializes the instance to validate the settings and
+ * prepare for encoding using
+ * - FLAC__stream_encoder_init_stream() or FLAC__stream_encoder_init_FILE()
+ * or FLAC__stream_encoder_init_file() for native FLAC
+ * - FLAC__stream_encoder_init_ogg_stream() or FLAC__stream_encoder_init_ogg_FILE()
+ * or FLAC__stream_encoder_init_ogg_file() for Ogg FLAC
+ * - The program calls FLAC__stream_encoder_process() or
+ * FLAC__stream_encoder_process_interleaved() to encode data, which
+ * subsequently calls the callbacks when there is encoder data ready
+ * to be written.
+ * - The program finishes the encoding with FLAC__stream_encoder_finish(),
+ * which causes the encoder to encode any data still in its input pipe,
+ * update the metadata with the final encoding statistics if output
+ * seeking is possible, and finally reset the encoder to the
+ * uninitialized state.
+ * - The instance may be used again or deleted with
+ * FLAC__stream_encoder_delete().
+ *
+ * In more detail, the stream encoder functions similarly to the
+ * \link flac_stream_decoder stream decoder \endlink, but has fewer
+ * callbacks and more options. Typically the client will create a new
+ * instance by calling FLAC__stream_encoder_new(), then set the necessary
+ * parameters with FLAC__stream_encoder_set_*(), and initialize it by
+ * calling one of the FLAC__stream_encoder_init_*() functions.
+ *
+ * Unlike the decoders, the stream encoder has many options that can
+ * affect the speed and compression ratio. When setting these parameters
+ * you should have some basic knowledge of the format (see the
+ * <A HREF="../documentation.html#format">user-level documentation</A>
+ * or the <A HREF="../format.html">formal description</A>). The
+ * FLAC__stream_encoder_set_*() functions themselves do not validate the
+ * values as many are interdependent. The FLAC__stream_encoder_init_*()
+ * functions will do this, so make sure to pay attention to the state
+ * returned by FLAC__stream_encoder_init_*() to make sure that it is
+ * FLAC__STREAM_ENCODER_INIT_STATUS_OK. Any parameters that are not set
+ * before FLAC__stream_encoder_init_*() will take on the defaults from
+ * the constructor.
+ *
+ * There are three initialization functions for native FLAC, one for
+ * setting up the encoder to encode FLAC data to the client via
+ * callbacks, and two for encoding directly to a file.
+ *
+ * For encoding via callbacks, use FLAC__stream_encoder_init_stream().
+ * You must also supply a write callback which will be called anytime
+ * there is raw encoded data to write. If the client can seek the output
+ * it is best to also supply seek and tell callbacks, as this allows the
+ * encoder to go back after encoding is finished to write back
+ * information that was collected while encoding, like seek point offsets,
+ * frame sizes, etc.
+ *
+ * For encoding directly to a file, use FLAC__stream_encoder_init_FILE()
+ * or FLAC__stream_encoder_init_file(). Then you must only supply a
+ * filename or open \c FILE*; the encoder will handle all the callbacks
+ * internally. You may also supply a progress callback for periodic
+ * notification of the encoding progress.
+ *
+ * There are three similarly-named init functions for encoding to Ogg
+ * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the
+ * library has been built with Ogg support.
+ *
+ * The call to FLAC__stream_encoder_init_*() currently will also immediately
+ * call the write callback several times, once with the \c fLaC signature,
+ * and once for each encoded metadata block. Note that for Ogg FLAC
+ * encoding you will usually get at least twice the number of callbacks than
+ * with native FLAC, one for the Ogg page header and one for the page body.
+ *
+ * After initializing the instance, the client may feed audio data to the
+ * encoder in one of two ways:
+ *
+ * - Channel separate, through FLAC__stream_encoder_process() - The client
+ * will pass an array of pointers to buffers, one for each channel, to
+ * the encoder, each of the same length. The samples need not be
+ * block-aligned, but each channel should have the same number of samples.
+ * - Channel interleaved, through
+ * FLAC__stream_encoder_process_interleaved() - The client will pass a single
+ * pointer to data that is channel-interleaved (i.e. channel0_sample0,
+ * channel1_sample0, ... , channelN_sample0, channel0_sample1, ...).
+ * Again, the samples need not be block-aligned but they must be
+ * sample-aligned, i.e. the first value should be channel0_sample0 and
+ * the last value channelN_sampleM.
+ *
+ * Note that for either process call, each sample in the buffers should be a
+ * signed integer, right-justified to the resolution set by
+ * FLAC__stream_encoder_set_bits_per_sample(). For example, if the resolution
+ * is 16 bits per sample, the samples should all be in the range [-32768,32767].
+ *
+ * When the client is finished encoding data, it calls
+ * FLAC__stream_encoder_finish(), which causes the encoder to encode any
+ * data still in its input pipe, and call the metadata callback with the
+ * final encoding statistics. Then the instance may be deleted with
+ * FLAC__stream_encoder_delete() or initialized again to encode another
+ * stream.
+ *
+ * For programs that write their own metadata, but that do not know the
+ * actual metadata until after encoding, it is advantageous to instruct
+ * the encoder to write a PADDING block of the correct size, so that
+ * instead of rewriting the whole stream after encoding, the program can
+ * just overwrite the PADDING block. If only the maximum size of the
+ * metadata is known, the program can write a slightly larger padding
+ * block, then split it after encoding.
+ *
+ * Make sure you understand how lengths are calculated. All FLAC metadata
+ * blocks have a 4 byte header which contains the type and length. This
+ * length does not include the 4 bytes of the header. See the format page
+ * for the specification of metadata blocks and their lengths.
+ *
+ * \note
+ * If you are writing the FLAC data to a file via callbacks, make sure it
+ * is open for update (e.g. mode "w+" for stdio streams). This is because
+ * after the first encoding pass, the encoder will try to seek back to the
+ * beginning of the stream, to the STREAMINFO block, to write some data
+ * there. (If using FLAC__stream_encoder_init*_file() or
+ * FLAC__stream_encoder_init*_FILE(), the file is managed internally.)
+ *
+ * \note
+ * The "set" functions may only be called when the encoder is in the
+ * state FLAC__STREAM_ENCODER_UNINITIALIZED, i.e. after
+ * FLAC__stream_encoder_new() or FLAC__stream_encoder_finish(), but
+ * before FLAC__stream_encoder_init_*(). If this is the case they will
+ * return \c true, otherwise \c false.
+ *
+ * \note
+ * FLAC__stream_encoder_finish() resets all settings to the constructor
+ * defaults.
+ *
+ * \{
+ */
+
+
+/** State values for a FLAC__StreamEncoder.
+ *
+ * The encoder's state can be obtained by calling FLAC__stream_encoder_get_state().
+ *
+ * If the encoder gets into any other state besides \c FLAC__STREAM_ENCODER_OK
+ * or \c FLAC__STREAM_ENCODER_UNINITIALIZED, it becomes invalid for encoding and
+ * must be deleted with FLAC__stream_encoder_delete().
+ */
+typedef enum {
+
+ FLAC__STREAM_ENCODER_OK = 0,
+ /**< The encoder is in the normal OK state and samples can be processed. */
+
+ FLAC__STREAM_ENCODER_UNINITIALIZED,
+ /**< The encoder is in the uninitialized state; one of the
+ * FLAC__stream_encoder_init_*() functions must be called before samples
+ * can be processed.
+ */
+
+ FLAC__STREAM_ENCODER_OGG_ERROR,
+ /**< An error occurred in the underlying Ogg layer. */
+
+ FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR,
+ /**< An error occurred in the underlying verify stream decoder;
+ * check FLAC__stream_encoder_get_verify_decoder_state().
+ */
+
+ FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA,
+ /**< The verify decoder detected a mismatch between the original
+ * audio signal and the decoded audio signal.
+ */
+
+ FLAC__STREAM_ENCODER_CLIENT_ERROR,
+ /**< One of the callbacks returned a fatal error. */
+
+ FLAC__STREAM_ENCODER_IO_ERROR,
+ /**< An I/O error occurred while opening/reading/writing a file.
+ * Check \c errno.
+ */
+
+ FLAC__STREAM_ENCODER_FRAMING_ERROR,
+ /**< An error occurred while writing the stream; usually, the
+ * write_callback returned an error.
+ */
+
+ FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR
+ /**< Memory allocation failed. */
+
+} FLAC__StreamEncoderState;
+
+/** Maps a FLAC__StreamEncoderState to a C string.
+ *
+ * Using a FLAC__StreamEncoderState as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderStateString[];
+
+
+/** Possible return values for the FLAC__stream_encoder_init_*() functions.
+ */
+typedef enum {
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_OK = 0,
+ /**< Initialization was successful. */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR,
+ /**< General failure to set up encoder; call FLAC__stream_encoder_get_state() for cause. */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER,
+ /**< The library was not compiled with support for the given container
+ * format.
+ */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS,
+ /**< A required callback was not supplied. */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS,
+ /**< The encoder has an invalid setting for number of channels. */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE,
+ /**< The encoder has an invalid setting for bits-per-sample.
+ * FLAC supports 4-32 bps but the reference encoder currently supports
+ * only up to 24 bps.
+ */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE,
+ /**< The encoder has an invalid setting for the input sample rate. */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE,
+ /**< The encoder has an invalid setting for the block size. */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER,
+ /**< The encoder has an invalid setting for the maximum LPC order. */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION,
+ /**< The encoder has an invalid setting for the precision of the quantized linear predictor coefficients. */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER,
+ /**< The specified block size is less than the maximum LPC order. */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE,
+ /**< The encoder is bound to the <A HREF="../format.html#subset">Subset</A> but other settings violate it. */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA,
+ /**< The metadata input to the encoder is invalid, in one of the following ways:
+ * - FLAC__stream_encoder_set_metadata() was called with a null pointer but a block count > 0
+ * - One of the metadata blocks contains an undefined type
+ * - It contains an illegal CUESHEET as checked by FLAC__format_cuesheet_is_legal()
+ * - It contains an illegal SEEKTABLE as checked by FLAC__format_seektable_is_legal()
+ * - It contains more than one SEEKTABLE block or more than one VORBIS_COMMENT block
+ */
+
+ FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED
+ /**< FLAC__stream_encoder_init_*() was called when the encoder was
+ * already initialized, usually because
+ * FLAC__stream_encoder_finish() was not called.
+ */
+
+} FLAC__StreamEncoderInitStatus;
+
+/** Maps a FLAC__StreamEncoderInitStatus to a C string.
+ *
+ * Using a FLAC__StreamEncoderInitStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderInitStatusString[];
+
+
+/** Return values for the FLAC__StreamEncoder read callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE,
+ /**< The read was OK and decoding can continue. */
+
+ FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM,
+ /**< The read was attempted at the end of the stream. */
+
+ FLAC__STREAM_ENCODER_READ_STATUS_ABORT,
+ /**< An unrecoverable error occurred. */
+
+ FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED
+ /**< Client does not support reading back from the output. */
+
+} FLAC__StreamEncoderReadStatus;
+
+/** Maps a FLAC__StreamEncoderReadStatus to a C string.
+ *
+ * Using a FLAC__StreamEncoderReadStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderReadStatusString[];
+
+
+/** Return values for the FLAC__StreamEncoder write callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_ENCODER_WRITE_STATUS_OK = 0,
+ /**< The write was OK and encoding can continue. */
+
+ FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR
+ /**< An unrecoverable error occurred. The encoder will return from the process call. */
+
+} FLAC__StreamEncoderWriteStatus;
+
+/** Maps a FLAC__StreamEncoderWriteStatus to a C string.
+ *
+ * Using a FLAC__StreamEncoderWriteStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[];
+
+
+/** Return values for the FLAC__StreamEncoder seek callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_ENCODER_SEEK_STATUS_OK,
+ /**< The seek was OK and encoding can continue. */
+
+ FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR,
+ /**< An unrecoverable error occurred. */
+
+ FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
+ /**< Client does not support seeking. */
+
+} FLAC__StreamEncoderSeekStatus;
+
+/** Maps a FLAC__StreamEncoderSeekStatus to a C string.
+ *
+ * Using a FLAC__StreamEncoderSeekStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[];
+
+
+/** Return values for the FLAC__StreamEncoder tell callback.
+ */
+typedef enum {
+
+ FLAC__STREAM_ENCODER_TELL_STATUS_OK,
+ /**< The tell was OK and encoding can continue. */
+
+ FLAC__STREAM_ENCODER_TELL_STATUS_ERROR,
+ /**< An unrecoverable error occurred. */
+
+ FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
+ /**< Client does not support seeking. */
+
+} FLAC__StreamEncoderTellStatus;
+
+/** Maps a FLAC__StreamEncoderTellStatus to a C string.
+ *
+ * Using a FLAC__StreamEncoderTellStatus as the index to this array
+ * will give the string equivalent. The contents should not be modified.
+ */
+extern FLAC_API const char * const FLAC__StreamEncoderTellStatusString[];
+
+
+/***********************************************************************
+ *
+ * class FLAC__StreamEncoder
+ *
+ ***********************************************************************/
+
+struct FLAC__StreamEncoderProtected;
+struct FLAC__StreamEncoderPrivate;
+/** The opaque structure definition for the stream encoder type.
+ * See the \link flac_stream_encoder stream encoder module \endlink
+ * for a detailed description.
+ */
+typedef struct {
+ struct FLAC__StreamEncoderProtected *protected_; /* avoid the C++ keyword 'protected' */
+ struct FLAC__StreamEncoderPrivate *private_; /* avoid the C++ keyword 'private' */
+} FLAC__StreamEncoder;
+
+/** Signature for the read callback.
+ *
+ * A function pointer matching this signature must be passed to
+ * FLAC__stream_encoder_init_ogg_stream() if seeking is supported.
+ * The supplied function will be called when the encoder needs to read back
+ * encoded data. This happens during the metadata callback, when the encoder
+ * has to read, modify, and rewrite the metadata (e.g. seekpoints) gathered
+ * while encoding. The address of the buffer to be filled is supplied, along
+ * with the number of bytes the buffer can hold. The callback may choose to
+ * supply less data and modify the byte count but must be careful not to
+ * overflow the buffer. The callback then returns a status code chosen from
+ * FLAC__StreamEncoderReadStatus.
+ *
+ * Here is an example of a read callback for stdio streams:
+ * \code
+ * FLAC__StreamEncoderReadStatus read_cb(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * if(*bytes > 0) {
+ * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file);
+ * if(ferror(file))
+ * return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+ * else if(*bytes == 0)
+ * return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
+ * else
+ * return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
+ * }
+ * else
+ * return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param encoder The encoder instance calling the callback.
+ * \param buffer A pointer to a location for the callee to store
+ * data to be encoded.
+ * \param bytes A pointer to the size of the buffer. On entry
+ * to the callback, it contains the maximum number
+ * of bytes that may be stored in \a buffer. The
+ * callee must set it to the actual number of bytes
+ * stored (0 in case of error or end-of-stream) before
+ * returning.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_encoder_set_client_data().
+ * \retval FLAC__StreamEncoderReadStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamEncoderReadStatus (*FLAC__StreamEncoderReadCallback)(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/** Signature for the write callback.
+ *
+ * A function pointer matching this signature must be passed to
+ * FLAC__stream_encoder_init*_stream(). The supplied function will be called
+ * by the encoder anytime there is raw encoded data ready to write. It may
+ * include metadata mixed with encoded audio frames and the data is not
+ * guaranteed to be aligned on frame or metadata block boundaries.
+ *
+ * The only duty of the callback is to write out the \a bytes worth of data
+ * in \a buffer to the current position in the output stream. The arguments
+ * \a samples and \a current_frame are purely informational. If \a samples
+ * is greater than \c 0, then \a current_frame will hold the current frame
+ * number that is being written; otherwise it indicates that the write
+ * callback is being called to write metadata.
+ *
+ * \note
+ * Unlike when writing to native FLAC, when writing to Ogg FLAC the
+ * write callback will be called twice when writing each audio
+ * frame; once for the page header, and once for the page body.
+ * When writing the page header, the \a samples argument to the
+ * write callback will be \c 0.
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param encoder The encoder instance calling the callback.
+ * \param buffer An array of encoded data of length \a bytes.
+ * \param bytes The byte length of \a buffer.
+ * \param samples The number of samples encoded by \a buffer.
+ * \c 0 has a special meaning; see above.
+ * \param current_frame The number of the current frame being encoded.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_encoder_init_*().
+ * \retval FLAC__StreamEncoderWriteStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+/** Signature for the seek callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_encoder_init*_stream(). The supplied function will be called
+ * when the encoder needs to seek the output stream. The encoder will pass
+ * the absolute byte offset to seek to, 0 meaning the beginning of the stream.
+ *
+ * Here is an example of a seek callback for stdio streams:
+ * \code
+ * FLAC__StreamEncoderSeekStatus seek_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * if(file == stdin)
+ * return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED;
+ * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+ * return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+ * else
+ * return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param encoder The encoder instance calling the callback.
+ * \param absolute_byte_offset The offset from the beginning of the stream
+ * to seek to.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_encoder_init_*().
+ * \retval FLAC__StreamEncoderSeekStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamEncoderSeekStatus (*FLAC__StreamEncoderSeekCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+
+/** Signature for the tell callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_encoder_init*_stream(). The supplied function will be called
+ * when the encoder needs to know the current position of the output stream.
+ *
+ * \warning
+ * The callback must return the true current byte offset of the output to
+ * which the encoder is writing. If you are buffering the output, make
+ * sure and take this into account. If you are writing directly to a
+ * FILE* from your write callback, ftell() is sufficient. If you are
+ * writing directly to a file descriptor from your write callback, you
+ * can use lseek(fd, SEEK_CUR, 0). The encoder may later seek back to
+ * these points to rewrite metadata after encoding.
+ *
+ * Here is an example of a tell callback for stdio streams:
+ * \code
+ * FLAC__StreamEncoderTellStatus tell_cb(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+ * {
+ * FILE *file = ((MyClientData*)client_data)->file;
+ * off_t pos;
+ * if(file == stdin)
+ * return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED;
+ * else if((pos = ftello(file)) < 0)
+ * return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+ * else {
+ * *absolute_byte_offset = (FLAC__uint64)pos;
+ * return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+ * }
+ * }
+ * \endcode
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param encoder The encoder instance calling the callback.
+ * \param absolute_byte_offset The address at which to store the current
+ * position of the output.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_encoder_init_*().
+ * \retval FLAC__StreamEncoderTellStatus
+ * The callee's return status.
+ */
+typedef FLAC__StreamEncoderTellStatus (*FLAC__StreamEncoderTellCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+
+/** Signature for the metadata callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_encoder_init*_stream(). The supplied function will be called
+ * once at the end of encoding with the populated STREAMINFO structure. This
+ * is so the client can seek back to the beginning of the file and write the
+ * STREAMINFO block with the correct statistics after encoding (like
+ * minimum/maximum frame size and total samples).
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param encoder The encoder instance calling the callback.
+ * \param metadata The final populated STREAMINFO block.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_encoder_init_*().
+ */
+typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data);
+
+/** Signature for the progress callback.
+ *
+ * A function pointer matching this signature may be passed to
+ * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE().
+ * The supplied function will be called when the encoder has finished
+ * writing a frame. The \c total_frames_estimate argument to the
+ * callback will be based on the value from
+ * FLAC__stream_encoder_set_total_samples_estimate().
+ *
+ * \note In general, FLAC__StreamEncoder functions which change the
+ * state should not be called on the \a encoder while in the callback.
+ *
+ * \param encoder The encoder instance calling the callback.
+ * \param bytes_written Bytes written so far.
+ * \param samples_written Samples written so far.
+ * \param frames_written Frames written so far.
+ * \param total_frames_estimate The estimate of the total number of
+ * frames to be written.
+ * \param client_data The callee's client data set through
+ * FLAC__stream_encoder_init_*().
+ */
+typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+/** Create a new stream encoder instance. The instance is created with
+ * default settings; see the individual FLAC__stream_encoder_set_*()
+ * functions for each setting's default.
+ *
+ * \retval FLAC__StreamEncoder*
+ * \c NULL if there was an error allocating memory, else the new instance.
+ */
+FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void);
+
+/** Free an encoder instance. Deletes the object pointed to by \a encoder.
+ *
+ * \param encoder A pointer to an existing encoder.
+ * \assert
+ * \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder);
+
+
+/***********************************************************************
+ *
+ * Public class method prototypes
+ *
+ ***********************************************************************/
+
+/** Set the serial number for the FLAC stream to use in the Ogg container.
+ *
+ * \note
+ * This does not need to be set for native FLAC encoding.
+ *
+ * \note
+ * It is recommended to set a serial number explicitly as the default of '0'
+ * may collide with other streams.
+ *
+ * \default \c 0
+ * \param encoder An encoder instance to set.
+ * \param serial_number See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long serial_number);
+
+/** Set the "verify" flag. If \c true, the encoder will verify it's own
+ * encoded output by feeding it through an internal decoder and comparing
+ * the original signal against the decoded signal. If a mismatch occurs,
+ * the process call will return \c false. Note that this will slow the
+ * encoding process by the extra time required for decoding and comparison.
+ *
+ * \default \c false
+ * \param encoder An encoder instance to set.
+ * \param value Flag value (see above).
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set the <A HREF="../format.html#subset">Subset</A> flag. If \c true,
+ * the encoder will comply with the Subset and will check the
+ * settings during FLAC__stream_encoder_init_*() to see if all settings
+ * comply. If \c false, the settings may take advantage of the full
+ * range that the format allows.
+ *
+ * Make sure you know what it entails before setting this to \c false.
+ *
+ * \default \c true
+ * \param encoder An encoder instance to set.
+ * \param value Flag value (see above).
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set the number of channels to be encoded.
+ *
+ * \default \c 2
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the sample resolution of the input to be encoded.
+ *
+ * \warning
+ * Do not feed the encoder data that is wider than the value you
+ * set here or you will generate an invalid stream.
+ *
+ * \default \c 16
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the sample rate (in Hz) of the input to be encoded.
+ *
+ * \default \c 44100
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the compression level
+ *
+ * The compression level is roughly proportional to the amount of effort
+ * the encoder expends to compress the file. A higher level usually
+ * means more computation but higher compression. The default level is
+ * suitable for most applications.
+ *
+ * Currently the levels range from \c 0 (fastest, least compression) to
+ * \c 8 (slowest, most compression). A value larger than \c 8 will be
+ * treated as \c 8.
+ *
+ * This function automatically calls the following other \c _set_
+ * functions with appropriate values, so the client does not need to
+ * unless it specifically wants to override them:
+ * - FLAC__stream_encoder_set_do_mid_side_stereo()
+ * - FLAC__stream_encoder_set_loose_mid_side_stereo()
+ * - FLAC__stream_encoder_set_apodization()
+ * - FLAC__stream_encoder_set_max_lpc_order()
+ * - FLAC__stream_encoder_set_qlp_coeff_precision()
+ * - FLAC__stream_encoder_set_do_qlp_coeff_prec_search()
+ * - FLAC__stream_encoder_set_do_escape_coding()
+ * - FLAC__stream_encoder_set_do_exhaustive_model_search()
+ * - FLAC__stream_encoder_set_min_residual_partition_order()
+ * - FLAC__stream_encoder_set_max_residual_partition_order()
+ * - FLAC__stream_encoder_set_rice_parameter_search_dist()
+ *
+ * The actual values set for each level are:
+ * <table>
+ * <tr>
+ * <td><b>level</b><td>
+ * <td>do mid-side stereo<td>
+ * <td>loose mid-side stereo<td>
+ * <td>apodization<td>
+ * <td>max lpc order<td>
+ * <td>qlp coeff precision<td>
+ * <td>qlp coeff prec search<td>
+ * <td>escape coding<td>
+ * <td>exhaustive model search<td>
+ * <td>min residual partition order<td>
+ * <td>max residual partition order<td>
+ * <td>rice parameter search dist<td>
+ * </tr>
+ * <tr> <td><b>0</b><td> <td>false<td> <td>false<td> <td>tukey(0.5)<td> <td>0<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>3<td> <td>0<td> </tr>
+ * <tr> <td><b>1</b><td> <td>true<td> <td>true<td> <td>tukey(0.5)<td> <td>0<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>3<td> <td>0<td> </tr>
+ * <tr> <td><b>2</b><td> <td>true<td> <td>false<td> <td>tukey(0.5)<td> <td>0<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>3<td> <td>0<td> </tr>
+ * <tr> <td><b>3</b><td> <td>false<td> <td>false<td> <td>tukey(0.5)<td> <td>6<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>4<td> <td>0<td> </tr>
+ * <tr> <td><b>4</b><td> <td>true<td> <td>true<td> <td>tukey(0.5)<td> <td>8<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>4<td> <td>0<td> </tr>
+ * <tr> <td><b>5</b><td> <td>true<td> <td>false<td> <td>tukey(0.5)<td> <td>8<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>5<td> <td>0<td> </tr>
+ * <tr> <td><b>6</b><td> <td>true<td> <td>false<td> <td>tukey(0.5)<td> <td>8<td> <td>0<td> <td>false<td> <td>false<td> <td>false<td> <td>0<td> <td>6<td> <td>0<td> </tr>
+ * <tr> <td><b>7</b><td> <td>true<td> <td>false<td> <td>tukey(0.5)<td> <td>8<td> <td>0<td> <td>false<td> <td>false<td> <td>true<td> <td>0<td> <td>6<td> <td>0<td> </tr>
+ * <tr> <td><b>8</b><td> <td>true<td> <td>false<td> <td>tukey(0.5)<td> <td>12<td> <td>0<td> <td>false<td> <td>false<td> <td>true<td> <td>0<td> <td>6<td> <td>0<td> </tr>
+ * </table>
+ *
+ * \default \c 5
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the blocksize to use while encoding.
+ *
+ * The number of samples to use per frame. Use \c 0 to let the encoder
+ * estimate a blocksize; this is usually best.
+ *
+ * \default \c 0
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set to \c true to enable mid-side encoding on stereo input. The
+ * number of channels must be 2 for this to have any effect. Set to
+ * \c false to use only independent channel coding.
+ *
+ * \default \c false
+ * \param encoder An encoder instance to set.
+ * \param value Flag value (see above).
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set to \c true to enable adaptive switching between mid-side and
+ * left-right encoding on stereo input. Set to \c false to use
+ * exhaustive searching. Setting this to \c true requires
+ * FLAC__stream_encoder_set_do_mid_side_stereo() to also be set to
+ * \c true in order to have any effect.
+ *
+ * \default \c false
+ * \param encoder An encoder instance to set.
+ * \param value Flag value (see above).
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/* @@@@add to unit tests*/
+/** Sets the apodization function(s) the encoder will use when windowing
+ * audio data for LPC analysis.
+ *
+ * The \a specification is a plain ASCII string which specifies exactly
+ * which functions to use. There may be more than one (up to 32),
+ * separated by \c ';' characters. Some functions take one or more
+ * comma-separated arguments in parentheses.
+ *
+ * The available functions are \c bartlett, \c bartlett_hann,
+ * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop,
+ * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall,
+ * \c rectangle, \c triangle, \c tukey(P), \c welch.
+ *
+ * For \c gauss(STDDEV), STDDEV specifies the standard deviation
+ * (0<STDDEV<=0.5).
+ *
+ * For \c tukey(P), P specifies the fraction of the window that is
+ * tapered (0<=P<=1). P=0 corresponds to \c rectangle and P=1
+ * corresponds to \c hann.
+ *
+ * Example specifications are \c "blackman" or
+ * \c "hann;triangle;tukey(0.5);tukey(0.25);tukey(0.125)"
+ *
+ * Any function that is specified erroneously is silently dropped. Up
+ * to 32 functions are kept, the rest are dropped. If the specification
+ * is empty the encoder defaults to \c "tukey(0.5)".
+ *
+ * When more than one function is specified, then for every subframe the
+ * encoder will try each of them separately and choose the window that
+ * results in the smallest compressed subframe.
+ *
+ * Note that each function specified causes the encoder to occupy a
+ * floating point array in which to store the window.
+ *
+ * \default \c "tukey(0.5)"
+ * \param encoder An encoder instance to set.
+ * \param specification See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \code specification != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification);
+
+/** Set the maximum LPC order, or \c 0 to use only the fixed predictors.
+ *
+ * \default \c 0
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the precision, in bits, of the quantized linear predictor
+ * coefficients, or \c 0 to let the encoder select it based on the
+ * blocksize.
+ *
+ * \note
+ * In the current implementation, qlp_coeff_precision + bits_per_sample must
+ * be less than 32.
+ *
+ * \default \c 0
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set to \c false to use only the specified quantized linear predictor
+ * coefficient precision, or \c true to search neighboring precision
+ * values and use the best one.
+ *
+ * \default \c false
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Deprecated. Setting this value has no effect.
+ *
+ * \default \c false
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set to \c false to let the encoder estimate the best model order
+ * based on the residual signal energy, or \c true to force the
+ * encoder to evaluate all order models and select the best.
+ *
+ * \default \c false
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value);
+
+/** Set the minimum partition order to search when coding the residual.
+ * This is used in tandem with
+ * FLAC__stream_encoder_set_max_residual_partition_order().
+ *
+ * The partition order determines the context size in the residual.
+ * The context size will be approximately <tt>blocksize / (2 ^ order)</tt>.
+ *
+ * Set both min and max values to \c 0 to force a single context,
+ * whose Rice parameter is based on the residual signal variance.
+ * Otherwise, set a min and max order, and the encoder will search
+ * all orders, using the mean of each context for its Rice parameter,
+ * and use the best.
+ *
+ * \default \c 0
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set the maximum partition order to search when coding the residual.
+ * This is used in tandem with
+ * FLAC__stream_encoder_set_min_residual_partition_order().
+ *
+ * The partition order determines the context size in the residual.
+ * The context size will be approximately <tt>blocksize / (2 ^ order)</tt>.
+ *
+ * Set both min and max values to \c 0 to force a single context,
+ * whose Rice parameter is based on the residual signal variance.
+ * Otherwise, set a min and max order, and the encoder will search
+ * all orders, using the mean of each context for its Rice parameter,
+ * and use the best.
+ *
+ * \default \c 0
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Deprecated. Setting this value has no effect.
+ *
+ * \default \c 0
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value);
+
+/** Set an estimate of the total samples that will be encoded.
+ * This is merely an estimate and may be set to \c 0 if unknown.
+ * This value will be written to the STREAMINFO block before encoding,
+ * and can remove the need for the caller to rewrite the value later
+ * if the value is known before encoding.
+ *
+ * \default \c 0
+ * \param encoder An encoder instance to set.
+ * \param value See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value);
+
+/** Set the metadata blocks to be emitted to the stream before encoding.
+ * A value of \c NULL, \c 0 implies no metadata; otherwise, supply an
+ * array of pointers to metadata blocks. The array is non-const since
+ * the encoder may need to change the \a is_last flag inside them, and
+ * in some cases update seek point offsets. Otherwise, the encoder will
+ * not modify or free the blocks. It is up to the caller to free the
+ * metadata blocks after encoding finishes.
+ *
+ * \note
+ * The encoder stores only copies of the pointers in the \a metadata array;
+ * the metadata blocks themselves must survive at least until after
+ * FLAC__stream_encoder_finish() returns. Do not free the blocks until then.
+ *
+ * \note
+ * The STREAMINFO block is always written and no STREAMINFO block may
+ * occur in the supplied array.
+ *
+ * \note
+ * By default the encoder does not create a SEEKTABLE. If one is supplied
+ * in the \a metadata array, but the client has specified that it does not
+ * support seeking, then the SEEKTABLE will be written verbatim. However
+ * by itself this is not very useful as the client will not know the stream
+ * offsets for the seekpoints ahead of time. In order to get a proper
+ * seektable the client must support seeking. See next note.
+ *
+ * \note
+ * SEEKTABLE blocks are handled specially. Since you will not know
+ * the values for the seek point stream offsets, you should pass in
+ * a SEEKTABLE 'template', that is, a SEEKTABLE object with the
+ * required sample numbers (or placeholder points), with \c 0 for the
+ * \a frame_samples and \a stream_offset fields for each point. If the
+ * client has specified that it supports seeking by providing a seek
+ * callback to FLAC__stream_encoder_init_stream() or both seek AND read
+ * callback to FLAC__stream_encoder_init_ogg_stream() (or by using
+ * FLAC__stream_encoder_init*_file() or FLAC__stream_encoder_init*_FILE()),
+ * then while it is encoding the encoder will fill the stream offsets in
+ * for you and when encoding is finished, it will seek back and write the
+ * real values into the SEEKTABLE block in the stream. There are helper
+ * routines for manipulating seektable template blocks; see metadata.h:
+ * FLAC__metadata_object_seektable_template_*(). If the client does
+ * not support seeking, the SEEKTABLE will have inaccurate offsets which
+ * will slow down or remove the ability to seek in the FLAC stream.
+ *
+ * \note
+ * The encoder instance \b will modify the first \c SEEKTABLE block
+ * as it transforms the template to a valid seektable while encoding,
+ * but it is still up to the caller to free all metadata blocks after
+ * encoding.
+ *
+ * \note
+ * A VORBIS_COMMENT block may be supplied. The vendor string in it
+ * will be ignored. libFLAC will use it's own vendor string. libFLAC
+ * will not modify the passed-in VORBIS_COMMENT's vendor string, it
+ * will simply write it's own into the stream. If no VORBIS_COMMENT
+ * block is present in the \a metadata array, libFLAC will write an
+ * empty one, containing only the vendor string.
+ *
+ * \note The Ogg FLAC mapping requires that the VORBIS_COMMENT block be
+ * the second metadata block of the stream. The encoder already supplies
+ * the STREAMINFO block automatically. If \a metadata does not contain a
+ * VORBIS_COMMENT block, the encoder will supply that too. Otherwise, if
+ * \a metadata does contain a VORBIS_COMMENT block and it is not the
+ * first, the init function will reorder \a metadata by moving the
+ * VORBIS_COMMENT block to the front; the relative ordering of the other
+ * blocks will remain as they were.
+ *
+ * \note The Ogg FLAC mapping limits the number of metadata blocks per
+ * stream to \c 65535. If \a num_blocks exceeds this the function will
+ * return \c false.
+ *
+ * \default \c NULL, 0
+ * \param encoder An encoder instance to set.
+ * \param metadata See above.
+ * \param num_blocks See above.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if the encoder is already initialized, else \c true.
+ * \c false if the encoder is already initialized, or if
+ * \a num_blocks > 65535 if encoding to Ogg FLAC, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
+
+/** Get the current encoder state.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderState
+ * The current encoder state.
+ */
+FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder);
+
+/** Get the state of the verify stream decoder.
+ * Useful when the stream encoder state is
+ * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__StreamDecoderState
+ * The verify stream decoder state.
+ */
+FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder);
+
+/** Get the current encoder state as a C string.
+ * This version automatically resolves
+ * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR by getting the
+ * verify decoder's state.
+ *
+ * \param encoder A encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval const char *
+ * The encoder state as a C string. Do not modify the contents.
+ */
+FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder);
+
+/** Get relevant values about the nature of a verify decoder error.
+ * Useful when the stream encoder state is
+ * \c FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR. The arguments should
+ * be addresses in which the stats will be returned, or NULL if value
+ * is not desired.
+ *
+ * \param encoder An encoder instance to query.
+ * \param absolute_sample The absolute sample number of the mismatch.
+ * \param frame_number The number of the frame in which the mismatch occurred.
+ * \param channel The channel in which the mismatch occurred.
+ * \param sample The number of the sample (relative to the frame) in
+ * which the mismatch occurred.
+ * \param expected The expected value for the sample in question.
+ * \param got The actual value returned by the decoder.
+ * \assert
+ * \code encoder != NULL \endcode
+ */
+FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+
+/** Get the "verify" flag.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * See FLAC__stream_encoder_set_verify().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder);
+
+/** Get the <A HREF="../format.html#subset>Subset</A> flag.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * See FLAC__stream_encoder_set_streamable_subset().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder);
+
+/** Get the number of input channels being processed.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval unsigned
+ * See FLAC__stream_encoder_set_channels().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder);
+
+/** Get the input sample resolution setting.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval unsigned
+ * See FLAC__stream_encoder_set_bits_per_sample().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder);
+
+/** Get the input sample rate setting.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval unsigned
+ * See FLAC__stream_encoder_set_sample_rate().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder);
+
+/** Get the blocksize setting.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval unsigned
+ * See FLAC__stream_encoder_set_blocksize().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder);
+
+/** Get the "mid/side stereo coding" flag.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * See FLAC__stream_encoder_get_do_mid_side_stereo().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder);
+
+/** Get the "adaptive mid/side switching" flag.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * See FLAC__stream_encoder_set_loose_mid_side_stereo().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder);
+
+/** Get the maximum LPC order setting.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval unsigned
+ * See FLAC__stream_encoder_set_max_lpc_order().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder);
+
+/** Get the quantized linear predictor coefficient precision setting.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval unsigned
+ * See FLAC__stream_encoder_set_qlp_coeff_precision().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder);
+
+/** Get the qlp coefficient precision search flag.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * See FLAC__stream_encoder_set_do_qlp_coeff_prec_search().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder);
+
+/** Get the "escape coding" flag.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * See FLAC__stream_encoder_set_do_escape_coding().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder);
+
+/** Get the exhaustive model search flag.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * See FLAC__stream_encoder_set_do_exhaustive_model_search().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder);
+
+/** Get the minimum residual partition order setting.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval unsigned
+ * See FLAC__stream_encoder_set_min_residual_partition_order().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder);
+
+/** Get maximum residual partition order setting.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval unsigned
+ * See FLAC__stream_encoder_set_max_residual_partition_order().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder);
+
+/** Get the Rice parameter search distance setting.
+ *
+ * \param encoder An encoder instance to query.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval unsigned
+ * See FLAC__stream_encoder_set_rice_parameter_search_dist().
+ */
+FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder);
+
+/** Get the previously set estimate of the total samples to be encoded.
+ * The encoder merely mimics back the value given to
+ * FLAC__stream_encoder_set_total_samples_estimate() since it has no
+ * other way of knowing how many samples the client will encode.
+ *
+ * \param encoder An encoder instance to set.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__uint64
+ * See FLAC__stream_encoder_get_total_samples_estimate().
+ */
+FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder);
+
+/** Initialize the encoder instance to encode native FLAC streams.
+ *
+ * This flavor of initialization sets up the encoder to encode to a
+ * native FLAC stream. I/O is performed via callbacks to the client.
+ * For encoding to a plain file via filename or open \c FILE*,
+ * FLAC__stream_encoder_init_file() and FLAC__stream_encoder_init_FILE()
+ * provide a simpler interface.
+ *
+ * This function should be called after FLAC__stream_encoder_new() and
+ * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ * or FLAC__stream_encoder_process_interleaved().
+ * initialization succeeded.
+ *
+ * The call to FLAC__stream_encoder_init_stream() currently will also
+ * immediately call the write callback several times, once with the \c fLaC
+ * signature, and once for each encoded metadata block.
+ *
+ * \param encoder An uninitialized encoder instance.
+ * \param write_callback See FLAC__StreamEncoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param seek_callback See FLAC__StreamEncoderSeekCallback. This
+ * pointer may be \c NULL if seeking is not
+ * supported. The encoder uses seeking to go back
+ * and write some some stream statistics to the
+ * STREAMINFO block; this is recommended but not
+ * necessary to create a valid FLAC stream. If
+ * \a seek_callback is not \c NULL then a
+ * \a tell_callback must also be supplied.
+ * Alternatively, a dummy seek callback that just
+ * returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the encoder.
+ * \param tell_callback See FLAC__StreamEncoderTellCallback. This
+ * pointer may be \c NULL if seeking is not
+ * supported. If \a seek_callback is \c NULL then
+ * this argument will be ignored. If
+ * \a seek_callback is not \c NULL then a
+ * \a tell_callback must also be supplied.
+ * Alternatively, a dummy tell callback that just
+ * returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the encoder.
+ * \param metadata_callback See FLAC__StreamEncoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired. If the client provides a seek callback,
+ * this function is not necessary as the encoder
+ * will automatically seek back and update the
+ * STREAMINFO block. It may also be \c NULL if the
+ * client does not support seeking, since it will
+ * have no way of going back to update the
+ * STREAMINFO. However the client can still supply
+ * a callback if it would like to know the details
+ * from the STREAMINFO.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data);
+
+/** Initialize the encoder instance to encode Ogg FLAC streams.
+ *
+ * This flavor of initialization sets up the encoder to encode to a FLAC
+ * stream in an Ogg container. I/O is performed via callbacks to the
+ * client. For encoding to a plain file via filename or open \c FILE*,
+ * FLAC__stream_encoder_init_ogg_file() and FLAC__stream_encoder_init_ogg_FILE()
+ * provide a simpler interface.
+ *
+ * This function should be called after FLAC__stream_encoder_new() and
+ * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ * or FLAC__stream_encoder_process_interleaved().
+ * initialization succeeded.
+ *
+ * The call to FLAC__stream_encoder_init_ogg_stream() currently will also
+ * immediately call the write callback several times to write the metadata
+ * packets.
+ *
+ * \param encoder An uninitialized encoder instance.
+ * \param read_callback See FLAC__StreamEncoderReadCallback. This
+ * pointer must not be \c NULL if \a seek_callback
+ * is non-NULL since they are both needed to be
+ * able to write data back to the Ogg FLAC stream
+ * in the post-encode phase.
+ * \param write_callback See FLAC__StreamEncoderWriteCallback. This
+ * pointer must not be \c NULL.
+ * \param seek_callback See FLAC__StreamEncoderSeekCallback. This
+ * pointer may be \c NULL if seeking is not
+ * supported. The encoder uses seeking to go back
+ * and write some some stream statistics to the
+ * STREAMINFO block; this is recommended but not
+ * necessary to create a valid FLAC stream. If
+ * \a seek_callback is not \c NULL then a
+ * \a tell_callback must also be supplied.
+ * Alternatively, a dummy seek callback that just
+ * returns \c FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the encoder.
+ * \param tell_callback See FLAC__StreamEncoderTellCallback. This
+ * pointer may be \c NULL if seeking is not
+ * supported. If \a seek_callback is \c NULL then
+ * this argument will be ignored. If
+ * \a seek_callback is not \c NULL then a
+ * \a tell_callback must also be supplied.
+ * Alternatively, a dummy tell callback that just
+ * returns \c FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED
+ * may also be supplied, all though this is slightly
+ * less efficient for the encoder.
+ * \param metadata_callback See FLAC__StreamEncoderMetadataCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired. If the client provides a seek callback,
+ * this function is not necessary as the encoder
+ * will automatically seek back and update the
+ * STREAMINFO block. It may also be \c NULL if the
+ * client does not support seeking, since it will
+ * have no way of going back to update the
+ * STREAMINFO. However the client can still supply
+ * a callback if it would like to know the details
+ * from the STREAMINFO.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream(FLAC__StreamEncoder *encoder, FLAC__StreamEncoderReadCallback read_callback, FLAC__StreamEncoderWriteCallback write_callback, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderTellCallback tell_callback, FLAC__StreamEncoderMetadataCallback metadata_callback, void *client_data);
+
+/** Initialize the encoder instance to encode native FLAC files.
+ *
+ * This flavor of initialization sets up the encoder to encode to a
+ * plain native FLAC file. For non-stdio streams, you must use
+ * FLAC__stream_encoder_init_stream() and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_encoder_new() and
+ * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ * or FLAC__stream_encoder_process_interleaved().
+ * initialization succeeded.
+ *
+ * \param encoder An uninitialized encoder instance.
+ * \param file An open file. The file should have been opened
+ * with mode \c "w+b" and rewound. The file
+ * becomes owned by the encoder and should not be
+ * manipulated by the client while encoding.
+ * Unless \a file is \c stdout, it will be closed
+ * when FLAC__stream_encoder_finish() is called.
+ * Note however that a proper SEEKTABLE cannot be
+ * created when encoding to \c stdout since it is
+ * not seekable.
+ * \param progress_callback See FLAC__StreamEncoderProgressCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \code file != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Initialize the encoder instance to encode Ogg FLAC files.
+ *
+ * This flavor of initialization sets up the encoder to encode to a
+ * plain Ogg FLAC file. For non-stdio streams, you must use
+ * FLAC__stream_encoder_init_ogg_stream() and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_encoder_new() and
+ * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ * or FLAC__stream_encoder_process_interleaved().
+ * initialization succeeded.
+ *
+ * \param encoder An uninitialized encoder instance.
+ * \param file An open file. The file should have been opened
+ * with mode \c "w+b" and rewound. The file
+ * becomes owned by the encoder and should not be
+ * manipulated by the client while encoding.
+ * Unless \a file is \c stdout, it will be closed
+ * when FLAC__stream_encoder_finish() is called.
+ * Note however that a proper SEEKTABLE cannot be
+ * created when encoding to \c stdout since it is
+ * not seekable.
+ * \param progress_callback See FLAC__StreamEncoderProgressCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \code file != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(FLAC__StreamEncoder *encoder, FILE *file, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Initialize the encoder instance to encode native FLAC files.
+ *
+ * This flavor of initialization sets up the encoder to encode to a plain
+ * FLAC file. If POSIX fopen() semantics are not sufficient (for example,
+ * with Unicode filenames on Windows), you must use
+ * FLAC__stream_encoder_init_FILE(), or FLAC__stream_encoder_init_stream()
+ * and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_encoder_new() and
+ * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ * or FLAC__stream_encoder_process_interleaved().
+ * initialization succeeded.
+ *
+ * \param encoder An uninitialized encoder instance.
+ * \param filename The name of the file to encode to. The file will
+ * be opened with fopen(). Use \c NULL to encode to
+ * \c stdout. Note however that a proper SEEKTABLE
+ * cannot be created when encoding to \c stdout since
+ * it is not seekable.
+ * \param progress_callback See FLAC__StreamEncoderProgressCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Initialize the encoder instance to encode Ogg FLAC files.
+ *
+ * This flavor of initialization sets up the encoder to encode to a plain
+ * Ogg FLAC file. If POSIX fopen() semantics are not sufficient (for example,
+ * with Unicode filenames on Windows), you must use
+ * FLAC__stream_encoder_init_ogg_FILE(), or FLAC__stream_encoder_init_ogg_stream()
+ * and provide callbacks for the I/O.
+ *
+ * This function should be called after FLAC__stream_encoder_new() and
+ * FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
+ * or FLAC__stream_encoder_process_interleaved().
+ * initialization succeeded.
+ *
+ * \param encoder An uninitialized encoder instance.
+ * \param filename The name of the file to encode to. The file will
+ * be opened with fopen(). Use \c NULL to encode to
+ * \c stdout. Note however that a proper SEEKTABLE
+ * cannot be created when encoding to \c stdout since
+ * it is not seekable.
+ * \param progress_callback See FLAC__StreamEncoderProgressCallback. This
+ * pointer may be \c NULL if the callback is not
+ * desired.
+ * \param client_data This value will be supplied to callbacks in their
+ * \a client_data argument.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__StreamEncoderInitStatus
+ * \c FLAC__STREAM_ENCODER_INIT_STATUS_OK if initialization was successful;
+ * see FLAC__StreamEncoderInitStatus for the meanings of other return values.
+ */
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file(FLAC__StreamEncoder *encoder, const char *filename, FLAC__StreamEncoderProgressCallback progress_callback, void *client_data);
+
+/** Finish the encoding process.
+ * Flushes the encoding buffer, releases resources, resets the encoder
+ * settings to their defaults, and returns the encoder state to
+ * FLAC__STREAM_ENCODER_UNINITIALIZED. Note that this can generate
+ * one or more write callbacks before returning, and will generate
+ * a metadata callback.
+ *
+ * Note that in the course of processing the last frame, errors can
+ * occur, so the caller should be sure to check the return value to
+ * ensure the file was encoded properly.
+ *
+ * In the event of a prematurely-terminated encode, it is not strictly
+ * necessary to call this immediately before FLAC__stream_encoder_delete()
+ * but it is good practice to match every FLAC__stream_encoder_init_*()
+ * with a FLAC__stream_encoder_finish().
+ *
+ * \param encoder An uninitialized encoder instance.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ * \c false if an error occurred processing the last frame; or if verify
+ * mode is set (see FLAC__stream_encoder_set_verify()), there was a
+ * verify mismatch; else \c true. If \c false, caller should check the
+ * state with FLAC__stream_encoder_get_state() for more information
+ * about the error.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder);
+
+/** Submit data for encoding.
+ * This version allows you to supply the input data via an array of
+ * pointers, each pointer pointing to an array of \a samples samples
+ * representing one channel. The samples need not be block-aligned,
+ * but each channel should have the same number of samples. Each sample
+ * should be a signed integer, right-justified to the resolution set by
+ * FLAC__stream_encoder_set_bits_per_sample(). For example, if the
+ * resolution is 16 bits per sample, the samples should all be in the
+ * range [-32768,32767].
+ *
+ * For applications where channel order is important, channels must
+ * follow the order as described in the
+ * <A HREF="../format.html#frame_header">frame header</A>.
+ *
+ * \param encoder An initialized encoder instance in the OK state.
+ * \param buffer An array of pointers to each channel's signal.
+ * \param samples The number of samples in one channel.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false; in this case, check the
+ * encoder state with FLAC__stream_encoder_get_state() to see what
+ * went wrong.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
+
+/** Submit data for encoding.
+ * This version allows you to supply the input data where the channels
+ * are interleaved into a single array (i.e. channel0_sample0,
+ * channel1_sample0, ... , channelN_sample0, channel0_sample1, ...).
+ * The samples need not be block-aligned but they must be
+ * sample-aligned, i.e. the first value should be channel0_sample0
+ * and the last value channelN_sampleM. Each sample should be a signed
+ * integer, right-justified to the resolution set by
+ * FLAC__stream_encoder_set_bits_per_sample(). For example, if the
+ * resolution is 16 bits per sample, the samples should all be in the
+ * range [-32768,32767].
+ *
+ * For applications where channel order is important, channels must
+ * follow the order as described in the
+ * <A HREF="../format.html#frame_header">frame header</A>.
+ *
+ * \param encoder An initialized encoder instance in the OK state.
+ * \param buffer An array of channel-interleaved data (see above).
+ * \param samples The number of samples in one channel, the same as for
+ * FLAC__stream_encoder_process(). For example, if
+ * encoding two channels, \c 1000 \a samples corresponds
+ * to a \a buffer of 2000 values.
+ * \assert
+ * \code encoder != NULL \endcode
+ * \code FLAC__stream_encoder_get_state(encoder) == FLAC__STREAM_ENCODER_OK \endcode
+ * \retval FLAC__bool
+ * \c true if successful, else \c false; in this case, check the
+ * encoder state with FLAC__stream_encoder_get_state() to see what
+ * went wrong.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
+
+/* \} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/FLAC/include/Makefile.am b/src/FLAC/include/Makefile.am
new file mode 100644
index 0000000..2015f83
--- /dev/null
+++ b/src/FLAC/include/Makefile.am
@@ -0,0 +1,18 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under difference licenses. The codec libraries
+# are distributed under Xiph.Org's BSD-like license (see the file
+# COPYING.Xiph in this distribution). All other programs, libraries, and
+# plugins are distributed under the GPL (see COPYING.GPL). The documentation
+# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
+# FLAC distribution contains at the top the terms under which it may be
+# distributed.
+#
+# Since this particular file is relevant to all components of FLAC,
+# it may be distributed under the Xiph.Org license, which is the least
+# restrictive of those mentioned above. See the file COPYING.Xiph in this
+# distribution.
+
+SUBDIRS = FLAC share test_libs_common
diff --git a/src/FLAC/include/share/Makefile.am b/src/FLAC/include/share/Makefile.am
new file mode 100644
index 0000000..b50d883
--- /dev/null
+++ b/src/FLAC/include/share/Makefile.am
@@ -0,0 +1,12 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = grabbag
+
+EXTRA_DIST = \
+ getopt.h \
+ grabbag.h \
+ replaygain_analysis.h \
+ replaygain_synthesis.h \
+ utf8.h
diff --git a/src/FLAC/include/share/getopt.h b/src/FLAC/include/share/getopt.h
new file mode 100644
index 0000000..5b97691
--- /dev/null
+++ b/src/FLAC/include/share/getopt.h
@@ -0,0 +1,184 @@
+/*
+ NOTE:
+ I cannot get the vanilla getopt code to work (i.e. compile only what
+ is needed and not duplicate symbols found in the standard library)
+ on all the platforms that FLAC supports. In particular the gating
+ of code with the ELIDE_CODE #define is not accurate enough on systems
+ that are POSIX but not glibc. If someone has a patch that works on
+ GNU/Linux, Darwin, AND Solaris please submit it on the project page:
+ http://sourceforge.net/projects/flac
+
+ In the meantime I have munged the global symbols and removed gates
+ around code, while at the same time trying to touch the original as
+ little as possible.
+*/
+/* Declarations for getopt.
+ Copyright (C) 1989,90,91,92,93,94,96,97,98 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef SHARE__GETOPT_H
+#define SHARE__GETOPT_H
+
+/*[JEC] was:#ifndef __need_getopt*/
+/*[JEC] was:# define _GETOPT_H 1*/
+/*[JEC] was:#endif*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For communication from `share__getopt' to the caller.
+ When `share__getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *share__optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `share__getopt'.
+
+ On entry to `share__getopt', zero means this is the first call; initialize.
+
+ When `share__getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `share__optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int share__optind;
+
+/* Callers store zero here to inhibit the error message `share__getopt' prints
+ for unrecognized options. */
+
+extern int share__opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int share__optopt;
+
+/*[JEC] was:#ifndef __need_getopt */
+/* Describe the long-named options requested by the application.
+ The LONG_OPTIONS argument to share__getopt_long or share__getopt_long_only is a vector
+ of `struct share__option' terminated by an element containing a name which is
+ zero.
+
+ The field `has_arg' is:
+ share__no_argument (or 0) if the option does not take an argument,
+ share__required_argument (or 1) if the option requires an argument,
+ share__optional_argument (or 2) if the option takes an optional argument.
+
+ If the field `flag' is not NULL, it points to a variable that is set
+ to the value given in the field `val' when the option is found, but
+ left unchanged if the option is not found.
+
+ To have a long-named option do something other than set an `int' to
+ a compiled-in constant, such as set a value from `share__optarg', set the
+ option's `flag' field to zero and its `val' field to a nonzero
+ value (the equivalent single-letter option character, if there is
+ one). For long options that have a zero `flag' field, `share__getopt'
+ returns the contents of the `val' field. */
+
+struct share__option
+{
+# if defined __STDC__ && __STDC__
+ const char *name;
+# else
+ char *name;
+# endif
+ /* has_arg can't be an enum because some compilers complain about
+ type mismatches in all the code that assumes it is an int. */
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+/* Names for the values of the `has_arg' field of `struct share__option'. */
+
+# define share__no_argument 0
+# define share__required_argument 1
+# define share__optional_argument 2
+/*[JEC] was:#endif*/ /* need getopt */
+
+
+/* Get definitions and prototypes for functions to process the
+ arguments in ARGV (ARGC of them, minus the program name) for
+ options given in OPTS.
+
+ Return the option character from OPTS just read. Return -1 when
+ there are no more options. For unrecognized options, or options
+ missing arguments, `share__optopt' is set to the option letter, and '?' is
+ returned.
+
+ The OPTS string is a list of characters which are recognized option
+ letters, optionally followed by colons, specifying that that letter
+ takes an argument, to be placed in `share__optarg'.
+
+ If a letter in OPTS is followed by two colons, its argument is
+ optional. This behavior is specific to the GNU `share__getopt'.
+
+ The argument `--' causes premature termination of argument
+ scanning, explicitly telling `share__getopt' that there are no more
+ options.
+
+ If OPTS begins with `--', then non-option arguments are treated as
+ arguments to the option '\0'. This behavior is specific to the GNU
+ `share__getopt'. */
+
+/*[JEC] was:#if defined __STDC__ && __STDC__*/
+/*[JEC] was:# ifdef __GNU_LIBRARY__*/
+/* Many other libraries have conflicting prototypes for getopt, with
+ differences in the consts, in stdlib.h. To avoid compilation
+ errors, only prototype getopt for the GNU C library. */
+extern int share__getopt (int argc, char **argv, const char *shortopts);
+/*[JEC] was:# else*/ /* not __GNU_LIBRARY__ */
+/*[JEC] was:extern int getopt ();*/
+/*[JEC] was:# endif*/ /* __GNU_LIBRARY__ */
+
+/*[JEC] was:# ifndef __need_getopt*/
+extern int share__getopt_long (int argc, char **argv, const char *shortopts,
+ const struct share__option *longopts, int *longind);
+extern int share__getopt_long_only (int argc, char **argv,
+ const char *shortopts,
+ const struct share__option *longopts, int *longind);
+
+/* Internal only. Users should not call this directly. */
+extern int share___getopt_internal (int argc, char **argv,
+ const char *shortopts,
+ const struct share__option *longopts, int *longind,
+ int long_only);
+/*[JEC] was:# endif*/
+/*[JEC] was:#else*/ /* not __STDC__ */
+/*[JEC] was:extern int getopt ();*/
+/*[JEC] was:# ifndef __need_getopt*/
+/*[JEC] was:extern int getopt_long ();*/
+/*[JEC] was:extern int getopt_long_only ();*/
+
+/*[JEC] was:extern int _getopt_internal ();*/
+/*[JEC] was:# endif*/
+/*[JEC] was:#endif*/ /* __STDC__ */
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Make sure we later can get all the definitions and declarations. */
+/*[JEC] was:#undef __need_getopt*/
+
+#endif /* getopt.h */
diff --git a/src/FLAC/include/share/grabbag.h b/src/FLAC/include/share/grabbag.h
new file mode 100644
index 0000000..42c6998
--- /dev/null
+++ b/src/FLAC/include/share/grabbag.h
@@ -0,0 +1,29 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef SHARE__GRABBAG_H
+#define SHARE__GRABBAG_H
+
+/* These can't be included by themselves, only from within grabbag.h */
+#include "grabbag/cuesheet.h"
+#include "grabbag/file.h"
+#include "grabbag/picture.h"
+#include "grabbag/replaygain.h"
+#include "grabbag/seektable.h"
+
+#endif
diff --git a/src/FLAC/include/share/grabbag/Makefile.am b/src/FLAC/include/share/grabbag/Makefile.am
new file mode 100644
index 0000000..0d520aa
--- /dev/null
+++ b/src/FLAC/include/share/grabbag/Makefile.am
@@ -0,0 +1,10 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+EXTRA_DIST = \
+ cuesheet.h \
+ file.h \
+ picture.h \
+ replaygain.h \
+ seektable.h
diff --git a/src/FLAC/include/share/grabbag/cuesheet.h b/src/FLAC/include/share/grabbag/cuesheet.h
new file mode 100644
index 0000000..698d49b
--- /dev/null
+++ b/src/FLAC/include/share/grabbag/cuesheet.h
@@ -0,0 +1,42 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABBAG__CUESHEET_H
+#define GRABBAG__CUESHEET_H
+
+#include <stdio.h>
+#include "FLAC/metadata.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames);
+void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames);
+
+FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset);
+
+void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/FLAC/include/share/grabbag/file.h b/src/FLAC/include/share/grabbag/file.h
new file mode 100644
index 0000000..c8b149f
--- /dev/null
+++ b/src/FLAC/include/share/grabbag/file.h
@@ -0,0 +1,63 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Convenience routines for manipulating files */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABAG__FILE_H
+#define GRABAG__FILE_H
+
+/* needed because of off_t */
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h> /* for off_t */
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grabbag__file_copy_metadata(const char *srcpath, const char *destpath);
+off_t grabbag__file_get_filesize(const char *srcpath);
+const char *grabbag__file_get_basename(const char *srcpath);
+
+/* read_only == false means "make file writable by user"
+ * read_only == true means "make file read-only for everyone"
+ */
+FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only);
+
+/* returns true iff stat() succeeds for both files and they have the same device and inode. */
+/* on windows, uses GetFileInformationByHandle() to compare */
+FLAC__bool grabbag__file_are_same(const char *f1, const char *f2);
+
+/* attempts to make writable before unlinking */
+FLAC__bool grabbag__file_remove_file(const char *filename);
+
+/* these will forcibly set stdin/stdout to binary mode (for OSes that require it) */
+FILE *grabbag__file_get_binary_stdin(void);
+FILE *grabbag__file_get_binary_stdout(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/FLAC/include/share/grabbag/picture.h b/src/FLAC/include/share/grabbag/picture.h
new file mode 100644
index 0000000..e7f4278
--- /dev/null
+++ b/src/FLAC/include/share/grabbag/picture.h
@@ -0,0 +1,46 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2006,2007 Josh Coalson
+ *
+ * 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 .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABBAG__PICTURE_H
+#define GRABBAG__PICTURE_H
+
+#include "FLAC/metadata.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* spec should be of the form "[TYPE]|MIME_TYPE|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE", e.g.
+ * "|image/jpeg|||cover.jpg"
+ * "4|image/jpeg||300x300x24|backcover.jpg"
+ * "|image/png|description|300x300x24/71|cover.png"
+ * "-->|image/gif||300x300x24/71|http://blah.blah.blah/cover.gif"
+ *
+ * empty type means default to FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER
+ * empty resolution spec means to get from the file (cannot get used with "-->" linked images)
+ * spec and error_message must not be NULL
+ */
+FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/FLAC/include/share/grabbag/replaygain.h b/src/FLAC/include/share/grabbag/replaygain.h
new file mode 100644
index 0000000..ea8c935
--- /dev/null
+++ b/src/FLAC/include/share/grabbag/replaygain.h
@@ -0,0 +1,72 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * This wraps the replaygain_analysis lib, which is LGPL. This wrapper
+ * allows analysis of different input resolutions by automatically
+ * scaling the input signal
+ */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABBAG__REPLAYGAIN_H
+#define GRABBAG__REPLAYGAIN_H
+
+#include "FLAC/metadata.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED;
+
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS; /* = "REPLAYGAIN_REFERENCE_LOUDNESS" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN; /* = "REPLAYGAIN_TRACK_GAIN" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK; /* = "REPLAYGAIN_TRACK_PEAK" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN; /* = "REPLAYGAIN_ALBUM_GAIN" */
+extern const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK; /* = "REPLAYGAIN_ALBUM_PEAK" */
+
+FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency);
+
+FLAC__bool grabbag__replaygain_init(unsigned sample_frequency);
+
+/* 'bps' must be valid for FLAC, i.e. >=4 and <= 32 */
+FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples);
+
+void grabbag__replaygain_get_album(float *gain, float *peak);
+void grabbag__replaygain_get_title(float *gain, float *peak);
+
+/* These three functions return an error string on error, or NULL if successful */
+const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak);
+const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak);
+const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block);
+const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak);
+const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak);
+const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime);
+const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime);
+const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime);
+const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime);
+
+FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak);
+double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/FLAC/include/share/grabbag/seektable.h b/src/FLAC/include/share/grabbag/seektable.h
new file mode 100644
index 0000000..8010fc9
--- /dev/null
+++ b/src/FLAC/include/share/grabbag/seektable.h
@@ -0,0 +1,38 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Convenience routines for working with seek tables */
+
+/* This .h cannot be included by itself; #include "share/grabbag.h" instead. */
+
+#ifndef GRABAG__SEEKTABLE_H
+#define GRABAG__SEEKTABLE_H
+
+#include "FLAC/format.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/FLAC/include/share/replaygain_analysis.h b/src/FLAC/include/share/replaygain_analysis.h
new file mode 100644
index 0000000..02067d2
--- /dev/null
+++ b/src/FLAC/include/share/replaygain_analysis.h
@@ -0,0 +1,59 @@
+/*
+ * ReplayGainAnalysis - analyzes input samples and give the recommended dB change
+ * Copyright (C) 2001 David Robinson and Glen Sawyer
+ *
+ * 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
+ *
+ * concept and filter values by David Robinson (David@Robinson.org)
+ * -- blame him if you think the idea is flawed
+ * coding by Glen Sawyer (glensawyer@hotmail.com) 442 N 700 E, Provo, UT 84606 USA
+ * -- blame him if you think this runs too slowly, or the coding is otherwise flawed
+ * minor cosmetic tweaks to integrate with FLAC by Josh Coalson
+ *
+ * For an explanation of the concepts and the basic algorithms involved, go to:
+ * http://www.replaygain.org/
+ */
+
+#ifndef GAIN_ANALYSIS_H
+#define GAIN_ANALYSIS_H
+
+#include <stddef.h>
+
+#define GAIN_NOT_ENOUGH_SAMPLES -24601
+#define GAIN_ANALYSIS_ERROR 0
+#define GAIN_ANALYSIS_OK 1
+
+#define INIT_GAIN_ANALYSIS_ERROR 0
+#define INIT_GAIN_ANALYSIS_OK 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef float Float_t; /* Type used for filtering */
+
+extern Float_t ReplayGainReferenceLoudness; /* in dB SPL, currently == 89.0 */
+
+int InitGainAnalysis ( long samplefreq );
+int AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels );
+int ResetSampleFrequency ( long samplefreq );
+Float_t GetTitleGain ( void );
+Float_t GetAlbumGain ( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GAIN_ANALYSIS_H */
diff --git a/src/FLAC/include/share/replaygain_synthesis.h b/src/FLAC/include/share/replaygain_synthesis.h
new file mode 100644
index 0000000..ca1ae64
--- /dev/null
+++ b/src/FLAC/include/share/replaygain_synthesis.h
@@ -0,0 +1,51 @@
+/* replaygain_synthesis - Routines for applying ReplayGain to a signal
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H
+#define FLAC__SHARE__REPLAYGAIN_SYNTHESIS_H
+
+#include <stdlib.h> /* for size_t */
+#include "FLAC/ordinals.h"
+
+#define FLAC_SHARE__MAX_SUPPORTED_CHANNELS 2
+
+typedef enum {
+ NOISE_SHAPING_NONE = 0,
+ NOISE_SHAPING_LOW = 1,
+ NOISE_SHAPING_MEDIUM = 2,
+ NOISE_SHAPING_HIGH = 3
+} NoiseShaping;
+
+typedef struct {
+ const float* FilterCoeff;
+ FLAC__uint64 Mask;
+ double Add;
+ float Dither;
+ float ErrorHistory [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16]; /* 16th order Noise shaping */
+ float DitherHistory [FLAC_SHARE__MAX_SUPPORTED_CHANNELS] [16];
+ int LastRandomNumber [FLAC_SHARE__MAX_SUPPORTED_CHANNELS];
+ unsigned LastHistoryIndex;
+ NoiseShaping ShapingType;
+} DitherContext;
+
+void FLAC__replaygain_synthesis__init_dither_context(DitherContext *dither, int bits, int shapingtype);
+
+/* scale = (float) pow(10., (double)replaygain * 0.05); */
+size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context);
+
+#endif
diff --git a/src/FLAC/include/share/utf8.h b/src/FLAC/include/share/utf8.h
new file mode 100644
index 0000000..7d6650d
--- /dev/null
+++ b/src/FLAC/include/share/utf8.h
@@ -0,0 +1,25 @@
+#ifndef SHARE__UTF8_H
+#define SHARE__UTF8_H
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ *
+ * If the locale's charset is not set explicitly then it is
+ * obtained using nl_langinfo(CODESET), where available, the
+ * environment variable CHARSET, or assumed to be US-ASCII.
+ *
+ * Return value of conversion functions:
+ *
+ * -1 : memory allocation failed
+ * 0 : data was converted exactly
+ * 1 : valid data was converted approximately (using '?')
+ * 2 : input was invalid (but still converted, using '#')
+ * 3 : unknown encoding (but still converted, using '?')
+ */
+
+int utf8_encode(const char *from, char **to);
+int utf8_decode(const char *from, char **to);
+
+#endif
diff --git a/src/FLAC/include/test_libs_common/Makefile.am b/src/FLAC/include/test_libs_common/Makefile.am
new file mode 100644
index 0000000..a0342dc
--- /dev/null
+++ b/src/FLAC/include/test_libs_common/Makefile.am
@@ -0,0 +1,7 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+EXTRA_DIST = \
+ file_utils_flac.h \
+ metadata_utils.h
diff --git a/src/FLAC/include/test_libs_common/file_utils_flac.h b/src/FLAC/include/test_libs_common/file_utils_flac.h
new file mode 100644
index 0000000..27e3671
--- /dev/null
+++ b/src/FLAC/include/test_libs_common/file_utils_flac.h
@@ -0,0 +1,34 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_FILE_UTILS_H
+#define FLAC__TEST_LIBFLAC_FILE_UTILS_H
+
+/* needed because of off_t */
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/format.h"
+#include <sys/types.h> /* for off_t */
+
+extern const long file_utils__ogg_serial_number;
+
+FLAC__bool file_utils__generate_flacfile(FLAC__bool is_ogg, const char *output_filename, off_t *output_filesize, unsigned length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, unsigned num_metadata);
+
+#endif
diff --git a/src/FLAC/include/test_libs_common/metadata_utils.h b/src/FLAC/include/test_libs_common/metadata_utils.h
new file mode 100644
index 0000000..933bece
--- /dev/null
+++ b/src/FLAC/include/test_libs_common/metadata_utils.h
@@ -0,0 +1,73 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_METADATA_UTILS_H
+#define FLAC__TEST_LIBFLAC_METADATA_UTILS_H
+
+/*
+ * These are not tests, just utility functions used by the metadata tests
+ */
+
+#include "FLAC/format.h"
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp() */
+
+FLAC__bool mutils__compare_block_data_streaminfo(const FLAC__StreamMetadata_StreamInfo *block, const FLAC__StreamMetadata_StreamInfo *blockcopy);
+
+FLAC__bool mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding *block, const FLAC__StreamMetadata_Padding *blockcopy, unsigned block_length);
+
+FLAC__bool mutils__compare_block_data_application(const FLAC__StreamMetadata_Application *block, const FLAC__StreamMetadata_Application *blockcopy, unsigned block_length);
+
+FLAC__bool mutils__compare_block_data_seektable(const FLAC__StreamMetadata_SeekTable *block, const FLAC__StreamMetadata_SeekTable *blockcopy);
+
+FLAC__bool mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_VorbisComment *block, const FLAC__StreamMetadata_VorbisComment *blockcopy);
+
+FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy);
+
+FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy);
+
+FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, unsigned block_length);
+
+FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy);
+
+void mutils__init_metadata_blocks(
+ FLAC__StreamMetadata *streaminfo,
+ FLAC__StreamMetadata *padding,
+ FLAC__StreamMetadata *seektable,
+ FLAC__StreamMetadata *application1,
+ FLAC__StreamMetadata *application2,
+ FLAC__StreamMetadata *vorbiscomment,
+ FLAC__StreamMetadata *cuesheet,
+ FLAC__StreamMetadata *picture,
+ FLAC__StreamMetadata *unknown
+);
+
+void mutils__free_metadata_blocks(
+ FLAC__StreamMetadata *streaminfo,
+ FLAC__StreamMetadata *padding,
+ FLAC__StreamMetadata *seektable,
+ FLAC__StreamMetadata *application1,
+ FLAC__StreamMetadata *application2,
+ FLAC__StreamMetadata *vorbiscomment,
+ FLAC__StreamMetadata *cuesheet,
+ FLAC__StreamMetadata *picture,
+ FLAC__StreamMetadata *unknown
+);
+
+#endif
diff --git a/src/FLAC/src/Makefile.am b/src/FLAC/src/Makefile.am
new file mode 100644
index 0000000..ec715bb
--- /dev/null
+++ b/src/FLAC/src/Makefile.am
@@ -0,0 +1,27 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under difference licenses. The codec libraries
+# are distributed under Xiph.Org's BSD-like license (see the file
+# COPYING.Xiph in this distribution). All other programs, libraries, and
+# plugins are distributed under the GPL (see COPYING.GPL). The documentation
+# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
+# FLAC distribution contains at the top the terms under which it may be
+# distributed.
+#
+# Since this particular file is relevant to all components of FLAC,
+# it may be distributed under the Xiph.Org license, which is the least
+# restrictive of those mentioned above. See the file COPYING.Xiph in this
+# distribution.
+
+SUBDIRS = \
+ libFLAC \
+ share \
+ monkeys_audio_utilities \
+ test_grabbag \
+ test_libs_common \
+ test_libFLAC \
+ test_seeking \
+ test_streams
+
diff --git a/src/FLAC/src/libFLAC/Makefile.am b/src/FLAC/src/libFLAC/Makefile.am
new file mode 100644
index 0000000..cfae71c
--- /dev/null
+++ b/src/FLAC/src/libFLAC/Makefile.am
@@ -0,0 +1,92 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+noinst_LTLIBRARIES = libFLAC.la
+
+INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/FLAC/src/libFLAC/include \
+ -I$(top_srcdir)/src/FLAC/include -I$(top_srcdir)/src/OGG/include
+
+if FLaC__CPU_PPC
+# The -force_cpusubtype_ALL is needed to insert a ppc64 instruction
+# into cpu.c with an asm().
+if FLaC__SYS_DARWIN
+#@@@ PPC optimizations temporarily disabled
+CPUCFLAGS = -faltivec -force_cpusubtype_ALL -DFLAC__NO_ASM
+else
+# Linux-gcc for PPC does not have -force_cpusubtype_ALL, it is Darwin-specific
+#@@@ PPC optimizations temporarily disabled
+CPUCFLAGS = -maltivec -mabi=altivec -DFLAC__NO_ASM
+endif
+endif
+
+AM_CFLAGS = $(DEBUGCFLAGS) $(CPUCFLAGS)
+
+if FLaC__NO_ASM
+else
+if FLaC__CPU_IA32
+if FLaC__HAS_NASM
+ARCH_SUBDIRS = ia32
+LOCAL_EXTRA_LIBADD = $(top_builddir)/src/FLAC/src/libFLAC/ia32/libFLAC-asm.la
+endif
+endif
+if FLaC__CPU_PPC
+ARCH_SUBDIRS = ppc
+endif
+endif
+
+libFLAC_la_LIBADD = $(LOCAL_EXTRA_LIBADD)
+
+SUBDIRS = $(ARCH_SUBDIRS) include .
+
+extra_ogg_sources = \
+ ogg_decoder_aspect.c \
+ ogg_encoder_aspect.c \
+ ogg_helper.c \
+ ogg_mapping.c
+
+libFLAC_la_SOURCES = \
+ bitmath.c \
+ bitreader.c \
+ bitwriter.c \
+ cpu.c \
+ crc.c \
+ fixed.c \
+ float.c \
+ format.c \
+ lpc.c \
+ md5.c \
+ memory.c \
+ metadata_iterators.c \
+ metadata_object.c \
+ stream_decoder.c \
+ stream_encoder.c \
+ stream_encoder_framing.c \
+ window.c \
+ $(extra_ogg_sources)
diff --git a/src/FLAC/src/libFLAC/bitmath.c b/src/FLAC/src/libFLAC/bitmath.c
new file mode 100644
index 0000000..27e25f0
--- /dev/null
+++ b/src/FLAC/src/libFLAC/bitmath.c
@@ -0,0 +1,149 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/bitmath.h"
+#include "FLAC/assert.h"
+
+/* An example of what FLAC__bitmath_ilog2() computes:
+ *
+ * ilog2( 0) = assertion failure
+ * ilog2( 1) = 0
+ * ilog2( 2) = 1
+ * ilog2( 3) = 1
+ * ilog2( 4) = 2
+ * ilog2( 5) = 2
+ * ilog2( 6) = 2
+ * ilog2( 7) = 2
+ * ilog2( 8) = 3
+ * ilog2( 9) = 3
+ * ilog2(10) = 3
+ * ilog2(11) = 3
+ * ilog2(12) = 3
+ * ilog2(13) = 3
+ * ilog2(14) = 3
+ * ilog2(15) = 3
+ * ilog2(16) = 4
+ * ilog2(17) = 4
+ * ilog2(18) = 4
+ */
+unsigned FLAC__bitmath_ilog2(FLAC__uint32 v)
+{
+ unsigned l = 0;
+ FLAC__ASSERT(v > 0);
+ while(v >>= 1)
+ l++;
+ return l;
+}
+
+unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v)
+{
+ unsigned l = 0;
+ FLAC__ASSERT(v > 0);
+ while(v >>= 1)
+ l++;
+ return l;
+}
+
+/* An example of what FLAC__bitmath_silog2() computes:
+ *
+ * silog2(-10) = 5
+ * silog2(- 9) = 5
+ * silog2(- 8) = 4
+ * silog2(- 7) = 4
+ * silog2(- 6) = 4
+ * silog2(- 5) = 4
+ * silog2(- 4) = 3
+ * silog2(- 3) = 3
+ * silog2(- 2) = 2
+ * silog2(- 1) = 2
+ * silog2( 0) = 0
+ * silog2( 1) = 2
+ * silog2( 2) = 3
+ * silog2( 3) = 3
+ * silog2( 4) = 4
+ * silog2( 5) = 4
+ * silog2( 6) = 4
+ * silog2( 7) = 4
+ * silog2( 8) = 5
+ * silog2( 9) = 5
+ * silog2( 10) = 5
+ */
+unsigned FLAC__bitmath_silog2(int v)
+{
+ while(1) {
+ if(v == 0) {
+ return 0;
+ }
+ else if(v > 0) {
+ unsigned l = 0;
+ while(v) {
+ l++;
+ v >>= 1;
+ }
+ return l+1;
+ }
+ else if(v == -1) {
+ return 2;
+ }
+ else {
+ v++;
+ v = -v;
+ }
+ }
+}
+
+unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v)
+{
+ while(1) {
+ if(v == 0) {
+ return 0;
+ }
+ else if(v > 0) {
+ unsigned l = 0;
+ while(v) {
+ l++;
+ v >>= 1;
+ }
+ return l+1;
+ }
+ else if(v == -1) {
+ return 2;
+ }
+ else {
+ v++;
+ v = -v;
+ }
+ }
+}
diff --git a/src/FLAC/src/libFLAC/bitreader.c b/src/FLAC/src/libFLAC/bitreader.c
new file mode 100644
index 0000000..e3f85b8
--- /dev/null
+++ b/src/FLAC/src/libFLAC/bitreader.c
@@ -0,0 +1,1363 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy(), memset() */
+
+#include <sfendian.h>
+
+
+#include "private/bitmath.h"
+#include "private/bitreader.h"
+#include "private/crc.h"
+#include "FLAC/assert.h"
+
+/* Things should be fastest when this matches the machine word size */
+/* WATCHOUT: if you change this you must also change the following #defines down to COUNT_ZERO_MSBS below to match */
+/* WATCHOUT: there are a few places where the code will not work unless brword is >= 32 bits wide */
+/* also, some sections currently only have fast versions for 4 or 8 bytes per word */
+typedef FLAC__uint32 brword;
+#define FLAC__BYTES_PER_WORD 4
+#define FLAC__BITS_PER_WORD 32
+#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */
+#define SWAP_BE_WORD_TO_HOST(x) BEI2H_INT(x)
+
+/* counts the # of zero MSBs in a word */
+#define COUNT_ZERO_MSBS(word) ( \
+ (word) <= 0xffff ? \
+ ( (word) <= 0xff? byte_to_unary_table[word] + 24 : byte_to_unary_table[(word) >> 8] + 16 ) : \
+ ( (word) <= 0xffffff? byte_to_unary_table[word >> 16] + 8 : byte_to_unary_table[(word) >> 24] ) \
+)
+/* this alternate might be slightly faster on some systems/compilers: */
+#define COUNT_ZERO_MSBS2(word) ( (word) <= 0xff ? byte_to_unary_table[word] + 24 : ((word) <= 0xffff ? byte_to_unary_table[(word) >> 8] + 16 : ((word) <= 0xffffff ? byte_to_unary_table[(word) >> 16] + 8 : byte_to_unary_table[(word) >> 24])) )
+
+
+/*
+ * This should be at least twice as large as the largest number of words
+ * required to represent any 'number' (in any encoding) you are going to
+ * read. With FLAC this is on the order of maybe a few hundred bits.
+ * If the buffer is smaller than that, the decoder won't be able to read
+ * in a whole number that is in a variable length encoding (e.g. Rice).
+ * But to be practical it should be at least 1K bytes.
+ *
+ * Increase this number to decrease the number of read callbacks, at the
+ * expense of using more memory. Or decrease for the reverse effect,
+ * keeping in mind the limit from the first paragraph. The optimal size
+ * also depends on the CPU cache size and other factors; some twiddling
+ * may be necessary to squeeze out the best performance.
+ */
+static const unsigned FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */
+
+static const unsigned char byte_to_unary_table[] = {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+/* WATCHOUT: assembly routines rely on the order in which these fields are declared */
+struct FLAC__BitReader {
+ /* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */
+ /* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */
+ brword *buffer;
+ unsigned capacity; /* in words */
+ unsigned words; /* # of completed words in buffer */
+ unsigned bytes; /* # of bytes in incomplete word at buffer[words] */
+ unsigned consumed_words; /* #words ... */
+ unsigned consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */
+ unsigned read_crc16; /* the running frame CRC */
+ unsigned crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */
+ FLAC__BitReaderReadCallback read_callback;
+ void *client_data;
+ FLAC__CPUInfo cpu_info;
+};
+
+#ifdef _MSC_VER
+/* OPT: an MSVC built-in would be better */
+static _inline FLAC__uint32 local_swap32_(FLAC__uint32 x)
+{
+ x = ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF);
+ return (x>>16) | (x<<16);
+}
+static void local_swap32_block_(FLAC__uint32 *start, FLAC__uint32 len)
+{
+ __asm {
+ mov edx, start
+ mov ecx, len
+ test ecx, ecx
+loop1:
+ jz done1
+ mov eax, [edx]
+ bswap eax
+ mov [edx], eax
+ add edx, 4
+ dec ecx
+ jmp short loop1
+done1:
+ }
+}
+#endif
+
+static FLaC__INLINE void crc16_update_word_(FLAC__BitReader *br, brword word)
+{
+ register unsigned crc = br->read_crc16;
+#if FLAC__BYTES_PER_WORD == 4
+ switch(br->crc16_align) {
+ case 0: crc = FLAC__CRC16_UPDATE((unsigned)(word >> 24), crc);
+ case 8: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 16) & 0xff), crc);
+ case 16: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 8) & 0xff), crc);
+ case 24: br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)(word & 0xff), crc);
+ }
+#elif FLAC__BYTES_PER_WORD == 8
+ switch(br->crc16_align) {
+ case 0: crc = FLAC__CRC16_UPDATE((unsigned)(word >> 56), crc);
+ case 8: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 48) & 0xff), crc);
+ case 16: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 40) & 0xff), crc);
+ case 24: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 32) & 0xff), crc);
+ case 32: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 24) & 0xff), crc);
+ case 40: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 16) & 0xff), crc);
+ case 48: crc = FLAC__CRC16_UPDATE((unsigned)((word >> 8) & 0xff), crc);
+ case 56: br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)(word & 0xff), crc);
+ }
+#else
+ for( ; br->crc16_align < FLAC__BITS_PER_WORD; br->crc16_align += 8)
+ crc = FLAC__CRC16_UPDATE((unsigned)((word >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), crc);
+ br->read_crc16 = crc;
+#endif
+ br->crc16_align = 0;
+}
+
+/* would be static except it needs to be called by asm routines */
+FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br)
+{
+ unsigned start, end;
+ size_t bytes;
+ FLAC__byte *target;
+
+ /* first shift the unconsumed buffer data toward the front as much as possible */
+ if(br->consumed_words > 0) {
+ start = br->consumed_words;
+ end = br->words + (br->bytes? 1:0);
+ memmove(br->buffer, br->buffer+start, FLAC__BYTES_PER_WORD * (end - start));
+
+ br->words -= start;
+ br->consumed_words = 0;
+ }
+
+ /*
+ * set the target for reading, taking into account word alignment and endianness
+ */
+ bytes = (br->capacity - br->words) * FLAC__BYTES_PER_WORD - br->bytes;
+ if(bytes == 0)
+ return false; /* no space left, buffer is too small; see note for FLAC__BITREADER_DEFAULT_CAPACITY */
+ target = ((FLAC__byte*)(br->buffer+br->words)) + br->bytes;
+
+ /* before reading, if the existing reader looks like this (say brword is 32 bits wide)
+ * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1 (partial tail word is left-justified)
+ * buffer[BE]: 11 22 33 44 55 ?? ?? ?? (shown layed out as bytes sequentially in memory)
+ * buffer[LE]: 44 33 22 11 ?? ?? ?? 55 (?? being don't-care)
+ * ^^-------target, bytes=3
+ * on LE machines, have to byteswap the odd tail word so nothing is
+ * overwritten:
+ */
+#if WORDS_BIGENDIAN
+#else
+ if(br->bytes)
+ br->buffer[br->words] = SWAP_BE_WORD_TO_HOST(br->buffer[br->words]);
+#endif
+
+ /* now it looks like:
+ * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1
+ * buffer[BE]: 11 22 33 44 55 ?? ?? ??
+ * buffer[LE]: 44 33 22 11 55 ?? ?? ??
+ * ^^-------target, bytes=3
+ */
+
+ /* read in the data; note that the callback may return a smaller number of bytes */
+ if(!br->read_callback(target, &bytes, br->client_data))
+ return false;
+
+ /* after reading bytes 66 77 88 99 AA BB CC DD EE FF from the client:
+ * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
+ * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ??
+ * buffer[LE]: 44 33 22 11 55 66 77 88 99 AA BB CC DD EE FF ??
+ * now have to byteswap on LE machines:
+ */
+#if WORDS_BIGENDIAN
+#else
+ end = (br->words*FLAC__BYTES_PER_WORD + br->bytes + bytes + (FLAC__BYTES_PER_WORD-1)) / FLAC__BYTES_PER_WORD;
+# if defined(_MSC_VER) && (FLAC__BYTES_PER_WORD == 4)
+ if(br->cpu_info.type == FLAC__CPUINFO_TYPE_IA32 && br->cpu_info.data.ia32.bswap) {
+ start = br->words;
+ local_swap32_block_(br->buffer + start, end - start);
+ }
+ else
+# endif
+ for(start = br->words; start < end; start++)
+ br->buffer[start] = SWAP_BE_WORD_TO_HOST(br->buffer[start]);
+#endif
+
+ /* now it looks like:
+ * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF
+ * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ??
+ * buffer[LE]: 44 33 22 11 88 77 66 55 CC BB AA 99 ?? FF EE DD
+ * finally we'll update the reader values:
+ */
+ end = br->words*FLAC__BYTES_PER_WORD + br->bytes + bytes;
+ br->words = end / FLAC__BYTES_PER_WORD;
+ br->bytes = end % FLAC__BYTES_PER_WORD;
+
+ return true;
+}
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC__BitReader *FLAC__bitreader_new(void)
+{
+ FLAC__BitReader *br = (FLAC__BitReader*)calloc(1, sizeof(FLAC__BitReader));
+
+ /* calloc() implies:
+ memset(br, 0, sizeof(FLAC__BitReader));
+ br->buffer = 0;
+ br->capacity = 0;
+ br->words = br->bytes = 0;
+ br->consumed_words = br->consumed_bits = 0;
+ br->read_callback = 0;
+ br->client_data = 0;
+ */
+ return br;
+}
+
+void FLAC__bitreader_delete(FLAC__BitReader *br)
+{
+ FLAC__ASSERT(0 != br);
+
+ FLAC__bitreader_free(br);
+ free(br);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__CPUInfo cpu, FLAC__BitReaderReadCallback rcb, void *cd)
+{
+ FLAC__ASSERT(0 != br);
+
+ br->words = br->bytes = 0;
+ br->consumed_words = br->consumed_bits = 0;
+ br->capacity = FLAC__BITREADER_DEFAULT_CAPACITY;
+ br->buffer = (brword*)malloc(sizeof(brword) * br->capacity);
+ if(br->buffer == 0)
+ return false;
+ br->read_callback = rcb;
+ br->client_data = cd;
+ br->cpu_info = cpu;
+
+ return true;
+}
+
+void FLAC__bitreader_free(FLAC__BitReader *br)
+{
+ FLAC__ASSERT(0 != br);
+
+ if(0 != br->buffer)
+ free(br->buffer);
+ br->buffer = 0;
+ br->capacity = 0;
+ br->words = br->bytes = 0;
+ br->consumed_words = br->consumed_bits = 0;
+ br->read_callback = 0;
+ br->client_data = 0;
+}
+
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br)
+{
+ br->words = br->bytes = 0;
+ br->consumed_words = br->consumed_bits = 0;
+ return true;
+}
+
+void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out)
+{
+ unsigned i, j;
+ if(br == 0) {
+ fprintf(out, "bitreader is NULL\n");
+ }
+ else {
+ fprintf(out, "bitreader: capacity=%u words=%u bytes=%u consumed: words=%u, bits=%u\n", br->capacity, br->words, br->bytes, br->consumed_words, br->consumed_bits);
+
+ for(i = 0; i < br->words; i++) {
+ fprintf(out, "%08X: ", i);
+ for(j = 0; j < FLAC__BITS_PER_WORD; j++)
+ if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits))
+ fprintf(out, ".");
+ else
+ fprintf(out, "%01u", br->buffer[i] & (1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0);
+ fprintf(out, "\n");
+ }
+ if(br->bytes > 0) {
+ fprintf(out, "%08X: ", i);
+ for(j = 0; j < br->bytes*8; j++)
+ if(i < br->consumed_words || (i == br->consumed_words && j < br->consumed_bits))
+ fprintf(out, ".");
+ else
+ fprintf(out, "%01u", br->buffer[i] & (1 << (br->bytes*8-j-1)) ? 1:0);
+ fprintf(out, "\n");
+ }
+ }
+}
+
+void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed)
+{
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+ FLAC__ASSERT((br->consumed_bits & 7) == 0);
+
+ br->read_crc16 = (unsigned)seed;
+ br->crc16_align = br->consumed_bits;
+}
+
+FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br)
+{
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+ FLAC__ASSERT((br->consumed_bits & 7) == 0);
+ FLAC__ASSERT(br->crc16_align <= br->consumed_bits);
+
+ /* CRC any tail bytes in a partially-consumed word */
+ if(br->consumed_bits) {
+ const brword tail = br->buffer[br->consumed_words];
+ for( ; br->crc16_align < br->consumed_bits; br->crc16_align += 8)
+ br->read_crc16 = FLAC__CRC16_UPDATE((unsigned)((tail >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), br->read_crc16);
+ }
+ return br->read_crc16;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br)
+{
+ return ((br->consumed_bits & 7) == 0);
+}
+
+FLaC__INLINE unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br)
+{
+ return 8 - (br->consumed_bits & 7);
+}
+
+FLaC__INLINE unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br)
+{
+ return (br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, unsigned bits)
+{
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+
+ FLAC__ASSERT(bits <= 32);
+ FLAC__ASSERT((br->capacity*FLAC__BITS_PER_WORD) * 2 >= bits);
+ FLAC__ASSERT(br->consumed_words <= br->words);
+
+ /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+ FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+
+ if(bits == 0) { /* OPT: investigate if this can ever happen, maybe change to assertion */
+ *val = 0;
+ return true;
+ }
+
+ while((br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits < bits) {
+ if(!bitreader_read_from_client_(br))
+ return false;
+ }
+ if(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */
+ /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */
+ if(br->consumed_bits) {
+ /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ const unsigned n = FLAC__BITS_PER_WORD - br->consumed_bits;
+ const brword word = br->buffer[br->consumed_words];
+ if(bits < n) {
+ *val = (word & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (n-bits);
+ br->consumed_bits += bits;
+ return true;
+ }
+ *val = word & (FLAC__WORD_ALL_ONES >> br->consumed_bits);
+ bits -= n;
+ crc16_update_word_(br, word);
+ br->consumed_words++;
+ br->consumed_bits = 0;
+ if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+ *val <<= bits;
+ *val |= (br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits));
+ br->consumed_bits = bits;
+ }
+ return true;
+ }
+ else {
+ const brword word = br->buffer[br->consumed_words];
+ if(bits < FLAC__BITS_PER_WORD) {
+ *val = word >> (FLAC__BITS_PER_WORD-bits);
+ br->consumed_bits = bits;
+ return true;
+ }
+ /* at this point 'bits' must be == FLAC__BITS_PER_WORD; because of previous assertions, it can't be larger */
+ *val = word;
+ crc16_update_word_(br, word);
+ br->consumed_words++;
+ return true;
+ }
+ }
+ else {
+ /* in this case we're starting our read at a partial tail word;
+ * the reader has guaranteed that we have at least 'bits' bits
+ * available to read, which makes this case simpler.
+ */
+ /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */
+ if(br->consumed_bits) {
+ /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ FLAC__ASSERT(br->consumed_bits + bits <= br->bytes*8);
+ *val = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (FLAC__BITS_PER_WORD-br->consumed_bits-bits);
+ br->consumed_bits += bits;
+ return true;
+ }
+ else {
+ *val = br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits);
+ br->consumed_bits += bits;
+ return true;
+ }
+ }
+}
+
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, unsigned bits)
+{
+ /* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */
+ if(!FLAC__bitreader_read_raw_uint32(br, (FLAC__uint32*)val, bits))
+ return false;
+ /* sign-extend: */
+ *val <<= (32-bits);
+ *val >>= (32-bits);
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, unsigned bits)
+{
+ FLAC__uint32 hi, lo;
+
+ if(bits > 32) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &hi, bits-32))
+ return false;
+ if(!FLAC__bitreader_read_raw_uint32(br, &lo, 32))
+ return false;
+ *val = hi;
+ *val <<= 32;
+ *val |= lo;
+ }
+ else {
+ if(!FLAC__bitreader_read_raw_uint32(br, &lo, bits))
+ return false;
+ *val = lo;
+ }
+ return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val)
+{
+ FLAC__uint32 x8, x32 = 0;
+
+ /* this doesn't need to be that fast as currently it is only used for vorbis comments */
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x32, 8))
+ return false;
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+ return false;
+ x32 |= (x8 << 8);
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+ return false;
+ x32 |= (x8 << 16);
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8))
+ return false;
+ x32 |= (x8 << 24);
+
+ *val = x32;
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, unsigned bits)
+{
+ /*
+ * OPT: a faster implementation is possible but probably not that useful
+ * since this is only called a couple of times in the metadata readers.
+ */
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+
+ if(bits > 0) {
+ const unsigned n = br->consumed_bits & 7;
+ unsigned m;
+ FLAC__uint32 x;
+
+ if(n != 0) {
+ m = min(8-n, bits);
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, m))
+ return false;
+ bits -= m;
+ }
+ m = bits / 8;
+ if(m > 0) {
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(br, m))
+ return false;
+ bits %= 8;
+ }
+ if(bits > 0) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, bits))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, unsigned nvals)
+{
+ FLAC__uint32 x;
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br));
+
+ /* step 1: skip over partial head word to get word aligned */
+ while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ nvals--;
+ }
+ if(0 == nvals)
+ return true;
+ /* step 2: skip whole words in chunks */
+ while(nvals >= FLAC__BYTES_PER_WORD) {
+ if(br->consumed_words < br->words) {
+ br->consumed_words++;
+ nvals -= FLAC__BYTES_PER_WORD;
+ }
+ else if(!bitreader_read_from_client_(br))
+ return false;
+ }
+ /* step 3: skip any remainder from partial tail bytes */
+ while(nvals) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ nvals--;
+ }
+
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, unsigned nvals)
+{
+ FLAC__uint32 x;
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br));
+
+ /* step 1: read from partial head word to get word aligned */
+ while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ *val++ = (FLAC__byte)x;
+ nvals--;
+ }
+ if(0 == nvals)
+ return true;
+ /* step 2: read whole words in chunks */
+ while(nvals >= FLAC__BYTES_PER_WORD) {
+ if(br->consumed_words < br->words) {
+ const brword word = br->buffer[br->consumed_words++];
+#if FLAC__BYTES_PER_WORD == 4
+ val[0] = (FLAC__byte)(word >> 24);
+ val[1] = (FLAC__byte)(word >> 16);
+ val[2] = (FLAC__byte)(word >> 8);
+ val[3] = (FLAC__byte)word;
+#elif FLAC__BYTES_PER_WORD == 8
+ val[0] = (FLAC__byte)(word >> 56);
+ val[1] = (FLAC__byte)(word >> 48);
+ val[2] = (FLAC__byte)(word >> 40);
+ val[3] = (FLAC__byte)(word >> 32);
+ val[4] = (FLAC__byte)(word >> 24);
+ val[5] = (FLAC__byte)(word >> 16);
+ val[6] = (FLAC__byte)(word >> 8);
+ val[7] = (FLAC__byte)word;
+#else
+ for(x = 0; x < FLAC__BYTES_PER_WORD; x++)
+ val[x] = (FLAC__byte)(word >> (8*(FLAC__BYTES_PER_WORD-x-1)));
+#endif
+ val += FLAC__BYTES_PER_WORD;
+ nvals -= FLAC__BYTES_PER_WORD;
+ }
+ else if(!bitreader_read_from_client_(br))
+ return false;
+ }
+ /* step 3: read any remainder from partial tail bytes */
+ while(nvals) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ *val++ = (FLAC__byte)x;
+ nvals--;
+ }
+
+ return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val)
+#if 0 /* slow but readable version */
+{
+ unsigned bit;
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+
+ *val = 0;
+ while(1) {
+ if(!FLAC__bitreader_read_bit(br, &bit))
+ return false;
+ if(bit)
+ break;
+ else
+ *val++;
+ }
+ return true;
+}
+#else
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+
+ *val = 0;
+ while(1) {
+ while(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */
+ brword b = br->buffer[br->consumed_words] << br->consumed_bits;
+ if(b) {
+ i = COUNT_ZERO_MSBS(b);
+ *val += i;
+ i++;
+ br->consumed_bits += i;
+ if(br->consumed_bits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(br->consumed_bits == FLAC__BITS_PER_WORD) */
+ crc16_update_word_(br, br->buffer[br->consumed_words]);
+ br->consumed_words++;
+ br->consumed_bits = 0;
+ }
+ return true;
+ }
+ else {
+ *val += FLAC__BITS_PER_WORD - br->consumed_bits;
+ crc16_update_word_(br, br->buffer[br->consumed_words]);
+ br->consumed_words++;
+ br->consumed_bits = 0;
+ /* didn't find stop bit yet, have to keep going... */
+ }
+ }
+ /* at this point we've eaten up all the whole words; have to try
+ * reading through any tail bytes before calling the read callback.
+ * this is a repeat of the above logic adjusted for the fact we
+ * don't have a whole word. note though if the client is feeding
+ * us data a byte at a time (unlikely), br->consumed_bits may not
+ * be zero.
+ */
+ if(br->bytes) {
+ const unsigned end = br->bytes * 8;
+ brword b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits;
+ if(b) {
+ i = COUNT_ZERO_MSBS(b);
+ *val += i;
+ i++;
+ br->consumed_bits += i;
+ FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD);
+ return true;
+ }
+ else {
+ *val += end - br->consumed_bits;
+ br->consumed_bits += end;
+ FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD);
+ /* didn't find stop bit yet, have to keep going... */
+ }
+ }
+ if(!bitreader_read_from_client_(br))
+ return false;
+ }
+}
+#endif
+
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter)
+{
+ FLAC__uint32 lsbs = 0, msbs = 0;
+ unsigned uval;
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+ FLAC__ASSERT(parameter <= 31);
+
+ /* read the unary MSBs and end bit */
+ if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+ return false;
+
+ /* read the binary LSBs */
+ if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter))
+ return false;
+
+ /* compose the value */
+ uval = (msbs << parameter) | lsbs;
+ if(uval & 1)
+ *val = -((int)(uval >> 1)) - 1;
+ else
+ *val = (int)(uval >> 1);
+
+ return true;
+}
+
+/* this is by far the most heavily used reader call. it ain't pretty but it's fast */
+/* a lot of the logic is copied, then adapted, from FLAC__bitreader_read_unary_unsigned() and FLAC__bitreader_read_raw_uint32() */
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter)
+#ifdef _MSC_VER
+{
+ unsigned i;
+ unsigned uval = 0;
+ unsigned bits; /* the # of binary LSBs left to read to finish a rice codeword */
+
+ /* try and get br->consumed_words and br->consumed_bits into register;
+ * must remember to flush them back to *br before calling other
+ * bitwriter functions that use them, and before returning */
+ register unsigned cwords;
+ register unsigned cbits;
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+ /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+ FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+ FLAC__ASSERT(parameter < 32);
+ /* the above two asserts also guarantee that the binary part never straddles more that 2 words, so we don't have to loop to read it */
+
+ if(nvals == 0)
+ return true;
+
+ cbits = br->consumed_bits;
+ cwords = br->consumed_words;
+
+ while(1) {
+
+ /* read unary part */
+ while(1) {
+ while(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+ brword b = br->buffer[cwords] << cbits;
+ if(b) {
+#if 0 /* slower, probably due to bad register allocation... */ && defined FLAC__CPU_IA32 && !defined FLAC__NO_ASM && FLAC__BITS_PER_WORD == 32
+ __asm {
+ bsr eax, b
+ not eax
+ and eax, 31
+ mov i, eax
+ }
+#else
+ i = COUNT_ZERO_MSBS(b);
+#endif
+ uval += i;
+ bits = parameter;
+ i++;
+ cbits += i;
+ if(cbits == FLAC__BITS_PER_WORD) {
+ crc16_update_word_(br, br->buffer[cwords]);
+ cwords++;
+ cbits = 0;
+ }
+ goto break1;
+ }
+ else {
+ uval += FLAC__BITS_PER_WORD - cbits;
+ crc16_update_word_(br, br->buffer[cwords]);
+ cwords++;
+ cbits = 0;
+ /* didn't find stop bit yet, have to keep going... */
+ }
+ }
+ /* at this point we've eaten up all the whole words; have to try
+ * reading through any tail bytes before calling the read callback.
+ * this is a repeat of the above logic adjusted for the fact we
+ * don't have a whole word. note though if the client is feeding
+ * us data a byte at a time (unlikely), br->consumed_bits may not
+ * be zero.
+ */
+ if(br->bytes) {
+ const unsigned end = br->bytes * 8;
+ brword b = (br->buffer[cwords] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << cbits;
+ if(b) {
+ i = COUNT_ZERO_MSBS(b);
+ uval += i;
+ bits = parameter;
+ i++;
+ cbits += i;
+ FLAC__ASSERT(cbits < FLAC__BITS_PER_WORD);
+ goto break1;
+ }
+ else {
+ uval += end - cbits;
+ cbits += end;
+ FLAC__ASSERT(cbits < FLAC__BITS_PER_WORD);
+ /* didn't find stop bit yet, have to keep going... */
+ }
+ }
+ /* flush registers and read; bitreader_read_from_client_() does
+ * not touch br->consumed_bits at all but we still need to set
+ * it in case it fails and we have to return false.
+ */
+ br->consumed_bits = cbits;
+ br->consumed_words = cwords;
+ if(!bitreader_read_from_client_(br))
+ return false;
+ cwords = br->consumed_words;
+ }
+break1:
+ /* read binary part */
+ FLAC__ASSERT(cwords <= br->words);
+
+ if(bits) {
+ while((br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits < bits) {
+ /* flush registers and read; bitreader_read_from_client_() does
+ * not touch br->consumed_bits at all but we still need to set
+ * it in case it fails and we have to return false.
+ */
+ br->consumed_bits = cbits;
+ br->consumed_words = cwords;
+ if(!bitreader_read_from_client_(br))
+ return false;
+ cwords = br->consumed_words;
+ }
+ if(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+ if(cbits) {
+ /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ const unsigned n = FLAC__BITS_PER_WORD - cbits;
+ const brword word = br->buffer[cwords];
+ if(bits < n) {
+ uval <<= bits;
+ uval |= (word & (FLAC__WORD_ALL_ONES >> cbits)) >> (n-bits);
+ cbits += bits;
+ goto break2;
+ }
+ uval <<= n;
+ uval |= word & (FLAC__WORD_ALL_ONES >> cbits);
+ bits -= n;
+ crc16_update_word_(br, word);
+ cwords++;
+ cbits = 0;
+ if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+ uval <<= bits;
+ uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-bits));
+ cbits = bits;
+ }
+ goto break2;
+ }
+ else {
+ FLAC__ASSERT(bits < FLAC__BITS_PER_WORD);
+ uval <<= bits;
+ uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-bits);
+ cbits = bits;
+ goto break2;
+ }
+ }
+ else {
+ /* in this case we're starting our read at a partial tail word;
+ * the reader has guaranteed that we have at least 'bits' bits
+ * available to read, which makes this case simpler.
+ */
+ uval <<= bits;
+ if(cbits) {
+ /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ FLAC__ASSERT(cbits + bits <= br->bytes*8);
+ uval |= (br->buffer[cwords] & (FLAC__WORD_ALL_ONES >> cbits)) >> (FLAC__BITS_PER_WORD-cbits-bits);
+ cbits += bits;
+ goto break2;
+ }
+ else {
+ uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-bits);
+ cbits += bits;
+ goto break2;
+ }
+ }
+ }
+break2:
+ /* compose the value */
+ *vals = (int)(uval >> 1 ^ -(int)(uval & 1));
+
+ /* are we done? */
+ --nvals;
+ if(nvals == 0) {
+ br->consumed_bits = cbits;
+ br->consumed_words = cwords;
+ return true;
+ }
+
+ uval = 0;
+ ++vals;
+
+ }
+}
+#else
+{
+ unsigned i;
+ unsigned uval = 0;
+
+ /* try and get br->consumed_words and br->consumed_bits into register;
+ * must remember to flush them back to *br before calling other
+ * bitwriter functions that use them, and before returning */
+ register unsigned cwords;
+ register unsigned cbits;
+ unsigned ucbits; /* keep track of the number of unconsumed bits in the buffer */
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+ /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+ FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+ FLAC__ASSERT(parameter < 32);
+ /* the above two asserts also guarantee that the binary part never straddles more than 2 words, so we don't have to loop to read it */
+
+ if(nvals == 0)
+ return true;
+
+ cbits = br->consumed_bits;
+ cwords = br->consumed_words;
+ ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+
+ while(1) {
+
+ /* read unary part */
+ while(1) {
+ while(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+ brword b = br->buffer[cwords] << cbits;
+ if(b) {
+#if 0 /* is not discernably faster... */ && defined FLAC__CPU_IA32 && !defined FLAC__NO_ASM && FLAC__BITS_PER_WORD == 32 && defined __GNUC__
+ asm volatile (
+ "bsrl %1, %0;"
+ "notl %0;"
+ "andl $31, %0;"
+ : "=r"(i)
+ : "r"(b)
+ );
+#else
+ i = COUNT_ZERO_MSBS(b);
+#endif
+ uval += i;
+ cbits += i;
+ cbits++; /* skip over stop bit */
+ if(cbits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(cbits == FLAC__BITS_PER_WORD) */
+ crc16_update_word_(br, br->buffer[cwords]);
+ cwords++;
+ cbits = 0;
+ }
+ goto break1;
+ }
+ else {
+ uval += FLAC__BITS_PER_WORD - cbits;
+ crc16_update_word_(br, br->buffer[cwords]);
+ cwords++;
+ cbits = 0;
+ /* didn't find stop bit yet, have to keep going... */
+ }
+ }
+ /* at this point we've eaten up all the whole words; have to try
+ * reading through any tail bytes before calling the read callback.
+ * this is a repeat of the above logic adjusted for the fact we
+ * don't have a whole word. note though if the client is feeding
+ * us data a byte at a time (unlikely), br->consumed_bits may not
+ * be zero.
+ */
+ if(br->bytes) {
+ const unsigned end = br->bytes * 8;
+ brword b = (br->buffer[cwords] & ~(FLAC__WORD_ALL_ONES >> end)) << cbits;
+ if(b) {
+ i = COUNT_ZERO_MSBS(b);
+ uval += i;
+ cbits += i;
+ cbits++; /* skip over stop bit */
+ FLAC__ASSERT(cbits < FLAC__BITS_PER_WORD);
+ goto break1;
+ }
+ else {
+ uval += end - cbits;
+ cbits += end;
+ FLAC__ASSERT(cbits < FLAC__BITS_PER_WORD);
+ /* didn't find stop bit yet, have to keep going... */
+ }
+ }
+ /* flush registers and read; bitreader_read_from_client_() does
+ * not touch br->consumed_bits at all but we still need to set
+ * it in case it fails and we have to return false.
+ */
+ br->consumed_bits = cbits;
+ br->consumed_words = cwords;
+ if(!bitreader_read_from_client_(br))
+ return false;
+ cwords = br->consumed_words;
+ ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits + uval;
+ /* + uval to offset our count by the # of unary bits already
+ * consumed before the read, because we will add these back
+ * in all at once at break1
+ */
+ }
+break1:
+ ucbits -= uval;
+ ucbits--; /* account for stop bit */
+
+ /* read binary part */
+ FLAC__ASSERT(cwords <= br->words);
+
+ if(parameter) {
+ while(ucbits < parameter) {
+ /* flush registers and read; bitreader_read_from_client_() does
+ * not touch br->consumed_bits at all but we still need to set
+ * it in case it fails and we have to return false.
+ */
+ br->consumed_bits = cbits;
+ br->consumed_words = cwords;
+ if(!bitreader_read_from_client_(br))
+ return false;
+ cwords = br->consumed_words;
+ ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+ }
+ if(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+ if(cbits) {
+ /* this also works when consumed_bits==0, it's just slower than necessary for that case */
+ const unsigned n = FLAC__BITS_PER_WORD - cbits;
+ const brword word = br->buffer[cwords];
+ if(parameter < n) {
+ uval <<= parameter;
+ uval |= (word & (FLAC__WORD_ALL_ONES >> cbits)) >> (n-parameter);
+ cbits += parameter;
+ }
+ else {
+ uval <<= n;
+ uval |= word & (FLAC__WORD_ALL_ONES >> cbits);
+ crc16_update_word_(br, word);
+ cwords++;
+ cbits = parameter - n;
+ if(cbits) { /* parameter > n, i.e. if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+ uval <<= cbits;
+ uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits));
+ }
+ }
+ }
+ else {
+ cbits = parameter;
+ uval <<= parameter;
+ uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits);
+ }
+ }
+ else {
+ /* in this case we're starting our read at a partial tail word;
+ * the reader has guaranteed that we have at least 'parameter'
+ * bits available to read, which makes this case simpler.
+ */
+ uval <<= parameter;
+ if(cbits) {
+ /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ FLAC__ASSERT(cbits + parameter <= br->bytes*8);
+ uval |= (br->buffer[cwords] & (FLAC__WORD_ALL_ONES >> cbits)) >> (FLAC__BITS_PER_WORD-cbits-parameter);
+ cbits += parameter;
+ }
+ else {
+ cbits = parameter;
+ uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits);
+ }
+ }
+ }
+
+ ucbits -= parameter;
+
+ /* compose the value */
+ *vals = (int)(uval >> 1 ^ -(int)(uval & 1));
+
+ /* are we done? */
+ --nvals;
+ if(nvals == 0) {
+ br->consumed_bits = cbits;
+ br->consumed_words = cwords;
+ return true;
+ }
+
+ uval = 0;
+ ++vals;
+
+ }
+}
+#endif
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter)
+{
+ FLAC__uint32 lsbs = 0, msbs = 0;
+ unsigned bit, uval, k;
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+
+ k = FLAC__bitmath_ilog2(parameter);
+
+ /* read the unary MSBs and end bit */
+ if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+ return false;
+
+ /* read the binary LSBs */
+ if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k))
+ return false;
+
+ if(parameter == 1u<<k) {
+ /* compose the value */
+ uval = (msbs << k) | lsbs;
+ }
+ else {
+ unsigned d = (1 << (k+1)) - parameter;
+ if(lsbs >= d) {
+ if(!FLAC__bitreader_read_bit(br, &bit))
+ return false;
+ lsbs <<= 1;
+ lsbs |= bit;
+ lsbs -= d;
+ }
+ /* compose the value */
+ uval = msbs * parameter + lsbs;
+ }
+
+ /* unfold unsigned to signed */
+ if(uval & 1)
+ *val = -((int)(uval >> 1)) - 1;
+ else
+ *val = (int)(uval >> 1);
+
+ return true;
+}
+
+FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter)
+{
+ FLAC__uint32 lsbs, msbs = 0;
+ unsigned bit, k;
+
+ FLAC__ASSERT(0 != br);
+ FLAC__ASSERT(0 != br->buffer);
+
+ k = FLAC__bitmath_ilog2(parameter);
+
+ /* read the unary MSBs and end bit */
+ if(!FLAC__bitreader_read_unary_unsigned(br, &msbs))
+ return false;
+
+ /* read the binary LSBs */
+ if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k))
+ return false;
+
+ if(parameter == 1u<<k) {
+ /* compose the value */
+ *val = (msbs << k) | lsbs;
+ }
+ else {
+ unsigned d = (1 << (k+1)) - parameter;
+ if(lsbs >= d) {
+ if(!FLAC__bitreader_read_bit(br, &bit))
+ return false;
+ lsbs <<= 1;
+ lsbs |= bit;
+ lsbs -= d;
+ }
+ /* compose the value */
+ *val = msbs * parameter + lsbs;
+ }
+
+ return true;
+}
+#endif /* UNUSED */
+
+/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen)
+{
+ FLAC__uint32 v = 0;
+ FLAC__uint32 x;
+ unsigned i;
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (FLAC__byte)x;
+ if(!(x & 0x80)) { /* 0xxxxxxx */
+ v = x;
+ i = 0;
+ }
+ else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */
+ v = x & 0x1F;
+ i = 1;
+ }
+ else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */
+ v = x & 0x0F;
+ i = 2;
+ }
+ else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */
+ v = x & 0x07;
+ i = 3;
+ }
+ else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */
+ v = x & 0x03;
+ i = 4;
+ }
+ else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */
+ v = x & 0x01;
+ i = 5;
+ }
+ else {
+ *val = 0xffffffff;
+ return true;
+ }
+ for( ; i; i--) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (FLAC__byte)x;
+ if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */
+ *val = 0xffffffff;
+ return true;
+ }
+ v <<= 6;
+ v |= (x & 0x3F);
+ }
+ *val = v;
+ return true;
+}
+
+/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen)
+{
+ FLAC__uint64 v = 0;
+ FLAC__uint32 x;
+ unsigned i;
+
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (FLAC__byte)x;
+ if(!(x & 0x80)) { /* 0xxxxxxx */
+ v = x;
+ i = 0;
+ }
+ else if(x & 0xC0 && !(x & 0x20)) { /* 110xxxxx */
+ v = x & 0x1F;
+ i = 1;
+ }
+ else if(x & 0xE0 && !(x & 0x10)) { /* 1110xxxx */
+ v = x & 0x0F;
+ i = 2;
+ }
+ else if(x & 0xF0 && !(x & 0x08)) { /* 11110xxx */
+ v = x & 0x07;
+ i = 3;
+ }
+ else if(x & 0xF8 && !(x & 0x04)) { /* 111110xx */
+ v = x & 0x03;
+ i = 4;
+ }
+ else if(x & 0xFC && !(x & 0x02)) { /* 1111110x */
+ v = x & 0x01;
+ i = 5;
+ }
+ else if(x & 0xFE && !(x & 0x01)) { /* 11111110 */
+ v = 0;
+ i = 6;
+ }
+ else {
+ *val = FLAC__U64L(0xffffffffffffffff);
+ return true;
+ }
+ for( ; i; i--) {
+ if(!FLAC__bitreader_read_raw_uint32(br, &x, 8))
+ return false;
+ if(raw)
+ raw[(*rawlen)++] = (FLAC__byte)x;
+ if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */
+ *val = FLAC__U64L(0xffffffffffffffff);
+ return true;
+ }
+ v <<= 6;
+ v |= (x & 0x3F);
+ }
+ *val = v;
+ return true;
+}
diff --git a/src/FLAC/src/libFLAC/bitwriter.c b/src/FLAC/src/libFLAC/bitwriter.c
new file mode 100644
index 0000000..82190a5
--- /dev/null
+++ b/src/FLAC/src/libFLAC/bitwriter.c
@@ -0,0 +1,872 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy(), memset() */
+
+#include <sfendian.h>
+
+#if 0 /* UNUSED */
+#include "private/bitmath.h"
+#endif
+#include "private/bitwriter.h"
+#include "private/crc.h"
+#include "FLAC/assert.h"
+
+/* Things should be fastest when this matches the machine word size */
+/* WATCHOUT: if you change this you must also change the following #defines down to SWAP_BE_WORD_TO_HOST below to match */
+/* WATCHOUT: there are a few places where the code will not work unless bwword is >= 32 bits wide */
+typedef FLAC__uint32 bwword;
+#define FLAC__BYTES_PER_WORD 4
+#define FLAC__BITS_PER_WORD 32
+#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff)
+/* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (which is always big-endian) if necessary to match host byte order */
+#define SWAP_BE_WORD_TO_HOST(x) BEI2H_INT(x)
+
+/*
+ * The default capacity here doesn't matter too much. The buffer always grows
+ * to hold whatever is written to it. Usually the encoder will stop adding at
+ * a frame or metadata block, then write that out and clear the buffer for the
+ * next one.
+ */
+static const unsigned FLAC__BITWRITER_DEFAULT_CAPACITY = 32768u / sizeof(bwword); /* size in words */
+/* When growing, increment 4K at a time */
+static const unsigned FLAC__BITWRITER_DEFAULT_INCREMENT = 4096u / sizeof(bwword); /* size in words */
+
+#define FLAC__WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD)
+#define FLAC__TOTAL_BITS(bw) (FLAC__WORDS_TO_BITS((bw)->words) + (bw)->bits)
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+struct FLAC__BitWriter {
+ bwword *buffer;
+ bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */
+ unsigned capacity; /* capacity of buffer in words */
+ unsigned words; /* # of complete words in buffer */
+ unsigned bits; /* # of used bits in accum */
+};
+
+#ifdef _MSC_VER
+/* OPT: an MSVC built-in would be better */
+static _inline FLAC__uint32 local_swap32_(FLAC__uint32 x)
+{
+ x = ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF);
+ return (x>>16) | (x<<16);
+}
+#endif
+
+/* * WATCHOUT: The current implementation only grows the buffer. */
+static FLAC__bool bitwriter_grow_(FLAC__BitWriter *bw, unsigned bits_to_add)
+{
+ unsigned new_capacity;
+ bwword *new_buffer;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+
+ /* calculate total words needed to store 'bits_to_add' additional bits */
+ new_capacity = bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD);
+
+ /* it's possible (due to pessimism in the growth estimation that
+ * leads to this call) that we don't actually need to grow
+ */
+ if(bw->capacity >= new_capacity)
+ return true;
+
+ /* round up capacity increase to the nearest FLAC__BITWRITER_DEFAULT_INCREMENT */
+ if((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT)
+ new_capacity += FLAC__BITWRITER_DEFAULT_INCREMENT - ((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT);
+ /* make sure we got everything right */
+ FLAC__ASSERT(0 == (new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT);
+ FLAC__ASSERT(new_capacity > bw->capacity);
+ FLAC__ASSERT(new_capacity >= bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD));
+
+ new_buffer = (bwword*)realloc(bw->buffer, sizeof(bwword)*new_capacity);
+ if(new_buffer == 0)
+ return false;
+ bw->buffer = new_buffer;
+ bw->capacity = new_capacity;
+ return true;
+}
+
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+
+FLAC__BitWriter *FLAC__bitwriter_new(void)
+{
+ FLAC__BitWriter *bw = (FLAC__BitWriter*)calloc(1, sizeof(FLAC__BitWriter));
+ /* note that calloc() sets all members to 0 for us */
+ return bw;
+}
+
+void FLAC__bitwriter_delete(FLAC__BitWriter *bw)
+{
+ FLAC__ASSERT(0 != bw);
+
+ FLAC__bitwriter_free(bw);
+ free(bw);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw)
+{
+ FLAC__ASSERT(0 != bw);
+
+ bw->words = bw->bits = 0;
+ bw->capacity = FLAC__BITWRITER_DEFAULT_CAPACITY;
+ bw->buffer = (bwword*)malloc(sizeof(bwword) * bw->capacity);
+ if(bw->buffer == 0)
+ return false;
+
+ return true;
+}
+
+void FLAC__bitwriter_free(FLAC__BitWriter *bw)
+{
+ FLAC__ASSERT(0 != bw);
+
+ if(0 != bw->buffer)
+ free(bw->buffer);
+ bw->buffer = 0;
+ bw->capacity = 0;
+ bw->words = bw->bits = 0;
+}
+
+void FLAC__bitwriter_clear(FLAC__BitWriter *bw)
+{
+ bw->words = bw->bits = 0;
+}
+
+void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out)
+{
+ unsigned i, j;
+ if(bw == 0) {
+ fprintf(out, "bitwriter is NULL\n");
+ }
+ else {
+ fprintf(out, "bitwriter: capacity=%u words=%u bits=%u total_bits=%u\n", bw->capacity, bw->words, bw->bits, FLAC__TOTAL_BITS(bw));
+
+ for(i = 0; i < bw->words; i++) {
+ fprintf(out, "%08X: ", i);
+ for(j = 0; j < FLAC__BITS_PER_WORD; j++)
+ fprintf(out, "%01u", bw->buffer[i] & (1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0);
+ fprintf(out, "\n");
+ }
+ if(bw->bits > 0) {
+ fprintf(out, "%08X: ", i);
+ for(j = 0; j < bw->bits; j++)
+ fprintf(out, "%01u", bw->accum & (1 << (bw->bits-j-1)) ? 1:0);
+ fprintf(out, "\n");
+ }
+ }
+}
+
+FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc)
+{
+ const FLAC__byte *buffer;
+ size_t bytes;
+
+ FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */
+
+ if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes))
+ return false;
+
+ *crc = (FLAC__uint16)FLAC__crc16(buffer, bytes);
+ FLAC__bitwriter_release_buffer(bw);
+ return true;
+}
+
+FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc)
+{
+ const FLAC__byte *buffer;
+ size_t bytes;
+
+ FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */
+
+ if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes))
+ return false;
+
+ *crc = FLAC__crc8(buffer, bytes);
+ FLAC__bitwriter_release_buffer(bw);
+ return true;
+}
+
+FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw)
+{
+ return ((bw->bits & 7) == 0);
+}
+
+unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw)
+{
+ return FLAC__TOTAL_BITS(bw);
+}
+
+FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes)
+{
+ FLAC__ASSERT((bw->bits & 7) == 0);
+ /* double protection */
+ if(bw->bits & 7)
+ return false;
+ /* if we have bits in the accumulator we have to flush those to the buffer first */
+ if(bw->bits) {
+ FLAC__ASSERT(bw->words <= bw->capacity);
+ if(bw->words == bw->capacity && !bitwriter_grow_(bw, FLAC__BITS_PER_WORD))
+ return false;
+ /* append bits as complete word to buffer, but don't change bw->accum or bw->bits */
+ bw->buffer[bw->words] = SWAP_BE_WORD_TO_HOST(bw->accum << (FLAC__BITS_PER_WORD-bw->bits));
+ }
+ /* now we can just return what we have */
+ *buffer = (FLAC__byte*)bw->buffer;
+ *bytes = (FLAC__BYTES_PER_WORD * bw->words) + (bw->bits >> 3);
+ return true;
+}
+
+void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw)
+{
+ /* nothing to do. in the future, strict checking of a 'writer-is-in-
+ * get-mode' flag could be added everywhere and then cleared here
+ */
+ (void)bw;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits)
+{
+ unsigned n;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+
+ if(bits == 0)
+ return true;
+ /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
+ if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits))
+ return false;
+ /* first part gets to word alignment */
+ if(bw->bits) {
+ n = min(FLAC__BITS_PER_WORD - bw->bits, bits);
+ bw->accum <<= n;
+ bits -= n;
+ bw->bits += n;
+ if(bw->bits == FLAC__BITS_PER_WORD) {
+ bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+ bw->bits = 0;
+ }
+ else
+ return true;
+ }
+ /* do whole words */
+ while(bits >= FLAC__BITS_PER_WORD) {
+ bw->buffer[bw->words++] = 0;
+ bits -= FLAC__BITS_PER_WORD;
+ }
+ /* do any leftovers */
+ if(bits > 0) {
+ bw->accum = 0;
+ bw->bits = bits;
+ }
+ return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits)
+{
+ register unsigned left;
+
+ /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+ FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+
+ FLAC__ASSERT(bits <= 32);
+ if(bits == 0)
+ return true;
+
+ /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
+ if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits))
+ return false;
+
+ left = FLAC__BITS_PER_WORD - bw->bits;
+ if(bits < left) {
+ bw->accum <<= bits;
+ bw->accum |= val;
+ bw->bits += bits;
+ }
+ else if(bw->bits) { /* WATCHOUT: if bw->bits == 0, left==FLAC__BITS_PER_WORD and bw->accum<<=left is a NOP instead of setting to 0 */
+ bw->accum <<= left;
+ bw->accum |= val >> (bw->bits = bits - left);
+ bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+ bw->accum = val;
+ }
+ else {
+ bw->accum = val;
+ bw->bits = 0;
+ bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(val);
+ }
+
+ return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits)
+{
+ /* zero-out unused bits */
+ if(bits < 32)
+ val &= (~(0xffffffff << bits));
+
+ return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits);
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits)
+{
+ /* this could be a little faster but it's not used for much */
+ if(bits > 32) {
+ return
+ FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(val>>32), bits-32) &&
+ FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 32);
+ }
+ else
+ return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits);
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val)
+{
+ /* this doesn't need to be that fast as currently it is only used for vorbis comments */
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, val & 0xff, 8))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>8) & 0xff, 8))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>16) & 0xff, 8))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, val>>24, 8))
+ return false;
+
+ return true;
+}
+
+FLaC__INLINE FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals)
+{
+ unsigned i;
+
+ /* this could be faster but currently we don't need it to be since it's only used for writing metadata */
+ for(i = 0; i < nvals; i++) {
+ if(!FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(vals[i]), 8))
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val)
+{
+ if(val < 32)
+ return FLAC__bitwriter_write_raw_uint32(bw, 1, ++val);
+ else
+ return
+ FLAC__bitwriter_write_zeroes(bw, val) &&
+ FLAC__bitwriter_write_raw_uint32(bw, 1, 1);
+}
+
+unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter)
+{
+ FLAC__uint32 uval;
+
+ FLAC__ASSERT(parameter < sizeof(unsigned)*8);
+
+ /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
+ uval = (val<<1) ^ (val>>31);
+
+ return 1 + parameter + (uval >> parameter);
+}
+
+#if 0 /* UNUSED */
+unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter)
+{
+ unsigned bits, msbs, uval;
+ unsigned k;
+
+ FLAC__ASSERT(parameter > 0);
+
+ /* fold signed to unsigned */
+ if(val < 0)
+ uval = (unsigned)(((-(++val)) << 1) + 1);
+ else
+ uval = (unsigned)(val << 1);
+
+ k = FLAC__bitmath_ilog2(parameter);
+ if(parameter == 1u<<k) {
+ FLAC__ASSERT(k <= 30);
+
+ msbs = uval >> k;
+ bits = 1 + k + msbs;
+ }
+ else {
+ unsigned q, r, d;
+
+ d = (1 << (k+1)) - parameter;
+ q = uval / parameter;
+ r = uval - (q * parameter);
+
+ bits = 1 + q + k;
+ if(r >= d)
+ bits++;
+ }
+ return bits;
+}
+
+unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned uval, unsigned parameter)
+{
+ unsigned bits, msbs;
+ unsigned k;
+
+ FLAC__ASSERT(parameter > 0);
+
+ k = FLAC__bitmath_ilog2(parameter);
+ if(parameter == 1u<<k) {
+ FLAC__ASSERT(k <= 30);
+
+ msbs = uval >> k;
+ bits = 1 + k + msbs;
+ }
+ else {
+ unsigned q, r, d;
+
+ d = (1 << (k+1)) - parameter;
+ q = uval / parameter;
+ r = uval - (q * parameter);
+
+ bits = 1 + q + k;
+ if(r >= d)
+ bits++;
+ }
+ return bits;
+}
+#endif /* UNUSED */
+
+FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter)
+{
+ unsigned total_bits, interesting_bits, msbs;
+ FLAC__uint32 uval, pattern;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+ FLAC__ASSERT(parameter < 8*sizeof(uval));
+
+ /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
+ uval = (val<<1) ^ (val>>31);
+
+ msbs = uval >> parameter;
+ interesting_bits = 1 + parameter;
+ total_bits = interesting_bits + msbs;
+ pattern = 1 << parameter; /* the unary end bit */
+ pattern |= (uval & ((1<<parameter)-1)); /* the binary LSBs */
+
+ if(total_bits <= 32)
+ return FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits);
+ else
+ return
+ FLAC__bitwriter_write_zeroes(bw, msbs) && /* write the unary MSBs */
+ FLAC__bitwriter_write_raw_uint32(bw, pattern, interesting_bits); /* write the unary end bit and binary LSBs */
+}
+
+FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter)
+{
+ const FLAC__uint32 mask1 = FLAC__WORD_ALL_ONES << parameter; /* we val|=mask1 to set the stop bit above it... */
+ const FLAC__uint32 mask2 = FLAC__WORD_ALL_ONES >> (31-parameter); /* ...then mask off the bits above the stop bit with val&=mask2*/
+ FLAC__uint32 uval;
+ unsigned left;
+ const unsigned lsbits = 1 + parameter;
+ unsigned msbits;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+ FLAC__ASSERT(parameter < 8*sizeof(bwword)-1);
+ /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */
+ FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32);
+
+ while(nvals) {
+ /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */
+ uval = (*vals<<1) ^ (*vals>>31);
+
+ msbits = uval >> parameter;
+
+#if 1 /* OPT: can remove this special case if it doesn't make up for the extra compare */
+ if(bw->bits + msbits + lsbits <= FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */
+ bw->bits = bw->bits + msbits + lsbits;
+ uval |= mask1; /* set stop bit */
+ uval &= mask2; /* mask off unused top bits */
+ /* NOT: bw->accum <<= msbits + lsbits because msbits+lsbits could be 32, then the shift would be a NOP */
+ bw->accum <<= msbits;
+ bw->accum <<= lsbits;
+ bw->accum |= uval;
+ if(bw->bits == FLAC__BITS_PER_WORD) {
+ bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+ bw->bits = 0;
+ /* burying the capacity check down here means we have to grow the buffer a little if there are more vals to do */
+ if(bw->capacity <= bw->words && nvals > 1 && !bitwriter_grow_(bw, 1)) {
+ FLAC__ASSERT(bw->capacity == bw->words);
+ return false;
+ }
+ }
+ }
+ else {
+#elif 0 /*@@@@@@ OPT: try this version with MSVC6 to see if better, not much difference for gcc-4 */
+ if(bw->bits + msbits + lsbits < FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */
+ bw->bits = bw->bits + msbits + lsbits;
+ uval |= mask1; /* set stop bit */
+ uval &= mask2; /* mask off unused top bits */
+ bw->accum <<= msbits + lsbits;
+ bw->accum |= uval;
+ }
+ else {
+#endif
+ /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+msbits+lsbits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */
+ /* OPT: pessimism may cause flurry of false calls to grow_ which eat up all savings before it */
+ if(bw->capacity <= bw->words + bw->bits + msbits + 1/*lsbits always fit in 1 bwword*/ && !bitwriter_grow_(bw, msbits+lsbits))
+ return false;
+
+ if(msbits) {
+ /* first part gets to word alignment */
+ if(bw->bits) {
+ left = FLAC__BITS_PER_WORD - bw->bits;
+ if(msbits < left) {
+ bw->accum <<= msbits;
+ bw->bits += msbits;
+ goto break1;
+ }
+ else {
+ bw->accum <<= left;
+ msbits -= left;
+ bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+ bw->bits = 0;
+ }
+ }
+ /* do whole words */
+ while(msbits >= FLAC__BITS_PER_WORD) {
+ bw->buffer[bw->words++] = 0;
+ msbits -= FLAC__BITS_PER_WORD;
+ }
+ /* do any leftovers */
+ if(msbits > 0) {
+ bw->accum = 0;
+ bw->bits = msbits;
+ }
+ }
+break1:
+ uval |= mask1; /* set stop bit */
+ uval &= mask2; /* mask off unused top bits */
+
+ left = FLAC__BITS_PER_WORD - bw->bits;
+ if(lsbits < left) {
+ bw->accum <<= lsbits;
+ bw->accum |= uval;
+ bw->bits += lsbits;
+ }
+ else {
+ /* if bw->bits == 0, left==FLAC__BITS_PER_WORD which will always
+ * be > lsbits (because of previous assertions) so it would have
+ * triggered the (lsbits<left) case above.
+ */
+ FLAC__ASSERT(bw->bits);
+ FLAC__ASSERT(left < FLAC__BITS_PER_WORD);
+ bw->accum <<= left;
+ bw->accum |= uval >> (bw->bits = lsbits - left);
+ bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum);
+ bw->accum = uval;
+ }
+#if 1
+ }
+#endif
+ vals++;
+ nvals--;
+ }
+ return true;
+}
+
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter)
+{
+ unsigned total_bits, msbs, uval;
+ unsigned k;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+ FLAC__ASSERT(parameter > 0);
+
+ /* fold signed to unsigned */
+ if(val < 0)
+ uval = (unsigned)(((-(++val)) << 1) + 1);
+ else
+ uval = (unsigned)(val << 1);
+
+ k = FLAC__bitmath_ilog2(parameter);
+ if(parameter == 1u<<k) {
+ unsigned pattern;
+
+ FLAC__ASSERT(k <= 30);
+
+ msbs = uval >> k;
+ total_bits = 1 + k + msbs;
+ pattern = 1 << k; /* the unary end bit */
+ pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */
+
+ if(total_bits <= 32) {
+ if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits))
+ return false;
+ }
+ else {
+ /* write the unary MSBs */
+ if(!FLAC__bitwriter_write_zeroes(bw, msbs))
+ return false;
+ /* write the unary end bit and binary LSBs */
+ if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, k+1))
+ return false;
+ }
+ }
+ else {
+ unsigned q, r, d;
+
+ d = (1 << (k+1)) - parameter;
+ q = uval / parameter;
+ r = uval - (q * parameter);
+ /* write the unary MSBs */
+ if(!FLAC__bitwriter_write_zeroes(bw, q))
+ return false;
+ /* write the unary end bit */
+ if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1))
+ return false;
+ /* write the binary LSBs */
+ if(r >= d) {
+ if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1))
+ return false;
+ }
+ else {
+ if(!FLAC__bitwriter_write_raw_uint32(bw, r, k))
+ return false;
+ }
+ }
+ return true;
+}
+
+FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned uval, unsigned parameter)
+{
+ unsigned total_bits, msbs;
+ unsigned k;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+ FLAC__ASSERT(parameter > 0);
+
+ k = FLAC__bitmath_ilog2(parameter);
+ if(parameter == 1u<<k) {
+ unsigned pattern;
+
+ FLAC__ASSERT(k <= 30);
+
+ msbs = uval >> k;
+ total_bits = 1 + k + msbs;
+ pattern = 1 << k; /* the unary end bit */
+ pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */
+
+ if(total_bits <= 32) {
+ if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits))
+ return false;
+ }
+ else {
+ /* write the unary MSBs */
+ if(!FLAC__bitwriter_write_zeroes(bw, msbs))
+ return false;
+ /* write the unary end bit and binary LSBs */
+ if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, k+1))
+ return false;
+ }
+ }
+ else {
+ unsigned q, r, d;
+
+ d = (1 << (k+1)) - parameter;
+ q = uval / parameter;
+ r = uval - (q * parameter);
+ /* write the unary MSBs */
+ if(!FLAC__bitwriter_write_zeroes(bw, q))
+ return false;
+ /* write the unary end bit */
+ if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1))
+ return false;
+ /* write the binary LSBs */
+ if(r >= d) {
+ if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1))
+ return false;
+ }
+ else {
+ if(!FLAC__bitwriter_write_raw_uint32(bw, r, k))
+ return false;
+ }
+ }
+ return true;
+}
+#endif /* UNUSED */
+
+FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val)
+{
+ FLAC__bool ok = 1;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+
+ FLAC__ASSERT(!(val & 0x80000000)); /* this version only handles 31 bits */
+
+ if(val < 0x80) {
+ return FLAC__bitwriter_write_raw_uint32(bw, val, 8);
+ }
+ else if(val < 0x800) {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (val>>6), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+ }
+ else if(val < 0x10000) {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (val>>12), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+ }
+ else if(val < 0x200000) {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (val>>18), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+ }
+ else if(val < 0x4000000) {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (val>>24), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+ }
+ else {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (val>>30), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>24)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8);
+ }
+
+ return ok;
+}
+
+FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val)
+{
+ FLAC__bool ok = 1;
+
+ FLAC__ASSERT(0 != bw);
+ FLAC__ASSERT(0 != bw->buffer);
+
+ FLAC__ASSERT(!(val & FLAC__U64L(0xFFFFFFF000000000))); /* this version only handles 36 bits */
+
+ if(val < 0x80) {
+ return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 8);
+ }
+ else if(val < 0x800) {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (FLAC__uint32)(val>>6), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x10000) {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (FLAC__uint32)(val>>12), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x200000) {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (FLAC__uint32)(val>>18), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x4000000) {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (FLAC__uint32)(val>>24), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+ else if(val < 0x80000000) {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (FLAC__uint32)(val>>30), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+ else {
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFE, 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8);
+ ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8);
+ }
+
+ return ok;
+}
+
+FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw)
+{
+ /* 0-pad to byte boundary */
+ if(bw->bits & 7u)
+ return FLAC__bitwriter_write_zeroes(bw, 8 - (bw->bits & 7u));
+ else
+ return true;
+}
diff --git a/src/FLAC/src/libFLAC/cpu.c b/src/FLAC/src/libFLAC/cpu.c
new file mode 100644
index 0000000..8d78762
--- /dev/null
+++ b/src/FLAC/src/libFLAC/cpu.c
@@ -0,0 +1,418 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/cpu.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+#if defined FLAC__CPU_IA32
+# include <signal.h>
+#elif defined FLAC__CPU_PPC
+# if !defined FLAC__NO_ASM
+# if defined FLAC__SYS_DARWIN
+# include <sys/sysctl.h>
+# include <mach/mach.h>
+# include <mach/mach_host.h>
+# include <mach/host_info.h>
+# include <mach/machine.h>
+# ifndef CPU_SUBTYPE_POWERPC_970
+# define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100)
+# endif
+# else /* FLAC__SYS_DARWIN */
+
+# include <signal.h>
+# include <setjmp.h>
+
+static sigjmp_buf jmpbuf;
+static volatile sig_atomic_t canjump = 0;
+
+static void sigill_handler (int sig)
+{
+ if (!canjump) {
+ signal (sig, SIG_DFL);
+ raise (sig);
+ }
+ canjump = 0;
+ siglongjmp (jmpbuf, 1);
+}
+# endif /* FLAC__SYS_DARWIN */
+# endif /* FLAC__NO_ASM */
+#endif /* FLAC__CPU_PPC */
+
+#if defined (__NetBSD__) || defined(__OpenBSD__)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <machine/cpu.h>
+#endif
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
+#if defined(__APPLE__)
+/* how to get sysctlbyname()? */
+#endif
+
+/* these are flags in EDX of CPUID AX=00000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000;
+/* these are flags in ECX of CPUID AX=00000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200;
+/* these are flags in EDX of CPUID AX=80000001 */
+static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000;
+static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000;
+
+
+/*
+ * Extra stuff needed for detection of OS support for SSE on IA-32
+ */
+#if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM && !defined FLAC__NO_SSE_OS && !defined FLAC__SSE_OS
+# if defined(__linux__)
+/*
+ * If the OS doesn't support SSE, we will get here with a SIGILL. We
+ * modify the return address to jump over the offending SSE instruction
+ * and also the operation following it that indicates the instruction
+ * executed successfully. In this way we use no global variables and
+ * stay thread-safe.
+ *
+ * 3 + 3 + 6:
+ * 3 bytes for "xorps xmm0,xmm0"
+ * 3 bytes for estimate of how long the follwing "inc var" instruction is
+ * 6 bytes extra in case our estimate is wrong
+ * 12 bytes puts us in the NOP "landing zone"
+ */
+# undef USE_OBSOLETE_SIGCONTEXT_FLAVOR /* #define this to use the older signal handler method */
+# ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR
+ static void sigill_handler_sse_os(int signal, struct sigcontext sc)
+ {
+ (void)signal;
+ sc.eip += 3 + 3 + 6;
+ }
+# else
+# include <sys/ucontext.h>
+ static void sigill_handler_sse_os(int sig, siginfo_t *si, void *uc)
+ {
+ (void)sig, (void)si;
+ ((ucontext_t*)uc)->uc_mcontext.gregs[14/*REG_EIP*/] += 3 + 3 + 6;
+ }
+# endif
+# elif defined(_MSC_VER)
+# include <windows.h>
+# undef USE_TRY_CATCH_FLAVOR /* #define this to use the try/catch method for catching illegal opcode exception */
+# ifdef USE_TRY_CATCH_FLAVOR
+# else
+ LONG CALLBACK sigill_handler_sse_os(EXCEPTION_POINTERS *ep)
+ {
+ if(ep->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) {
+ ep->ContextRecord->Eip += 3 + 3 + 6;
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+# endif
+# endif
+#endif
+
+
+void FLAC__cpu_info(FLAC__CPUInfo *info)
+{
+/*
+ * IA32-specific
+ */
+#ifdef FLAC__CPU_IA32
+ info->type = FLAC__CPUINFO_TYPE_IA32;
+#if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
+ info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */
+ info->data.ia32.cpuid = FLAC__cpu_have_cpuid_asm_ia32()? true : false;
+ info->data.ia32.bswap = info->data.ia32.cpuid; /* CPUID => BSWAP since it came after */
+ info->data.ia32.cmov = false;
+ info->data.ia32.mmx = false;
+ info->data.ia32.fxsr = false;
+ info->data.ia32.sse = false;
+ info->data.ia32.sse2 = false;
+ info->data.ia32.sse3 = false;
+ info->data.ia32.ssse3 = false;
+ info->data.ia32._3dnow = false;
+ info->data.ia32.ext3dnow = false;
+ info->data.ia32.extmmx = false;
+ if(info->data.ia32.cpuid) {
+ /* http://www.sandpile.org/ia32/cpuid.htm */
+ FLAC__uint32 flags_edx, flags_ecx;
+ FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx);
+ info->data.ia32.cmov = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false;
+ info->data.ia32.mmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX )? true : false;
+ info->data.ia32.fxsr = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false;
+ info->data.ia32.sse = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE )? true : false;
+ info->data.ia32.sse2 = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false;
+ info->data.ia32.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false;
+ info->data.ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false;
+
+#ifdef FLAC__USE_3DNOW
+ flags_edx = FLAC__cpu_info_extended_amd_asm_ia32();
+ info->data.ia32._3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW )? true : false;
+ info->data.ia32.ext3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false;
+ info->data.ia32.extmmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX )? true : false;
+#else
+ info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false;
+#endif
+
+#ifdef DEBUG
+ fprintf(stderr, "CPU info (IA-32):\n");
+ fprintf(stderr, " CPUID ...... %c\n", info->data.ia32.cpuid ? 'Y' : 'n');
+ fprintf(stderr, " BSWAP ...... %c\n", info->data.ia32.bswap ? 'Y' : 'n');
+ fprintf(stderr, " CMOV ....... %c\n", info->data.ia32.cmov ? 'Y' : 'n');
+ fprintf(stderr, " MMX ........ %c\n", info->data.ia32.mmx ? 'Y' : 'n');
+ fprintf(stderr, " FXSR ....... %c\n", info->data.ia32.fxsr ? 'Y' : 'n');
+ fprintf(stderr, " SSE ........ %c\n", info->data.ia32.sse ? 'Y' : 'n');
+ fprintf(stderr, " SSE2 ....... %c\n", info->data.ia32.sse2 ? 'Y' : 'n');
+ fprintf(stderr, " SSE3 ....... %c\n", info->data.ia32.sse3 ? 'Y' : 'n');
+ fprintf(stderr, " SSSE3 ...... %c\n", info->data.ia32.ssse3 ? 'Y' : 'n');
+ fprintf(stderr, " 3DNow! ..... %c\n", info->data.ia32._3dnow ? 'Y' : 'n');
+ fprintf(stderr, " 3DNow!-ext . %c\n", info->data.ia32.ext3dnow? 'Y' : 'n');
+ fprintf(stderr, " 3DNow!-MMX . %c\n", info->data.ia32.extmmx ? 'Y' : 'n');
+#endif
+
+ /*
+ * now have to check for OS support of SSE/SSE2
+ */
+ if(info->data.ia32.fxsr || info->data.ia32.sse || info->data.ia32.sse2) {
+#if defined FLAC__NO_SSE_OS
+ /* assume user knows better than us; turn it off */
+ info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+#elif defined FLAC__SSE_OS
+ /* assume user knows better than us; leave as detected above */
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__)
+ int sse = 0;
+ size_t len;
+ /* at least one of these must work: */
+ len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse);
+ len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse" , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */
+ if(!sse)
+ info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+#elif defined(__NetBSD__) || defined (__OpenBSD__)
+# if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__)
+ int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE };
+ size_t len = sizeof(val);
+ if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
+ info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+ else { /* double-check SSE2 */
+ mib[1] = CPU_SSE2;
+ len = sizeof(val);
+ if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val)
+ info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+ }
+# else
+ info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+# endif
+#elif defined(__linux__)
+ int sse = 0;
+ struct sigaction sigill_save;
+#ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR
+ if(0 == sigaction(SIGILL, NULL, &sigill_save) && signal(SIGILL, (void (*)(int))sigill_handler_sse_os) != SIG_ERR)
+#else
+ struct sigaction sigill_sse;
+ sigill_sse.sa_sigaction = sigill_handler_sse_os;
+ __sigemptyset(&sigill_sse.sa_mask);
+ sigill_sse.sa_flags = SA_SIGINFO | SA_RESETHAND; /* SA_RESETHAND just in case our SIGILL return jump breaks, so we don't get stuck in a loop */
+ if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save))
+#endif
+ {
+ /* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */
+ /* see sigill_handler_sse_os() for an explanation of the following: */
+ asm volatile (
+ "xorl %0,%0\n\t" /* for some reason, still need to do this to clear 'sse' var */
+ "xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */
+ "incl %0\n\t" /* SIGILL handler will jump over this */
+ /* landing zone */
+ "nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */
+ "nop\n\t"
+ "nop" /* SIGILL jump lands here if "inc" is 1 byte */
+ : "=r"(sse)
+ : "r"(sse)
+ );
+
+ sigaction(SIGILL, &sigill_save, NULL);
+ }
+
+ if(!sse)
+ info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+#elif defined(_MSC_VER)
+# ifdef USE_TRY_CATCH_FLAVOR
+ _try {
+ __asm {
+# if _MSC_VER <= 1200
+ /* VC6 assembler doesn't know SSE, have to emit bytecode instead */
+ _emit 0x0F
+ _emit 0x57
+ _emit 0xC0
+# else
+ xorps xmm0,xmm0
+# endif
+ }
+ }
+ _except(EXCEPTION_EXECUTE_HANDLER) {
+ if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION)
+ info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+ }
+# else
+ int sse = 0;
+ LPTOP_LEVEL_EXCEPTION_FILTER save = SetUnhandledExceptionFilter(sigill_handler_sse_os);
+ /* see GCC version above for explanation */
+ //@@@@@@ http://msdn2.microsoft.com/en-us/library/4ks26t93.aspx
+ //@@@@@@ http://www.codeproject.com/cpp/gccasm.asp
+ //@@@@@@ http://www.hick.org/~mmiller/msvc_inline_asm.html
+ __asm {
+# if _MSC_VER <= 1200
+ /* VC6 assembler doesn't know SSE, have to emit bytecode instead */
+ _emit 0x0F
+ _emit 0x57
+ _emit 0xC0
+# else
+ xorps xmm0,xmm0
+# endif
+ inc sse
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ }
+ SetUnhandledExceptionFilter(save);
+ if(!sse)
+ info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+# endif
+#else
+ /* no way to test, disable to be safe */
+ info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false;
+#endif
+#ifdef DEBUG
+ fprintf(stderr, " SSE OS sup . %c\n", info->data.ia32.sse ? 'Y' : 'n');
+#endif
+
+ }
+ }
+#else
+ info->use_asm = false;
+#endif
+
+/*
+ * PPC-specific
+ */
+#elif defined FLAC__CPU_PPC
+ info->type = FLAC__CPUINFO_TYPE_PPC;
+# if !defined FLAC__NO_ASM
+ info->use_asm = true;
+# ifdef FLAC__USE_ALTIVEC
+# if defined FLAC__SYS_DARWIN
+ {
+ int val = 0, mib[2] = { CTL_HW, HW_VECTORUNIT };
+ size_t len = sizeof(val);
+ info->data.ppc.altivec = !(sysctl(mib, 2, &val, &len, NULL, 0) || !val);
+ }
+ {
+ host_basic_info_data_t hostInfo;
+ mach_msg_type_number_t infoCount;
+
+ infoCount = HOST_BASIC_INFO_COUNT;
+ host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount);
+
+ info->data.ppc.ppc64 = (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970);
+ }
+# else /* FLAC__USE_ALTIVEC && !FLAC__SYS_DARWIN */
+ {
+ /* no Darwin, do it the brute-force way */
+ /* @@@@@@ this is not thread-safe; replace with SSE OS method above or remove */
+ info->data.ppc.altivec = 0;
+ info->data.ppc.ppc64 = 0;
+
+ signal (SIGILL, sigill_handler);
+ canjump = 0;
+ if (!sigsetjmp (jmpbuf, 1)) {
+ canjump = 1;
+
+ asm volatile (
+ "mtspr 256, %0\n\t"
+ "vand %%v0, %%v0, %%v0"
+ :
+ : "r" (-1)
+ );
+
+ info->data.ppc.altivec = 1;
+ }
+ canjump = 0;
+ if (!sigsetjmp (jmpbuf, 1)) {
+ int x = 0;
+ canjump = 1;
+
+ /* PPC64 hardware implements the cntlzd instruction */
+ asm volatile ("cntlzd %0, %1" : "=r" (x) : "r" (x) );
+
+ info->data.ppc.ppc64 = 1;
+ }
+ signal (SIGILL, SIG_DFL); /*@@@@@@ should save and restore old signal */
+ }
+# endif
+# else /* !FLAC__USE_ALTIVEC */
+ info->data.ppc.altivec = 0;
+ info->data.ppc.ppc64 = 0;
+# endif
+# else
+ info->use_asm = false;
+# endif
+
+/*
+ * unknown CPI
+ */
+#else
+ info->type = FLAC__CPUINFO_TYPE_UNKNOWN;
+ info->use_asm = false;
+#endif
+}
diff --git a/src/FLAC/src/libFLAC/crc.c b/src/FLAC/src/libFLAC/crc.c
new file mode 100644
index 0000000..463ab65
--- /dev/null
+++ b/src/FLAC/src/libFLAC/crc.c
@@ -0,0 +1,142 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/crc.h"
+
+/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */
+
+FLAC__byte const FLAC__crc8_table[256] = {
+ 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+ 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+ 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+ 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+ 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+ 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+ 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+ 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+ 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+ 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+ 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+ 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+ 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+ 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+ 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+ 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+ 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+ 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+ 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+ 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+ 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+ 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+ 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+ 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+ 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+ 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+ 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+ 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+ 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+ 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+ 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+ 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+};
+
+/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */
+
+unsigned FLAC__crc16_table[256] = {
+ 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011,
+ 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022,
+ 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072,
+ 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041,
+ 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2,
+ 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1,
+ 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1,
+ 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082,
+ 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192,
+ 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1,
+ 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1,
+ 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2,
+ 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151,
+ 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162,
+ 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132,
+ 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101,
+ 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312,
+ 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321,
+ 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371,
+ 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342,
+ 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1,
+ 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2,
+ 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2,
+ 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381,
+ 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291,
+ 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2,
+ 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2,
+ 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1,
+ 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252,
+ 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261,
+ 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231,
+ 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202
+};
+
+
+void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc)
+{
+ *crc = FLAC__crc8_table[*crc ^ data];
+}
+
+void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc)
+{
+ while(len--)
+ *crc = FLAC__crc8_table[*crc ^ *data++];
+}
+
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len)
+{
+ FLAC__uint8 crc = 0;
+
+ while(len--)
+ crc = FLAC__crc8_table[crc ^ *data++];
+
+ return crc;
+}
+
+unsigned FLAC__crc16(const FLAC__byte *data, unsigned len)
+{
+ unsigned crc = 0;
+
+ while(len--)
+ crc = ((crc<<8) ^ FLAC__crc16_table[(crc>>8) ^ *data++]) & 0xffff;
+
+ return crc;
+}
diff --git a/src/FLAC/src/libFLAC/fixed.c b/src/FLAC/src/libFLAC/fixed.c
new file mode 100644
index 0000000..1a3aac0
--- /dev/null
+++ b/src/FLAC/src/libFLAC/fixed.c
@@ -0,0 +1,435 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include <string.h>
+#include "private/bitmath.h"
+#include "private/fixed.h"
+#include "FLAC/assert.h"
+
+#ifndef M_LN2
+/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
+#define M_LN2 0.69314718055994530942
+#endif
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x) < (y)? (x) : (y))
+
+#ifdef local_abs
+#undef local_abs
+#endif
+#define local_abs(x) ((unsigned)((x)<0? -(x) : (x)))
+
+#ifdef FLAC__INTEGER_ONLY_LIBRARY
+/* rbps stands for residual bits per sample
+ *
+ * (ln(2) * err)
+ * rbps = log (-----------)
+ * 2 ( n )
+ */
+static FLAC__fixedpoint local__compute_rbps_integerized(FLAC__uint32 err, FLAC__uint32 n)
+{
+ FLAC__uint32 rbps;
+ unsigned bits; /* the number of bits required to represent a number */
+ int fracbits; /* the number of bits of rbps that comprise the fractional part */
+
+ FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint));
+ FLAC__ASSERT(err > 0);
+ FLAC__ASSERT(n > 0);
+
+ FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE);
+ if(err <= n)
+ return 0;
+ /*
+ * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1.
+ * These allow us later to know we won't lose too much precision in the
+ * fixed-point division (err<<fracbits)/n.
+ */
+
+ fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2(err)+1);
+
+ err <<= fracbits;
+ err /= n;
+ /* err now holds err/n with fracbits fractional bits */
+
+ /*
+ * Whittle err down to 16 bits max. 16 significant bits is enough for
+ * our purposes.
+ */
+ FLAC__ASSERT(err > 0);
+ bits = FLAC__bitmath_ilog2(err)+1;
+ if(bits > 16) {
+ err >>= (bits-16);
+ fracbits -= (bits-16);
+ }
+ rbps = (FLAC__uint32)err;
+
+ /* Multiply by fixed-point version of ln(2), with 16 fractional bits */
+ rbps *= FLAC__FP_LN2;
+ fracbits += 16;
+ FLAC__ASSERT(fracbits >= 0);
+
+ /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */
+ {
+ const int f = fracbits & 3;
+ if(f) {
+ rbps >>= f;
+ fracbits -= f;
+ }
+ }
+
+ rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1));
+
+ if(rbps == 0)
+ return 0;
+
+ /*
+ * The return value must have 16 fractional bits. Since the whole part
+ * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits
+ * must be >= -3, these assertion allows us to be able to shift rbps
+ * left if necessary to get 16 fracbits without losing any bits of the
+ * whole part of rbps.
+ *
+ * There is a slight chance due to accumulated error that the whole part
+ * will require 6 bits, so we use 6 in the assertion. Really though as
+ * long as it fits in 13 bits (32 - (16 - (-3))) we are fine.
+ */
+ FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6);
+ FLAC__ASSERT(fracbits >= -3);
+
+ /* now shift the decimal point into place */
+ if(fracbits < 16)
+ return rbps << (16-fracbits);
+ else if(fracbits > 16)
+ return rbps >> (fracbits-16);
+ else
+ return rbps;
+}
+
+static FLAC__fixedpoint local__compute_rbps_wide_integerized(FLAC__uint64 err, FLAC__uint32 n)
+{
+ FLAC__uint32 rbps;
+ unsigned bits; /* the number of bits required to represent a number */
+ int fracbits; /* the number of bits of rbps that comprise the fractional part */
+
+ FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint));
+ FLAC__ASSERT(err > 0);
+ FLAC__ASSERT(n > 0);
+
+ FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE);
+ if(err <= n)
+ return 0;
+ /*
+ * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1.
+ * These allow us later to know we won't lose too much precision in the
+ * fixed-point division (err<<fracbits)/n.
+ */
+
+ fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2_wide(err)+1);
+
+ err <<= fracbits;
+ err /= n;
+ /* err now holds err/n with fracbits fractional bits */
+
+ /*
+ * Whittle err down to 16 bits max. 16 significant bits is enough for
+ * our purposes.
+ */
+ FLAC__ASSERT(err > 0);
+ bits = FLAC__bitmath_ilog2_wide(err)+1;
+ if(bits > 16) {
+ err >>= (bits-16);
+ fracbits -= (bits-16);
+ }
+ rbps = (FLAC__uint32)err;
+
+ /* Multiply by fixed-point version of ln(2), with 16 fractional bits */
+ rbps *= FLAC__FP_LN2;
+ fracbits += 16;
+ FLAC__ASSERT(fracbits >= 0);
+
+ /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */
+ {
+ const int f = fracbits & 3;
+ if(f) {
+ rbps >>= f;
+ fracbits -= f;
+ }
+ }
+
+ rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1));
+
+ if(rbps == 0)
+ return 0;
+
+ /*
+ * The return value must have 16 fractional bits. Since the whole part
+ * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits
+ * must be >= -3, these assertion allows us to be able to shift rbps
+ * left if necessary to get 16 fracbits without losing any bits of the
+ * whole part of rbps.
+ *
+ * There is a slight chance due to accumulated error that the whole part
+ * will require 6 bits, so we use 6 in the assertion. Really though as
+ * long as it fits in 13 bits (32 - (16 - (-3))) we are fine.
+ */
+ FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6);
+ FLAC__ASSERT(fracbits >= -3);
+
+ /* now shift the decimal point into place */
+ if(fracbits < 16)
+ return rbps << (16-fracbits);
+ else if(fracbits > 16)
+ return rbps >> (fracbits-16);
+ else
+ return rbps;
+}
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#endif
+{
+ FLAC__int32 last_error_0 = data[-1];
+ FLAC__int32 last_error_1 = data[-1] - data[-2];
+ FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
+ FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+ FLAC__int32 error, save;
+ FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+ unsigned i, order;
+
+ for(i = 0; i < data_len; i++) {
+ error = data[i] ; total_error_0 += local_abs(error); save = error;
+ error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+ error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+ error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+ error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+ }
+
+ if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+ order = 0;
+ else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+ order = 1;
+ else if(total_error_2 < min(total_error_3, total_error_4))
+ order = 2;
+ else if(total_error_3 < total_error_4)
+ order = 3;
+ else
+ order = 4;
+
+ /* Estimate the expected number of bits per residual signal sample. */
+ /* 'total_error*' is linearly related to the variance of the residual */
+ /* signal, so we use it directly to compute E(|x|) */
+ FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+ FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+ FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+ FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+ FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+#else
+ residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_integerized(total_error_0, data_len) : 0;
+ residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_integerized(total_error_1, data_len) : 0;
+ residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_integerized(total_error_2, data_len) : 0;
+ residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_integerized(total_error_3, data_len) : 0;
+ residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_integerized(total_error_4, data_len) : 0;
+#endif
+
+ return order;
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#else
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+#endif
+{
+ FLAC__int32 last_error_0 = data[-1];
+ FLAC__int32 last_error_1 = data[-1] - data[-2];
+ FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
+ FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+ FLAC__int32 error, save;
+ /* total_error_* are 64-bits to avoid overflow when encoding
+ * erratic signals when the bits-per-sample and blocksize are
+ * large.
+ */
+ FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+ unsigned i, order;
+
+ for(i = 0; i < data_len; i++) {
+ error = data[i] ; total_error_0 += local_abs(error); save = error;
+ error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+ error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+ error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+ error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+ }
+
+ if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+ order = 0;
+ else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+ order = 1;
+ else if(total_error_2 < min(total_error_3, total_error_4))
+ order = 2;
+ else if(total_error_3 < total_error_4)
+ order = 3;
+ else
+ order = 4;
+
+ /* Estimate the expected number of bits per residual signal sample. */
+ /* 'total_error*' is linearly related to the variance of the residual */
+ /* signal, so we use it directly to compute E(|x|) */
+ FLAC__ASSERT(data_len > 0 || total_error_0 == 0);
+ FLAC__ASSERT(data_len > 0 || total_error_1 == 0);
+ FLAC__ASSERT(data_len > 0 || total_error_2 == 0);
+ FLAC__ASSERT(data_len > 0 || total_error_3 == 0);
+ FLAC__ASSERT(data_len > 0 || total_error_4 == 0);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if defined _MSC_VER || defined __MINGW32__
+ /* with MSVC you have to spoon feed it the casting */
+ residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+#else
+ residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+#endif
+#else
+ residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_wide_integerized(total_error_0, data_len) : 0;
+ residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_wide_integerized(total_error_1, data_len) : 0;
+ residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_wide_integerized(total_error_2, data_len) : 0;
+ residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_wide_integerized(total_error_3, data_len) : 0;
+ residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_wide_integerized(total_error_4, data_len) : 0;
+#endif
+
+ return order;
+}
+
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[])
+{
+ const int idata_len = (int)data_len;
+ int i;
+
+ switch(order) {
+ case 0:
+ FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0]));
+ memcpy(residual, data, sizeof(residual[0])*data_len);
+ break;
+ case 1:
+ for(i = 0; i < idata_len; i++)
+ residual[i] = data[i] - data[i-1];
+ break;
+ case 2:
+ for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+ residual[i] = data[i] - (data[i-1] << 1) + data[i-2];
+#else
+ residual[i] = data[i] - 2*data[i-1] + data[i-2];
+#endif
+ break;
+ case 3:
+ for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+ residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3];
+#else
+ residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3];
+#endif
+ break;
+ case 4:
+ for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+ residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4];
+#else
+ residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4];
+#endif
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+}
+
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[])
+{
+ int i, idata_len = (int)data_len;
+
+ switch(order) {
+ case 0:
+ FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0]));
+ memcpy(data, residual, sizeof(residual[0])*data_len);
+ break;
+ case 1:
+ for(i = 0; i < idata_len; i++)
+ data[i] = residual[i] + data[i-1];
+ break;
+ case 2:
+ for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+ data[i] = residual[i] + (data[i-1]<<1) - data[i-2];
+#else
+ data[i] = residual[i] + 2*data[i-1] - data[i-2];
+#endif
+ break;
+ case 3:
+ for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+ data[i] = residual[i] + (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) + data[i-3];
+#else
+ data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3];
+#endif
+ break;
+ case 4:
+ for(i = 0; i < idata_len; i++)
+#if 1 /* OPT: may be faster with some compilers on some systems */
+ data[i] = residual[i] + ((data[i-1]+data[i-3])<<2) - ((data[i-2]<<2) + (data[i-2]<<1)) - data[i-4];
+#else
+ data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4];
+#endif
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+}
diff --git a/src/FLAC/src/libFLAC/flac.pc.in b/src/FLAC/src/libFLAC/flac.pc.in
new file mode 100644
index 0000000..8fc39f8
--- /dev/null
+++ b/src/FLAC/src/libFLAC/flac.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: FLAC
+Description: Free Lossless Audio Codec Library
+Version: @VERSION@
+Libs: -L${libdir} -lFLAC -lm
+Cflags: -I${includedir}/FLAC
diff --git a/src/FLAC/src/libFLAC/float.c b/src/FLAC/src/libFLAC/float.c
new file mode 100644
index 0000000..8e19280
--- /dev/null
+++ b/src/FLAC/src/libFLAC/float.c
@@ -0,0 +1,308 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+
+#include "private/float.h"
+
+#ifdef FLAC__INTEGER_ONLY_LIBRARY
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+const FLAC__fixedpoint FLAC__FP_ZERO = 0;
+const FLAC__fixedpoint FLAC__FP_ONE_HALF = 0x00008000;
+const FLAC__fixedpoint FLAC__FP_ONE = 0x00010000;
+const FLAC__fixedpoint FLAC__FP_LN2 = 45426;
+const FLAC__fixedpoint FLAC__FP_E = 178145;
+
+/* Lookup tables for Knuth's logarithm algorithm */
+#define LOG2_LOOKUP_PRECISION 16
+static const FLAC__uint32 log2_lookup[][LOG2_LOOKUP_PRECISION] = {
+ {
+ /*
+ * 0 fraction bits
+ */
+ /* undefined */ 0x00000000,
+ /* lg(2/1) = */ 0x00000001,
+ /* lg(4/3) = */ 0x00000000,
+ /* lg(8/7) = */ 0x00000000,
+ /* lg(16/15) = */ 0x00000000,
+ /* lg(32/31) = */ 0x00000000,
+ /* lg(64/63) = */ 0x00000000,
+ /* lg(128/127) = */ 0x00000000,
+ /* lg(256/255) = */ 0x00000000,
+ /* lg(512/511) = */ 0x00000000,
+ /* lg(1024/1023) = */ 0x00000000,
+ /* lg(2048/2047) = */ 0x00000000,
+ /* lg(4096/4095) = */ 0x00000000,
+ /* lg(8192/8191) = */ 0x00000000,
+ /* lg(16384/16383) = */ 0x00000000,
+ /* lg(32768/32767) = */ 0x00000000
+ },
+ {
+ /*
+ * 4 fraction bits
+ */
+ /* undefined */ 0x00000000,
+ /* lg(2/1) = */ 0x00000010,
+ /* lg(4/3) = */ 0x00000007,
+ /* lg(8/7) = */ 0x00000003,
+ /* lg(16/15) = */ 0x00000001,
+ /* lg(32/31) = */ 0x00000001,
+ /* lg(64/63) = */ 0x00000000,
+ /* lg(128/127) = */ 0x00000000,
+ /* lg(256/255) = */ 0x00000000,
+ /* lg(512/511) = */ 0x00000000,
+ /* lg(1024/1023) = */ 0x00000000,
+ /* lg(2048/2047) = */ 0x00000000,
+ /* lg(4096/4095) = */ 0x00000000,
+ /* lg(8192/8191) = */ 0x00000000,
+ /* lg(16384/16383) = */ 0x00000000,
+ /* lg(32768/32767) = */ 0x00000000
+ },
+ {
+ /*
+ * 8 fraction bits
+ */
+ /* undefined */ 0x00000000,
+ /* lg(2/1) = */ 0x00000100,
+ /* lg(4/3) = */ 0x0000006a,
+ /* lg(8/7) = */ 0x00000031,
+ /* lg(16/15) = */ 0x00000018,
+ /* lg(32/31) = */ 0x0000000c,
+ /* lg(64/63) = */ 0x00000006,
+ /* lg(128/127) = */ 0x00000003,
+ /* lg(256/255) = */ 0x00000001,
+ /* lg(512/511) = */ 0x00000001,
+ /* lg(1024/1023) = */ 0x00000000,
+ /* lg(2048/2047) = */ 0x00000000,
+ /* lg(4096/4095) = */ 0x00000000,
+ /* lg(8192/8191) = */ 0x00000000,
+ /* lg(16384/16383) = */ 0x00000000,
+ /* lg(32768/32767) = */ 0x00000000
+ },
+ {
+ /*
+ * 12 fraction bits
+ */
+ /* undefined */ 0x00000000,
+ /* lg(2/1) = */ 0x00001000,
+ /* lg(4/3) = */ 0x000006a4,
+ /* lg(8/7) = */ 0x00000315,
+ /* lg(16/15) = */ 0x0000017d,
+ /* lg(32/31) = */ 0x000000bc,
+ /* lg(64/63) = */ 0x0000005d,
+ /* lg(128/127) = */ 0x0000002e,
+ /* lg(256/255) = */ 0x00000017,
+ /* lg(512/511) = */ 0x0000000c,
+ /* lg(1024/1023) = */ 0x00000006,
+ /* lg(2048/2047) = */ 0x00000003,
+ /* lg(4096/4095) = */ 0x00000001,
+ /* lg(8192/8191) = */ 0x00000001,
+ /* lg(16384/16383) = */ 0x00000000,
+ /* lg(32768/32767) = */ 0x00000000
+ },
+ {
+ /*
+ * 16 fraction bits
+ */
+ /* undefined */ 0x00000000,
+ /* lg(2/1) = */ 0x00010000,
+ /* lg(4/3) = */ 0x00006a40,
+ /* lg(8/7) = */ 0x00003151,
+ /* lg(16/15) = */ 0x000017d6,
+ /* lg(32/31) = */ 0x00000bba,
+ /* lg(64/63) = */ 0x000005d1,
+ /* lg(128/127) = */ 0x000002e6,
+ /* lg(256/255) = */ 0x00000172,
+ /* lg(512/511) = */ 0x000000b9,
+ /* lg(1024/1023) = */ 0x0000005c,
+ /* lg(2048/2047) = */ 0x0000002e,
+ /* lg(4096/4095) = */ 0x00000017,
+ /* lg(8192/8191) = */ 0x0000000c,
+ /* lg(16384/16383) = */ 0x00000006,
+ /* lg(32768/32767) = */ 0x00000003
+ },
+ {
+ /*
+ * 20 fraction bits
+ */
+ /* undefined */ 0x00000000,
+ /* lg(2/1) = */ 0x00100000,
+ /* lg(4/3) = */ 0x0006a3fe,
+ /* lg(8/7) = */ 0x00031513,
+ /* lg(16/15) = */ 0x00017d60,
+ /* lg(32/31) = */ 0x0000bb9d,
+ /* lg(64/63) = */ 0x00005d10,
+ /* lg(128/127) = */ 0x00002e59,
+ /* lg(256/255) = */ 0x00001721,
+ /* lg(512/511) = */ 0x00000b8e,
+ /* lg(1024/1023) = */ 0x000005c6,
+ /* lg(2048/2047) = */ 0x000002e3,
+ /* lg(4096/4095) = */ 0x00000171,
+ /* lg(8192/8191) = */ 0x000000b9,
+ /* lg(16384/16383) = */ 0x0000005c,
+ /* lg(32768/32767) = */ 0x0000002e
+ },
+ {
+ /*
+ * 24 fraction bits
+ */
+ /* undefined */ 0x00000000,
+ /* lg(2/1) = */ 0x01000000,
+ /* lg(4/3) = */ 0x006a3fe6,
+ /* lg(8/7) = */ 0x00315130,
+ /* lg(16/15) = */ 0x0017d605,
+ /* lg(32/31) = */ 0x000bb9ca,
+ /* lg(64/63) = */ 0x0005d0fc,
+ /* lg(128/127) = */ 0x0002e58f,
+ /* lg(256/255) = */ 0x0001720e,
+ /* lg(512/511) = */ 0x0000b8d8,
+ /* lg(1024/1023) = */ 0x00005c61,
+ /* lg(2048/2047) = */ 0x00002e2d,
+ /* lg(4096/4095) = */ 0x00001716,
+ /* lg(8192/8191) = */ 0x00000b8b,
+ /* lg(16384/16383) = */ 0x000005c5,
+ /* lg(32768/32767) = */ 0x000002e3
+ },
+ {
+ /*
+ * 28 fraction bits
+ */
+ /* undefined */ 0x00000000,
+ /* lg(2/1) = */ 0x10000000,
+ /* lg(4/3) = */ 0x06a3fe5c,
+ /* lg(8/7) = */ 0x03151301,
+ /* lg(16/15) = */ 0x017d6049,
+ /* lg(32/31) = */ 0x00bb9ca6,
+ /* lg(64/63) = */ 0x005d0fba,
+ /* lg(128/127) = */ 0x002e58f7,
+ /* lg(256/255) = */ 0x001720da,
+ /* lg(512/511) = */ 0x000b8d87,
+ /* lg(1024/1023) = */ 0x0005c60b,
+ /* lg(2048/2047) = */ 0x0002e2d7,
+ /* lg(4096/4095) = */ 0x00017160,
+ /* lg(8192/8191) = */ 0x0000b8ad,
+ /* lg(16384/16383) = */ 0x00005c56,
+ /* lg(32768/32767) = */ 0x00002e2b
+ }
+};
+
+#if 0
+static const FLAC__uint64 log2_lookup_wide[] = {
+ {
+ /*
+ * 32 fraction bits
+ */
+ /* undefined */ 0x00000000,
+ /* lg(2/1) = */ FLAC__U64L(0x100000000),
+ /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c6),
+ /* lg(8/7) = */ FLAC__U64L(0x31513015),
+ /* lg(16/15) = */ FLAC__U64L(0x17d60497),
+ /* lg(32/31) = */ FLAC__U64L(0x0bb9ca65),
+ /* lg(64/63) = */ FLAC__U64L(0x05d0fba2),
+ /* lg(128/127) = */ FLAC__U64L(0x02e58f74),
+ /* lg(256/255) = */ FLAC__U64L(0x01720d9c),
+ /* lg(512/511) = */ FLAC__U64L(0x00b8d875),
+ /* lg(1024/1023) = */ FLAC__U64L(0x005c60aa),
+ /* lg(2048/2047) = */ FLAC__U64L(0x002e2d72),
+ /* lg(4096/4095) = */ FLAC__U64L(0x00171600),
+ /* lg(8192/8191) = */ FLAC__U64L(0x000b8ad2),
+ /* lg(16384/16383) = */ FLAC__U64L(0x0005c55d),
+ /* lg(32768/32767) = */ FLAC__U64L(0x0002e2ac)
+ },
+ {
+ /*
+ * 48 fraction bits
+ */
+ /* undefined */ 0x00000000,
+ /* lg(2/1) = */ FLAC__U64L(0x1000000000000),
+ /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c60429),
+ /* lg(8/7) = */ FLAC__U64L(0x315130157f7a),
+ /* lg(16/15) = */ FLAC__U64L(0x17d60496cfbb),
+ /* lg(32/31) = */ FLAC__U64L(0xbb9ca64ecac),
+ /* lg(64/63) = */ FLAC__U64L(0x5d0fba187cd),
+ /* lg(128/127) = */ FLAC__U64L(0x2e58f7441ee),
+ /* lg(256/255) = */ FLAC__U64L(0x1720d9c06a8),
+ /* lg(512/511) = */ FLAC__U64L(0xb8d8752173),
+ /* lg(1024/1023) = */ FLAC__U64L(0x5c60aa252e),
+ /* lg(2048/2047) = */ FLAC__U64L(0x2e2d71b0d8),
+ /* lg(4096/4095) = */ FLAC__U64L(0x1716001719),
+ /* lg(8192/8191) = */ FLAC__U64L(0xb8ad1de1b),
+ /* lg(16384/16383) = */ FLAC__U64L(0x5c55d640d),
+ /* lg(32768/32767) = */ FLAC__U64L(0x2e2abcf52)
+ }
+};
+#endif
+
+FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision)
+{
+ const FLAC__uint32 ONE = (1u << fracbits);
+ const FLAC__uint32 *table = log2_lookup[fracbits >> 2];
+
+ FLAC__ASSERT(fracbits < 32);
+ FLAC__ASSERT((fracbits & 0x3) == 0);
+
+ if(x < ONE)
+ return 0;
+
+ if(precision > LOG2_LOOKUP_PRECISION)
+ precision = LOG2_LOOKUP_PRECISION;
+
+ /* Knuth's algorithm for computing logarithms, optimized for base-2 with lookup tables */
+ {
+ FLAC__uint32 y = 0;
+ FLAC__uint32 z = x >> 1, k = 1;
+ while (x > ONE && k < precision) {
+ if (x - z >= ONE) {
+ x -= z;
+ z = x >> k;
+ y += table[k];
+ }
+ else {
+ z >>= 1;
+ k++;
+ }
+ }
+ return y;
+ }
+}
+
+#endif /* defined FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/FLAC/src/libFLAC/format.c b/src/FLAC/src/libFLAC/format.c
new file mode 100644
index 0000000..de911ac
--- /dev/null
+++ b/src/FLAC/src/libFLAC/format.c
@@ -0,0 +1,583 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for qsort() */
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/format.h"
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a)<(b)?(a):(b))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+/* VERSION should come from configure */
+FLAC_API const char *FLAC__VERSION_STRING = VERSION;
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINW32__
+/* yet one more hack because of MSVC6: */
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.1.4 20070213";
+#else
+FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20070213";
+#endif
+
+FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' };
+FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143;
+FLAC_API const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */
+
+FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff);
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */
+
+FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */
+FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */
+
+FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC = 0x3ffe;
+FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 2; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */
+
+FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */
+
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */
+
+FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
+
+FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = {
+ "PARTITIONED_RICE"
+};
+
+FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */
+FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */
+
+FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */
+FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */
+
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00;
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02;
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10;
+FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40;
+
+FLAC_API const char * const FLAC__SubframeTypeString[] = {
+ "CONSTANT",
+ "VERBATIM",
+ "FIXED",
+ "LPC"
+};
+
+FLAC_API const char * const FLAC__ChannelAssignmentString[] = {
+ "INDEPENDENT",
+ "LEFT_SIDE",
+ "RIGHT_SIDE",
+ "MID_SIDE"
+};
+
+FLAC_API const char * const FLAC__FrameNumberTypeString[] = {
+ "FRAME_NUMBER_TYPE_FRAME_NUMBER",
+ "FRAME_NUMBER_TYPE_SAMPLE_NUMBER"
+};
+
+FLAC_API const char * const FLAC__MetadataTypeString[] = {
+ "STREAMINFO",
+ "PADDING",
+ "APPLICATION",
+ "SEEKTABLE",
+ "VORBIS_COMMENT",
+ "CUESHEET",
+ "PICTURE"
+};
+
+FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = {
+ "Other",
+ "32x32 pixels 'file icon' (PNG only)",
+ "Other file icon",
+ "Cover (front)",
+ "Cover (back)",
+ "Leaflet page",
+ "Media (e.g. label side of CD)",
+ "Lead artist/lead performer/soloist",
+ "Artist/performer",
+ "Conductor",
+ "Band/Orchestra",
+ "Composer",
+ "Lyricist/text writer",
+ "Recording Location",
+ "During recording",
+ "During performance",
+ "Movie/video screen capture",
+ "A bright coloured fish",
+ "Illustration",
+ "Band/artist logotype",
+ "Publisher/Studio logotype"
+};
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate)
+{
+ if(sample_rate == 0 || sample_rate > FLAC__MAX_SAMPLE_RATE) {
+ return false;
+ }
+ else
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate)
+{
+ if(
+ !FLAC__format_sample_rate_is_valid(sample_rate) ||
+ (
+ sample_rate >= (1u << 16) &&
+ !(sample_rate % 1000 == 0 || sample_rate % 10 == 0)
+ )
+ ) {
+ return false;
+ }
+ else
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table)
+{
+ unsigned i;
+ FLAC__uint64 prev_sample_number = 0;
+ FLAC__bool got_prev = false;
+
+ FLAC__ASSERT(0 != seek_table);
+
+ for(i = 0; i < seek_table->num_points; i++) {
+ if(got_prev) {
+ if(
+ seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER &&
+ seek_table->points[i].sample_number <= prev_sample_number
+ )
+ return false;
+ }
+ prev_sample_number = seek_table->points[i].sample_number;
+ got_prev = true;
+ }
+
+ return true;
+}
+
+/* used as the sort predicate for qsort() */
+static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r)
+{
+ /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */
+ if(l->sample_number == r->sample_number)
+ return 0;
+ else if(l->sample_number < r->sample_number)
+ return -1;
+ else
+ return 1;
+}
+
+FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table)
+{
+ unsigned i, j;
+ FLAC__bool first;
+
+ FLAC__ASSERT(0 != seek_table);
+
+ /* sort the seekpoints */
+ qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_);
+
+ /* uniquify the seekpoints */
+ first = true;
+ for(i = j = 0; i < seek_table->num_points; i++) {
+ if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) {
+ if(!first) {
+ if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number)
+ continue;
+ }
+ }
+ first = false;
+ seek_table->points[j++] = seek_table->points[i];
+ }
+
+ for(i = j; i < seek_table->num_points; i++) {
+ seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ seek_table->points[i].stream_offset = 0;
+ seek_table->points[i].frame_samples = 0;
+ }
+
+ return j;
+}
+
+/*
+ * also disallows non-shortest-form encodings, c.f.
+ * http://www.unicode.org/versions/corrigendum1.html
+ * and a more clear explanation at the end of this section:
+ * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+ */
+static FLaC__INLINE unsigned utf8len_(const FLAC__byte *utf8)
+{
+ FLAC__ASSERT(0 != utf8);
+ if ((utf8[0] & 0x80) == 0) {
+ return 1;
+ }
+ else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) {
+ if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */
+ return 0;
+ return 2;
+ }
+ else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) {
+ if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */
+ return 0;
+ /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */
+ if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */
+ return 0;
+ if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */
+ return 0;
+ return 3;
+ }
+ else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) {
+ if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */
+ return 0;
+ return 4;
+ }
+ else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) {
+ if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */
+ return 0;
+ return 5;
+ }
+ else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) {
+ if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */
+ return 0;
+ return 6;
+ }
+ else {
+ return 0;
+ }
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name)
+{
+ char c;
+ for(c = *name; c; c = *(++name))
+ if(c < 0x20 || c == 0x3d || c > 0x7d)
+ return false;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length)
+{
+ if(length == (unsigned)(-1)) {
+ while(*value) {
+ unsigned n = utf8len_(value);
+ if(n == 0)
+ return false;
+ value += n;
+ }
+ }
+ else {
+ const FLAC__byte *end = value + length;
+ while(value < end) {
+ unsigned n = utf8len_(value);
+ if(n == 0)
+ return false;
+ value += n;
+ }
+ if(value != end)
+ return false;
+ }
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length)
+{
+ const FLAC__byte *s, *end;
+
+ for(s = entry, end = s + length; s < end && *s != '='; s++) {
+ if(*s < 0x20 || *s > 0x7D)
+ return false;
+ }
+ if(s == end)
+ return false;
+
+ s++; /* skip '=' */
+
+ while(s < end) {
+ unsigned n = utf8len_(s);
+ if(n == 0)
+ return false;
+ s += n;
+ }
+ if(s != end)
+ return false;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation)
+{
+ unsigned i, j;
+
+ if(check_cd_da_subset) {
+ if(cue_sheet->lead_in < 2 * 44100) {
+ if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds";
+ return false;
+ }
+ if(cue_sheet->lead_in % 588 != 0) {
+ if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples";
+ return false;
+ }
+ }
+
+ if(cue_sheet->num_tracks == 0) {
+ if(violation) *violation = "cue sheet must have at least one track (the lead-out)";
+ return false;
+ }
+
+ if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) {
+ if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)";
+ return false;
+ }
+
+ for(i = 0; i < cue_sheet->num_tracks; i++) {
+ if(cue_sheet->tracks[i].number == 0) {
+ if(violation) *violation = "cue sheet may not have a track number 0";
+ return false;
+ }
+
+ if(check_cd_da_subset) {
+ if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) {
+ if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170";
+ return false;
+ }
+ }
+
+ if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) {
+ if(violation) {
+ if(i == cue_sheet->num_tracks-1) /* the lead-out track... */
+ *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples";
+ else
+ *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples";
+ }
+ return false;
+ }
+
+ if(i < cue_sheet->num_tracks - 1) {
+ if(cue_sheet->tracks[i].num_indices == 0) {
+ if(violation) *violation = "cue sheet track must have at least one index point";
+ return false;
+ }
+
+ if(cue_sheet->tracks[i].indices[0].number > 1) {
+ if(violation) *violation = "cue sheet track's first index number must be 0 or 1";
+ return false;
+ }
+ }
+
+ for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) {
+ if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) {
+ if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples";
+ return false;
+ }
+
+ if(j > 0) {
+ if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) {
+ if(violation) *violation = "cue sheet track index numbers must increase by 1";
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation)
+{
+ char *p;
+ FLAC__byte *b;
+
+ for(p = picture->mime_type; *p; p++) {
+ if(*p < 0x20 || *p > 0x7e) {
+ if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)";
+ return false;
+ }
+ }
+
+ for(b = picture->description; *b; ) {
+ unsigned n = utf8len_(b);
+ if(n == 0) {
+ if(violation) *violation = "description string must be valid UTF-8";
+ return false;
+ }
+ b += n;
+ }
+
+ return true;
+}
+
+/*
+ * These routines are private to libFLAC
+ */
+unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order)
+{
+ return
+ FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(
+ FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize),
+ blocksize,
+ predictor_order
+ );
+}
+
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize)
+{
+ unsigned max_rice_partition_order = 0;
+ while(!(blocksize & 1)) {
+ max_rice_partition_order++;
+ blocksize >>= 1;
+ }
+ return min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order);
+}
+
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order)
+{
+ unsigned max_rice_partition_order = limit;
+
+ while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order)
+ max_rice_partition_order--;
+
+ FLAC__ASSERT(
+ (max_rice_partition_order == 0 && blocksize >= predictor_order) ||
+ (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order)
+ );
+
+ return max_rice_partition_order;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+ FLAC__ASSERT(0 != object);
+
+ object->parameters = 0;
+ object->raw_bits = 0;
+ object->capacity_by_order = 0;
+}
+
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object)
+{
+ FLAC__ASSERT(0 != object);
+
+ if(0 != object->parameters)
+ free(object->parameters);
+ if(0 != object->raw_bits)
+ free(object->raw_bits);
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object);
+}
+
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order)
+{
+ FLAC__ASSERT(0 != object);
+
+ FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits));
+
+ if(object->capacity_by_order < max_partition_order) {
+ if(0 == (object->parameters = (unsigned*)realloc(object->parameters, sizeof(unsigned)*(1 << max_partition_order))))
+ return false;
+ if(0 == (object->raw_bits = (unsigned*)realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order))))
+ return false;
+ object->capacity_by_order = max_partition_order;
+ }
+
+ return true;
+}
diff --git a/src/FLAC/src/libFLAC/ia32/Makefile.am b/src/FLAC/src/libFLAC/ia32/Makefile.am
new file mode 100644
index 0000000..93a1c4f
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ia32/Makefile.am
@@ -0,0 +1,45 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+SUFFIXES = .nasm .lo
+
+STRIP_NON_ASM = sh $(top_srcdir)/src/FLAC/strip_non_asm_libtool_args.sh
+
+.nasm.lo:
+ $(LIBTOOL) --tag=CC --mode=compile $(STRIP_NON_ASM) $(NASM) -f $(OBJ_FORMAT) -d OBJ_FORMAT_$(OBJ_FORMAT) -i$(srcdir)/ $< -o $@
+
+noinst_LTLIBRARIES = libFLAC-asm.la
+libFLAC_asm_la_SOURCES = \
+ bitreader_asm.nasm \
+ cpu_asm.nasm \
+ fixed_asm.nasm \
+ lpc_asm.nasm \
+ nasm.h \
+ stream_encoder_asm.nasm
diff --git a/src/FLAC/src/libFLAC/ia32/bitreader_asm.nasm b/src/FLAC/src/libFLAC/ia32/bitreader_asm.nasm
new file mode 100644
index 0000000..5d1bbfa
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ia32/bitreader_asm.nasm
@@ -0,0 +1,568 @@
+; vim:filetype=nasm ts=8
+
+; libFLAC - Free Lossless Audio Codec library
+; Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+;
+; 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 "nasm.h"
+
+ data_section
+
+cextern FLAC__crc16_table ; unsigned FLAC__crc16_table[256];
+cextern bitreader_read_from_client_ ; FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br);
+
+cglobal FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap
+
+ code_section
+
+
+; **********************************************************************
+;
+; void FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter)
+;
+; Some details like assertions and other checking is performed by the caller.
+ ALIGN 16
+cident FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap
+
+ ;ASSERT(0 != br);
+ ;ASSERT(0 != br->buffer);
+ ; WATCHOUT: code only works if sizeof(brword)==32; we can make things much faster with this assertion
+ ;ASSERT(FLAC__BITS_PER_WORD == 32);
+ ;ASSERT(parameter < 32);
+ ; the above two asserts also guarantee that the binary part never straddles more than 2 words, so we don't have to loop to read it
+
+ ;; peppered throughout the code at major checkpoints are keys like this as to where things are at that point in time
+ ;; [esp + 16] unsigned parameter
+ ;; [esp + 12] unsigned nvals
+ ;; [esp + 8] int vals[]
+ ;; [esp + 4] FLAC__BitReader *br
+ mov eax, [esp + 12] ; if(nvals == 0)
+ test eax, eax
+ ja .nvals_gt_0
+ mov eax, 1 ; return true;
+ ret
+
+.nvals_gt_0:
+ push ebp
+ push ebx
+ push esi
+ push edi
+ sub esp, 4
+ ;; [esp + 36] unsigned parameter
+ ;; [esp + 32] unsigned nvals
+ ;; [esp + 28] int vals[]
+ ;; [esp + 24] FLAC__BitReader *br
+ ;; [esp] ucbits
+ mov ebp, [esp + 24] ; ebp <- br == br->buffer
+ mov esi, [ebp + 16] ; esi <- br->consumed_words (aka 'cwords' in the C version)
+ mov ecx, [ebp + 20] ; ecx <- br->consumed_bits (aka 'cbits' in the C version)
+ xor edi, edi ; edi <- 0 'uval'
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ ;; [ebp] br->buffer
+ ;; [ebp + 8] br->words
+ ;; [ebp + 12] br->bytes
+ ;; [ebp + 16] br->consumed_words
+ ;; [ebp + 20] br->consumed_bits
+ ;; [ebp + 24] br->read_crc
+ ;; [ebp + 28] br->crc16_align
+
+ ; ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+ mov eax, [ebp + 8] ; eax <- br->words
+ sub eax, esi ; eax <- br->words-cwords
+ shl eax, 2 ; eax <- (br->words-cwords)*FLAC__BYTES_PER_WORD
+ add eax, [ebp + 12] ; eax <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
+ shl eax, 3 ; eax <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
+ sub eax, ecx ; eax <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
+ mov [esp], eax ; ucbits <- eax
+
+ ALIGN 16
+.val_loop: ; while(1) {
+
+ ;
+ ; read unary part
+ ;
+.unary_loop: ; while(1) {
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ cmp esi, [ebp + 8] ; while(cwords < br->words) /* if we've not consumed up to a partial tail word... */
+ jae near .c1_next1
+.c1_loop: ; {
+ mov ebx, [ebp]
+ mov eax, [ebx + 4*esi] ; b = br->buffer[cwords]
+ mov edx, eax ; edx = br->buffer[cwords] (saved for later use)
+ shl eax, cl ; b = br->buffer[cwords] << cbits
+ test eax, eax ; (still have to test since cbits may be 0, thus ZF not updated for shl eax,0)
+ jz near .c1_next2 ; if(b) {
+ bsr ebx, eax
+ not ebx
+ and ebx, 31 ; ebx = 'i' = # of leading 0 bits in 'b' (eax)
+ add ecx, ebx ; cbits += i;
+ add edi, ebx ; uval += i;
+ add ecx, byte 1 ; cbits++; /* skip over stop bit */
+ test ecx, ~31
+ jz near .break1 ; if(cbits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(cbits == FLAC__BITS_PER_WORD) */
+ ; crc16_update_word_(br, br->buffer[cwords]);
+ push edi ; [need more registers]
+ bswap edx ; edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
+ mov ecx, [ebp + 28] ; ecx <- br->crc16_align
+ mov eax, [ebp + 24] ; ax <- br->read_crc (a.k.a. crc)
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ mov edi, _FLAC__crc16_table
+%else
+ mov edi, FLAC__crc16_table
+%endif
+ ;; eax (ax) crc a.k.a. br->read_crc
+ ;; ebx (bl) intermediate result index into FLAC__crc16_table[]
+ ;; ecx br->crc16_align
+ ;; edx byteswapped brword to CRC
+ ;; esi cwords
+ ;; edi unsigned FLAC__crc16_table[]
+ ;; ebp br
+ test ecx, ecx ; switch(br->crc16_align) ...
+ jnz .c0b4 ; [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
+.c0b0: xor dl, ah ; dl <- (crc>>8)^(word>>24)
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
+.c0b1: xor dh, ah ; dh <- (crc>>8)^((word>>16)&0xff))
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shr edx, 16
+.c0b2: xor dl, ah ; dl <- (crc>>8)^((word>>8)&0xff))
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+.c0b3: xor dh, ah ; dh <- (crc>>8)^(word&0xff)
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ movzx eax, ax
+ mov [ebp + 24], eax ; br->read_crc <- crc
+ pop edi
+
+ add esi, byte 1 ; cwords++;
+ xor ecx, ecx ; cbits = 0;
+ ; }
+ jmp near .break1 ; goto break1;
+ ;; this section relocated out of the way for performance
+.c0b4:
+ mov [ebp + 28], dword 0 ; br->crc16_align <- 0
+ cmp ecx, 8
+ je .c0b1
+ shr edx, 16
+ cmp ecx, 16
+ je .c0b2
+ jmp .c0b3
+
+ ;; this section relocated out of the way for performance
+.c1b4:
+ mov [ebp + 28], dword 0 ; br->crc16_align <- 0
+ cmp ecx, 8
+ je .c1b1
+ shr edx, 16
+ cmp ecx, 16
+ je .c1b2
+ jmp .c1b3
+
+.c1_next2: ; } else {
+ ;; ecx cbits
+ ;; edx current brword 'b'
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ add edi, 32
+ sub edi, ecx ; uval += FLAC__BITS_PER_WORD - cbits;
+ ; crc16_update_word_(br, br->buffer[cwords]);
+ push edi ; [need more registers]
+ bswap edx ; edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
+ mov ecx, [ebp + 28] ; ecx <- br->crc16_align
+ mov eax, [ebp + 24] ; ax <- br->read_crc (a.k.a. crc)
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ mov edi, _FLAC__crc16_table
+%else
+ mov edi, FLAC__crc16_table
+%endif
+ ;; eax (ax) crc a.k.a. br->read_crc
+ ;; ebx (bl) intermediate result index into FLAC__crc16_table[]
+ ;; ecx br->crc16_align
+ ;; edx byteswapped brword to CRC
+ ;; esi cwords
+ ;; edi unsigned FLAC__crc16_table[]
+ ;; ebp br
+ test ecx, ecx ; switch(br->crc16_align) ...
+ jnz .c1b4 ; [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
+.c1b0: xor dl, ah ; dl <- (crc>>8)^(word>>24)
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
+.c1b1: xor dh, ah ; dh <- (crc>>8)^((word>>16)&0xff))
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shr edx, 16
+.c1b2: xor dl, ah ; dl <- (crc>>8)^((word>>8)&0xff))
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+.c1b3: xor dh, ah ; dh <- (crc>>8)^(word&0xff)
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ movzx eax, ax
+ mov [ebp + 24], eax ; br->read_crc <- crc
+ pop edi
+
+ add esi, byte 1 ; cwords++;
+ xor ecx, ecx ; cbits = 0;
+ ; /* didn't find stop bit yet, have to keep going... */
+ ; }
+
+ cmp esi, [ebp + 8] ; } while(cwords < br->words) /* if we've not consumed up to a partial tail word... */
+ jb near .c1_loop
+
+.c1_next1:
+ ; at this point we've eaten up all the whole words; have to try
+ ; reading through any tail bytes before calling the read callback.
+ ; this is a repeat of the above logic adjusted for the fact we
+ ; don't have a whole word. note though if the client is feeding
+ ; us data a byte at a time (unlikely), br->consumed_bits may not
+ ; be zero.
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ mov edx, [ebp + 12] ; edx <- br->bytes
+ test edx, edx
+ jz .read1 ; if(br->bytes) { [NOTE: this case is rare so it doesn't have to be all that fast ]
+ mov ebx, [ebp]
+ shl edx, 3 ; edx <- const unsigned end = br->bytes * 8;
+ mov eax, [ebx + 4*esi] ; b = br->buffer[cwords]
+ xchg edx, ecx ; [edx <- cbits , ecx <- end]
+ mov ebx, 0xffffffff ; ebx <- FLAC__WORD_ALL_ONES
+ shr ebx, cl ; ebx <- FLAC__WORD_ALL_ONES >> end
+ not ebx ; ebx <- ~(FLAC__WORD_ALL_ONES >> end)
+ xchg edx, ecx ; [edx <- end , ecx <- cbits]
+ and eax, ebx ; b = (br->buffer[cwords] & ~(FLAC__WORD_ALL_ONES >> end));
+ shl eax, cl ; b = (br->buffer[cwords] & ~(FLAC__WORD_ALL_ONES >> end)) << cbits;
+ test eax, eax ; (still have to test since cbits may be 0, thus ZF not updated for shl eax,0)
+ jz .c1_next3 ; if(b) {
+ bsr ebx, eax
+ not ebx
+ and ebx, 31 ; ebx = 'i' = # of leading 0 bits in 'b' (eax)
+ add ecx, ebx ; cbits += i;
+ add edi, ebx ; uval += i;
+ add ecx, byte 1 ; cbits++; /* skip over stop bit */
+ jmp short .break1 ; goto break1;
+.c1_next3: ; } else {
+ sub edi, ecx
+ add edi, edx ; uval += end - cbits;
+ add ecx, edx ; cbits += end
+ ; /* didn't find stop bit yet, have to keep going... */
+ ; }
+ ; }
+.read1:
+ ; flush registers and read; bitreader_read_from_client_() does
+ ; not touch br->consumed_bits at all but we still need to set
+ ; it in case it fails and we have to return false.
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ mov [ebp + 16], esi ; br->consumed_words = cwords;
+ mov [ebp + 20], ecx ; br->consumed_bits = cbits;
+ push ecx ; /* save */
+ push ebp ; /* push br argument */
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ call _bitreader_read_from_client_
+%else
+ call bitreader_read_from_client_
+%endif
+ pop edx ; /* discard, unused */
+ pop ecx ; /* restore */
+ mov esi, [ebp + 16] ; cwords = br->consumed_words;
+ ; ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+ mov ebx, [ebp + 8] ; ebx <- br->words
+ sub ebx, esi ; ebx <- br->words-cwords
+ shl ebx, 2 ; ebx <- (br->words-cwords)*FLAC__BYTES_PER_WORD
+ add ebx, [ebp + 12] ; ebx <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
+ shl ebx, 3 ; ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
+ sub ebx, ecx ; ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
+ add ebx, edi ; ebx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits + uval
+ ; + uval to offset our count by the # of unary bits already
+ ; consumed before the read, because we will add these back
+ ; in all at once at break1
+ mov [esp], ebx ; ucbits <- ebx
+ test eax, eax ; if(!bitreader_read_from_client_(br))
+ jnz near .unary_loop
+ jmp .end ; return false; /* eax (the return value) is already 0 */
+ ; } /* end while(1) unary part */
+
+ ALIGN 16
+.break1:
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ ;; [esp] ucbits
+ sub [esp], edi ; ucbits -= uval;
+ sub dword [esp], byte 1 ; ucbits--; /* account for stop bit */
+
+ ;
+ ; read binary part
+ ;
+ mov ebx, [esp + 36] ; ebx <- parameter
+ test ebx, ebx ; if(parameter) {
+ jz near .break2
+.read2:
+ cmp [esp], ebx ; while(ucbits < parameter) {
+ jae .c2_next1
+ ; flush registers and read; bitreader_read_from_client_() does
+ ; not touch br->consumed_bits at all but we still need to set
+ ; it in case it fails and we have to return false.
+ mov [ebp + 16], esi ; br->consumed_words = cwords;
+ mov [ebp + 20], ecx ; br->consumed_bits = cbits;
+ push ecx ; /* save */
+ push ebp ; /* push br argument */
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ call _bitreader_read_from_client_
+%else
+ call bitreader_read_from_client_
+%endif
+ pop edx ; /* discard, unused */
+ pop ecx ; /* restore */
+ mov esi, [ebp + 16] ; cwords = br->consumed_words;
+ ; ucbits = (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits;
+ mov edx, [ebp + 8] ; edx <- br->words
+ sub edx, esi ; edx <- br->words-cwords
+ shl edx, 2 ; edx <- (br->words-cwords)*FLAC__BYTES_PER_WORD
+ add edx, [ebp + 12] ; edx <- (br->words-cwords)*FLAC__BYTES_PER_WORD + br->bytes
+ shl edx, 3 ; edx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8
+ sub edx, ecx ; edx <- (br->words-cwords)*FLAC__BITS_PER_WORD + br->bytes*8 - cbits
+ mov [esp], edx ; ucbits <- edx
+ test eax, eax ; if(!bitreader_read_from_client_(br))
+ jnz .read2
+ jmp .end ; return false; /* eax (the return value) is already 0 */
+ ; }
+.c2_next1:
+ ;; ebx parameter
+ ;; ecx cbits
+ ;; esi cwords
+ ;; edi uval
+ ;; ebp br
+ ;; [esp] ucbits
+ cmp esi, [ebp + 8] ; if(cwords < br->words) { /* if we've not consumed up to a partial tail word... */
+ jae near .c2_next2
+ test ecx, ecx ; if(cbits) {
+ jz near .c2_next3 ; /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ mov eax, 32
+ mov edx, [ebp]
+ sub eax, ecx ; const unsigned n = FLAC__BITS_PER_WORD - cbits;
+ mov edx, [edx + 4*esi] ; const brword word = br->buffer[cwords];
+ cmp ebx, eax ; if(parameter < n) {
+ jae .c2_next4
+ ; uval <<= parameter;
+ ; uval |= (word & (FLAC__WORD_ALL_ONES >> cbits)) >> (n-parameter);
+ shl edx, cl
+ xchg ebx, ecx
+ shld edi, edx, cl
+ add ebx, ecx ; cbits += parameter;
+ xchg ebx, ecx ; ebx <- parameter, ecx <- cbits
+ jmp .break2 ; goto break2;
+ ; }
+.c2_next4:
+ ; uval <<= n;
+ ; uval |= word & (FLAC__WORD_ALL_ONES >> cbits);
+%if 1
+ rol edx, cl ; @@@@@@OPT: may be faster to use rol to save edx so we can restore it for CRC'ing
+ ; @@@@@@OPT: or put parameter in ch instead and free up ebx completely again
+%else
+ shl edx, cl
+%endif
+ xchg eax, ecx
+ shld edi, edx, cl
+ xchg eax, ecx
+%if 1
+ ror edx, cl ; restored.
+%else
+ mov edx, [ebp]
+ mov edx, [edx + 4*esi]
+%endif
+ ; crc16_update_word_(br, br->buffer[cwords]);
+ push edi ; [need more registers]
+ push ebx ; [need more registers]
+ push eax ; [need more registers]
+ bswap edx ; edx = br->buffer[cwords] swapped; now we can CRC the bytes from LSByte to MSByte which makes things much easier
+ mov ecx, [ebp + 28] ; ecx <- br->crc16_align
+ mov eax, [ebp + 24] ; ax <- br->read_crc (a.k.a. crc)
+%ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ mov edi, _FLAC__crc16_table
+%else
+ mov edi, FLAC__crc16_table
+%endif
+ ;; eax (ax) crc a.k.a. br->read_crc
+ ;; ebx (bl) intermediate result index into FLAC__crc16_table[]
+ ;; ecx br->crc16_align
+ ;; edx byteswapped brword to CRC
+ ;; esi cwords
+ ;; edi unsigned FLAC__crc16_table[]
+ ;; ebp br
+ test ecx, ecx ; switch(br->crc16_align) ...
+ jnz .c2b4 ; [br->crc16_align is 0 the vast majority of the time so we optimize the common case]
+.c2b0: xor dl, ah ; dl <- (crc>>8)^(word>>24)
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word>>24)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word>>24)]
+.c2b1: xor dh, ah ; dh <- (crc>>8)^((word>>16)&0xff))
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>16)&0xff))]
+ shr edx, 16
+.c2b2: xor dl, ah ; dl <- (crc>>8)^((word>>8)&0xff))
+ movzx ebx, dl
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^((word>>8)&0xff))]
+.c2b3: xor dh, ah ; dh <- (crc>>8)^(word&0xff)
+ movzx ebx, dh
+ mov ecx, [ebx*4 + edi] ; cx <- FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ shl eax, 8 ; ax <- (crc<<8)
+ xor eax, ecx ; crc <- ax <- (crc<<8) ^ FLAC__crc16_table[(crc>>8)^(word&0xff)]
+ movzx eax, ax
+ mov [ebp + 24], eax ; br->read_crc <- crc
+ pop eax
+ pop ebx
+ pop edi
+ add esi, byte 1 ; cwords++;
+ mov ecx, ebx
+ sub ecx, eax ; cbits = parameter - n;
+ jz .break2 ; if(cbits) { /* parameter > n, i.e. if there are still bits left to read, there have to be less than 32 so they will all be in the next word */
+ ; uval <<= cbits;
+ ; uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits));
+ mov eax, [ebp]
+ mov eax, [eax + 4*esi]
+ shld edi, eax, cl
+ ; }
+ jmp .break2 ; goto break2;
+
+ ;; this section relocated out of the way for performance
+.c2b4:
+ mov [ebp + 28], dword 0 ; br->crc16_align <- 0
+ cmp ecx, 8
+ je .c2b1
+ shr edx, 16
+ cmp ecx, 16
+ je .c2b2
+ jmp .c2b3
+
+.c2_next3: ; } else {
+ mov ecx, ebx ; cbits = parameter;
+ ; uval <<= cbits;
+ ; uval |= (br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits));
+ mov eax, [ebp]
+ mov eax, [eax + 4*esi]
+ shld edi, eax, cl
+ jmp .break2 ; goto break2;
+ ; }
+.c2_next2: ; } else {
+ ; in this case we're starting our read at a partial tail word;
+ ; the reader has guaranteed that we have at least 'parameter'
+ ; bits available to read, which makes this case simpler.
+ ; uval <<= parameter;
+ ; if(cbits) {
+ ; /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */
+ ; uval |= (br->buffer[cwords] & (FLAC__WORD_ALL_ONES >> cbits)) >> (FLAC__BITS_PER_WORD-cbits-parameter);
+ ; cbits += parameter;
+ ; goto break2;
+ ; } else {
+ ; cbits = parameter;
+ ; uval |= br->buffer[cwords] >> (FLAC__BITS_PER_WORD-cbits);
+ ; goto break2;
+ ; }
+ ; the above is much shorter in assembly:
+ mov eax, [ebp]
+ mov eax, [eax + 4*esi] ; eax <- br->buffer[cwords]
+ shl eax, cl ; eax <- br->buffer[cwords] << cbits
+ add ecx, ebx ; cbits += parameter
+ xchg ebx, ecx ; ebx <- cbits, ecx <- parameter
+ shld edi, eax, cl ; uval <<= parameter <<< 'parameter' bits of tail word
+ xchg ebx, ecx ; ebx <- parameter, ecx <- cbits
+ ; }
+ ; }
+.break2:
+ sub [esp], ebx ; ucbits -= parameter;
+
+ ;
+ ; compose the value
+ ;
+ mov ebx, [esp + 28] ; ebx <- vals
+ mov edx, edi ; edx <- uval
+ and edi, 1 ; edi <- uval & 1
+ shr edx, 1 ; edx <- uval >> 1
+ neg edi ; edi <- -(int)(uval & 1)
+ xor edx, edi ; edx <- (uval >> 1 ^ -(int)(uval & 1))
+ mov [ebx], edx ; *vals <- edx
+ sub dword [esp + 32], byte 1 ; --nvals;
+ jz .finished ; if(nvals == 0) /* jump to finish */
+ xor edi, edi ; uval = 0;
+ add dword [esp + 28], 4 ; ++vals
+ jmp .val_loop ; }
+
+.finished:
+ mov [ebp + 16], esi ; br->consumed_words = cwords;
+ mov [ebp + 20], ecx ; br->consumed_bits = cbits;
+ mov eax, 1
+.end:
+ add esp, 4
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+ section .note.GNU-stack noalloc
+%endif
diff --git a/src/FLAC/src/libFLAC/ia32/cpu_asm.nasm b/src/FLAC/src/libFLAC/ia32/cpu_asm.nasm
new file mode 100644
index 0000000..f5eb110
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ia32/cpu_asm.nasm
@@ -0,0 +1,121 @@
+; vim:filetype=nasm ts=8
+
+; libFLAC - Free Lossless Audio Codec library
+; Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+;
+; 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 "nasm.h"
+
+ data_section
+
+cglobal FLAC__cpu_have_cpuid_asm_ia32
+cglobal FLAC__cpu_info_asm_ia32
+cglobal FLAC__cpu_info_extended_amd_asm_ia32
+
+ code_section
+
+; **********************************************************************
+;
+; FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32()
+;
+
+cident FLAC__cpu_have_cpuid_asm_ia32
+ push ebx
+ pushfd
+ pop eax
+ mov edx, eax
+ xor eax, 0x00200000
+ push eax
+ popfd
+ pushfd
+ pop eax
+ cmp eax, edx
+ jz .no_cpuid
+ mov eax, 1
+ jmp .end
+.no_cpuid:
+ xor eax, eax
+.end:
+ pop ebx
+ ret
+
+; **********************************************************************
+;
+; void FLAC__cpu_info_asm_ia32(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx)
+;
+
+cident FLAC__cpu_info_asm_ia32
+ ;[esp + 8] == flags_edx
+ ;[esp + 12] == flags_ecx
+
+ push ebx
+ call FLAC__cpu_have_cpuid_asm_ia32
+ test eax, eax
+ jz .no_cpuid
+ mov eax, 1
+ cpuid
+ mov ebx, [esp + 8]
+ mov [ebx], edx
+ mov ebx, [esp + 12]
+ mov [ebx], ecx
+ jmp .end
+.no_cpuid
+ xor eax, eax
+ mov ebx, [esp + 8]
+ mov [ebx], eax
+ mov ebx, [esp + 12]
+ mov [ebx], eax
+.end
+ pop ebx
+ ret
+
+cident FLAC__cpu_info_extended_amd_asm_ia32
+ push ebx
+ call FLAC__cpu_have_cpuid_asm_ia32
+ test eax, eax
+ jz .no_cpuid
+ mov eax, 0x80000000
+ cpuid
+ cmp eax, 0x80000001
+ jb .no_cpuid
+ mov eax, 0x80000001
+ cpuid
+ mov eax, edx
+ jmp .end
+.no_cpuid
+ xor eax, eax
+.end
+ pop ebx
+ ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+ section .note.GNU-stack noalloc
+%endif
diff --git a/src/FLAC/src/libFLAC/ia32/fixed_asm.nasm b/src/FLAC/src/libFLAC/ia32/fixed_asm.nasm
new file mode 100644
index 0000000..0185f4d
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ia32/fixed_asm.nasm
@@ -0,0 +1,312 @@
+; vim:filetype=nasm ts=8
+
+; libFLAC - Free Lossless Audio Codec library
+; Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+;
+; 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 "nasm.h"
+
+ data_section
+
+cglobal FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov
+
+ code_section
+
+; **********************************************************************
+;
+; unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 *data, unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1])
+; {
+; FLAC__int32 last_error_0 = data[-1];
+; FLAC__int32 last_error_1 = data[-1] - data[-2];
+; FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]);
+; FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]);
+; FLAC__int32 error, save;
+; FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0;
+; unsigned i, order;
+;
+; for(i = 0; i < data_len; i++) {
+; error = data[i] ; total_error_0 += local_abs(error); save = error;
+; error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error;
+; error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error;
+; error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error;
+; error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save;
+; }
+;
+; if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+; order = 0;
+; else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+; order = 1;
+; else if(total_error_2 < min(total_error_3, total_error_4))
+; order = 2;
+; else if(total_error_3 < total_error_4)
+; order = 3;
+; else
+; order = 4;
+;
+; residual_bits_per_sample[0] = (FLAC__float)((data_len > 0 && total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+; residual_bits_per_sample[1] = (FLAC__float)((data_len > 0 && total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+; residual_bits_per_sample[2] = (FLAC__float)((data_len > 0 && total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+; residual_bits_per_sample[3] = (FLAC__float)((data_len > 0 && total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+; residual_bits_per_sample[4] = (FLAC__float)((data_len > 0 && total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+;
+; return order;
+; }
+ ALIGN 16
+cident FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov
+
+ ; esp + 36 == data[]
+ ; esp + 40 == data_len
+ ; esp + 44 == residual_bits_per_sample[]
+
+ push ebp
+ push ebx
+ push esi
+ push edi
+ sub esp, byte 16
+ ; qword [esp] == temp space for loading FLAC__uint64s to FPU regs
+
+ ; ebx == &data[i]
+ ; ecx == loop counter (i)
+ ; ebp == order
+ ; mm0 == total_error_1:total_error_0
+ ; mm1 == total_error_2:total_error_3
+ ; mm2 == :total_error_4
+ ; mm3 == last_error_1:last_error_0
+ ; mm4 == last_error_2:last_error_3
+
+ mov ecx, [esp + 40] ; ecx = data_len
+ test ecx, ecx
+ jz near .data_len_is_0
+
+ mov ebx, [esp + 36] ; ebx = data[]
+ movd mm3, [ebx - 4] ; mm3 = 0:last_error_0
+ movd mm2, [ebx - 8] ; mm2 = 0:data[-2]
+ movd mm1, [ebx - 12] ; mm1 = 0:data[-3]
+ movd mm0, [ebx - 16] ; mm0 = 0:data[-4]
+ movq mm5, mm3 ; mm5 = 0:last_error_0
+ psubd mm5, mm2 ; mm5 = 0:last_error_1
+ punpckldq mm3, mm5 ; mm3 = last_error_1:last_error_0
+ psubd mm2, mm1 ; mm2 = 0:data[-2] - data[-3]
+ psubd mm5, mm2 ; mm5 = 0:last_error_2
+ movq mm4, mm5 ; mm4 = 0:last_error_2
+ psubd mm4, mm2 ; mm4 = 0:last_error_2 - (data[-2] - data[-3])
+ paddd mm4, mm1 ; mm4 = 0:last_error_2 - (data[-2] - 2 * data[-3])
+ psubd mm4, mm0 ; mm4 = 0:last_error_3
+ punpckldq mm4, mm5 ; mm4 = last_error_2:last_error_3
+ pxor mm0, mm0 ; mm0 = total_error_1:total_error_0
+ pxor mm1, mm1 ; mm1 = total_error_2:total_error_3
+ pxor mm2, mm2 ; mm2 = 0:total_error_4
+
+ ALIGN 16
+.loop:
+ movd mm7, [ebx] ; mm7 = 0:error_0
+ add ebx, byte 4
+ movq mm6, mm7 ; mm6 = 0:error_0
+ psubd mm7, mm3 ; mm7 = :error_1
+ punpckldq mm6, mm7 ; mm6 = error_1:error_0
+ movq mm5, mm6 ; mm5 = error_1:error_0
+ movq mm7, mm6 ; mm7 = error_1:error_0
+ psubd mm5, mm3 ; mm5 = error_2:
+ movq mm3, mm6 ; mm3 = error_1:error_0
+ psrad mm6, 31
+ pxor mm7, mm6
+ psubd mm7, mm6 ; mm7 = abs(error_1):abs(error_0)
+ paddd mm0, mm7 ; mm0 = total_error_1:total_error_0
+ movq mm6, mm5 ; mm6 = error_2:
+ psubd mm5, mm4 ; mm5 = error_3:
+ punpckhdq mm5, mm6 ; mm5 = error_2:error_3
+ movq mm7, mm5 ; mm7 = error_2:error_3
+ movq mm6, mm5 ; mm6 = error_2:error_3
+ psubd mm5, mm4 ; mm5 = :error_4
+ movq mm4, mm6 ; mm4 = error_2:error_3
+ psrad mm6, 31
+ pxor mm7, mm6
+ psubd mm7, mm6 ; mm7 = abs(error_2):abs(error_3)
+ paddd mm1, mm7 ; mm1 = total_error_2:total_error_3
+ movq mm6, mm5 ; mm6 = :error_4
+ psrad mm5, 31
+ pxor mm6, mm5
+ psubd mm6, mm5 ; mm6 = :abs(error_4)
+ paddd mm2, mm6 ; mm2 = :total_error_4
+
+ dec ecx
+ jnz short .loop
+
+; if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4))
+; order = 0;
+; else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4))
+; order = 1;
+; else if(total_error_2 < min(total_error_3, total_error_4))
+; order = 2;
+; else if(total_error_3 < total_error_4)
+; order = 3;
+; else
+; order = 4;
+ movq mm3, mm0 ; mm3 = total_error_1:total_error_0
+ movd edi, mm2 ; edi = total_error_4
+ movd esi, mm1 ; esi = total_error_3
+ movd eax, mm0 ; eax = total_error_0
+ punpckhdq mm1, mm1 ; mm1 = total_error_2:total_error_2
+ punpckhdq mm3, mm3 ; mm3 = total_error_1:total_error_1
+ movd edx, mm1 ; edx = total_error_2
+ movd ecx, mm3 ; ecx = total_error_1
+
+ xor ebx, ebx
+ xor ebp, ebp
+ inc ebx
+ cmp ecx, eax
+ cmovb eax, ecx ; eax = min(total_error_0, total_error_1)
+ cmovbe ebp, ebx
+ inc ebx
+ cmp edx, eax
+ cmovb eax, edx ; eax = min(total_error_0, total_error_1, total_error_2)
+ cmovbe ebp, ebx
+ inc ebx
+ cmp esi, eax
+ cmovb eax, esi ; eax = min(total_error_0, total_error_1, total_error_2, total_error_3)
+ cmovbe ebp, ebx
+ inc ebx
+ cmp edi, eax
+ cmovb eax, edi ; eax = min(total_error_0, total_error_1, total_error_2, total_error_3, total_error_4)
+ cmovbe ebp, ebx
+ movd ebx, mm0 ; ebx = total_error_0
+ emms
+
+ ; residual_bits_per_sample[0] = (FLAC__float)((data_len > 0 && total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ ; residual_bits_per_sample[1] = (FLAC__float)((data_len > 0 && total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ ; residual_bits_per_sample[2] = (FLAC__float)((data_len > 0 && total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ ; residual_bits_per_sample[3] = (FLAC__float)((data_len > 0 && total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ ; residual_bits_per_sample[4] = (FLAC__float)((data_len > 0 && total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0);
+ xor eax, eax
+ fild dword [esp + 40] ; ST = data_len (NOTE: assumes data_len is <2gigs)
+.rbps_0:
+ test ebx, ebx
+ jz .total_error_0_is_0
+ fld1 ; ST = 1.0 data_len
+ mov [esp], ebx
+ mov [esp + 4], eax ; [esp] = (FLAC__uint64)total_error_0
+ mov ebx, [esp + 44]
+ fild qword [esp] ; ST = total_error_0 1.0 data_len
+ fdiv st2 ; ST = total_error_0/data_len 1.0 data_len
+ fldln2 ; ST = ln2 total_error_0/data_len 1.0 data_len
+ fmulp st1 ; ST = ln2*total_error_0/data_len 1.0 data_len
+ fyl2x ; ST = log2(ln2*total_error_0/data_len) data_len
+ fstp dword [ebx] ; residual_bits_per_sample[0] = log2(ln2*total_error_0/data_len) ST = data_len
+ jmp short .rbps_1
+.total_error_0_is_0:
+ mov ebx, [esp + 44]
+ mov [ebx], eax ; residual_bits_per_sample[0] = 0.0
+.rbps_1:
+ test ecx, ecx
+ jz .total_error_1_is_0
+ fld1 ; ST = 1.0 data_len
+ mov [esp], ecx
+ mov [esp + 4], eax ; [esp] = (FLAC__uint64)total_error_1
+ fild qword [esp] ; ST = total_error_1 1.0 data_len
+ fdiv st2 ; ST = total_error_1/data_len 1.0 data_len
+ fldln2 ; ST = ln2 total_error_1/data_len 1.0 data_len
+ fmulp st1 ; ST = ln2*total_error_1/data_len 1.0 data_len
+ fyl2x ; ST = log2(ln2*total_error_1/data_len) data_len
+ fstp dword [ebx + 4] ; residual_bits_per_sample[1] = log2(ln2*total_error_1/data_len) ST = data_len
+ jmp short .rbps_2
+.total_error_1_is_0:
+ mov [ebx + 4], eax ; residual_bits_per_sample[1] = 0.0
+.rbps_2:
+ test edx, edx
+ jz .total_error_2_is_0
+ fld1 ; ST = 1.0 data_len
+ mov [esp], edx
+ mov [esp + 4], eax ; [esp] = (FLAC__uint64)total_error_2
+ fild qword [esp] ; ST = total_error_2 1.0 data_len
+ fdiv st2 ; ST = total_error_2/data_len 1.0 data_len
+ fldln2 ; ST = ln2 total_error_2/data_len 1.0 data_len
+ fmulp st1 ; ST = ln2*total_error_2/data_len 1.0 data_len
+ fyl2x ; ST = log2(ln2*total_error_2/data_len) data_len
+ fstp dword [ebx + 8] ; residual_bits_per_sample[2] = log2(ln2*total_error_2/data_len) ST = data_len
+ jmp short .rbps_3
+.total_error_2_is_0:
+ mov [ebx + 8], eax ; residual_bits_per_sample[2] = 0.0
+.rbps_3:
+ test esi, esi
+ jz .total_error_3_is_0
+ fld1 ; ST = 1.0 data_len
+ mov [esp], esi
+ mov [esp + 4], eax ; [esp] = (FLAC__uint64)total_error_3
+ fild qword [esp] ; ST = total_error_3 1.0 data_len
+ fdiv st2 ; ST = total_error_3/data_len 1.0 data_len
+ fldln2 ; ST = ln2 total_error_3/data_len 1.0 data_len
+ fmulp st1 ; ST = ln2*total_error_3/data_len 1.0 data_len
+ fyl2x ; ST = log2(ln2*total_error_3/data_len) data_len
+ fstp dword [ebx + 12] ; residual_bits_per_sample[3] = log2(ln2*total_error_3/data_len) ST = data_len
+ jmp short .rbps_4
+.total_error_3_is_0:
+ mov [ebx + 12], eax ; residual_bits_per_sample[3] = 0.0
+.rbps_4:
+ test edi, edi
+ jz .total_error_4_is_0
+ fld1 ; ST = 1.0 data_len
+ mov [esp], edi
+ mov [esp + 4], eax ; [esp] = (FLAC__uint64)total_error_4
+ fild qword [esp] ; ST = total_error_4 1.0 data_len
+ fdiv st2 ; ST = total_error_4/data_len 1.0 data_len
+ fldln2 ; ST = ln2 total_error_4/data_len 1.0 data_len
+ fmulp st1 ; ST = ln2*total_error_4/data_len 1.0 data_len
+ fyl2x ; ST = log2(ln2*total_error_4/data_len) data_len
+ fstp dword [ebx + 16] ; residual_bits_per_sample[4] = log2(ln2*total_error_4/data_len) ST = data_len
+ jmp short .rbps_end
+.total_error_4_is_0:
+ mov [ebx + 16], eax ; residual_bits_per_sample[4] = 0.0
+.rbps_end:
+ fstp st0 ; ST = [empty]
+ jmp short .end
+.data_len_is_0:
+ ; data_len == 0, so residual_bits_per_sample[*] = 0.0
+ xor ebp, ebp
+ mov edi, [esp + 44]
+ mov [edi], ebp
+ mov [edi + 4], ebp
+ mov [edi + 8], ebp
+ mov [edi + 12], ebp
+ mov [edi + 16], ebp
+ add ebp, byte 4 ; order = 4
+
+.end:
+ mov eax, ebp ; return order
+ add esp, byte 16
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+ section .note.GNU-stack noalloc
+%endif
diff --git a/src/FLAC/src/libFLAC/ia32/lpc_asm-unrolled.nasm b/src/FLAC/src/libFLAC/ia32/lpc_asm-unrolled.nasm
new file mode 100644
index 0000000..c0eab41
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ia32/lpc_asm-unrolled.nasm
@@ -0,0 +1,784 @@
+; vim:filetype=nasm ts=8
+
+; libFLAC - Free Lossless Audio Codec library
+; Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+;
+; 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.
+
+; [CR] is a note to flag that the instruction can be easily reordered
+
+%include "nasm.h"
+
+ data_section
+
+cglobal FLAC__lpc_compute_autocorrelation_asm
+
+ code_section
+
+; **********************************************************************
+;
+; void FLAC__lpc_compute_autocorrelation_asm(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
+; {
+; FLAC__real d;
+; unsigned sample, coeff;
+; const unsigned limit = data_len - lag;
+;
+; assert(lag > 0);
+; assert(lag <= data_len);
+;
+; for(coeff = 0; coeff < lag; coeff++)
+; autoc[coeff] = 0.0;
+; for(sample = 0; sample <= limit; sample++){
+; d = data[sample];
+; for(coeff = 0; coeff < lag; coeff++)
+; autoc[coeff] += d * data[sample+coeff];
+; }
+; for(; sample < data_len; sample++){
+; d = data[sample];
+; for(coeff = 0; coeff < data_len - sample; coeff++)
+; autoc[coeff] += d * data[sample+coeff];
+; }
+; }
+;
+FLAC__lpc_compute_autocorrelation_asm:
+
+ push ebp
+ lea ebp, [esp + 8]
+ push ebx
+ push esi
+ push edi
+
+ mov edx, [ebp + 8] ; edx == lag
+ mov ecx, [ebp + 4] ; ecx == data_len
+ mov esi, [ebp] ; esi == data
+ mov edi, [ebp + 12] ; edi == autoc
+
+ cmp edx, 1
+ ja short .lag_above_1
+.lag_eq_1:
+ fldz ; will accumulate autoc[0]
+ ALIGN 16
+.lag_1_loop:
+ fld dword [esi]
+ add esi, byte 4 ; sample++
+ fmul st0, st0
+ faddp st1, st0
+ dec ecx
+ jnz .lag_1_loop
+ fstp dword [edi]
+ jmp .end
+
+.lag_above_1:
+ cmp edx, 2
+ ja short .lag_above_2
+.lag_eq_2:
+ fldz ; will accumulate autoc[1]
+ dec ecx
+ fldz ; will accumulate autoc[0]
+ fld dword [esi]
+ ALIGN 16
+.lag_2_loop:
+ add esi, byte 4 ; [CR] sample++
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi]
+ fmul st1, st0
+ fxch
+ faddp st3, st0 ; add to autoc[1]
+ dec ecx
+ jnz .lag_2_loop
+ ; clean up the leftovers
+ fmul st0, st0
+ faddp st1, st0 ; add to autoc[0]
+ fstp dword [edi]
+ fstp dword [edi + 4]
+ jmp .end
+
+.lag_above_2:
+ cmp edx, 3
+ ja short .lag_above_3
+.lag_eq_3:
+ fldz ; will accumulate autoc[2]
+ dec ecx
+ fldz ; will accumulate autoc[1]
+ dec ecx
+ fldz ; will accumulate autoc[0]
+ ALIGN 16
+.lag_3_loop:
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[1]
+ fld dword [esi + 8]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st3, st0 ; add to autoc[2]
+ dec ecx
+ jnz .lag_3_loop
+ ; clean up the leftovers
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st1, st0
+ fxch
+ faddp st3, st0 ; add to autoc[1]
+ fmul st0, st0
+ faddp st1, st0 ; add to autoc[0]
+ fstp dword [edi]
+ fstp dword [edi + 4]
+ fstp dword [edi + 8]
+ jmp .end
+
+.lag_above_3:
+ cmp edx, 4
+ ja near .lag_above_4
+.lag_eq_4:
+ fldz ; will accumulate autoc[3]
+ dec ecx
+ fldz ; will accumulate autoc[2]
+ dec ecx
+ fldz ; will accumulate autoc[1]
+ dec ecx
+ fldz ; will accumulate autoc[0]
+ ALIGN 16
+.lag_4_loop:
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[1]
+ fld dword [esi + 8]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[2]
+ fld dword [esi + 12]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st4, st0 ; add to autoc[3]
+ dec ecx
+ jnz .lag_4_loop
+ ; clean up the leftovers
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[1]
+ fld dword [esi + 8]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st3, st0 ; add to autoc[2]
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st1, st0
+ fxch
+ faddp st3, st0 ; add to autoc[1]
+ fmul st0, st0
+ faddp st1, st0 ; add to autoc[0]
+ fstp dword [edi]
+ fstp dword [edi + 4]
+ fstp dword [edi + 8]
+ fstp dword [edi + 12]
+ jmp .end
+
+.lag_above_4:
+ cmp edx, 5
+ ja near .lag_above_5
+.lag_eq_5:
+ fldz ; will accumulate autoc[4]
+ fldz ; will accumulate autoc[3]
+ fldz ; will accumulate autoc[2]
+ fldz ; will accumulate autoc[1]
+ fldz ; will accumulate autoc[0]
+ sub ecx, byte 4
+ ALIGN 16
+.lag_5_loop:
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[1]
+ fld dword [esi + 8]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[2]
+ fld dword [esi + 12]
+ fmul st0, st1
+ faddp st5, st0 ; add to autoc[3]
+ fld dword [esi + 16]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st5, st0 ; add to autoc[4]
+ dec ecx
+ jnz .lag_5_loop
+ ; clean up the leftovers
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[1]
+ fld dword [esi + 8]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[2]
+ fld dword [esi + 12]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st4, st0 ; add to autoc[3]
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[1]
+ fld dword [esi + 8]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st3, st0 ; add to autoc[2]
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st1, st0
+ fxch
+ faddp st3, st0 ; add to autoc[1]
+ fmul st0, st0
+ faddp st1, st0 ; add to autoc[0]
+ fstp dword [edi]
+ fstp dword [edi + 4]
+ fstp dword [edi + 8]
+ fstp dword [edi + 12]
+ fstp dword [edi + 16]
+ jmp .end
+
+.lag_above_5:
+ cmp edx, 6
+ ja .lag_above_6
+.lag_eq_6:
+ fldz ; will accumulate autoc[5]
+ fldz ; will accumulate autoc[4]
+ fldz ; will accumulate autoc[3]
+ fldz ; will accumulate autoc[2]
+ fldz ; will accumulate autoc[1]
+ fldz ; will accumulate autoc[0]
+ sub ecx, byte 5
+ ALIGN 16
+.lag_6_loop:
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[1]
+ fld dword [esi + 8]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[2]
+ fld dword [esi + 12]
+ fmul st0, st1
+ faddp st5, st0 ; add to autoc[3]
+ fld dword [esi + 16]
+ fmul st0, st1
+ faddp st6, st0 ; add to autoc[4]
+ fld dword [esi + 20]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st6, st0 ; add to autoc[5]
+ dec ecx
+ jnz .lag_6_loop
+ ; clean up the leftovers
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[1]
+ fld dword [esi + 8]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[2]
+ fld dword [esi + 12]
+ fmul st0, st1
+ faddp st5, st0 ; add to autoc[3]
+ fld dword [esi + 16]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st5, st0 ; add to autoc[4]
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[1]
+ fld dword [esi + 8]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[2]
+ fld dword [esi + 12]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st4, st0 ; add to autoc[3]
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[1]
+ fld dword [esi + 8]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st3, st0 ; add to autoc[2]
+ fld dword [esi]
+ fld st0
+ fmul st0, st0
+ faddp st2, st0 ; add to autoc[0]
+ fld dword [esi + 4]
+ fmul st1, st0
+ fxch
+ faddp st3, st0 ; add to autoc[1]
+ fmul st0, st0
+ faddp st1, st0 ; add to autoc[0]
+ fstp dword [edi]
+ fstp dword [edi + 4]
+ fstp dword [edi + 8]
+ fstp dword [edi + 12]
+ fstp dword [edi + 16]
+ fstp dword [edi + 20]
+ jmp .end
+
+.lag_above_6:
+ ; for(coeff = 0; coeff < lag; coeff++)
+ ; autoc[coeff] = 0.0;
+ lea ecx, [edx * 2] ; ecx = # of dwords of 0 to write
+ xor eax, eax
+ rep stosd
+ mov ecx, [ebp + 4] ; ecx == data_len
+ mov edi, [ebp + 12] ; edi == autoc
+ ; const unsigned limit = data_len - lag;
+ sub ecx, edx
+ inc ecx ; we are looping <= limit so we add one to the counter
+ ; for(sample = 0; sample <= limit; sample++){
+ ; d = data[sample];
+ ; for(coeff = 0; coeff < lag; coeff++)
+ ; autoc[coeff] += d * data[sample+coeff];
+ ; }
+ xor eax, eax ; eax == sample <- 0
+ ALIGN 16
+.outer_loop:
+ push eax ; save sample
+ fld dword [esi + eax * 4] ; ST = d <- data[sample]
+ mov ebx, eax ; ebx == sample+coeff <- sample
+ mov edx, [ebp + 8] ; edx <- lag
+ xor eax, eax ; eax == coeff <- 0
+ ALIGN 16
+.inner_loop:
+ fld st0 ; ST = d d
+ fmul dword [esi + ebx * 4] ; ST = d*data[sample+coeff] d
+ fadd dword [edi + eax * 4] ; ST = autoc[coeff]+d*data[sample+coeff] d
+ fstp dword [edi + eax * 4] ; autoc[coeff]+=d*data[sample+coeff] ST = d
+ inc ebx ; (sample+coeff)++
+ inc eax ; coeff++
+ dec edx
+ jnz .inner_loop
+ pop eax ; restore sample
+ fstp st0 ; pop d, ST = empty
+ inc eax ; sample++
+ loop .outer_loop
+ ; for(; sample < data_len; sample++){
+ ; d = data[sample];
+ ; for(coeff = 0; coeff < data_len - sample; coeff++)
+ ; autoc[coeff] += d * data[sample+coeff];
+ ; }
+ mov ecx, [ebp + 8] ; ecx <- lag
+ dec ecx ; ecx <- lag - 1
+ jz .outer_end ; skip loop if 0
+.outer_loop2:
+ push eax ; save sample
+ fld dword [esi + eax * 4] ; ST = d <- data[sample]
+ mov ebx, eax ; ebx == sample+coeff <- sample
+ mov edx, [ebp + 4] ; edx <- data_len
+ sub edx, eax ; edx <- data_len-sample
+ xor eax, eax ; eax == coeff <- 0
+.inner_loop2:
+ fld st0 ; ST = d d
+ fmul dword [esi + ebx * 4] ; ST = d*data[sample+coeff] d
+ fadd dword [edi + eax * 4] ; ST = autoc[coeff]+d*data[sample+coeff] d
+ fstp dword [edi + eax * 4] ; autoc[coeff]+=d*data[sample+coeff] ST = d
+ inc ebx ; (sample+coeff)++
+ inc eax ; coeff++
+ dec edx
+ jnz .inner_loop2
+ pop eax ; restore sample
+ fstp st0 ; pop d, ST = empty
+ inc eax ; sample++
+ loop .outer_loop2
+.outer_end:
+ jmp .end
+
+.lag_eq_6_plus_1:
+ mov ecx, [ebp + 4] ; ecx == data_len
+ mov esi, [ebp] ; esi == data
+ mov edi, [ebp + 12] ; edi == autoc
+ fldz ; will accumulate autoc[6]
+ sub ecx, byte 6
+ ALIGN 16
+.lag_6_1_loop:
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st1, st0 ; add to autoc[6]
+ dec ecx
+ jnz .lag_6_1_loop
+ fstp dword [edi + 24]
+ jmp .end
+
+.lag_eq_6_plus_2:
+ mov ecx, [ebp + 4] ; ecx == data_len
+ mov esi, [ebp] ; esi == data
+ mov edi, [ebp + 12] ; edi == autoc
+ fldz ; will accumulate autoc[7]
+ fldz ; will accumulate autoc[6]
+ sub ecx, byte 7
+ ALIGN 16
+.lag_6_2_loop:
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st2, st0 ; add to autoc[7]
+ dec ecx
+ jnz .lag_6_2_loop
+ ; clean up the leftovers
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmulp st1, st0
+ faddp st1, st0 ; add to autoc[6]
+ fstp dword [edi + 24]
+ fstp dword [edi + 28]
+ jmp .end
+
+.lag_eq_6_plus_3:
+ mov ecx, [ebp + 4] ; ecx == data_len
+ mov esi, [ebp] ; esi == data
+ mov edi, [ebp + 12] ; edi == autoc
+ fldz ; will accumulate autoc[8]
+ fldz ; will accumulate autoc[7]
+ fldz ; will accumulate autoc[6]
+ sub ecx, byte 8
+ ALIGN 16
+.lag_6_3_loop:
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[7]
+ fld dword [esi + 32]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st3, st0 ; add to autoc[8]
+ dec ecx
+ jnz .lag_6_3_loop
+ ; clean up the leftovers
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st2, st0 ; add to autoc[7]
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmulp st1, st0
+ faddp st1, st0 ; add to autoc[6]
+ fstp dword [edi + 24]
+ fstp dword [edi + 28]
+ fstp dword [edi + 32]
+ jmp .end
+
+.lag_eq_6_plus_4:
+ mov ecx, [ebp + 4] ; ecx == data_len
+ mov esi, [ebp] ; esi == data
+ mov edi, [ebp + 12] ; edi == autoc
+ fldz ; will accumulate autoc[9]
+ fldz ; will accumulate autoc[8]
+ fldz ; will accumulate autoc[7]
+ fldz ; will accumulate autoc[6]
+ sub ecx, byte 9
+ ALIGN 16
+.lag_6_4_loop:
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[7]
+ fld dword [esi + 32]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[8]
+ fld dword [esi + 36]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st4, st0 ; add to autoc[9]
+ dec ecx
+ jnz .lag_6_4_loop
+ ; clean up the leftovers
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[7]
+ fld dword [esi + 32]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st3, st0 ; add to autoc[8]
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st2, st0 ; add to autoc[7]
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmulp st1, st0
+ faddp st1, st0 ; add to autoc[6]
+ fstp dword [edi + 24]
+ fstp dword [edi + 28]
+ fstp dword [edi + 32]
+ fstp dword [edi + 36]
+ jmp .end
+
+.lag_eq_6_plus_5:
+ mov ecx, [ebp + 4] ; ecx == data_len
+ mov esi, [ebp] ; esi == data
+ mov edi, [ebp + 12] ; edi == autoc
+ fldz ; will accumulate autoc[10]
+ fldz ; will accumulate autoc[9]
+ fldz ; will accumulate autoc[8]
+ fldz ; will accumulate autoc[7]
+ fldz ; will accumulate autoc[6]
+ sub ecx, byte 10
+ ALIGN 16
+.lag_6_5_loop:
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[7]
+ fld dword [esi + 32]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[8]
+ fld dword [esi + 36]
+ fmul st0, st1
+ faddp st5, st0 ; add to autoc[9]
+ fld dword [esi + 40]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st5, st0 ; add to autoc[10]
+ dec ecx
+ jnz .lag_6_5_loop
+ ; clean up the leftovers
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[7]
+ fld dword [esi + 32]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[8]
+ fld dword [esi + 36]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st4, st0 ; add to autoc[9]
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[7]
+ fld dword [esi + 32]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st3, st0 ; add to autoc[8]
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st2, st0 ; add to autoc[7]
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmulp st1, st0
+ faddp st1, st0 ; add to autoc[6]
+ fstp dword [edi + 24]
+ fstp dword [edi + 28]
+ fstp dword [edi + 32]
+ fstp dword [edi + 36]
+ fstp dword [edi + 40]
+ jmp .end
+
+.lag_eq_6_plus_6:
+ mov ecx, [ebp + 4] ; ecx == data_len
+ mov esi, [ebp] ; esi == data
+ mov edi, [ebp + 12] ; edi == autoc
+ fldz ; will accumulate autoc[11]
+ fldz ; will accumulate autoc[10]
+ fldz ; will accumulate autoc[9]
+ fldz ; will accumulate autoc[8]
+ fldz ; will accumulate autoc[7]
+ fldz ; will accumulate autoc[6]
+ sub ecx, byte 11
+ ALIGN 16
+.lag_6_6_loop:
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[7]
+ fld dword [esi + 32]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[8]
+ fld dword [esi + 36]
+ fmul st0, st1
+ faddp st5, st0 ; add to autoc[9]
+ fld dword [esi + 40]
+ fmul st0, st1
+ faddp st6, st0 ; add to autoc[10]
+ fld dword [esi + 44]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st6, st0 ; add to autoc[11]
+ dec ecx
+ jnz .lag_6_6_loop
+ ; clean up the leftovers
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[7]
+ fld dword [esi + 32]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[8]
+ fld dword [esi + 36]
+ fmul st0, st1
+ faddp st5, st0 ; add to autoc[9]
+ fld dword [esi + 40]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st5, st0 ; add to autoc[10]
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[7]
+ fld dword [esi + 32]
+ fmul st0, st1
+ faddp st4, st0 ; add to autoc[8]
+ fld dword [esi + 36]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st4, st0 ; add to autoc[9]
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmul st0, st1
+ faddp st3, st0 ; add to autoc[7]
+ fld dword [esi + 32]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st3, st0 ; add to autoc[8]
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmul st0, st1
+ faddp st2, st0 ; add to autoc[6]
+ fld dword [esi + 28]
+ fmulp st1, st0
+ add esi, byte 4 ; [CR] sample++
+ faddp st2, st0 ; add to autoc[7]
+ fld dword [esi]
+ fld dword [esi + 24]
+ fmulp st1, st0
+ faddp st1, st0 ; add to autoc[6]
+ fstp dword [edi + 24]
+ fstp dword [edi + 28]
+ fstp dword [edi + 32]
+ fstp dword [edi + 36]
+ fstp dword [edi + 40]
+ fstp dword [edi + 44]
+ jmp .end
+
+.end:
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+end
diff --git a/src/FLAC/src/libFLAC/ia32/lpc_asm.nasm b/src/FLAC/src/libFLAC/ia32/lpc_asm.nasm
new file mode 100644
index 0000000..4bc4c91
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ia32/lpc_asm.nasm
@@ -0,0 +1,1511 @@
+; vim:filetype=nasm ts=8
+
+; libFLAC - Free Lossless Audio Codec library
+; Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+;
+; 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 "nasm.h"
+
+ data_section
+
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12
+cglobal FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow
+cglobal FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32
+cglobal FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx
+cglobal FLAC__lpc_restore_signal_asm_ia32
+cglobal FLAC__lpc_restore_signal_asm_ia32_mmx
+
+ code_section
+
+; **********************************************************************
+;
+; void FLAC__lpc_compute_autocorrelation_asm(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
+; {
+; FLAC__real d;
+; unsigned sample, coeff;
+; const unsigned limit = data_len - lag;
+;
+; FLAC__ASSERT(lag > 0);
+; FLAC__ASSERT(lag <= data_len);
+;
+; for(coeff = 0; coeff < lag; coeff++)
+; autoc[coeff] = 0.0;
+; for(sample = 0; sample <= limit; sample++) {
+; d = data[sample];
+; for(coeff = 0; coeff < lag; coeff++)
+; autoc[coeff] += d * data[sample+coeff];
+; }
+; for(; sample < data_len; sample++) {
+; d = data[sample];
+; for(coeff = 0; coeff < data_len - sample; coeff++)
+; autoc[coeff] += d * data[sample+coeff];
+; }
+; }
+;
+ ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32
+ ;[esp + 28] == autoc[]
+ ;[esp + 24] == lag
+ ;[esp + 20] == data_len
+ ;[esp + 16] == data[]
+
+ ;ASSERT(lag > 0)
+ ;ASSERT(lag <= 33)
+ ;ASSERT(lag <= data_len)
+
+.begin:
+ push esi
+ push edi
+ push ebx
+
+ ; for(coeff = 0; coeff < lag; coeff++)
+ ; autoc[coeff] = 0.0;
+ mov edi, [esp + 28] ; edi == autoc
+ mov ecx, [esp + 24] ; ecx = # of dwords (=lag) of 0 to write
+ xor eax, eax
+ rep stosd
+
+ ; const unsigned limit = data_len - lag;
+ mov eax, [esp + 24] ; eax == lag
+ mov ecx, [esp + 20]
+ sub ecx, eax ; ecx == limit
+
+ mov edi, [esp + 28] ; edi == autoc
+ mov esi, [esp + 16] ; esi == data
+ inc ecx ; we are looping <= limit so we add one to the counter
+
+ ; for(sample = 0; sample <= limit; sample++) {
+ ; d = data[sample];
+ ; for(coeff = 0; coeff < lag; coeff++)
+ ; autoc[coeff] += d * data[sample+coeff];
+ ; }
+ fld dword [esi] ; ST = d <- data[sample]
+ ; each iteration is 11 bytes so we need (-eax)*11, so we do (-12*eax + eax)
+ lea edx, [eax + eax*2]
+ neg edx
+ lea edx, [eax + edx*4 + .jumper1_0 - .get_eip1]
+ call .get_eip1
+.get_eip1:
+ pop ebx
+ add edx, ebx
+ inc edx ; compensate for the shorter opcode on the last iteration
+ inc edx ; compensate for the shorter opcode on the last iteration
+ inc edx ; compensate for the shorter opcode on the last iteration
+ cmp eax, 33
+ jne .loop1_start
+ sub edx, byte 9 ; compensate for the longer opcodes on the first iteration
+.loop1_start:
+ jmp edx
+
+ fld st0 ; ST = d d
+ fmul dword [esi + (32*4)] ; ST = d*data[sample+32] d WATCHOUT: not a byte displacement here!
+ fadd dword [edi + (32*4)] ; ST = autoc[32]+d*data[sample+32] d WATCHOUT: not a byte displacement here!
+ fstp dword [edi + (32*4)] ; autoc[32]+=d*data[sample+32] ST = d WATCHOUT: not a byte displacement here!
+ fld st0 ; ST = d d
+ fmul dword [esi + (31*4)] ; ST = d*data[sample+31] d
+ fadd dword [edi + (31*4)] ; ST = autoc[31]+d*data[sample+31] d
+ fstp dword [edi + (31*4)] ; autoc[31]+=d*data[sample+31] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (30*4)] ; ST = d*data[sample+30] d
+ fadd dword [edi + (30*4)] ; ST = autoc[30]+d*data[sample+30] d
+ fstp dword [edi + (30*4)] ; autoc[30]+=d*data[sample+30] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (29*4)] ; ST = d*data[sample+29] d
+ fadd dword [edi + (29*4)] ; ST = autoc[29]+d*data[sample+29] d
+ fstp dword [edi + (29*4)] ; autoc[29]+=d*data[sample+29] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (28*4)] ; ST = d*data[sample+28] d
+ fadd dword [edi + (28*4)] ; ST = autoc[28]+d*data[sample+28] d
+ fstp dword [edi + (28*4)] ; autoc[28]+=d*data[sample+28] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (27*4)] ; ST = d*data[sample+27] d
+ fadd dword [edi + (27*4)] ; ST = autoc[27]+d*data[sample+27] d
+ fstp dword [edi + (27*4)] ; autoc[27]+=d*data[sample+27] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (26*4)] ; ST = d*data[sample+26] d
+ fadd dword [edi + (26*4)] ; ST = autoc[26]+d*data[sample+26] d
+ fstp dword [edi + (26*4)] ; autoc[26]+=d*data[sample+26] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (25*4)] ; ST = d*data[sample+25] d
+ fadd dword [edi + (25*4)] ; ST = autoc[25]+d*data[sample+25] d
+ fstp dword [edi + (25*4)] ; autoc[25]+=d*data[sample+25] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (24*4)] ; ST = d*data[sample+24] d
+ fadd dword [edi + (24*4)] ; ST = autoc[24]+d*data[sample+24] d
+ fstp dword [edi + (24*4)] ; autoc[24]+=d*data[sample+24] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (23*4)] ; ST = d*data[sample+23] d
+ fadd dword [edi + (23*4)] ; ST = autoc[23]+d*data[sample+23] d
+ fstp dword [edi + (23*4)] ; autoc[23]+=d*data[sample+23] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (22*4)] ; ST = d*data[sample+22] d
+ fadd dword [edi + (22*4)] ; ST = autoc[22]+d*data[sample+22] d
+ fstp dword [edi + (22*4)] ; autoc[22]+=d*data[sample+22] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (21*4)] ; ST = d*data[sample+21] d
+ fadd dword [edi + (21*4)] ; ST = autoc[21]+d*data[sample+21] d
+ fstp dword [edi + (21*4)] ; autoc[21]+=d*data[sample+21] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (20*4)] ; ST = d*data[sample+20] d
+ fadd dword [edi + (20*4)] ; ST = autoc[20]+d*data[sample+20] d
+ fstp dword [edi + (20*4)] ; autoc[20]+=d*data[sample+20] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (19*4)] ; ST = d*data[sample+19] d
+ fadd dword [edi + (19*4)] ; ST = autoc[19]+d*data[sample+19] d
+ fstp dword [edi + (19*4)] ; autoc[19]+=d*data[sample+19] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (18*4)] ; ST = d*data[sample+18] d
+ fadd dword [edi + (18*4)] ; ST = autoc[18]+d*data[sample+18] d
+ fstp dword [edi + (18*4)] ; autoc[18]+=d*data[sample+18] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (17*4)] ; ST = d*data[sample+17] d
+ fadd dword [edi + (17*4)] ; ST = autoc[17]+d*data[sample+17] d
+ fstp dword [edi + (17*4)] ; autoc[17]+=d*data[sample+17] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (16*4)] ; ST = d*data[sample+16] d
+ fadd dword [edi + (16*4)] ; ST = autoc[16]+d*data[sample+16] d
+ fstp dword [edi + (16*4)] ; autoc[16]+=d*data[sample+16] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (15*4)] ; ST = d*data[sample+15] d
+ fadd dword [edi + (15*4)] ; ST = autoc[15]+d*data[sample+15] d
+ fstp dword [edi + (15*4)] ; autoc[15]+=d*data[sample+15] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (14*4)] ; ST = d*data[sample+14] d
+ fadd dword [edi + (14*4)] ; ST = autoc[14]+d*data[sample+14] d
+ fstp dword [edi + (14*4)] ; autoc[14]+=d*data[sample+14] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (13*4)] ; ST = d*data[sample+13] d
+ fadd dword [edi + (13*4)] ; ST = autoc[13]+d*data[sample+13] d
+ fstp dword [edi + (13*4)] ; autoc[13]+=d*data[sample+13] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (12*4)] ; ST = d*data[sample+12] d
+ fadd dword [edi + (12*4)] ; ST = autoc[12]+d*data[sample+12] d
+ fstp dword [edi + (12*4)] ; autoc[12]+=d*data[sample+12] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (11*4)] ; ST = d*data[sample+11] d
+ fadd dword [edi + (11*4)] ; ST = autoc[11]+d*data[sample+11] d
+ fstp dword [edi + (11*4)] ; autoc[11]+=d*data[sample+11] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (10*4)] ; ST = d*data[sample+10] d
+ fadd dword [edi + (10*4)] ; ST = autoc[10]+d*data[sample+10] d
+ fstp dword [edi + (10*4)] ; autoc[10]+=d*data[sample+10] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 9*4)] ; ST = d*data[sample+9] d
+ fadd dword [edi + ( 9*4)] ; ST = autoc[9]+d*data[sample+9] d
+ fstp dword [edi + ( 9*4)] ; autoc[9]+=d*data[sample+9] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 8*4)] ; ST = d*data[sample+8] d
+ fadd dword [edi + ( 8*4)] ; ST = autoc[8]+d*data[sample+8] d
+ fstp dword [edi + ( 8*4)] ; autoc[8]+=d*data[sample+8] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 7*4)] ; ST = d*data[sample+7] d
+ fadd dword [edi + ( 7*4)] ; ST = autoc[7]+d*data[sample+7] d
+ fstp dword [edi + ( 7*4)] ; autoc[7]+=d*data[sample+7] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 6*4)] ; ST = d*data[sample+6] d
+ fadd dword [edi + ( 6*4)] ; ST = autoc[6]+d*data[sample+6] d
+ fstp dword [edi + ( 6*4)] ; autoc[6]+=d*data[sample+6] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 5*4)] ; ST = d*data[sample+4] d
+ fadd dword [edi + ( 5*4)] ; ST = autoc[4]+d*data[sample+4] d
+ fstp dword [edi + ( 5*4)] ; autoc[4]+=d*data[sample+4] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 4*4)] ; ST = d*data[sample+4] d
+ fadd dword [edi + ( 4*4)] ; ST = autoc[4]+d*data[sample+4] d
+ fstp dword [edi + ( 4*4)] ; autoc[4]+=d*data[sample+4] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 3*4)] ; ST = d*data[sample+3] d
+ fadd dword [edi + ( 3*4)] ; ST = autoc[3]+d*data[sample+3] d
+ fstp dword [edi + ( 3*4)] ; autoc[3]+=d*data[sample+3] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 2*4)] ; ST = d*data[sample+2] d
+ fadd dword [edi + ( 2*4)] ; ST = autoc[2]+d*data[sample+2] d
+ fstp dword [edi + ( 2*4)] ; autoc[2]+=d*data[sample+2] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 1*4)] ; ST = d*data[sample+1] d
+ fadd dword [edi + ( 1*4)] ; ST = autoc[1]+d*data[sample+1] d
+ fstp dword [edi + ( 1*4)] ; autoc[1]+=d*data[sample+1] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi] ; ST = d*data[sample] d WATCHOUT: no displacement byte here!
+ fadd dword [edi] ; ST = autoc[0]+d*data[sample] d WATCHOUT: no displacement byte here!
+ fstp dword [edi] ; autoc[0]+=d*data[sample] ST = d WATCHOUT: no displacement byte here!
+.jumper1_0:
+
+ fstp st0 ; pop d, ST = empty
+ add esi, byte 4 ; sample++
+ dec ecx
+ jz .loop1_end
+ fld dword [esi] ; ST = d <- data[sample]
+ jmp edx
+.loop1_end:
+
+ ; for(; sample < data_len; sample++) {
+ ; d = data[sample];
+ ; for(coeff = 0; coeff < data_len - sample; coeff++)
+ ; autoc[coeff] += d * data[sample+coeff];
+ ; }
+ mov ecx, [esp + 24] ; ecx <- lag
+ dec ecx ; ecx <- lag - 1
+ jz near .end ; skip loop if 0 (i.e. lag == 1)
+
+ fld dword [esi] ; ST = d <- data[sample]
+ mov eax, ecx ; eax <- lag - 1 == data_len - sample the first time through
+ ; each iteration is 11 bytes so we need (-eax)*11, so we do (-12*eax + eax)
+ lea edx, [eax + eax*2]
+ neg edx
+ lea edx, [eax + edx*4 + .jumper2_0 - .get_eip2]
+ call .get_eip2
+.get_eip2:
+ pop ebx
+ add edx, ebx
+ inc edx ; compensate for the shorter opcode on the last iteration
+ inc edx ; compensate for the shorter opcode on the last iteration
+ inc edx ; compensate for the shorter opcode on the last iteration
+ jmp edx
+
+ fld st0 ; ST = d d
+ fmul dword [esi + (31*4)] ; ST = d*data[sample+31] d
+ fadd dword [edi + (31*4)] ; ST = autoc[31]+d*data[sample+31] d
+ fstp dword [edi + (31*4)] ; autoc[31]+=d*data[sample+31] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (30*4)] ; ST = d*data[sample+30] d
+ fadd dword [edi + (30*4)] ; ST = autoc[30]+d*data[sample+30] d
+ fstp dword [edi + (30*4)] ; autoc[30]+=d*data[sample+30] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (29*4)] ; ST = d*data[sample+29] d
+ fadd dword [edi + (29*4)] ; ST = autoc[29]+d*data[sample+29] d
+ fstp dword [edi + (29*4)] ; autoc[29]+=d*data[sample+29] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (28*4)] ; ST = d*data[sample+28] d
+ fadd dword [edi + (28*4)] ; ST = autoc[28]+d*data[sample+28] d
+ fstp dword [edi + (28*4)] ; autoc[28]+=d*data[sample+28] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (27*4)] ; ST = d*data[sample+27] d
+ fadd dword [edi + (27*4)] ; ST = autoc[27]+d*data[sample+27] d
+ fstp dword [edi + (27*4)] ; autoc[27]+=d*data[sample+27] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (26*4)] ; ST = d*data[sample+26] d
+ fadd dword [edi + (26*4)] ; ST = autoc[26]+d*data[sample+26] d
+ fstp dword [edi + (26*4)] ; autoc[26]+=d*data[sample+26] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (25*4)] ; ST = d*data[sample+25] d
+ fadd dword [edi + (25*4)] ; ST = autoc[25]+d*data[sample+25] d
+ fstp dword [edi + (25*4)] ; autoc[25]+=d*data[sample+25] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (24*4)] ; ST = d*data[sample+24] d
+ fadd dword [edi + (24*4)] ; ST = autoc[24]+d*data[sample+24] d
+ fstp dword [edi + (24*4)] ; autoc[24]+=d*data[sample+24] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (23*4)] ; ST = d*data[sample+23] d
+ fadd dword [edi + (23*4)] ; ST = autoc[23]+d*data[sample+23] d
+ fstp dword [edi + (23*4)] ; autoc[23]+=d*data[sample+23] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (22*4)] ; ST = d*data[sample+22] d
+ fadd dword [edi + (22*4)] ; ST = autoc[22]+d*data[sample+22] d
+ fstp dword [edi + (22*4)] ; autoc[22]+=d*data[sample+22] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (21*4)] ; ST = d*data[sample+21] d
+ fadd dword [edi + (21*4)] ; ST = autoc[21]+d*data[sample+21] d
+ fstp dword [edi + (21*4)] ; autoc[21]+=d*data[sample+21] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (20*4)] ; ST = d*data[sample+20] d
+ fadd dword [edi + (20*4)] ; ST = autoc[20]+d*data[sample+20] d
+ fstp dword [edi + (20*4)] ; autoc[20]+=d*data[sample+20] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (19*4)] ; ST = d*data[sample+19] d
+ fadd dword [edi + (19*4)] ; ST = autoc[19]+d*data[sample+19] d
+ fstp dword [edi + (19*4)] ; autoc[19]+=d*data[sample+19] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (18*4)] ; ST = d*data[sample+18] d
+ fadd dword [edi + (18*4)] ; ST = autoc[18]+d*data[sample+18] d
+ fstp dword [edi + (18*4)] ; autoc[18]+=d*data[sample+18] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (17*4)] ; ST = d*data[sample+17] d
+ fadd dword [edi + (17*4)] ; ST = autoc[17]+d*data[sample+17] d
+ fstp dword [edi + (17*4)] ; autoc[17]+=d*data[sample+17] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (16*4)] ; ST = d*data[sample+16] d
+ fadd dword [edi + (16*4)] ; ST = autoc[16]+d*data[sample+16] d
+ fstp dword [edi + (16*4)] ; autoc[16]+=d*data[sample+16] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (15*4)] ; ST = d*data[sample+15] d
+ fadd dword [edi + (15*4)] ; ST = autoc[15]+d*data[sample+15] d
+ fstp dword [edi + (15*4)] ; autoc[15]+=d*data[sample+15] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (14*4)] ; ST = d*data[sample+14] d
+ fadd dword [edi + (14*4)] ; ST = autoc[14]+d*data[sample+14] d
+ fstp dword [edi + (14*4)] ; autoc[14]+=d*data[sample+14] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (13*4)] ; ST = d*data[sample+13] d
+ fadd dword [edi + (13*4)] ; ST = autoc[13]+d*data[sample+13] d
+ fstp dword [edi + (13*4)] ; autoc[13]+=d*data[sample+13] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (12*4)] ; ST = d*data[sample+12] d
+ fadd dword [edi + (12*4)] ; ST = autoc[12]+d*data[sample+12] d
+ fstp dword [edi + (12*4)] ; autoc[12]+=d*data[sample+12] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (11*4)] ; ST = d*data[sample+11] d
+ fadd dword [edi + (11*4)] ; ST = autoc[11]+d*data[sample+11] d
+ fstp dword [edi + (11*4)] ; autoc[11]+=d*data[sample+11] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + (10*4)] ; ST = d*data[sample+10] d
+ fadd dword [edi + (10*4)] ; ST = autoc[10]+d*data[sample+10] d
+ fstp dword [edi + (10*4)] ; autoc[10]+=d*data[sample+10] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 9*4)] ; ST = d*data[sample+9] d
+ fadd dword [edi + ( 9*4)] ; ST = autoc[9]+d*data[sample+9] d
+ fstp dword [edi + ( 9*4)] ; autoc[9]+=d*data[sample+9] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 8*4)] ; ST = d*data[sample+8] d
+ fadd dword [edi + ( 8*4)] ; ST = autoc[8]+d*data[sample+8] d
+ fstp dword [edi + ( 8*4)] ; autoc[8]+=d*data[sample+8] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 7*4)] ; ST = d*data[sample+7] d
+ fadd dword [edi + ( 7*4)] ; ST = autoc[7]+d*data[sample+7] d
+ fstp dword [edi + ( 7*4)] ; autoc[7]+=d*data[sample+7] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 6*4)] ; ST = d*data[sample+6] d
+ fadd dword [edi + ( 6*4)] ; ST = autoc[6]+d*data[sample+6] d
+ fstp dword [edi + ( 6*4)] ; autoc[6]+=d*data[sample+6] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 5*4)] ; ST = d*data[sample+4] d
+ fadd dword [edi + ( 5*4)] ; ST = autoc[4]+d*data[sample+4] d
+ fstp dword [edi + ( 5*4)] ; autoc[4]+=d*data[sample+4] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 4*4)] ; ST = d*data[sample+4] d
+ fadd dword [edi + ( 4*4)] ; ST = autoc[4]+d*data[sample+4] d
+ fstp dword [edi + ( 4*4)] ; autoc[4]+=d*data[sample+4] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 3*4)] ; ST = d*data[sample+3] d
+ fadd dword [edi + ( 3*4)] ; ST = autoc[3]+d*data[sample+3] d
+ fstp dword [edi + ( 3*4)] ; autoc[3]+=d*data[sample+3] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 2*4)] ; ST = d*data[sample+2] d
+ fadd dword [edi + ( 2*4)] ; ST = autoc[2]+d*data[sample+2] d
+ fstp dword [edi + ( 2*4)] ; autoc[2]+=d*data[sample+2] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi + ( 1*4)] ; ST = d*data[sample+1] d
+ fadd dword [edi + ( 1*4)] ; ST = autoc[1]+d*data[sample+1] d
+ fstp dword [edi + ( 1*4)] ; autoc[1]+=d*data[sample+1] ST = d
+ fld st0 ; ST = d d
+ fmul dword [esi] ; ST = d*data[sample] d WATCHOUT: no displacement byte here!
+ fadd dword [edi] ; ST = autoc[0]+d*data[sample] d WATCHOUT: no displacement byte here!
+ fstp dword [edi] ; autoc[0]+=d*data[sample] ST = d WATCHOUT: no displacement byte here!
+.jumper2_0:
+
+ fstp st0 ; pop d, ST = empty
+ add esi, byte 4 ; sample++
+ dec ecx
+ jz .loop2_end
+ add edx, byte 11 ; adjust our inner loop counter by adjusting the jump target
+ fld dword [esi] ; ST = d <- data[sample]
+ jmp edx
+.loop2_end:
+
+.end:
+ pop ebx
+ pop edi
+ pop esi
+ ret
+
+ ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4
+ ;[esp + 16] == autoc[]
+ ;[esp + 12] == lag
+ ;[esp + 8] == data_len
+ ;[esp + 4] == data[]
+
+ ;ASSERT(lag > 0)
+ ;ASSERT(lag <= 4)
+ ;ASSERT(lag <= data_len)
+
+ ; for(coeff = 0; coeff < lag; coeff++)
+ ; autoc[coeff] = 0.0;
+ xorps xmm5, xmm5
+
+ mov edx, [esp + 8] ; edx == data_len
+ mov eax, [esp + 4] ; eax == &data[sample] <- &data[0]
+
+ movss xmm0, [eax] ; xmm0 = 0,0,0,data[0]
+ add eax, 4
+ movaps xmm2, xmm0 ; xmm2 = 0,0,0,data[0]
+ shufps xmm0, xmm0, 0 ; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+.warmup: ; xmm2 == data[sample-3],data[sample-2],data[sample-1],data[sample]
+ mulps xmm0, xmm2 ; xmm0 = xmm0 * xmm2
+ addps xmm5, xmm0 ; xmm5 += xmm0 * xmm2
+ dec edx
+ jz .loop_end
+ ALIGN 16
+.loop_start:
+ ; start by reading the next sample
+ movss xmm0, [eax] ; xmm0 = 0,0,0,data[sample]
+ add eax, 4
+ shufps xmm0, xmm0, 0 ; xmm0 = data[sample],data[sample],data[sample],data[sample]
+ shufps xmm2, xmm2, 93h ; 93h=2-1-0-3 => xmm2 gets rotated left by one float
+ movss xmm2, xmm0
+ mulps xmm0, xmm2 ; xmm0 = xmm0 * xmm2
+ addps xmm5, xmm0 ; xmm5 += xmm0 * xmm2
+ dec edx
+ jnz .loop_start
+.loop_end:
+ ; store autoc
+ mov edx, [esp + 16] ; edx == autoc
+ movups [edx], xmm5
+
+.end:
+ ret
+
+ ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8
+ ;[esp + 16] == autoc[]
+ ;[esp + 12] == lag
+ ;[esp + 8] == data_len
+ ;[esp + 4] == data[]
+
+ ;ASSERT(lag > 0)
+ ;ASSERT(lag <= 8)
+ ;ASSERT(lag <= data_len)
+
+ ; for(coeff = 0; coeff < lag; coeff++)
+ ; autoc[coeff] = 0.0;
+ xorps xmm5, xmm5
+ xorps xmm6, xmm6
+
+ mov edx, [esp + 8] ; edx == data_len
+ mov eax, [esp + 4] ; eax == &data[sample] <- &data[0]
+
+ movss xmm0, [eax] ; xmm0 = 0,0,0,data[0]
+ add eax, 4
+ movaps xmm2, xmm0 ; xmm2 = 0,0,0,data[0]
+ shufps xmm0, xmm0, 0 ; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+ movaps xmm1, xmm0 ; xmm1 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+ xorps xmm3, xmm3 ; xmm3 = 0,0,0,0
+.warmup: ; xmm3:xmm2 == data[sample-7],data[sample-6],...,data[sample]
+ mulps xmm0, xmm2
+ mulps xmm1, xmm3 ; xmm1:xmm0 = xmm1:xmm0 * xmm3:xmm2
+ addps xmm5, xmm0
+ addps xmm6, xmm1 ; xmm6:xmm5 += xmm1:xmm0 * xmm3:xmm2
+ dec edx
+ jz .loop_end
+ ALIGN 16
+.loop_start:
+ ; start by reading the next sample
+ movss xmm0, [eax] ; xmm0 = 0,0,0,data[sample]
+ ; here we reorder the instructions; see the (#) indexes for a logical order
+ shufps xmm2, xmm2, 93h ; (3) 93h=2-1-0-3 => xmm2 gets rotated left by one float
+ add eax, 4 ; (0)
+ shufps xmm3, xmm3, 93h ; (4) 93h=2-1-0-3 => xmm3 gets rotated left by one float
+ shufps xmm0, xmm0, 0 ; (1) xmm0 = data[sample],data[sample],data[sample],data[sample]
+ movss xmm3, xmm2 ; (5)
+ movaps xmm1, xmm0 ; (2) xmm1 = data[sample],data[sample],data[sample],data[sample]
+ movss xmm2, xmm0 ; (6)
+ mulps xmm1, xmm3 ; (8)
+ mulps xmm0, xmm2 ; (7) xmm1:xmm0 = xmm1:xmm0 * xmm3:xmm2
+ addps xmm6, xmm1 ; (10)
+ addps xmm5, xmm0 ; (9) xmm6:xmm5 += xmm1:xmm0 * xmm3:xmm2
+ dec edx
+ jnz .loop_start
+.loop_end:
+ ; store autoc
+ mov edx, [esp + 16] ; edx == autoc
+ movups [edx], xmm5
+ movups [edx + 16], xmm6
+
+.end:
+ ret
+
+ ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12
+ ;[esp + 16] == autoc[]
+ ;[esp + 12] == lag
+ ;[esp + 8] == data_len
+ ;[esp + 4] == data[]
+
+ ;ASSERT(lag > 0)
+ ;ASSERT(lag <= 12)
+ ;ASSERT(lag <= data_len)
+
+ ; for(coeff = 0; coeff < lag; coeff++)
+ ; autoc[coeff] = 0.0;
+ xorps xmm5, xmm5
+ xorps xmm6, xmm6
+ xorps xmm7, xmm7
+
+ mov edx, [esp + 8] ; edx == data_len
+ mov eax, [esp + 4] ; eax == &data[sample] <- &data[0]
+
+ movss xmm0, [eax] ; xmm0 = 0,0,0,data[0]
+ add eax, 4
+ movaps xmm2, xmm0 ; xmm2 = 0,0,0,data[0]
+ shufps xmm0, xmm0, 0 ; xmm0 == data[sample],data[sample],data[sample],data[sample] = data[0],data[0],data[0],data[0]
+ xorps xmm3, xmm3 ; xmm3 = 0,0,0,0
+ xorps xmm4, xmm4 ; xmm4 = 0,0,0,0
+.warmup: ; xmm3:xmm2 == data[sample-7],data[sample-6],...,data[sample]
+ movaps xmm1, xmm0
+ mulps xmm1, xmm2
+ addps xmm5, xmm1
+ movaps xmm1, xmm0
+ mulps xmm1, xmm3
+ addps xmm6, xmm1
+ mulps xmm0, xmm4
+ addps xmm7, xmm0 ; xmm7:xmm6:xmm5 += xmm0:xmm0:xmm0 * xmm4:xmm3:xmm2
+ dec edx
+ jz .loop_end
+ ALIGN 16
+.loop_start:
+ ; start by reading the next sample
+ movss xmm0, [eax] ; xmm0 = 0,0,0,data[sample]
+ add eax, 4
+ shufps xmm0, xmm0, 0 ; xmm0 = data[sample],data[sample],data[sample],data[sample]
+
+ ; shift xmm4:xmm3:xmm2 left by one float
+ shufps xmm2, xmm2, 93h ; 93h=2-1-0-3 => xmm2 gets rotated left by one float
+ shufps xmm3, xmm3, 93h ; 93h=2-1-0-3 => xmm3 gets rotated left by one float
+ shufps xmm4, xmm4, 93h ; 93h=2-1-0-3 => xmm4 gets rotated left by one float
+ movss xmm4, xmm3
+ movss xmm3, xmm2
+ movss xmm2, xmm0
+
+ ; xmm7:xmm6:xmm5 += xmm0:xmm0:xmm0 * xmm3:xmm3:xmm2
+ movaps xmm1, xmm0
+ mulps xmm1, xmm2
+ addps xmm5, xmm1
+ movaps xmm1, xmm0
+ mulps xmm1, xmm3
+ addps xmm6, xmm1
+ mulps xmm0, xmm4
+ addps xmm7, xmm0
+
+ dec edx
+ jnz .loop_start
+.loop_end:
+ ; store autoc
+ mov edx, [esp + 16] ; edx == autoc
+ movups [edx], xmm5
+ movups [edx + 16], xmm6
+ movups [edx + 32], xmm7
+
+.end:
+ ret
+
+ ALIGN 16
+cident FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow
+ ;[ebp + 32] autoc
+ ;[ebp + 28] lag
+ ;[ebp + 24] data_len
+ ;[ebp + 20] data
+
+ push ebp
+ push ebx
+ push esi
+ push edi
+ mov ebp, esp
+
+ mov esi, [ebp + 20]
+ mov edi, [ebp + 24]
+ mov edx, [ebp + 28]
+ inc edx
+ and edx, byte -2
+ mov eax, edx
+ neg eax
+ and esp, byte -8
+ lea esp, [esp + 4 * eax]
+ mov ecx, edx
+ xor eax, eax
+.loop0:
+ dec ecx
+ mov [esp + 4 * ecx], eax
+ jnz short .loop0
+
+ mov eax, edi
+ sub eax, edx
+ mov ebx, edx
+ and ebx, byte 1
+ sub eax, ebx
+ lea ecx, [esi + 4 * eax - 12]
+ cmp esi, ecx
+ mov eax, esi
+ ja short .loop2_pre
+ ALIGN 16 ;4 nops
+.loop1_i:
+ movd mm0, [eax]
+ movd mm2, [eax + 4]
+ movd mm4, [eax + 8]
+ movd mm6, [eax + 12]
+ mov ebx, edx
+ punpckldq mm0, mm0
+ punpckldq mm2, mm2
+ punpckldq mm4, mm4
+ punpckldq mm6, mm6
+ ALIGN 16 ;3 nops
+.loop1_j:
+ sub ebx, byte 2
+ movd mm1, [eax + 4 * ebx]
+ movd mm3, [eax + 4 * ebx + 4]
+ movd mm5, [eax + 4 * ebx + 8]
+ movd mm7, [eax + 4 * ebx + 12]
+ punpckldq mm1, mm3
+ punpckldq mm3, mm5
+ pfmul mm1, mm0
+ punpckldq mm5, mm7
+ pfmul mm3, mm2
+ punpckldq mm7, [eax + 4 * ebx + 16]
+ pfmul mm5, mm4
+ pfmul mm7, mm6
+ pfadd mm1, mm3
+ movq mm3, [esp + 4 * ebx]
+ pfadd mm5, mm7
+ pfadd mm1, mm5
+ pfadd mm3, mm1
+ movq [esp + 4 * ebx], mm3
+ jg short .loop1_j
+
+ add eax, byte 16
+ cmp eax, ecx
+ jb short .loop1_i
+
+.loop2_pre:
+ mov ebx, eax
+ sub eax, esi
+ shr eax, 2
+ lea ecx, [esi + 4 * edi]
+ mov esi, ebx
+.loop2_i:
+ movd mm0, [esi]
+ mov ebx, edi
+ sub ebx, eax
+ cmp ebx, edx
+ jbe short .loop2_j
+ mov ebx, edx
+.loop2_j:
+ dec ebx
+ movd mm1, [esi + 4 * ebx]
+ pfmul mm1, mm0
+ movd mm2, [esp + 4 * ebx]
+ pfadd mm1, mm2
+ movd [esp + 4 * ebx], mm1
+
+ jnz short .loop2_j
+
+ add esi, byte 4
+ inc eax
+ cmp esi, ecx
+ jnz short .loop2_i
+
+ mov edi, [ebp + 32]
+ mov edx, [ebp + 28]
+.loop3:
+ dec edx
+ mov eax, [esp + 4 * edx]
+ mov [edi + 4 * edx], eax
+ jnz short .loop3
+
+ femms
+
+ mov esp, ebp
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+;void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
+;
+; for(i = 0; i < data_len; i++) {
+; sum = 0;
+; for(j = 0; j < order; j++)
+; sum += qlp_coeff[j] * data[i-j-1];
+; residual[i] = data[i] - (sum >> lp_quantization);
+; }
+;
+ ALIGN 16
+cident FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32
+ ;[esp + 40] residual[]
+ ;[esp + 36] lp_quantization
+ ;[esp + 32] order
+ ;[esp + 28] qlp_coeff[]
+ ;[esp + 24] data_len
+ ;[esp + 20] data[]
+
+ ;ASSERT(order > 0)
+
+ push ebp
+ push ebx
+ push esi
+ push edi
+
+ mov esi, [esp + 20] ; esi = data[]
+ mov edi, [esp + 40] ; edi = residual[]
+ mov eax, [esp + 32] ; eax = order
+ mov ebx, [esp + 24] ; ebx = data_len
+
+ test ebx, ebx
+ jz near .end ; do nothing if data_len == 0
+.begin:
+ cmp eax, byte 1
+ jg short .i_1more
+
+ mov ecx, [esp + 28]
+ mov edx, [ecx] ; edx = qlp_coeff[0]
+ mov eax, [esi - 4] ; eax = data[-1]
+ mov cl, [esp + 36] ; cl = lp_quantization
+ ALIGN 16
+.i_1_loop_i:
+ imul eax, edx
+ sar eax, cl
+ neg eax
+ add eax, [esi]
+ mov [edi], eax
+ mov eax, [esi]
+ add edi, byte 4
+ add esi, byte 4
+ dec ebx
+ jnz .i_1_loop_i
+
+ jmp .end
+
+.i_1more:
+ cmp eax, byte 32 ; for order <= 32 there is a faster routine
+ jbe short .i_32
+
+ ; This version is here just for completeness, since FLAC__MAX_LPC_ORDER == 32
+ ALIGN 16
+.i_32more_loop_i:
+ xor ebp, ebp
+ mov ecx, [esp + 32]
+ mov edx, ecx
+ shl edx, 2
+ add edx, [esp + 28]
+ neg ecx
+ ALIGN 16
+.i_32more_loop_j:
+ sub edx, byte 4
+ mov eax, [edx]
+ imul eax, [esi + 4 * ecx]
+ add ebp, eax
+ inc ecx
+ jnz short .i_32more_loop_j
+
+ mov cl, [esp + 36]
+ sar ebp, cl
+ neg ebp
+ add ebp, [esi]
+ mov [edi], ebp
+ add esi, byte 4
+ add edi, byte 4
+
+ dec ebx
+ jnz .i_32more_loop_i
+
+ jmp .end
+
+.i_32:
+ sub edi, esi
+ neg eax
+ lea edx, [eax + eax * 8 + .jumper_0 - .get_eip0]
+ call .get_eip0
+.get_eip0:
+ pop eax
+ add edx, eax
+ inc edx
+ mov eax, [esp + 28] ; eax = qlp_coeff[]
+ xor ebp, ebp
+ jmp edx
+
+ mov ecx, [eax + 124]
+ imul ecx, [esi - 128]
+ add ebp, ecx
+ mov ecx, [eax + 120]
+ imul ecx, [esi - 124]
+ add ebp, ecx
+ mov ecx, [eax + 116]
+ imul ecx, [esi - 120]
+ add ebp, ecx
+ mov ecx, [eax + 112]
+ imul ecx, [esi - 116]
+ add ebp, ecx
+ mov ecx, [eax + 108]
+ imul ecx, [esi - 112]
+ add ebp, ecx
+ mov ecx, [eax + 104]
+ imul ecx, [esi - 108]
+ add ebp, ecx
+ mov ecx, [eax + 100]
+ imul ecx, [esi - 104]
+ add ebp, ecx
+ mov ecx, [eax + 96]
+ imul ecx, [esi - 100]
+ add ebp, ecx
+ mov ecx, [eax + 92]
+ imul ecx, [esi - 96]
+ add ebp, ecx
+ mov ecx, [eax + 88]
+ imul ecx, [esi - 92]
+ add ebp, ecx
+ mov ecx, [eax + 84]
+ imul ecx, [esi - 88]
+ add ebp, ecx
+ mov ecx, [eax + 80]
+ imul ecx, [esi - 84]
+ add ebp, ecx
+ mov ecx, [eax + 76]
+ imul ecx, [esi - 80]
+ add ebp, ecx
+ mov ecx, [eax + 72]
+ imul ecx, [esi - 76]
+ add ebp, ecx
+ mov ecx, [eax + 68]
+ imul ecx, [esi - 72]
+ add ebp, ecx
+ mov ecx, [eax + 64]
+ imul ecx, [esi - 68]
+ add ebp, ecx
+ mov ecx, [eax + 60]
+ imul ecx, [esi - 64]
+ add ebp, ecx
+ mov ecx, [eax + 56]
+ imul ecx, [esi - 60]
+ add ebp, ecx
+ mov ecx, [eax + 52]
+ imul ecx, [esi - 56]
+ add ebp, ecx
+ mov ecx, [eax + 48]
+ imul ecx, [esi - 52]
+ add ebp, ecx
+ mov ecx, [eax + 44]
+ imul ecx, [esi - 48]
+ add ebp, ecx
+ mov ecx, [eax + 40]
+ imul ecx, [esi - 44]
+ add ebp, ecx
+ mov ecx, [eax + 36]
+ imul ecx, [esi - 40]
+ add ebp, ecx
+ mov ecx, [eax + 32]
+ imul ecx, [esi - 36]
+ add ebp, ecx
+ mov ecx, [eax + 28]
+ imul ecx, [esi - 32]
+ add ebp, ecx
+ mov ecx, [eax + 24]
+ imul ecx, [esi - 28]
+ add ebp, ecx
+ mov ecx, [eax + 20]
+ imul ecx, [esi - 24]
+ add ebp, ecx
+ mov ecx, [eax + 16]
+ imul ecx, [esi - 20]
+ add ebp, ecx
+ mov ecx, [eax + 12]
+ imul ecx, [esi - 16]
+ add ebp, ecx
+ mov ecx, [eax + 8]
+ imul ecx, [esi - 12]
+ add ebp, ecx
+ mov ecx, [eax + 4]
+ imul ecx, [esi - 8]
+ add ebp, ecx
+ mov ecx, [eax] ; there is one byte missing
+ imul ecx, [esi - 4]
+ add ebp, ecx
+.jumper_0:
+
+ mov cl, [esp + 36]
+ sar ebp, cl
+ neg ebp
+ add ebp, [esi]
+ mov [edi + esi], ebp
+ add esi, byte 4
+
+ dec ebx
+ jz short .end
+ xor ebp, ebp
+ jmp edx
+
+.end:
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+; WATCHOUT: this routine works on 16 bit data which means bits-per-sample for
+; the channel and qlp_coeffs must be <= 16. Especially note that this routine
+; cannot be used for side-channel coded 16bps channels since the effective bps
+; is 17.
+ ALIGN 16
+cident FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx
+ ;[esp + 40] residual[]
+ ;[esp + 36] lp_quantization
+ ;[esp + 32] order
+ ;[esp + 28] qlp_coeff[]
+ ;[esp + 24] data_len
+ ;[esp + 20] data[]
+
+ ;ASSERT(order > 0)
+
+ push ebp
+ push ebx
+ push esi
+ push edi
+
+ mov esi, [esp + 20] ; esi = data[]
+ mov edi, [esp + 40] ; edi = residual[]
+ mov eax, [esp + 32] ; eax = order
+ mov ebx, [esp + 24] ; ebx = data_len
+
+ test ebx, ebx
+ jz near .end ; do nothing if data_len == 0
+ dec ebx
+ test ebx, ebx
+ jz near .last_one
+
+ mov edx, [esp + 28] ; edx = qlp_coeff[]
+ movd mm6, [esp + 36] ; mm6 = 0:lp_quantization
+ mov ebp, esp
+
+ and esp, 0xfffffff8
+
+ xor ecx, ecx
+.copy_qlp_loop:
+ push word [edx + 4 * ecx]
+ inc ecx
+ cmp ecx, eax
+ jnz short .copy_qlp_loop
+
+ and ecx, 0x3
+ test ecx, ecx
+ je short .za_end
+ sub ecx, byte 4
+.za_loop:
+ push word 0
+ inc eax
+ inc ecx
+ jnz short .za_loop
+.za_end:
+
+ movq mm5, [esp + 2 * eax - 8]
+ movd mm4, [esi - 16]
+ punpckldq mm4, [esi - 12]
+ movd mm0, [esi - 8]
+ punpckldq mm0, [esi - 4]
+ packssdw mm4, mm0
+
+ cmp eax, byte 4
+ jnbe short .mmx_4more
+
+ ALIGN 16
+.mmx_4_loop_i:
+ movd mm1, [esi]
+ movq mm3, mm4
+ punpckldq mm1, [esi + 4]
+ psrlq mm4, 16
+ movq mm0, mm1
+ psllq mm0, 48
+ por mm4, mm0
+ movq mm2, mm4
+ psrlq mm4, 16
+ pxor mm0, mm0
+ punpckhdq mm0, mm1
+ pmaddwd mm3, mm5
+ pmaddwd mm2, mm5
+ psllq mm0, 16
+ por mm4, mm0
+ movq mm0, mm3
+ punpckldq mm3, mm2
+ punpckhdq mm0, mm2
+ paddd mm3, mm0
+ psrad mm3, mm6
+ psubd mm1, mm3
+ movd [edi], mm1
+ punpckhdq mm1, mm1
+ movd [edi + 4], mm1
+
+ add edi, byte 8
+ add esi, byte 8
+
+ sub ebx, 2
+ jg .mmx_4_loop_i
+ jmp .mmx_end
+
+.mmx_4more:
+ shl eax, 2
+ neg eax
+ add eax, byte 16
+
+ ALIGN 16
+.mmx_4more_loop_i:
+ movd mm1, [esi]
+ punpckldq mm1, [esi + 4]
+ movq mm3, mm4
+ psrlq mm4, 16
+ movq mm0, mm1
+ psllq mm0, 48
+ por mm4, mm0
+ movq mm2, mm4
+ psrlq mm4, 16
+ pxor mm0, mm0
+ punpckhdq mm0, mm1
+ pmaddwd mm3, mm5
+ pmaddwd mm2, mm5
+ psllq mm0, 16
+ por mm4, mm0
+
+ mov ecx, esi
+ add ecx, eax
+ mov edx, esp
+
+ ALIGN 16
+.mmx_4more_loop_j:
+ movd mm0, [ecx - 16]
+ movd mm7, [ecx - 8]
+ punpckldq mm0, [ecx - 12]
+ punpckldq mm7, [ecx - 4]
+ packssdw mm0, mm7
+ pmaddwd mm0, [edx]
+ punpckhdq mm7, mm7
+ paddd mm3, mm0
+ movd mm0, [ecx - 12]
+ punpckldq mm0, [ecx - 8]
+ punpckldq mm7, [ecx]
+ packssdw mm0, mm7
+ pmaddwd mm0, [edx]
+ paddd mm2, mm0
+
+ add edx, byte 8
+ add ecx, byte 16
+ cmp ecx, esi
+ jnz .mmx_4more_loop_j
+
+ movq mm0, mm3
+ punpckldq mm3, mm2
+ punpckhdq mm0, mm2
+ paddd mm3, mm0
+ psrad mm3, mm6
+ psubd mm1, mm3
+ movd [edi], mm1
+ punpckhdq mm1, mm1
+ movd [edi + 4], mm1
+
+ add edi, byte 8
+ add esi, byte 8
+
+ sub ebx, 2
+ jg near .mmx_4more_loop_i
+
+.mmx_end:
+ emms
+ mov esp, ebp
+.last_one:
+ mov eax, [esp + 32]
+ inc ebx
+ jnz near FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32.begin
+
+.end:
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+; **********************************************************************
+;
+; void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
+; {
+; unsigned i, j;
+; FLAC__int32 sum;
+;
+; FLAC__ASSERT(order > 0);
+;
+; for(i = 0; i < data_len; i++) {
+; sum = 0;
+; for(j = 0; j < order; j++)
+; sum += qlp_coeff[j] * data[i-j-1];
+; data[i] = residual[i] + (sum >> lp_quantization);
+; }
+; }
+ ALIGN 16
+cident FLAC__lpc_restore_signal_asm_ia32
+ ;[esp + 40] data[]
+ ;[esp + 36] lp_quantization
+ ;[esp + 32] order
+ ;[esp + 28] qlp_coeff[]
+ ;[esp + 24] data_len
+ ;[esp + 20] residual[]
+
+ ;ASSERT(order > 0)
+
+ push ebp
+ push ebx
+ push esi
+ push edi
+
+ mov esi, [esp + 20] ; esi = residual[]
+ mov edi, [esp + 40] ; edi = data[]
+ mov eax, [esp + 32] ; eax = order
+ mov ebx, [esp + 24] ; ebx = data_len
+
+ test ebx, ebx
+ jz near .end ; do nothing if data_len == 0
+
+.begin:
+ cmp eax, byte 1
+ jg short .x87_1more
+
+ mov ecx, [esp + 28]
+ mov edx, [ecx]
+ mov eax, [edi - 4]
+ mov cl, [esp + 36]
+ ALIGN 16
+.x87_1_loop_i:
+ imul eax, edx
+ sar eax, cl
+ add eax, [esi]
+ mov [edi], eax
+ add esi, byte 4
+ add edi, byte 4
+ dec ebx
+ jnz .x87_1_loop_i
+
+ jmp .end
+
+.x87_1more:
+ cmp eax, byte 32 ; for order <= 32 there is a faster routine
+ jbe short .x87_32
+
+ ; This version is here just for completeness, since FLAC__MAX_LPC_ORDER == 32
+ ALIGN 16
+.x87_32more_loop_i:
+ xor ebp, ebp
+ mov ecx, [esp + 32]
+ mov edx, ecx
+ shl edx, 2
+ add edx, [esp + 28]
+ neg ecx
+ ALIGN 16
+.x87_32more_loop_j:
+ sub edx, byte 4
+ mov eax, [edx]
+ imul eax, [edi + 4 * ecx]
+ add ebp, eax
+ inc ecx
+ jnz short .x87_32more_loop_j
+
+ mov cl, [esp + 36]
+ sar ebp, cl
+ add ebp, [esi]
+ mov [edi], ebp
+ add edi, byte 4
+ add esi, byte 4
+
+ dec ebx
+ jnz .x87_32more_loop_i
+
+ jmp .end
+
+.x87_32:
+ sub esi, edi
+ neg eax
+ lea edx, [eax + eax * 8 + .jumper_0 - .get_eip0]
+ call .get_eip0
+.get_eip0:
+ pop eax
+ add edx, eax
+ inc edx ; compensate for the shorter opcode on the last iteration
+ mov eax, [esp + 28] ; eax = qlp_coeff[]
+ xor ebp, ebp
+ jmp edx
+
+ mov ecx, [eax + 124] ; ecx = qlp_coeff[31]
+ imul ecx, [edi - 128] ; ecx = qlp_coeff[31] * data[i-32]
+ add ebp, ecx ; sum += qlp_coeff[31] * data[i-32]
+ mov ecx, [eax + 120] ; ecx = qlp_coeff[30]
+ imul ecx, [edi - 124] ; ecx = qlp_coeff[30] * data[i-31]
+ add ebp, ecx ; sum += qlp_coeff[30] * data[i-31]
+ mov ecx, [eax + 116] ; ecx = qlp_coeff[29]
+ imul ecx, [edi - 120] ; ecx = qlp_coeff[29] * data[i-30]
+ add ebp, ecx ; sum += qlp_coeff[29] * data[i-30]
+ mov ecx, [eax + 112] ; ecx = qlp_coeff[28]
+ imul ecx, [edi - 116] ; ecx = qlp_coeff[28] * data[i-29]
+ add ebp, ecx ; sum += qlp_coeff[28] * data[i-29]
+ mov ecx, [eax + 108] ; ecx = qlp_coeff[27]
+ imul ecx, [edi - 112] ; ecx = qlp_coeff[27] * data[i-28]
+ add ebp, ecx ; sum += qlp_coeff[27] * data[i-28]
+ mov ecx, [eax + 104] ; ecx = qlp_coeff[26]
+ imul ecx, [edi - 108] ; ecx = qlp_coeff[26] * data[i-27]
+ add ebp, ecx ; sum += qlp_coeff[26] * data[i-27]
+ mov ecx, [eax + 100] ; ecx = qlp_coeff[25]
+ imul ecx, [edi - 104] ; ecx = qlp_coeff[25] * data[i-26]
+ add ebp, ecx ; sum += qlp_coeff[25] * data[i-26]
+ mov ecx, [eax + 96] ; ecx = qlp_coeff[24]
+ imul ecx, [edi - 100] ; ecx = qlp_coeff[24] * data[i-25]
+ add ebp, ecx ; sum += qlp_coeff[24] * data[i-25]
+ mov ecx, [eax + 92] ; ecx = qlp_coeff[23]
+ imul ecx, [edi - 96] ; ecx = qlp_coeff[23] * data[i-24]
+ add ebp, ecx ; sum += qlp_coeff[23] * data[i-24]
+ mov ecx, [eax + 88] ; ecx = qlp_coeff[22]
+ imul ecx, [edi - 92] ; ecx = qlp_coeff[22] * data[i-23]
+ add ebp, ecx ; sum += qlp_coeff[22] * data[i-23]
+ mov ecx, [eax + 84] ; ecx = qlp_coeff[21]
+ imul ecx, [edi - 88] ; ecx = qlp_coeff[21] * data[i-22]
+ add ebp, ecx ; sum += qlp_coeff[21] * data[i-22]
+ mov ecx, [eax + 80] ; ecx = qlp_coeff[20]
+ imul ecx, [edi - 84] ; ecx = qlp_coeff[20] * data[i-21]
+ add ebp, ecx ; sum += qlp_coeff[20] * data[i-21]
+ mov ecx, [eax + 76] ; ecx = qlp_coeff[19]
+ imul ecx, [edi - 80] ; ecx = qlp_coeff[19] * data[i-20]
+ add ebp, ecx ; sum += qlp_coeff[19] * data[i-20]
+ mov ecx, [eax + 72] ; ecx = qlp_coeff[18]
+ imul ecx, [edi - 76] ; ecx = qlp_coeff[18] * data[i-19]
+ add ebp, ecx ; sum += qlp_coeff[18] * data[i-19]
+ mov ecx, [eax + 68] ; ecx = qlp_coeff[17]
+ imul ecx, [edi - 72] ; ecx = qlp_coeff[17] * data[i-18]
+ add ebp, ecx ; sum += qlp_coeff[17] * data[i-18]
+ mov ecx, [eax + 64] ; ecx = qlp_coeff[16]
+ imul ecx, [edi - 68] ; ecx = qlp_coeff[16] * data[i-17]
+ add ebp, ecx ; sum += qlp_coeff[16] * data[i-17]
+ mov ecx, [eax + 60] ; ecx = qlp_coeff[15]
+ imul ecx, [edi - 64] ; ecx = qlp_coeff[15] * data[i-16]
+ add ebp, ecx ; sum += qlp_coeff[15] * data[i-16]
+ mov ecx, [eax + 56] ; ecx = qlp_coeff[14]
+ imul ecx, [edi - 60] ; ecx = qlp_coeff[14] * data[i-15]
+ add ebp, ecx ; sum += qlp_coeff[14] * data[i-15]
+ mov ecx, [eax + 52] ; ecx = qlp_coeff[13]
+ imul ecx, [edi - 56] ; ecx = qlp_coeff[13] * data[i-14]
+ add ebp, ecx ; sum += qlp_coeff[13] * data[i-14]
+ mov ecx, [eax + 48] ; ecx = qlp_coeff[12]
+ imul ecx, [edi - 52] ; ecx = qlp_coeff[12] * data[i-13]
+ add ebp, ecx ; sum += qlp_coeff[12] * data[i-13]
+ mov ecx, [eax + 44] ; ecx = qlp_coeff[11]
+ imul ecx, [edi - 48] ; ecx = qlp_coeff[11] * data[i-12]
+ add ebp, ecx ; sum += qlp_coeff[11] * data[i-12]
+ mov ecx, [eax + 40] ; ecx = qlp_coeff[10]
+ imul ecx, [edi - 44] ; ecx = qlp_coeff[10] * data[i-11]
+ add ebp, ecx ; sum += qlp_coeff[10] * data[i-11]
+ mov ecx, [eax + 36] ; ecx = qlp_coeff[ 9]
+ imul ecx, [edi - 40] ; ecx = qlp_coeff[ 9] * data[i-10]
+ add ebp, ecx ; sum += qlp_coeff[ 9] * data[i-10]
+ mov ecx, [eax + 32] ; ecx = qlp_coeff[ 8]
+ imul ecx, [edi - 36] ; ecx = qlp_coeff[ 8] * data[i- 9]
+ add ebp, ecx ; sum += qlp_coeff[ 8] * data[i- 9]
+ mov ecx, [eax + 28] ; ecx = qlp_coeff[ 7]
+ imul ecx, [edi - 32] ; ecx = qlp_coeff[ 7] * data[i- 8]
+ add ebp, ecx ; sum += qlp_coeff[ 7] * data[i- 8]
+ mov ecx, [eax + 24] ; ecx = qlp_coeff[ 6]
+ imul ecx, [edi - 28] ; ecx = qlp_coeff[ 6] * data[i- 7]
+ add ebp, ecx ; sum += qlp_coeff[ 6] * data[i- 7]
+ mov ecx, [eax + 20] ; ecx = qlp_coeff[ 5]
+ imul ecx, [edi - 24] ; ecx = qlp_coeff[ 5] * data[i- 6]
+ add ebp, ecx ; sum += qlp_coeff[ 5] * data[i- 6]
+ mov ecx, [eax + 16] ; ecx = qlp_coeff[ 4]
+ imul ecx, [edi - 20] ; ecx = qlp_coeff[ 4] * data[i- 5]
+ add ebp, ecx ; sum += qlp_coeff[ 4] * data[i- 5]
+ mov ecx, [eax + 12] ; ecx = qlp_coeff[ 3]
+ imul ecx, [edi - 16] ; ecx = qlp_coeff[ 3] * data[i- 4]
+ add ebp, ecx ; sum += qlp_coeff[ 3] * data[i- 4]
+ mov ecx, [eax + 8] ; ecx = qlp_coeff[ 2]
+ imul ecx, [edi - 12] ; ecx = qlp_coeff[ 2] * data[i- 3]
+ add ebp, ecx ; sum += qlp_coeff[ 2] * data[i- 3]
+ mov ecx, [eax + 4] ; ecx = qlp_coeff[ 1]
+ imul ecx, [edi - 8] ; ecx = qlp_coeff[ 1] * data[i- 2]
+ add ebp, ecx ; sum += qlp_coeff[ 1] * data[i- 2]
+ mov ecx, [eax] ; ecx = qlp_coeff[ 0] (NOTE: one byte missing from instruction)
+ imul ecx, [edi - 4] ; ecx = qlp_coeff[ 0] * data[i- 1]
+ add ebp, ecx ; sum += qlp_coeff[ 0] * data[i- 1]
+.jumper_0:
+
+ mov cl, [esp + 36]
+ sar ebp, cl ; ebp = (sum >> lp_quantization)
+ add ebp, [esi + edi] ; ebp = residual[i] + (sum >> lp_quantization)
+ mov [edi], ebp ; data[i] = residual[i] + (sum >> lp_quantization)
+ add edi, byte 4
+
+ dec ebx
+ jz short .end
+ xor ebp, ebp
+ jmp edx
+
+.end:
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+; WATCHOUT: this routine works on 16 bit data which means bits-per-sample for
+; the channel and qlp_coeffs must be <= 16. Especially note that this routine
+; cannot be used for side-channel coded 16bps channels since the effective bps
+; is 17.
+; WATCHOUT: this routine requires that each data array have a buffer of up to
+; 3 zeroes in front (at negative indices) for alignment purposes, i.e. for each
+; channel n, data[n][-1] through data[n][-3] should be accessible and zero.
+ ALIGN 16
+cident FLAC__lpc_restore_signal_asm_ia32_mmx
+ ;[esp + 40] data[]
+ ;[esp + 36] lp_quantization
+ ;[esp + 32] order
+ ;[esp + 28] qlp_coeff[]
+ ;[esp + 24] data_len
+ ;[esp + 20] residual[]
+
+ ;ASSERT(order > 0)
+
+ push ebp
+ push ebx
+ push esi
+ push edi
+
+ mov esi, [esp + 20]
+ mov edi, [esp + 40]
+ mov eax, [esp + 32]
+ mov ebx, [esp + 24]
+
+ test ebx, ebx
+ jz near .end ; do nothing if data_len == 0
+ cmp eax, byte 4
+ jb near FLAC__lpc_restore_signal_asm_ia32.begin
+
+ mov edx, [esp + 28]
+ movd mm6, [esp + 36]
+ mov ebp, esp
+
+ and esp, 0xfffffff8
+
+ xor ecx, ecx
+.copy_qlp_loop:
+ push word [edx + 4 * ecx]
+ inc ecx
+ cmp ecx, eax
+ jnz short .copy_qlp_loop
+
+ and ecx, 0x3
+ test ecx, ecx
+ je short .za_end
+ sub ecx, byte 4
+.za_loop:
+ push word 0
+ inc eax
+ inc ecx
+ jnz short .za_loop
+.za_end:
+
+ movq mm5, [esp + 2 * eax - 8]
+ movd mm4, [edi - 16]
+ punpckldq mm4, [edi - 12]
+ movd mm0, [edi - 8]
+ punpckldq mm0, [edi - 4]
+ packssdw mm4, mm0
+
+ cmp eax, byte 4
+ jnbe short .mmx_4more
+
+ ALIGN 16
+.mmx_4_loop_i:
+ movq mm7, mm4
+ pmaddwd mm7, mm5
+ movq mm0, mm7
+ punpckhdq mm7, mm7
+ paddd mm7, mm0
+ psrad mm7, mm6
+ movd mm1, [esi]
+ paddd mm7, mm1
+ movd [edi], mm7
+ psllq mm7, 48
+ psrlq mm4, 16
+ por mm4, mm7
+
+ add esi, byte 4
+ add edi, byte 4
+
+ dec ebx
+ jnz .mmx_4_loop_i
+ jmp .mmx_end
+.mmx_4more:
+ shl eax, 2
+ neg eax
+ add eax, byte 16
+ ALIGN 16
+.mmx_4more_loop_i:
+ mov ecx, edi
+ add ecx, eax
+ mov edx, esp
+
+ movq mm7, mm4
+ pmaddwd mm7, mm5
+
+ ALIGN 16
+.mmx_4more_loop_j:
+ movd mm0, [ecx - 16]
+ punpckldq mm0, [ecx - 12]
+ movd mm1, [ecx - 8]
+ punpckldq mm1, [ecx - 4]
+ packssdw mm0, mm1
+ pmaddwd mm0, [edx]
+ paddd mm7, mm0
+
+ add edx, byte 8
+ add ecx, byte 16
+ cmp ecx, edi
+ jnz .mmx_4more_loop_j
+
+ movq mm0, mm7
+ punpckhdq mm7, mm7
+ paddd mm7, mm0
+ psrad mm7, mm6
+ movd mm1, [esi]
+ paddd mm7, mm1
+ movd [edi], mm7
+ psllq mm7, 48
+ psrlq mm4, 16
+ por mm4, mm7
+
+ add esi, byte 4
+ add edi, byte 4
+
+ dec ebx
+ jnz short .mmx_4more_loop_i
+.mmx_end:
+ emms
+ mov esp, ebp
+
+.end:
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+ section .note.GNU-stack noalloc
+%endif
diff --git a/src/FLAC/src/libFLAC/ia32/nasm.h b/src/FLAC/src/libFLAC/ia32/nasm.h
new file mode 100644
index 0000000..215498d
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ia32/nasm.h
@@ -0,0 +1,75 @@
+; libFLAC - Free Lossless Audio Codec library
+; Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+;
+; 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.
+
+ bits 32
+
+%ifdef OBJ_FORMAT_win32
+ %define FLAC__PUBLIC_NEEDS_UNDERSCORE
+ %idefine code_section section .text align=16 class=CODE use32
+ %idefine data_section section .data align=32 class=DATA use32
+ %idefine bss_section section .bss align=32 class=DATA use32
+%elifdef OBJ_FORMAT_aout
+ %define FLAC__PUBLIC_NEEDS_UNDERSCORE
+ %idefine code_section section .text
+ %idefine data_section section .data
+ %idefine bss_section section .bss
+%elifdef OBJ_FORMAT_aoutb
+ %define FLAC__PUBLIC_NEEDS_UNDERSCORE
+ %idefine code_section section .text
+ %idefine data_section section .data
+ %idefine bss_section section .bss
+%elifdef OBJ_FORMAT_elf
+ %idefine code_section section .text align=16
+ %idefine data_section section .data align=32
+ %idefine bss_section section .bss align=32
+%else
+ %error unsupported object format!
+%endif
+
+%imacro cglobal 1
+ %ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ global _%1
+ %else
+ global %1
+ %endif
+%endmacro
+
+%imacro cextern 1
+ %ifdef FLAC__PUBLIC_NEEDS_UNDERSCORE
+ extern _%1
+ %else
+ extern %1
+ %endif
+%endmacro
+
+%imacro cident 1
+_%1:
+%1:
+%endmacro
diff --git a/src/FLAC/src/libFLAC/ia32/stream_encoder_asm.nasm b/src/FLAC/src/libFLAC/ia32/stream_encoder_asm.nasm
new file mode 100644
index 0000000..da2d0e6
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ia32/stream_encoder_asm.nasm
@@ -0,0 +1,157 @@
+; vim:filetype=nasm ts=8
+
+; libFLAC - Free Lossless Audio Codec library
+; Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+;
+; 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 "nasm.h"
+
+ data_section
+
+cglobal precompute_partition_info_sums_32bit_asm_ia32_
+
+ code_section
+
+
+; **********************************************************************
+;
+; void FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter)
+; void precompute_partition_info_sums_32bit_(
+; const FLAC__int32 residual[],
+; FLAC__uint64 abs_residual_partition_sums[],
+; unsigned blocksize,
+; unsigned predictor_order,
+; unsigned min_partition_order,
+; unsigned max_partition_order
+; )
+;
+ ALIGN 16
+cident precompute_partition_info_sums_32bit_asm_ia32_
+
+ ;; peppered throughout the code at major checkpoints are keys like this as to where things are at that point in time
+ ;; [esp + 4] const FLAC__int32 residual[]
+ ;; [esp + 8] FLAC__uint64 abs_residual_partition_sums[]
+ ;; [esp + 12] unsigned blocksize
+ ;; [esp + 16] unsigned predictor_order
+ ;; [esp + 20] unsigned min_partition_order
+ ;; [esp + 24] unsigned max_partition_order
+ push ebp
+ push ebx
+ push esi
+ push edi
+ sub esp, 8
+ ;; [esp + 28] const FLAC__int32 residual[]
+ ;; [esp + 32] FLAC__uint64 abs_residual_partition_sums[]
+ ;; [esp + 36] unsigned blocksize
+ ;; [esp + 40] unsigned predictor_order
+ ;; [esp + 44] unsigned min_partition_order
+ ;; [esp + 48] unsigned max_partition_order
+ ;; [esp] partitions
+ ;; [esp + 4] default_partition_samples
+
+ mov ecx, [esp + 48]
+ mov eax, 1
+ shl eax, cl
+ mov [esp], eax ; [esp] <- partitions = 1u << max_partition_order;
+ mov eax, [esp + 36]
+ shr eax, cl
+ mov [esp + 4], eax ; [esp + 4] <- default_partition_samples = blocksize >> max_partition_order;
+
+ ;
+ ; first do max_partition_order
+ ;
+ mov edi, [esp + 4]
+ sub edi, [esp + 40] ; edi <- end = (unsigned)(-(int)predictor_order) + default_partition_samples
+ xor esi, esi ; esi <- residual_sample = 0
+ xor ecx, ecx ; ecx <- partition = 0
+ mov ebp, [esp + 28] ; ebp <- residual[]
+ xor ebx, ebx ; ebx <- abs_residual_partition_sum = 0;
+ ; note we put the updates to 'end' and 'abs_residual_partition_sum' at the end of loop0 and in the initialization above so we could align loop0 and loop1
+ ALIGN 16
+.loop0: ; for(partition = residual_sample = 0; partition < partitions; partition++) {
+.loop1: ; for( ; residual_sample < end; residual_sample++)
+ mov eax, [ebp + esi * 4]
+ cdq
+ xor eax, edx
+ sub eax, edx
+ add ebx, eax ; abs_residual_partition_sum += abs(residual[residual_sample]);
+ add esi, byte 1
+ cmp esi, edi ; /* since the loop will always run at least once, we can put the loop check down here */
+ jb .loop1
+.next1:
+ add edi, [esp + 4] ; end += default_partition_samples;
+ mov eax, [esp + 32]
+ mov [eax + ecx * 8], ebx ; abs_residual_partition_sums[partition] = abs_residual_partition_sum;
+ mov [eax + ecx * 8 + 4], dword 0
+ xor ebx, ebx ; abs_residual_partition_sum = 0;
+ add ecx, byte 1
+ cmp ecx, [esp] ; /* since the loop will always run at least once, we can put the loop check down here */
+ jb .loop0
+.next0: ; }
+ ;
+ ; now merge partitions for lower orders
+ ;
+ mov esi, [esp + 32] ; esi <- abs_residual_partition_sums[from_partition==0];
+ mov eax, [esp]
+ lea edi, [esi + eax * 8] ; edi <- abs_residual_partition_sums[to_partition==partitions];
+ mov ecx, [esp + 48]
+ sub ecx, byte 1 ; ecx <- partition_order = (int)max_partition_order - 1;
+ ALIGN 16
+.loop2: ; for(; partition_order >= (int)min_partition_order; partition_order--) {
+ cmp ecx, [esp + 44]
+ jl .next2
+ mov edx, 1
+ shl edx, cl ; const unsigned partitions = 1u << partition_order;
+ ALIGN 16
+.loop3: ; for(i = 0; i < partitions; i++) {
+ mov eax, [esi]
+ mov [edi + 4], dword 0
+ mov [edi], eax
+ mov ebx, [esi + 8]
+ add [edi], ebx ; a_r_p_s[to_partition] = a_r_p_s[from_partition] + a_r_p_s[from_partition+1];
+ add esi, byte 16
+ add edi, byte 8
+ sub edx, byte 1
+ jnz .loop3 ; }
+ sub ecx, byte 1
+ jmp .loop2 ; }
+.next2:
+
+ add esp, 8
+ pop edi
+ pop esi
+ pop ebx
+ pop ebp
+ ret
+
+end
+
+%ifdef OBJ_FORMAT_elf
+ section .note.GNU-stack noalloc
+%endif
diff --git a/src/FLAC/src/libFLAC/include/Makefile.am b/src/FLAC/src/libFLAC/include/Makefile.am
new file mode 100644
index 0000000..866a894
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/Makefile.am
@@ -0,0 +1,31 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+SUBDIRS = private protected
diff --git a/src/FLAC/src/libFLAC/include/private/Makefile.am b/src/FLAC/src/libFLAC/include/private/Makefile.am
new file mode 100644
index 0000000..e8abc58
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/Makefile.am
@@ -0,0 +1,50 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+noinst_HEADERS = \
+ all.h \
+ bitmath.h \
+ bitreader.h \
+ bitwriter.h \
+ cpu.h \
+ crc.h \
+ fixed.h \
+ float.h \
+ format.h \
+ lpc.h \
+ md5.h \
+ memory.h \
+ metadata.h \
+ ogg_decoder_aspect.h \
+ ogg_encoder_aspect.h \
+ ogg_helper.h \
+ ogg_mapping.h \
+ stream_encoder_framing.h \
+ window.h
diff --git a/src/FLAC/src/libFLAC/include/private/all.h b/src/FLAC/src/libFLAC/include/private/all.h
new file mode 100644
index 0000000..304c471
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/all.h
@@ -0,0 +1,49 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__ALL_H
+#define FLAC__PRIVATE__ALL_H
+
+#include "bitmath.h"
+#include "bitreader.h"
+#include "bitwriter.h"
+#include "cpu.h"
+#include "crc.h"
+#include "fixed.h"
+#include "float.h"
+#include "format.h"
+#include "lpc.h"
+#include "md5.h"
+#include "memory.h"
+#include "metadata.h"
+#include "stream_encoder_framing.h"
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/bitmath.h b/src/FLAC/src/libFLAC/include/private/bitmath.h
new file mode 100644
index 0000000..87fa0fa
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/bitmath.h
@@ -0,0 +1,42 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__BITMATH_H
+#define FLAC__PRIVATE__BITMATH_H
+
+#include "FLAC/ordinals.h"
+
+unsigned FLAC__bitmath_ilog2(FLAC__uint32 v);
+unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v);
+unsigned FLAC__bitmath_silog2(int v);
+unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/bitreader.h b/src/FLAC/src/libFLAC/include/private/bitreader.h
new file mode 100644
index 0000000..1ad9742
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/bitreader.h
@@ -0,0 +1,99 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__BITREADER_H
+#define FLAC__PRIVATE__BITREADER_H
+
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+#include "cpu.h"
+
+/*
+ * opaque structure definition
+ */
+struct FLAC__BitReader;
+typedef struct FLAC__BitReader FLAC__BitReader;
+
+typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+/*
+ * construction, deletion, initialization, etc functions
+ */
+FLAC__BitReader *FLAC__bitreader_new(void);
+void FLAC__bitreader_delete(FLAC__BitReader *br);
+FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__CPUInfo cpu, FLAC__BitReaderReadCallback rcb, void *cd);
+void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */
+FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br);
+void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out);
+
+/*
+ * CRC functions
+ */
+void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed);
+FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br);
+
+/*
+ * info functions
+ */
+FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br);
+unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br);
+unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br);
+
+/*
+ * read functions
+ */
+
+FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, unsigned bits);
+FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, unsigned bits);
+FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, unsigned bits);
+FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/
+FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, unsigned bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */
+FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, unsigned nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, unsigned nvals); /* WATCHOUT: does not CRC the read data! */
+FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val);
+FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter);
+FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter);
+#ifndef FLAC__NO_ASM
+# ifdef FLAC__CPU_IA32
+# ifdef FLAC__HAS_NASM
+FLAC__bool FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter);
+# endif
+# endif
+#endif
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter);
+FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter);
+#endif
+FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen);
+FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen);
+
+FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br);//@@@@@@
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/bitwriter.h b/src/FLAC/src/libFLAC/include/private/bitwriter.h
new file mode 100644
index 0000000..aa5c4f7
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/bitwriter.h
@@ -0,0 +1,103 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__BITWRITER_H
+#define FLAC__PRIVATE__BITWRITER_H
+
+#include <stdio.h> /* for FILE */
+#include "FLAC/ordinals.h"
+
+/*
+ * opaque structure definition
+ */
+struct FLAC__BitWriter;
+typedef struct FLAC__BitWriter FLAC__BitWriter;
+
+/*
+ * construction, deletion, initialization, etc functions
+ */
+FLAC__BitWriter *FLAC__bitwriter_new(void);
+void FLAC__bitwriter_delete(FLAC__BitWriter *bw);
+FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw);
+void FLAC__bitwriter_free(FLAC__BitWriter *bw); /* does not 'free(buffer)' */
+void FLAC__bitwriter_clear(FLAC__BitWriter *bw);
+void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out);
+
+/*
+ * CRC functions
+ *
+ * non-const *bw because they have to cal FLAC__bitwriter_get_buffer()
+ */
+FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc);
+FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc);
+
+/*
+ * info functions
+ */
+FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw);
+unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw); /* can be called anytime, returns total # of bits unconsumed */
+
+/*
+ * direct buffer access
+ *
+ * there may be no calls on the bitwriter between get and release.
+ * the bitwriter continues to own the returned buffer.
+ * before get, bitwriter MUST be byte aligned: check with FLAC__bitwriter_is_byte_aligned()
+ */
+FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes);
+void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw);
+
+/*
+ * write functions
+ */
+FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits);
+FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); /*only for bits=32*/
+FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals);
+FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val);
+unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter);
+#if 0 /* UNUSED */
+unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter);
+unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned val, unsigned parameter);
+#endif
+FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter);
+FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter);
+#if 0 /* UNUSED */
+FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter);
+FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned val, unsigned parameter);
+#endif
+FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val);
+FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val);
+FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/cpu.h b/src/FLAC/src/libFLAC/include/private/cpu.h
new file mode 100644
index 0000000..651bb22
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/cpu.h
@@ -0,0 +1,88 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__CPU_H
+#define FLAC__PRIVATE__CPU_H
+
+#include "FLAC/ordinals.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+typedef enum {
+ FLAC__CPUINFO_TYPE_IA32,
+ FLAC__CPUINFO_TYPE_PPC,
+ FLAC__CPUINFO_TYPE_UNKNOWN
+} FLAC__CPUInfo_Type;
+
+typedef struct {
+ FLAC__bool cpuid;
+ FLAC__bool bswap;
+ FLAC__bool cmov;
+ FLAC__bool mmx;
+ FLAC__bool fxsr;
+ FLAC__bool sse;
+ FLAC__bool sse2;
+ FLAC__bool sse3;
+ FLAC__bool ssse3;
+ FLAC__bool _3dnow;
+ FLAC__bool ext3dnow;
+ FLAC__bool extmmx;
+} FLAC__CPUInfo_IA32;
+
+typedef struct {
+ FLAC__bool altivec;
+ FLAC__bool ppc64;
+} FLAC__CPUInfo_PPC;
+
+typedef struct {
+ FLAC__bool use_asm;
+ FLAC__CPUInfo_Type type;
+ union {
+ FLAC__CPUInfo_IA32 ia32;
+ FLAC__CPUInfo_PPC ppc;
+ } data;
+} FLAC__CPUInfo;
+
+void FLAC__cpu_info(FLAC__CPUInfo *info);
+
+#ifndef FLAC__NO_ASM
+#ifdef FLAC__CPU_IA32
+#ifdef FLAC__HAS_NASM
+FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void);
+void FLAC__cpu_info_asm_ia32(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx);
+FLAC__uint32 FLAC__cpu_info_extended_amd_asm_ia32(void);
+#endif
+#endif
+#endif
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/crc.h b/src/FLAC/src/libFLAC/include/private/crc.h
new file mode 100644
index 0000000..0b67fb4
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/crc.h
@@ -0,0 +1,61 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__CRC_H
+#define FLAC__PRIVATE__CRC_H
+
+#include "FLAC/ordinals.h"
+
+/* 8 bit CRC generator, MSB shifted first
+** polynomial = x^8 + x^2 + x^1 + x^0
+** init = 0
+*/
+extern FLAC__byte const FLAC__crc8_table[256];
+#define FLAC__CRC8_UPDATE(data, crc) (crc) = FLAC__crc8_table[(crc) ^ (data)];
+void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc);
+void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc);
+FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len);
+
+/* 16 bit CRC generator, MSB shifted first
+** polynomial = x^16 + x^15 + x^2 + x^0
+** init = 0
+*/
+extern unsigned FLAC__crc16_table[256];
+
+#define FLAC__CRC16_UPDATE(data, crc) (((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]))
+/* this alternate may be faster on some systems/compilers */
+#if 0
+#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]) & 0xffff)
+#endif
+
+unsigned FLAC__crc16(const FLAC__byte *data, unsigned len);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/fixed.h b/src/FLAC/src/libFLAC/include/private/fixed.h
new file mode 100644
index 0000000..6656b79
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/fixed.h
@@ -0,0 +1,97 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FIXED_H
+#define FLAC__PRIVATE__FIXED_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "private/float.h"
+#include "FLAC/format.h"
+
+/*
+ * FLAC__fixed_compute_best_predictor()
+ * --------------------------------------------------------------------
+ * Compute the best fixed predictor and the expected bits-per-sample
+ * of the residual signal for each order. The _wide() version uses
+ * 64-bit integers which is statistically necessary when bits-per-
+ * sample + log2(blocksize) > 30
+ *
+ * IN data[0,data_len-1]
+ * IN data_len
+ * OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER]
+ */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+# ifndef FLAC__NO_ASM
+# ifdef FLAC__CPU_IA32
+# ifdef FLAC__HAS_NASM
+unsigned FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+# endif
+# endif
+# endif
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#else
+unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#endif
+
+/*
+ * FLAC__fixed_compute_residual()
+ * --------------------------------------------------------------------
+ * Compute the residual signal obtained from sutracting the predicted
+ * signal from the original.
+ *
+ * IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
+ * IN data_len length of original signal
+ * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ * OUT residual[0,data_len-1] residual signal
+ */
+void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]);
+
+/*
+ * FLAC__fixed_restore_signal()
+ * --------------------------------------------------------------------
+ * Restore the original signal by summing the residual and the
+ * predictor.
+ *
+ * IN residual[0,data_len-1] residual signal
+ * IN data_len length of original signal
+ * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order
+ * *** IMPORTANT: the caller must pass in the historical samples:
+ * IN data[-order,-1] previously-reconstructed historical samples
+ * OUT data[0,data_len-1] original signal
+ */
+void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[]);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/float.h b/src/FLAC/src/libFLAC/include/private/float.h
new file mode 100644
index 0000000..73313f6
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/float.h
@@ -0,0 +1,97 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FLOAT_H
+#define FLAC__PRIVATE__FLOAT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "FLAC/ordinals.h"
+
+/*
+ * These typedefs make it easier to ensure that integer versions of
+ * the library really only contain integer operations. All the code
+ * in libFLAC should use FLAC__float and FLAC__double in place of
+ * float and double, and be protected by checks of the macro
+ * FLAC__INTEGER_ONLY_LIBRARY.
+ *
+ * FLAC__real is the basic floating point type used in LPC analysis.
+ */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+typedef double FLAC__double;
+typedef float FLAC__float;
+/*
+ * WATCHOUT: changing FLAC__real will change the signatures of many
+ * functions that have assembly language equivalents and break them.
+ */
+typedef float FLAC__real;
+#else
+/*
+ * The convention for FLAC__fixedpoint is to use the upper 16 bits
+ * for the integer part and lower 16 bits for the fractional part.
+ */
+typedef FLAC__int32 FLAC__fixedpoint;
+extern const FLAC__fixedpoint FLAC__FP_ZERO;
+extern const FLAC__fixedpoint FLAC__FP_ONE_HALF;
+extern const FLAC__fixedpoint FLAC__FP_ONE;
+extern const FLAC__fixedpoint FLAC__FP_LN2;
+extern const FLAC__fixedpoint FLAC__FP_E;
+
+#define FLAC__fixedpoint_trunc(x) ((x)>>16)
+
+#define FLAC__fixedpoint_mul(x, y) ( (FLAC__fixedpoint) ( ((FLAC__int64)(x)*(FLAC__int64)(y)) >> 16 ) )
+
+#define FLAC__fixedpoint_div(x, y) ( (FLAC__fixedpoint) ( ( ((FLAC__int64)(x)<<32) / (FLAC__int64)(y) ) >> 16 ) )
+
+/*
+ * FLAC__fixedpoint_log2()
+ * --------------------------------------------------------------------
+ * Returns the base-2 logarithm of the fixed-point number 'x' using an
+ * algorithm by Knuth for x >= 1.0
+ *
+ * 'fracbits' is the number of fractional bits of 'x'. 'fracbits' must
+ * be < 32 and evenly divisible by 4 (0 is OK but not very precise).
+ *
+ * 'precision' roughly limits the number of iterations that are done;
+ * use (unsigned)(-1) for maximum precision.
+ *
+ * If 'x' is less than one -- that is, x < (1<<fracbits) -- then this
+ * function will punt and return 0.
+ *
+ * The return value will also have 'fracbits' fractional bits.
+ */
+FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision);
+
+#endif
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/format.h b/src/FLAC/src/libFLAC/include/private/format.h
new file mode 100644
index 0000000..7f5cc93
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/format.h
@@ -0,0 +1,44 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__FORMAT_H
+#define FLAC__PRIVATE__FORMAT_H
+
+#include "FLAC/format.h"
+
+unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order);
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize);
+unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object);
+FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/lpc.h b/src/FLAC/src/libFLAC/include/private/lpc.h
new file mode 100644
index 0000000..2cb139b
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/lpc.h
@@ -0,0 +1,214 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__LPC_H
+#define FLAC__PRIVATE__LPC_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "private/float.h"
+#include "FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ * FLAC__lpc_window_data()
+ * --------------------------------------------------------------------
+ * Applies the given window to the data.
+ * OPT: asm implementation
+ *
+ * IN in[0,data_len-1]
+ * IN window[0,data_len-1]
+ * OUT out[0,lag-1]
+ * IN data_len
+ */
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len);
+
+/*
+ * FLAC__lpc_compute_autocorrelation()
+ * --------------------------------------------------------------------
+ * Compute the autocorrelation for lags between 0 and lag-1.
+ * Assumes data[] outside of [0,data_len-1] == 0.
+ * Asserts that lag > 0.
+ *
+ * IN data[0,data_len-1]
+ * IN data_len
+ * IN 0 < lag <= data_len
+ * OUT autoc[0,lag-1]
+ */
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+#ifndef FLAC__NO_ASM
+# ifdef FLAC__CPU_IA32
+# ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+void FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+# endif
+# endif
+#endif
+
+/*
+ * FLAC__lpc_compute_lp_coefficients()
+ * --------------------------------------------------------------------
+ * Computes LP coefficients for orders 1..max_order.
+ * Do not call if autoc[0] == 0.0. This means the signal is zero
+ * and there is no point in calculating a predictor.
+ *
+ * IN autoc[0,max_order] autocorrelation values
+ * IN 0 < max_order <= FLAC__MAX_LPC_ORDER max LP order to compute
+ * OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order
+ * *** IMPORTANT:
+ * *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched
+ * OUT error[0,max_order-1] error for each order (more
+ * specifically, the variance of
+ * the error signal times # of
+ * samples in the signal)
+ *
+ * Example: if max_order is 9, the LP coefficients for order 9 will be
+ * in lp_coeff[8][0,8], the LP coefficients for order 8 will be
+ * in lp_coeff[7][0,7], etc.
+ */
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[]);
+
+/*
+ * FLAC__lpc_quantize_coefficients()
+ * --------------------------------------------------------------------
+ * Quantizes the LP coefficients. NOTE: precision + bits_per_sample
+ * must be less than 32 (sizeof(FLAC__int32)*8).
+ *
+ * IN lp_coeff[0,order-1] LP coefficients
+ * IN order LP order
+ * IN FLAC__MIN_QLP_COEFF_PRECISION < precision
+ * desired precision (in bits, including sign
+ * bit) of largest coefficient
+ * OUT qlp_coeff[0,order-1] quantized coefficients
+ * OUT shift # of bits to shift right to get approximated
+ * LP coefficients. NOTE: could be negative.
+ * RETURN 0 => quantization OK
+ * 1 => coefficients require too much shifting for *shift to
+ * fit in the LPC subframe header. 'shift' is unset.
+ * 2 => coefficients are all zero, which is bad. 'shift' is
+ * unset.
+ */
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift);
+
+/*
+ * FLAC__lpc_compute_residual_from_qlp_coefficients()
+ * --------------------------------------------------------------------
+ * Compute the residual signal obtained from sutracting the predicted
+ * signal from the original.
+ *
+ * IN data[-order,data_len-1] original signal (NOTE THE INDICES!)
+ * IN data_len length of original signal
+ * IN qlp_coeff[0,order-1] quantized LP coefficients
+ * IN order > 0 LP order
+ * IN lp_quantization quantization of LP coefficients in bits
+ * OUT residual[0,data_len-1] residual signal
+ */
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#ifndef FLAC__NO_ASM
+# ifdef FLAC__CPU_IA32
+# ifdef FLAC__HAS_NASM
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+# endif
+# endif
+#endif
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+/*
+ * FLAC__lpc_restore_signal()
+ * --------------------------------------------------------------------
+ * Restore the original signal by summing the residual and the
+ * predictor.
+ *
+ * IN residual[0,data_len-1] residual signal
+ * IN data_len length of original signal
+ * IN qlp_coeff[0,order-1] quantized LP coefficients
+ * IN order > 0 LP order
+ * IN lp_quantization quantization of LP coefficients in bits
+ * *** IMPORTANT: the caller must pass in the historical samples:
+ * IN data[-order,-1] previously-reconstructed historical samples
+ * OUT data[0,data_len-1] original signal
+ */
+void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+#ifndef FLAC__NO_ASM
+# ifdef FLAC__CPU_IA32
+# ifdef FLAC__HAS_NASM
+void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+# endif /* FLAC__HAS_NASM */
+# elif defined FLAC__CPU_PPC
+void FLAC__lpc_restore_signal_asm_ppc_altivec_16(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+void FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+# endif/* FLAC__CPU_IA32 || FLAC__CPU_PPC */
+#endif /* FLAC__NO_ASM */
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ * FLAC__lpc_compute_expected_bits_per_residual_sample()
+ * --------------------------------------------------------------------
+ * Compute the expected number of bits per residual signal sample
+ * based on the LP error (which is related to the residual variance).
+ *
+ * IN lpc_error >= 0.0 error returned from calculating LP coefficients
+ * IN total_samples > 0 # of samples in residual signal
+ * RETURN expected bits per sample
+ */
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples);
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale);
+
+/*
+ * FLAC__lpc_compute_best_order()
+ * --------------------------------------------------------------------
+ * Compute the best order from the array of signal errors returned
+ * during coefficient computation.
+ *
+ * IN lpc_error[0,max_order-1] >= 0.0 error returned from calculating LP coefficients
+ * IN max_order > 0 max LP order
+ * IN total_samples > 0 # of samples in residual signal
+ * IN overhead_bits_per_order # of bits overhead for each increased LP order
+ * (includes warmup sample size and quantized LP coefficient)
+ * RETURN [1,max_order] best order
+ */
+unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/md5.h b/src/FLAC/src/libFLAC/include/private/md5.h
new file mode 100644
index 0000000..659912c
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/md5.h
@@ -0,0 +1,44 @@
+#ifndef FLAC__PRIVATE__MD5_H
+#define FLAC__PRIVATE__MD5_H
+
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ * - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain, with no warranty.
+ */
+
+#include "FLAC/ordinals.h"
+
+typedef struct {
+ FLAC__uint32 in[16];
+ FLAC__uint32 buf[4];
+ FLAC__uint32 bytes[2];
+ FLAC__byte *internal_buf;
+ unsigned capacity;
+} FLAC__MD5Context;
+
+void FLAC__MD5Init(FLAC__MD5Context *context);
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context);
+
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/memory.h b/src/FLAC/src/libFLAC/include/private/memory.h
new file mode 100644
index 0000000..7852c81
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/memory.h
@@ -0,0 +1,56 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__MEMORY_H
+#define FLAC__PRIVATE__MEMORY_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h> /* for size_t */
+
+#include "private/float.h"
+#include "FLAC/ordinals.h" /* for FLAC__bool */
+
+/* Returns the unaligned address returned by malloc.
+ * Use free() on this address to deallocate.
+ */
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address);
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer);
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer);
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer);
+#endif
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/metadata.h b/src/FLAC/src/libFLAC/include/private/metadata.h
new file mode 100644
index 0000000..b5268c9
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/metadata.h
@@ -0,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__METADATA_H
+#define FLAC__PRIVATE__METADATA_H
+
+#include "FLAC/metadata.h"
+
+/* WATCHOUT: all malloc()ed data in the block is free()ed; this may not
+ * be a consistent state (e.g. PICTURE) or equivalent to the initial
+ * state after FLAC__metadata_object_new()
+ */
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object);
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/ogg_decoder_aspect.h b/src/FLAC/src/libFLAC/include/private/ogg_decoder_aspect.h
new file mode 100644
index 0000000..df2b6b5
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/ogg_decoder_aspect.h
@@ -0,0 +1,79 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__OGG_DECODER_ASPECT_H
+#define FLAC__PRIVATE__OGG_DECODER_ASPECT_H
+
+#include <ogg/ogg.h>
+
+#include "FLAC/ordinals.h"
+#include "FLAC/stream_decoder.h" /* for FLAC__StreamDecoderReadStatus */
+
+typedef struct FLAC__OggDecoderAspect {
+ /* these are storage for values that can be set through the API */
+ FLAC__bool use_first_serial_number;
+ long serial_number;
+
+ /* these are for internal state related to Ogg decoding */
+ ogg_stream_state stream_state;
+ ogg_sync_state sync_state;
+ unsigned version_major, version_minor;
+ FLAC__bool need_serial_number;
+ FLAC__bool end_of_stream;
+ FLAC__bool have_working_page; /* only if true will the following vars be valid */
+ ogg_page working_page;
+ FLAC__bool have_working_packet; /* only if true will the following vars be valid */
+ ogg_packet working_packet; /* as we work through the packet we will move working_packet.packet forward and working_packet.bytes down */
+} FLAC__OggDecoderAspect;
+
+void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value);
+void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect);
+FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect);
+void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect);
+void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect);
+void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect);
+
+typedef enum {
+ FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK = 0,
+ FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM,
+ FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC,
+ FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC,
+ FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION,
+ FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT,
+ FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR,
+ FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR
+} FLAC__OggDecoderAspectReadStatus;
+
+typedef FLAC__OggDecoderAspectReadStatus (*FLAC__OggDecoderAspectReadCallbackProxy)(const void *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+
+FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/ogg_encoder_aspect.h b/src/FLAC/src/libFLAC/include/private/ogg_encoder_aspect.h
new file mode 100644
index 0000000..290da07
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/ogg_encoder_aspect.h
@@ -0,0 +1,62 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__OGG_ENCODER_ASPECT_H
+#define FLAC__PRIVATE__OGG_ENCODER_ASPECT_H
+
+#include <ogg/ogg.h>
+
+#include "FLAC/ordinals.h"
+#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoderWriteStatus */
+
+typedef struct FLAC__OggEncoderAspect {
+ /* these are storage for values that can be set through the API */
+ long serial_number;
+ unsigned num_metadata;
+
+ /* these are for internal state related to Ogg encoding */
+ ogg_stream_state stream_state;
+ ogg_page page;
+ FLAC__bool seen_magic; /* true if we've seen the fLaC magic in the write callback yet */
+ FLAC__bool is_first_packet;
+ FLAC__uint64 samples_written;
+} FLAC__OggEncoderAspect;
+
+void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value);
+FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, unsigned value);
+void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect);
+FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect);
+void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect);
+
+typedef FLAC__StreamEncoderWriteStatus (*FLAC__OggEncoderAspectWriteCallbackProxy)(const void *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
+
+FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data);
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/ogg_helper.h b/src/FLAC/src/libFLAC/include/private/ogg_helper.h
new file mode 100644
index 0000000..389be18
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/ogg_helper.h
@@ -0,0 +1,43 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__OGG_HELPER_H
+#define FLAC__PRIVATE__OGG_HELPER_H
+
+#include <ogg/ogg.h>
+#include "FLAC/stream_encoder.h" /* for FLAC__StreamEncoder */
+
+void simple_ogg_page__init(ogg_page *page);
+void simple_ogg_page__clear(ogg_page *page);
+FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data);
+FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/ogg_mapping.h b/src/FLAC/src/libFLAC/include/private/ogg_mapping.h
new file mode 100644
index 0000000..07dd8b2
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/ogg_mapping.h
@@ -0,0 +1,63 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__OGG_MAPPING_H
+#define FLAC__PRIVATE__OGG_MAPPING_H
+
+#include "FLAC/ordinals.h"
+
+/** The length of the 'FLAC' magic in bytes. */
+#define FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH (1u)
+
+extern const unsigned FLAC__OGG_MAPPING_PACKET_TYPE_LEN; /* = 8 bits */
+
+extern const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE; /* = 0x7f */
+
+/** The length of the 'FLAC' magic in bytes. */
+#define FLAC__OGG_MAPPING_MAGIC_LENGTH (4u)
+
+extern const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC; /* = "FLAC" */
+
+extern const unsigned FLAC__OGG_MAPPING_VERSION_MAJOR_LEN; /* = 8 bits */
+extern const unsigned FLAC__OGG_MAPPING_VERSION_MINOR_LEN; /* = 8 bits */
+
+/** The length of the Ogg FLAC mapping major version number in bytes. */
+#define FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH (1u)
+
+/** The length of the Ogg FLAC mapping minor version number in bytes. */
+#define FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH (1u)
+
+extern const unsigned FLAC__OGG_MAPPING_NUM_HEADERS_LEN; /* = 16 bits */
+
+/** The length of the #-of-header-packets number bytes. */
+#define FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH (2u)
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/stream_encoder_framing.h b/src/FLAC/src/libFLAC/include/private/stream_encoder_framing.h
new file mode 100644
index 0000000..4865c16
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/stream_encoder_framing.h
@@ -0,0 +1,45 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
+#define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H
+
+#include "FLAC/format.h"
+#include "bitwriter.h"
+
+FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw);
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/private/window.h b/src/FLAC/src/libFLAC/include/private/window.h
new file mode 100644
index 0000000..01e0fc4
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/private/window.h
@@ -0,0 +1,71 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PRIVATE__WINDOW_H
+#define FLAC__PRIVATE__WINDOW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "private/float.h"
+#include "FLAC/format.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+/*
+ * FLAC__window_*()
+ * --------------------------------------------------------------------
+ * Calculates window coefficients according to different apodization
+ * functions.
+ *
+ * OUT window[0,L-1]
+ * IN L (number of points in window)
+ */
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L);
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p);
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L);
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/protected/Makefile.am b/src/FLAC/src/libFLAC/include/protected/Makefile.am
new file mode 100644
index 0000000..66c697c
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/protected/Makefile.am
@@ -0,0 +1,34 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+noinst_HEADERS = \
+ all.h \
+ stream_decoder.h \
+ stream_encoder.h
diff --git a/src/FLAC/src/libFLAC/include/protected/all.h b/src/FLAC/src/libFLAC/include/protected/all.h
new file mode 100644
index 0000000..2921092
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/protected/all.h
@@ -0,0 +1,38 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__ALL_H
+#define FLAC__PROTECTED__ALL_H
+
+#include "stream_decoder.h"
+#include "stream_encoder.h"
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/protected/stream_decoder.h b/src/FLAC/src/libFLAC/include/protected/stream_decoder.h
new file mode 100644
index 0000000..9108ca7
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/protected/stream_decoder.h
@@ -0,0 +1,58 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__STREAM_DECODER_H
+#define FLAC__PROTECTED__STREAM_DECODER_H
+
+#include "FLAC/stream_decoder.h"
+#if FLAC__HAS_OGG
+#include "private/ogg_decoder_aspect.h"
+#endif
+
+typedef struct FLAC__StreamDecoderProtected {
+ FLAC__StreamDecoderState state;
+ unsigned channels;
+ FLAC__ChannelAssignment channel_assignment;
+ unsigned bits_per_sample;
+ unsigned sample_rate; /* in Hz */
+ unsigned blocksize; /* in samples (per channel) */
+ FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */
+#if FLAC__HAS_OGG
+ FLAC__OggDecoderAspect ogg_decoder_aspect;
+#endif
+} FLAC__StreamDecoderProtected;
+
+/*
+ * return the number of input bytes consumed
+ */
+unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder);
+
+#endif
diff --git a/src/FLAC/src/libFLAC/include/protected/stream_encoder.h b/src/FLAC/src/libFLAC/include/protected/stream_encoder.h
new file mode 100644
index 0000000..e299916
--- /dev/null
+++ b/src/FLAC/src/libFLAC/include/protected/stream_encoder.h
@@ -0,0 +1,109 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of the Xiph.org Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FLAC__PROTECTED__STREAM_ENCODER_H
+#define FLAC__PROTECTED__STREAM_ENCODER_H
+
+#include "FLAC/stream_encoder.h"
+#if FLAC__HAS_OGG
+#include "private/ogg_encoder_aspect.h"
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#include "private/float.h"
+
+#define FLAC__MAX_APODIZATION_FUNCTIONS 32
+
+typedef enum {
+ FLAC__APODIZATION_BARTLETT,
+ FLAC__APODIZATION_BARTLETT_HANN,
+ FLAC__APODIZATION_BLACKMAN,
+ FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE,
+ FLAC__APODIZATION_CONNES,
+ FLAC__APODIZATION_FLATTOP,
+ FLAC__APODIZATION_GAUSS,
+ FLAC__APODIZATION_HAMMING,
+ FLAC__APODIZATION_HANN,
+ FLAC__APODIZATION_KAISER_BESSEL,
+ FLAC__APODIZATION_NUTTALL,
+ FLAC__APODIZATION_RECTANGLE,
+ FLAC__APODIZATION_TRIANGLE,
+ FLAC__APODIZATION_TUKEY,
+ FLAC__APODIZATION_WELCH
+} FLAC__ApodizationFunction;
+
+typedef struct {
+ FLAC__ApodizationFunction type;
+ union {
+ struct {
+ FLAC__real stddev;
+ } gauss;
+ struct {
+ FLAC__real p;
+ } tukey;
+ } parameters;
+} FLAC__ApodizationSpecification;
+
+#endif // #ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+typedef struct FLAC__StreamEncoderProtected {
+ FLAC__StreamEncoderState state;
+ FLAC__bool verify;
+ FLAC__bool streamable_subset;
+ FLAC__bool do_mid_side_stereo;
+ FLAC__bool loose_mid_side_stereo;
+ unsigned channels;
+ unsigned bits_per_sample;
+ unsigned sample_rate;
+ unsigned blocksize;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ unsigned num_apodizations;
+ FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS];
+#endif
+ unsigned max_lpc_order;
+ unsigned qlp_coeff_precision;
+ FLAC__bool do_qlp_coeff_prec_search;
+ FLAC__bool do_exhaustive_model_search;
+ FLAC__bool do_escape_coding;
+ unsigned min_residual_partition_order;
+ unsigned max_residual_partition_order;
+ unsigned rice_parameter_search_dist;
+ FLAC__uint64 total_samples_estimate;
+ FLAC__StreamMetadata **metadata;
+ unsigned num_metadata_blocks;
+ FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset;
+#if FLAC__HAS_OGG
+ FLAC__OggEncoderAspect ogg_encoder_aspect;
+#endif
+} FLAC__StreamEncoderProtected;
+
+#endif
diff --git a/src/FLAC/src/libFLAC/libFLAC.m4 b/src/FLAC/src/libFLAC/libFLAC.m4
new file mode 100644
index 0000000..ee589e2
--- /dev/null
+++ b/src/FLAC/src/libFLAC/libFLAC.m4
@@ -0,0 +1,114 @@
+# Configure paths for libFLAC
+# "Inspired" by ogg.m4
+
+dnl AM_PATH_LIBFLAC([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for libFLAC, and define LIBFLAC_CFLAGS, LIBFLAC_LIBS, LIBFLAC_LIBDIR
+dnl
+AC_DEFUN([AM_PATH_LIBFLAC],
+[dnl
+dnl Get the cflags and libraries
+dnl
+AC_ARG_WITH(libFLAC,[ --with-libFLAC=PFX Prefix where libFLAC is installed (optional)], libFLAC_prefix="$withval", libFLAC_prefix="")
+AC_ARG_WITH(libFLAC-libraries,[ --with-libFLAC-libraries=DIR Directory where libFLAC library is installed (optional)], libFLAC_libraries="$withval", libFLAC_libraries="")
+AC_ARG_WITH(libFLAC-includes,[ --with-libFLAC-includes=DIR Directory where libFLAC header files are installed (optional)], libFLAC_includes="$withval", libFLAC_includes="")
+AC_ARG_ENABLE(libFLACtest, [ --disable-libFLACtest Do not try to compile and run a test libFLAC program],, enable_libFLACtest=yes)
+
+ if test "x$libFLAC_libraries" != "x" ; then
+ LIBFLAC_LIBDIR="$libFLAC_libraries"
+ elif test "x$libFLAC_prefix" != "x" ; then
+ LIBFLAC_LIBDIR="$libFLAC_prefix/lib"
+ elif test "x$prefix" != "xNONE" ; then
+ LIBFLAC_LIBDIR="$libdir"
+ fi
+
+ LIBFLAC_LIBS="-L$LIBFLAC_LIBDIR -lFLAC $OGG_LIBS -lm"
+
+ if test "x$libFLAC_includes" != "x" ; then
+ LIBFLAC_CFLAGS="-I$libFLAC_includes"
+ elif test "x$libFLAC_prefix" != "x" ; then
+ LIBFLAC_CFLAGS="-I$libFLAC_prefix/include"
+ elif test "$prefix" != "xNONE"; then
+ LIBFLAC_CFLAGS=""
+ fi
+
+ AC_MSG_CHECKING(for libFLAC)
+ no_libFLAC=""
+
+
+ if test "x$enable_libFLACtest" = "xyes" ; then
+ ac_save_CFLAGS="$CFLAGS"
+ ac_save_CXXFLAGS="$CXXFLAGS"
+ ac_save_LIBS="$LIBS"
+ ac_save_LDPATH="$LD_LIBRARY_PATH"
+ CFLAGS="$CFLAGS $LIBFLAC_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS"
+ LIBS="$LIBS $LIBFLAC_LIBS"
+ LD_LIBRARY_PATH="$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
+dnl
+dnl Now check if the installed libFLAC is sufficiently new.
+dnl
+ rm -f conf.libFLACtest
+ AC_TRY_RUN([
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <FLAC/format.h>
+
+int main ()
+{
+ system("touch conf.libFLACtest");
+ return 0;
+}
+
+],, no_libFLAC=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ LIBS="$ac_save_LIBS"
+ LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
+ fi
+
+ if test "x$no_libFLAC" = "x" ; then
+ AC_MSG_RESULT(yes)
+ ifelse([$1], , :, [$1])
+ else
+ AC_MSG_RESULT(no)
+ if test -f conf.libFLACtest ; then
+ :
+ else
+ echo "*** Could not run libFLAC test program, checking why..."
+ CFLAGS="$CFLAGS $LIBFLAC_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $LIBFLAC_CFLAGS"
+ LIBS="$LIBS $LIBFLAC_LIBS"
+ LD_LIBRARY_PATH="$LIBFLAC_LIBDIR:$LD_LIBRARY_PATH"
+ AC_TRY_LINK([
+#include <stdio.h>
+#include <FLAC/format.h>
+], [ return 0; ],
+ [ echo "*** The test program compiled, but did not run. This usually means"
+ echo "*** that the run-time linker is not finding libFLAC or finding the wrong"
+ echo "*** version of libFLAC. If it is not finding libFLAC, you'll need to set your"
+ echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+ echo "*** to the installed location Also, make sure you have run ldconfig if that"
+ echo "*** is required on your system"
+ echo "***"
+ echo "*** If you have an old version installed, it is best to remove it, although"
+ echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
+ [ echo "*** The test program failed to compile or link. See the file config.log for the"
+ echo "*** exact error that occured. This usually means libFLAC was incorrectly installed"
+ echo "*** or that you have moved libFLAC since it was installed. In the latter case, you"
+ echo "*** may want to edit the libFLAC-config script: $LIBFLAC_CONFIG" ])
+ CFLAGS="$ac_save_CFLAGS"
+ CXXFLAGS="$ac_save_CXXFLAGS"
+ LIBS="$ac_save_LIBS"
+ LD_LIBRARY_PATH="$ac_save_LD_LIBRARY_PATH"
+ fi
+ LIBFLAC_CFLAGS=""
+ LIBFLAC_LIBDIR=""
+ LIBFLAC_LIBS=""
+ ifelse([$2], , :, [$2])
+ fi
+ AC_SUBST(LIBFLAC_CFLAGS)
+ AC_SUBST(LIBFLAC_LIBDIR)
+ AC_SUBST(LIBFLAC_LIBS)
+ rm -f conf.libFLACtest
+])
diff --git a/src/FLAC/src/libFLAC/lpc.c b/src/FLAC/src/libFLAC/lpc.c
new file mode 100644
index 0000000..37dcdf8
--- /dev/null
+++ b/src/FLAC/src/libFLAC/lpc.c
@@ -0,0 +1,1373 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/bitmath.h"
+#include "private/lpc.h"
+#if defined DEBUG || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE
+#include <stdio.h>
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#ifndef M_LN2
+/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
+#define M_LN2 0.69314718055994530942
+#endif
+
+void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len)
+{
+ unsigned i;
+ for(i = 0; i < data_len; i++)
+ out[i] = in[i] * window[i];
+}
+
+void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[])
+{
+ /* a readable, but slower, version */
+#if 0
+ FLAC__real d;
+ unsigned i;
+
+ FLAC__ASSERT(lag > 0);
+ FLAC__ASSERT(lag <= data_len);
+
+ /*
+ * Technically we should subtract the mean first like so:
+ * for(i = 0; i < data_len; i++)
+ * data[i] -= mean;
+ * but it appears not to make enough of a difference to matter, and
+ * most signals are already closely centered around zero
+ */
+ while(lag--) {
+ for(i = lag, d = 0.0; i < data_len; i++)
+ d += data[i] * data[i - lag];
+ autoc[lag] = d;
+ }
+#endif
+
+ /*
+ * this version tends to run faster because of better data locality
+ * ('data_len' is usually much larger than 'lag')
+ */
+ FLAC__real d;
+ unsigned sample, coeff;
+ const unsigned limit = data_len - lag;
+
+ FLAC__ASSERT(lag > 0);
+ FLAC__ASSERT(lag <= data_len);
+
+ for(coeff = 0; coeff < lag; coeff++)
+ autoc[coeff] = 0.0;
+ for(sample = 0; sample <= limit; sample++) {
+ d = data[sample];
+ for(coeff = 0; coeff < lag; coeff++)
+ autoc[coeff] += d * data[sample+coeff];
+ }
+ for(; sample < data_len; sample++) {
+ d = data[sample];
+ for(coeff = 0; coeff < data_len - sample; coeff++)
+ autoc[coeff] += d * data[sample+coeff];
+ }
+}
+
+void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[])
+{
+ unsigned i, j;
+ FLAC__double r, err, ref[FLAC__MAX_LPC_ORDER], lpc[FLAC__MAX_LPC_ORDER];
+
+ FLAC__ASSERT(0 != max_order);
+ FLAC__ASSERT(0 < *max_order);
+ FLAC__ASSERT(*max_order <= FLAC__MAX_LPC_ORDER);
+ FLAC__ASSERT(autoc[0] != 0.0);
+
+ err = autoc[0];
+
+ for(i = 0; i < *max_order; i++) {
+ /* Sum up this iteration's reflection coefficient. */
+ r = -autoc[i+1];
+ for(j = 0; j < i; j++)
+ r -= lpc[j] * autoc[i-j];
+ ref[i] = (r/=err);
+
+ /* Update LPC coefficients and total error. */
+ lpc[i]=r;
+ for(j = 0; j < (i>>1); j++) {
+ FLAC__double tmp = lpc[j];
+ lpc[j] += r * lpc[i-1-j];
+ lpc[i-1-j] += r * tmp;
+ }
+ if(i & 1)
+ lpc[j] += lpc[j] * r;
+
+ err *= (1.0 - r * r);
+
+ /* save this order */
+ for(j = 0; j <= i; j++)
+ lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */
+ error[i] = err;
+
+ /* see SF bug #1601812 http://sourceforge.net/tracker/index.php?func=detail&aid=1601812&group_id=13478&atid=113478 */
+ if(err == 0.0) {
+ *max_order = i+1;
+ return;
+ }
+ }
+}
+
+int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift)
+{
+ unsigned i;
+ FLAC__double cmax;
+ FLAC__int32 qmax, qmin;
+
+ FLAC__ASSERT(precision > 0);
+ FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION);
+
+ /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */
+ precision--;
+ qmax = 1 << precision;
+ qmin = -qmax;
+ qmax--;
+
+ /* calc cmax = max( |lp_coeff[i]| ) */
+ cmax = 0.0;
+ for(i = 0; i < order; i++) {
+ const FLAC__double d = fabs(lp_coeff[i]);
+ if(d > cmax)
+ cmax = d;
+ }
+
+ if(cmax <= 0.0) {
+ /* => coefficients are all 0, which means our constant-detect didn't work */
+ return 2;
+ }
+ else {
+ const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1;
+ const int min_shiftlimit = -max_shiftlimit - 1;
+ int log2cmax;
+
+ (void)frexp(cmax, &log2cmax);
+ log2cmax--;
+ *shift = (int)precision - log2cmax - 1;
+
+ if(*shift > max_shiftlimit)
+ *shift = max_shiftlimit;
+ else if(*shift < min_shiftlimit)
+ return 1;
+ }
+
+ if(*shift >= 0) {
+ FLAC__double error = 0.0;
+ FLAC__int32 q;
+ for(i = 0; i < order; i++) {
+ error += lp_coeff[i] * (1 << *shift);
+#if 1 /* unfortunately lround() is C99 */
+ if(error >= 0.0)
+ q = (FLAC__int32)(error + 0.5);
+ else
+ q = (FLAC__int32)(error - 0.5);
+#else
+ q = lround(error);
+#endif
+#ifdef FLAC__OVERFLOW_DETECT
+ if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */
+ fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]);
+ else if(q < qmin)
+ fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]);
+#endif
+ if(q > qmax)
+ q = qmax;
+ else if(q < qmin)
+ q = qmin;
+ error -= q;
+ qlp_coeff[i] = q;
+ }
+ }
+ /* negative shift is very rare but due to design flaw, negative shift is
+ * a NOP in the decoder, so it must be handled specially by scaling down
+ * coeffs
+ */
+ else {
+ const int nshift = -(*shift);
+ FLAC__double error = 0.0;
+ FLAC__int32 q;
+#ifdef DEBUG
+ fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift=%d order=%u cmax=%f\n", *shift, order, cmax);
+#endif
+ for(i = 0; i < order; i++) {
+ error += lp_coeff[i] / (1 << nshift);
+#if 1 /* unfortunately lround() is C99 */
+ if(error >= 0.0)
+ q = (FLAC__int32)(error + 0.5);
+ else
+ q = (FLAC__int32)(error - 0.5);
+#else
+ q = lround(error);
+#endif
+#ifdef FLAC__OVERFLOW_DETECT
+ if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */
+ fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]);
+ else if(q < qmin)
+ fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q<qmin %d<%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmin,*shift,cmax,precision+1,i,lp_coeff[i]);
+#endif
+ if(q > qmax)
+ q = qmax;
+ else if(q < qmin)
+ q = qmin;
+ error -= q;
+ qlp_coeff[i] = q;
+ }
+ *shift = 0;
+ }
+
+ return 0;
+}
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
+#ifdef FLAC__OVERFLOW_DETECT /* this ugly flavor is only for debugging */
+{
+ FLAC__int64 sumo;
+ unsigned i, j;
+ FLAC__int32 sum;
+ const FLAC__int32 *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+ for(i=0;i<order;i++)
+ fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+ fprintf(stderr,"\n");
+#endif
+ FLAC__ASSERT(order > 0);
+
+ for(i = 0; i < data_len; i++) {
+ sumo = 0;
+ sum = 0;
+ history = data;
+ for(j = 0; j < order; j++) {
+ sum += qlp_coeff[j] * (*(--history));
+ sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+#if defined _MSC_VER
+ if(sumo > 2147483647I64 || sumo < -2147483648I64)
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%I64d\n",i,j,qlp_coeff[j],*history,sumo);
+#else
+ if(sumo > 2147483647ll || sumo < -2147483648ll)
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,(long long)sumo);
+#endif
+ }
+ *(residual++) = *(data++) - (sum >> lp_quantization);
+ }
+
+ /* Here's a slower but clearer version:
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ for(j = 0; j < order; j++)
+ sum += qlp_coeff[j] * data[i-j-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ */
+}
+#else /* fully unrolled version for normal use */
+{
+ unsigned i;
+ FLAC__int32 sum;
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ /*
+ * We do unique versions up to 12th order since that's the subset limit.
+ * Also they are roughly ordered to match frequency of occurrence to
+ * minimize branching.
+ */
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[11] * data[i-12];
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 11 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 9 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 7 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 5 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 3 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 1 */
+ for(i = 0; i < data_len; i++)
+ residual[i] = data[i] - ((qlp_coeff[0] * data[i-1]) >> lp_quantization);
+ }
+ }
+ }
+ }
+ else { /* order > 12 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 32: sum += qlp_coeff[31] * data[i-32];
+ case 31: sum += qlp_coeff[30] * data[i-31];
+ case 30: sum += qlp_coeff[29] * data[i-30];
+ case 29: sum += qlp_coeff[28] * data[i-29];
+ case 28: sum += qlp_coeff[27] * data[i-28];
+ case 27: sum += qlp_coeff[26] * data[i-27];
+ case 26: sum += qlp_coeff[25] * data[i-26];
+ case 25: sum += qlp_coeff[24] * data[i-25];
+ case 24: sum += qlp_coeff[23] * data[i-24];
+ case 23: sum += qlp_coeff[22] * data[i-23];
+ case 22: sum += qlp_coeff[21] * data[i-22];
+ case 21: sum += qlp_coeff[20] * data[i-21];
+ case 20: sum += qlp_coeff[19] * data[i-20];
+ case 19: sum += qlp_coeff[18] * data[i-19];
+ case 18: sum += qlp_coeff[17] * data[i-18];
+ case 17: sum += qlp_coeff[16] * data[i-17];
+ case 16: sum += qlp_coeff[15] * data[i-16];
+ case 15: sum += qlp_coeff[14] * data[i-15];
+ case 14: sum += qlp_coeff[13] * data[i-14];
+ case 13: sum += qlp_coeff[12] * data[i-13];
+ sum += qlp_coeff[11] * data[i-12];
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[ 9] * data[i-10];
+ sum += qlp_coeff[ 8] * data[i- 9];
+ sum += qlp_coeff[ 7] * data[i- 8];
+ sum += qlp_coeff[ 6] * data[i- 7];
+ sum += qlp_coeff[ 5] * data[i- 6];
+ sum += qlp_coeff[ 4] * data[i- 5];
+ sum += qlp_coeff[ 3] * data[i- 4];
+ sum += qlp_coeff[ 2] * data[i- 3];
+ sum += qlp_coeff[ 1] * data[i- 2];
+ sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ residual[i] = data[i] - (sum >> lp_quantization);
+ }
+ }
+}
+#endif
+
+void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[])
+#ifdef FLAC__OVERFLOW_DETECT /* this ugly flavor is only for debugging */
+{
+ unsigned i, j;
+ FLAC__int64 sum;
+ const FLAC__int32 *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+ for(i=0;i<order;i++)
+ fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+ fprintf(stderr,"\n");
+#endif
+ FLAC__ASSERT(order > 0);
+
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ history = data;
+ for(j = 0; j < order; j++)
+ sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+ if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) {
+#if defined _MSC_VER
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%I64d\n", i, sum >> lp_quantization);
+#else
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, sum=%lld\n", i, (long long)(sum >> lp_quantization));
+#endif
+ break;
+ }
+ if(FLAC__bitmath_silog2_wide((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) {
+#if defined _MSC_VER
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%I64d, residual=%I64d\n", i, *data, sum >> lp_quantization, (FLAC__int64)(*data) - (sum >> lp_quantization));
+#else
+ fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%lld, residual=%lld\n", i, *data, (long long)(sum >> lp_quantization), (long long)((FLAC__int64)(*data) - (sum >> lp_quantization)));
+#endif
+ break;
+ }
+ *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization);
+ }
+}
+#else /* fully unrolled version for normal use */
+{
+ unsigned i;
+ FLAC__int64 sum;
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ /*
+ * We do unique versions up to 12th order since that's the subset limit.
+ * Also they are roughly ordered to match frequency of occurrence to
+ * minimize branching.
+ */
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 11 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 9 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 7 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 5 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 3 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 1 */
+ for(i = 0; i < data_len; i++)
+ residual[i] = data[i] - (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization);
+ }
+ }
+ }
+ }
+ else { /* order > 12 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32];
+ case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31];
+ case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30];
+ case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29];
+ case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28];
+ case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27];
+ case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26];
+ case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25];
+ case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24];
+ case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23];
+ case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22];
+ case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21];
+ case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20];
+ case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19];
+ case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18];
+ case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17];
+ case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16];
+ case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15];
+ case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14];
+ case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13];
+ sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
+ sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
+ sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
+ sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
+ sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
+ sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
+ sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
+ sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
+ sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+ }
+ residual[i] = data[i] - (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+}
+#endif
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+
+void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
+#ifdef FLAC__OVERFLOW_DETECT /* this ugly flavor is only for debugging */
+{
+ FLAC__int64 sumo;
+ unsigned i, j;
+ FLAC__int32 sum;
+ const FLAC__int32 *r = residual, *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+ fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+ for(i=0;i<order;i++)
+ fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+ fprintf(stderr,"\n");
+#endif
+ FLAC__ASSERT(order > 0);
+
+ for(i = 0; i < data_len; i++) {
+ sumo = 0;
+ sum = 0;
+ history = data;
+ for(j = 0; j < order; j++) {
+ sum += qlp_coeff[j] * (*(--history));
+ sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history);
+#if defined _MSC_VER
+ if(sumo > 2147483647I64 || sumo < -2147483648I64)
+ fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%I64d\n",i,j,qlp_coeff[j],*history,sumo);
+#else
+ if(sumo > 2147483647ll || sumo < -2147483648ll)
+ fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%lld\n",i,j,qlp_coeff[j],*history,(long long)sumo);
+#endif
+ }
+ *(data++) = *(r++) + (sum >> lp_quantization);
+ }
+
+ /* Here's a slower but clearer version:
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ for(j = 0; j < order; j++)
+ sum += qlp_coeff[j] * data[i-j-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ */
+}
+#else /* fully unrolled version for normal use */
+{
+ unsigned i;
+ FLAC__int32 sum;
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ /*
+ * We do unique versions up to 12th order since that's the subset limit.
+ * Also they are roughly ordered to match frequency of occurrence to
+ * minimize branching.
+ */
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[11] * data[i-12];
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 11 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[9] * data[i-10];
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 9 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[8] * data[i-9];
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[7] * data[i-8];
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 7 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[6] * data[i-7];
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[5] * data[i-6];
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 5 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[4] * data[i-5];
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[3] * data[i-4];
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 3 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[2] * data[i-3];
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[1] * data[i-2];
+ sum += qlp_coeff[0] * data[i-1];
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+ else { /* order == 1 */
+ for(i = 0; i < data_len; i++)
+ data[i] = residual[i] + ((qlp_coeff[0] * data[i-1]) >> lp_quantization);
+ }
+ }
+ }
+ }
+ else { /* order > 12 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 32: sum += qlp_coeff[31] * data[i-32];
+ case 31: sum += qlp_coeff[30] * data[i-31];
+ case 30: sum += qlp_coeff[29] * data[i-30];
+ case 29: sum += qlp_coeff[28] * data[i-29];
+ case 28: sum += qlp_coeff[27] * data[i-28];
+ case 27: sum += qlp_coeff[26] * data[i-27];
+ case 26: sum += qlp_coeff[25] * data[i-26];
+ case 25: sum += qlp_coeff[24] * data[i-25];
+ case 24: sum += qlp_coeff[23] * data[i-24];
+ case 23: sum += qlp_coeff[22] * data[i-23];
+ case 22: sum += qlp_coeff[21] * data[i-22];
+ case 21: sum += qlp_coeff[20] * data[i-21];
+ case 20: sum += qlp_coeff[19] * data[i-20];
+ case 19: sum += qlp_coeff[18] * data[i-19];
+ case 18: sum += qlp_coeff[17] * data[i-18];
+ case 17: sum += qlp_coeff[16] * data[i-17];
+ case 16: sum += qlp_coeff[15] * data[i-16];
+ case 15: sum += qlp_coeff[14] * data[i-15];
+ case 14: sum += qlp_coeff[13] * data[i-14];
+ case 13: sum += qlp_coeff[12] * data[i-13];
+ sum += qlp_coeff[11] * data[i-12];
+ sum += qlp_coeff[10] * data[i-11];
+ sum += qlp_coeff[ 9] * data[i-10];
+ sum += qlp_coeff[ 8] * data[i- 9];
+ sum += qlp_coeff[ 7] * data[i- 8];
+ sum += qlp_coeff[ 6] * data[i- 7];
+ sum += qlp_coeff[ 5] * data[i- 6];
+ sum += qlp_coeff[ 4] * data[i- 5];
+ sum += qlp_coeff[ 3] * data[i- 4];
+ sum += qlp_coeff[ 2] * data[i- 3];
+ sum += qlp_coeff[ 1] * data[i- 2];
+ sum += qlp_coeff[ 0] * data[i- 1];
+ }
+ data[i] = residual[i] + (sum >> lp_quantization);
+ }
+ }
+}
+#endif
+
+void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[])
+#ifdef FLAC__OVERFLOW_DETECT /* this ugly flavor is only for debugging */
+{
+ unsigned i, j;
+ FLAC__int64 sum;
+ const FLAC__int32 *r = residual, *history;
+
+#ifdef FLAC__OVERFLOW_DETECT_VERBOSE
+ fprintf(stderr,"FLAC__lpc_restore_signal_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization);
+ for(i=0;i<order;i++)
+ fprintf(stderr,", q[%u]=%d",i,qlp_coeff[i]);
+ fprintf(stderr,"\n");
+#endif
+ FLAC__ASSERT(order > 0);
+
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ history = data;
+ for(j = 0; j < order; j++)
+ sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history));
+ if(FLAC__bitmath_silog2_wide(sum >> lp_quantization) > 32) {
+#ifdef _MSC_VER
+ fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%I64d\n", i, sum >> lp_quantization);
+#else
+ fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, sum=%lld\n", i, (long long)(sum >> lp_quantization));
+#endif
+ break;
+ }
+ if(FLAC__bitmath_silog2_wide((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) {
+#ifdef _MSC_VER
+ fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%I64d, data=%I64d\n", i, *r, sum >> lp_quantization, (FLAC__int64)(*r) + (sum >> lp_quantization));
+#else
+ fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%lld, data=%lld\n", i, *r, (long long)(sum >> lp_quantization), (long long)((FLAC__int64)(*r) + (sum >> lp_quantization)));
+#endif
+ break;
+ }
+ *(data++) = *(r++) + (FLAC__int32)(sum >> lp_quantization);
+ }
+}
+#else /* fully unrolled version for normal use */
+{
+ unsigned i;
+ FLAC__int64 sum;
+
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= 32);
+
+ /*
+ * We do unique versions up to 12th order since that's the subset limit.
+ * Also they are roughly ordered to match frequency of occurrence to
+ * minimize branching.
+ */
+ if(order <= 12) {
+ if(order > 8) {
+ if(order > 10) {
+ if(order == 12) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 11 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 10) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 9 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[8] * (FLAC__int64)data[i-9];
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else if(order > 4) {
+ if(order > 6) {
+ if(order == 8) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[7] * (FLAC__int64)data[i-8];
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 7 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[6] * (FLAC__int64)data[i-7];
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 6) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[5] * (FLAC__int64)data[i-6];
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 5 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[4] * (FLAC__int64)data[i-5];
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ }
+ else {
+ if(order > 2) {
+ if(order == 4) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[3] * (FLAC__int64)data[i-4];
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 3 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[2] * (FLAC__int64)data[i-3];
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ }
+ else {
+ if(order == 2) {
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ sum += qlp_coeff[1] * (FLAC__int64)data[i-2];
+ sum += qlp_coeff[0] * (FLAC__int64)data[i-1];
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+ else { /* order == 1 */
+ for(i = 0; i < data_len; i++)
+ data[i] = residual[i] + (FLAC__int32)((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization);
+ }
+ }
+ }
+ }
+ else { /* order > 12 */
+ for(i = 0; i < data_len; i++) {
+ sum = 0;
+ switch(order) {
+ case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32];
+ case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31];
+ case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30];
+ case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29];
+ case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28];
+ case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27];
+ case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26];
+ case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25];
+ case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24];
+ case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23];
+ case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22];
+ case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21];
+ case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20];
+ case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19];
+ case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18];
+ case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17];
+ case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16];
+ case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15];
+ case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14];
+ case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13];
+ sum += qlp_coeff[11] * (FLAC__int64)data[i-12];
+ sum += qlp_coeff[10] * (FLAC__int64)data[i-11];
+ sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10];
+ sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9];
+ sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8];
+ sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7];
+ sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6];
+ sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5];
+ sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4];
+ sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3];
+ sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2];
+ sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1];
+ }
+ data[i] = residual[i] + (FLAC__int32)(sum >> lp_quantization);
+ }
+ }
+}
+#endif
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples)
+{
+ FLAC__double error_scale;
+
+ FLAC__ASSERT(total_samples > 0);
+
+ error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples;
+
+ return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale);
+}
+
+FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale)
+{
+ if(lpc_error > 0.0) {
+ FLAC__double bps = (FLAC__double)0.5 * log(error_scale * lpc_error) / M_LN2;
+ if(bps >= 0.0)
+ return bps;
+ else
+ return 0.0;
+ }
+ else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */
+ return 1e32;
+ }
+ else {
+ return 0.0;
+ }
+}
+
+unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order)
+{
+ unsigned order, index, best_index; /* 'index' the index into lpc_error; index==order-1 since lpc_error[0] is for order==1, lpc_error[1] is for order==2, etc */
+ FLAC__double bits, best_bits, error_scale;
+
+ FLAC__ASSERT(max_order > 0);
+ FLAC__ASSERT(total_samples > 0);
+
+ error_scale = 0.5 * M_LN2 * M_LN2 / (FLAC__double)total_samples;
+
+ best_index = 0;
+ best_bits = (unsigned)(-1);
+
+ for(index = 0, order = 1; index < max_order; index++, order++) {
+ bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[index], error_scale) * (FLAC__double)(total_samples - order) + (FLAC__double)(order * overhead_bits_per_order);
+ if(bits < best_bits) {
+ best_index = index;
+ best_bits = bits;
+ }
+ }
+
+ return best_index+1; /* +1 since index of lpc_error[] is order-1 */
+}
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/FLAC/src/libFLAC/md5.c b/src/FLAC/src/libFLAC/md5.c
new file mode 100644
index 0000000..47e163f
--- /dev/null
+++ b/src/FLAC/src/libFLAC/md5.c
@@ -0,0 +1,417 @@
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy() */
+
+#include "private/md5.h"
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions; now uses stuff from dpkg's config.h.
+ * - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ *
+ * Josh Coalson: made some changes to integrate with libFLAC.
+ * Still in the public domain.
+ */
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+ (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16])
+{
+ register FLAC__uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#if WORDS_BIGENDIAN
+//@@@@@@ OPT: use bswap/intrinsics
+static void byteSwap(FLAC__uint32 *buf, unsigned words)
+{
+ register FLAC__uint32 x;
+ do {
+ x = *buf;
+ x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff);
+ *buf++ = (x >> 16) | (x << 16);
+ } while (--words);
+}
+static void byteSwapX16(FLAC__uint32 *buf)
+{
+ register FLAC__uint32 x;
+
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16);
+ x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf = (x >> 16) | (x << 16);
+}
+#else
+#define byteSwap(buf, words)
+#define byteSwapX16(buf)
+#endif
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, unsigned len)
+{
+ FLAC__uint32 t;
+
+ /* Update byte count */
+
+ t = ctx->bytes[0];
+ if ((ctx->bytes[0] = t + len) < t)
+ ctx->bytes[1]++; /* Carry from low to high */
+
+ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
+ if (t > len) {
+ memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len);
+ return;
+ }
+ /* First chunk is an odd size */
+ memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t);
+ byteSwapX16(ctx->in);
+ FLAC__MD5Transform(ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+
+ /* Process data in 64-byte chunks */
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteSwapX16(ctx->in);
+ FLAC__MD5Transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void FLAC__MD5Init(FLAC__MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bytes[0] = 0;
+ ctx->bytes[1] = 0;
+
+ ctx->internal_buf = 0;
+ ctx->capacity = 0;
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx)
+{
+ int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
+ FLAC__byte *p = (FLAC__byte *)ctx->in + count;
+
+ /* Set the first char of padding to 0x80. There is always room. */
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 56 bytes (-8..55) */
+ count = 56 - 1 - count;
+
+ if (count < 0) { /* Padding forces an extra block */
+ memset(p, 0, count + 8);
+ byteSwapX16(ctx->in);
+ FLAC__MD5Transform(ctx->buf, ctx->in);
+ p = (FLAC__byte *)ctx->in;
+ count = 56;
+ }
+ memset(p, 0, count);
+ byteSwap(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ctx->in[14] = ctx->bytes[0] << 3;
+ ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+ FLAC__MD5Transform(ctx->buf, ctx->in);
+
+ byteSwap(ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+ if(0 != ctx->internal_buf) {
+ free(ctx->internal_buf);
+ ctx->internal_buf = 0;
+ ctx->capacity = 0;
+ }
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream
+ */
+static void format_input_(FLAC__byte *buf, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
+{
+ unsigned channel, sample;
+ register FLAC__int32 a_word;
+ register FLAC__byte *buf_ = buf;
+
+#if WORDS_BIGENDIAN
+#else
+ if(channels == 2 && bytes_per_sample == 2) {
+ FLAC__int16 *buf1_ = ((FLAC__int16*)buf_) + 1;
+ memcpy(buf_, signal[0], sizeof(FLAC__int32) * samples);
+ for(sample = 0; sample < samples; sample++, buf1_+=2)
+ *buf1_ = (FLAC__int16)signal[1][sample];
+ }
+ else if(channels == 1 && bytes_per_sample == 2) {
+ FLAC__int16 *buf1_ = (FLAC__int16*)buf_;
+ for(sample = 0; sample < samples; sample++)
+ *buf1_++ = (FLAC__int16)signal[0][sample];
+ }
+ else
+#endif
+ if(bytes_per_sample == 2) {
+ if(channels == 2) {
+ for(sample = 0; sample < samples; sample++) {
+ a_word = signal[0][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ a_word = signal[1][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ }
+ else if(channels == 1) {
+ for(sample = 0; sample < samples; sample++) {
+ a_word = signal[0][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ }
+ else {
+ for(sample = 0; sample < samples; sample++) {
+ for(channel = 0; channel < channels; channel++) {
+ a_word = signal[channel][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ }
+ }
+ }
+ else if(bytes_per_sample == 3) {
+ if(channels == 2) {
+ for(sample = 0; sample < samples; sample++) {
+ a_word = signal[0][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ a_word = signal[1][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ }
+ else if(channels == 1) {
+ for(sample = 0; sample < samples; sample++) {
+ a_word = signal[0][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ }
+ else {
+ for(sample = 0; sample < samples; sample++) {
+ for(channel = 0; channel < channels; channel++) {
+ a_word = signal[channel][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ }
+ }
+ }
+ else if(bytes_per_sample == 1) {
+ if(channels == 2) {
+ for(sample = 0; sample < samples; sample++) {
+ a_word = signal[0][sample];
+ *buf_++ = (FLAC__byte)a_word;
+ a_word = signal[1][sample];
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ }
+ else if(channels == 1) {
+ for(sample = 0; sample < samples; sample++) {
+ a_word = signal[0][sample];
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ }
+ else {
+ for(sample = 0; sample < samples; sample++) {
+ for(channel = 0; channel < channels; channel++) {
+ a_word = signal[channel][sample];
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ }
+ }
+ }
+ else { /* bytes_per_sample == 4, maybe optimize more later */
+ for(sample = 0; sample < samples; sample++) {
+ for(channel = 0; channel < channels; channel++) {
+ a_word = signal[channel][sample];
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word; a_word >>= 8;
+ *buf_++ = (FLAC__byte)a_word;
+ }
+ }
+ }
+}
+
+/*
+ * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it.
+ */
+FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample)
+{
+ const unsigned bytes_needed = channels * samples * bytes_per_sample;
+
+ if(ctx->capacity < bytes_needed) {
+ FLAC__byte *tmp = (FLAC__byte*)realloc(ctx->internal_buf, bytes_needed);
+ if(0 == tmp) {
+ free(ctx->internal_buf);
+ if(0 == (ctx->internal_buf = (FLAC__byte*)malloc(bytes_needed)))
+ return false;
+ }
+ ctx->internal_buf = tmp;
+ ctx->capacity = bytes_needed;
+ }
+
+ format_input_(ctx->internal_buf, signal, channels, samples, bytes_per_sample);
+
+ FLAC__MD5Update(ctx, ctx->internal_buf, bytes_needed);
+
+ return true;
+}
diff --git a/src/FLAC/src/libFLAC/memory.c b/src/FLAC/src/libFLAC/memory.c
new file mode 100644
index 0000000..2df3bfb
--- /dev/null
+++ b/src/FLAC/src/libFLAC/memory.c
@@ -0,0 +1,194 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/memory.h"
+#include "FLAC/assert.h"
+
+void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address)
+{
+ void *x;
+
+ FLAC__ASSERT(0 != aligned_address);
+
+#ifdef FLAC__ALIGN_MALLOC_DATA
+ /* align on 32-byte (256-bit) boundary */
+ x = malloc(bytes+31);
+ /* there's got to be a better way to do this right for all archs */
+ if(sizeof(void*) == sizeof(unsigned))
+ *aligned_address = (void*)(((unsigned)x + 31) & -32);
+ else if(sizeof(void*) == sizeof(FLAC__uint64))
+ *aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32)));
+ else
+ return 0;
+#else
+ x = malloc(bytes);
+ *aligned_address = x;
+#endif
+ return x;
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer)
+{
+ FLAC__int32 *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ FLAC__int32 *pa; /* aligned pointer */
+ void *pv; /* aligned pointer alias */
+ } u;
+
+ FLAC__ASSERT(elements > 0);
+ FLAC__ASSERT(0 != unaligned_pointer);
+ FLAC__ASSERT(0 != aligned_pointer);
+ FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+ pu = (FLAC__int32*)FLAC__memory_alloc_aligned(sizeof(FLAC__int32) * elements, &u.pv);
+ if(0 == pu) {
+ return false;
+ }
+ else {
+ if(*unaligned_pointer != 0)
+ free(*unaligned_pointer);
+ *unaligned_pointer = pu;
+ *aligned_pointer = u.pa;
+ return true;
+ }
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer)
+{
+ FLAC__uint32 *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ FLAC__uint32 *pa; /* aligned pointer */
+ void *pv; /* aligned pointer alias */
+ } u;
+
+ FLAC__ASSERT(elements > 0);
+ FLAC__ASSERT(0 != unaligned_pointer);
+ FLAC__ASSERT(0 != aligned_pointer);
+ FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+ pu = (FLAC__uint32*)FLAC__memory_alloc_aligned(sizeof(FLAC__uint32) * elements, &u.pv);
+ if(0 == pu) {
+ return false;
+ }
+ else {
+ if(*unaligned_pointer != 0)
+ free(*unaligned_pointer);
+ *unaligned_pointer = pu;
+ *aligned_pointer = u.pa;
+ return true;
+ }
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer)
+{
+ FLAC__uint64 *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ FLAC__uint64 *pa; /* aligned pointer */
+ void *pv; /* aligned pointer alias */
+ } u;
+
+ FLAC__ASSERT(elements > 0);
+ FLAC__ASSERT(0 != unaligned_pointer);
+ FLAC__ASSERT(0 != aligned_pointer);
+ FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+ pu = (FLAC__uint64*)FLAC__memory_alloc_aligned(sizeof(FLAC__uint64) * elements, &u.pv);
+ if(0 == pu) {
+ return false;
+ }
+ else {
+ if(*unaligned_pointer != 0)
+ free(*unaligned_pointer);
+ *unaligned_pointer = pu;
+ *aligned_pointer = u.pa;
+ return true;
+ }
+}
+
+FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer)
+{
+ unsigned *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ unsigned *pa; /* aligned pointer */
+ void *pv; /* aligned pointer alias */
+ } u;
+
+ FLAC__ASSERT(elements > 0);
+ FLAC__ASSERT(0 != unaligned_pointer);
+ FLAC__ASSERT(0 != aligned_pointer);
+ FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+ pu = (unsigned*)FLAC__memory_alloc_aligned(sizeof(unsigned) * elements, &u.pv);
+ if(0 == pu) {
+ return false;
+ }
+ else {
+ if(*unaligned_pointer != 0)
+ free(*unaligned_pointer);
+ *unaligned_pointer = pu;
+ *aligned_pointer = u.pa;
+ return true;
+ }
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer)
+{
+ FLAC__real *pu; /* unaligned pointer */
+ union { /* union needed to comply with C99 pointer aliasing rules */
+ FLAC__real *pa; /* aligned pointer */
+ void *pv; /* aligned pointer alias */
+ } u;
+
+ FLAC__ASSERT(elements > 0);
+ FLAC__ASSERT(0 != unaligned_pointer);
+ FLAC__ASSERT(0 != aligned_pointer);
+ FLAC__ASSERT(unaligned_pointer != aligned_pointer);
+
+ pu = (FLAC__real*)FLAC__memory_alloc_aligned(sizeof(FLAC__real) * elements, &u.pv);
+ if(0 == pu) {
+ return false;
+ }
+ else {
+ if(*unaligned_pointer != 0)
+ free(*unaligned_pointer);
+ *unaligned_pointer = pu;
+ *aligned_pointer = u.pa;
+ return true;
+ }
+}
+
+#endif
diff --git a/src/FLAC/src/libFLAC/metadata_iterators.c b/src/FLAC/src/libFLAC/metadata_iterators.c
new file mode 100644
index 0000000..d06d195
--- /dev/null
+++ b/src/FLAC/src/libFLAC/metadata_iterators.c
@@ -0,0 +1,3304 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#if defined __BORLANDC__
+#include <utime.h> /* for utime() */
+#else
+#include <sys/utime.h> /* for utime() */
+#endif
+#include <io.h> /* for chmod() */
+#include <sys/types.h> /* for off_t */
+#if _MSC_VER <= 1600 || defined __BORLANDC__ /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+
+#include "private/metadata.h"
+
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) ((a)>(b)?(a):(b))
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a)<(b)?(a):(b))
+
+
+/****************************************************************************
+ *
+ * Local function declarations
+ *
+ ***************************************************************************/
+
+static void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
+static void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes);
+static void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes);
+static FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes);
+static FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes);
+static FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes);
+
+static FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block);
+static FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block);
+static FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length);
+
+static FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block);
+static FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length);
+static FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length);
+static FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block);
+static FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block);
+static FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block);
+static FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block);
+static FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length);
+
+static FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block);
+static FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last);
+static FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append);
+
+static void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator);
+static FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator);
+
+static unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb);
+static unsigned seek_to_first_metadata_block_(FILE *f);
+
+static FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append);
+static FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, off_t fixup_is_last_flag_offset, FLAC__bool backup);
+
+static FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status);
+
+static FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status);
+static void cleanup_tempfile_(FILE **tempfile, char **tempfilename);
+
+static FLAC__bool get_file_stats_(const char *filename, struct stat *stats);
+static void set_file_stats_(const char *filename, struct stat *stats);
+
+static int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence);
+static FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle);
+
+static FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status);
+
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ size_t ret = fwrite(ptr, size, nmemb, stream);
+ if(!ferror(stream))
+ fflush(stream);
+ return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+/****************************************************************************
+ *
+ * Level 0 implementation
+ *
+ ***************************************************************************/
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+typedef struct {
+ FLAC__bool got_error;
+ FLAC__StreamMetadata *object;
+} level0_client_data;
+
+static FLAC__StreamMetadata *get_one_metadata_block_(const char *filename, FLAC__MetadataType type)
+{
+ level0_client_data cd;
+ FLAC__StreamDecoder *decoder;
+
+ FLAC__ASSERT(0 != filename);
+
+ cd.got_error = false;
+ cd.object = 0;
+
+ decoder = FLAC__stream_decoder_new();
+
+ if(0 == decoder)
+ return 0;
+
+ FLAC__stream_decoder_set_md5_checking(decoder, false);
+ FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+ FLAC__stream_decoder_set_metadata_respond(decoder, type);
+
+ if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &cd) != FLAC__STREAM_DECODER_INIT_STATUS_OK || cd.got_error) {
+ (void)FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+ return 0;
+ }
+
+ if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder) || cd.got_error) {
+ (void)FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+ if(0 != cd.object)
+ FLAC__metadata_object_delete(cd.object);
+ return 0;
+ }
+
+ (void)FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+
+ return cd.object;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_streaminfo(const char *filename, FLAC__StreamMetadata *streaminfo)
+{
+ FLAC__StreamMetadata *object;
+
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != streaminfo);
+
+ object = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_STREAMINFO);
+
+ if (object) {
+ /* can just copy the contents since STREAMINFO has no internal structure */
+ *streaminfo = *object;
+ FLAC__metadata_object_delete(object);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_tags(const char *filename, FLAC__StreamMetadata **tags)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != tags);
+
+ *tags = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ return 0 != *tags;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__StreamMetadata **cuesheet)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != cuesheet);
+
+ *cuesheet = get_one_metadata_block_(filename, FLAC__METADATA_TYPE_CUESHEET);
+
+ return 0 != *cuesheet;
+}
+
+FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ (void)decoder, (void)frame, (void)buffer, (void)client_data;
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ level0_client_data *cd = (level0_client_data *)client_data;
+ (void)decoder;
+
+ /*
+ * we assume we only get here when the one metadata block we were
+ * looking for was passed to us
+ */
+ if(!cd->got_error && 0 == cd->object) {
+ if(0 == (cd->object = FLAC__metadata_object_clone(metadata)))
+ cd->got_error = true;
+ }
+}
+
+void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ level0_client_data *cd = (level0_client_data *)client_data;
+ (void)decoder;
+
+ if(status != FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC)
+ cd->got_error = true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors)
+{
+ FLAC__Metadata_SimpleIterator *it;
+ FLAC__uint64 max_area_seen = 0;
+ FLAC__uint64 max_depth_seen = 0;
+
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != picture);
+
+ *picture = 0;
+
+ it = FLAC__metadata_simple_iterator_new();
+ if(0 == it)
+ return false;
+ if(!FLAC__metadata_simple_iterator_init(it, filename, /*read_only=*/true, /*preserve_file_stats=*/true)) {
+ FLAC__metadata_simple_iterator_delete(it);
+ return false;
+ }
+ do {
+ if(FLAC__metadata_simple_iterator_get_block_type(it) == FLAC__METADATA_TYPE_PICTURE) {
+ FLAC__StreamMetadata *obj = FLAC__metadata_simple_iterator_get_block(it);
+ FLAC__uint64 area = (FLAC__uint64)obj->data.picture.width * (FLAC__uint64)obj->data.picture.height;
+ /* check constraints */
+ if(
+ (type == (FLAC__StreamMetadata_Picture_Type)(-1) || type == obj->data.picture.type) &&
+ (mime_type == 0 || !strcmp(mime_type, obj->data.picture.mime_type)) &&
+ (description == 0 || !strcmp((const char *)description, (const char *)obj->data.picture.description)) &&
+ obj->data.picture.width <= max_width &&
+ obj->data.picture.height <= max_height &&
+ obj->data.picture.depth <= max_depth &&
+ obj->data.picture.colors <= max_colors &&
+ (area > max_area_seen || (area == max_area_seen && obj->data.picture.depth > max_depth_seen))
+ ) {
+ if(*picture)
+ FLAC__metadata_object_delete(*picture);
+ *picture = obj;
+ max_area_seen = area;
+ max_depth_seen = obj->data.picture.depth;
+ }
+ else {
+ FLAC__metadata_object_delete(obj);
+ }
+ }
+ } while(FLAC__metadata_simple_iterator_next(it));
+
+ FLAC__metadata_simple_iterator_delete(it);
+
+ return (0 != *picture);
+}
+
+
+/****************************************************************************
+ *
+ * Level 1 implementation
+ *
+ ***************************************************************************/
+
+#define SIMPLE_ITERATOR_MAX_PUSH_DEPTH (1+4)
+/* 1 for initial offset, +4 for our own personal use */
+
+struct FLAC__Metadata_SimpleIterator {
+ FILE *file;
+ char *filename, *tempfile_path_prefix;
+ struct stat stats;
+ FLAC__bool has_stats;
+ FLAC__bool is_writable;
+ FLAC__Metadata_SimpleIteratorStatus status;
+ off_t offset[SIMPLE_ITERATOR_MAX_PUSH_DEPTH];
+ off_t first_offset; /* this is the offset to the STREAMINFO block */
+ unsigned depth;
+ /* this is the metadata block header of the current block we are pointing to: */
+ FLAC__bool is_last;
+ FLAC__MetadataType type;
+ unsigned length;
+};
+
+FLAC_API const char * const FLAC__Metadata_SimpleIteratorStatusString[] = {
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR",
+ "FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR"
+};
+
+
+FLAC_API FLAC__Metadata_SimpleIterator *FLAC__metadata_simple_iterator_new(void)
+{
+ FLAC__Metadata_SimpleIterator *iterator = (FLAC__Metadata_SimpleIterator*)calloc(1, sizeof(FLAC__Metadata_SimpleIterator));
+
+ if(0 != iterator) {
+ iterator->file = 0;
+ iterator->filename = 0;
+ iterator->tempfile_path_prefix = 0;
+ iterator->has_stats = false;
+ iterator->is_writable = false;
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ iterator->first_offset = iterator->offset[0] = -1;
+ iterator->depth = 0;
+ }
+
+ return iterator;
+}
+
+static void simple_iterator_free_guts_(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+
+ if(0 != iterator->file) {
+ fclose(iterator->file);
+ iterator->file = 0;
+ if(iterator->has_stats)
+ set_file_stats_(iterator->filename, &iterator->stats);
+ }
+ if(0 != iterator->filename) {
+ free(iterator->filename);
+ iterator->filename = 0;
+ }
+ if(0 != iterator->tempfile_path_prefix) {
+ free(iterator->tempfile_path_prefix);
+ iterator->tempfile_path_prefix = 0;
+ }
+}
+
+FLAC_API void FLAC__metadata_simple_iterator_delete(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+
+ simple_iterator_free_guts_(iterator);
+ free(iterator);
+}
+
+FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_status(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__Metadata_SimpleIteratorStatus status;
+
+ FLAC__ASSERT(0 != iterator);
+
+ status = iterator->status;
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return status;
+}
+
+static FLAC__bool simple_iterator_prime_input_(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool read_only)
+{
+ unsigned ret;
+
+ FLAC__ASSERT(0 != iterator);
+
+ if(read_only || 0 == (iterator->file = fopen(iterator->filename, "r+b"))) {
+ iterator->is_writable = false;
+ if(read_only || errno == EACCES) {
+ if(0 == (iterator->file = fopen(iterator->filename, "rb"))) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+ }
+ else {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+ }
+ else {
+ iterator->is_writable = true;
+ }
+
+ ret = seek_to_first_metadata_block_(iterator->file);
+ switch(ret) {
+ case 0:
+ iterator->depth = 0;
+ iterator->first_offset = iterator->offset[iterator->depth] = ftello(iterator->file);
+ return read_metadata_block_header_(iterator);
+ case 1:
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ case 2:
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ case 3:
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE;
+ return false;
+ default:
+ FLAC__ASSERT(0);
+ return false;
+ }
+}
+
+#if 0
+@@@ If we decide to finish implementing this, put this comment back in metadata.h
+/*
+ * The 'tempfile_path_prefix' allows you to specify a directory where
+ * tempfiles should go. Remember that if your metadata edits cause the
+ * FLAC file to grow, the entire file will have to be rewritten. If
+ * 'tempfile_path_prefix' is NULL, the temp file will be written in the
+ * same directory as the original FLAC file. This makes replacing the
+ * original with the tempfile fast but requires extra space in the same
+ * partition for the tempfile. If space is a problem, you can pass a
+ * directory name belonging to a different partition in
+ * 'tempfile_path_prefix'. Note that you should use the forward slash
+ * '/' as the directory separator. A trailing slash is not needed; it
+ * will be added automatically.
+ */
+FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool preserve_file_stats, const char *tempfile_path_prefix);
+#endif
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_init(FLAC__Metadata_SimpleIterator *iterator, const char *filename, FLAC__bool read_only, FLAC__bool preserve_file_stats)
+{
+ const char *tempfile_path_prefix = 0; /*@@@ search for comments near 'rename(...)' for what it will take to finish implementing this */
+
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != filename);
+
+ simple_iterator_free_guts_(iterator);
+
+ if(!read_only && preserve_file_stats)
+ iterator->has_stats = get_file_stats_(filename, &iterator->stats);
+
+ if(0 == (iterator->filename = strdup(filename))) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(0 != tempfile_path_prefix && 0 == (iterator->tempfile_path_prefix = strdup(tempfile_path_prefix))) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ return simple_iterator_prime_input_(iterator, read_only);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_is_writable(const FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+
+ return iterator->is_writable;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_next(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+
+ if(iterator->is_last)
+ return false;
+
+ if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ iterator->offset[iterator->depth] = ftello(iterator->file);
+
+ return read_metadata_block_header_(iterator);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_prev(FLAC__Metadata_SimpleIterator *iterator)
+{
+ off_t this_offset;
+
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+
+ if(iterator->offset[iterator->depth] == iterator->first_offset)
+ return false;
+
+ if(0 != fseeko(iterator->file, iterator->first_offset, SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ this_offset = iterator->first_offset;
+ if(!read_metadata_block_header_(iterator))
+ return false;
+
+ /* we ignore any error from ftello() and catch it in fseeko() */
+ while(ftello(iterator->file) + (off_t)iterator->length < iterator->offset[iterator->depth]) {
+ if(0 != fseeko(iterator->file, iterator->length, SEEK_CUR)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ this_offset = ftello(iterator->file);
+ if(!read_metadata_block_header_(iterator))
+ return false;
+ }
+
+ iterator->offset[iterator->depth] = this_offset;
+
+ return true;
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+
+ return iterator->type;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_simple_iterator_get_block(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__StreamMetadata *block = FLAC__metadata_object_new(iterator->type);
+
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+
+ if(0 != block) {
+ block->is_last = iterator->is_last;
+ block->length = iterator->length;
+
+ if(!read_metadata_block_data_(iterator, block)) {
+ FLAC__metadata_object_delete(block);
+ return 0;
+ }
+
+ /* back up to the beginning of the block data to stay consistent */
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH, SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ FLAC__metadata_object_delete(block);
+ return 0;
+ }
+ }
+ else
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ return block;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_set_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+ FLAC__ASSERT_DECLARATION(off_t debug_target_offset = iterator->offset[iterator->depth];)
+ FLAC__bool ret;
+
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+ FLAC__ASSERT(0 != block);
+
+ if(!iterator->is_writable) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE;
+ return false;
+ }
+
+ if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO || block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ if(iterator->type != block->type) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+ return false;
+ }
+ }
+
+ block->is_last = iterator->is_last;
+
+ if(iterator->length == block->length)
+ return write_metadata_block_stationary_(iterator, block);
+ else if(iterator->length > block->length) {
+ if(use_padding && iterator->length >= FLAC__STREAM_METADATA_HEADER_LENGTH + block->length) {
+ ret = write_metadata_block_stationary_with_padding_(iterator, block, iterator->length - FLAC__STREAM_METADATA_HEADER_LENGTH - block->length, block->is_last);
+ FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+ FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+ else {
+ ret = rewrite_whole_file_(iterator, block, /*append=*/false);
+ FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+ FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+ }
+ else /* iterator->length < block->length */ {
+ unsigned padding_leftover = 0;
+ FLAC__bool padding_is_last = false;
+ if(use_padding) {
+ /* first see if we can even use padding */
+ if(iterator->is_last) {
+ use_padding = false;
+ }
+ else {
+ const unsigned extra_padding_bytes_required = block->length - iterator->length;
+ simple_iterator_push_(iterator);
+ if(!FLAC__metadata_simple_iterator_next(iterator)) {
+ (void)simple_iterator_pop_(iterator);
+ return false;
+ }
+ if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+ use_padding = false;
+ }
+ else {
+ if(FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length == extra_padding_bytes_required) {
+ padding_leftover = 0;
+ block->is_last = iterator->is_last;
+ }
+ else if(iterator->length < extra_padding_bytes_required)
+ use_padding = false;
+ else {
+ padding_leftover = FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length - extra_padding_bytes_required;
+ padding_is_last = iterator->is_last;
+ block->is_last = false;
+ }
+ }
+ if(!simple_iterator_pop_(iterator))
+ return false;
+ }
+ }
+ if(use_padding) {
+ if(padding_leftover == 0) {
+ ret = write_metadata_block_stationary_(iterator, block);
+ FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+ FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+ else {
+ FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
+ ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+ FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+ FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+ }
+ else {
+ ret = rewrite_whole_file_(iterator, block, /*append=*/false);
+ FLAC__ASSERT(!ret || iterator->offset[iterator->depth] == debug_target_offset);
+ FLAC__ASSERT(!ret || ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_insert_block_after(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool use_padding)
+{
+ unsigned padding_leftover = 0;
+ FLAC__bool padding_is_last = false;
+
+ FLAC__ASSERT_DECLARATION(off_t debug_target_offset = iterator->offset[iterator->depth] + FLAC__STREAM_METADATA_HEADER_LENGTH + iterator->length;)
+ FLAC__bool ret;
+
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+ FLAC__ASSERT(0 != block);
+
+ if(!iterator->is_writable)
+ return false;
+
+ if(block->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+ return false;
+ }
+
+ block->is_last = iterator->is_last;
+
+ if(use_padding) {
+ /* first see if we can even use padding */
+ if(iterator->is_last) {
+ use_padding = false;
+ }
+ else {
+ simple_iterator_push_(iterator);
+ if(!FLAC__metadata_simple_iterator_next(iterator)) {
+ (void)simple_iterator_pop_(iterator);
+ return false;
+ }
+ if(iterator->type != FLAC__METADATA_TYPE_PADDING) {
+ use_padding = false;
+ }
+ else {
+ if(iterator->length == block->length) {
+ padding_leftover = 0;
+ block->is_last = iterator->is_last;
+ }
+ else if(iterator->length < FLAC__STREAM_METADATA_HEADER_LENGTH + block->length)
+ use_padding = false;
+ else {
+ padding_leftover = iterator->length - block->length;
+ padding_is_last = iterator->is_last;
+ block->is_last = false;
+ }
+ }
+ if(!simple_iterator_pop_(iterator))
+ return false;
+ }
+ }
+ if(use_padding) {
+ /* move to the next block, which is suitable padding */
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return false;
+ if(padding_leftover == 0) {
+ ret = write_metadata_block_stationary_(iterator, block);
+ FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+ FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+ else {
+ FLAC__ASSERT(padding_leftover >= FLAC__STREAM_METADATA_HEADER_LENGTH);
+ ret = write_metadata_block_stationary_with_padding_(iterator, block, padding_leftover - FLAC__STREAM_METADATA_HEADER_LENGTH, padding_is_last);
+ FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+ FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+ }
+ else {
+ ret = rewrite_whole_file_(iterator, block, /*append=*/true);
+ FLAC__ASSERT(iterator->offset[iterator->depth] == debug_target_offset);
+ FLAC__ASSERT(ftello(iterator->file) == debug_target_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH);
+ return ret;
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_SimpleIterator *iterator, FLAC__bool use_padding)
+{
+ FLAC__ASSERT_DECLARATION(off_t debug_target_offset = iterator->offset[iterator->depth];)
+ FLAC__bool ret;
+
+ if(iterator->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT;
+ return false;
+ }
+
+ if(use_padding) {
+ FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+ if(0 == padding) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ padding->length = iterator->length;
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false)) {
+ FLAC__metadata_object_delete(padding);
+ return false;
+ }
+ FLAC__metadata_object_delete(padding);
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return false;
+ FLAC__ASSERT(iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length == debug_target_offset);
+ FLAC__ASSERT(ftello(iterator->file) + (off_t)iterator->length == debug_target_offset);
+ return true;
+ }
+ else {
+ ret = rewrite_whole_file_(iterator, 0, /*append=*/false);
+ FLAC__ASSERT(iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length == debug_target_offset);
+ FLAC__ASSERT(ftello(iterator->file) + (off_t)iterator->length == debug_target_offset);
+ return ret;
+ }
+}
+
+
+
+/****************************************************************************
+ *
+ * Level 2 implementation
+ *
+ ***************************************************************************/
+
+
+typedef struct FLAC__Metadata_Node {
+ FLAC__StreamMetadata *data;
+ struct FLAC__Metadata_Node *prev, *next;
+} FLAC__Metadata_Node;
+
+struct FLAC__Metadata_Chain {
+ char *filename; /* will be NULL if using callbacks */
+ FLAC__bool is_ogg;
+ FLAC__Metadata_Node *head;
+ FLAC__Metadata_Node *tail;
+ unsigned nodes;
+ FLAC__Metadata_ChainStatus status;
+ off_t first_offset, last_offset;
+ /*
+ * This is the length of the chain initially read from the FLAC file.
+ * it is used to compare against the current length to decide whether
+ * or not the whole file has to be rewritten.
+ */
+ off_t initial_length;
+ /* @@@ hacky, these are currently only needed by ogg reader */
+ FLAC__IOHandle handle;
+ FLAC__IOCallback_Read read_cb;
+};
+
+struct FLAC__Metadata_Iterator {
+ FLAC__Metadata_Chain *chain;
+ FLAC__Metadata_Node *current;
+};
+
+FLAC_API const char * const FLAC__Metadata_ChainStatusString[] = {
+ "FLAC__METADATA_CHAIN_STATUS_OK",
+ "FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT",
+ "FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE",
+ "FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE",
+ "FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE",
+ "FLAC__METADATA_CHAIN_STATUS_BAD_METADATA",
+ "FLAC__METADATA_CHAIN_STATUS_READ_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR",
+ "FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS",
+ "FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH",
+ "FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL"
+};
+
+
+static FLAC__Metadata_Node *node_new_(void)
+{
+ return (FLAC__Metadata_Node*)calloc(1, sizeof(FLAC__Metadata_Node));
+}
+
+static void node_delete_(FLAC__Metadata_Node *node)
+{
+ FLAC__ASSERT(0 != node);
+ if(0 != node->data)
+ FLAC__metadata_object_delete(node->data);
+ free(node);
+}
+
+static void chain_init_(FLAC__Metadata_Chain *chain)
+{
+ FLAC__ASSERT(0 != chain);
+
+ chain->filename = 0;
+ chain->is_ogg = false;
+ chain->head = chain->tail = 0;
+ chain->nodes = 0;
+ chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+ chain->initial_length = 0;
+ chain->read_cb = 0;
+}
+
+static void chain_clear_(FLAC__Metadata_Chain *chain)
+{
+ FLAC__Metadata_Node *node, *next;
+
+ FLAC__ASSERT(0 != chain);
+
+ for(node = chain->head; node; ) {
+ next = node->next;
+ node_delete_(node);
+ node = next;
+ }
+
+ if(0 != chain->filename)
+ free(chain->filename);
+
+ chain_init_(chain);
+}
+
+static void chain_append_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+ FLAC__ASSERT(0 != chain);
+ FLAC__ASSERT(0 != node);
+ FLAC__ASSERT(0 != node->data);
+
+ node->next = node->prev = 0;
+ node->data->is_last = true;
+ if(0 != chain->tail)
+ chain->tail->data->is_last = false;
+
+ if(0 == chain->head)
+ chain->head = node;
+ else {
+ FLAC__ASSERT(0 != chain->tail);
+ chain->tail->next = node;
+ node->prev = chain->tail;
+ }
+ chain->tail = node;
+ chain->nodes++;
+}
+
+static void chain_remove_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+ FLAC__ASSERT(0 != chain);
+ FLAC__ASSERT(0 != node);
+
+ if(node == chain->head)
+ chain->head = node->next;
+ else
+ node->prev->next = node->next;
+
+ if(node == chain->tail)
+ chain->tail = node->prev;
+ else
+ node->next->prev = node->prev;
+
+ if(0 != chain->tail)
+ chain->tail->data->is_last = true;
+
+ chain->nodes--;
+}
+
+static void chain_delete_node_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+ chain_remove_node_(chain, node);
+ node_delete_(node);
+}
+
+static off_t chain_calculate_length_(FLAC__Metadata_Chain *chain)
+{
+ const FLAC__Metadata_Node *node;
+ off_t length = 0;
+ for(node = chain->head; node; node = node->next)
+ length += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+ return length;
+}
+
+static void iterator_insert_node_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+ FLAC__ASSERT(0 != node);
+ FLAC__ASSERT(0 != node->data);
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->current);
+ FLAC__ASSERT(0 != iterator->chain);
+ FLAC__ASSERT(0 != iterator->chain->head);
+ FLAC__ASSERT(0 != iterator->chain->tail);
+
+ node->data->is_last = false;
+
+ node->prev = iterator->current->prev;
+ node->next = iterator->current;
+
+ if(0 == node->prev)
+ iterator->chain->head = node;
+ else
+ node->prev->next = node;
+
+ iterator->current->prev = node;
+
+ iterator->chain->nodes++;
+}
+
+static void iterator_insert_node_after_(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Node *node)
+{
+ FLAC__ASSERT(0 != node);
+ FLAC__ASSERT(0 != node->data);
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->current);
+ FLAC__ASSERT(0 != iterator->chain);
+ FLAC__ASSERT(0 != iterator->chain->head);
+ FLAC__ASSERT(0 != iterator->chain->tail);
+
+ iterator->current->data->is_last = false;
+
+ node->prev = iterator->current;
+ node->next = iterator->current->next;
+
+ if(0 == node->next)
+ iterator->chain->tail = node;
+ else
+ node->next->prev = node;
+
+ node->prev->next = node;
+
+ iterator->chain->tail->data->is_last = true;
+
+ iterator->chain->nodes++;
+}
+
+/* return true iff node and node->next are both padding */
+static FLAC__bool chain_merge_adjacent_padding_(FLAC__Metadata_Chain *chain, FLAC__Metadata_Node *node)
+{
+ if(node->data->type == FLAC__METADATA_TYPE_PADDING && 0 != node->next && node->next->data->type == FLAC__METADATA_TYPE_PADDING) {
+ const unsigned growth = FLAC__STREAM_METADATA_HEADER_LENGTH + node->next->data->length;
+ node->data->length += growth;
+
+ chain_delete_node_(chain, node->next);
+ return true;
+ }
+ else
+ return false;
+}
+
+/* Returns the new length of the chain, or 0 if there was an error. */
+/* WATCHOUT: This can get called multiple times before a write, so
+ * it should still work when this happens.
+ */
+/* WATCHOUT: Make sure to also update the logic in
+ * FLAC__metadata_chain_check_if_tempfile_needed() if the logic here changes.
+ */
+static off_t chain_prepare_for_write_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+ off_t current_length = chain_calculate_length_(chain);
+
+ if(use_padding) {
+ /* if the metadata shrank and the last block is padding, we just extend the last padding block */
+ if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+ const off_t delta = chain->initial_length - current_length;
+ chain->tail->data->length += delta;
+ current_length += delta;
+ FLAC__ASSERT(current_length == chain->initial_length);
+ }
+ /* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+ else if(current_length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length) {
+ FLAC__StreamMetadata *padding;
+ FLAC__Metadata_Node *node;
+ if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING))) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ padding->length = chain->initial_length - (FLAC__STREAM_METADATA_HEADER_LENGTH + current_length);
+ if(0 == (node = node_new_())) {
+ FLAC__metadata_object_delete(padding);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return 0;
+ }
+ node->data = padding;
+ chain_append_node_(chain, node);
+ current_length = chain_calculate_length_(chain);
+ FLAC__ASSERT(current_length == chain->initial_length);
+ }
+ /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+ else if(current_length > chain->initial_length) {
+ const off_t delta = current_length - chain->initial_length;
+ if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+ /* if the delta is exactly the size of the last padding block, remove the padding block */
+ if((off_t)chain->tail->data->length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta) {
+ chain_delete_node_(chain, chain->tail);
+ current_length = chain_calculate_length_(chain);
+ FLAC__ASSERT(current_length == chain->initial_length);
+ }
+ /* if there is at least 'delta' bytes of padding, trim the padding down */
+ else if((off_t)chain->tail->data->length >= delta) {
+ chain->tail->data->length -= delta;
+ current_length -= delta;
+ FLAC__ASSERT(current_length == chain->initial_length);
+ }
+ }
+ }
+ }
+
+ return current_length;
+}
+
+static FLAC__bool chain_read_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Tell tell_cb)
+{
+ FLAC__Metadata_Node *node;
+
+ FLAC__ASSERT(0 != chain);
+
+ /* we assume we're already at the beginning of the file */
+
+ switch(seek_to_first_metadata_block_cb_(handle, read_cb, seek_cb)) {
+ case 0:
+ break;
+ case 1:
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+ return false;
+ case 2:
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ case 3:
+ chain->status = FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+ return false;
+ default:
+ FLAC__ASSERT(0);
+ return false;
+ }
+
+ {
+ FLAC__int64 pos = tell_cb(handle);
+ if(pos < 0) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+ return false;
+ }
+ chain->first_offset = (off_t)pos;
+ }
+
+ {
+ FLAC__bool is_last;
+ FLAC__MetadataType type;
+ unsigned length;
+
+ do {
+ node = node_new_();
+ if(0 == node) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ if(!read_metadata_block_header_cb_(handle, read_cb, &is_last, &type, &length)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+ return false;
+ }
+
+ node->data = FLAC__metadata_object_new(type);
+ if(0 == node->data) {
+ node_delete_(node);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ node->data->is_last = is_last;
+ node->data->length = length;
+
+ chain->status = get_equivalent_status_(read_metadata_block_data_cb_(handle, read_cb, seek_cb, node->data));
+ if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+ node_delete_(node);
+ return false;
+ }
+ chain_append_node_(chain, node);
+ } while(!is_last);
+ }
+
+ {
+ FLAC__int64 pos = tell_cb(handle);
+ if(pos < 0) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+ return false;
+ }
+ chain->last_offset = (off_t)pos;
+ }
+
+ chain->initial_length = chain_calculate_length_(chain);
+
+ return true;
+}
+
+static
+FLAC__StreamDecoderReadStatus chain_read_ogg_read_cb_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+ (void)decoder;
+ if(*bytes > 0 && chain->status == FLAC__METADATA_CHAIN_STATUS_OK) {
+ *bytes = chain->read_cb(buffer, sizeof(FLAC__byte), *bytes, chain->handle);
+ if(*bytes == 0)
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+}
+
+static FLAC__StreamDecoderWriteStatus chain_read_ogg_write_cb_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ (void)decoder, (void)frame, (void)buffer, (void)client_data;
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+}
+
+static void chain_read_ogg_metadata_cb_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+ FLAC__Metadata_Node *node;
+
+ (void)decoder;
+
+ node = node_new_();
+ if(0 == node) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ node->data = FLAC__metadata_object_clone(metadata);
+ if(0 == node->data) {
+ node_delete_(node);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return;
+ }
+
+ chain_append_node_(chain, node);
+}
+
+static void chain_read_ogg_error_cb_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)client_data;
+ (void)decoder, (void)status;
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+}
+
+static FLAC__bool chain_read_ogg_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb)
+{
+ FLAC__StreamDecoder *decoder;
+
+ FLAC__ASSERT(0 != chain);
+
+ /* we assume we're already at the beginning of the file */
+
+ chain->handle = handle;
+ chain->read_cb = read_cb;
+ if(0 == (decoder = FLAC__stream_decoder_new())) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ FLAC__stream_decoder_set_metadata_respond_all(decoder);
+ if(FLAC__stream_decoder_init_ogg_stream(decoder, chain_read_ogg_read_cb_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, chain_read_ogg_write_cb_, chain_read_ogg_metadata_cb_, chain_read_ogg_error_cb_, chain) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ FLAC__stream_decoder_delete(decoder);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+ return false;
+ }
+
+ chain->first_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
+
+ if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR; /*@@@ maybe needs better error code */
+ if(chain->status != FLAC__METADATA_CHAIN_STATUS_OK) {
+ FLAC__stream_decoder_delete(decoder);
+ return false;
+ }
+
+ FLAC__stream_decoder_delete(decoder);
+
+ chain->last_offset = 0; /*@@@ wrong; will need to be set correctly to implement metadata writing for Ogg FLAC */
+
+ chain->initial_length = chain_calculate_length_(chain);
+
+ return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, FLAC__IOCallback_Seek seek_cb)
+{
+ FLAC__Metadata_Node *node;
+
+ FLAC__ASSERT(0 != chain);
+ FLAC__ASSERT(0 != chain->head);
+
+ if(0 != seek_cb(handle, chain->first_offset, SEEK_SET)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ for(node = chain->head; node; node = node->next) {
+ if(!write_metadata_block_header_cb_(handle, write_cb, node->data)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ if(!write_metadata_block_data_cb_(handle, write_cb, node->data)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+ chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+ return true;
+}
+
+static FLAC__bool chain_rewrite_metadata_in_place_(FLAC__Metadata_Chain *chain)
+{
+ FILE *file;
+ FLAC__bool ret;
+
+ FLAC__ASSERT(0 != chain->filename);
+
+ if(0 == (file = fopen(chain->filename, "r+b"))) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+
+ /* chain_rewrite_metadata_in_place_cb_() sets chain->status for us */
+ ret = chain_rewrite_metadata_in_place_cb_(chain, (FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, fseek_wrapper_);
+
+ fclose(file);
+
+ return ret;
+}
+
+static FLAC__bool chain_rewrite_file_(FLAC__Metadata_Chain *chain, const char *tempfile_path_prefix)
+{
+ FILE *f, *tempfile;
+ char *tempfilename;
+ FLAC__Metadata_SimpleIteratorStatus status;
+ const FLAC__Metadata_Node *node;
+
+ FLAC__ASSERT(0 != chain);
+ FLAC__ASSERT(0 != chain->filename);
+ FLAC__ASSERT(0 != chain->head);
+
+ /* copy the file prefix (data up to first metadata block */
+ if(0 == (f = fopen(chain->filename, "rb"))) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+ if(!open_tempfile_(chain->filename, tempfile_path_prefix, &tempfile, &tempfilename, &status)) {
+ chain->status = get_equivalent_status_(status);
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ return false;
+ }
+ if(!copy_n_bytes_from_file_(f, tempfile, chain->first_offset, &status)) {
+ chain->status = get_equivalent_status_(status);
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ return false;
+ }
+
+ /* write the metadata */
+ for(node = chain->head; node; node = node->next) {
+ if(!write_metadata_block_header_(tempfile, &status, node->data)) {
+ chain->status = get_equivalent_status_(status);
+ return false;
+ }
+ if(!write_metadata_block_data_(tempfile, &status, node->data)) {
+ chain->status = get_equivalent_status_(status);
+ return false;
+ }
+ }
+ /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+ /* copy the file postfix (everything after the metadata) */
+ if(0 != fseeko(f, chain->last_offset, SEEK_SET)) {
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(!copy_remaining_bytes_from_file_(f, tempfile, &status)) {
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ chain->status = get_equivalent_status_(status);
+ return false;
+ }
+
+ /* move the tempfile on top of the original */
+ (void)fclose(f);
+ if(!transport_tempfile_(chain->filename, &tempfile, &tempfilename, &status))
+ return false;
+
+ return true;
+}
+
+/* assumes 'handle' is already at beginning of file */
+static FLAC__bool chain_rewrite_file_cb_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb)
+{
+ FLAC__Metadata_SimpleIteratorStatus status;
+ const FLAC__Metadata_Node *node;
+
+ FLAC__ASSERT(0 != chain);
+ FLAC__ASSERT(0 == chain->filename);
+ FLAC__ASSERT(0 != chain->head);
+
+ /* copy the file prefix (data up to first metadata block */
+ if(!copy_n_bytes_from_file_cb_(handle, read_cb, temp_handle, temp_write_cb, chain->first_offset, &status)) {
+ chain->status = get_equivalent_status_(status);
+ return false;
+ }
+
+ /* write the metadata */
+ for(node = chain->head; node; node = node->next) {
+ if(!write_metadata_block_header_cb_(temp_handle, temp_write_cb, node->data)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ if(!write_metadata_block_data_cb_(temp_handle, temp_write_cb, node->data)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+ /*FLAC__ASSERT(fflush(), ftello() == chain->last_offset);*/
+
+ /* copy the file postfix (everything after the metadata) */
+ if(0 != seek_cb(handle, chain->last_offset, SEEK_SET)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(!copy_remaining_bytes_from_file_cb_(handle, read_cb, eof_cb, temp_handle, temp_write_cb, &status)) {
+ chain->status = get_equivalent_status_(status);
+ return false;
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__Metadata_Chain *FLAC__metadata_chain_new(void)
+{
+ FLAC__Metadata_Chain *chain = (FLAC__Metadata_Chain*)calloc(1, sizeof(FLAC__Metadata_Chain));
+
+ if(0 != chain)
+ chain_init_(chain);
+
+ return chain;
+}
+
+FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain)
+{
+ FLAC__ASSERT(0 != chain);
+
+ chain_clear_(chain);
+
+ free(chain);
+}
+
+FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain)
+{
+ FLAC__Metadata_ChainStatus status;
+
+ FLAC__ASSERT(0 != chain);
+
+ status = chain->status;
+ chain->status = FLAC__METADATA_CHAIN_STATUS_OK;
+ return status;
+}
+
+static FLAC__bool chain_read_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool is_ogg)
+{
+ FILE *file;
+ FLAC__bool ret;
+
+ FLAC__ASSERT(0 != chain);
+ FLAC__ASSERT(0 != filename);
+
+ chain_clear_(chain);
+
+ if(0 == (chain->filename = strdup(filename))) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ chain->is_ogg = is_ogg;
+
+ if(0 == (file = fopen(filename, "rb"))) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+
+ /* the function also sets chain->status for us */
+ ret = is_ogg?
+ chain_read_ogg_cb_(chain, file, (FLAC__IOCallback_Read)fread) :
+ chain_read_cb_(chain, file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, ftell_wrapper_)
+ ;
+
+ fclose(file);
+
+ return ret;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename)
+{
+ return chain_read_(chain, filename, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg(FLAC__Metadata_Chain *chain, const char *filename)
+{
+ return chain_read_(chain, filename, /*is_ogg=*/true);
+}
+
+static FLAC__bool chain_read_with_callbacks_(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__bool is_ogg)
+{
+ FLAC__bool ret;
+
+ FLAC__ASSERT(0 != chain);
+
+ chain_clear_(chain);
+
+ if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.tell) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+ return false;
+ }
+
+ chain->is_ogg = is_ogg;
+
+ /* rewind */
+ if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ /* the function also sets chain->status for us */
+ ret = is_ogg?
+ chain_read_ogg_cb_(chain, handle, callbacks.read) :
+ chain_read_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.tell)
+ ;
+
+ return ret;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+ return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_read_ogg_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+ return chain_read_with_callbacks_(chain, handle, callbacks, /*is_ogg=*/true);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_check_if_tempfile_needed(FLAC__Metadata_Chain *chain, FLAC__bool use_padding)
+{
+ /* This does all the same checks that are in chain_prepare_for_write_()
+ * but doesn't actually alter the chain. Make sure to update the logic
+ * here if chain_prepare_for_write_() changes.
+ */
+ const off_t current_length = chain_calculate_length_(chain);
+
+ FLAC__ASSERT(0 != chain);
+
+ if(use_padding) {
+ /* if the metadata shrank and the last block is padding, we just extend the last padding block */
+ if(current_length < chain->initial_length && chain->tail->data->type == FLAC__METADATA_TYPE_PADDING)
+ return false;
+ /* if the metadata shrank more than 4 bytes then there's room to add another padding block */
+ else if(current_length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH <= chain->initial_length)
+ return false;
+ /* if the metadata grew but the last block is padding, try cutting the padding to restore the original length so we don't have to rewrite the whole file */
+ else if(current_length > chain->initial_length) {
+ const off_t delta = current_length - chain->initial_length;
+ if(chain->tail->data->type == FLAC__METADATA_TYPE_PADDING) {
+ /* if the delta is exactly the size of the last padding block, remove the padding block */
+ if((off_t)chain->tail->data->length + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH == delta)
+ return false;
+ /* if there is at least 'delta' bytes of padding, trim the padding down */
+ else if((off_t)chain->tail->data->length >= delta)
+ return false;
+ }
+ }
+ }
+
+ return (current_length != chain->initial_length);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats)
+{
+ struct stat stats;
+ const char *tempfile_path_prefix = 0;
+ off_t current_length;
+
+ FLAC__ASSERT(0 != chain);
+
+ if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+ return false;
+ }
+
+ if (0 == chain->filename) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+ return false;
+ }
+
+ current_length = chain_prepare_for_write_(chain, use_padding);
+
+ /* a return value of 0 means there was an error; chain->status is already set */
+ if (0 == current_length)
+ return false;
+
+ if(preserve_file_stats)
+ get_file_stats_(chain->filename, &stats);
+
+ if(current_length == chain->initial_length) {
+ if(!chain_rewrite_metadata_in_place_(chain))
+ return false;
+ }
+ else {
+ if(!chain_rewrite_file_(chain, tempfile_path_prefix))
+ return false;
+
+ /* recompute lengths and offsets */
+ {
+ const FLAC__Metadata_Node *node;
+ chain->initial_length = current_length;
+ chain->last_offset = chain->first_offset;
+ for(node = chain->head; node; node = node->next)
+ chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+ }
+ }
+
+ if(preserve_file_stats)
+ set_file_stats_(chain->filename, &stats);
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks)
+{
+ off_t current_length;
+
+ FLAC__ASSERT(0 != chain);
+
+ if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+ return false;
+ }
+
+ if (0 != chain->filename) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+ return false;
+ }
+
+ if (0 == callbacks.write || 0 == callbacks.seek) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+ return false;
+ }
+
+ if (FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+ return false;
+ }
+
+ current_length = chain_prepare_for_write_(chain, use_padding);
+
+ /* a return value of 0 means there was an error; chain->status is already set */
+ if (0 == current_length)
+ return false;
+
+ FLAC__ASSERT(current_length == chain->initial_length);
+
+ return chain_rewrite_metadata_in_place_cb_(chain, handle, callbacks.write, callbacks.seek);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_chain_write_with_callbacks_and_tempfile(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__IOHandle handle, FLAC__IOCallbacks callbacks, FLAC__IOHandle temp_handle, FLAC__IOCallbacks temp_callbacks)
+{
+ off_t current_length;
+
+ FLAC__ASSERT(0 != chain);
+
+ if (chain->is_ogg) { /* cannot write back to Ogg FLAC yet */
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+ return false;
+ }
+
+ if (0 != chain->filename) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH;
+ return false;
+ }
+
+ if (0 == callbacks.read || 0 == callbacks.seek || 0 == callbacks.eof) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+ return false;
+ }
+ if (0 == temp_callbacks.write) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_INVALID_CALLBACKS;
+ return false;
+ }
+
+ if (!FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL;
+ return false;
+ }
+
+ current_length = chain_prepare_for_write_(chain, use_padding);
+
+ /* a return value of 0 means there was an error; chain->status is already set */
+ if (0 == current_length)
+ return false;
+
+ FLAC__ASSERT(current_length != chain->initial_length);
+
+ /* rewind */
+ if(0 != callbacks.seek(handle, 0, SEEK_SET)) {
+ chain->status = FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ if(!chain_rewrite_file_cb_(chain, handle, callbacks.read, callbacks.seek, callbacks.eof, temp_handle, temp_callbacks.write))
+ return false;
+
+ /* recompute lengths and offsets */
+ {
+ const FLAC__Metadata_Node *node;
+ chain->initial_length = current_length;
+ chain->last_offset = chain->first_offset;
+ for(node = chain->head; node; node = node->next)
+ chain->last_offset += (FLAC__STREAM_METADATA_HEADER_LENGTH + node->data->length);
+ }
+
+ return true;
+}
+
+FLAC_API void FLAC__metadata_chain_merge_padding(FLAC__Metadata_Chain *chain)
+{
+ FLAC__Metadata_Node *node;
+
+ FLAC__ASSERT(0 != chain);
+
+ for(node = chain->head; node; ) {
+ if(!chain_merge_adjacent_padding_(chain, node))
+ node = node->next;
+ }
+}
+
+FLAC_API void FLAC__metadata_chain_sort_padding(FLAC__Metadata_Chain *chain)
+{
+ FLAC__Metadata_Node *node, *save;
+ unsigned i;
+
+ FLAC__ASSERT(0 != chain);
+
+ /*
+ * Don't try and be too smart... this simple algo is good enough for
+ * the small number of nodes that we deal with.
+ */
+ for(i = 0, node = chain->head; i < chain->nodes; i++) {
+ if(node->data->type == FLAC__METADATA_TYPE_PADDING) {
+ save = node->next;
+ chain_remove_node_(chain, node);
+ chain_append_node_(chain, node);
+ node = save;
+ }
+ else {
+ node = node->next;
+ }
+ }
+
+ FLAC__metadata_chain_merge_padding(chain);
+}
+
+
+FLAC_API FLAC__Metadata_Iterator *FLAC__metadata_iterator_new(void)
+{
+ FLAC__Metadata_Iterator *iterator = (FLAC__Metadata_Iterator*)calloc(1, sizeof(FLAC__Metadata_Iterator));
+
+ /* calloc() implies:
+ iterator->current = 0;
+ iterator->chain = 0;
+ */
+
+ return iterator;
+}
+
+FLAC_API void FLAC__metadata_iterator_delete(FLAC__Metadata_Iterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+
+ free(iterator);
+}
+
+FLAC_API void FLAC__metadata_iterator_init(FLAC__Metadata_Iterator *iterator, FLAC__Metadata_Chain *chain)
+{
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != chain);
+ FLAC__ASSERT(0 != chain->head);
+
+ iterator->chain = chain;
+ iterator->current = chain->head;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_next(FLAC__Metadata_Iterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+
+ if(0 == iterator->current || 0 == iterator->current->next)
+ return false;
+
+ iterator->current = iterator->current->next;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_prev(FLAC__Metadata_Iterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+
+ if(0 == iterator->current || 0 == iterator->current->prev)
+ return false;
+
+ iterator->current = iterator->current->prev;
+ return true;
+}
+
+FLAC_API FLAC__MetadataType FLAC__metadata_iterator_get_block_type(const FLAC__Metadata_Iterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->current);
+ FLAC__ASSERT(0 != iterator->current->data);
+
+ return iterator->current->data->type;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_iterator_get_block(FLAC__Metadata_Iterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->current);
+
+ return iterator->current->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_set_block(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != block);
+ return FLAC__metadata_iterator_delete_block(iterator, false) && FLAC__metadata_iterator_insert_block_after(iterator, block);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_delete_block(FLAC__Metadata_Iterator *iterator, FLAC__bool replace_with_padding)
+{
+ FLAC__Metadata_Node *save;
+
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->current);
+
+ if(0 == iterator->current->prev) {
+ FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
+ return false;
+ }
+
+ save = iterator->current->prev;
+
+ if(replace_with_padding) {
+ FLAC__metadata_object_delete_data(iterator->current->data);
+ iterator->current->data->type = FLAC__METADATA_TYPE_PADDING;
+ }
+ else {
+ chain_delete_node_(iterator->chain, iterator->current);
+ }
+
+ iterator->current = save;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_before(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+ FLAC__Metadata_Node *node;
+
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->current);
+ FLAC__ASSERT(0 != block);
+
+ if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+ return false;
+
+ if(0 == iterator->current->prev) {
+ FLAC__ASSERT(iterator->current->data->type == FLAC__METADATA_TYPE_STREAMINFO);
+ return false;
+ }
+
+ if(0 == (node = node_new_()))
+ return false;
+
+ node->data = block;
+ iterator_insert_node_(iterator, node);
+ iterator->current = node;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_iterator_insert_block_after(FLAC__Metadata_Iterator *iterator, FLAC__StreamMetadata *block)
+{
+ FLAC__Metadata_Node *node;
+
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->current);
+ FLAC__ASSERT(0 != block);
+
+ if(block->type == FLAC__METADATA_TYPE_STREAMINFO)
+ return false;
+
+ if(0 == (node = node_new_()))
+ return false;
+
+ node->data = block;
+ iterator_insert_node_after_(iterator, node);
+ iterator->current = node;
+ return true;
+}
+
+
+/****************************************************************************
+ *
+ * Local function definitions
+ *
+ ***************************************************************************/
+
+void pack_uint32_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
+{
+ unsigned i;
+
+ b += bytes;
+
+ for(i = 0; i < bytes; i++) {
+ *(--b) = (FLAC__byte)(val & 0xff);
+ val >>= 8;
+ }
+}
+
+void pack_uint32_little_endian_(FLAC__uint32 val, FLAC__byte *b, unsigned bytes)
+{
+ unsigned i;
+
+ for(i = 0; i < bytes; i++) {
+ *(b++) = (FLAC__byte)(val & 0xff);
+ val >>= 8;
+ }
+}
+
+void pack_uint64_(FLAC__uint64 val, FLAC__byte *b, unsigned bytes)
+{
+ unsigned i;
+
+ b += bytes;
+
+ for(i = 0; i < bytes; i++) {
+ *(--b) = (FLAC__byte)(val & 0xff);
+ val >>= 8;
+ }
+}
+
+FLAC__uint32 unpack_uint32_(FLAC__byte *b, unsigned bytes)
+{
+ FLAC__uint32 ret = 0;
+ unsigned i;
+
+ for(i = 0; i < bytes; i++)
+ ret = (ret << 8) | (FLAC__uint32)(*b++);
+
+ return ret;
+}
+
+FLAC__uint32 unpack_uint32_little_endian_(FLAC__byte *b, unsigned bytes)
+{
+ FLAC__uint32 ret = 0;
+ unsigned i;
+
+ b += bytes;
+
+ for(i = 0; i < bytes; i++)
+ ret = (ret << 8) | (FLAC__uint32)(*--b);
+
+ return ret;
+}
+
+FLAC__uint64 unpack_uint64_(FLAC__byte *b, unsigned bytes)
+{
+ FLAC__uint64 ret = 0;
+ unsigned i;
+
+ for(i = 0; i < bytes; i++)
+ ret = (ret << 8) | (FLAC__uint64)(*b++);
+
+ return ret;
+}
+
+FLAC__bool read_metadata_block_header_(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+
+ if(!read_metadata_block_header_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, &iterator->is_last, &iterator->type, &iterator->length)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool read_metadata_block_data_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block)
+{
+ FLAC__ASSERT(0 != iterator);
+ FLAC__ASSERT(0 != iterator->file);
+
+ iterator->status = read_metadata_block_data_cb_((FLAC__IOHandle)iterator->file, (FLAC__IOCallback_Read)fread, fseek_wrapper_, block);
+
+ return (iterator->status == FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK);
+}
+
+FLAC__bool read_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__bool *is_last, FLAC__MetadataType *type, unsigned *length)
+{
+ FLAC__byte raw_header[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+ if(read_cb(raw_header, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+ return false;
+
+ *is_last = raw_header[0] & 0x80? true : false;
+ *type = (FLAC__MetadataType)(raw_header[0] & 0x7f);
+ *length = unpack_uint32_(raw_header + 1, 3);
+
+ /* Note that we don't check:
+ * if(iterator->type >= FLAC__METADATA_TYPE_UNDEFINED)
+ * we just will read in an opaque block
+ */
+
+ return true;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata *block)
+{
+ switch(block->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ return read_metadata_block_data_streaminfo_cb_(handle, read_cb, &block->data.stream_info);
+ case FLAC__METADATA_TYPE_PADDING:
+ return read_metadata_block_data_padding_cb_(handle, seek_cb, &block->data.padding, block->length);
+ case FLAC__METADATA_TYPE_APPLICATION:
+ return read_metadata_block_data_application_cb_(handle, read_cb, &block->data.application, block->length);
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ return read_metadata_block_data_seektable_cb_(handle, read_cb, &block->data.seek_table, block->length);
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ return read_metadata_block_data_vorbis_comment_cb_(handle, read_cb, &block->data.vorbis_comment);
+ case FLAC__METADATA_TYPE_CUESHEET:
+ return read_metadata_block_data_cuesheet_cb_(handle, read_cb, &block->data.cue_sheet);
+ case FLAC__METADATA_TYPE_PICTURE:
+ return read_metadata_block_data_picture_cb_(handle, read_cb, &block->data.picture);
+ default:
+ return read_metadata_block_data_unknown_cb_(handle, read_cb, &block->data.unknown, block->length);
+ }
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_StreamInfo *block)
+{
+ FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH], *b;
+
+ if(read_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ b = buffer;
+
+ /* we are using hardcoded numbers for simplicity but we should
+ * probably eventually write a bit-level unpacker and use the
+ * _STREAMINFO_ constants.
+ */
+ block->min_blocksize = unpack_uint32_(b, 2); b += 2;
+ block->max_blocksize = unpack_uint32_(b, 2); b += 2;
+ block->min_framesize = unpack_uint32_(b, 3); b += 3;
+ block->max_framesize = unpack_uint32_(b, 3); b += 3;
+ block->sample_rate = (unpack_uint32_(b, 2) << 4) | ((unsigned)(b[2] & 0xf0) >> 4);
+ block->channels = (unsigned)((b[2] & 0x0e) >> 1) + 1;
+ block->bits_per_sample = ((((unsigned)(b[2] & 0x01)) << 4) | (((unsigned)(b[3] & 0xf0)) >> 4)) + 1;
+ block->total_samples = (((FLAC__uint64)(b[3] & 0x0f)) << 32) | unpack_uint64_(b+4, 4);
+ memcpy(block->md5sum, b+8, 16);
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Seek seek_cb, FLAC__StreamMetadata_Padding *block, unsigned block_length)
+{
+ (void)block; /* nothing to do; we don't care about reading the padding bytes */
+
+ if(0 != seek_cb(handle, block_length, SEEK_CUR))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Application *block, unsigned block_length)
+{
+ const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+ if(read_cb(block->id, 1, id_bytes, handle) != id_bytes)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ block_length -= id_bytes;
+
+ if(block_length == 0) {
+ block->data = 0;
+ }
+ else {
+ if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ if(read_cb(block->data, 1, block_length, handle) != block_length)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_SeekTable *block, unsigned block_length)
+{
+ unsigned i;
+ FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+ FLAC__ASSERT(block_length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH == 0);
+
+ block->num_points = block_length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+ if(block->num_points == 0)
+ block->points = 0;
+ else if(0 == (block->points = (FLAC__StreamMetadata_SeekPoint*)malloc(block->num_points * sizeof(FLAC__StreamMetadata_SeekPoint))))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ for(i = 0; i < block->num_points; i++) {
+ if(read_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ /* some MAGIC NUMBERs here */
+ block->points[i].sample_number = unpack_uint64_(buffer, 8);
+ block->points[i].stream_offset = unpack_uint64_(buffer+8, 8);
+ block->points[i].frame_samples = unpack_uint32_(buffer+16, 2);
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_entry_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment_Entry *entry)
+{
+ const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+ FLAC__byte buffer[4]; /* magic number is asserted below */
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8 == sizeof(buffer));
+
+ if(read_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ entry->length = unpack_uint32_little_endian_(buffer, entry_length_len);
+
+ if(0 != entry->entry)
+ free(entry->entry);
+
+ if(entry->length == 0) {
+ entry->entry = 0;
+ }
+ else {
+ if(0 == (entry->entry = (FLAC__byte*)malloc(entry->length+1)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ if(read_cb(entry->entry, 1, entry->length, handle) != entry->length)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ entry->entry[entry->length] = '\0';
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_VorbisComment *block)
+{
+ unsigned i;
+ FLAC__Metadata_SimpleIteratorStatus status;
+ const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+ FLAC__byte buffer[4]; /* magic number is asserted below */
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8 == sizeof(buffer));
+
+ if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, &(block->vendor_string))))
+ return status;
+
+ if(read_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->num_comments = unpack_uint32_little_endian_(buffer, num_comments_len);
+
+ if(block->num_comments == 0) {
+ block->comments = 0;
+ }
+ else if(0 == (block->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(block->num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry))))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ for(i = 0; i < block->num_comments; i++) {
+ if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_vorbis_comment_entry_cb_(handle, read_cb, block->comments + i)))
+ return status;
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_track_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet_Track *track)
+{
+ unsigned i, len;
+ FLAC__byte buffer[32]; /* asserted below that this is big enough */
+
+ FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8);
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->offset = unpack_uint64_(buffer, len);
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+ if(read_cb(track->isrc, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
+ len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN == 1);
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN == 1);
+ track->type = buffer[0] >> 7;
+ track->pre_emphasis = (buffer[0] >> 6) & 1;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->num_indices = (FLAC__byte)unpack_uint32_(buffer, len);
+
+ if(track->num_indices == 0) {
+ track->indices = 0;
+ }
+ else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index))))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ for(i = 0; i < track->num_indices; i++) {
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->indices[i].offset = unpack_uint64_(buffer, len);
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ track->indices[i].number = (FLAC__byte)unpack_uint32_(buffer, len);
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_CueSheet *block)
+{
+ unsigned i, len;
+ FLAC__Metadata_SimpleIteratorStatus status;
+ FLAC__byte buffer[1024]; /* MSVC needs a constant expression so we put a magic number and assert */
+
+ FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)/8 <= sizeof(buffer));
+ FLAC__ASSERT(sizeof(FLAC__uint64) <= sizeof(buffer));
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+ if(read_cb(block->media_catalog_number, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->lead_in = unpack_uint64_(buffer, len);
+
+ FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
+ len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->is_cd = buffer[0]&0x80? true : false;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->num_tracks = unpack_uint32_(buffer, len);
+
+ if(block->num_tracks == 0) {
+ block->tracks = 0;
+ }
+ else if(0 == (block->tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc(block->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track))))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ for(i = 0; i < block->num_tracks; i++) {
+ if(FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK != (status = read_metadata_block_data_cuesheet_track_cb_(handle, read_cb, block->tracks + i)))
+ return status;
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+static
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cstring_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__byte **data, FLAC__uint32 *length, FLAC__uint32 length_len)
+{
+ FLAC__byte buffer[sizeof(FLAC__uint32)];
+
+ FLAC__ASSERT(0 != data);
+ FLAC__ASSERT(length_len%8 == 0);
+
+ length_len /= 8; /* convert to bytes */
+
+ FLAC__ASSERT(sizeof(buffer) >= length_len);
+
+ if(read_cb(buffer, 1, length_len, handle) != length_len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ *length = unpack_uint32_(buffer, length_len);
+
+ if(0 != *data)
+ free(*data);
+
+ if(0 == (*data = (FLAC__byte*)malloc(*length+1)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ if(*length > 0) {
+ if(read_cb(*data, 1, *length, handle) != *length)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ }
+
+ (*data)[*length] = '\0';
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Picture *block)
+{
+ FLAC__Metadata_SimpleIteratorStatus status;
+ FLAC__byte buffer[4]; /* asserted below that this is big enough */
+ FLAC__uint32 len;
+
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8);
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_TYPE_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->type = unpack_uint32_(buffer, len);
+
+ if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, (FLAC__byte**)(&(block->mime_type)), &len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+ return status;
+
+ if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->description), &len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+ return status;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->width = unpack_uint32_(buffer, len);
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->height = unpack_uint32_(buffer, len);
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->depth = unpack_uint32_(buffer, len);
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_PICTURE_COLORS_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN / 8;
+ if(read_cb(buffer, 1, len, handle) != len)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ block->colors = unpack_uint32_(buffer, len);
+
+ /* for convenience we use read_metadata_block_data_picture_cstring_cb_() even though it adds an extra terminating NUL we don't use */
+ if((status = read_metadata_block_data_picture_cstring_cb_(handle, read_cb, &(block->data), &(block->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) != FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK)
+ return status;
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__Metadata_SimpleIteratorStatus read_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__StreamMetadata_Unknown *block, unsigned block_length)
+{
+ if(block_length == 0) {
+ block->data = 0;
+ }
+ else {
+ if(0 == (block->data = (FLAC__byte*)malloc(block_length)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ if(read_cb(block->data, 1, block_length, handle) != block_length)
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ }
+
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+}
+
+FLAC__bool write_metadata_block_header_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+ FLAC__ASSERT(0 != file);
+ FLAC__ASSERT(0 != status);
+
+ if(!write_metadata_block_header_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_(FILE *file, FLAC__Metadata_SimpleIteratorStatus *status, const FLAC__StreamMetadata *block)
+{
+ FLAC__ASSERT(0 != file);
+ FLAC__ASSERT(0 != status);
+
+ if (write_metadata_block_data_cb_((FLAC__IOHandle)file, (FLAC__IOCallback_Write)fwrite, block)) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK;
+ return true;
+ }
+ else {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+}
+
+FLAC__bool write_metadata_block_header_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+ FLAC__byte buffer[FLAC__STREAM_METADATA_HEADER_LENGTH];
+
+ FLAC__ASSERT(block->length < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+
+ buffer[0] = (block->is_last? 0x80 : 0) | (FLAC__byte)block->type;
+ pack_uint32_(block->length, buffer + 1, 3);
+
+ if(write_cb(buffer, 1, FLAC__STREAM_METADATA_HEADER_LENGTH, handle) != FLAC__STREAM_METADATA_HEADER_LENGTH)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata *block)
+{
+ FLAC__ASSERT(0 != block);
+
+ switch(block->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ return write_metadata_block_data_streaminfo_cb_(handle, write_cb, &block->data.stream_info);
+ case FLAC__METADATA_TYPE_PADDING:
+ return write_metadata_block_data_padding_cb_(handle, write_cb, &block->data.padding, block->length);
+ case FLAC__METADATA_TYPE_APPLICATION:
+ return write_metadata_block_data_application_cb_(handle, write_cb, &block->data.application, block->length);
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ return write_metadata_block_data_seektable_cb_(handle, write_cb, &block->data.seek_table);
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ return write_metadata_block_data_vorbis_comment_cb_(handle, write_cb, &block->data.vorbis_comment);
+ case FLAC__METADATA_TYPE_CUESHEET:
+ return write_metadata_block_data_cuesheet_cb_(handle, write_cb, &block->data.cue_sheet);
+ case FLAC__METADATA_TYPE_PICTURE:
+ return write_metadata_block_data_picture_cb_(handle, write_cb, &block->data.picture);
+ default:
+ return write_metadata_block_data_unknown_cb_(handle, write_cb, &block->data.unknown, block->length);
+ }
+}
+
+FLAC__bool write_metadata_block_data_streaminfo_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_StreamInfo *block)
+{
+ FLAC__byte buffer[FLAC__STREAM_METADATA_STREAMINFO_LENGTH];
+ const unsigned channels1 = block->channels - 1;
+ const unsigned bps1 = block->bits_per_sample - 1;
+
+ /* we are using hardcoded numbers for simplicity but we should
+ * probably eventually write a bit-level packer and use the
+ * _STREAMINFO_ constants.
+ */
+ pack_uint32_(block->min_blocksize, buffer, 2);
+ pack_uint32_(block->max_blocksize, buffer+2, 2);
+ pack_uint32_(block->min_framesize, buffer+4, 3);
+ pack_uint32_(block->max_framesize, buffer+7, 3);
+ buffer[10] = (block->sample_rate >> 12) & 0xff;
+ buffer[11] = (block->sample_rate >> 4) & 0xff;
+ buffer[12] = ((block->sample_rate & 0x0f) << 4) | (channels1 << 1) | (bps1 >> 4);
+ buffer[13] = (FLAC__byte)(((bps1 & 0x0f) << 4) | ((block->total_samples >> 32) & 0x0f));
+ pack_uint32_((FLAC__uint32)block->total_samples, buffer+14, 4);
+ memcpy(buffer+18, block->md5sum, 16);
+
+ if(write_cb(buffer, 1, FLAC__STREAM_METADATA_STREAMINFO_LENGTH, handle) != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_padding_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Padding *block, unsigned block_length)
+{
+ unsigned i, n = block_length;
+ FLAC__byte buffer[1024];
+
+ (void)block;
+
+ memset(buffer, 0, 1024);
+
+ for(i = 0; i < n/1024; i++)
+ if(write_cb(buffer, 1, 1024, handle) != 1024)
+ return false;
+
+ n %= 1024;
+
+ if(write_cb(buffer, 1, n, handle) != n)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_application_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Application *block, unsigned block_length)
+{
+ const unsigned id_bytes = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+
+ if(write_cb(block->id, 1, id_bytes, handle) != id_bytes)
+ return false;
+
+ block_length -= id_bytes;
+
+ if(write_cb(block->data, 1, block_length, handle) != block_length)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_seektable_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_SeekTable *block)
+{
+ unsigned i;
+ FLAC__byte buffer[FLAC__STREAM_METADATA_SEEKPOINT_LENGTH];
+
+ for(i = 0; i < block->num_points; i++) {
+ /* some MAGIC NUMBERs here */
+ pack_uint64_(block->points[i].sample_number, buffer, 8);
+ pack_uint64_(block->points[i].stream_offset, buffer+8, 8);
+ pack_uint32_(block->points[i].frame_samples, buffer+16, 2);
+ if(write_cb(buffer, 1, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH, handle) != FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_vorbis_comment_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_VorbisComment *block)
+{
+ unsigned i;
+ const unsigned entry_length_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+ const unsigned num_comments_len = FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+ FLAC__byte buffer[4]; /* magic number is asserted below */
+
+ FLAC__ASSERT(max(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN, FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8 == sizeof(buffer));
+
+ pack_uint32_little_endian_(block->vendor_string.length, buffer, entry_length_len);
+ if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+ return false;
+ if(write_cb(block->vendor_string.entry, 1, block->vendor_string.length, handle) != block->vendor_string.length)
+ return false;
+
+ pack_uint32_little_endian_(block->num_comments, buffer, num_comments_len);
+ if(write_cb(buffer, 1, num_comments_len, handle) != num_comments_len)
+ return false;
+
+ for(i = 0; i < block->num_comments; i++) {
+ pack_uint32_little_endian_(block->comments[i].length, buffer, entry_length_len);
+ if(write_cb(buffer, 1, entry_length_len, handle) != entry_length_len)
+ return false;
+ if(write_cb(block->comments[i].entry, 1, block->comments[i].length, handle) != block->comments[i].length)
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_cuesheet_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_CueSheet *block)
+{
+ unsigned i, j, len;
+ FLAC__byte buffer[1024]; /* asserted below that this is big enough */
+
+ FLAC__ASSERT(sizeof(buffer) >= sizeof(FLAC__uint64));
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN/8);
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN / 8;
+ if(write_cb(block->media_catalog_number, 1, len, handle) != len)
+ return false;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN / 8;
+ pack_uint64_(block->lead_in, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) % 8 == 0);
+ len = (FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN + FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN) / 8;
+ memset(buffer, 0, len);
+ if(block->is_cd)
+ buffer[0] |= 0x80;
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN / 8;
+ pack_uint32_(block->num_tracks, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ for(i = 0; i < block->num_tracks; i++) {
+ FLAC__StreamMetadata_CueSheet_Track *track = block->tracks + i;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN / 8;
+ pack_uint64_(track->offset, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN / 8;
+ pack_uint32_(track->number, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN / 8;
+ if(write_cb(track->isrc, 1, len, handle) != len)
+ return false;
+
+ FLAC__ASSERT((FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) % 8 == 0);
+ len = (FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN + FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN) / 8;
+ memset(buffer, 0, len);
+ buffer[0] = (track->type << 7) | (track->pre_emphasis << 6);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN / 8;
+ pack_uint32_(track->num_indices, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ for(j = 0; j < track->num_indices; j++) {
+ FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + j;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN / 8;
+ pack_uint64_(indx->offset, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN / 8;
+ pack_uint32_(indx->number, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN % 8 == 0);
+ len = FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN / 8;
+ memset(buffer, 0, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_picture_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Picture *block)
+{
+ unsigned len;
+ size_t slen;
+ FLAC__byte buffer[4]; /* magic number is asserted below */
+
+ FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_TYPE_LEN%8);
+ FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN%8);
+ FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN%8);
+ FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN%8);
+ FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN%8);
+ FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN%8);
+ FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_COLORS_LEN%8);
+ FLAC__ASSERT(0 == FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN%8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8);
+ FLAC__ASSERT(sizeof(buffer) >= FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8);
+
+ len = FLAC__STREAM_METADATA_PICTURE_TYPE_LEN/8;
+ pack_uint32_(block->type, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN/8;
+ slen = strlen(block->mime_type);
+ pack_uint32_(slen, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+ if(write_cb(block->mime_type, 1, slen, handle) != slen)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN/8;
+ slen = strlen((const char *)block->description);
+ pack_uint32_(slen, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+ if(write_cb(block->description, 1, slen, handle) != slen)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN/8;
+ pack_uint32_(block->width, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN/8;
+ pack_uint32_(block->height, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN/8;
+ pack_uint32_(block->depth, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_COLORS_LEN/8;
+ pack_uint32_(block->colors, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+
+ len = FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN/8;
+ pack_uint32_(block->data_length, buffer, len);
+ if(write_cb(buffer, 1, len, handle) != len)
+ return false;
+ if(write_cb(block->data, 1, block->data_length, handle) != block->data_length)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_data_unknown_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Write write_cb, const FLAC__StreamMetadata_Unknown *block, unsigned block_length)
+{
+ if(write_cb(block->data, 1, block_length, handle) != block_length)
+ return false;
+
+ return true;
+}
+
+FLAC__bool write_metadata_block_stationary_(FLAC__Metadata_SimpleIterator *iterator, const FLAC__StreamMetadata *block)
+{
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+ return false;
+
+ if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+ return false;
+
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool write_metadata_block_stationary_with_padding_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, unsigned padding_length, FLAC__bool padding_is_last)
+{
+ FLAC__StreamMetadata *padding;
+
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ block->is_last = false;
+
+ if(!write_metadata_block_header_(iterator->file, &iterator->status, block))
+ return false;
+
+ if(!write_metadata_block_data_(iterator->file, &iterator->status, block))
+ return false;
+
+ if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+ return FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+
+ padding->is_last = padding_is_last;
+ padding->length = padding_length;
+
+ if(!write_metadata_block_header_(iterator->file, &iterator->status, padding)) {
+ FLAC__metadata_object_delete(padding);
+ return false;
+ }
+
+ if(!write_metadata_block_data_(iterator->file, &iterator->status, padding)) {
+ FLAC__metadata_object_delete(padding);
+ return false;
+ }
+
+ FLAC__metadata_object_delete(padding);
+
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ return read_metadata_block_header_(iterator);
+}
+
+FLAC__bool rewrite_whole_file_(FLAC__Metadata_SimpleIterator *iterator, FLAC__StreamMetadata *block, FLAC__bool append)
+{
+ FILE *tempfile;
+ char *tempfilename;
+ int fixup_is_last_code = 0; /* 0 => no need to change any is_last flags */
+ off_t fixup_is_last_flag_offset = -1;
+
+ FLAC__ASSERT(0 != block || append == false);
+
+ if(iterator->is_last) {
+ if(append) {
+ fixup_is_last_code = 1; /* 1 => clear the is_last flag at the following offset */
+ fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+ }
+ else if(0 == block) {
+ simple_iterator_push_(iterator);
+ if(!FLAC__metadata_simple_iterator_prev(iterator)) {
+ (void)simple_iterator_pop_(iterator);
+ return false;
+ }
+ fixup_is_last_code = -1; /* -1 => set the is_last the flag at the following offset */
+ fixup_is_last_flag_offset = iterator->offset[iterator->depth];
+ if(!simple_iterator_pop_(iterator))
+ return false;
+ }
+ }
+
+ if(!simple_iterator_copy_file_prefix_(iterator, &tempfile, &tempfilename, append))
+ return false;
+
+ if(0 != block) {
+ if(!write_metadata_block_header_(tempfile, &iterator->status, block)) {
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ return false;
+ }
+
+ if(!write_metadata_block_data_(tempfile, &iterator->status, block)) {
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ return false;
+ }
+ }
+
+ if(!simple_iterator_copy_file_postfix_(iterator, &tempfile, &tempfilename, fixup_is_last_code, fixup_is_last_flag_offset, block==0))
+ return false;
+
+ if(append)
+ return FLAC__metadata_simple_iterator_next(iterator);
+
+ return true;
+}
+
+void simple_iterator_push_(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__ASSERT(iterator->depth+1 < SIMPLE_ITERATOR_MAX_PUSH_DEPTH);
+ iterator->offset[iterator->depth+1] = iterator->offset[iterator->depth];
+ iterator->depth++;
+}
+
+FLAC__bool simple_iterator_pop_(FLAC__Metadata_SimpleIterator *iterator)
+{
+ FLAC__ASSERT(iterator->depth > 0);
+ iterator->depth--;
+ if(0 != fseeko(iterator->file, iterator->offset[iterator->depth], SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+
+ return read_metadata_block_header_(iterator);
+}
+
+/* return meanings:
+ * 0: ok
+ * 1: read error
+ * 2: seek error
+ * 3: not a FLAC file
+ */
+unsigned seek_to_first_metadata_block_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Seek seek_cb)
+{
+ FLAC__byte buffer[4];
+ size_t n;
+ unsigned i;
+
+ FLAC__ASSERT(FLAC__STREAM_SYNC_LENGTH == sizeof(buffer));
+
+ /* skip any id3v2 tag */
+ errno = 0;
+ n = read_cb(buffer, 1, 4, handle);
+ if(errno)
+ return 1;
+ else if(n != 4)
+ return 3;
+ else if(0 == memcmp(buffer, "ID3", 3)) {
+ unsigned tag_length = 0;
+
+ /* skip to the tag length */
+ if(seek_cb(handle, 2, SEEK_CUR) < 0)
+ return 2;
+
+ /* read the length */
+ for(i = 0; i < 4; i++) {
+ if(read_cb(buffer, 1, 1, handle) < 1 || buffer[0] & 0x80)
+ return 1;
+ tag_length <<= 7;
+ tag_length |= (buffer[0] & 0x7f);
+ }
+
+ /* skip the rest of the tag */
+ if(seek_cb(handle, tag_length, SEEK_CUR) < 0)
+ return 2;
+
+ /* read the stream sync code */
+ errno = 0;
+ n = read_cb(buffer, 1, 4, handle);
+ if(errno)
+ return 1;
+ else if(n != 4)
+ return 3;
+ }
+
+ /* check for the fLaC signature */
+ if(0 == memcmp(FLAC__STREAM_SYNC_STRING, buffer, FLAC__STREAM_SYNC_LENGTH))
+ return 0;
+ else
+ return 3;
+}
+
+unsigned seek_to_first_metadata_block_(FILE *f)
+{
+ return seek_to_first_metadata_block_cb_((FLAC__IOHandle)f, (FLAC__IOCallback_Read)fread, fseek_wrapper_);
+}
+
+FLAC__bool simple_iterator_copy_file_prefix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, FLAC__bool append)
+{
+ const off_t offset_end = append? iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length : iterator->offset[iterator->depth];
+
+ if(0 != fseeko(iterator->file, 0, SEEK_SET)) {
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(!open_tempfile_(iterator->filename, iterator->tempfile_path_prefix, tempfile, tempfilename, &iterator->status)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+ if(!copy_n_bytes_from_file_(iterator->file, *tempfile, offset_end, &iterator->status)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool simple_iterator_copy_file_postfix_(FLAC__Metadata_SimpleIterator *iterator, FILE **tempfile, char **tempfilename, int fixup_is_last_code, off_t fixup_is_last_flag_offset, FLAC__bool backup)
+{
+ off_t save_offset = iterator->offset[iterator->depth];
+ FLAC__ASSERT(0 != *tempfile);
+
+ if(0 != fseeko(iterator->file, save_offset + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length, SEEK_SET)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(!copy_remaining_bytes_from_file_(iterator->file, *tempfile, &iterator->status)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+
+ if(fixup_is_last_code != 0) {
+ /*
+ * if code == 1, it means a block was appended to the end so
+ * we have to clear the is_last flag of the previous block
+ * if code == -1, it means the last block was deleted so
+ * we have to set the is_last flag of the previous block
+ */
+ /* MAGIC NUMBERs here; we know the is_last flag is the high bit of the byte at this location */
+ FLAC__byte x;
+ if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(fread(&x, 1, 1, *tempfile) != 1) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(fixup_is_last_code > 0) {
+ FLAC__ASSERT(x & 0x80);
+ x &= 0x7f;
+ }
+ else {
+ FLAC__ASSERT(!(x & 0x80));
+ x |= 0x80;
+ }
+ if(0 != fseeko(*tempfile, fixup_is_last_flag_offset, SEEK_SET)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR;
+ return false;
+ }
+ if(local__fwrite(&x, 1, 1, *tempfile) != 1) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ iterator->status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ (void)fclose(iterator->file);
+
+ if(!transport_tempfile_(iterator->filename, tempfile, tempfilename, &iterator->status))
+ return false;
+
+ if(iterator->has_stats)
+ set_file_stats_(iterator->filename, &iterator->stats);
+
+ if(!simple_iterator_prime_input_(iterator, !iterator->is_writable))
+ return false;
+ if(backup) {
+ while(iterator->offset[iterator->depth] + (off_t)FLAC__STREAM_METADATA_HEADER_LENGTH + (off_t)iterator->length < save_offset)
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return false;
+ return true;
+ }
+ else {
+ /* move the iterator to it's original block faster by faking a push, then doing a pop_ */
+ FLAC__ASSERT(iterator->depth == 0);
+ iterator->offset[0] = save_offset;
+ iterator->depth++;
+ return simple_iterator_pop_(iterator);
+ }
+}
+
+FLAC__bool copy_n_bytes_from_file_(FILE *file, FILE *tempfile, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ FLAC__ASSERT(bytes >= 0);
+ while(bytes > 0) {
+ n = min(sizeof(buffer), (size_t)bytes);
+ if(fread(buffer, 1, n, file) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(local__fwrite(buffer, 1, n, tempfile) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ bytes -= n;
+ }
+
+ return true;
+}
+
+FLAC__bool copy_n_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, off_t bytes, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ FLAC__ASSERT(bytes >= 0);
+ while(bytes > 0) {
+ n = min(sizeof(buffer), (size_t)bytes);
+ if(read_cb(buffer, 1, n, handle) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(temp_write_cb(buffer, 1, n, temp_handle) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ bytes -= n;
+ }
+
+ return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_(FILE *file, FILE *tempfile, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ while(!feof(file)) {
+ n = fread(buffer, 1, sizeof(buffer), file);
+ if(n == 0 && !feof(file)) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(n > 0 && local__fwrite(buffer, 1, n, tempfile) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool copy_remaining_bytes_from_file_cb_(FLAC__IOHandle handle, FLAC__IOCallback_Read read_cb, FLAC__IOCallback_Eof eof_cb, FLAC__IOHandle temp_handle, FLAC__IOCallback_Write temp_write_cb, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__byte buffer[8192];
+ size_t n;
+
+ while(!eof_cb(handle)) {
+ n = read_cb(buffer, 1, sizeof(buffer), handle);
+ if(n == 0 && !eof_cb(handle)) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR;
+ return false;
+ }
+ if(n > 0 && temp_write_cb(buffer, 1, n, temp_handle) != n) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool open_tempfile_(const char *filename, const char *tempfile_path_prefix, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ static const char *tempfile_suffix = ".metadata_edit";
+ if(0 == tempfile_path_prefix) {
+ if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1))) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ strcpy(*tempfilename, filename);
+ strcat(*tempfilename, tempfile_suffix);
+ }
+ else {
+ const char *p = strrchr(filename, '/');
+ if(0 == p)
+ p = filename;
+ else
+ p++;
+
+ if(0 == (*tempfilename = (char*)malloc(strlen(tempfile_path_prefix) + 1 + strlen(p) + strlen(tempfile_suffix) + 1))) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ strcpy(*tempfilename, tempfile_path_prefix);
+ strcat(*tempfilename, "/");
+ strcat(*tempfilename, p);
+ strcat(*tempfilename, tempfile_suffix);
+ }
+
+ if(0 == (*tempfile = fopen(*tempfilename, "w+b"))) {
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE;
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename, FLAC__Metadata_SimpleIteratorStatus *status)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != tempfile);
+ FLAC__ASSERT(0 != *tempfile);
+ FLAC__ASSERT(0 != tempfilename);
+ FLAC__ASSERT(0 != *tempfilename);
+ FLAC__ASSERT(0 != status);
+
+ (void)fclose(*tempfile);
+ *tempfile = 0;
+
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__
+ /* on some flavors of windows, rename() will fail if the destination already exists */
+ if(unlink(filename) < 0) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR;
+ return false;
+ }
+#endif
+
+ /*@@@ to fully support the tempfile_path_prefix we need to update this piece to actually copy across filesystems instead of just rename(): */
+ if(0 != rename(*tempfilename, filename)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ *status = FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR;
+ return false;
+ }
+
+ cleanup_tempfile_(tempfile, tempfilename);
+
+ return true;
+}
+
+void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+ if(0 != *tempfile) {
+ (void)fclose(*tempfile);
+ *tempfile = 0;
+ }
+
+ if(0 != *tempfilename) {
+ (void)unlink(*tempfilename);
+ free(*tempfilename);
+ *tempfilename = 0;
+ }
+}
+
+FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+ return (0 == stat(filename, stats));
+}
+
+void set_file_stats_(const char *filename, struct stat *stats)
+{
+ struct utimbuf srctime;
+
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+
+ srctime.actime = stats->st_atime;
+ srctime.modtime = stats->st_mtime;
+ (void)chmod(filename, stats->st_mode);
+ (void)utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __BORLANDC__ && !defined __MINGW32__ && !defined __EMX__
+ (void)chown(filename, stats->st_uid, -1);
+ (void)chown(filename, -1, stats->st_gid);
+#endif
+}
+
+int fseek_wrapper_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+ return fseeko((FILE*)handle, (off_t)offset, whence);
+}
+
+FLAC__int64 ftell_wrapper_(FLAC__IOHandle handle)
+{
+ return ftello((FILE*)handle);
+}
+
+FLAC__Metadata_ChainStatus get_equivalent_status_(FLAC__Metadata_SimpleIteratorStatus status)
+{
+ switch(status) {
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_OK:
+ return FLAC__METADATA_CHAIN_STATUS_OK;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ILLEGAL_INPUT:
+ return FLAC__METADATA_CHAIN_STATUS_ILLEGAL_INPUT;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_ERROR_OPENING_FILE:
+ return FLAC__METADATA_CHAIN_STATUS_ERROR_OPENING_FILE;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_A_FLAC_FILE:
+ return FLAC__METADATA_CHAIN_STATUS_NOT_A_FLAC_FILE;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_NOT_WRITABLE:
+ return FLAC__METADATA_CHAIN_STATUS_NOT_WRITABLE;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_BAD_METADATA:
+ return FLAC__METADATA_CHAIN_STATUS_BAD_METADATA;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_READ_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_READ_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_SEEK_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_SEEK_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_WRITE_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_WRITE_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_RENAME_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_RENAME_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_UNLINK_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_UNLINK_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_MEMORY_ALLOCATION_ERROR:
+ return FLAC__METADATA_CHAIN_STATUS_MEMORY_ALLOCATION_ERROR;
+ case FLAC__METADATA_SIMPLE_ITERATOR_STATUS_INTERNAL_ERROR:
+ default:
+ return FLAC__METADATA_CHAIN_STATUS_INTERNAL_ERROR;
+ }
+}
diff --git a/src/FLAC/src/libFLAC/metadata_object.c b/src/FLAC/src/libFLAC/metadata_object.c
new file mode 100644
index 0000000..7511767
--- /dev/null
+++ b/src/FLAC/src/libFLAC/metadata_object.c
@@ -0,0 +1,1789 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "private/metadata.h"
+
+#include "FLAC/assert.h"
+
+
+/****************************************************************************
+ *
+ * Local routines
+ *
+ ***************************************************************************/
+
+/* copy bytes:
+ * from = NULL && bytes = 0
+ * to <- NULL
+ * from != NULL && bytes > 0
+ * to <- copy of from
+ * else ASSERT
+ * malloc error leaved 'to' unchanged
+ */
+static FLAC__bool copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
+{
+ FLAC__ASSERT(0 != to);
+ if(bytes > 0 && 0 != from) {
+ FLAC__byte *x;
+ if(0 == (x = (FLAC__byte*)malloc(bytes)))
+ return false;
+ memcpy(x, from, bytes);
+ *to = x;
+ }
+ else {
+ FLAC__ASSERT(0 == from);
+ FLAC__ASSERT(bytes == 0);
+ *to = 0;
+ }
+ return true;
+}
+
+#if 0 /* UNUSED */
+/* like copy_bytes_(), but free()s the original '*to' if the copy succeeds and the original '*to' is non-NULL */
+static FLAC__bool free_copy_bytes_(FLAC__byte **to, const FLAC__byte *from, unsigned bytes)
+{
+ FLAC__byte *copy;
+ FLAC__ASSERT(0 != to);
+ if(copy_bytes_(&copy, from, bytes)) {
+ if(*to)
+ free(*to);
+ *to = copy;
+ return true;
+ }
+ else
+ return false;
+}
+#endif
+
+/* reallocate entry to 1 byte larger and add a terminating NUL */
+/* realloc() failure leaves entry unchanged */
+static FLAC__bool ensure_null_terminated_(FLAC__byte **entry, unsigned length)
+{
+ FLAC__byte *x = (FLAC__byte*)realloc(*entry, length+1);
+ if(0 != x) {
+ x[length] = '\0';
+ *entry = x;
+ return true;
+ }
+ else
+ return false;
+}
+
+/* copies the NUL-terminated C-string 'from' to '*to', leaving '*to'
+ * unchanged if malloc fails, free()ing the original '*to' if it
+ * succeeds and the original '*to' was not NULL
+ */
+static FLAC__bool copy_cstring_(char **to, const char *from)
+{
+ char *copy = strdup(from);
+ FLAC__ASSERT(to);
+ if(copy) {
+ if(*to)
+ free(*to);
+ *to = copy;
+ return true;
+ }
+ else
+ return false;
+}
+
+static FLAC__bool copy_vcentry_(FLAC__StreamMetadata_VorbisComment_Entry *to, const FLAC__StreamMetadata_VorbisComment_Entry *from)
+{
+ to->length = from->length;
+ if(0 == from->entry) {
+ FLAC__ASSERT(from->length == 0);
+ to->entry = 0;
+ }
+ else {
+ FLAC__byte *x;
+ FLAC__ASSERT(from->length > 0);
+ if(0 == (x = (FLAC__byte*)malloc(from->length+1)))
+ return false;
+ memcpy(x, from->entry, from->length);
+ x[from->length] = '\0';
+ to->entry = x;
+ }
+ return true;
+}
+
+static FLAC__bool copy_track_(FLAC__StreamMetadata_CueSheet_Track *to, const FLAC__StreamMetadata_CueSheet_Track *from)
+{
+ memcpy(to, from, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+ if(0 == from->indices) {
+ FLAC__ASSERT(from->num_indices == 0);
+ }
+ else {
+ FLAC__StreamMetadata_CueSheet_Index *x;
+ FLAC__ASSERT(from->num_indices > 0);
+ if(0 == (x = (FLAC__StreamMetadata_CueSheet_Index*)malloc(from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index))))
+ return false;
+ memcpy(x, from->indices, from->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+ to->indices = x;
+ }
+ return true;
+}
+
+static void seektable_calculate_length_(FLAC__StreamMetadata *object)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+ object->length = object->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+}
+
+static FLAC__StreamMetadata_SeekPoint *seekpoint_array_new_(unsigned num_points)
+{
+ FLAC__StreamMetadata_SeekPoint *object_array;
+
+ FLAC__ASSERT(num_points > 0);
+
+ object_array = (FLAC__StreamMetadata_SeekPoint*)malloc(num_points * sizeof(FLAC__StreamMetadata_SeekPoint));
+
+ if(0 != object_array) {
+ unsigned i;
+ for(i = 0; i < num_points; i++) {
+ object_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ object_array[i].stream_offset = 0;
+ object_array[i].frame_samples = 0;
+ }
+ }
+
+ return object_array;
+}
+
+static void vorbiscomment_calculate_length_(FLAC__StreamMetadata *object)
+{
+ unsigned i;
+
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ object->length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN) / 8;
+ object->length += object->data.vorbis_comment.vendor_string.length;
+ object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN) / 8;
+ for(i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+ object->length += (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8);
+ object->length += object->data.vorbis_comment.comments[i].length;
+ }
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_new_(unsigned num_comments)
+{
+ FLAC__ASSERT(num_comments > 0);
+
+ return (FLAC__StreamMetadata_VorbisComment_Entry*)calloc(num_comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+}
+
+static void vorbiscomment_entry_array_delete_(FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != object_array && num_comments > 0);
+
+ for(i = 0; i < num_comments; i++)
+ if(0 != object_array[i].entry)
+ free(object_array[i].entry);
+
+ if(0 != object_array)
+ free(object_array);
+}
+
+static FLAC__StreamMetadata_VorbisComment_Entry *vorbiscomment_entry_array_copy_(const FLAC__StreamMetadata_VorbisComment_Entry *object_array, unsigned num_comments)
+{
+ FLAC__StreamMetadata_VorbisComment_Entry *return_array;
+
+ FLAC__ASSERT(0 != object_array);
+ FLAC__ASSERT(num_comments > 0);
+
+ return_array = vorbiscomment_entry_array_new_(num_comments);
+
+ if(0 != return_array) {
+ unsigned i;
+
+ for(i = 0; i < num_comments; i++) {
+ if(!copy_vcentry_(return_array+i, object_array+i)) {
+ vorbiscomment_entry_array_delete_(return_array, num_comments);
+ return 0;
+ }
+ }
+ }
+
+ return return_array;
+}
+
+static FLAC__bool vorbiscomment_set_entry_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry *dest, const FLAC__StreamMetadata_VorbisComment_Entry *src, FLAC__bool copy)
+{
+ FLAC__byte *save;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(0 != dest);
+ FLAC__ASSERT(0 != src);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ FLAC__ASSERT((0 != src->entry && src->length > 0) || (0 == src->entry && src->length == 0));
+
+ save = dest->entry;
+
+ if(0 != src->entry && src->length > 0) {
+ if(copy) {
+ /* do the copy first so that if we fail we leave the dest object untouched */
+ if(!copy_vcentry_(dest, src))
+ return false;
+ }
+ else {
+ /* we have to make sure that the string we're taking over is null-terminated */
+
+ /*
+ * Stripping the const from src->entry is OK since we're taking
+ * ownership of the pointer. This is a hack around a deficiency
+ * in the API where the same function is used for 'copy' and
+ * 'own', but the source entry is a const pointer. If we were
+ * precise, the 'own' flavor would be a separate function with a
+ * non-const source pointer. But it's not, so we hack away.
+ */
+ if(!ensure_null_terminated_((FLAC__byte**)(&src->entry), src->length))
+ return false;
+ *dest = *src;
+ }
+ }
+ else {
+ /* the src is null */
+ *dest = *src;
+ }
+
+ if(0 != save)
+ free(save);
+
+ vorbiscomment_calculate_length_(object);
+ return true;
+}
+
+static int vorbiscomment_find_entry_from_(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name, unsigned field_name_length)
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ FLAC__ASSERT(0 != field_name);
+
+ for(i = offset; i < object->data.vorbis_comment.num_comments; i++) {
+ if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length))
+ return (int)i;
+ }
+
+ return -1;
+}
+
+static void cuesheet_calculate_length_(FLAC__StreamMetadata *object)
+{
+ unsigned i;
+
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+ object->length = (
+ FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+ ) / 8;
+
+ object->length += object->data.cue_sheet.num_tracks * (
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+ ) / 8;
+
+ for(i = 0; i < object->data.cue_sheet.num_tracks; i++) {
+ object->length += object->data.cue_sheet.tracks[i].num_indices * (
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+ ) / 8;
+ }
+}
+
+static FLAC__StreamMetadata_CueSheet_Index *cuesheet_track_index_array_new_(unsigned num_indices)
+{
+ FLAC__ASSERT(num_indices > 0);
+
+ return (FLAC__StreamMetadata_CueSheet_Index*)calloc(num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index));
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_new_(unsigned num_tracks)
+{
+ FLAC__ASSERT(num_tracks > 0);
+
+ return (FLAC__StreamMetadata_CueSheet_Track*)calloc(num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+static void cuesheet_track_array_delete_(FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != object_array && num_tracks > 0);
+
+ for(i = 0; i < num_tracks; i++) {
+ if(0 != object_array[i].indices) {
+ FLAC__ASSERT(object_array[i].num_indices > 0);
+ free(object_array[i].indices);
+ }
+ }
+
+ if(0 != object_array)
+ free(object_array);
+}
+
+static FLAC__StreamMetadata_CueSheet_Track *cuesheet_track_array_copy_(const FLAC__StreamMetadata_CueSheet_Track *object_array, unsigned num_tracks)
+{
+ FLAC__StreamMetadata_CueSheet_Track *return_array;
+
+ FLAC__ASSERT(0 != object_array);
+ FLAC__ASSERT(num_tracks > 0);
+
+ return_array = cuesheet_track_array_new_(num_tracks);
+
+ if(0 != return_array) {
+ unsigned i;
+
+ for(i = 0; i < num_tracks; i++) {
+ if(!copy_track_(return_array+i, object_array+i)) {
+ cuesheet_track_array_delete_(return_array, num_tracks);
+ return 0;
+ }
+ }
+ }
+
+ return return_array;
+}
+
+static FLAC__bool cuesheet_set_track_(FLAC__StreamMetadata *object, FLAC__StreamMetadata_CueSheet_Track *dest, const FLAC__StreamMetadata_CueSheet_Track *src, FLAC__bool copy)
+{
+ FLAC__StreamMetadata_CueSheet_Index *save;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(0 != dest);
+ FLAC__ASSERT(0 != src);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+ FLAC__ASSERT((0 != src->indices && src->num_indices > 0) || (0 == src->indices && src->num_indices == 0));
+
+ save = dest->indices;
+
+ /* do the copy first so that if we fail we leave the object untouched */
+ if(copy) {
+ if(!copy_track_(dest, src))
+ return false;
+ }
+ else {
+ *dest = *src;
+ }
+
+ if(0 != save)
+ free(save);
+
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+
+/****************************************************************************
+ *
+ * Metadata object routines
+ *
+ ***************************************************************************/
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_new(FLAC__MetadataType type)
+{
+ FLAC__StreamMetadata *object;
+
+ if(type > FLAC__MAX_METADATA_TYPE_CODE)
+ return 0;
+
+ object = (FLAC__StreamMetadata*)calloc(1, sizeof(FLAC__StreamMetadata));
+ if(0 != object) {
+ object->is_last = false;
+ object->type = type;
+ switch(type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ object->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+ break;
+ case FLAC__METADATA_TYPE_PADDING:
+ /* calloc() took care of this for us:
+ object->length = 0;
+ */
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+ /* calloc() took care of this for us:
+ object->data.application.data = 0;
+ */
+ break;
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ /* calloc() took care of this for us:
+ object->length = 0;
+ object->data.seek_table.num_points = 0;
+ object->data.seek_table.points = 0;
+ */
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ object->data.vorbis_comment.vendor_string.length = (unsigned)strlen(FLAC__VENDOR_STRING);
+ if(!copy_bytes_(&object->data.vorbis_comment.vendor_string.entry, (const FLAC__byte*)FLAC__VENDOR_STRING, object->data.vorbis_comment.vendor_string.length+1)) {
+ free(object);
+ return 0;
+ }
+ vorbiscomment_calculate_length_(object);
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ cuesheet_calculate_length_(object);
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ object->length = (
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+ FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* empty mime_type string */
+ FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* empty description string */
+ FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN +
+ 0 /* no data */
+ ) / 8;
+ object->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER;
+ object->data.picture.mime_type = 0;
+ object->data.picture.description = 0;
+ /* calloc() took care of this for us:
+ object->data.picture.width = 0;
+ object->data.picture.height = 0;
+ object->data.picture.depth = 0;
+ object->data.picture.colors = 0;
+ object->data.picture.data_length = 0;
+ object->data.picture.data = 0;
+ */
+ /* now initialize mime_type and description with empty strings to make things easier on the client */
+ if(!copy_cstring_(&object->data.picture.mime_type, "")) {
+ free(object);
+ return 0;
+ }
+ if(!copy_cstring_((char**)(&object->data.picture.description), "")) {
+ if(object->data.picture.mime_type)
+ free(object->data.picture.mime_type);
+ free(object);
+ return 0;
+ }
+ break;
+ default:
+ /* calloc() took care of this for us:
+ object->length = 0;
+ object->data.unknown.data = 0;
+ */
+ break;
+ }
+ }
+
+ return object;
+}
+
+FLAC_API FLAC__StreamMetadata *FLAC__metadata_object_clone(const FLAC__StreamMetadata *object)
+{
+ FLAC__StreamMetadata *to;
+
+ FLAC__ASSERT(0 != object);
+
+ if(0 != (to = FLAC__metadata_object_new(object->type))) {
+ to->is_last = object->is_last;
+ to->type = object->type;
+ to->length = object->length;
+ switch(to->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ memcpy(&to->data.stream_info, &object->data.stream_info, sizeof(FLAC__StreamMetadata_StreamInfo));
+ break;
+ case FLAC__METADATA_TYPE_PADDING:
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ memcpy(&to->data.application.id, &object->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8);
+ if(!copy_bytes_(&to->data.application.data, object->data.application.data, object->length - FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ break;
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ to->data.seek_table.num_points = object->data.seek_table.num_points;
+ if(!copy_bytes_((FLAC__byte**)&to->data.seek_table.points, (FLAC__byte*)object->data.seek_table.points, object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint))) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ if(0 != to->data.vorbis_comment.vendor_string.entry) {
+ free(to->data.vorbis_comment.vendor_string.entry);
+ to->data.vorbis_comment.vendor_string.entry = 0;
+ }
+ if(!copy_vcentry_(&to->data.vorbis_comment.vendor_string, &object->data.vorbis_comment.vendor_string)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ if(object->data.vorbis_comment.num_comments == 0) {
+ FLAC__ASSERT(0 == object->data.vorbis_comment.comments);
+ to->data.vorbis_comment.comments = 0;
+ }
+ else {
+ FLAC__ASSERT(0 != object->data.vorbis_comment.comments);
+ to->data.vorbis_comment.comments = vorbiscomment_entry_array_copy_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+ if(0 == to->data.vorbis_comment.comments) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ }
+ to->data.vorbis_comment.num_comments = object->data.vorbis_comment.num_comments;
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ memcpy(&to->data.cue_sheet, &object->data.cue_sheet, sizeof(FLAC__StreamMetadata_CueSheet));
+ if(object->data.cue_sheet.num_tracks == 0) {
+ FLAC__ASSERT(0 == object->data.cue_sheet.tracks);
+ }
+ else {
+ FLAC__ASSERT(0 != object->data.cue_sheet.tracks);
+ to->data.cue_sheet.tracks = cuesheet_track_array_copy_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+ if(0 == to->data.cue_sheet.tracks) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ }
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ to->data.picture.type = object->data.picture.type;
+ if(!copy_cstring_(&to->data.picture.mime_type, object->data.picture.mime_type)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ if(!copy_cstring_((char**)(&to->data.picture.description), (const char*)object->data.picture.description)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ to->data.picture.width = object->data.picture.width;
+ to->data.picture.height = object->data.picture.height;
+ to->data.picture.depth = object->data.picture.depth;
+ to->data.picture.colors = object->data.picture.colors;
+ to->data.picture.data_length = object->data.picture.data_length;
+ if(!copy_bytes_((&to->data.picture.data), object->data.picture.data, object->data.picture.data_length)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ break;
+ default:
+ if(!copy_bytes_(&to->data.unknown.data, object->data.unknown.data, object->length)) {
+ FLAC__metadata_object_delete(to);
+ return 0;
+ }
+ break;
+ }
+ }
+
+ return to;
+}
+
+void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object)
+{
+ FLAC__ASSERT(0 != object);
+
+ switch(object->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ case FLAC__METADATA_TYPE_PADDING:
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ if(0 != object->data.application.data) {
+ free(object->data.application.data);
+ object->data.application.data = 0;
+ }
+ break;
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ if(0 != object->data.seek_table.points) {
+ free(object->data.seek_table.points);
+ object->data.seek_table.points = 0;
+ }
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ if(0 != object->data.vorbis_comment.vendor_string.entry) {
+ free(object->data.vorbis_comment.vendor_string.entry);
+ object->data.vorbis_comment.vendor_string.entry = 0;
+ }
+ if(0 != object->data.vorbis_comment.comments) {
+ FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
+ vorbiscomment_entry_array_delete_(object->data.vorbis_comment.comments, object->data.vorbis_comment.num_comments);
+ }
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ if(0 != object->data.cue_sheet.tracks) {
+ FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
+ cuesheet_track_array_delete_(object->data.cue_sheet.tracks, object->data.cue_sheet.num_tracks);
+ }
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ if(0 != object->data.picture.mime_type) {
+ free(object->data.picture.mime_type);
+ object->data.picture.mime_type = 0;
+ }
+ if(0 != object->data.picture.description) {
+ free(object->data.picture.description);
+ object->data.picture.description = 0;
+ }
+ if(0 != object->data.picture.data) {
+ free(object->data.picture.data);
+ object->data.picture.data = 0;
+ }
+ break;
+ default:
+ if(0 != object->data.unknown.data) {
+ free(object->data.unknown.data);
+ object->data.unknown.data = 0;
+ }
+ break;
+ }
+}
+
+FLAC_API void FLAC__metadata_object_delete(FLAC__StreamMetadata *object)
+{
+ FLAC__metadata_object_delete_data(object);
+ free(object);
+}
+
+static FLAC__bool compare_block_data_streaminfo_(const FLAC__StreamMetadata_StreamInfo *block1, const FLAC__StreamMetadata_StreamInfo *block2)
+{
+ if(block1->min_blocksize != block2->min_blocksize)
+ return false;
+ if(block1->max_blocksize != block2->max_blocksize)
+ return false;
+ if(block1->min_framesize != block2->min_framesize)
+ return false;
+ if(block1->max_framesize != block2->max_framesize)
+ return false;
+ if(block1->sample_rate != block2->sample_rate)
+ return false;
+ if(block1->channels != block2->channels)
+ return false;
+ if(block1->bits_per_sample != block2->bits_per_sample)
+ return false;
+ if(block1->total_samples != block2->total_samples)
+ return false;
+ if(0 != memcmp(block1->md5sum, block2->md5sum, 16))
+ return false;
+ return true;
+}
+
+static FLAC__bool compare_block_data_application_(const FLAC__StreamMetadata_Application *block1, const FLAC__StreamMetadata_Application *block2, unsigned block_length)
+{
+ FLAC__ASSERT(0 != block1);
+ FLAC__ASSERT(0 != block2);
+ FLAC__ASSERT(block_length >= sizeof(block1->id));
+
+ if(0 != memcmp(block1->id, block2->id, sizeof(block1->id)))
+ return false;
+ if(0 != block1->data && 0 != block2->data)
+ return 0 == memcmp(block1->data, block2->data, block_length - sizeof(block1->id));
+ else
+ return block1->data == block2->data;
+}
+
+static FLAC__bool compare_block_data_seektable_(const FLAC__StreamMetadata_SeekTable *block1, const FLAC__StreamMetadata_SeekTable *block2)
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != block1);
+ FLAC__ASSERT(0 != block2);
+
+ if(block1->num_points != block2->num_points)
+ return false;
+
+ if(0 != block1->points && 0 != block2->points) {
+ for(i = 0; i < block1->num_points; i++) {
+ if(block1->points[i].sample_number != block2->points[i].sample_number)
+ return false;
+ if(block1->points[i].stream_offset != block2->points[i].stream_offset)
+ return false;
+ if(block1->points[i].frame_samples != block2->points[i].frame_samples)
+ return false;
+ }
+ return true;
+ }
+ else
+ return block1->points == block2->points;
+}
+
+static FLAC__bool compare_block_data_vorbiscomment_(const FLAC__StreamMetadata_VorbisComment *block1, const FLAC__StreamMetadata_VorbisComment *block2)
+{
+ unsigned i;
+
+ if(block1->vendor_string.length != block2->vendor_string.length)
+ return false;
+
+ if(0 != block1->vendor_string.entry && 0 != block2->vendor_string.entry) {
+ if(0 != memcmp(block1->vendor_string.entry, block2->vendor_string.entry, block1->vendor_string.length))
+ return false;
+ }
+ else if(block1->vendor_string.entry != block2->vendor_string.entry)
+ return false;
+
+ if(block1->num_comments != block2->num_comments)
+ return false;
+
+ for(i = 0; i < block1->num_comments; i++) {
+ if(0 != block1->comments[i].entry && 0 != block2->comments[i].entry) {
+ if(0 != memcmp(block1->comments[i].entry, block2->comments[i].entry, block1->comments[i].length))
+ return false;
+ }
+ else if(block1->comments[i].entry != block2->comments[i].entry)
+ return false;
+ }
+ return true;
+}
+
+static FLAC__bool compare_block_data_cuesheet_(const FLAC__StreamMetadata_CueSheet *block1, const FLAC__StreamMetadata_CueSheet *block2)
+{
+ unsigned i, j;
+
+ if(0 != strcmp(block1->media_catalog_number, block2->media_catalog_number))
+ return false;
+
+ if(block1->lead_in != block2->lead_in)
+ return false;
+
+ if(block1->is_cd != block2->is_cd)
+ return false;
+
+ if(block1->num_tracks != block2->num_tracks)
+ return false;
+
+ if(0 != block1->tracks && 0 != block2->tracks) {
+ FLAC__ASSERT(block1->num_tracks > 0);
+ for(i = 0; i < block1->num_tracks; i++) {
+ if(block1->tracks[i].offset != block2->tracks[i].offset)
+ return false;
+ if(block1->tracks[i].number != block2->tracks[i].number)
+ return false;
+ if(0 != memcmp(block1->tracks[i].isrc, block2->tracks[i].isrc, sizeof(block1->tracks[i].isrc)))
+ return false;
+ if(block1->tracks[i].type != block2->tracks[i].type)
+ return false;
+ if(block1->tracks[i].pre_emphasis != block2->tracks[i].pre_emphasis)
+ return false;
+ if(block1->tracks[i].num_indices != block2->tracks[i].num_indices)
+ return false;
+ if(0 != block1->tracks[i].indices && 0 != block2->tracks[i].indices) {
+ FLAC__ASSERT(block1->tracks[i].num_indices > 0);
+ for(j = 0; j < block1->tracks[i].num_indices; j++) {
+ if(block1->tracks[i].indices[j].offset != block2->tracks[i].indices[j].offset)
+ return false;
+ if(block1->tracks[i].indices[j].number != block2->tracks[i].indices[j].number)
+ return false;
+ }
+ }
+ else if(block1->tracks[i].indices != block2->tracks[i].indices)
+ return false;
+ }
+ }
+ else if(block1->tracks != block2->tracks)
+ return false;
+ return true;
+}
+
+static FLAC__bool compare_block_data_picture_(const FLAC__StreamMetadata_Picture *block1, const FLAC__StreamMetadata_Picture *block2)
+{
+ if(block1->type != block2->type)
+ return false;
+ if(block1->mime_type != block2->mime_type && (0 == block1->mime_type || 0 == block2->mime_type || strcmp(block1->mime_type, block2->mime_type)))
+ return false;
+ if(block1->description != block2->description && (0 == block1->description || 0 == block2->description || strcmp((const char *)block1->description, (const char *)block2->description)))
+ return false;
+ if(block1->width != block2->width)
+ return false;
+ if(block1->height != block2->height)
+ return false;
+ if(block1->depth != block2->depth)
+ return false;
+ if(block1->colors != block2->colors)
+ return false;
+ if(block1->data_length != block2->data_length)
+ return false;
+ if(block1->data != block2->data && (0 == block1->data || 0 == block2->data || memcmp(block1->data, block2->data, block1->data_length)))
+ return false;
+ return true;
+}
+
+static FLAC__bool compare_block_data_unknown_(const FLAC__StreamMetadata_Unknown *block1, const FLAC__StreamMetadata_Unknown *block2, unsigned block_length)
+{
+ FLAC__ASSERT(0 != block1);
+ FLAC__ASSERT(0 != block2);
+
+ if(0 != block1->data && 0 != block2->data)
+ return 0 == memcmp(block1->data, block2->data, block_length);
+ else
+ return block1->data == block2->data;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *block1, const FLAC__StreamMetadata *block2)
+{
+ FLAC__ASSERT(0 != block1);
+ FLAC__ASSERT(0 != block2);
+
+ if(block1->type != block2->type) {
+ return false;
+ }
+ if(block1->is_last != block2->is_last) {
+ return false;
+ }
+ if(block1->length != block2->length) {
+ return false;
+ }
+ switch(block1->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ return compare_block_data_streaminfo_(&block1->data.stream_info, &block2->data.stream_info);
+ case FLAC__METADATA_TYPE_PADDING:
+ return true; /* we don't compare the padding guts */
+ case FLAC__METADATA_TYPE_APPLICATION:
+ return compare_block_data_application_(&block1->data.application, &block2->data.application, block1->length);
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ return compare_block_data_seektable_(&block1->data.seek_table, &block2->data.seek_table);
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ return compare_block_data_vorbiscomment_(&block1->data.vorbis_comment, &block2->data.vorbis_comment);
+ case FLAC__METADATA_TYPE_CUESHEET:
+ return compare_block_data_cuesheet_(&block1->data.cue_sheet, &block2->data.cue_sheet);
+ case FLAC__METADATA_TYPE_PICTURE:
+ return compare_block_data_picture_(&block1->data.picture, &block2->data.picture);
+ default:
+ return compare_block_data_unknown_(&block1->data.unknown, &block2->data.unknown, block1->length);
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy)
+{
+ FLAC__byte *save;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_APPLICATION);
+ FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false));
+
+ save = object->data.application.data;
+
+ /* do the copy first so that if we fail we leave the object untouched */
+ if(copy) {
+ if(!copy_bytes_(&object->data.application.data, data, length))
+ return false;
+ }
+ else {
+ object->data.application.data = data;
+ }
+
+ if(0 != save)
+ free(save);
+
+ object->length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8 + length;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+ if(0 == object->data.seek_table.points) {
+ FLAC__ASSERT(object->data.seek_table.num_points == 0);
+ if(0 == new_num_points)
+ return true;
+ else if(0 == (object->data.seek_table.points = seekpoint_array_new_(new_num_points)))
+ return false;
+ }
+ else {
+ const unsigned old_size = object->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+ const unsigned new_size = new_num_points * sizeof(FLAC__StreamMetadata_SeekPoint);
+
+ FLAC__ASSERT(object->data.seek_table.num_points > 0);
+
+ if(new_size == 0) {
+ free(object->data.seek_table.points);
+ object->data.seek_table.points = 0;
+ }
+ else if(0 == (object->data.seek_table.points = (FLAC__StreamMetadata_SeekPoint*)realloc(object->data.seek_table.points, new_size)))
+ return false;
+
+ /* if growing, set new elements to placeholders */
+ if(new_size > old_size) {
+ unsigned i;
+ for(i = object->data.seek_table.num_points; i < new_num_points; i++) {
+ object->data.seek_table.points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ object->data.seek_table.points[i].stream_offset = 0;
+ object->data.seek_table.points[i].frame_samples = 0;
+ }
+ }
+ }
+
+ object->data.seek_table.num_points = new_num_points;
+
+ seektable_calculate_length_(object);
+ return true;
+}
+
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+ FLAC__ASSERT(point_num < object->data.seek_table.num_points);
+
+ object->data.seek_table.points[point_num] = point;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point)
+{
+ int i;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+ FLAC__ASSERT(point_num <= object->data.seek_table.num_points);
+
+ if(!FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points+1))
+ return false;
+
+ /* move all points >= point_num forward one space */
+ for(i = (int)object->data.seek_table.num_points-1; i > (int)point_num; i--)
+ object->data.seek_table.points[i] = object->data.seek_table.points[i-1];
+
+ FLAC__metadata_object_seektable_set_point(object, point_num, point);
+ seektable_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num)
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+ FLAC__ASSERT(point_num < object->data.seek_table.num_points);
+
+ /* move all points > point_num backward one space */
+ for(i = point_num; i < object->data.seek_table.num_points-1; i++)
+ object->data.seek_table.points[i] = object->data.seek_table.points[i+1];
+
+ return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamMetadata *object)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+ return FLAC__format_seektable_is_legal(&object->data.seek_table);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+ if(num > 0)
+ /* WATCHOUT: we rely on the fact that growing the array adds PLACEHOLDERS at the end */
+ return FLAC__metadata_object_seektable_resize_points(object, object->data.seek_table.num_points + num);
+ else
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__StreamMetadata *object, FLAC__uint64 sample_number)
+{
+ FLAC__StreamMetadata_SeekTable *seek_table;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+ seek_table = &object->data.seek_table;
+
+ if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + 1))
+ return false;
+
+ seek_table->points[seek_table->num_points - 1].sample_number = sample_number;
+ seek_table->points[seek_table->num_points - 1].stream_offset = 0;
+ seek_table->points[seek_table->num_points - 1].frame_samples = 0;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+ FLAC__ASSERT(0 != sample_numbers || num == 0);
+
+ if(num > 0) {
+ FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+ unsigned i, j;
+
+ i = seek_table->num_points;
+
+ if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+ return false;
+
+ for(j = 0; j < num; i++, j++) {
+ seek_table->points[i].sample_number = sample_numbers[j];
+ seek_table->points[i].stream_offset = 0;
+ seek_table->points[i].frame_samples = 0;
+ }
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+ FLAC__ASSERT(total_samples > 0);
+
+ if(num > 0 && total_samples > 0) {
+ FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+ unsigned i, j;
+
+ i = seek_table->num_points;
+
+ if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + num))
+ return false;
+
+ for(j = 0; j < num; i++, j++) {
+ seek_table->points[i].sample_number = total_samples * (FLAC__uint64)j / (FLAC__uint64)num;
+ seek_table->points[i].stream_offset = 0;
+ seek_table->points[i].frame_samples = 0;
+ }
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+ FLAC__ASSERT(samples > 0);
+ FLAC__ASSERT(total_samples > 0);
+
+ if(samples > 0 && total_samples > 0) {
+ FLAC__StreamMetadata_SeekTable *seek_table = &object->data.seek_table;
+ unsigned i, j;
+ FLAC__uint64 num, sample;
+
+ num = 1 + total_samples / samples; /* 1+ for the first sample at 0 */
+ /* now account for the fact that we don't place a seekpoint at "total_samples" since samples are number from 0: */
+ if(total_samples % samples == 0)
+ num--;
+
+ i = seek_table->num_points;
+
+ if(!FLAC__metadata_object_seektable_resize_points(object, seek_table->num_points + (unsigned)num))
+ return false;
+
+ sample = 0;
+ for(j = 0; j < num; i++, j++, sample += samples) {
+ seek_table->points[i].sample_number = sample;
+ seek_table->points[i].stream_offset = 0;
+ seek_table->points[i].frame_samples = 0;
+ }
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_sort(FLAC__StreamMetadata *object, FLAC__bool compact)
+{
+ unsigned unique;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_SEEKTABLE);
+
+ unique = FLAC__format_seektable_sort(&object->data.seek_table);
+
+ return !compact || FLAC__metadata_object_seektable_resize_points(object, unique);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ if(!FLAC__format_vorbiscomment_entry_value_is_legal(entry.entry, entry.length))
+ return false;
+ return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.vendor_string, &entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ if(0 == object->data.vorbis_comment.comments) {
+ FLAC__ASSERT(object->data.vorbis_comment.num_comments == 0);
+ if(0 == new_num_comments)
+ return true;
+ else if(0 == (object->data.vorbis_comment.comments = vorbiscomment_entry_array_new_(new_num_comments)))
+ return false;
+ }
+ else {
+ const unsigned old_size = object->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+ const unsigned new_size = new_num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry);
+
+ FLAC__ASSERT(object->data.vorbis_comment.num_comments > 0);
+
+ /* if shrinking, free the truncated entries */
+ if(new_num_comments < object->data.vorbis_comment.num_comments) {
+ unsigned i;
+ for(i = new_num_comments; i < object->data.vorbis_comment.num_comments; i++)
+ if(0 != object->data.vorbis_comment.comments[i].entry)
+ free(object->data.vorbis_comment.comments[i].entry);
+ }
+
+ if(new_size == 0) {
+ free(object->data.vorbis_comment.comments);
+ object->data.vorbis_comment.comments = 0;
+ }
+ else if(0 == (object->data.vorbis_comment.comments = (FLAC__StreamMetadata_VorbisComment_Entry*)realloc(object->data.vorbis_comment.comments, new_size)))
+ return false;
+
+ /* if growing, zero all the length/pointers of new elements */
+ if(new_size > old_size)
+ memset(object->data.vorbis_comment.comments + object->data.vorbis_comment.num_comments, 0, new_size - old_size);
+ }
+
+ object->data.vorbis_comment.num_comments = new_num_comments;
+
+ vorbiscomment_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
+
+ if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+ return false;
+ return vorbiscomment_set_entry_(object, &object->data.vorbis_comment.comments[comment_num], &entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ FLAC__StreamMetadata_VorbisComment *vc;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ FLAC__ASSERT(comment_num <= object->data.vorbis_comment.num_comments);
+
+ if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+ return false;
+
+ vc = &object->data.vorbis_comment;
+
+ if(!FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments+1))
+ return false;
+
+ /* move all comments >= comment_num forward one space */
+ memmove(&vc->comments[comment_num+1], &vc->comments[comment_num], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-1-comment_num));
+ vc->comments[comment_num].length = 0;
+ vc->comments[comment_num].entry = 0;
+
+ return FLAC__metadata_object_vorbiscomment_set_comment(object, comment_num, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ return FLAC__metadata_object_vorbiscomment_insert_comment(object, object->data.vorbis_comment.num_comments, entry, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__StreamMetadata *object, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool all, FLAC__bool copy)
+{
+ FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+
+ if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+ return false;
+
+ {
+ int i;
+ size_t field_name_length;
+ const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+
+ FLAC__ASSERT(0 != eq);
+
+ if(0 == eq)
+ return false; /* double protection */
+
+ field_name_length = eq-entry.entry;
+
+ if((i = vorbiscomment_find_entry_from_(object, 0, (const char *)entry.entry, field_name_length)) >= 0) {
+ unsigned indx = (unsigned)i;
+ if(!FLAC__metadata_object_vorbiscomment_set_comment(object, indx, entry, copy))
+ return false;
+ if(all && (indx+1 < object->data.vorbis_comment.num_comments)) {
+ for(i = vorbiscomment_find_entry_from_(object, indx+1, (const char *)entry.entry, field_name_length); i >= 0; ) {
+ if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i))
+ return false;
+ if((unsigned)i < object->data.vorbis_comment.num_comments)
+ i = vorbiscomment_find_entry_from_(object, (unsigned)i, (const char *)entry.entry, field_name_length);
+ else
+ i = -1;
+ }
+ }
+ return true;
+ }
+ else
+ return FLAC__metadata_object_vorbiscomment_append_comment(object, entry, copy);
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num)
+{
+ FLAC__StreamMetadata_VorbisComment *vc;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ FLAC__ASSERT(comment_num < object->data.vorbis_comment.num_comments);
+
+ vc = &object->data.vorbis_comment;
+
+ /* free the comment at comment_num */
+ if(0 != vc->comments[comment_num].entry)
+ free(vc->comments[comment_num].entry);
+
+ /* move all comments > comment_num backward one space */
+ memmove(&vc->comments[comment_num], &vc->comments[comment_num+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(vc->num_comments-comment_num-1));
+ vc->comments[vc->num_comments-1].length = 0;
+ vc->comments[vc->num_comments-1].entry = 0;
+
+ return FLAC__metadata_object_vorbiscomment_resize_comments(object, vc->num_comments-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field_name, const char *field_value)
+{
+ FLAC__ASSERT(0 != entry);
+ FLAC__ASSERT(0 != field_name);
+ FLAC__ASSERT(0 != field_value);
+
+ if(!FLAC__format_vorbiscomment_entry_name_is_legal(field_name))
+ return false;
+ if(!FLAC__format_vorbiscomment_entry_value_is_legal((const FLAC__byte *)field_value, (unsigned)(-1)))
+ return false;
+
+ {
+ const size_t nn = strlen(field_name);
+ const size_t nv = strlen(field_value);
+ entry->length = nn + 1 /*=*/ + nv;
+ if(0 == (entry->entry = (FLAC__byte*)malloc(entry->length+1)))
+ return false;
+ memcpy(entry->entry, field_name, nn);
+ entry->entry[nn] = '=';
+ memcpy(entry->entry+nn+1, field_value, nv);
+ entry->entry[entry->length] = '\0';
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(const FLAC__StreamMetadata_VorbisComment_Entry entry, char **field_name, char **field_value)
+{
+ FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+ FLAC__ASSERT(0 != field_name);
+ FLAC__ASSERT(0 != field_value);
+
+ if(!FLAC__format_vorbiscomment_entry_is_legal(entry.entry, entry.length))
+ return false;
+
+ {
+ const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+ const size_t nn = eq-entry.entry;
+ const size_t nv = entry.length-nn-1; /* -1 for the '=' */
+ FLAC__ASSERT(0 != eq);
+ if(0 == eq)
+ return false; /* double protection */
+ if(0 == (*field_name = (char*)malloc(nn+1)))
+ return false;
+ if(0 == (*field_value = (char*)malloc(nv+1))) {
+ free(*field_name);
+ return false;
+ }
+ memcpy(*field_name, entry.entry, nn);
+ memcpy(*field_value, entry.entry+nn+1, nv);
+ (*field_name)[nn] = '\0';
+ (*field_value)[nv] = '\0';
+ }
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length)
+{
+ FLAC__ASSERT(0 != entry.entry && entry.length > 0);
+ {
+ const FLAC__byte *eq = (FLAC__byte*)memchr(entry.entry, '=', entry.length);
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ || defined __EMX__
+#define FLAC__STRNCASECMP strnicmp
+#else
+#define FLAC__STRNCASECMP strncasecmp
+#endif
+ return (0 != eq && (unsigned)(eq-entry.entry) == field_name_length && 0 == FLAC__STRNCASECMP(field_name, (const char *)entry.entry, field_name_length));
+#undef FLAC__STRNCASECMP
+ }
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name)
+{
+ FLAC__ASSERT(0 != field_name);
+
+ return vorbiscomment_find_entry_from_(object, offset, field_name, strlen(field_name));
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entry_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+ const unsigned field_name_length = strlen(field_name);
+ unsigned i;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ for(i = 0; i < object->data.vorbis_comment.num_comments; i++) {
+ if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
+ if(!FLAC__metadata_object_vorbiscomment_delete_comment(object, i))
+ return -1;
+ else
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+FLAC_API int FLAC__metadata_object_vorbiscomment_remove_entries_matching(FLAC__StreamMetadata *object, const char *field_name)
+{
+ FLAC__bool ok = true;
+ unsigned matching = 0;
+ const unsigned field_name_length = strlen(field_name);
+ int i;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ /* must delete from end to start otherwise it will interfere with our iteration */
+ for(i = (int)object->data.vorbis_comment.num_comments - 1; ok && i >= 0; i--) {
+ if(FLAC__metadata_object_vorbiscomment_entry_matches(object->data.vorbis_comment.comments[i], field_name, field_name_length)) {
+ matching++;
+ ok &= FLAC__metadata_object_vorbiscomment_delete_comment(object, (unsigned)i);
+ }
+ }
+
+ return ok? (int)matching : -1;
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_new(void)
+{
+ return (FLAC__StreamMetadata_CueSheet_Track*)calloc(1, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+}
+
+FLAC_API FLAC__StreamMetadata_CueSheet_Track *FLAC__metadata_object_cuesheet_track_clone(const FLAC__StreamMetadata_CueSheet_Track *object)
+{
+ FLAC__StreamMetadata_CueSheet_Track *to;
+
+ FLAC__ASSERT(0 != object);
+
+ if(0 != (to = FLAC__metadata_object_cuesheet_track_new())) {
+ if(!copy_track_(to, object)) {
+ FLAC__metadata_object_cuesheet_track_delete(to);
+ return 0;
+ }
+ }
+
+ return to;
+}
+
+void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+ FLAC__ASSERT(0 != object);
+
+ if(0 != object->indices) {
+ FLAC__ASSERT(object->num_indices > 0);
+ free(object->indices);
+ }
+}
+
+FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_CueSheet_Track *object)
+{
+ FLAC__metadata_object_cuesheet_track_delete_data(object);
+ free(object);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices)
+{
+ FLAC__StreamMetadata_CueSheet_Track *track;
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+ FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+ track = &object->data.cue_sheet.tracks[track_num];
+
+ if(0 == track->indices) {
+ FLAC__ASSERT(track->num_indices == 0);
+ if(0 == new_num_indices)
+ return true;
+ else if(0 == (track->indices = cuesheet_track_index_array_new_(new_num_indices)))
+ return false;
+ }
+ else {
+ const unsigned old_size = track->num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+ const unsigned new_size = new_num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index);
+
+ FLAC__ASSERT(track->num_indices > 0);
+
+ if(new_size == 0) {
+ free(track->indices);
+ track->indices = 0;
+ }
+ else if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)realloc(track->indices, new_size)))
+ return false;
+
+ /* if growing, zero all the lengths/pointers of new elements */
+ if(new_size > old_size)
+ memset(track->indices + track->num_indices, 0, new_size - old_size);
+ }
+
+ track->num_indices = new_num_indices;
+
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+ FLAC__StreamMetadata_CueSheet_Track *track;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+ FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+ FLAC__ASSERT(index_num <= object->data.cue_sheet.tracks[track_num].num_indices);
+
+ track = &object->data.cue_sheet.tracks[track_num];
+
+ if(!FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices+1))
+ return false;
+
+ /* move all indices >= index_num forward one space */
+ memmove(&track->indices[index_num+1], &track->indices[index_num], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-1-index_num));
+
+ track->indices[index_num] = indx;
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
+{
+ FLAC__StreamMetadata_CueSheet_Index indx;
+ memset(&indx, 0, sizeof(indx));
+ return FLAC__metadata_object_cuesheet_track_insert_index(object, track_num, index_num, indx);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num)
+{
+ FLAC__StreamMetadata_CueSheet_Track *track;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+ FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+ FLAC__ASSERT(index_num < object->data.cue_sheet.tracks[track_num].num_indices);
+
+ track = &object->data.cue_sheet.tracks[track_num];
+
+ /* move all indices > index_num backward one space */
+ memmove(&track->indices[index_num], &track->indices[index_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(track->num_indices-index_num-1));
+
+ FLAC__metadata_object_cuesheet_track_resize_indices(object, track_num, track->num_indices-1);
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+ if(0 == object->data.cue_sheet.tracks) {
+ FLAC__ASSERT(object->data.cue_sheet.num_tracks == 0);
+ if(0 == new_num_tracks)
+ return true;
+ else if(0 == (object->data.cue_sheet.tracks = cuesheet_track_array_new_(new_num_tracks)))
+ return false;
+ }
+ else {
+ const unsigned old_size = object->data.cue_sheet.num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+ const unsigned new_size = new_num_tracks * sizeof(FLAC__StreamMetadata_CueSheet_Track);
+
+ FLAC__ASSERT(object->data.cue_sheet.num_tracks > 0);
+
+ /* if shrinking, free the truncated entries */
+ if(new_num_tracks < object->data.cue_sheet.num_tracks) {
+ unsigned i;
+ for(i = new_num_tracks; i < object->data.cue_sheet.num_tracks; i++)
+ if(0 != object->data.cue_sheet.tracks[i].indices)
+ free(object->data.cue_sheet.tracks[i].indices);
+ }
+
+ if(new_size == 0) {
+ free(object->data.cue_sheet.tracks);
+ object->data.cue_sheet.tracks = 0;
+ }
+ else if(0 == (object->data.cue_sheet.tracks = (FLAC__StreamMetadata_CueSheet_Track*)realloc(object->data.cue_sheet.tracks, new_size)))
+ return false;
+
+ /* if growing, zero all the lengths/pointers of new elements */
+ if(new_size > old_size)
+ memset(object->data.cue_sheet.tracks + object->data.cue_sheet.num_tracks, 0, new_size - old_size);
+ }
+
+ object->data.cue_sheet.num_tracks = new_num_tracks;
+
+ cuesheet_calculate_length_(object);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+ return cuesheet_set_track_(object, object->data.cue_sheet.tracks + track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy)
+{
+ FLAC__StreamMetadata_CueSheet *cs;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+ FLAC__ASSERT(track_num <= object->data.cue_sheet.num_tracks);
+
+ cs = &object->data.cue_sheet;
+
+ if(!FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks+1))
+ return false;
+
+ /* move all tracks >= track_num forward one space */
+ memmove(&cs->tracks[track_num+1], &cs->tracks[track_num], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-1-track_num));
+ cs->tracks[track_num].num_indices = 0;
+ cs->tracks[track_num].indices = 0;
+
+ return FLAC__metadata_object_cuesheet_set_track(object, track_num, track, copy);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num)
+{
+ FLAC__StreamMetadata_CueSheet_Track track;
+ memset(&track, 0, sizeof(track));
+ return FLAC__metadata_object_cuesheet_insert_track(object, track_num, &track, /*copy=*/false);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num)
+{
+ FLAC__StreamMetadata_CueSheet *cs;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+ FLAC__ASSERT(track_num < object->data.cue_sheet.num_tracks);
+
+ cs = &object->data.cue_sheet;
+
+ /* free the track at track_num */
+ if(0 != cs->tracks[track_num].indices)
+ free(cs->tracks[track_num].indices);
+
+ /* move all tracks > track_num backward one space */
+ memmove(&cs->tracks[track_num], &cs->tracks[track_num+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(cs->num_tracks-track_num-1));
+ cs->tracks[cs->num_tracks-1].num_indices = 0;
+ cs->tracks[cs->num_tracks-1].indices = 0;
+
+ return FLAC__metadata_object_cuesheet_resize_tracks(object, cs->num_tracks-1);
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_is_legal(const FLAC__StreamMetadata *object, FLAC__bool check_cd_da_subset, const char **violation)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+ return FLAC__format_cuesheet_is_legal(&object->data.cue_sheet, check_cd_da_subset, violation);
+}
+
+static FLAC__uint64 get_index_01_offset_(const FLAC__StreamMetadata_CueSheet *cs, unsigned track)
+{
+ if (track >= (cs->num_tracks-1) || cs->tracks[track].num_indices < 1)
+ return 0;
+ else if (cs->tracks[track].indices[0].number == 1)
+ return cs->tracks[track].indices[0].offset + cs->tracks[track].offset + cs->lead_in;
+ else if (cs->tracks[track].num_indices < 2)
+ return 0;
+ else if (cs->tracks[track].indices[1].number == 1)
+ return cs->tracks[track].indices[1].offset + cs->tracks[track].offset + cs->lead_in;
+ else
+ return 0;
+}
+
+static FLAC__uint32 cddb_add_digits_(FLAC__uint32 x)
+{
+ FLAC__uint32 n = 0;
+ while (x) {
+ n += (x%10);
+ x /= 10;
+ }
+ return n;
+}
+
+FLAC_API FLAC__uint32 FLAC__metadata_object_cuesheet_calculate_cddb_id(const FLAC__StreamMetadata *object)
+{
+ const FLAC__StreamMetadata_CueSheet *cs;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_CUESHEET);
+
+ cs = &object->data.cue_sheet;
+
+ if (cs->num_tracks < 2) /* need at least one real track and the lead-out track */
+ return 0;
+
+ {
+ FLAC__uint32 i, length, sum = 0;
+ for (i = 0; i < (cs->num_tracks-1); i++) /* -1 to avoid counting the lead-out */
+ sum += cddb_add_digits_((FLAC__uint32)(get_index_01_offset_(cs, i) / 44100));
+ length = (FLAC__uint32)((cs->tracks[cs->num_tracks-1].offset+cs->lead_in) / 44100) - (FLAC__uint32)(get_index_01_offset_(cs, 0) / 44100);
+
+ return (sum % 0xFF) << 24 | length << 8 | (FLAC__uint32)(cs->num_tracks-1);
+ }
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_mime_type(FLAC__StreamMetadata *object, const char *mime_type, FLAC__bool copy)
+{
+ char *old;
+ size_t old_length, new_length;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+ FLAC__ASSERT(0 != mime_type);
+
+ old = object->data.picture.mime_type;
+ old_length = old? strlen(old) : 0;
+ new_length = strlen(mime_type);
+
+ /* do the copy first so that if we fail we leave the object untouched */
+ if(copy) {
+ if(!copy_bytes_((FLAC__byte**)(&object->data.picture.mime_type), (FLAC__byte*)mime_type, new_length+1))
+ return false;
+ }
+ else {
+ object->data.picture.mime_type = mime_type;
+ }
+
+ if(0 != old)
+ free(old);
+
+ object->length -= old_length;
+ object->length += new_length;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_description(FLAC__StreamMetadata *object, const FLAC__byte *description, FLAC__bool copy)
+{
+ FLAC__byte *old;
+ size_t old_length, new_length;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+ FLAC__ASSERT(0 != description);
+
+ old = object->data.picture.description;
+ old_length = old? strlen((const char *)old) : 0;
+ new_length = strlen((const char *)description);
+
+ /* do the copy first so that if we fail we leave the object untouched */
+ if(copy) {
+ if(!copy_bytes_(&object->data.picture.description, description, new_length+1))
+ return false;
+ }
+ else {
+ object->data.picture.description = description;
+ }
+
+ if(0 != old)
+ free(old);
+
+ object->length -= old_length;
+ object->length += new_length;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata *object, const FLAC__byte *data, FLAC__uint32 length, FLAC__bool copy)
+{
+ FLAC__byte *old;
+
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+ FLAC__ASSERT((0 != data && length > 0) || (0 == data && length == 0 && copy == false));
+
+ old = object->data.picture.data;
+
+ /* do the copy first so that if we fail we leave the object untouched */
+ if(copy) {
+ if(!copy_bytes_(&object->data.picture.data, data, length))
+ return false;
+ }
+ else {
+ object->data.picture.data = data;
+ }
+
+ if(0 != old)
+ free(old);
+
+ object->length -= object->data.picture.data_length;
+ object->data.picture.data_length = length;
+ object->length += length;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation)
+{
+ FLAC__ASSERT(0 != object);
+ FLAC__ASSERT(object->type == FLAC__METADATA_TYPE_PICTURE);
+
+ return FLAC__format_picture_is_legal(&object->data.picture, violation);
+}
diff --git a/src/FLAC/src/libFLAC/ogg_decoder_aspect.c b/src/FLAC/src/libFLAC/ogg_decoder_aspect.c
new file mode 100644
index 0000000..6974de3
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ogg_decoder_aspect.c
@@ -0,0 +1,253 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h> /* for memcpy() */
+#include "FLAC/assert.h"
+#include "private/ogg_decoder_aspect.h"
+#include "private/ogg_mapping.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__ogg_decoder_aspect_init(FLAC__OggDecoderAspect *aspect)
+{
+ /* we will determine the serial number later if necessary */
+ if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
+ return false;
+
+ if(ogg_sync_init(&aspect->sync_state) != 0)
+ return false;
+
+ aspect->version_major = ~(0u);
+ aspect->version_minor = ~(0u);
+
+ aspect->need_serial_number = aspect->use_first_serial_number;
+
+ aspect->end_of_stream = false;
+ aspect->have_working_page = false;
+
+ return true;
+}
+
+void FLAC__ogg_decoder_aspect_finish(FLAC__OggDecoderAspect *aspect)
+{
+ (void)ogg_sync_clear(&aspect->sync_state);
+ (void)ogg_stream_clear(&aspect->stream_state);
+}
+
+void FLAC__ogg_decoder_aspect_set_serial_number(FLAC__OggDecoderAspect *aspect, long value)
+{
+ aspect->use_first_serial_number = false;
+ aspect->serial_number = value;
+}
+
+void FLAC__ogg_decoder_aspect_set_defaults(FLAC__OggDecoderAspect *aspect)
+{
+ aspect->use_first_serial_number = true;
+}
+
+void FLAC__ogg_decoder_aspect_flush(FLAC__OggDecoderAspect *aspect)
+{
+ (void)ogg_stream_reset(&aspect->stream_state);
+ (void)ogg_sync_reset(&aspect->sync_state);
+ aspect->end_of_stream = false;
+ aspect->have_working_page = false;
+}
+
+void FLAC__ogg_decoder_aspect_reset(FLAC__OggDecoderAspect *aspect)
+{
+ FLAC__ogg_decoder_aspect_flush(aspect);
+
+ if(aspect->use_first_serial_number)
+ aspect->need_serial_number = true;
+}
+
+FLAC__OggDecoderAspectReadStatus FLAC__ogg_decoder_aspect_read_callback_wrapper(FLAC__OggDecoderAspect *aspect, FLAC__byte buffer[], size_t *bytes, FLAC__OggDecoderAspectReadCallbackProxy read_callback, const FLAC__StreamDecoder *decoder, void *client_data)
+{
+ static const size_t OGG_BYTES_CHUNK = 8192;
+ const size_t bytes_requested = *bytes;
+
+ /*
+ * The FLAC decoding API uses pull-based reads, whereas Ogg decoding
+ * is push-based. In libFLAC, when you ask to decode a frame, the
+ * decoder will eventually call the read callback to supply some data,
+ * but how much it asks for depends on how much free space it has in
+ * its internal buffer. It does not try to grow its internal buffer
+ * to accomodate a whole frame because then the internal buffer size
+ * could not be limited, which is necessary in embedded applications.
+ *
+ * Ogg however grows its internal buffer until a whole page is present;
+ * only then can you get decoded data out. So we can't just ask for
+ * the same number of bytes from Ogg, then pass what's decoded down to
+ * libFLAC. If what libFLAC is asking for will not contain a whole
+ * page, then we will get no data from ogg_sync_pageout(), and at the
+ * same time cannot just read more data from the client for the purpose
+ * of getting a whole decoded page because the decoded size might be
+ * larger than libFLAC's internal buffer.
+ *
+ * Instead, whenever this read callback wrapper is called, we will
+ * continually request data from the client until we have at least one
+ * page, and manage pages internally so that we can send pieces of
+ * pages down to libFLAC in such a way that we obey its size
+ * requirement. To limit the amount of callbacks, we will always try
+ * to read in enough pages to return the full number of bytes
+ * requested.
+ */
+ *bytes = 0;
+ while (*bytes < bytes_requested && !aspect->end_of_stream) {
+ if (aspect->have_working_page) {
+ if (aspect->have_working_packet) {
+ size_t n = bytes_requested - *bytes;
+ if ((size_t)aspect->working_packet.bytes <= n) {
+ /* the rest of the packet will fit in the buffer */
+ n = aspect->working_packet.bytes;
+ memcpy(buffer, aspect->working_packet.packet, n);
+ *bytes += n;
+ buffer += n;
+ aspect->have_working_packet = false;
+ }
+ else {
+ /* only n bytes of the packet will fit in the buffer */
+ memcpy(buffer, aspect->working_packet.packet, n);
+ *bytes += n;
+ buffer += n;
+ aspect->working_packet.packet += n;
+ aspect->working_packet.bytes -= n;
+ }
+ }
+ else {
+ /* try and get another packet */
+ const int ret = ogg_stream_packetout(&aspect->stream_state, &aspect->working_packet);
+ if (ret > 0) {
+ aspect->have_working_packet = true;
+ /* if it is the first header packet, check for magic and a supported Ogg FLAC mapping version */
+ if (aspect->working_packet.bytes > 0 && aspect->working_packet.packet[0] == FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE) {
+ const FLAC__byte *b = aspect->working_packet.packet;
+ const unsigned header_length =
+ FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
+ FLAC__OGG_MAPPING_MAGIC_LENGTH +
+ FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
+ FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
+ FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH;
+ if (aspect->working_packet.bytes < (long)header_length)
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
+ b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH;
+ if (memcmp(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH))
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC;
+ b += FLAC__OGG_MAPPING_MAGIC_LENGTH;
+ aspect->version_major = (unsigned)(*b);
+ b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
+ aspect->version_minor = (unsigned)(*b);
+ if (aspect->version_major != 1)
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION;
+ aspect->working_packet.packet += header_length;
+ aspect->working_packet.bytes -= header_length;
+ }
+ }
+ else if (ret == 0) {
+ aspect->have_working_page = false;
+ }
+ else { /* ret < 0 */
+ /* lost sync, we'll leave the working page for the next call */
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
+ }
+ }
+ }
+ else {
+ /* try and get another page */
+ const int ret = ogg_sync_pageout(&aspect->sync_state, &aspect->working_page);
+ if (ret > 0) {
+ /* got a page, grab the serial number if necessary */
+ if(aspect->need_serial_number) {
+ aspect->stream_state.serialno = aspect->serial_number = ogg_page_serialno(&aspect->working_page);
+ aspect->need_serial_number = false;
+ }
+ if(ogg_stream_pagein(&aspect->stream_state, &aspect->working_page) == 0) {
+ aspect->have_working_page = true;
+ aspect->have_working_packet = false;
+ }
+ /* else do nothing, could be a page from another stream */
+ }
+ else if (ret == 0) {
+ /* need more data */
+ const size_t ogg_bytes_to_read = max(bytes_requested - *bytes, OGG_BYTES_CHUNK);
+ char *oggbuf = ogg_sync_buffer(&aspect->sync_state, ogg_bytes_to_read);
+
+ if(0 == oggbuf) {
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR;
+ }
+ else {
+ size_t ogg_bytes_read = ogg_bytes_to_read;
+
+ switch(read_callback(decoder, (FLAC__byte*)oggbuf, &ogg_bytes_read, client_data)) {
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
+ break;
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
+ aspect->end_of_stream = true;
+ break;
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
+ default:
+ FLAC__ASSERT(0);
+ }
+
+ if(ogg_sync_wrote(&aspect->sync_state, ogg_bytes_read) < 0) {
+ /* double protection; this will happen if the read callback returns more bytes than the max requested, which would overflow Ogg's internal buffer */
+ FLAC__ASSERT(0);
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR;
+ }
+ }
+ }
+ else { /* ret < 0 */
+ /* lost sync, bail out */
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC;
+ }
+ }
+ }
+
+ if (aspect->end_of_stream && *bytes == 0) {
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
+ }
+
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
+}
diff --git a/src/FLAC/src/libFLAC/ogg_encoder_aspect.c b/src/FLAC/src/libFLAC/ogg_encoder_aspect.c
new file mode 100644
index 0000000..37df089
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ogg_encoder_aspect.c
@@ -0,0 +1,227 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h> /* for memset() */
+#include "FLAC/assert.h"
+#include "private/ogg_encoder_aspect.h"
+#include "private/ogg_mapping.h"
+
+static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MAJOR = 1;
+static const FLAC__byte FLAC__OGG_MAPPING_VERSION_MINOR = 0;
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+FLAC__bool FLAC__ogg_encoder_aspect_init(FLAC__OggEncoderAspect *aspect)
+{
+ /* we will determine the serial number later if necessary */
+ if(ogg_stream_init(&aspect->stream_state, aspect->serial_number) != 0)
+ return false;
+
+ aspect->seen_magic = false;
+ aspect->is_first_packet = true;
+ aspect->samples_written = 0;
+
+ return true;
+}
+
+void FLAC__ogg_encoder_aspect_finish(FLAC__OggEncoderAspect *aspect)
+{
+ (void)ogg_stream_clear(&aspect->stream_state);
+ /*@@@ what about the page? */
+}
+
+void FLAC__ogg_encoder_aspect_set_serial_number(FLAC__OggEncoderAspect *aspect, long value)
+{
+ aspect->serial_number = value;
+}
+
+FLAC__bool FLAC__ogg_encoder_aspect_set_num_metadata(FLAC__OggEncoderAspect *aspect, unsigned value)
+{
+ if(value < (1u << FLAC__OGG_MAPPING_NUM_HEADERS_LEN)) {
+ aspect->num_metadata = value;
+ return true;
+ }
+ else
+ return false;
+}
+
+void FLAC__ogg_encoder_aspect_set_defaults(FLAC__OggEncoderAspect *aspect)
+{
+ aspect->serial_number = 0;
+ aspect->num_metadata = 0;
+}
+
+/*
+ * The basic FLAC -> Ogg mapping goes like this:
+ *
+ * - 'fLaC' magic and STREAMINFO block get combined into the first
+ * packet. The packet is prefixed with
+ * + the one-byte packet type 0x7F
+ * + 'FLAC' magic
+ * + the 2 byte Ogg FLAC mapping version number
+ * + tne 2 byte big-endian # of header packets
+ * - The first packet is flushed to the first page.
+ * - Each subsequent metadata block goes into its own packet.
+ * - Each metadata packet is flushed to page (this is not required,
+ * the mapping only requires that a flush must occur after all
+ * metadata is written).
+ * - Each subsequent FLAC audio frame goes into its own packet.
+ *
+ * WATCHOUT:
+ * This depends on the behavior of FLAC__StreamEncoder that we get a
+ * separate write callback for the fLaC magic, and then separate write
+ * callbacks for each metadata block and audio frame.
+ */
+FLAC__StreamEncoderWriteStatus FLAC__ogg_encoder_aspect_write_callback_wrapper(FLAC__OggEncoderAspect *aspect, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, FLAC__bool is_last_block, FLAC__OggEncoderAspectWriteCallbackProxy write_callback, void *encoder, void *client_data)
+{
+ /* WATCHOUT:
+ * This depends on the behavior of FLAC__StreamEncoder that 'samples'
+ * will be 0 for metadata writes.
+ */
+ const FLAC__bool is_metadata = (samples == 0);
+
+ /*
+ * Treat fLaC magic packet specially. We will note when we see it, then
+ * wait until we get the STREAMINFO and prepend it in that packet
+ */
+ if(aspect->seen_magic) {
+ ogg_packet packet;
+ FLAC__byte synthetic_first_packet_body[
+ FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
+ FLAC__OGG_MAPPING_MAGIC_LENGTH +
+ FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
+ FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
+ FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH +
+ FLAC__STREAM_SYNC_LENGTH +
+ FLAC__STREAM_METADATA_HEADER_LENGTH +
+ FLAC__STREAM_METADATA_STREAMINFO_LENGTH
+ ];
+
+ memset(&packet, 0, sizeof(packet));
+ packet.granulepos = aspect->samples_written + samples;
+
+ if(aspect->is_first_packet) {
+ FLAC__byte *b = synthetic_first_packet_body;
+ if(bytes != FLAC__STREAM_METADATA_HEADER_LENGTH + FLAC__STREAM_METADATA_STREAMINFO_LENGTH) {
+ /*
+ * If we get here, our assumption about the way write callbacks happen
+ * (explained above) is wrong
+ */
+ FLAC__ASSERT(0);
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+ }
+ /* add first header packet type */
+ *b = FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE;
+ b += FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH;
+ /* add 'FLAC' mapping magic */
+ memcpy(b, FLAC__OGG_MAPPING_MAGIC, FLAC__OGG_MAPPING_MAGIC_LENGTH);
+ b += FLAC__OGG_MAPPING_MAGIC_LENGTH;
+ /* add Ogg FLAC mapping major version number */
+ memcpy(b, &FLAC__OGG_MAPPING_VERSION_MAJOR, FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH);
+ b += FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH;
+ /* add Ogg FLAC mapping minor version number */
+ memcpy(b, &FLAC__OGG_MAPPING_VERSION_MINOR, FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH);
+ b += FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH;
+ /* add number of header packets */
+ *b = (FLAC__byte)(aspect->num_metadata >> 8);
+ b++;
+ *b = (FLAC__byte)(aspect->num_metadata);
+ b++;
+ /* add native FLAC 'fLaC' magic */
+ memcpy(b, FLAC__STREAM_SYNC_STRING, FLAC__STREAM_SYNC_LENGTH);
+ b += FLAC__STREAM_SYNC_LENGTH;
+ /* add STREAMINFO */
+ memcpy(b, buffer, bytes);
+ FLAC__ASSERT(b + bytes - synthetic_first_packet_body == sizeof(synthetic_first_packet_body));
+ packet.packet = (unsigned char *)synthetic_first_packet_body;
+ packet.bytes = sizeof(synthetic_first_packet_body);
+
+ packet.b_o_s = 1;
+ aspect->is_first_packet = false;
+ }
+ else {
+ packet.packet = (unsigned char *)buffer;
+ packet.bytes = bytes;
+ }
+
+ if(is_last_block) {
+ /* we used to check:
+ * FLAC__ASSERT(total_samples_estimate == 0 || total_samples_estimate == aspect->samples_written + samples);
+ * but it's really not useful since total_samples_estimate is an estimate and can be inexact
+ */
+ packet.e_o_s = 1;
+ }
+
+ if(ogg_stream_packetin(&aspect->stream_state, &packet) != 0)
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+
+ /*@@@ can't figure out a way to pass a useful number for 'samples' to the write_callback, so we'll just pass 0 */
+ if(is_metadata) {
+ while(ogg_stream_flush(&aspect->stream_state, &aspect->page) != 0) {
+ if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+ if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+ }
+ }
+ else {
+ while(ogg_stream_pageout(&aspect->stream_state, &aspect->page) != 0) {
+ if(write_callback(encoder, aspect->page.header, aspect->page.header_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+ if(write_callback(encoder, aspect->page.body, aspect->page.body_len, 0, current_frame, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK)
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+ }
+ }
+ }
+ else if(is_metadata && current_frame == 0 && samples == 0 && bytes == 4 && 0 == memcmp(buffer, FLAC__STREAM_SYNC_STRING, sizeof(FLAC__STREAM_SYNC_STRING))) {
+ aspect->seen_magic = true;
+ }
+ else {
+ /*
+ * If we get here, our assumption about the way write callbacks happen
+ * explained above is wrong
+ */
+ FLAC__ASSERT(0);
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+ }
+
+ aspect->samples_written += samples;
+
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
diff --git a/src/FLAC/src/libFLAC/ogg_helper.c b/src/FLAC/src/libFLAC/ogg_helper.c
new file mode 100644
index 0000000..aeaf99f
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ogg_helper.c
@@ -0,0 +1,208 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp(), memcpy() */
+#include "FLAC/assert.h"
+#include "private/ogg_helper.h"
+#include "protected/stream_encoder.h"
+
+
+static FLAC__bool full_read_(FLAC__StreamEncoder *encoder, FLAC__byte *buffer, size_t bytes, FLAC__StreamEncoderReadCallback read_callback, void *client_data)
+{
+ while(bytes > 0) {
+ size_t bytes_read = bytes;
+ switch(read_callback(encoder, buffer, &bytes_read, client_data)) {
+ case FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE:
+ bytes -= bytes_read;
+ buffer += bytes_read;
+ break;
+ case FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM:
+ if(bytes_read == 0) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+ return false;
+ }
+ bytes -= bytes_read;
+ buffer += bytes_read;
+ break;
+ case FLAC__STREAM_ENCODER_READ_STATUS_ABORT:
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return false;
+ case FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED:
+ return false;
+ default:
+ /* double protection: */
+ FLAC__ASSERT(0);
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void simple_ogg_page__init(ogg_page *page)
+{
+ page->header = 0;
+ page->header_len = 0;
+ page->body = 0;
+ page->body_len = 0;
+}
+
+void simple_ogg_page__clear(ogg_page *page)
+{
+ if(page->header)
+ free(page->header);
+ if(page->body)
+ free(page->body);
+ simple_ogg_page__init(page);
+}
+
+FLAC__bool simple_ogg_page__get_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderReadCallback read_callback, void *client_data)
+{
+ static const unsigned OGG_HEADER_FIXED_PORTION_LEN = 27;
+ static const unsigned OGG_MAX_HEADER_LEN = 27/*OGG_HEADER_FIXED_PORTION_LEN*/ + 255;
+ FLAC__byte crc[4];
+ FLAC__StreamEncoderSeekStatus seek_status;
+
+ FLAC__ASSERT(page->header == 0);
+ FLAC__ASSERT(page->header_len == 0);
+ FLAC__ASSERT(page->body == 0);
+ FLAC__ASSERT(page->body_len == 0);
+
+ /* move the stream pointer to the supposed beginning of the page */
+ if(0 == seek_callback)
+ return false;
+ if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+ if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return false;
+ }
+
+ /* allocate space for the page header */
+ if(0 == (page->header = (unsigned char *)malloc(OGG_MAX_HEADER_LEN))) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ /* read in the fixed part of the page header (up to but not including
+ * the segment table */
+ if(!full_read_(encoder, page->header, OGG_HEADER_FIXED_PORTION_LEN, read_callback, client_data))
+ return false;
+
+ page->header_len = OGG_HEADER_FIXED_PORTION_LEN + page->header[26];
+
+ /* check to see if it's a correct, "simple" page (one packet only) */
+ if(
+ memcmp(page->header, "OggS", 4) || /* doesn't start with OggS */
+ (page->header[5] & 0x01) || /* continued packet */
+ memcmp(page->header+6, "\0\0\0\0\0\0\0\0", 8) || /* granulepos is non-zero */
+ page->header[26] == 0 /* packet is 0-size */
+ ) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+ return false;
+ }
+
+ /* read in the segment table */
+ if(!full_read_(encoder, page->header + OGG_HEADER_FIXED_PORTION_LEN, page->header[26], read_callback, client_data))
+ return false;
+
+ {
+ unsigned i;
+
+ /* check to see that it specifies a single packet */
+ for(i = 0; i < (unsigned)page->header[26] - 1; i++) {
+ if(page->header[i + OGG_HEADER_FIXED_PORTION_LEN] != 255) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+ return false;
+ }
+ }
+
+ page->body_len = 255 * i + page->header[i + OGG_HEADER_FIXED_PORTION_LEN];
+ }
+
+ /* allocate space for the page body */
+ if(0 == (page->body = (unsigned char *)malloc(page->body_len))) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ /* read in the page body */
+ if(!full_read_(encoder, page->body, page->body_len, read_callback, client_data))
+ return false;
+
+ /* check the CRC */
+ memcpy(crc, page->header+22, 4);
+ ogg_page_checksum_set(page);
+ if(memcmp(crc, page->header+22, 4)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+ return false;
+ }
+
+ return true;
+}
+
+FLAC__bool simple_ogg_page__set_at(FLAC__StreamEncoder *encoder, FLAC__uint64 position, ogg_page *page, FLAC__StreamEncoderSeekCallback seek_callback, FLAC__StreamEncoderWriteCallback write_callback, void *client_data)
+{
+ FLAC__StreamEncoderSeekStatus seek_status;
+
+ FLAC__ASSERT(page->header != 0);
+ FLAC__ASSERT(page->header_len != 0);
+ FLAC__ASSERT(page->body != 0);
+ FLAC__ASSERT(page->body_len != 0);
+
+ /* move the stream pointer to the supposed beginning of the page */
+ if(0 == seek_callback)
+ return false;
+ if((seek_status = seek_callback((FLAC__StreamEncoder*)encoder, position, client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+ if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return false;
+ }
+
+ ogg_page_checksum_set(page);
+
+ /* re-write the page */
+ if(write_callback((FLAC__StreamEncoder*)encoder, page->header, page->header_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return false;
+ }
+ if(write_callback((FLAC__StreamEncoder*)encoder, page->body, page->body_len, 0, 0, client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/FLAC/src/libFLAC/ogg_mapping.c b/src/FLAC/src/libFLAC/ogg_mapping.c
new file mode 100644
index 0000000..a518892
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ogg_mapping.c
@@ -0,0 +1,47 @@
+/* libFLAC - Free Lossless Audio Codec
+ * Copyright (C) 2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "private/ogg_mapping.h"
+
+const unsigned FLAC__OGG_MAPPING_PACKET_TYPE_LEN = 8; /* bits */
+
+const FLAC__byte FLAC__OGG_MAPPING_FIRST_HEADER_PACKET_TYPE = 0x7f;
+
+const FLAC__byte * const FLAC__OGG_MAPPING_MAGIC = (const FLAC__byte * const)"FLAC";
+
+const unsigned FLAC__OGG_MAPPING_VERSION_MAJOR_LEN = 8; /* bits */
+const unsigned FLAC__OGG_MAPPING_VERSION_MINOR_LEN = 8; /* bits */
+
+const unsigned FLAC__OGG_MAPPING_NUM_HEADERS_LEN = 16; /* bits */
diff --git a/src/FLAC/src/libFLAC/ppc/Makefile.am b/src/FLAC/src/libFLAC/ppc/Makefile.am
new file mode 100644
index 0000000..87cd95c
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ppc/Makefile.am
@@ -0,0 +1,31 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+SUBDIRS = as gas
diff --git a/src/FLAC/src/libFLAC/ppc/as/Makefile.am b/src/FLAC/src/libFLAC/ppc/as/Makefile.am
new file mode 100644
index 0000000..f65e3cf
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ppc/as/Makefile.am
@@ -0,0 +1,34 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+
+EXTRA_DIST = \
+ lpc_asm.s
+
diff --git a/src/FLAC/src/libFLAC/ppc/as/lpc_asm.s b/src/FLAC/src/libFLAC/ppc/as/lpc_asm.s
new file mode 100644
index 0000000..ca39c6f
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ppc/as/lpc_asm.s
@@ -0,0 +1,429 @@
+; libFLAC - Free Lossless Audio Codec library
+; Copyright (C) 2004,2005,2006,2007 Josh Coalson
+;
+; 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.
+
+.text
+ .align 2
+.globl _FLAC__lpc_restore_signal_asm_ppc_altivec_16
+
+.globl _FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8
+
+_FLAC__lpc_restore_signal_asm_ppc_altivec_16:
+; r3: residual[]
+; r4: data_len
+; r5: qlp_coeff[]
+; r6: order
+; r7: lp_quantization
+; r8: data[]
+
+; see src/libFLAC/lpc.c:FLAC__lpc_restore_signal()
+; these is a PowerPC/Altivec assembly version which requires bps<=16 (or actual
+; bps<=15 for mid-side coding, since that uses an extra bit)
+
+; these should be fast; the inner loop is unrolled (it takes no more than
+; 3*(order%4) instructions, all of which are arithmetic), and all of the
+; coefficients and all relevant history stay in registers, so the outer loop
+; has only one load from memory (the residual)
+
+; I have not yet run this through simg4, so there may be some avoidable stalls,
+; and there may be a somewhat more clever way to do the outer loop
+
+; the branch mechanism may prevent dynamic loading; I still need to examine
+; this issue, and there may be a more elegant method
+
+ stmw r31,-4(r1)
+
+ addi r9,r1,-28
+ li r31,0xf
+ andc r9,r9,r31 ; for quadword-aligned stack data
+
+ slwi r6,r6,2 ; adjust for word size
+ slwi r4,r4,2
+ add r4,r4,r8 ; r4 = data+data_len
+
+ mfspr r0,256 ; cache old vrsave
+ addis r31,0,hi16(0xfffffc00)
+ ori r31,r31,lo16(0xfffffc00)
+ mtspr 256,r31 ; declare VRs in vrsave
+
+ cmplw cr0,r8,r4 ; i<data_len
+ bc 4,0,L1400
+
+ ; load coefficients into v0-v7 and initial history into v8-v15
+ li r31,0xf
+ and r31,r8,r31 ; r31: data%4
+ li r11,16
+ subf r31,r31,r11 ; r31: 4-(data%4)
+ slwi r31,r31,3 ; convert to bits for vsro
+ li r10,-4
+ stw r31,-4(r9)
+ lvewx v0,r10,r9
+ vspltisb v18,-1
+ vsro v18,v18,v0 ; v18: mask vector
+
+ li r31,0x8
+ lvsl v0,0,r31
+ vsldoi v0,v0,v0,12
+ li r31,0xc
+ lvsl v1,0,r31
+ vspltisb v2,0
+ vspltisb v3,-1
+ vmrglw v2,v2,v3
+ vsel v0,v1,v0,v2 ; v0: reversal permutation vector
+
+ add r10,r5,r6
+ lvsl v17,0,r5 ; v17: coefficient alignment permutation vector
+ vperm v17,v17,v17,v0 ; v17: reversal coefficient alignment permutation vector
+
+ mr r11,r8
+ lvsl v16,0,r11 ; v16: history alignment permutation vector
+
+ lvx v0,0,r5
+ addi r5,r5,16
+ lvx v1,0,r5
+ vperm v0,v0,v1,v17
+ lvx v8,0,r11
+ addi r11,r11,-16
+ lvx v9,0,r11
+ vperm v8,v9,v8,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1101
+ vand v0,v0,v18
+ addis r31,0,hi16(L1307)
+ ori r31,r31,lo16(L1307)
+ b L1199
+
+L1101:
+ addi r5,r5,16
+ lvx v2,0,r5
+ vperm v1,v1,v2,v17
+ addi r11,r11,-16
+ lvx v10,0,r11
+ vperm v9,v10,v9,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1102
+ vand v1,v1,v18
+ addis r31,0,hi16(L1306)
+ ori r31,r31,lo16(L1306)
+ b L1199
+
+L1102:
+ addi r5,r5,16
+ lvx v3,0,r5
+ vperm v2,v2,v3,v17
+ addi r11,r11,-16
+ lvx v11,0,r11
+ vperm v10,v11,v10,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1103
+ vand v2,v2,v18
+ addis r31,0,hi16(L1305)
+ ori r31,r31,lo16(L1305)
+ b L1199
+
+L1103:
+ addi r5,r5,16
+ lvx v4,0,r5
+ vperm v3,v3,v4,v17
+ addi r11,r11,-16
+ lvx v12,0,r11
+ vperm v11,v12,v11,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1104
+ vand v3,v3,v18
+ addis r31,0,hi16(L1304)
+ ori r31,r31,lo16(L1304)
+ b L1199
+
+L1104:
+ addi r5,r5,16
+ lvx v5,0,r5
+ vperm v4,v4,v5,v17
+ addi r11,r11,-16
+ lvx v13,0,r11
+ vperm v12,v13,v12,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1105
+ vand v4,v4,v18
+ addis r31,0,hi16(L1303)
+ ori r31,r31,lo16(L1303)
+ b L1199
+
+L1105:
+ addi r5,r5,16
+ lvx v6,0,r5
+ vperm v5,v5,v6,v17
+ addi r11,r11,-16
+ lvx v14,0,r11
+ vperm v13,v14,v13,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1106
+ vand v5,v5,v18
+ addis r31,0,hi16(L1302)
+ ori r31,r31,lo16(L1302)
+ b L1199
+
+L1106:
+ addi r5,r5,16
+ lvx v7,0,r5
+ vperm v6,v6,v7,v17
+ addi r11,r11,-16
+ lvx v15,0,r11
+ vperm v14,v15,v14,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1107
+ vand v6,v6,v18
+ addis r31,0,hi16(L1301)
+ ori r31,r31,lo16(L1301)
+ b L1199
+
+L1107:
+ addi r5,r5,16
+ lvx v19,0,r5
+ vperm v7,v7,v19,v17
+ addi r11,r11,-16
+ lvx v19,0,r11
+ vperm v15,v19,v15,v16
+ vand v7,v7,v18
+ addis r31,0,hi16(L1300)
+ ori r31,r31,lo16(L1300)
+
+L1199:
+ mtctr r31
+
+ ; set up invariant vectors
+ vspltish v16,0 ; v16: zero vector
+
+ li r10,-12
+ lvsr v17,r10,r8 ; v17: result shift vector
+ lvsl v18,r10,r3 ; v18: residual shift back vector
+
+ li r10,-4
+ stw r7,-4(r9)
+ lvewx v19,r10,r9 ; v19: lp_quantization vector
+
+L1200:
+ vmulosh v20,v0,v8 ; v20: sum vector
+ bcctr 20,0
+
+L1300:
+ vmulosh v21,v7,v15
+ vsldoi v15,v15,v14,4 ; increment history
+ vaddsws v20,v20,v21
+
+L1301:
+ vmulosh v21,v6,v14
+ vsldoi v14,v14,v13,4
+ vaddsws v20,v20,v21
+
+L1302:
+ vmulosh v21,v5,v13
+ vsldoi v13,v13,v12,4
+ vaddsws v20,v20,v21
+
+L1303:
+ vmulosh v21,v4,v12
+ vsldoi v12,v12,v11,4
+ vaddsws v20,v20,v21
+
+L1304:
+ vmulosh v21,v3,v11
+ vsldoi v11,v11,v10,4
+ vaddsws v20,v20,v21
+
+L1305:
+ vmulosh v21,v2,v10
+ vsldoi v10,v10,v9,4
+ vaddsws v20,v20,v21
+
+L1306:
+ vmulosh v21,v1,v9
+ vsldoi v9,v9,v8,4
+ vaddsws v20,v20,v21
+
+L1307:
+ vsumsws v20,v20,v16 ; v20[3]: sum
+ vsraw v20,v20,v19 ; v20[3]: sum >> lp_quantization
+
+ lvewx v21,0,r3 ; v21[n]: *residual
+ vperm v21,v21,v21,v18 ; v21[3]: *residual
+ vaddsws v20,v21,v20 ; v20[3]: *residual + (sum >> lp_quantization)
+ vsldoi v18,v18,v18,4 ; increment shift vector
+
+ vperm v21,v20,v20,v17 ; v21[n]: shift for storage
+ vsldoi v17,v17,v17,12 ; increment shift vector
+ stvewx v21,0,r8
+
+ vsldoi v20,v20,v20,12
+ vsldoi v8,v8,v20,4 ; insert value onto history
+
+ addi r3,r3,4
+ addi r8,r8,4
+ cmplw cr0,r8,r4 ; i<data_len
+ bc 12,0,L1200
+
+L1400:
+ mtspr 256,r0 ; restore old vrsave
+ lmw r31,-4(r1)
+ blr
+
+_FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8:
+; r3: residual[]
+; r4: data_len
+; r5: qlp_coeff[]
+; r6: order
+; r7: lp_quantization
+; r8: data[]
+
+; see _FLAC__lpc_restore_signal_asm_ppc_altivec_16() above
+; this version assumes order<=8; it uses fewer vector registers, which should
+; save time in context switches, and has less code, which may improve
+; instruction caching
+
+ stmw r31,-4(r1)
+
+ addi r9,r1,-28
+ li r31,0xf
+ andc r9,r9,r31 ; for quadword-aligned stack data
+
+ slwi r6,r6,2 ; adjust for word size
+ slwi r4,r4,2
+ add r4,r4,r8 ; r4 = data+data_len
+
+ mfspr r0,256 ; cache old vrsave
+ addis r31,0,hi16(0xffc00000)
+ ori r31,r31,lo16(0xffc00000)
+ mtspr 256,r31 ; declare VRs in vrsave
+
+ cmplw cr0,r8,r4 ; i<data_len
+ bc 4,0,L2400
+
+ ; load coefficients into v0-v1 and initial history into v2-v3
+ li r31,0xf
+ and r31,r8,r31 ; r31: data%4
+ li r11,16
+ subf r31,r31,r11 ; r31: 4-(data%4)
+ slwi r31,r31,3 ; convert to bits for vsro
+ li r10,-4
+ stw r31,-4(r9)
+ lvewx v0,r10,r9
+ vspltisb v6,-1
+ vsro v6,v6,v0 ; v6: mask vector
+
+ li r31,0x8
+ lvsl v0,0,r31
+ vsldoi v0,v0,v0,12
+ li r31,0xc
+ lvsl v1,0,r31
+ vspltisb v2,0
+ vspltisb v3,-1
+ vmrglw v2,v2,v3
+ vsel v0,v1,v0,v2 ; v0: reversal permutation vector
+
+ add r10,r5,r6
+ lvsl v5,0,r5 ; v5: coefficient alignment permutation vector
+ vperm v5,v5,v5,v0 ; v5: reversal coefficient alignment permutation vector
+
+ mr r11,r8
+ lvsl v4,0,r11 ; v4: history alignment permutation vector
+
+ lvx v0,0,r5
+ addi r5,r5,16
+ lvx v1,0,r5
+ vperm v0,v0,v1,v5
+ lvx v2,0,r11
+ addi r11,r11,-16
+ lvx v3,0,r11
+ vperm v2,v3,v2,v4
+ cmplw cr0,r5,r10
+ bc 12,0,L2101
+ vand v0,v0,v6
+ addis r31,0,hi16(L2301)
+ ori r31,r31,lo16(L2301)
+ b L2199
+
+L2101:
+ addi r5,r5,16
+ lvx v7,0,r5
+ vperm v1,v1,v7,v5
+ addi r11,r11,-16
+ lvx v7,0,r11
+ vperm v3,v7,v3,v4
+ vand v1,v1,v6
+ addis r31,0,hi16(L2300)
+ ori r31,r31,lo16(L2300)
+
+L2199:
+ mtctr r31
+
+ ; set up invariant vectors
+ vspltish v4,0 ; v4: zero vector
+
+ li r10,-12
+ lvsr v5,r10,r8 ; v5: result shift vector
+ lvsl v6,r10,r3 ; v6: residual shift back vector
+
+ li r10,-4
+ stw r7,-4(r9)
+ lvewx v7,r10,r9 ; v7: lp_quantization vector
+
+L2200:
+ vmulosh v8,v0,v2 ; v8: sum vector
+ bcctr 20,0
+
+L2300:
+ vmulosh v9,v1,v3
+ vsldoi v3,v3,v2,4
+ vaddsws v8,v8,v9
+
+L2301:
+ vsumsws v8,v8,v4 ; v8[3]: sum
+ vsraw v8,v8,v7 ; v8[3]: sum >> lp_quantization
+
+ lvewx v9,0,r3 ; v9[n]: *residual
+ vperm v9,v9,v9,v6 ; v9[3]: *residual
+ vaddsws v8,v9,v8 ; v8[3]: *residual + (sum >> lp_quantization)
+ vsldoi v6,v6,v6,4 ; increment shift vector
+
+ vperm v9,v8,v8,v5 ; v9[n]: shift for storage
+ vsldoi v5,v5,v5,12 ; increment shift vector
+ stvewx v9,0,r8
+
+ vsldoi v8,v8,v8,12
+ vsldoi v2,v2,v8,4 ; insert value onto history
+
+ addi r3,r3,4
+ addi r8,r8,4
+ cmplw cr0,r8,r4 ; i<data_len
+ bc 12,0,L2200
+
+L2400:
+ mtspr 256,r0 ; restore old vrsave
+ lmw r31,-4(r1)
+ blr
diff --git a/src/FLAC/src/libFLAC/ppc/gas/Makefile.am b/src/FLAC/src/libFLAC/ppc/gas/Makefile.am
new file mode 100644
index 0000000..06e77de
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ppc/gas/Makefile.am
@@ -0,0 +1,33 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+
+EXTRA_DIST = \
+ lpc_asm.s
diff --git a/src/FLAC/src/libFLAC/ppc/gas/lpc_asm.s b/src/FLAC/src/libFLAC/ppc/gas/lpc_asm.s
new file mode 100644
index 0000000..2203570
--- /dev/null
+++ b/src/FLAC/src/libFLAC/ppc/gas/lpc_asm.s
@@ -0,0 +1,431 @@
+# libFLAC - Free Lossless Audio Codec library
+# Copyright (C) 2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+.text
+ .align 2
+.globl _FLAC__lpc_restore_signal_asm_ppc_altivec_16
+.type _FLAC__lpc_restore_signal_asm_ppc_altivec_16, @function
+
+.globl _FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8
+.type _FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8, @function
+
+_FLAC__lpc_restore_signal_asm_ppc_altivec_16:
+# r3: residual[]
+# r4: data_len
+# r5: qlp_coeff[]
+# r6: order
+# r7: lp_quantization
+# r8: data[]
+
+# see src/libFLAC/lpc.c:FLAC__lpc_restore_signal()
+# these is a PowerPC/Altivec assembly version which requires bps<=16 (or actual
+# bps<=15 for mid-side coding, since that uses an extra bit)
+
+# these should be fast; the inner loop is unrolled (it takes no more than
+# 3*(order%4) instructions, all of which are arithmetic), and all of the
+# coefficients and all relevant history stay in registers, so the outer loop
+# has only one load from memory (the residual)
+
+# I have not yet run this through simg4, so there may be some avoidable stalls,
+# and there may be a somewhat more clever way to do the outer loop
+
+# the branch mechanism may prevent dynamic loading; I still need to examine
+# this issue, and there may be a more elegant method
+
+ stmw r31,-4(r1)
+
+ addi r9,r1,-28
+ li r31,0xf
+ andc r9,r9,r31 # for quadword-aligned stack data
+
+ slwi r6,r6,2 # adjust for word size
+ slwi r4,r4,2
+ add r4,r4,r8 # r4 = data+data_len
+
+ mfspr r0,256 # cache old vrsave
+ addis r31,0,0xffff
+ ori r31,r31,0xfc00
+ mtspr 256,r31 # declare VRs in vrsave
+
+ cmplw cr0,r8,r4 # i<data_len
+ bc 4,0,L1400
+
+ # load coefficients into v0-v7 and initial history into v8-v15
+ li r31,0xf
+ and r31,r8,r31 # r31: data%4
+ li r11,16
+ subf r31,r31,r11 # r31: 4-(data%4)
+ slwi r31,r31,3 # convert to bits for vsro
+ li r10,-4
+ stw r31,-4(r9)
+ lvewx v0,r10,r9
+ vspltisb v18,-1
+ vsro v18,v18,v0 # v18: mask vector
+
+ li r31,0x8
+ lvsl v0,0,r31
+ vsldoi v0,v0,v0,12
+ li r31,0xc
+ lvsl v1,0,r31
+ vspltisb v2,0
+ vspltisb v3,-1
+ vmrglw v2,v2,v3
+ vsel v0,v1,v0,v2 # v0: reversal permutation vector
+
+ add r10,r5,r6
+ lvsl v17,0,r5 # v17: coefficient alignment permutation vector
+ vperm v17,v17,v17,v0 # v17: reversal coefficient alignment permutation vector
+
+ mr r11,r8
+ lvsl v16,0,r11 # v16: history alignment permutation vector
+
+ lvx v0,0,r5
+ addi r5,r5,16
+ lvx v1,0,r5
+ vperm v0,v0,v1,v17
+ lvx v8,0,r11
+ addi r11,r11,-16
+ lvx v9,0,r11
+ vperm v8,v9,v8,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1101
+ vand v0,v0,v18
+ addis r31,0,L1307@ha
+ ori r31,r31,L1307@l
+ b L1199
+
+L1101:
+ addi r5,r5,16
+ lvx v2,0,r5
+ vperm v1,v1,v2,v17
+ addi r11,r11,-16
+ lvx v10,0,r11
+ vperm v9,v10,v9,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1102
+ vand v1,v1,v18
+ addis r31,0,L1306@ha
+ ori r31,r31,L1306@l
+ b L1199
+
+L1102:
+ addi r5,r5,16
+ lvx v3,0,r5
+ vperm v2,v2,v3,v17
+ addi r11,r11,-16
+ lvx v11,0,r11
+ vperm v10,v11,v10,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1103
+ vand v2,v2,v18
+ lis r31,L1305@ha
+ la r31,L1305@l(r31)
+ b L1199
+
+L1103:
+ addi r5,r5,16
+ lvx v4,0,r5
+ vperm v3,v3,v4,v17
+ addi r11,r11,-16
+ lvx v12,0,r11
+ vperm v11,v12,v11,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1104
+ vand v3,v3,v18
+ lis r31,L1304@ha
+ la r31,L1304@l(r31)
+ b L1199
+
+L1104:
+ addi r5,r5,16
+ lvx v5,0,r5
+ vperm v4,v4,v5,v17
+ addi r11,r11,-16
+ lvx v13,0,r11
+ vperm v12,v13,v12,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1105
+ vand v4,v4,v18
+ lis r31,L1303@ha
+ la r31,L1303@l(r31)
+ b L1199
+
+L1105:
+ addi r5,r5,16
+ lvx v6,0,r5
+ vperm v5,v5,v6,v17
+ addi r11,r11,-16
+ lvx v14,0,r11
+ vperm v13,v14,v13,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1106
+ vand v5,v5,v18
+ lis r31,L1302@ha
+ la r31,L1302@l(r31)
+ b L1199
+
+L1106:
+ addi r5,r5,16
+ lvx v7,0,r5
+ vperm v6,v6,v7,v17
+ addi r11,r11,-16
+ lvx v15,0,r11
+ vperm v14,v15,v14,v16
+ cmplw cr0,r5,r10
+ bc 12,0,L1107
+ vand v6,v6,v18
+ lis r31,L1301@ha
+ la r31,L1301@l(r31)
+ b L1199
+
+L1107:
+ addi r5,r5,16
+ lvx v19,0,r5
+ vperm v7,v7,v19,v17
+ addi r11,r11,-16
+ lvx v19,0,r11
+ vperm v15,v19,v15,v16
+ vand v7,v7,v18
+ lis r31,L1300@ha
+ la r31,L1300@l(r31)
+
+L1199:
+ mtctr r31
+
+ # set up invariant vectors
+ vspltish v16,0 # v16: zero vector
+
+ li r10,-12
+ lvsr v17,r10,r8 # v17: result shift vector
+ lvsl v18,r10,r3 # v18: residual shift back vector
+
+ li r10,-4
+ stw r7,-4(r9)
+ lvewx v19,r10,r9 # v19: lp_quantization vector
+
+L1200:
+ vmulosh v20,v0,v8 # v20: sum vector
+ bcctr 20,0
+
+L1300:
+ vmulosh v21,v7,v15
+ vsldoi v15,v15,v14,4 # increment history
+ vaddsws v20,v20,v21
+
+L1301:
+ vmulosh v21,v6,v14
+ vsldoi v14,v14,v13,4
+ vaddsws v20,v20,v21
+
+L1302:
+ vmulosh v21,v5,v13
+ vsldoi v13,v13,v12,4
+ vaddsws v20,v20,v21
+
+L1303:
+ vmulosh v21,v4,v12
+ vsldoi v12,v12,v11,4
+ vaddsws v20,v20,v21
+
+L1304:
+ vmulosh v21,v3,v11
+ vsldoi v11,v11,v10,4
+ vaddsws v20,v20,v21
+
+L1305:
+ vmulosh v21,v2,v10
+ vsldoi v10,v10,v9,4
+ vaddsws v20,v20,v21
+
+L1306:
+ vmulosh v21,v1,v9
+ vsldoi v9,v9,v8,4
+ vaddsws v20,v20,v21
+
+L1307:
+ vsumsws v20,v20,v16 # v20[3]: sum
+ vsraw v20,v20,v19 # v20[3]: sum >> lp_quantization
+
+ lvewx v21,0,r3 # v21[n]: *residual
+ vperm v21,v21,v21,v18 # v21[3]: *residual
+ vaddsws v20,v21,v20 # v20[3]: *residual + (sum >> lp_quantization)
+ vsldoi v18,v18,v18,4 # increment shift vector
+
+ vperm v21,v20,v20,v17 # v21[n]: shift for storage
+ vsldoi v17,v17,v17,12 # increment shift vector
+ stvewx v21,0,r8
+
+ vsldoi v20,v20,v20,12
+ vsldoi v8,v8,v20,4 # insert value onto history
+
+ addi r3,r3,4
+ addi r8,r8,4
+ cmplw cr0,r8,r4 # i<data_len
+ bc 12,0,L1200
+
+L1400:
+ mtspr 256,r0 # restore old vrsave
+ lmw r31,-4(r1)
+ blr
+
+_FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8:
+# r3: residual[]
+# r4: data_len
+# r5: qlp_coeff[]
+# r6: order
+# r7: lp_quantization
+# r8: data[]
+
+# see _FLAC__lpc_restore_signal_asm_ppc_altivec_16() above
+# this version assumes order<=8; it uses fewer vector registers, which should
+# save time in context switches, and has less code, which may improve
+# instruction caching
+
+ stmw r31,-4(r1)
+
+ addi r9,r1,-28
+ li r31,0xf
+ andc r9,r9,r31 # for quadword-aligned stack data
+
+ slwi r6,r6,2 # adjust for word size
+ slwi r4,r4,2
+ add r4,r4,r8 # r4 = data+data_len
+
+ mfspr r0,256 # cache old vrsave
+ addis r31,0,0xffc0
+ ori r31,r31,0x0000
+ mtspr 256,r31 # declare VRs in vrsave
+
+ cmplw cr0,r8,r4 # i<data_len
+ bc 4,0,L2400
+
+ # load coefficients into v0-v1 and initial history into v2-v3
+ li r31,0xf
+ and r31,r8,r31 # r31: data%4
+ li r11,16
+ subf r31,r31,r11 # r31: 4-(data%4)
+ slwi r31,r31,3 # convert to bits for vsro
+ li r10,-4
+ stw r31,-4(r9)
+ lvewx v0,r10,r9
+ vspltisb v6,-1
+ vsro v6,v6,v0 # v6: mask vector
+
+ li r31,0x8
+ lvsl v0,0,r31
+ vsldoi v0,v0,v0,12
+ li r31,0xc
+ lvsl v1,0,r31
+ vspltisb v2,0
+ vspltisb v3,-1
+ vmrglw v2,v2,v3
+ vsel v0,v1,v0,v2 # v0: reversal permutation vector
+
+ add r10,r5,r6
+ lvsl v5,0,r5 # v5: coefficient alignment permutation vector
+ vperm v5,v5,v5,v0 # v5: reversal coefficient alignment permutation vector
+
+ mr r11,r8
+ lvsl v4,0,r11 # v4: history alignment permutation vector
+
+ lvx v0,0,r5
+ addi r5,r5,16
+ lvx v1,0,r5
+ vperm v0,v0,v1,v5
+ lvx v2,0,r11
+ addi r11,r11,-16
+ lvx v3,0,r11
+ vperm v2,v3,v2,v4
+ cmplw cr0,r5,r10
+ bc 12,0,L2101
+ vand v0,v0,v6
+ lis r31,L2301@ha
+ la r31,L2301@l(r31)
+ b L2199
+
+L2101:
+ addi r5,r5,16
+ lvx v7,0,r5
+ vperm v1,v1,v7,v5
+ addi r11,r11,-16
+ lvx v7,0,r11
+ vperm v3,v7,v3,v4
+ vand v1,v1,v6
+ lis r31,L2300@ha
+ la r31,L2300@l(r31)
+
+L2199:
+ mtctr r31
+
+ # set up invariant vectors
+ vspltish v4,0 # v4: zero vector
+
+ li r10,-12
+ lvsr v5,r10,r8 # v5: result shift vector
+ lvsl v6,r10,r3 # v6: residual shift back vector
+
+ li r10,-4
+ stw r7,-4(r9)
+ lvewx v7,r10,r9 # v7: lp_quantization vector
+
+L2200:
+ vmulosh v8,v0,v2 # v8: sum vector
+ bcctr 20,0
+
+L2300:
+ vmulosh v9,v1,v3
+ vsldoi v3,v3,v2,4
+ vaddsws v8,v8,v9
+
+L2301:
+ vsumsws v8,v8,v4 # v8[3]: sum
+ vsraw v8,v8,v7 # v8[3]: sum >> lp_quantization
+
+ lvewx v9,0,r3 # v9[n]: *residual
+ vperm v9,v9,v9,v6 # v9[3]: *residual
+ vaddsws v8,v9,v8 # v8[3]: *residual + (sum >> lp_quantization)
+ vsldoi v6,v6,v6,4 # increment shift vector
+
+ vperm v9,v8,v8,v5 # v9[n]: shift for storage
+ vsldoi v5,v5,v5,12 # increment shift vector
+ stvewx v9,0,r8
+
+ vsldoi v8,v8,v8,12
+ vsldoi v2,v2,v8,4 # insert value onto history
+
+ addi r3,r3,4
+ addi r8,r8,4
+ cmplw cr0,r8,r4 # i<data_len
+ bc 12,0,L2200
+
+L2400:
+ mtspr 256,r0 # restore old vrsave
+ lmw r31,-4(r1)
+ blr
diff --git a/src/FLAC/src/libFLAC/stream_decoder.c b/src/FLAC/src/libFLAC/stream_decoder.c
new file mode 100644
index 0000000..48636ff
--- /dev/null
+++ b/src/FLAC/src/libFLAC/stream_decoder.c
@@ -0,0 +1,3338 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__
+#include <io.h> /* for _setmode() */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#if defined __CYGWIN__ || defined __EMX__
+#include <io.h> /* for setmode(), O_BINARY */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memset/memcpy() */
+#include <sys/stat.h> /* for stat() */
+#include <sys/types.h> /* for off_t */
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#if _MSC_VER <= 1600 || defined __BORLANDC__ /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include "FLAC/assert.h"
+#include "protected/stream_decoder.h"
+#include "private/bitreader.h"
+#include "private/bitmath.h"
+#include "private/cpu.h"
+#include "private/crc.h"
+#include "private/fixed.h"
+#include "private/format.h"
+#include "private/lpc.h"
+#include "private/md5.h"
+#include "private/memory.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(a,b) ((a)>(b)?(a):(b))
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+
+/* technically this should be in an "export.c" but this is convenient enough */
+FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC =
+#if FLAC__HAS_OGG
+ 1
+#else
+ 0
+#endif
+;
+
+
+/***********************************************************************
+ *
+ * Private static data
+ *
+ ***********************************************************************/
+
+static FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' };
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__StreamDecoder *decoder);
+static FILE *get_binary_stdin_(void);
+static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels);
+static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id);
+static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length);
+static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length);
+static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj);
+static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj);
+static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj);
+static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder);
+static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode);
+static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode);
+static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode);
+static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual);
+static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder);
+static FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data);
+#if FLAC__HAS_OGG
+static FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes);
+static FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+#endif
+static FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+static void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status);
+static FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
+#if FLAC__HAS_OGG
+static FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample);
+#endif
+static FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+static FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data);
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamDecoderPrivate {
+#if FLAC__HAS_OGG
+ FLAC__bool is_ogg;
+#endif
+ FLAC__StreamDecoderReadCallback read_callback;
+ FLAC__StreamDecoderSeekCallback seek_callback;
+ FLAC__StreamDecoderTellCallback tell_callback;
+ FLAC__StreamDecoderLengthCallback length_callback;
+ FLAC__StreamDecoderEofCallback eof_callback;
+ FLAC__StreamDecoderWriteCallback write_callback;
+ FLAC__StreamDecoderMetadataCallback metadata_callback;
+ FLAC__StreamDecoderErrorCallback error_callback;
+ /* generic 32-bit datapath: */
+ void (*local_lpc_restore_signal)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+ /* generic 64-bit datapath: */
+ void (*local_lpc_restore_signal_64bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+ /* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit): */
+ void (*local_lpc_restore_signal_16bit)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+ /* for use when the signal is <= 16 bits-per-sample, or <= 15 bits-per-sample on a side channel (which requires 1 extra bit), AND order <= 8: */
+ void (*local_lpc_restore_signal_16bit_order8)(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]);
+ FLAC__bool (*local_bitreader_read_rice_signed_block)(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter);
+ void *client_data;
+ FILE *file; /* only used if FLAC__stream_decoder_init_file()/FLAC__stream_decoder_init_file() called, else NULL */
+ FLAC__BitReader *input;
+ FLAC__int32 *output[FLAC__MAX_CHANNELS];
+ FLAC__int32 *residual[FLAC__MAX_CHANNELS]; /* WATCHOUT: these are the aligned pointers; the real pointers that should be free()'d are residual_unaligned[] below */
+ FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS];
+ unsigned output_capacity, output_channels;
+ FLAC__uint32 last_frame_number;
+ FLAC__uint32 last_block_size;
+ FLAC__uint64 samples_decoded;
+ FLAC__bool has_stream_info, has_seek_table;
+ FLAC__StreamMetadata stream_info;
+ FLAC__StreamMetadata seek_table;
+ FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */
+ FLAC__byte *metadata_filter_ids;
+ unsigned metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */
+ FLAC__Frame frame;
+ FLAC__bool cached; /* true if there is a byte in lookahead */
+ FLAC__CPUInfo cpuinfo;
+ FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */
+ FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */
+ /* unaligned (original) pointers to allocated data */
+ FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS];
+ FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek or if the metadata has a zero MD5 */
+ FLAC__bool internal_reset_hack; /* used only during init() so we can call reset to set up the decoder without rewinding the input */
+ FLAC__bool is_seeking;
+ FLAC__MD5Context md5context;
+ FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */
+ /* (the rest of these are only used for seeking) */
+ FLAC__Frame last_frame; /* holds the info of the last frame we seeked to */
+ FLAC__uint64 first_frame_offset; /* hint to the seek routine of where in the stream the first audio frame starts */
+ FLAC__uint64 target_sample;
+ unsigned unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */
+#if FLAC__HAS_OGG
+ FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine to check when process_single() actually writes a frame */
+#endif
+} FLAC__StreamDecoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__StreamDecoderStateString[] = {
+ "FLAC__STREAM_DECODER_SEARCH_FOR_METADATA",
+ "FLAC__STREAM_DECODER_READ_METADATA",
+ "FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC",
+ "FLAC__STREAM_DECODER_READ_FRAME",
+ "FLAC__STREAM_DECODER_END_OF_STREAM",
+ "FLAC__STREAM_DECODER_OGG_ERROR",
+ "FLAC__STREAM_DECODER_SEEK_ERROR",
+ "FLAC__STREAM_DECODER_ABORTED",
+ "FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR",
+ "FLAC__STREAM_DECODER_UNINITIALIZED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderInitStatusString[] = {
+ "FLAC__STREAM_DECODER_INIT_STATUS_OK",
+ "FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER",
+ "FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS",
+ "FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR",
+ "FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE",
+ "FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = {
+ "FLAC__STREAM_DECODER_READ_STATUS_CONTINUE",
+ "FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM",
+ "FLAC__STREAM_DECODER_READ_STATUS_ABORT"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[] = {
+ "FLAC__STREAM_DECODER_SEEK_STATUS_OK",
+ "FLAC__STREAM_DECODER_SEEK_STATUS_ERROR",
+ "FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderTellStatusString[] = {
+ "FLAC__STREAM_DECODER_TELL_STATUS_OK",
+ "FLAC__STREAM_DECODER_TELL_STATUS_ERROR",
+ "FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[] = {
+ "FLAC__STREAM_DECODER_LENGTH_STATUS_OK",
+ "FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR",
+ "FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = {
+ "FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE",
+ "FLAC__STREAM_DECODER_WRITE_STATUS_ABORT"
+};
+
+FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = {
+ "FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC",
+ "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER",
+ "FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH",
+ "FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM"
+};
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ ***********************************************************************/
+FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void)
+{
+ FLAC__StreamDecoder *decoder;
+ unsigned i;
+
+ FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+ decoder = (FLAC__StreamDecoder*)calloc(1, sizeof(FLAC__StreamDecoder));
+ if(decoder == 0) {
+ return 0;
+ }
+
+ decoder->protected_ = (FLAC__StreamDecoderProtected*)calloc(1, sizeof(FLAC__StreamDecoderProtected));
+ if(decoder->protected_ == 0) {
+ free(decoder);
+ return 0;
+ }
+
+ decoder->private_ = (FLAC__StreamDecoderPrivate*)calloc(1, sizeof(FLAC__StreamDecoderPrivate));
+ if(decoder->private_ == 0) {
+ free(decoder->protected_);
+ free(decoder);
+ return 0;
+ }
+
+ decoder->private_->input = FLAC__bitreader_new();
+ if(decoder->private_->input == 0) {
+ free(decoder->private_);
+ free(decoder->protected_);
+ free(decoder);
+ return 0;
+ }
+
+ decoder->private_->metadata_filter_ids_capacity = 16;
+ if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) {
+ FLAC__bitreader_delete(decoder->private_->input);
+ free(decoder->private_);
+ free(decoder->protected_);
+ free(decoder);
+ return 0;
+ }
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ decoder->private_->output[i] = 0;
+ decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+ }
+
+ decoder->private_->output_capacity = 0;
+ decoder->private_->output_channels = 0;
+ decoder->private_->has_seek_table = false;
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]);
+
+ decoder->private_->file = 0;
+
+ set_defaults_(decoder);
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+
+ return decoder;
+}
+
+FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder)
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->private_->input);
+
+ (void)FLAC__stream_decoder_finish(decoder);
+
+ if(0 != decoder->private_->metadata_filter_ids)
+ free(decoder->private_->metadata_filter_ids);
+
+ FLAC__bitreader_delete(decoder->private_->input);
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++)
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]);
+
+ free(decoder->private_);
+ free(decoder->protected_);
+ free(decoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+static FLAC__StreamDecoderInitStatus init_stream_internal_(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data,
+ FLAC__bool is_ogg
+)
+{
+ FLAC__ASSERT(0 != decoder);
+
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+#if !FLAC__HAS_OGG
+ if(is_ogg)
+ return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+#endif
+
+ if(
+ 0 == read_callback ||
+ 0 == write_callback ||
+ 0 == error_callback ||
+ (seek_callback && (0 == tell_callback || 0 == length_callback || 0 == eof_callback))
+ )
+ return FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+#if FLAC__HAS_OGG
+ decoder->private_->is_ogg = is_ogg;
+ if(is_ogg && !FLAC__ogg_decoder_aspect_init(&decoder->protected_->ogg_decoder_aspect))
+ return decoder->protected_->state = FLAC__STREAM_DECODER_OGG_ERROR;
+#endif
+
+ /*
+ * get the CPU info and set the function pointers
+ */
+ FLAC__cpu_info(&decoder->private_->cpuinfo);
+ /* first default to the non-asm routines */
+ decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal;
+ decoder->private_->local_lpc_restore_signal_64bit = FLAC__lpc_restore_signal_wide;
+ decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal;
+ decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal;
+ decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block;
+ /* now override with asm where appropriate */
+#ifndef FLAC__NO_ASM
+ if(decoder->private_->cpuinfo.use_asm) {
+#ifdef FLAC__CPU_IA32
+ FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
+#ifdef FLAC__HAS_NASM
+ if(decoder->private_->cpuinfo.data.ia32.bswap)
+ decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap;
+ if(decoder->private_->cpuinfo.data.ia32.mmx) {
+ decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32;
+ decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32_mmx;
+ decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32_mmx;
+ }
+ else {
+ decoder->private_->local_lpc_restore_signal = FLAC__lpc_restore_signal_asm_ia32;
+ decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ia32;
+ decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ia32;
+ }
+#endif
+#elif defined FLAC__CPU_PPC
+ FLAC__ASSERT(decoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_PPC);
+ if(decoder->private_->cpuinfo.data.ppc.altivec) {
+ decoder->private_->local_lpc_restore_signal_16bit = FLAC__lpc_restore_signal_asm_ppc_altivec_16;
+ decoder->private_->local_lpc_restore_signal_16bit_order8 = FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8;
+ }
+#endif
+ }
+#endif
+
+ /* from here on, errors are fatal */
+
+ if(!FLAC__bitreader_init(decoder->private_->input, decoder->private_->cpuinfo, read_callback_, decoder)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR;
+ }
+
+ decoder->private_->read_callback = read_callback;
+ decoder->private_->seek_callback = seek_callback;
+ decoder->private_->tell_callback = tell_callback;
+ decoder->private_->length_callback = length_callback;
+ decoder->private_->eof_callback = eof_callback;
+ decoder->private_->write_callback = write_callback;
+ decoder->private_->metadata_callback = metadata_callback;
+ decoder->private_->error_callback = error_callback;
+ decoder->private_->client_data = client_data;
+ decoder->private_->last_frame_number = 0;
+ decoder->private_->last_block_size = 0;
+ decoder->private_->samples_decoded = 0;
+ decoder->private_->has_stream_info = false;
+ decoder->private_->cached = false;
+
+ decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+ decoder->private_->is_seeking = false;
+
+ decoder->private_->internal_reset_hack = true; /* so the following reset does not try to rewind the input */
+ if(!FLAC__stream_decoder_reset(decoder)) {
+ /* above call sets the state for us */
+ return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR;
+ }
+
+ return FLAC__STREAM_DECODER_INIT_STATUS_OK;
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_stream_internal_(
+ decoder,
+ read_callback,
+ seek_callback,
+ tell_callback,
+ length_callback,
+ eof_callback,
+ write_callback,
+ metadata_callback,
+ error_callback,
+ client_data,
+ /*is_ogg=*/false
+ );
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
+ FLAC__StreamDecoder *decoder,
+ FLAC__StreamDecoderReadCallback read_callback,
+ FLAC__StreamDecoderSeekCallback seek_callback,
+ FLAC__StreamDecoderTellCallback tell_callback,
+ FLAC__StreamDecoderLengthCallback length_callback,
+ FLAC__StreamDecoderEofCallback eof_callback,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_stream_internal_(
+ decoder,
+ read_callback,
+ seek_callback,
+ tell_callback,
+ length_callback,
+ eof_callback,
+ write_callback,
+ metadata_callback,
+ error_callback,
+ client_data,
+ /*is_ogg=*/true
+ );
+}
+
+static FLAC__StreamDecoderInitStatus init_FILE_internal_(
+ FLAC__StreamDecoder *decoder,
+ FILE *file,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data,
+ FLAC__bool is_ogg
+)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != file);
+
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return decoder->protected_->state = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+ if(0 == write_callback || 0 == error_callback)
+ return decoder->protected_->state = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+ /*
+ * To make sure that our file does not go unclosed after an error, we
+ * must assign the FILE pointer before any further error can occur in
+ * this routine.
+ */
+ if(file == stdin)
+ file = get_binary_stdin_(); /* just to be safe */
+
+ decoder->private_->file = file;
+
+ return init_stream_internal_(
+ decoder,
+ file_read_callback_,
+ decoder->private_->file == stdin? 0: file_seek_callback_,
+ decoder->private_->file == stdin? 0: file_tell_callback_,
+ decoder->private_->file == stdin? 0: file_length_callback_,
+ file_eof_callback_,
+ write_callback,
+ metadata_callback,
+ error_callback,
+ client_data,
+ is_ogg
+ );
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
+ FLAC__StreamDecoder *decoder,
+ FILE *file,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
+ FLAC__StreamDecoder *decoder,
+ FILE *file,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true);
+}
+
+static FLAC__StreamDecoderInitStatus init_file_internal_(
+ FLAC__StreamDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data,
+ FLAC__bool is_ogg
+)
+{
+ FILE *file;
+
+ FLAC__ASSERT(0 != decoder);
+
+ /*
+ * To make sure that our file does not go unclosed after an error, we
+ * have to do the same entrance checks here that are later performed
+ * in FLAC__stream_decoder_init_FILE() before the FILE* is assigned.
+ */
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return decoder->protected_->state = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+ if(0 == write_callback || 0 == error_callback)
+ return decoder->protected_->state = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS;
+
+ file = filename? fopen(filename, "rb") : stdin;
+
+ if(0 == file)
+ return FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE;
+
+ return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, is_ogg);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
+ FLAC__StreamDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file(
+ FLAC__StreamDecoder *decoder,
+ const char *filename,
+ FLAC__StreamDecoderWriteCallback write_callback,
+ FLAC__StreamDecoderMetadataCallback metadata_callback,
+ FLAC__StreamDecoderErrorCallback error_callback,
+ void *client_data
+)
+{
+ return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true);
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder)
+{
+ FLAC__bool md5_failed = false;
+ unsigned i;
+
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->protected_);
+
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED)
+ return true;
+
+ /* see the comment in FLAC__seekable_stream_decoder_reset() as to why we
+ * always call FLAC__MD5Final()
+ */
+ FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context);
+
+ if(decoder->private_->has_seek_table && 0 != decoder->private_->seek_table.data.seek_table.points) {
+ free(decoder->private_->seek_table.data.seek_table.points);
+ decoder->private_->seek_table.data.seek_table.points = 0;
+ decoder->private_->has_seek_table = false;
+ }
+ FLAC__bitreader_free(decoder->private_->input);
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ /* WATCHOUT:
+ * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
+ * output arrays have a buffer of up to 3 zeroes in front
+ * (at negative indices) for alignment purposes; we use 4
+ * to keep the data well-aligned.
+ */
+ if(0 != decoder->private_->output[i]) {
+ free(decoder->private_->output[i]-4);
+ decoder->private_->output[i] = 0;
+ }
+ if(0 != decoder->private_->residual_unaligned[i]) {
+ free(decoder->private_->residual_unaligned[i]);
+ decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+ }
+ }
+ decoder->private_->output_capacity = 0;
+ decoder->private_->output_channels = 0;
+
+#if FLAC__HAS_OGG
+ if(decoder->private_->is_ogg)
+ FLAC__ogg_decoder_aspect_finish(&decoder->protected_->ogg_decoder_aspect);
+#endif
+
+ if(0 != decoder->private_->file) {
+ if(decoder->private_->file != stdin)
+ fclose(decoder->private_->file);
+ decoder->private_->file = 0;
+ }
+
+ if(decoder->private_->do_md5_checking) {
+ if(memcmp(decoder->private_->stream_info.data.stream_info.md5sum, decoder->private_->computed_md5sum, 16))
+ md5_failed = true;
+ }
+ decoder->private_->is_seeking = false;
+
+ set_defaults_(decoder);
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED;
+
+ return !md5_failed;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long value)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->protected_);
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+#if FLAC__HAS_OGG
+ /* can't check decoder->private_->is_ogg since that's not set until init time */
+ FLAC__ogg_decoder_aspect_set_serial_number(&decoder->protected_->ogg_decoder_aspect, value);
+ return true;
+#else
+ (void)value;
+ return false;
+#endif
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+ decoder->protected_->md5_checking = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->protected_);
+ FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
+ /* double protection */
+ if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
+ return false;
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+ decoder->private_->metadata_filter[type] = true;
+ if(type == FLAC__METADATA_TYPE_APPLICATION)
+ decoder->private_->metadata_filter_ids_count = 0;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->protected_);
+ FLAC__ASSERT(0 != id);
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+
+ if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+ return true;
+
+ FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);
+
+ if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+ if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ decoder->private_->metadata_filter_ids_capacity *= 2;
+ }
+
+ memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+ decoder->private_->metadata_filter_ids_count++;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder)
+{
+ unsigned i;
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->protected_);
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+ for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++)
+ decoder->private_->metadata_filter[i] = true;
+ decoder->private_->metadata_filter_ids_count = 0;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->protected_);
+ FLAC__ASSERT((unsigned)type <= FLAC__MAX_METADATA_TYPE_CODE);
+ /* double protection */
+ if((unsigned)type > FLAC__MAX_METADATA_TYPE_CODE)
+ return false;
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+ decoder->private_->metadata_filter[type] = false;
+ if(type == FLAC__METADATA_TYPE_APPLICATION)
+ decoder->private_->metadata_filter_ids_count = 0;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4])
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->protected_);
+ FLAC__ASSERT(0 != id);
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+
+ if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION])
+ return true;
+
+ FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids);
+
+ if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) {
+ if(0 == (decoder->private_->metadata_filter_ids = (FLAC__byte*)realloc(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity * 2))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ decoder->private_->metadata_filter_ids_capacity *= 2;
+ }
+
+ memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+ decoder->private_->metadata_filter_ids_count++;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->protected_);
+ if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED)
+ return false;
+ memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+ decoder->private_->metadata_filter_ids_count = 0;
+ return true;
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+ return decoder->protected_->state;
+}
+
+FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder)
+{
+ return FLAC__StreamDecoderStateString[decoder->protected_->state];
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+ return decoder->protected_->md5_checking;
+}
+
+FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+ return decoder->private_->has_stream_info? decoder->private_->stream_info.data.stream_info.total_samples : 0;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+ return decoder->protected_->channels;
+}
+
+FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+ return decoder->protected_->channel_assignment;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+ return decoder->protected_->bits_per_sample;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+ return decoder->protected_->sample_rate;
+}
+
+FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+ return decoder->protected_->blocksize;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != position);
+
+#if FLAC__HAS_OGG
+ if(decoder->private_->is_ogg)
+ return false;
+#endif
+ if(0 == decoder->private_->tell_callback)
+ return false;
+ if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__STREAM_DECODER_TELL_STATUS_OK)
+ return false;
+ /* should never happen since all FLAC frames and metadata blocks are byte aligned, but check just in case */
+ if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input))
+ return false;
+ FLAC__ASSERT(*position >= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder));
+ *position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder);
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->protected_);
+
+ decoder->private_->samples_decoded = 0;
+ decoder->private_->do_md5_checking = false;
+
+#if FLAC__HAS_OGG
+ if(decoder->private_->is_ogg)
+ FLAC__ogg_decoder_aspect_flush(&decoder->protected_->ogg_decoder_aspect);
+#endif
+
+ if(!FLAC__bitreader_clear(decoder->private_->input)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ decoder->private_->last_frame_number = 0;
+ decoder->private_->last_block_size = 0;
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+ FLAC__ASSERT(0 != decoder->protected_);
+
+ if(!FLAC__stream_decoder_flush(decoder)) {
+ /* above call sets the state for us */
+ return false;
+ }
+
+#if FLAC__HAS_OGG
+ /*@@@ could go in !internal_reset_hack block below */
+ if(decoder->private_->is_ogg)
+ FLAC__ogg_decoder_aspect_reset(&decoder->protected_->ogg_decoder_aspect);
+#endif
+
+ /* Rewind if necessary. If FLAC__stream_decoder_init() is calling us,
+ * (internal_reset_hack) don't try to rewind since we are already at
+ * the beginning of the stream and don't want to fail if the input is
+ * not seekable.
+ */
+ if(!decoder->private_->internal_reset_hack) {
+ if(decoder->private_->file == stdin)
+ return false; /* can't rewind stdin, reset fails */
+ if(decoder->private_->seek_callback && decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR)
+ return false; /* seekable and seek fails, reset fails */
+ }
+ else
+ decoder->private_->internal_reset_hack = false;
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA;
+
+ decoder->private_->has_stream_info = false;
+ if(decoder->private_->has_seek_table && 0 != decoder->private_->seek_table.data.seek_table.points) {
+ free(decoder->private_->seek_table.data.seek_table.points);
+ decoder->private_->seek_table.data.seek_table.points = 0;
+ decoder->private_->has_seek_table = false;
+ }
+ decoder->private_->do_md5_checking = decoder->protected_->md5_checking;
+
+ /* We initialize the FLAC__MD5Context even though we may never use it. This
+ * is because md5 checking may be turned on to start and then turned off if
+ * a seek occurs. So we init the context here and finalize it in
+ * FLAC__stream_decoder_finish() to make sure things are always cleaned up
+ * properly.
+ */
+ FLAC__MD5Init(&decoder->private_->md5context);
+
+ decoder->private_->first_frame_offset = 0;
+ decoder->private_->unparseable_frame_count = 0;
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder)
+{
+ FLAC__bool got_a_frame;
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+
+ while(1) {
+ switch(decoder->protected_->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ if(!find_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ if(!read_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ else
+ return true;
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ if(!frame_sync_(decoder))
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true))
+ return false; /* above function sets the status for us */
+ if(got_a_frame)
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ case FLAC__STREAM_DECODER_ABORTED:
+ return true;
+ default:
+ FLAC__ASSERT(0);
+ return false;
+ }
+ }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+
+ while(1) {
+ switch(decoder->protected_->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ if(!find_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ if(!read_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ case FLAC__STREAM_DECODER_ABORTED:
+ return true;
+ default:
+ FLAC__ASSERT(0);
+ return false;
+ }
+ }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder)
+{
+ FLAC__bool dummy;
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+
+ while(1) {
+ switch(decoder->protected_->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ if(!find_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ if(!read_metadata_(decoder))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ if(!frame_sync_(decoder))
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true))
+ return false; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ case FLAC__STREAM_DECODER_ABORTED:
+ return true;
+ default:
+ FLAC__ASSERT(0);
+ return false;
+ }
+ }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder)
+{
+ FLAC__bool got_a_frame;
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->protected_);
+
+ while(1) {
+ switch(decoder->protected_->state) {
+ case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA:
+ case FLAC__STREAM_DECODER_READ_METADATA:
+ return false; /* above function sets the status for us */
+ case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC:
+ if(!frame_sync_(decoder))
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_READ_FRAME:
+ if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false))
+ return false; /* above function sets the status for us */
+ if(got_a_frame)
+ return true; /* above function sets the status for us */
+ break;
+ case FLAC__STREAM_DECODER_END_OF_STREAM:
+ case FLAC__STREAM_DECODER_ABORTED:
+ return true;
+ default:
+ FLAC__ASSERT(0);
+ return false;
+ }
+ }
+}
+
+FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample)
+{
+ FLAC__uint64 length;
+
+ FLAC__ASSERT(0 != decoder);
+
+ if(
+ decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA &&
+ decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA &&
+ decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC &&
+ decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME &&
+ decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM
+ )
+ return false;
+
+ if(0 == decoder->private_->seek_callback)
+ return false;
+
+ FLAC__ASSERT(decoder->private_->seek_callback);
+ FLAC__ASSERT(decoder->private_->tell_callback);
+ FLAC__ASSERT(decoder->private_->length_callback);
+ FLAC__ASSERT(decoder->private_->eof_callback);
+
+ if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder))
+ return false;
+
+ decoder->private_->is_seeking = true;
+
+ /* turn off md5 checking if a seek is attempted */
+ decoder->private_->do_md5_checking = false;
+
+ /* get the file length (currently our algorithm needs to know the length so it's also an error to get FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED) */
+ if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) {
+ decoder->private_->is_seeking = false;
+ return false;
+ }
+
+ /* if we haven't finished processing the metadata yet, do that so we have the STREAMINFO, SEEK_TABLE, and first_frame_offset */
+ if(
+ decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA ||
+ decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA
+ ) {
+ if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) {
+ /* above call sets the state for us */
+ decoder->private_->is_seeking = false;
+ return false;
+ }
+ /* check this again in case we didn't know total_samples the first time */
+ if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) {
+ decoder->private_->is_seeking = false;
+ return false;
+ }
+ }
+
+ {
+ const FLAC__bool ok =
+#if FLAC__HAS_OGG
+ decoder->private_->is_ogg?
+ seek_to_absolute_sample_ogg_(decoder, length, sample) :
+#endif
+ seek_to_absolute_sample_(decoder, length, sample)
+ ;
+ decoder->private_->is_seeking = false;
+ return ok;
+ }
+}
+
+/***********************************************************************
+ *
+ * Protected class methods
+ *
+ ***********************************************************************/
+
+unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder)
+{
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+ FLAC__ASSERT(!(FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) & 7));
+ return FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) / 8;
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__StreamDecoder *decoder)
+{
+#if FLAC__HAS_OGG
+ decoder->private_->is_ogg = false;
+#endif
+ decoder->private_->read_callback = 0;
+ decoder->private_->seek_callback = 0;
+ decoder->private_->tell_callback = 0;
+ decoder->private_->length_callback = 0;
+ decoder->private_->eof_callback = 0;
+ decoder->private_->write_callback = 0;
+ decoder->private_->metadata_callback = 0;
+ decoder->private_->error_callback = 0;
+ decoder->private_->client_data = 0;
+
+ memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter));
+ decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true;
+ decoder->private_->metadata_filter_ids_count = 0;
+
+ decoder->protected_->md5_checking = false;
+
+#if FLAC__HAS_OGG
+ FLAC__ogg_decoder_aspect_set_defaults(&decoder->protected_->ogg_decoder_aspect);
+#endif
+}
+
+/*
+ * This will forcibly set stdin to binary mode (for OSes that require it)
+ */
+FILE *get_binary_stdin_(void)
+{
+ /* if something breaks here it is probably due to the presence or
+ * absence of an underscore before the identifiers 'setmode',
+ * 'fileno', and/or 'O_BINARY'; check your system header files.
+ */
+#if defined _MSC_VER || defined __MINGW32__
+ _setmode(_fileno(stdin), _O_BINARY);
+#elif defined __CYGWIN__ || defined __EMX__
+ /* almost certainly not needed for any modern Cygwin, but let's be safe... */
+ setmode(_fileno(stdin), _O_BINARY);
+#endif
+
+ return stdin;
+}
+
+FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, unsigned size, unsigned channels)
+{
+ unsigned i;
+ FLAC__int32 *tmp;
+
+ if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels)
+ return true;
+
+ /* simply using realloc() is not practical because the number of channels may change mid-stream */
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ if(0 != decoder->private_->output[i]) {
+ free(decoder->private_->output[i]-4);
+ decoder->private_->output[i] = 0;
+ }
+ if(0 != decoder->private_->residual_unaligned[i]) {
+ free(decoder->private_->residual_unaligned[i]);
+ decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0;
+ }
+ }
+
+ for(i = 0; i < channels; i++) {
+ /* WATCHOUT:
+ * FLAC__lpc_restore_signal_asm_ia32_mmx() requires that the
+ * output arrays have a buffer of up to 3 zeroes in front
+ * (at negative indices) for alignment purposes; we use 4
+ * to keep the data well-aligned.
+ */
+ tmp = (FLAC__int32*)malloc(sizeof(FLAC__int32)*(size+4));
+ if(tmp == 0) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ memset(tmp, 0, sizeof(FLAC__int32)*4);
+ decoder->private_->output[i] = tmp + 4;
+
+ /* WATCHOUT:
+ * minimum of quadword alignment for PPC vector optimizations is REQUIRED:
+ */
+ if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ }
+
+ decoder->private_->output_capacity = size;
+ decoder->private_->output_channels = channels;
+
+ return true;
+}
+
+FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id)
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != decoder);
+ FLAC__ASSERT(0 != decoder->private_);
+
+ for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++)
+ if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)))
+ return true;
+
+ return false;
+}
+
+FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder)
+{
+ FLAC__uint32 x;
+ unsigned i, id;
+ FLAC__bool first = true;
+
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+ for(i = id = 0; i < 4; ) {
+ if(decoder->private_->cached) {
+ x = (FLAC__uint32)decoder->private_->lookahead;
+ decoder->private_->cached = false;
+ }
+ else {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ }
+ if(x == FLAC__STREAM_SYNC_STRING[i]) {
+ first = true;
+ i++;
+ id = 0;
+ continue;
+ }
+ if(x == ID3V2_TAG_[id]) {
+ id++;
+ i = 0;
+ if(id == 3) {
+ if(!skip_id3v2_tag_(decoder))
+ return false; /* skip_id3v2_tag_ sets the state for us */
+ }
+ continue;
+ }
+ id = 0;
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ decoder->private_->header_warmup[0] = (FLAC__byte)x;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+
+ /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
+ /* else we have to check if the second byte is the end of a sync code */
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ decoder->private_->lookahead = (FLAC__byte)x;
+ decoder->private_->cached = true;
+ }
+ else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
+ decoder->private_->header_warmup[1] = (FLAC__byte)x;
+ decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+ return true;
+ }
+ }
+ i = 0;
+ if(first) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ first = false;
+ }
+ }
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA;
+ return true;
+}
+
+FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder)
+{
+ FLAC__bool is_last;
+ FLAC__uint32 i, x, type, length;
+
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN))
+ return false; /* read_callback_ sets the state for us */
+ is_last = x? true : false;
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(type == FLAC__METADATA_TYPE_STREAMINFO) {
+ if(!read_metadata_streaminfo_(decoder, is_last, length))
+ return false;
+
+ decoder->private_->has_stream_info = true;
+ if(0 == memcmp(decoder->private_->stream_info.data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
+ decoder->private_->do_md5_checking = false;
+ if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] && decoder->private_->metadata_callback)
+ decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data);
+ }
+ else if(type == FLAC__METADATA_TYPE_SEEKTABLE) {
+ if(!read_metadata_seektable_(decoder, is_last, length))
+ return false;
+
+ decoder->private_->has_seek_table = true;
+ if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE] && decoder->private_->metadata_callback)
+ decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data);
+ }
+ else {
+ FLAC__bool skip_it = !decoder->private_->metadata_filter[type];
+ unsigned real_length = length;
+ FLAC__StreamMetadata block;
+
+ block.is_last = is_last;
+ block.type = (FLAC__MetadataType)type;
+ block.length = length;
+
+ if(type == FLAC__METADATA_TYPE_APPLICATION) {
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))
+ return false; /* read_callback_ sets the state for us */
+
+ real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8;
+
+ if(decoder->private_->metadata_filter_ids_count > 0 && has_id_filtered_(decoder, block.data.application.id))
+ skip_it = !skip_it;
+ }
+
+ if(skip_it) {
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length))
+ return false; /* read_callback_ sets the state for us */
+ }
+ else {
+ switch(type) {
+ case FLAC__METADATA_TYPE_PADDING:
+ /* skip the padding bytes */
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length))
+ return false; /* read_callback_ sets the state for us */
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ /* remember, we read the ID already */
+ if(real_length > 0) {
+ if(0 == (block.data.application.data = (FLAC__byte*)malloc(real_length))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length))
+ return false; /* read_callback_ sets the state for us */
+ }
+ else
+ block.data.application.data = 0;
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment))
+ return false;
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet))
+ return false;
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ if(!read_metadata_picture_(decoder, &block.data.picture))
+ return false;
+ break;
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ FLAC__ASSERT(0);
+ break;
+ default:
+ if(real_length > 0) {
+ if(0 == (block.data.unknown.data = (FLAC__byte*)malloc(real_length))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length))
+ return false; /* read_callback_ sets the state for us */
+ }
+ else
+ block.data.unknown.data = 0;
+ break;
+ }
+ if(!decoder->private_->is_seeking && decoder->private_->metadata_callback)
+ decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data);
+
+ /* now we have to free any malloc'ed data in the block */
+ switch(type) {
+ case FLAC__METADATA_TYPE_PADDING:
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ if(0 != block.data.application.data)
+ free(block.data.application.data);
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ if(0 != block.data.vorbis_comment.vendor_string.entry)
+ free(block.data.vorbis_comment.vendor_string.entry);
+ if(block.data.vorbis_comment.num_comments > 0)
+ for(i = 0; i < block.data.vorbis_comment.num_comments; i++)
+ if(0 != block.data.vorbis_comment.comments[i].entry)
+ free(block.data.vorbis_comment.comments[i].entry);
+ if(0 != block.data.vorbis_comment.comments)
+ free(block.data.vorbis_comment.comments);
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ if(block.data.cue_sheet.num_tracks > 0)
+ for(i = 0; i < block.data.cue_sheet.num_tracks; i++)
+ if(0 != block.data.cue_sheet.tracks[i].indices)
+ free(block.data.cue_sheet.tracks[i].indices);
+ if(0 != block.data.cue_sheet.tracks)
+ free(block.data.cue_sheet.tracks);
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ if(0 != block.data.picture.mime_type)
+ free(block.data.picture.mime_type);
+ if(0 != block.data.picture.description)
+ free(block.data.picture.description);
+ if(0 != block.data.picture.data)
+ free(block.data.picture.data);
+ break;
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ FLAC__ASSERT(0);
+ default:
+ if(0 != block.data.unknown.data)
+ free(block.data.unknown.data);
+ break;
+ }
+ }
+ }
+
+ if(is_last) {
+ /* if this fails, it's OK, it's just a hint for the seek routine */
+ if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->first_frame_offset))
+ decoder->private_->first_frame_offset = 0;
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ }
+
+ return true;
+}
+
+FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length)
+{
+ FLAC__uint32 x;
+ unsigned bits, used_bits = 0;
+
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+ decoder->private_->stream_info.type = FLAC__METADATA_TYPE_STREAMINFO;
+ decoder->private_->stream_info.is_last = is_last;
+ decoder->private_->stream_info.length = length;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, bits))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.min_blocksize = x;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.max_blocksize = x;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.min_framesize = x;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.max_framesize = x;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.sample_rate = x;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.channels = x+1;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->stream_info.data.stream_info.bits_per_sample = x+1;
+ used_bits += bits;
+
+ bits = FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN;
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
+ return false; /* read_callback_ sets the state for us */
+ used_bits += bits;
+
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16))
+ return false; /* read_callback_ sets the state for us */
+ used_bits += 16*8;
+
+ /* skip the rest of the block */
+ FLAC__ASSERT(used_bits % 8 == 0);
+ length -= (used_bits / 8);
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+ return false; /* read_callback_ sets the state for us */
+
+ return true;
+}
+
+FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, unsigned length)
+{
+ FLAC__uint32 i, x;
+ FLAC__uint64 xx;
+
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+ decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE;
+ decoder->private_->seek_table.is_last = is_last;
+ decoder->private_->seek_table.length = length;
+
+ decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+ /* use realloc since we may pass through here several times (e.g. after seeking) */
+ if(0 == (decoder->private_->seek_table.data.seek_table.points = (FLAC__StreamMetadata_SeekPoint*)realloc(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint)))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ for(i = 0; i < decoder->private_->seek_table.data.seek_table.num_points; i++) {
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->seek_table.data.seek_table.points[i].sample_number = xx;
+
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->seek_table.data.seek_table.points[i].stream_offset = xx;
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->seek_table.data.seek_table.points[i].frame_samples = x;
+ }
+ length -= (decoder->private_->seek_table.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH);
+ /* if there is a partial point left, skip over it */
+ if(length > 0) {
+ /*@@@ do a send_error_to_client_() here? there's an argument for either way */
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length))
+ return false; /* read_callback_ sets the state for us */
+ }
+
+ return true;
+}
+
+FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj)
+{
+ FLAC__uint32 i;
+
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+ /* read vendor string */
+ FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
+ if(!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length))
+ return false; /* read_callback_ sets the state for us */
+ if(obj->vendor_string.length > 0) {
+ if(0 == (obj->vendor_string.entry = (FLAC__byte*)malloc(obj->vendor_string.length+1))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length))
+ return false; /* read_callback_ sets the state for us */
+ obj->vendor_string.entry[obj->vendor_string.length] = '\0';
+ }
+ else
+ obj->vendor_string.entry = 0;
+
+ /* read num comments */
+ FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32);
+ if(!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments))
+ return false; /* read_callback_ sets the state for us */
+
+ /* read comments */
+ if(obj->num_comments > 0) {
+ if(0 == (obj->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)malloc(obj->num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ for(i = 0; i < obj->num_comments; i++) {
+ FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32);
+ if(!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length))
+ return false; /* read_callback_ sets the state for us */
+ if(obj->comments[i].length > 0) {
+ if(0 == (obj->comments[i].entry = (FLAC__byte*)malloc(obj->comments[i].length+1))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length))
+ return false; /* read_callback_ sets the state for us */
+ obj->comments[i].entry[obj->comments[i].length] = '\0';
+ }
+ else
+ obj->comments[i].entry = 0;
+ }
+ }
+ else {
+ obj->comments = 0;
+ }
+
+ return true;
+}
+
+FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj)
+{
+ FLAC__uint32 i, j, x;
+
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+ memset(obj, 0, sizeof(FLAC__StreamMetadata_CueSheet));
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN))
+ return false; /* read_callback_ sets the state for us */
+ obj->is_cd = x? true : false;
+
+ if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN))
+ return false; /* read_callback_ sets the state for us */
+ obj->num_tracks = x;
+
+ if(obj->num_tracks > 0) {
+ if(0 == (obj->tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc(obj->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ for(i = 0; i < obj->num_tracks; i++) {
+ FLAC__StreamMetadata_CueSheet_Track *track = &obj->tracks[i];
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ track->number = (FLAC__byte)x;
+
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ track->type = x;
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
+ return false; /* read_callback_ sets the state for us */
+ track->pre_emphasis = x;
+
+ if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN))
+ return false; /* read_callback_ sets the state for us */
+ track->num_indices = (FLAC__byte)x;
+
+ if(track->num_indices > 0) {
+ if(0 == (track->indices = (FLAC__StreamMetadata_CueSheet_Index*)calloc(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ for(j = 0; j < track->num_indices; j++) {
+ FLAC__StreamMetadata_CueSheet_Index *index = &track->indices[j];
+ if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ index->number = (FLAC__byte)x;
+
+ if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
+ return false; /* read_callback_ sets the state for us */
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj)
+{
+ FLAC__uint32 x;
+
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+ /* read type */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ obj->type = x;
+
+ /* read MIME type */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(0 == (obj->mime_type = (char*)malloc(x+1))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(x > 0) {
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, x))
+ return false; /* read_callback_ sets the state for us */
+ }
+ obj->mime_type[x] = '\0';
+
+ /* read description */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(0 == (obj->description = (FLAC__byte*)malloc(x+1))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(x > 0) {
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, x))
+ return false; /* read_callback_ sets the state for us */
+ }
+ obj->description[x] = '\0';
+
+ /* read width */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ /* read height */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ /* read depth */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ /* read colors */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN))
+ return false; /* read_callback_ sets the state for us */
+
+ /* read data */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(0 == (obj->data = (FLAC__byte*)malloc(obj->data_length))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+ if(obj->data_length > 0) {
+ if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length))
+ return false; /* read_callback_ sets the state for us */
+ }
+
+ return true;
+}
+
+FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder)
+{
+ FLAC__uint32 x;
+ unsigned i, skip;
+
+ /* skip the version and flags bytes */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 24))
+ return false; /* read_callback_ sets the state for us */
+ /* get the size (in bytes) to skip */
+ skip = 0;
+ for(i = 0; i < 4; i++) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ skip <<= 7;
+ skip |= (x & 0x7f);
+ }
+ /* skip the rest of the tag */
+ if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip))
+ return false; /* read_callback_ sets the state for us */
+ return true;
+}
+
+FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder)
+{
+ FLAC__uint32 x;
+ FLAC__bool first = true;
+
+ /* If we know the total number of samples in the stream, stop if we've read that many. */
+ /* This will stop us, for example, from wasting time trying to sync on an ID3V1 tag. */
+ if(FLAC__stream_decoder_get_total_samples(decoder) > 0) {
+ if(decoder->private_->samples_decoded >= FLAC__stream_decoder_get_total_samples(decoder)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+ return true;
+ }
+ }
+
+ /* make sure we're byte aligned */
+ if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input)))
+ return false; /* read_callback_ sets the state for us */
+ }
+
+ while(1) {
+ if(decoder->private_->cached) {
+ x = (FLAC__uint32)decoder->private_->lookahead;
+ decoder->private_->cached = false;
+ }
+ else {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ }
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ decoder->private_->header_warmup[0] = (FLAC__byte)x;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+
+ /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */
+ /* else we have to check if the second byte is the end of a sync code */
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ decoder->private_->lookahead = (FLAC__byte)x;
+ decoder->private_->cached = true;
+ }
+ else if(x >> 2 == 0x3e) { /* MAGIC NUMBER for the last 6 sync bits */
+ decoder->private_->header_warmup[1] = (FLAC__byte)x;
+ decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME;
+ return true;
+ }
+ }
+ if(first) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ first = false;
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode)
+{
+ unsigned channel;
+ unsigned i;
+ FLAC__int32 mid, side;
+ unsigned frame_crc; /* the one we calculate from the input stream */
+ FLAC__uint32 x;
+
+ *got_a_frame = false;
+
+ /* init the CRC */
+ frame_crc = 0;
+ frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc);
+ frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc);
+ FLAC__bitreader_reset_read_crc16(decoder->private_->input, (FLAC__uint16)frame_crc);
+
+ if(!read_frame_header_(decoder))
+ return false;
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means we didn't sync on a valid header */
+ return true;
+ if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels))
+ return false;
+ for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+ /*
+ * first figure the correct bits-per-sample of the subframe
+ */
+ unsigned bps = decoder->private_->frame.header.bits_per_sample;
+ switch(decoder->private_->frame.header.channel_assignment) {
+ case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+ /* no adjustment needed */
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+ if(channel == 1)
+ bps++;
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+ if(channel == 0)
+ bps++;
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+ FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+ if(channel == 1)
+ bps++;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+ /*
+ * now read it
+ */
+ if(!read_subframe_(decoder, channel, bps, do_full_decode))
+ return false;
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+ return true;
+ }
+ if(!read_zero_padding_(decoder))
+ return false;
+
+ /*
+ * Read the frame CRC-16 from the footer and check
+ */
+ frame_crc = FLAC__bitreader_get_read_crc16(decoder->private_->input);
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(frame_crc == x) {
+ if(do_full_decode) {
+ /* Undo any special channel coding */
+ switch(decoder->private_->frame.header.channel_assignment) {
+ case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+ /* do nothing */
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ decoder->private_->output[0][i] += decoder->private_->output[1][i];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+ FLAC__ASSERT(decoder->private_->frame.header.channels == 2);
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+#if 1
+ mid = decoder->private_->output[0][i];
+ side = decoder->private_->output[1][i];
+ mid <<= 1;
+ mid |= (side & 1); /* i.e. if 'side' is odd... */
+ decoder->private_->output[0][i] = (mid + side) >> 1;
+ decoder->private_->output[1][i] = (mid - side) >> 1;
+#else
+ //@@@@@@ OPT: try without 'side' temp variable
+ mid = (decoder->private_->output[0][i] << 1) | (decoder->private_->output[1][i] & 1); /* i.e. if 'side' is odd... */
+ decoder->private_->output[0][i] = (mid + decoder->private_->output[1][i]) >> 1;
+ decoder->private_->output[1][i] = (mid - decoder->private_->output[1][i]) >> 1;
+#endif
+ }
+ break;
+ default:
+ FLAC__ASSERT(0);
+ break;
+ }
+ }
+ }
+ else {
+ /* Bad frame, emit error and zero the output signal */
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH);
+ if(do_full_decode) {
+ for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) {
+ memset(decoder->private_->output[channel], 0, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+ }
+ }
+ }
+
+ *got_a_frame = true;
+
+ /* put the latest values into the public section of the decoder instance */
+ decoder->protected_->channels = decoder->private_->frame.header.channels;
+ decoder->protected_->channel_assignment = decoder->private_->frame.header.channel_assignment;
+ decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample;
+ decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate;
+ decoder->protected_->blocksize = decoder->private_->frame.header.blocksize;
+
+ FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+ decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize;
+
+ /* write it */
+ if(do_full_decode) {
+ if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE)
+ return false;
+ }
+
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+}
+
+FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder)
+{
+ FLAC__uint32 x;
+ FLAC__uint64 xx;
+ unsigned i, blocksize_hint = 0, sample_rate_hint = 0;
+ FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */
+ unsigned raw_header_len;
+ FLAC__bool is_unparseable = false;
+ const FLAC__bool is_known_variable_blocksize_stream = (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize);
+ const FLAC__bool is_known_fixed_blocksize_stream = (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize);
+
+ FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input));
+
+ /* init the raw header with the saved bits from synchronization */
+ raw_header[0] = decoder->private_->header_warmup[0];
+ raw_header[1] = decoder->private_->header_warmup[1];
+ raw_header_len = 2;
+
+ /*
+ * check to make sure that the reserved bits are 0
+ */
+ if(raw_header[1] & 0x03) { /* MAGIC NUMBER */
+ is_unparseable = true;
+ }
+
+ /*
+ * Note that along the way as we read the header, we look for a sync
+ * code inside. If we find one it would indicate that our original
+ * sync was bad since there cannot be a sync code in a valid header.
+ *
+ * Three kinds of things can go wrong when reading the frame header:
+ * 1) We may have sync'ed incorrectly and not landed on a frame header.
+ * If we don't find a sync code, it can end up looking like we read
+ * a valid but unparseable header, until getting to the frame header
+ * CRC. Even then we could get a false positive on the CRC.
+ * 2) We may have sync'ed correctly but on an unparseable frame (from a
+ * future encoder).
+ * 3) We may be on a damaged frame which appears valid but unparseable.
+ *
+ * For all these reasons, we try and read a complete frame header as
+ * long as it seems valid, even if unparseable, up until the frame
+ * header CRC.
+ */
+
+ /*
+ * read in the raw header as bytes so we can CRC it, and parse it on the way
+ */
+ for(i = 0; i < 2; i++) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */
+ /* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */
+ decoder->private_->lookahead = (FLAC__byte)x;
+ decoder->private_->cached = true;
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ raw_header[raw_header_len++] = (FLAC__byte)x;
+ }
+
+ switch(x = raw_header[2] >> 4) {
+ case 0:
+ if(is_known_fixed_blocksize_stream)
+ decoder->private_->frame.header.blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize;
+ else
+ is_unparseable = true;
+ break;
+ case 1:
+ decoder->private_->frame.header.blocksize = 192;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ decoder->private_->frame.header.blocksize = 576 << (x-2);
+ break;
+ case 6:
+ case 7:
+ blocksize_hint = x;
+ break;
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ decoder->private_->frame.header.blocksize = 256 << (x-8);
+ break;
+ default:
+ FLAC__ASSERT(0);
+ break;
+ }
+
+ switch(x = raw_header[2] & 0x0f) {
+ case 0:
+ if(decoder->private_->has_stream_info)
+ decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate;
+ else
+ is_unparseable = true;
+ break;
+ case 1:
+ case 2:
+ case 3:
+ is_unparseable = true;
+ break;
+ case 4:
+ decoder->private_->frame.header.sample_rate = 8000;
+ break;
+ case 5:
+ decoder->private_->frame.header.sample_rate = 16000;
+ break;
+ case 6:
+ decoder->private_->frame.header.sample_rate = 22050;
+ break;
+ case 7:
+ decoder->private_->frame.header.sample_rate = 24000;
+ break;
+ case 8:
+ decoder->private_->frame.header.sample_rate = 32000;
+ break;
+ case 9:
+ decoder->private_->frame.header.sample_rate = 44100;
+ break;
+ case 10:
+ decoder->private_->frame.header.sample_rate = 48000;
+ break;
+ case 11:
+ decoder->private_->frame.header.sample_rate = 96000;
+ break;
+ case 12:
+ case 13:
+ case 14:
+ sample_rate_hint = x;
+ break;
+ case 15:
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ default:
+ FLAC__ASSERT(0);
+ }
+
+ x = (unsigned)(raw_header[3] >> 4);
+ if(x & 8) {
+ decoder->private_->frame.header.channels = 2;
+ switch(x & 7) {
+ case 0:
+ decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE;
+ break;
+ case 1:
+ decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE;
+ break;
+ case 2:
+ decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE;
+ break;
+ default:
+ is_unparseable = true;
+ break;
+ }
+ }
+ else {
+ decoder->private_->frame.header.channels = (unsigned)x + 1;
+ decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+ }
+
+ switch(x = (unsigned)(raw_header[3] & 0x0e) >> 1) {
+ case 0:
+ if(decoder->private_->has_stream_info)
+ decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+ else
+ is_unparseable = true;
+ break;
+ case 1:
+ decoder->private_->frame.header.bits_per_sample = 8;
+ break;
+ case 2:
+ decoder->private_->frame.header.bits_per_sample = 12;
+ break;
+ case 4:
+ decoder->private_->frame.header.bits_per_sample = 16;
+ break;
+ case 5:
+ decoder->private_->frame.header.bits_per_sample = 20;
+ break;
+ case 6:
+ decoder->private_->frame.header.bits_per_sample = 24;
+ break;
+ case 3:
+ case 7:
+ is_unparseable = true;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ break;
+ }
+
+ if(raw_header[3] & 0x01) { /* this should be a zero padding bit */
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ /*
+ * Now we get to the regrettable consequences of not knowing for sure
+ * whether we got a frame number or a sample number. There are no
+ * encoders that do variable-blocksize encoding so unless we know from
+ * the STREAMINFO that it is variable-blocksize we will assume it is
+ * fixed-blocksize. The trouble comes when we have no STREAMINFO; again
+ * we will guess that is fixed-blocksize. Where this can go wrong: 1) a
+ * variable-blocksize stream with no STREAMINFO; 2) a fixed-blocksize
+ * stream that was edited such that one or more frames before or
+ * including this one do not have the same number of samples as the
+ * STREAMINFO's min and max blocksize.
+ */
+ if(is_known_variable_blocksize_stream) {
+ if(blocksize_hint) {
+ if(!FLAC__bitreader_read_utf8_uint64(decoder->private_->input, &xx, raw_header, &raw_header_len))
+ return false; /* read_callback_ sets the state for us */
+ if(xx == FLAC__U64L(0xffffffffffffffff)) { /* i.e. non-UTF8 code... */
+ decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */
+ decoder->private_->cached = true;
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+ decoder->private_->frame.header.number.sample_number = xx;
+ }
+ else
+ is_unparseable = true;
+ }
+ else {
+ if(!FLAC__bitreader_read_utf8_uint32(decoder->private_->input, &x, raw_header, &raw_header_len))
+ return false; /* read_callback_ sets the state for us */
+ if(x == 0xffffffff) { /* i.e. non-UTF8 code... */
+ decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */
+ decoder->private_->cached = true;
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ decoder->private_->last_frame_number = x;
+ decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER;
+ if(decoder->private_->has_stream_info) {
+ FLAC__ASSERT(decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize);
+ decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__uint64)x;
+ decoder->private_->last_block_size = decoder->private_->frame.header.blocksize;
+ }
+ else if(blocksize_hint) {
+ if(decoder->private_->last_block_size)
+ decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->last_block_size * (FLAC__uint64)x;
+ else
+ is_unparseable = true;
+ }
+ else {
+ decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->frame.header.blocksize * (FLAC__uint64)x;
+ decoder->private_->last_block_size = decoder->private_->frame.header.blocksize;
+ }
+ }
+
+ if(blocksize_hint) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (FLAC__byte)x;
+ if(blocksize_hint == 7) {
+ FLAC__uint32 _x;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8))
+ return false; /* read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (FLAC__byte)_x;
+ x = (x << 8) | _x;
+ }
+ decoder->private_->frame.header.blocksize = x+1;
+ }
+
+ if(sample_rate_hint) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (FLAC__byte)x;
+ if(sample_rate_hint != 12) {
+ FLAC__uint32 _x;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8))
+ return false; /* read_callback_ sets the state for us */
+ raw_header[raw_header_len++] = (FLAC__byte)_x;
+ x = (x << 8) | _x;
+ }
+ if(sample_rate_hint == 12)
+ decoder->private_->frame.header.sample_rate = x*1000;
+ else if(sample_rate_hint == 13)
+ decoder->private_->frame.header.sample_rate = x;
+ else
+ decoder->private_->frame.header.sample_rate = x*10;
+ }
+
+ /* read the CRC-8 byte */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8))
+ return false; /* read_callback_ sets the state for us */
+ crc8 = (FLAC__byte)x;
+
+ if(FLAC__crc8(raw_header, raw_header_len) != crc8) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ if(is_unparseable) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
+{
+ FLAC__uint32 x;
+ FLAC__bool wasted_bits;
+ unsigned i;
+
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) /* MAGIC NUMBER */
+ return false; /* read_callback_ sets the state for us */
+
+ wasted_bits = (x & 1);
+ x &= 0xfe;
+
+ if(wasted_bits) {
+ unsigned u;
+ if(!FLAC__bitreader_read_unary_unsigned(decoder->private_->input, &u))
+ return false; /* read_callback_ sets the state for us */
+ decoder->private_->frame.subframes[channel].wasted_bits = u+1;
+ bps -= decoder->private_->frame.subframes[channel].wasted_bits;
+ }
+ else
+ decoder->private_->frame.subframes[channel].wasted_bits = 0;
+
+ /*
+ * Lots of magic numbers here
+ */
+ if(x & 0x80) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ else if(x == 0) {
+ if(!read_subframe_constant_(decoder, channel, bps, do_full_decode))
+ return false;
+ }
+ else if(x == 2) {
+ if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode))
+ return false;
+ }
+ else if(x < 16) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ else if(x <= 24) {
+ if(!read_subframe_fixed_(decoder, channel, bps, (x>>1)&7, do_full_decode))
+ return false;
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+ return true;
+ }
+ else if(x < 64) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ else {
+ if(!read_subframe_lpc_(decoder, channel, bps, ((x>>1)&31)+1, do_full_decode))
+ return false;
+ if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */
+ return true;
+ }
+
+ if(wasted_bits && do_full_decode) {
+ x = decoder->private_->frame.subframes[channel].wasted_bits;
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ decoder->private_->output[channel][i] <<= x;
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant;
+ FLAC__int32 x;
+ unsigned i;
+ FLAC__int32 *output = decoder->private_->output[channel];
+
+ decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT;
+
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+ return false; /* read_callback_ sets the state for us */
+
+ subframe->value = x;
+
+ /* decode the subframe */
+ if(do_full_decode) {
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++)
+ output[i] = x;
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed;
+ FLAC__int32 i32;
+ FLAC__uint32 u32;
+ unsigned u;
+
+ decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED;
+
+ subframe->residual = decoder->private_->residual[channel];
+ subframe->order = order;
+
+ /* read warm-up samples */
+ for(u = 0; u < order; u++) {
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps))
+ return false; /* read_callback_ sets the state for us */
+ subframe->warmup[u] = i32;
+ }
+
+ /* read entropy coding method info */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32;
+ switch(subframe->entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ subframe->entropy_coding_method.data.partitioned_rice.order = u32;
+ subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel];
+ break;
+ default:
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ /* read residual */
+ switch(subframe->entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel]))
+ return false;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+
+ /* decode the subframe */
+ if(do_full_decode) {
+ memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+ FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order);
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, const unsigned order, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc;
+ FLAC__int32 i32;
+ FLAC__uint32 u32;
+ unsigned u;
+
+ decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC;
+
+ subframe->residual = decoder->private_->residual[channel];
+ subframe->order = order;
+
+ /* read warm-up samples */
+ for(u = 0; u < order; u++) {
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, bps))
+ return false; /* read_callback_ sets the state for us */
+ subframe->warmup[u] = i32;
+ }
+
+ /* read qlp coeff precision */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
+ return false; /* read_callback_ sets the state for us */
+ if(u32 == (1u << FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN) - 1) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ subframe->qlp_coeff_precision = u32+1;
+
+ /* read qlp shift */
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN))
+ return false; /* read_callback_ sets the state for us */
+ subframe->quantization_level = i32;
+
+ /* read quantized lp coefficiencts */
+ for(u = 0; u < order; u++) {
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision))
+ return false; /* read_callback_ sets the state for us */
+ subframe->qlp_coeff[u] = i32;
+ }
+
+ /* read entropy coding method info */
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+ return false; /* read_callback_ sets the state for us */
+ subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32;
+ switch(subframe->entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ subframe->entropy_coding_method.data.partitioned_rice.order = u32;
+ subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel];
+ break;
+ default:
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+
+ /* read residual */
+ switch(subframe->entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel]))
+ return false;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+
+ /* decode the subframe */
+ if(do_full_decode) {
+ memcpy(decoder->private_->output[channel], subframe->warmup, sizeof(FLAC__int32) * order);
+ /*@@@@@@ technically not pessimistic enough, should be more like
+ if( (FLAC__uint64)order * ((((FLAC__uint64)1)<<bps)-1) * ((1<<subframe->qlp_coeff_precision)-1) < (((FLAC__uint64)-1) << 32) )
+ */
+ if(bps + subframe->qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+ if(bps <= 16 && subframe->qlp_coeff_precision <= 16) {
+ if(order <= 8)
+ decoder->private_->local_lpc_restore_signal_16bit_order8(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+ else
+ decoder->private_->local_lpc_restore_signal_16bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+ }
+ else
+ decoder->private_->local_lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+ else
+ decoder->private_->local_lpc_restore_signal_64bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order);
+ }
+
+ return true;
+}
+
+FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, unsigned channel, unsigned bps, FLAC__bool do_full_decode)
+{
+ FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim;
+ FLAC__int32 x, *residual = decoder->private_->residual[channel];
+ unsigned i;
+
+ decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+ subframe->data = residual;
+
+ for(i = 0; i < decoder->private_->frame.header.blocksize; i++) {
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps))
+ return false; /* read_callback_ sets the state for us */
+ residual[i] = x;
+ }
+
+ /* decode the subframe */
+ if(do_full_decode)
+ memcpy(decoder->private_->output[channel], subframe->data, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize);
+
+ return true;
+}
+
+FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, unsigned predictor_order, unsigned partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual)
+{
+ FLAC__uint32 rice_parameter;
+ int i;
+ unsigned partition, sample, u;
+ const unsigned partitions = 1u << partition_order;
+ const unsigned partition_samples = partition_order > 0? decoder->private_->frame.header.blocksize >> partition_order : decoder->private_->frame.header.blocksize - predictor_order;
+
+ /* sanity checks */
+ if(partition_order == 0) {
+ if(decoder->private_->frame.header.blocksize < predictor_order) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ }
+ else {
+ if(partition_samples < predictor_order) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ return true;
+ }
+ }
+
+ if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order))) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ sample = 0;
+ for(partition = 0; partition < partitions; partition++) {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN))
+ return false; /* read_callback_ sets the state for us */
+ partitioned_rice_contents->parameters[partition] = rice_parameter;
+ if(rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+ u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order;
+ if(!decoder->private_->local_bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter))
+ return false; /* read_callback_ sets the state for us */
+ sample += u;
+ }
+ else {
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+ return false; /* read_callback_ sets the state for us */
+ partitioned_rice_contents->raw_bits[partition] = rice_parameter;
+ for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) {
+ if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter))
+ return false; /* read_callback_ sets the state for us */
+ residual[sample] = i;
+ }
+ }
+ }
+
+ return true;
+}
+
+FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder)
+{
+ if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) {
+ FLAC__uint32 zero = 0;
+ if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input)))
+ return false; /* read_callback_ sets the state for us */
+ if(zero != 0) {
+ send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC);
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC;
+ }
+ }
+ return true;
+}
+
+FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data;
+
+ if(
+#if FLAC__HAS_OGG
+ /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */
+ !decoder->private_->is_ogg &&
+#endif
+ decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data)
+ ) {
+ *bytes = 0;
+ decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+ return false;
+ }
+ else if(*bytes > 0) {
+ /* While seeking, it is possible for our seek to land in the
+ * middle of audio data that looks exactly like a frame header
+ * from a future version of an encoder. When that happens, our
+ * error callback will get an
+ * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM and increment its
+ * unparseable_frame_count. But there is a remote possibility
+ * that it is properly synced at such a "future-codec frame",
+ * so to make sure, we wait to see many "unparseable" errors in
+ * a row before bailing out.
+ */
+ if(decoder->private_->is_seeking && decoder->private_->unparseable_frame_count > 20) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+ return false;
+ }
+ else {
+ const FLAC__StreamDecoderReadStatus status =
+#if FLAC__HAS_OGG
+ decoder->private_->is_ogg?
+ read_callback_ogg_aspect_(decoder, buffer, bytes) :
+#endif
+ decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data)
+ ;
+ if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+ return false;
+ }
+ else if(*bytes == 0) {
+ if(
+ status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM ||
+ (
+#if FLAC__HAS_OGG
+ /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */
+ !decoder->private_->is_ogg &&
+#endif
+ decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data)
+ )
+ ) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM;
+ return false;
+ }
+ else
+ return true;
+ }
+ else
+ return true;
+ }
+ }
+ else {
+ /* abort to avoid a deadlock */
+ decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED;
+ return false;
+ }
+ /* [1] @@@ HACK NOTE: The end-of-stream checking has to be hacked around
+ * for Ogg FLAC. This is because the ogg decoder aspect can lose sync
+ * and at the same time hit the end of the stream (for example, seeking
+ * to a point that is after the beginning of the last Ogg page). There
+ * is no way to report an Ogg sync loss through the callbacks (see note
+ * in read_callback_ogg_aspect_()) so it returns CONTINUE with *bytes==0.
+ * So to keep the decoder from stopping at this point we gate the call
+ * to the eof_callback and let the Ogg decoder aspect set the
+ * end-of-stream state when it is needed.
+ */
+}
+
+#if FLAC__HAS_OGG
+FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes)
+{
+ switch(FLAC__ogg_decoder_aspect_read_callback_wrapper(&decoder->protected_->ogg_decoder_aspect, buffer, bytes, read_callback_proxy_, decoder, decoder->private_->client_data)) {
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK:
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ /* we don't really have a way to handle lost sync via read
+ * callback so we'll let it pass and let the underlying
+ * FLAC decoder catch the error
+ */
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC:
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM:
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC:
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION:
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT:
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR:
+ case FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR:
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ default:
+ FLAC__ASSERT(0);
+ /* double protection */
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+}
+
+FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder*)void_decoder;
+
+ switch(decoder->private_->read_callback(decoder, buffer, bytes, client_data)) {
+ case FLAC__STREAM_DECODER_READ_STATUS_CONTINUE:
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK;
+ case FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM:
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM;
+ case FLAC__STREAM_DECODER_READ_STATUS_ABORT:
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
+ default:
+ /* double protection: */
+ FLAC__ASSERT(0);
+ return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT;
+ }
+}
+#endif
+
+FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[])
+{
+ if(decoder->private_->is_seeking) {
+ FLAC__uint64 this_frame_sample = frame->header.number.sample_number;
+ FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize;
+ FLAC__uint64 target_sample = decoder->private_->target_sample;
+
+ FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+
+#if FLAC__HAS_OGG
+ decoder->private_->got_a_frame = true;
+#endif
+ decoder->private_->last_frame = *frame; /* save the frame */
+ if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */
+ unsigned delta = (unsigned)(target_sample - this_frame_sample);
+ /* kick out of seek mode */
+ decoder->private_->is_seeking = false;
+ /* shift out the samples before target_sample */
+ if(delta > 0) {
+ unsigned channel;
+ const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS];
+ for(channel = 0; channel < frame->header.channels; channel++)
+ newbuffer[channel] = buffer[channel] + delta;
+ decoder->private_->last_frame.header.blocksize -= delta;
+ decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta;
+ /* write the relevant samples */
+ return decoder->private_->write_callback(decoder, &decoder->private_->last_frame, newbuffer, decoder->private_->client_data);
+ }
+ else {
+ /* write the relevant samples */
+ return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data);
+ }
+ }
+ else {
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+ }
+ }
+ else {
+ /*
+ * If we never got STREAMINFO, turn off MD5 checking to save
+ * cycles since we don't have a sum to compare to anyway
+ */
+ if(!decoder->private_->has_stream_info)
+ decoder->private_->do_md5_checking = false;
+ if(decoder->private_->do_md5_checking) {
+ if(!FLAC__MD5Accumulate(&decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8))
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data);
+ }
+}
+
+void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status)
+{
+ if(!decoder->private_->is_seeking)
+ decoder->private_->error_callback(decoder, status, decoder->private_->client_data);
+ else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM)
+ decoder->private_->unparseable_frame_count++;
+}
+
+FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
+{
+ FLAC__uint64 first_frame_offset = decoder->private_->first_frame_offset, lower_bound, upper_bound, lower_bound_sample, upper_bound_sample, this_frame_sample;
+ FLAC__int64 pos = -1;
+ int i;
+ unsigned approx_bytes_per_frame;
+ FLAC__bool first_seek = true;
+ const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder);
+ const unsigned min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize;
+ const unsigned max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize;
+ const unsigned max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize;
+ const unsigned min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize;
+ /* take these from the current frame in case they've changed mid-stream */
+ unsigned channels = FLAC__stream_decoder_get_channels(decoder);
+ unsigned bps = FLAC__stream_decoder_get_bits_per_sample(decoder);
+ const FLAC__StreamMetadata_SeekTable *seek_table = decoder->private_->has_seek_table? &decoder->private_->seek_table.data.seek_table : 0;
+
+ /* use values from stream info if we didn't decode a frame */
+ if(channels == 0)
+ channels = decoder->private_->stream_info.data.stream_info.channels;
+ if(bps == 0)
+ bps = decoder->private_->stream_info.data.stream_info.bits_per_sample;
+
+ /* we are just guessing here */
+ if(max_framesize > 0)
+ approx_bytes_per_frame = (max_framesize + min_framesize) / 2 + 1;
+
+ /*
+ * Check if it's a known fixed-blocksize stream. Note that though
+ * the spec doesn't allow zeroes in the STREAMINFO block, we may
+ * never get a STREAMINFO block when decoding so the value of
+ * min_blocksize might be zero.
+ */
+ else if(min_blocksize == max_blocksize && min_blocksize > 0) {
+ /* note there are no () around 'bps/8' to keep precision up since it's an integer calulation */
+ approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64;
+ }
+ else
+ approx_bytes_per_frame = 4096 * channels * bps/8 + 64;
+
+ /*
+ * First, we set an upper and lower bound on where in the
+ * stream we will search. For now we assume the worst case
+ * scenario, which is our best guess at the beginning of
+ * the first frame and end of the stream.
+ */
+ lower_bound = first_frame_offset;
+ lower_bound_sample = 0;
+ upper_bound = stream_length;
+ upper_bound_sample = total_samples > 0 ? total_samples : target_sample;
+ if(upper_bound_sample == 0)
+ upper_bound_sample = 1;
+
+ /*
+ * Now we refine the bounds if we have a seektable with
+ * suitable points. Note that according to the spec they
+ * must be ordered by ascending sample number.
+ */
+ if(seek_table) {
+ /* find the closest seek point <= target_sample, if it exists */
+ for(i = (int)seek_table->num_points - 1; i >= 0; i--) {
+ if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && seek_table->points[i].sample_number <= target_sample)
+ break;
+ }
+ if(i >= 0) { /* i.e. we found a suitable seek point... */
+ lower_bound = first_frame_offset + seek_table->points[i].stream_offset;
+ lower_bound_sample = seek_table->points[i].sample_number;
+ }
+
+ /* find the closest seek point > target_sample, if it exists */
+ for(i = 0; i < (int)seek_table->num_points; i++) {
+ if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && seek_table->points[i].sample_number > target_sample)
+ break;
+ }
+ if(i < (int)seek_table->num_points) { /* i.e. we found a suitable seek point... */
+ upper_bound = first_frame_offset + seek_table->points[i].stream_offset;
+ upper_bound_sample = seek_table->points[i].sample_number;
+ }
+ }
+
+ decoder->private_->target_sample = target_sample;
+ while(1) {
+ /* check if the bounds are still ok */
+ if (lower_bound_sample >= upper_bound_sample || lower_bound > upper_bound) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if defined _MSC_VER || defined __MINGW32__
+ /* with VC++ you have to spoon feed it the casting */
+ pos = (FLAC__int64)lower_bound + (FLAC__int64)((FLAC__double)(FLAC__int64)(target_sample - lower_bound_sample) / (FLAC__double)(FLAC__int64)(upper_bound_sample - lower_bound_sample) * (FLAC__double)(FLAC__int64)(upper_bound - lower_bound)) - approx_bytes_per_frame;
+#else
+ pos = (FLAC__int64)lower_bound + (FLAC__int64)((FLAC__double)(target_sample - lower_bound_sample) / (FLAC__double)(upper_bound_sample - lower_bound_sample) * (FLAC__double)(upper_bound - lower_bound)) - approx_bytes_per_frame;
+#endif
+#else
+ /* a little less accurate: */
+ if(upper_bound - lower_bound < 0xffffffff)
+ pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_sample - lower_bound_sample) * (upper_bound - lower_bound)) / (upper_bound_sample - lower_bound_sample)) - approx_bytes_per_frame;
+ else /* @@@ WATCHOUT, ~2TB limit */
+ pos = (FLAC__int64)lower_bound + (FLAC__int64)((((target_sample - lower_bound_sample)>>8) * ((upper_bound - lower_bound)>>8)) / ((upper_bound_sample - lower_bound_sample)>>16)) - approx_bytes_per_frame;
+#endif
+ if(pos >= (FLAC__int64)upper_bound)
+ pos = (FLAC__int64)upper_bound - 1;
+ if(pos < (FLAC__int64)lower_bound)
+ pos = (FLAC__int64)lower_bound;
+ if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ if(!FLAC__stream_decoder_flush(decoder)) {
+ /* above call sets the state for us */
+ return false;
+ }
+ /* Now we need to get a frame. First we need to reset our
+ * unparseable_frame_count; if we get too many unparseable
+ * frames in a row, the read callback will return
+ * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing
+ * FLAC__stream_decoder_process_single() to return false.
+ */
+ decoder->private_->unparseable_frame_count = 0;
+ if(!FLAC__stream_decoder_process_single(decoder)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ /* our write callback will change the state when it gets to the target frame */
+ /* actually, we could have got_a_frame if our decoder is at FLAC__STREAM_DECODER_END_OF_STREAM so we need to check for that also */
+#if 0
+ /*@@@@@@ used to be the following; not clear if the check for end of stream is needed anymore */
+ if(decoder->protected_->state != FLAC__SEEKABLE_STREAM_DECODER_SEEKING && decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM)
+ break;
+#endif
+ if(!decoder->private_->is_seeking) {
+ break;
+ }
+ this_frame_sample = decoder->private_->last_frame.header.number.sample_number;
+
+ if (!decoder->private_->samples_decoded || (this_frame_sample + decoder->private_->last_frame.header.blocksize >= upper_bound_sample && !first_seek)) {
+ if (pos == (FLAC__int64)lower_bound) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ /* our last move backwards wasn't big enough, try again */
+ approx_bytes_per_frame *= 2;
+ continue;
+ }
+ /* allow one seek over upper bound, required for streams with unknown total_samples */
+ first_seek = false;
+
+ /* make sure we are not seeking in corrupted stream */
+ if (this_frame_sample < lower_bound_sample) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+
+ FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+
+ /* we need to narrow the search */
+ if(target_sample < this_frame_sample) {
+ upper_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
+ if(!FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ approx_bytes_per_frame = (unsigned)(2 * (upper_bound - pos) / 3 + 16);
+ }
+ else {
+ /* target_sample >= this_frame_sample + this frame's blocksize */
+
+ lower_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize;
+ if(!FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ approx_bytes_per_frame = (unsigned)(2 * (lower_bound - pos) / 3 + 16);
+ }
+ }
+
+ return true;
+}
+
+#if FLAC__HAS_OGG
+FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample)
+{
+ FLAC__uint64 left_pos = 0, right_pos = stream_length;
+ FLAC__uint64 left_sample = 0, right_sample = FLAC__stream_decoder_get_total_samples(decoder);
+ FLAC__uint64 this_frame_sample = 0; /* only initialized to avoid compiler warning */
+ FLAC__uint64 pos = 0; /* only initialized to avoid compiler warning */
+ FLAC__bool did_a_seek;
+ unsigned iteration = 0;
+
+ /* In the first iterations, we will calculate the target byte position
+ * by the distance from the target sample to left_sample and
+ * right_sample (let's call it "proportional search"). After that, we
+ * will switch to binary search.
+ */
+ unsigned BINARY_SEARCH_AFTER_ITERATION = 2;
+
+ /* We will switch to a linear search once our current sample is less
+ * than this number of samples ahead of the target sample
+ */
+ static const FLAC__uint64 LINEAR_SEARCH_WITHIN_SAMPLES = FLAC__MAX_BLOCK_SIZE * 2;
+
+ /* If the total number of samples is unknown, use a large value, and
+ * force binary search immediately.
+ */
+ if(right_sample == 0) {
+ right_sample = (FLAC__uint64)(-1);
+ BINARY_SEARCH_AFTER_ITERATION = 0;
+ }
+
+ decoder->private_->target_sample = target_sample;
+ for( ; ; iteration++) {
+ if (iteration == 0 || this_frame_sample > target_sample || target_sample - this_frame_sample > LINEAR_SEARCH_WITHIN_SAMPLES) {
+ if (iteration >= BINARY_SEARCH_AFTER_ITERATION) {
+ pos = (right_pos + left_pos) / 2;
+ }
+ else {
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if defined _MSC_VER || defined __MINGW32__
+ /* with MSVC you have to spoon feed it the casting */
+ pos = (FLAC__uint64)((FLAC__double)(FLAC__int64)(target_sample - left_sample) / (FLAC__double)(FLAC__int64)(right_sample - left_sample) * (FLAC__double)(FLAC__int64)(right_pos - left_pos));
+#else
+ pos = (FLAC__uint64)((FLAC__double)(target_sample - left_sample) / (FLAC__double)(right_sample - left_sample) * (FLAC__double)(right_pos - left_pos));
+#endif
+#else
+ /* a little less accurate: */
+ if ((target_sample-left_sample <= 0xffffffff) && (right_pos-left_pos <= 0xffffffff))
+ pos = (FLAC__int64)(((target_sample-left_sample) * (right_pos-left_pos)) / (right_sample-left_sample));
+ else /* @@@ WATCHOUT, ~2TB limit */
+ pos = (FLAC__int64)((((target_sample-left_sample)>>8) * ((right_pos-left_pos)>>8)) / ((right_sample-left_sample)>>16));
+#endif
+ /* @@@ TODO: might want to limit pos to some distance
+ * before EOF, to make sure we land before the last frame,
+ * thereby getting a this_frame_sample and so having a better
+ * estimate. @@@@@@DELETE:this would also mostly (or totally if we could
+ * be sure to land before the last frame) avoid the
+ * end-of-stream case we have to check later.
+ */
+ }
+
+ /* physical seek */
+ if(decoder->private_->seek_callback((FLAC__StreamDecoder*)decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ if(!FLAC__stream_decoder_flush(decoder)) {
+ /* above call sets the state for us */
+ return false;
+ }
+ did_a_seek = true;
+ }
+ else
+ did_a_seek = false;
+
+ decoder->private_->got_a_frame = false;
+ if(!FLAC__stream_decoder_process_single(decoder)) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ if(!decoder->private_->got_a_frame) {
+ if(did_a_seek) {
+ /* this can happen if we seek to a point after the last frame; we drop
+ * to binary search right away in this case to avoid any wasted
+ * iterations of proportional search.
+ */
+ right_pos = pos;
+ BINARY_SEARCH_AFTER_ITERATION = 0;
+ }
+ else {
+ /* this can probably only happen if total_samples is unknown and the
+ * target_sample is past the end of the stream
+ */
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ }
+ /* our write callback will change the state when it gets to the target frame */
+ else if(!decoder->private_->is_seeking/*@@@@@@ && decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM*/) {
+ break;
+ }
+ else {
+ this_frame_sample = decoder->private_->last_frame.header.number.sample_number;
+ FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+
+ if (did_a_seek) {
+ if (this_frame_sample <= target_sample) {
+ /* The 'equal' case should not happen, since
+ * FLAC__stream_decoder_process_single()
+ * should recognize that it has hit the
+ * target sample and we would exit through
+ * the 'break' above.
+ */
+ FLAC__ASSERT(this_frame_sample != target_sample);
+
+ left_sample = this_frame_sample;
+ /* sanity check to avoid infinite loop */
+ if (left_pos == pos) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ left_pos = pos;
+ }
+ else if(this_frame_sample > target_sample) {
+ right_sample = this_frame_sample;
+ /* sanity check to avoid infinite loop */
+ if (right_pos == pos) {
+ decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR;
+ return false;
+ }
+ right_pos = pos;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+#endif
+
+FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ (void)client_data;
+
+ if(*bytes > 0) {
+ *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, decoder->private_->file);
+ if(ferror(decoder->private_->file))
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ else if(*bytes == 0)
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+ (void)client_data;
+
+ if(decoder->private_->file == stdin)
+ return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
+ else if(fseeko(decoder->private_->file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ else
+ return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+ off_t pos;
+ (void)client_data;
+
+ if(decoder->private_->file == stdin)
+ return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
+ else if((pos = ftello(decoder->private_->file)) < 0)
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ else {
+ *absolute_byte_offset = (FLAC__uint64)pos;
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+ }
+}
+
+FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+ struct stat filestats;
+ (void)client_data;
+
+ if(decoder->private_->file == stdin)
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED;
+ else if(fstat(fileno(decoder->private_->file), &filestats) != 0)
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ else {
+ *stream_length = (FLAC__uint64)filestats.st_size;
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+ }
+}
+
+FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+ (void)client_data;
+
+ return feof(decoder->private_->file)? true : false;
+}
diff --git a/src/FLAC/src/libFLAC/stream_encoder.c b/src/FLAC/src/libFLAC/stream_encoder.c
new file mode 100644
index 0000000..f9f1436
--- /dev/null
+++ b/src/FLAC/src/libFLAC/stream_encoder.c
@@ -0,0 +1,4252 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__
+#include <io.h> /* for _setmode() */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#if defined __CYGWIN__ || defined __EMX__
+#include <io.h> /* for setmode(), O_BINARY */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy() */
+#include <sys/types.h> /* for off_t */
+#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__
+#if _MSC_VER <= 1600 || defined __BORLANDC__ /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "protected/stream_encoder.h"
+#include "private/bitwriter.h"
+#include "private/bitmath.h"
+#include "private/crc.h"
+#include "private/cpu.h"
+#include "private/fixed.h"
+#include "private/format.h"
+#include "private/lpc.h"
+#include "private/md5.h"
+#include "private/memory.h"
+#if FLAC__HAS_OGG
+#include "private/ogg_helper.h"
+#include "private/ogg_mapping.h"
+#endif
+#include "private/stream_encoder_framing.h"
+#include "private/window.h"
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+#ifdef min
+#undef min
+#endif
+#define min(x,y) ((x)<(y)?(x):(y))
+
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+/* Exact Rice codeword length calculation is off by default. The simple
+ * (and fast) estimation (of how many bits a residual value will be
+ * encoded with) in this encoder is very good, almost always yielding
+ * compression within 0.1% of exact calculation.
+ */
+#undef EXACT_RICE_BITS_CALCULATION
+/* Rice parameter searching is off by default. The simple (and fast)
+ * parameter estimation in this encoder is very good, almost always
+ * yielding compression within 0.1% of the optimal parameters.
+ */
+#undef ENABLE_RICE_PARAMETER_SEARCH
+
+
+typedef struct {
+ FLAC__int32 *data[FLAC__MAX_CHANNELS];
+ unsigned size; /* of each data[] in samples */
+ unsigned tail;
+} verify_input_fifo;
+
+typedef struct {
+ const FLAC__byte *data;
+ unsigned capacity;
+ unsigned bytes;
+} verify_output;
+
+typedef enum {
+ ENCODER_IN_MAGIC = 0,
+ ENCODER_IN_METADATA = 1,
+ ENCODER_IN_AUDIO = 2
+} EncoderStateHint;
+
+static struct CompressionLevels {
+ FLAC__bool do_mid_side_stereo;
+ FLAC__bool loose_mid_side_stereo;
+ unsigned max_lpc_order;
+ unsigned qlp_coeff_precision;
+ FLAC__bool do_qlp_coeff_prec_search;
+ FLAC__bool do_escape_coding;
+ FLAC__bool do_exhaustive_model_search;
+ unsigned min_residual_partition_order;
+ unsigned max_residual_partition_order;
+ unsigned rice_parameter_search_dist;
+} compression_levels_[] = {
+ { false, false, 0, 0, false, false, false, 0, 3, 0 },
+ { true , true , 0, 0, false, false, false, 0, 3, 0 },
+ { true , false, 0, 0, false, false, false, 0, 3, 0 },
+ { false, false, 6, 0, false, false, false, 0, 4, 0 },
+ { true , true , 8, 0, false, false, false, 0, 4, 0 },
+ { true , false, 8, 0, false, false, false, 0, 5, 0 },
+ { true , false, 8, 0, false, false, false, 0, 6, 0 },
+ { true , false, 8, 0, false, false, true , 0, 6, 0 },
+ { true , false, 12, 0, false, false, true , 0, 6, 0 }
+};
+
+
+/***********************************************************************
+ *
+ * Private class method prototypes
+ *
+ ***********************************************************************/
+
+static void set_defaults_(FLAC__StreamEncoder *encoder);
+static void free_(FLAC__StreamEncoder *encoder);
+static FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize);
+static FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block);
+static FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, FLAC__bool is_last_block);
+static void update_metadata_(const FLAC__StreamEncoder *encoder);
+#if FLAC__HAS_OGG
+static void update_ogg_metadata_(FLAC__StreamEncoder *encoder);
+#endif
+static FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block);
+static FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block);
+
+static FLAC__bool process_subframe_(
+ FLAC__StreamEncoder *encoder,
+ unsigned min_partition_order,
+ unsigned max_partition_order,
+ const FLAC__FrameHeader *frame_header,
+ unsigned subframe_bps,
+ const FLAC__int32 integer_signal[],
+ FLAC__Subframe *subframe[2],
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
+ FLAC__int32 *residual[2],
+ unsigned *best_subframe,
+ unsigned *best_bits
+);
+
+static FLAC__bool add_subframe_(
+ FLAC__StreamEncoder *encoder,
+ unsigned blocksize,
+ unsigned subframe_bps,
+ const FLAC__Subframe *subframe,
+ FLAC__BitWriter *frame
+);
+
+static unsigned evaluate_constant_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const FLAC__int32 signal,
+ unsigned blocksize,
+ unsigned subframe_bps,
+ FLAC__Subframe *subframe
+);
+
+static unsigned evaluate_fixed_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const FLAC__int32 signal[],
+ FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ unsigned raw_bits_per_partition[],
+ unsigned blocksize,
+ unsigned subframe_bps,
+ unsigned order,
+ unsigned rice_parameter,
+ unsigned min_partition_order,
+ unsigned max_partition_order,
+ FLAC__bool do_escape_coding,
+ unsigned rice_parameter_search_dist,
+ FLAC__Subframe *subframe,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+);
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+static unsigned evaluate_lpc_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const FLAC__int32 signal[],
+ FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ unsigned raw_bits_per_partition[],
+ const FLAC__real lp_coeff[],
+ unsigned blocksize,
+ unsigned subframe_bps,
+ unsigned order,
+ unsigned qlp_coeff_precision,
+ unsigned rice_parameter,
+ unsigned min_partition_order,
+ unsigned max_partition_order,
+ FLAC__bool do_escape_coding,
+ unsigned rice_parameter_search_dist,
+ FLAC__Subframe *subframe,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+);
+#endif
+
+static unsigned evaluate_verbatim_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const FLAC__int32 signal[],
+ unsigned blocksize,
+ unsigned subframe_bps,
+ FLAC__Subframe *subframe
+);
+
+static unsigned find_best_partition_order_(
+ struct FLAC__StreamEncoderPrivate *private_,
+ const FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ unsigned raw_bits_per_partition[],
+ unsigned residual_samples,
+ unsigned predictor_order,
+ unsigned rice_parameter,
+ unsigned min_partition_order,
+ unsigned max_partition_order,
+ unsigned bps,
+ FLAC__bool do_escape_coding,
+ unsigned rice_parameter_search_dist,
+ FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice
+);
+
+static void precompute_partition_info_sums_(
+ const FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ unsigned residual_samples,
+ unsigned predictor_order,
+ unsigned min_partition_order,
+ unsigned max_partition_order,
+ unsigned bps
+);
+
+static void precompute_partition_info_escapes_(
+ const FLAC__int32 residual[],
+ unsigned raw_bits_per_partition[],
+ unsigned residual_samples,
+ unsigned predictor_order,
+ unsigned min_partition_order,
+ unsigned max_partition_order
+);
+
+static FLAC__bool set_partitioned_rice_(
+#ifdef EXACT_RICE_BITS_CALCULATION
+ const FLAC__int32 residual[],
+#endif
+ const FLAC__uint64 abs_residual_partition_sums[],
+ const unsigned raw_bits_per_partition[],
+ const unsigned residual_samples,
+ const unsigned predictor_order,
+ const unsigned suggested_rice_parameter,
+ const unsigned rice_parameter_search_dist,
+ const unsigned partition_order,
+ const FLAC__bool search_for_escapes,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+ unsigned *bits
+);
+
+static unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples);
+
+/* verify-related routines: */
+static void append_to_verify_fifo_(
+ verify_input_fifo *fifo,
+ const FLAC__int32 * const input[],
+ unsigned input_offset,
+ unsigned channels,
+ unsigned wide_samples
+);
+
+static void append_to_verify_fifo_interleaved_(
+ verify_input_fifo *fifo,
+ const FLAC__int32 input[],
+ unsigned input_offset,
+ unsigned channels,
+ unsigned wide_samples
+);
+
+static FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
+static void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
+static void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
+
+static FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data);
+static FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data);
+static FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
+static FILE *get_binary_stdout_(void);
+
+
+/***********************************************************************
+ *
+ * Private class data
+ *
+ ***********************************************************************/
+
+typedef struct FLAC__StreamEncoderPrivate {
+ unsigned input_capacity; /* current size (in samples) of the signal and residual buffers */
+ FLAC__int32 *integer_signal[FLAC__MAX_CHANNELS]; /* the integer version of the input signal */
+ FLAC__int32 *integer_signal_mid_side[2]; /* the integer version of the mid-side input signal (stereo only) */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ FLAC__real *real_signal[FLAC__MAX_CHANNELS]; /* (@@@ currently unused) the floating-point version of the input signal */
+ FLAC__real *real_signal_mid_side[2]; /* (@@@ currently unused) the floating-point version of the mid-side input signal (stereo only) */
+ FLAC__real *window[FLAC__MAX_APODIZATION_FUNCTIONS]; /* the pre-computed floating-point window for each apodization function */
+ FLAC__real *windowed_signal; /* the integer_signal[] * current window[] */
+#endif
+ unsigned subframe_bps[FLAC__MAX_CHANNELS]; /* the effective bits per sample of the input signal (stream bps - wasted bits) */
+ unsigned subframe_bps_mid_side[2]; /* the effective bits per sample of the mid-side input signal (stream bps - wasted bits + 0/1) */
+ FLAC__int32 *residual_workspace[FLAC__MAX_CHANNELS][2]; /* each channel has a candidate and best workspace where the subframe residual signals will be stored */
+ FLAC__int32 *residual_workspace_mid_side[2][2];
+ FLAC__Subframe subframe_workspace[FLAC__MAX_CHANNELS][2];
+ FLAC__Subframe subframe_workspace_mid_side[2][2];
+ FLAC__Subframe *subframe_workspace_ptr[FLAC__MAX_CHANNELS][2];
+ FLAC__Subframe *subframe_workspace_ptr_mid_side[2][2];
+ FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace[FLAC__MAX_CHANNELS][2];
+ FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_workspace_mid_side[FLAC__MAX_CHANNELS][2];
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr[FLAC__MAX_CHANNELS][2];
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents_workspace_ptr_mid_side[FLAC__MAX_CHANNELS][2];
+ unsigned best_subframe[FLAC__MAX_CHANNELS]; /* index (0 or 1) into 2nd dimension of the above workspaces */
+ unsigned best_subframe_mid_side[2];
+ unsigned best_subframe_bits[FLAC__MAX_CHANNELS]; /* size in bits of the best subframe for each channel */
+ unsigned best_subframe_bits_mid_side[2];
+ FLAC__uint64 *abs_residual_partition_sums; /* workspace where the sum of abs(candidate residual) for each partition is stored */
+ unsigned *raw_bits_per_partition; /* workspace where the sum of silog2(candidate residual) for each partition is stored */
+ FLAC__BitWriter *frame; /* the current frame being worked on */
+ unsigned loose_mid_side_stereo_frames; /* rounded number of frames the encoder will use before trying both independent and mid/side frames again */
+ unsigned loose_mid_side_stereo_frame_count; /* number of frames using the current channel assignment */
+ FLAC__ChannelAssignment last_channel_assignment;
+ FLAC__StreamMetadata streaminfo; /* scratchpad for STREAMINFO as it is built */
+ FLAC__StreamMetadata_SeekTable *seek_table; /* pointer into encoder->protected_->metadata_ where the seek table is */
+ unsigned current_sample_number;
+ unsigned current_frame_number;
+ FLAC__MD5Context md5context;
+ FLAC__CPUInfo cpuinfo;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#else
+ unsigned (*local_fixed_compute_best_predictor)(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]);
+#endif
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ void (*local_lpc_compute_autocorrelation)(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]);
+ void (*local_lpc_compute_residual_from_qlp_coefficients)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+ void (*local_lpc_compute_residual_from_qlp_coefficients_64bit)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+ void (*local_lpc_compute_residual_from_qlp_coefficients_16bit)(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]);
+#endif
+ FLAC__bool use_wide_by_block; /* use slow 64-bit versions of some functions because of the block size */
+ FLAC__bool use_wide_by_partition; /* use slow 64-bit versions of some functions because of the min partition order and blocksize */
+ FLAC__bool use_wide_by_order; /* use slow 64-bit versions of some functions because of the lpc order */
+ FLAC__bool disable_constant_subframes;
+ FLAC__bool disable_fixed_subframes;
+ FLAC__bool disable_verbatim_subframes;
+#if FLAC__HAS_OGG
+ FLAC__bool is_ogg;
+#endif
+ FLAC__StreamEncoderReadCallback read_callback; /* currently only needed for Ogg FLAC */
+ FLAC__StreamEncoderSeekCallback seek_callback;
+ FLAC__StreamEncoderTellCallback tell_callback;
+ FLAC__StreamEncoderWriteCallback write_callback;
+ FLAC__StreamEncoderMetadataCallback metadata_callback;
+ FLAC__StreamEncoderProgressCallback progress_callback;
+ void *client_data;
+ unsigned first_seekpoint_to_check;
+ FILE *file; /* only used when encoding to a file */
+ FLAC__uint64 bytes_written;
+ FLAC__uint64 samples_written;
+ unsigned frames_written;
+ unsigned total_frames_estimate;
+ /* unaligned (original) pointers to allocated data */
+ FLAC__int32 *integer_signal_unaligned[FLAC__MAX_CHANNELS];
+ FLAC__int32 *integer_signal_mid_side_unaligned[2];
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ FLAC__real *real_signal_unaligned[FLAC__MAX_CHANNELS]; /* (@@@ currently unused) */
+ FLAC__real *real_signal_mid_side_unaligned[2]; /* (@@@ currently unused) */
+ FLAC__real *window_unaligned[FLAC__MAX_APODIZATION_FUNCTIONS];
+ FLAC__real *windowed_signal_unaligned;
+#endif
+ FLAC__int32 *residual_workspace_unaligned[FLAC__MAX_CHANNELS][2];
+ FLAC__int32 *residual_workspace_mid_side_unaligned[2][2];
+ FLAC__uint64 *abs_residual_partition_sums_unaligned;
+ unsigned *raw_bits_per_partition_unaligned;
+ /*
+ * These fields have been moved here from private function local
+ * declarations merely to save stack space during encoding.
+ */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ FLAC__real lp_coeff[FLAC__MAX_LPC_ORDER][FLAC__MAX_LPC_ORDER]; /* from process_subframe_() */
+#endif
+ FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents_extra[2]; /* from find_best_partition_order_() */
+ /*
+ * The data for the verify section
+ */
+ struct {
+ FLAC__StreamDecoder *decoder;
+ EncoderStateHint state_hint;
+ FLAC__bool needs_magic_hack;
+ verify_input_fifo input_fifo;
+ verify_output output;
+ struct {
+ FLAC__uint64 absolute_sample;
+ unsigned frame_number;
+ unsigned channel;
+ unsigned sample;
+ FLAC__int32 expected;
+ FLAC__int32 got;
+ } error_stats;
+ } verify;
+ FLAC__bool is_being_deleted; /* if true, call to ..._finish() from ..._delete() will not call the callbacks */
+} FLAC__StreamEncoderPrivate;
+
+/***********************************************************************
+ *
+ * Public static class data
+ *
+ ***********************************************************************/
+
+FLAC_API const char * const FLAC__StreamEncoderStateString[] = {
+ "FLAC__STREAM_ENCODER_OK",
+ "FLAC__STREAM_ENCODER_UNINITIALIZED",
+ "FLAC__STREAM_ENCODER_OGG_ERROR",
+ "FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR",
+ "FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA",
+ "FLAC__STREAM_ENCODER_CLIENT_ERROR",
+ "FLAC__STREAM_ENCODER_IO_ERROR",
+ "FLAC__STREAM_ENCODER_FRAMING_ERROR",
+ "FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR"
+};
+
+FLAC_API const char * const FLAC__StreamEncoderInitStatusString[] = {
+ "FLAC__STREAM_ENCODER_INIT_STATUS_OK",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA",
+ "FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED"
+};
+
+FLAC_API const char * const FLAC__treamEncoderReadStatusString[] = {
+ "FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE",
+ "FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM",
+ "FLAC__STREAM_ENCODER_READ_STATUS_ABORT",
+ "FLAC__STREAM_ENCODER_READ_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamEncoderWriteStatusString[] = {
+ "FLAC__STREAM_ENCODER_WRITE_STATUS_OK",
+ "FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR"
+};
+
+FLAC_API const char * const FLAC__StreamEncoderSeekStatusString[] = {
+ "FLAC__STREAM_ENCODER_SEEK_STATUS_OK",
+ "FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR",
+ "FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED"
+};
+
+FLAC_API const char * const FLAC__StreamEncoderTellStatusString[] = {
+ "FLAC__STREAM_ENCODER_TELL_STATUS_OK",
+ "FLAC__STREAM_ENCODER_TELL_STATUS_ERROR",
+ "FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED"
+};
+
+/* Number of samples that will be overread to watch for end of stream. By
+ * 'overread', we mean that the FLAC__stream_encoder_process*() calls will
+ * always try to read blocksize+1 samples before encoding a block, so that
+ * even if the stream has a total sample count that is an integral multiple
+ * of the blocksize, we will still notice when we are encoding the last
+ * block. This is needed, for example, to correctly set the end-of-stream
+ * marker in Ogg FLAC.
+ *
+ * WATCHOUT: some parts of the code assert that OVERREAD_ == 1 and there's
+ * not really any reason to change it.
+ */
+static const unsigned OVERREAD_ = 1;
+
+/***********************************************************************
+ *
+ * Class constructor/destructor
+ *
+ */
+FLAC_API FLAC__StreamEncoder *FLAC__stream_encoder_new(void)
+{
+ FLAC__StreamEncoder *encoder;
+ unsigned i;
+
+ FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */
+
+ encoder = (FLAC__StreamEncoder*)calloc(1, sizeof(FLAC__StreamEncoder));
+ if(encoder == 0) {
+ return 0;
+ }
+
+ encoder->protected_ = (FLAC__StreamEncoderProtected*)calloc(1, sizeof(FLAC__StreamEncoderProtected));
+ if(encoder->protected_ == 0) {
+ free(encoder);
+ return 0;
+ }
+
+ encoder->private_ = (FLAC__StreamEncoderPrivate*)calloc(1, sizeof(FLAC__StreamEncoderPrivate));
+ if(encoder->private_ == 0) {
+ free(encoder->protected_);
+ free(encoder);
+ return 0;
+ }
+
+ encoder->private_->frame = FLAC__bitwriter_new();
+ if(encoder->private_->frame == 0) {
+ free(encoder->private_);
+ free(encoder->protected_);
+ free(encoder);
+ return 0;
+ }
+
+ encoder->private_->file = 0;
+
+ set_defaults_(encoder);
+
+ encoder->private_->is_being_deleted = false;
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ encoder->private_->subframe_workspace_ptr[i][0] = &encoder->private_->subframe_workspace[i][0];
+ encoder->private_->subframe_workspace_ptr[i][1] = &encoder->private_->subframe_workspace[i][1];
+ }
+ for(i = 0; i < 2; i++) {
+ encoder->private_->subframe_workspace_ptr_mid_side[i][0] = &encoder->private_->subframe_workspace_mid_side[i][0];
+ encoder->private_->subframe_workspace_ptr_mid_side[i][1] = &encoder->private_->subframe_workspace_mid_side[i][1];
+ }
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ encoder->private_->partitioned_rice_contents_workspace_ptr[i][0] = &encoder->private_->partitioned_rice_contents_workspace[i][0];
+ encoder->private_->partitioned_rice_contents_workspace_ptr[i][1] = &encoder->private_->partitioned_rice_contents_workspace[i][1];
+ }
+ for(i = 0; i < 2; i++) {
+ encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][0] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0];
+ encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[i][1] = &encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1];
+ }
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
+ }
+ for(i = 0; i < 2; i++) {
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
+ }
+ for(i = 0; i < 2; i++)
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&encoder->private_->partitioned_rice_contents_extra[i]);
+
+ encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+
+ return encoder;
+}
+
+FLAC_API void FLAC__stream_encoder_delete(FLAC__StreamEncoder *encoder)
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->protected_);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->private_->frame);
+
+ encoder->private_->is_being_deleted = true;
+
+ (void)FLAC__stream_encoder_finish(encoder);
+
+ if(0 != encoder->private_->verify.decoder)
+ FLAC__stream_decoder_delete(encoder->private_->verify.decoder);
+
+ for(i = 0; i < FLAC__MAX_CHANNELS; i++) {
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][0]);
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace[i][1]);
+ }
+ for(i = 0; i < 2; i++) {
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][0]);
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_workspace_mid_side[i][1]);
+ }
+ for(i = 0; i < 2; i++)
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&encoder->private_->partitioned_rice_contents_extra[i]);
+
+ FLAC__bitwriter_delete(encoder->private_->frame);
+ free(encoder->private_);
+ free(encoder->protected_);
+ free(encoder);
+}
+
+/***********************************************************************
+ *
+ * Public class methods
+ *
+ ***********************************************************************/
+
+static FLAC__StreamEncoderInitStatus init_stream_internal_(
+ FLAC__StreamEncoder *encoder,
+ FLAC__StreamEncoderReadCallback read_callback,
+ FLAC__StreamEncoderWriteCallback write_callback,
+ FLAC__StreamEncoderSeekCallback seek_callback,
+ FLAC__StreamEncoderTellCallback tell_callback,
+ FLAC__StreamEncoderMetadataCallback metadata_callback,
+ void *client_data,
+ FLAC__bool is_ogg
+)
+{
+ unsigned i;
+ FLAC__bool metadata_has_seektable, metadata_has_vorbis_comment, metadata_picture_has_type1, metadata_picture_has_type2;
+
+ FLAC__ASSERT(0 != encoder);
+
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+#if !FLAC__HAS_OGG
+ if(is_ogg)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_UNSUPPORTED_CONTAINER;
+#endif
+
+ if(0 == write_callback || (seek_callback && 0 == tell_callback))
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_CALLBACKS;
+
+ if(encoder->protected_->channels == 0 || encoder->protected_->channels > FLAC__MAX_CHANNELS)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_NUMBER_OF_CHANNELS;
+
+ if(encoder->protected_->channels != 2) {
+ encoder->protected_->do_mid_side_stereo = false;
+ encoder->protected_->loose_mid_side_stereo = false;
+ }
+ else if(!encoder->protected_->do_mid_side_stereo)
+ encoder->protected_->loose_mid_side_stereo = false;
+
+ if(encoder->protected_->bits_per_sample >= 32)
+ encoder->protected_->do_mid_side_stereo = false; /* since we currenty do 32-bit math, the side channel would have 33 bps and overflow */
+
+ if(encoder->protected_->bits_per_sample < FLAC__MIN_BITS_PER_SAMPLE || encoder->protected_->bits_per_sample > FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE;
+
+ if(!FLAC__format_sample_rate_is_valid(encoder->protected_->sample_rate))
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE;
+
+ if(encoder->protected_->blocksize == 0) {
+ if(encoder->protected_->max_lpc_order == 0)
+ encoder->protected_->blocksize = 1152;
+ else
+ encoder->protected_->blocksize = 4096;
+ }
+
+ if(encoder->protected_->blocksize < FLAC__MIN_BLOCK_SIZE || encoder->protected_->blocksize > FLAC__MAX_BLOCK_SIZE)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BLOCK_SIZE;
+
+ if(encoder->protected_->max_lpc_order > FLAC__MAX_LPC_ORDER)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_MAX_LPC_ORDER;
+
+ if(encoder->protected_->blocksize < encoder->protected_->max_lpc_order)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_BLOCK_SIZE_TOO_SMALL_FOR_LPC_ORDER;
+
+ if(encoder->protected_->qlp_coeff_precision == 0) {
+ if(encoder->protected_->bits_per_sample < 16) {
+ /* @@@ need some data about how to set this here w.r.t. blocksize and sample rate */
+ /* @@@ until then we'll make a guess */
+ encoder->protected_->qlp_coeff_precision = max(FLAC__MIN_QLP_COEFF_PRECISION, 2 + encoder->protected_->bits_per_sample / 2);
+ }
+ else if(encoder->protected_->bits_per_sample == 16) {
+ if(encoder->protected_->blocksize <= 192)
+ encoder->protected_->qlp_coeff_precision = 7;
+ else if(encoder->protected_->blocksize <= 384)
+ encoder->protected_->qlp_coeff_precision = 8;
+ else if(encoder->protected_->blocksize <= 576)
+ encoder->protected_->qlp_coeff_precision = 9;
+ else if(encoder->protected_->blocksize <= 1152)
+ encoder->protected_->qlp_coeff_precision = 10;
+ else if(encoder->protected_->blocksize <= 2304)
+ encoder->protected_->qlp_coeff_precision = 11;
+ else if(encoder->protected_->blocksize <= 4608)
+ encoder->protected_->qlp_coeff_precision = 12;
+ else
+ encoder->protected_->qlp_coeff_precision = 13;
+ }
+ else {
+ if(encoder->protected_->blocksize <= 384)
+ encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-2;
+ else if(encoder->protected_->blocksize <= 1152)
+ encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION-1;
+ else
+ encoder->protected_->qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION;
+ }
+ FLAC__ASSERT(encoder->protected_->qlp_coeff_precision <= FLAC__MAX_QLP_COEFF_PRECISION);
+ }
+ else if(encoder->protected_->qlp_coeff_precision < FLAC__MIN_QLP_COEFF_PRECISION || encoder->protected_->qlp_coeff_precision > FLAC__MAX_QLP_COEFF_PRECISION)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_QLP_COEFF_PRECISION;
+
+ if(encoder->protected_->streamable_subset) {
+ if(
+ encoder->protected_->blocksize != 192 &&
+ encoder->protected_->blocksize != 576 &&
+ encoder->protected_->blocksize != 1152 &&
+ encoder->protected_->blocksize != 2304 &&
+ encoder->protected_->blocksize != 4608 &&
+ encoder->protected_->blocksize != 256 &&
+ encoder->protected_->blocksize != 512 &&
+ encoder->protected_->blocksize != 1024 &&
+ encoder->protected_->blocksize != 2048 &&
+ encoder->protected_->blocksize != 4096 &&
+ encoder->protected_->blocksize != 8192 &&
+ encoder->protected_->blocksize != 16384
+ )
+ return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+ if(!FLAC__format_sample_rate_is_subset(encoder->protected_->sample_rate))
+ return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+ if(
+ encoder->protected_->bits_per_sample != 8 &&
+ encoder->protected_->bits_per_sample != 12 &&
+ encoder->protected_->bits_per_sample != 16 &&
+ encoder->protected_->bits_per_sample != 20 &&
+ encoder->protected_->bits_per_sample != 24
+ )
+ return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+ if(encoder->protected_->max_residual_partition_order > FLAC__SUBSET_MAX_RICE_PARTITION_ORDER)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+ if(
+ encoder->protected_->sample_rate <= 48000 &&
+ (
+ encoder->protected_->blocksize > FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ ||
+ encoder->protected_->max_lpc_order > FLAC__SUBSET_MAX_LPC_ORDER_48000HZ
+ )
+ ) {
+ return FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE;
+ }
+ }
+
+ if(encoder->protected_->max_residual_partition_order >= (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+ encoder->protected_->max_residual_partition_order = (1u << FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN) - 1;
+ if(encoder->protected_->min_residual_partition_order >= encoder->protected_->max_residual_partition_order)
+ encoder->protected_->min_residual_partition_order = encoder->protected_->max_residual_partition_order;
+
+#if FLAC__HAS_OGG
+ /* reorder metadata if necessary to ensure that any VORBIS_COMMENT is the first, according to the mapping spec */
+ if(is_ogg && 0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 1) {
+ for(i = 1; i < encoder->protected_->num_metadata_blocks; i++) {
+ if(0 != encoder->protected_->metadata[i] && encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+ FLAC__StreamMetadata *vc = encoder->protected_->metadata[i];
+ for( ; i > 0; i--)
+ encoder->protected_->metadata[i] = encoder->protected_->metadata[i-1];
+ encoder->protected_->metadata[0] = vc;
+ break;
+ }
+ }
+ }
+#endif
+ /* keep track of any SEEKTABLE block */
+ if(0 != encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0) {
+ for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
+ if(0 != encoder->protected_->metadata[i] && encoder->protected_->metadata[i]->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+ encoder->private_->seek_table = &encoder->protected_->metadata[i]->data.seek_table;
+ break; /* take only the first one */
+ }
+ }
+ }
+
+ /* validate metadata */
+ if(0 == encoder->protected_->metadata && encoder->protected_->num_metadata_blocks > 0)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+ metadata_has_seektable = false;
+ metadata_has_vorbis_comment = false;
+ metadata_picture_has_type1 = false;
+ metadata_picture_has_type2 = false;
+ for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
+ const FLAC__StreamMetadata *m = encoder->protected_->metadata[i];
+ if(m->type == FLAC__METADATA_TYPE_STREAMINFO)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+ else if(m->type == FLAC__METADATA_TYPE_SEEKTABLE) {
+ if(metadata_has_seektable) /* only one is allowed */
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+ metadata_has_seektable = true;
+ if(!FLAC__format_seektable_is_legal(&m->data.seek_table))
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+ }
+ else if(m->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+ if(metadata_has_vorbis_comment) /* only one is allowed */
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+ metadata_has_vorbis_comment = true;
+ }
+ else if(m->type == FLAC__METADATA_TYPE_CUESHEET) {
+ if(!FLAC__format_cuesheet_is_legal(&m->data.cue_sheet, m->data.cue_sheet.is_cd, /*violation=*/0))
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+ }
+ else if(m->type == FLAC__METADATA_TYPE_PICTURE) {
+ if(!FLAC__format_picture_is_legal(&m->data.picture, /*violation=*/0))
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+ if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD) {
+ if(metadata_picture_has_type1) /* there should only be 1 per stream */
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+ metadata_picture_has_type1 = true;
+ /* standard icon must be 32x32 pixel PNG */
+ if(
+ m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD &&
+ (
+ (strcmp(m->data.picture.mime_type, "image/png") && strcmp(m->data.picture.mime_type, "-->")) ||
+ m->data.picture.width != 32 ||
+ m->data.picture.height != 32
+ )
+ )
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+ }
+ else if(m->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON) {
+ if(metadata_picture_has_type2) /* there should only be 1 per stream */
+ return FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA;
+ metadata_picture_has_type2 = true;
+ }
+ }
+ }
+
+ encoder->private_->input_capacity = 0;
+ for(i = 0; i < encoder->protected_->channels; i++) {
+ encoder->private_->integer_signal_unaligned[i] = encoder->private_->integer_signal[i] = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ encoder->private_->real_signal_unaligned[i] = encoder->private_->real_signal[i] = 0;
+#endif
+ }
+ for(i = 0; i < 2; i++) {
+ encoder->private_->integer_signal_mid_side_unaligned[i] = encoder->private_->integer_signal_mid_side[i] = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ encoder->private_->real_signal_mid_side_unaligned[i] = encoder->private_->real_signal_mid_side[i] = 0;
+#endif
+ }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ for(i = 0; i < encoder->protected_->num_apodizations; i++)
+ encoder->private_->window_unaligned[i] = encoder->private_->window[i] = 0;
+ encoder->private_->windowed_signal_unaligned = encoder->private_->windowed_signal = 0;
+#endif
+ for(i = 0; i < encoder->protected_->channels; i++) {
+ encoder->private_->residual_workspace_unaligned[i][0] = encoder->private_->residual_workspace[i][0] = 0;
+ encoder->private_->residual_workspace_unaligned[i][1] = encoder->private_->residual_workspace[i][1] = 0;
+ encoder->private_->best_subframe[i] = 0;
+ }
+ for(i = 0; i < 2; i++) {
+ encoder->private_->residual_workspace_mid_side_unaligned[i][0] = encoder->private_->residual_workspace_mid_side[i][0] = 0;
+ encoder->private_->residual_workspace_mid_side_unaligned[i][1] = encoder->private_->residual_workspace_mid_side[i][1] = 0;
+ encoder->private_->best_subframe_mid_side[i] = 0;
+ }
+ encoder->private_->abs_residual_partition_sums_unaligned = encoder->private_->abs_residual_partition_sums = 0;
+ encoder->private_->raw_bits_per_partition_unaligned = encoder->private_->raw_bits_per_partition = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ encoder->private_->loose_mid_side_stereo_frames = (unsigned)((FLAC__double)encoder->protected_->sample_rate * 0.4 / (FLAC__double)encoder->protected_->blocksize + 0.5);
+#else
+ /* 26214 is the approximate fixed-point equivalent to 0.4 (0.4 * 2^16) */
+ /* sample rate can be up to 655350 Hz, and thus use 20 bits, so we do the multiply&divide by hand */
+ FLAC__ASSERT(FLAC__MAX_SAMPLE_RATE <= 655350);
+ FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535);
+ FLAC__ASSERT(encoder->protected_->sample_rate <= 655350);
+ FLAC__ASSERT(encoder->protected_->blocksize <= 65535);
+ encoder->private_->loose_mid_side_stereo_frames = (unsigned)FLAC__fixedpoint_trunc((((FLAC__uint64)(encoder->protected_->sample_rate) * (FLAC__uint64)(26214)) << 16) / (encoder->protected_->blocksize<<16) + FLAC__FP_ONE_HALF);
+#endif
+ if(encoder->private_->loose_mid_side_stereo_frames == 0)
+ encoder->private_->loose_mid_side_stereo_frames = 1;
+ encoder->private_->loose_mid_side_stereo_frame_count = 0;
+ encoder->private_->current_sample_number = 0;
+ encoder->private_->current_frame_number = 0;
+
+ encoder->private_->use_wide_by_block = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(encoder->protected_->blocksize)+1 > 30);
+ encoder->private_->use_wide_by_order = (encoder->protected_->bits_per_sample + FLAC__bitmath_ilog2(max(encoder->protected_->max_lpc_order, FLAC__MAX_FIXED_ORDER))+1 > 30); /*@@@ need to use this? */
+ encoder->private_->use_wide_by_partition = (false); /*@@@ need to set this */
+
+ /*
+ * get the CPU info and set the function pointers
+ */
+ FLAC__cpu_info(&encoder->private_->cpuinfo);
+ /* first default to the non-asm routines */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation;
+#endif
+ encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit = FLAC__lpc_compute_residual_from_qlp_coefficients_wide;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients;
+#endif
+ /* now override with asm where appropriate */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+# ifndef FLAC__NO_ASM
+ if(encoder->private_->cpuinfo.use_asm) {
+# ifdef FLAC__CPU_IA32
+ FLAC__ASSERT(encoder->private_->cpuinfo.type == FLAC__CPUINFO_TYPE_IA32);
+# ifdef FLAC__HAS_NASM
+ if(encoder->private_->cpuinfo.data.ia32.sse) {
+ if(encoder->protected_->max_lpc_order < 4)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4;
+ else if(encoder->protected_->max_lpc_order < 8)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8;
+ else if(encoder->protected_->max_lpc_order < 12)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12;
+ else
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
+ }
+ else if(encoder->private_->cpuinfo.data.ia32._3dnow)
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow;
+ else
+ encoder->private_->local_lpc_compute_autocorrelation = FLAC__lpc_compute_autocorrelation_asm_ia32;
+ if(encoder->private_->cpuinfo.data.ia32.mmx) {
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx;
+ }
+ else {
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit = FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32;
+ }
+ if(encoder->private_->cpuinfo.data.ia32.mmx && encoder->private_->cpuinfo.data.ia32.cmov)
+ encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov;
+# endif /* FLAC__HAS_NASM */
+# endif /* FLAC__CPU_IA32 */
+ }
+# endif /* !FLAC__NO_ASM */
+#endif /* !FLAC__INTEGER_ONLY_LIBRARY */
+ /* finally override based on wide-ness if necessary */
+ if(encoder->private_->use_wide_by_block) {
+ encoder->private_->local_fixed_compute_best_predictor = FLAC__fixed_compute_best_predictor_wide;
+ }
+
+ /* set state to OK; from here on, errors are fatal and we'll override the state then */
+ encoder->protected_->state = FLAC__STREAM_ENCODER_OK;
+
+#if FLAC__HAS_OGG
+ encoder->private_->is_ogg = is_ogg;
+ if(is_ogg && !FLAC__ogg_encoder_aspect_init(&encoder->protected_->ogg_encoder_aspect)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+#endif
+
+ encoder->private_->read_callback = read_callback;
+ encoder->private_->write_callback = write_callback;
+ encoder->private_->seek_callback = seek_callback;
+ encoder->private_->tell_callback = tell_callback;
+ encoder->private_->metadata_callback = metadata_callback;
+ encoder->private_->client_data = client_data;
+
+ if(!resize_buffers_(encoder, encoder->protected_->blocksize)) {
+ /* the above function sets the state for us in case of an error */
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+
+ if(!FLAC__bitwriter_init(encoder->private_->frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+
+ /*
+ * Set up the verify stuff if necessary
+ */
+ if(encoder->protected_->verify) {
+ /*
+ * First, set up the fifo which will hold the
+ * original signal to compare against
+ */
+ encoder->private_->verify.input_fifo.size = encoder->protected_->blocksize+OVERREAD_;
+ for(i = 0; i < encoder->protected_->channels; i++) {
+ if(0 == (encoder->private_->verify.input_fifo.data[i] = (FLAC__int32*)malloc(sizeof(FLAC__int32) * encoder->private_->verify.input_fifo.size))) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+ }
+ encoder->private_->verify.input_fifo.tail = 0;
+
+ /*
+ * Now set up a stream decoder for verification
+ */
+ encoder->private_->verify.decoder = FLAC__stream_decoder_new();
+ if(0 == encoder->private_->verify.decoder) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+
+ if(FLAC__stream_decoder_init_stream(encoder->private_->verify.decoder, verify_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, verify_write_callback_, verify_metadata_callback_, verify_error_callback_, /*client_data=*/encoder) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+ }
+ encoder->private_->verify.error_stats.absolute_sample = 0;
+ encoder->private_->verify.error_stats.frame_number = 0;
+ encoder->private_->verify.error_stats.channel = 0;
+ encoder->private_->verify.error_stats.sample = 0;
+ encoder->private_->verify.error_stats.expected = 0;
+ encoder->private_->verify.error_stats.got = 0;
+
+ /*
+ * These must be done before we write any metadata, because that
+ * calls the write_callback, which uses these values.
+ */
+ encoder->private_->first_seekpoint_to_check = 0;
+ encoder->private_->samples_written = 0;
+ encoder->protected_->streaminfo_offset = 0;
+ encoder->protected_->seektable_offset = 0;
+ encoder->protected_->audio_offset = 0;
+
+ /*
+ * write the stream header
+ */
+ if(encoder->protected_->verify)
+ encoder->private_->verify.state_hint = ENCODER_IN_MAGIC;
+ if(!FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, FLAC__STREAM_SYNC, FLAC__STREAM_SYNC_LEN)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+ if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
+ /* the above function sets the state for us in case of an error */
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+
+ /*
+ * write the STREAMINFO metadata block
+ */
+ if(encoder->protected_->verify)
+ encoder->private_->verify.state_hint = ENCODER_IN_METADATA;
+ encoder->private_->streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
+ encoder->private_->streaminfo.is_last = false; /* we will have at a minimum a VORBIS_COMMENT afterwards */
+ encoder->private_->streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+ encoder->private_->streaminfo.data.stream_info.min_blocksize = encoder->protected_->blocksize; /* this encoder uses the same blocksize for the whole stream */
+ encoder->private_->streaminfo.data.stream_info.max_blocksize = encoder->protected_->blocksize;
+ encoder->private_->streaminfo.data.stream_info.min_framesize = 0; /* we don't know this yet; have to fill it in later */
+ encoder->private_->streaminfo.data.stream_info.max_framesize = 0; /* we don't know this yet; have to fill it in later */
+ encoder->private_->streaminfo.data.stream_info.sample_rate = encoder->protected_->sample_rate;
+ encoder->private_->streaminfo.data.stream_info.channels = encoder->protected_->channels;
+ encoder->private_->streaminfo.data.stream_info.bits_per_sample = encoder->protected_->bits_per_sample;
+ encoder->private_->streaminfo.data.stream_info.total_samples = encoder->protected_->total_samples_estimate; /* we will replace this later with the real total */
+ memset(encoder->private_->streaminfo.data.stream_info.md5sum, 0, 16); /* we don't know this yet; have to fill it in later */
+ FLAC__MD5Init(&encoder->private_->md5context);
+ if(!FLAC__add_metadata_block(&encoder->private_->streaminfo, encoder->private_->frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+ if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
+ /* the above function sets the state for us in case of an error */
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+
+ /*
+ * Now that the STREAMINFO block is written, we can init this to an
+ * absurdly-high value...
+ */
+ encoder->private_->streaminfo.data.stream_info.min_framesize = (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN) - 1;
+ /* ... and clear this to 0 */
+ encoder->private_->streaminfo.data.stream_info.total_samples = 0;
+
+ /*
+ * Check to see if the supplied metadata contains a VORBIS_COMMENT;
+ * if not, we will write an empty one (FLAC__add_metadata_block()
+ * automatically supplies the vendor string).
+ *
+ * WATCHOUT: the Ogg FLAC mapping requires us to write this block after
+ * the STREAMINFO. (In the case that metadata_has_vorbis_comment is
+ * true it will have already insured that the metadata list is properly
+ * ordered.)
+ */
+ if(!metadata_has_vorbis_comment) {
+ FLAC__StreamMetadata vorbis_comment;
+ vorbis_comment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+ vorbis_comment.is_last = (encoder->protected_->num_metadata_blocks == 0);
+ vorbis_comment.length = 4 + 4; /* MAGIC NUMBER */
+ vorbis_comment.data.vorbis_comment.vendor_string.length = 0;
+ vorbis_comment.data.vorbis_comment.vendor_string.entry = 0;
+ vorbis_comment.data.vorbis_comment.num_comments = 0;
+ vorbis_comment.data.vorbis_comment.comments = 0;
+ if(!FLAC__add_metadata_block(&vorbis_comment, encoder->private_->frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+ if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
+ /* the above function sets the state for us in case of an error */
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+ }
+
+ /*
+ * write the user's metadata blocks
+ */
+ for(i = 0; i < encoder->protected_->num_metadata_blocks; i++) {
+ encoder->protected_->metadata[i]->is_last = (i == encoder->protected_->num_metadata_blocks - 1);
+ if(!FLAC__add_metadata_block(encoder->protected_->metadata[i], encoder->private_->frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+ if(!write_bitbuffer_(encoder, 0, /*is_last_block=*/false)) {
+ /* the above function sets the state for us in case of an error */
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+ }
+
+ /* now that all the metadata is written, we save the stream offset */
+ if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &encoder->protected_->audio_offset, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) { /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+
+ if(encoder->protected_->verify)
+ encoder->private_->verify.state_hint = ENCODER_IN_AUDIO;
+
+ return FLAC__STREAM_ENCODER_INIT_STATUS_OK;
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_stream(
+ FLAC__StreamEncoder *encoder,
+ FLAC__StreamEncoderWriteCallback write_callback,
+ FLAC__StreamEncoderSeekCallback seek_callback,
+ FLAC__StreamEncoderTellCallback tell_callback,
+ FLAC__StreamEncoderMetadataCallback metadata_callback,
+ void *client_data
+)
+{
+ return init_stream_internal_(
+ encoder,
+ /*read_callback=*/0,
+ write_callback,
+ seek_callback,
+ tell_callback,
+ metadata_callback,
+ client_data,
+ /*is_ogg=*/false
+ );
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_stream(
+ FLAC__StreamEncoder *encoder,
+ FLAC__StreamEncoderReadCallback read_callback,
+ FLAC__StreamEncoderWriteCallback write_callback,
+ FLAC__StreamEncoderSeekCallback seek_callback,
+ FLAC__StreamEncoderTellCallback tell_callback,
+ FLAC__StreamEncoderMetadataCallback metadata_callback,
+ void *client_data
+)
+{
+ return init_stream_internal_(
+ encoder,
+ read_callback,
+ write_callback,
+ seek_callback,
+ tell_callback,
+ metadata_callback,
+ client_data,
+ /*is_ogg=*/true
+ );
+}
+
+static FLAC__StreamEncoderInitStatus init_FILE_internal_(
+ FLAC__StreamEncoder *encoder,
+ FILE *file,
+ FLAC__StreamEncoderProgressCallback progress_callback,
+ void *client_data,
+ FLAC__bool is_ogg
+)
+{
+ FLAC__StreamEncoderInitStatus init_status;
+
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != file);
+
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+ /* double protection */
+ if(file == 0) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+
+ /*
+ * To make sure that our file does not go unclosed after an error, we
+ * must assign the FILE pointer before any further error can occur in
+ * this routine.
+ */
+ if(file == stdout)
+ file = get_binary_stdout_(); /* just to be safe */
+
+ encoder->private_->file = file;
+
+ encoder->private_->progress_callback = progress_callback;
+ encoder->private_->bytes_written = 0;
+ encoder->private_->samples_written = 0;
+ encoder->private_->frames_written = 0;
+
+ init_status = init_stream_internal_(
+ encoder,
+ encoder->private_->file == stdout? 0 : is_ogg? file_read_callback_ : 0,
+ file_write_callback_,
+ encoder->private_->file == stdout? 0 : file_seek_callback_,
+ encoder->private_->file == stdout? 0 : file_tell_callback_,
+ /*metadata_callback=*/0,
+ client_data,
+ is_ogg
+ );
+ if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+ /* the above function sets the state for us in case of an error */
+ return init_status;
+ }
+
+ {
+ unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder);
+
+ FLAC__ASSERT(blocksize != 0);
+ encoder->private_->total_frames_estimate = (unsigned)((FLAC__stream_encoder_get_total_samples_estimate(encoder) + blocksize - 1) / blocksize);
+ }
+
+ return init_status;
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_FILE(
+ FLAC__StreamEncoder *encoder,
+ FILE *file,
+ FLAC__StreamEncoderProgressCallback progress_callback,
+ void *client_data
+)
+{
+ return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(
+ FLAC__StreamEncoder *encoder,
+ FILE *file,
+ FLAC__StreamEncoderProgressCallback progress_callback,
+ void *client_data
+)
+{
+ return init_FILE_internal_(encoder, file, progress_callback, client_data, /*is_ogg=*/true);
+}
+
+static FLAC__StreamEncoderInitStatus init_file_internal_(
+ FLAC__StreamEncoder *encoder,
+ const char *filename,
+ FLAC__StreamEncoderProgressCallback progress_callback,
+ void *client_data,
+ FLAC__bool is_ogg
+)
+{
+ FILE *file;
+
+ FLAC__ASSERT(0 != encoder);
+
+ /*
+ * To make sure that our file does not go unclosed after an error, we
+ * have to do the same entrance checks here that are later performed
+ * in FLAC__stream_encoder_init_FILE() before the FILE* is assigned.
+ */
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ALREADY_INITIALIZED;
+
+ file = filename? fopen(filename, "w+b") : stdout;
+
+ if(file == 0) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_IO_ERROR;
+ return FLAC__STREAM_ENCODER_INIT_STATUS_ENCODER_ERROR;
+ }
+
+ return init_FILE_internal_(encoder, file, progress_callback, client_data, is_ogg);
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(
+ FLAC__StreamEncoder *encoder,
+ const char *filename,
+ FLAC__StreamEncoderProgressCallback progress_callback,
+ void *client_data
+)
+{
+ return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/false);
+}
+
+FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_file(
+ FLAC__StreamEncoder *encoder,
+ const char *filename,
+ FLAC__StreamEncoderProgressCallback progress_callback,
+ void *client_data
+)
+{
+ return init_file_internal_(encoder, filename, progress_callback, client_data, /*is_ogg=*/true);
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder)
+{
+ FLAC__bool error = false;
+
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+
+ if(encoder->protected_->state == FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return true;
+
+ if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK && !encoder->private_->is_being_deleted) {
+ if(encoder->private_->current_sample_number != 0) {
+ const FLAC__bool is_fractional_block = encoder->protected_->blocksize != encoder->private_->current_sample_number;
+ encoder->protected_->blocksize = encoder->private_->current_sample_number;
+ if(!process_frame_(encoder, is_fractional_block, /*is_last_block=*/true))
+ error = true;
+ }
+ }
+
+ FLAC__MD5Final(encoder->private_->streaminfo.data.stream_info.md5sum, &encoder->private_->md5context);
+
+ if(!encoder->private_->is_being_deleted) {
+ if(encoder->protected_->state == FLAC__STREAM_ENCODER_OK) {
+ if(encoder->private_->seek_callback) {
+#if FLAC__HAS_OGG
+ if(encoder->private_->is_ogg)
+ update_ogg_metadata_(encoder);
+ else
+#endif
+ update_metadata_(encoder);
+
+ /* check if an error occurred while updating metadata */
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_OK)
+ error = true;
+ }
+ if(encoder->private_->metadata_callback)
+ encoder->private_->metadata_callback(encoder, &encoder->private_->streaminfo, encoder->private_->client_data);
+ }
+
+ if(encoder->protected_->verify && 0 != encoder->private_->verify.decoder && !FLAC__stream_decoder_finish(encoder->private_->verify.decoder)) {
+ if(!error)
+ encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA;
+ error = true;
+ }
+ }
+
+ if(0 != encoder->private_->file) {
+ if(encoder->private_->file != stdout)
+ fclose(encoder->private_->file);
+ encoder->private_->file = 0;
+ }
+
+#if FLAC__HAS_OGG
+ if(encoder->private_->is_ogg)
+ FLAC__ogg_encoder_aspect_finish(&encoder->protected_->ogg_encoder_aspect);
+#endif
+
+ free_(encoder);
+ set_defaults_(encoder);
+
+ if(!error)
+ encoder->protected_->state = FLAC__STREAM_ENCODER_UNINITIALIZED;
+
+ return !error;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncoder *encoder, long value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+#if FLAC__HAS_OGG
+ /* can't check encoder->private_->is_ogg since that's not set until init time */
+ FLAC__ogg_encoder_aspect_set_serial_number(&encoder->protected_->ogg_encoder_aspect, value);
+ return true;
+#else
+ (void)value;
+ return false;
+#endif
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+#ifndef FLAC__MANDATORY_VERIFY_WHILE_ENCODING
+ encoder->protected_->verify = value;
+#endif
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->streamable_subset = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->channels = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->bits_per_sample = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->sample_rate = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value)
+{
+ FLAC__bool ok = true;
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ if(value >= sizeof(compression_levels_)/sizeof(compression_levels_[0]))
+ value = sizeof(compression_levels_)/sizeof(compression_levels_[0]) - 1;
+ ok &= FLAC__stream_encoder_set_do_mid_side_stereo (encoder, compression_levels_[value].do_mid_side_stereo);
+ ok &= FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, compression_levels_[value].loose_mid_side_stereo);
+#if 0
+ /* was: */
+ ok &= FLAC__stream_encoder_set_apodization (encoder, compression_levels_[value].apodization);
+ /* but it's too hard to specify the string in a locale-specific way */
+#else
+ encoder->protected_->num_apodizations = 1;
+ encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
+ encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
+#endif
+ ok &= FLAC__stream_encoder_set_max_lpc_order (encoder, compression_levels_[value].max_lpc_order);
+ ok &= FLAC__stream_encoder_set_qlp_coeff_precision (encoder, compression_levels_[value].qlp_coeff_precision);
+ ok &= FLAC__stream_encoder_set_do_qlp_coeff_prec_search (encoder, compression_levels_[value].do_qlp_coeff_prec_search);
+ ok &= FLAC__stream_encoder_set_do_escape_coding (encoder, compression_levels_[value].do_escape_coding);
+ ok &= FLAC__stream_encoder_set_do_exhaustive_model_search (encoder, compression_levels_[value].do_exhaustive_model_search);
+ ok &= FLAC__stream_encoder_set_min_residual_partition_order(encoder, compression_levels_[value].min_residual_partition_order);
+ ok &= FLAC__stream_encoder_set_max_residual_partition_order(encoder, compression_levels_[value].max_residual_partition_order);
+ ok &= FLAC__stream_encoder_set_rice_parameter_search_dist (encoder, compression_levels_[value].rice_parameter_search_dist);
+ return ok;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->blocksize = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->do_mid_side_stereo = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->loose_mid_side_stereo = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *encoder, const char *specification)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ FLAC__ASSERT(0 != specification);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+#ifdef FLAC__INTEGER_ONLY_LIBRARY
+ (void)specification; /* silently ignore since we haven't integerized; will always use a rectangular window */
+#else
+ encoder->protected_->num_apodizations = 0;
+ while(1) {
+ const char *s = strchr(specification, ';');
+ const size_t n = s? (size_t)(s - specification) : strlen(specification);
+ if (n==8 && 0 == strncmp("bartlett" , specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT;
+ else if(n==13 && 0 == strncmp("bartlett_hann", specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BARTLETT_HANN;
+ else if(n==8 && 0 == strncmp("blackman" , specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN;
+ else if(n==26 && 0 == strncmp("blackman_harris_4term_92db", specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE;
+ else if(n==6 && 0 == strncmp("connes" , specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_CONNES;
+ else if(n==7 && 0 == strncmp("flattop" , specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_FLATTOP;
+ else if(n>7 && 0 == strncmp("gauss(" , specification, 6)) {
+ FLAC__real stddev = (FLAC__real)strtod(specification+6, 0);
+ if (stddev > 0.0 && stddev <= 0.5) {
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.gauss.stddev = stddev;
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_GAUSS;
+ }
+ }
+ else if(n==7 && 0 == strncmp("hamming" , specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HAMMING;
+ else if(n==4 && 0 == strncmp("hann" , specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_HANN;
+ else if(n==13 && 0 == strncmp("kaiser_bessel", specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_KAISER_BESSEL;
+ else if(n==7 && 0 == strncmp("nuttall" , specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_NUTTALL;
+ else if(n==9 && 0 == strncmp("rectangle" , specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_RECTANGLE;
+ else if(n==8 && 0 == strncmp("triangle" , specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TRIANGLE;
+ else if(n>7 && 0 == strncmp("tukey(" , specification, 6)) {
+ FLAC__real p = (FLAC__real)strtod(specification+6, 0);
+ if (p >= 0.0 && p <= 1.0) {
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = p;
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
+ }
+ }
+ else if(n==5 && 0 == strncmp("welch" , specification, n))
+ encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_WELCH;
+ if (encoder->protected_->num_apodizations == 32)
+ break;
+ if (s)
+ specification = s+1;
+ else
+ break;
+ }
+ if(encoder->protected_->num_apodizations == 0) {
+ encoder->protected_->num_apodizations = 1;
+ encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
+ encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
+ }
+#endif
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->max_lpc_order = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->qlp_coeff_precision = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_qlp_coeff_prec_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->do_qlp_coeff_prec_search = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_escape_coding(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+#if 0
+ /*@@@ deprecated: */
+ encoder->protected_->do_escape_coding = value;
+#else
+ (void)value;
+#endif
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__StreamEncoder *encoder, FLAC__bool value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->do_exhaustive_model_search = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->min_residual_partition_order = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->max_residual_partition_order = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+#if 0
+ /*@@@ deprecated: */
+ encoder->protected_->rice_parameter_search_dist = value;
+#else
+ (void)value;
+#endif
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__StreamEncoder *encoder, FLAC__uint64 value)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ encoder->protected_->total_samples_estimate = value;
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_UNINITIALIZED)
+ return false;
+ if(0 == metadata)
+ num_blocks = 0;
+ if(0 == num_blocks)
+ metadata = 0;
+ /* realloc() does not do exactly what we want so... */
+ if(encoder->protected_->metadata) {
+ free(encoder->protected_->metadata);
+ encoder->protected_->metadata = 0;
+ encoder->protected_->num_metadata_blocks = 0;
+ }
+ if(num_blocks) {
+ FLAC__StreamMetadata **m;
+ if(0 == (m = (FLAC__StreamMetadata**)malloc(sizeof(m[0]) * num_blocks)))
+ return false;
+ memcpy(m, metadata, sizeof(m[0]) * num_blocks);
+ encoder->protected_->metadata = m;
+ encoder->protected_->num_metadata_blocks = num_blocks;
+ }
+#if FLAC__HAS_OGG
+ if(!FLAC__ogg_encoder_aspect_set_num_metadata(&encoder->protected_->ogg_encoder_aspect, num_blocks))
+ return false;
+#endif
+ return true;
+}
+
+FLAC_API FLAC__StreamEncoderState FLAC__stream_encoder_get_state(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->state;
+}
+
+FLAC_API FLAC__StreamDecoderState FLAC__stream_encoder_get_verify_decoder_state(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->verify)
+ return FLAC__stream_decoder_get_state(encoder->private_->verify.decoder);
+ else
+ return FLAC__STREAM_DECODER_UNINITIALIZED;
+}
+
+FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR)
+ return FLAC__StreamEncoderStateString[encoder->protected_->state];
+ else
+ return FLAC__stream_decoder_get_resolved_state_string(encoder->private_->verify.decoder);
+}
+
+FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ if(0 != absolute_sample)
+ *absolute_sample = encoder->private_->verify.error_stats.absolute_sample;
+ if(0 != frame_number)
+ *frame_number = encoder->private_->verify.error_stats.frame_number;
+ if(0 != channel)
+ *channel = encoder->private_->verify.error_stats.channel;
+ if(0 != sample)
+ *sample = encoder->private_->verify.error_stats.sample;
+ if(0 != expected)
+ *expected = encoder->private_->verify.error_stats.expected;
+ if(0 != got)
+ *got = encoder->private_->verify.error_stats.got;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->verify;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->streamable_subset;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->channels;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->bits_per_sample;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->sample_rate;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->blocksize;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_mid_side_stereo(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->do_mid_side_stereo;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->loose_mid_side_stereo;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->max_lpc_order;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->qlp_coeff_precision;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_qlp_coeff_prec_search(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->do_qlp_coeff_prec_search;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_escape_coding(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->do_escape_coding;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->do_exhaustive_model_search;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->min_residual_partition_order;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->max_residual_partition_order;
+}
+
+FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->rice_parameter_search_dist;
+}
+
+FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ return encoder->protected_->total_samples_estimate;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples)
+{
+ unsigned i, j = 0, channel;
+ const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
+
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+
+ do {
+ const unsigned n = min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j);
+
+ if(encoder->protected_->verify)
+ append_to_verify_fifo_(&encoder->private_->verify.input_fifo, buffer, j, channels, n);
+
+ for(channel = 0; channel < channels; channel++)
+ memcpy(&encoder->private_->integer_signal[channel][encoder->private_->current_sample_number], &buffer[channel][j], sizeof(buffer[channel][0]) * n);
+
+ if(encoder->protected_->do_mid_side_stereo) {
+ FLAC__ASSERT(channels == 2);
+ /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
+ for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
+ encoder->private_->integer_signal_mid_side[1][i] = buffer[0][j] - buffer[1][j];
+ encoder->private_->integer_signal_mid_side[0][i] = (buffer[0][j] + buffer[1][j]) >> 1; /* NOTE: not the same as 'mid = (buffer[0][j] + buffer[1][j]) / 2' ! */
+ }
+ }
+ else
+ j += n;
+
+ encoder->private_->current_sample_number += n;
+
+ /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
+ if(encoder->private_->current_sample_number > blocksize) {
+ FLAC__ASSERT(encoder->private_->current_sample_number == blocksize+OVERREAD_);
+ FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
+ if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
+ return false;
+ /* move unprocessed overread samples to beginnings of arrays */
+ for(channel = 0; channel < channels; channel++)
+ encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize];
+ if(encoder->protected_->do_mid_side_stereo) {
+ encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][blocksize];
+ encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][blocksize];
+ }
+ encoder->private_->current_sample_number = 1;
+ }
+ } while(j < samples);
+
+ return true;
+}
+
+FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples)
+{
+ unsigned i, j, k, channel;
+ FLAC__int32 x, mid, side;
+ const unsigned channels = encoder->protected_->channels, blocksize = encoder->protected_->blocksize;
+
+ FLAC__ASSERT(0 != encoder);
+ FLAC__ASSERT(0 != encoder->private_);
+ FLAC__ASSERT(0 != encoder->protected_);
+ FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+
+ j = k = 0;
+ /*
+ * we have several flavors of the same basic loop, optimized for
+ * different conditions:
+ */
+ if(encoder->protected_->do_mid_side_stereo && channels == 2) {
+ /*
+ * stereo coding: unroll channel loop
+ */
+ do {
+ if(encoder->protected_->verify)
+ append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j));
+
+ /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
+ for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
+ encoder->private_->integer_signal[0][i] = mid = side = buffer[k++];
+ x = buffer[k++];
+ encoder->private_->integer_signal[1][i] = x;
+ mid += x;
+ side -= x;
+ mid >>= 1; /* NOTE: not the same as 'mid = (left + right) / 2' ! */
+ encoder->private_->integer_signal_mid_side[1][i] = side;
+ encoder->private_->integer_signal_mid_side[0][i] = mid;
+ }
+ encoder->private_->current_sample_number = i;
+ /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
+ if(i > blocksize) {
+ if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
+ return false;
+ /* move unprocessed overread samples to beginnings of arrays */
+ FLAC__ASSERT(i == blocksize+OVERREAD_);
+ FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
+ encoder->private_->integer_signal[0][0] = encoder->private_->integer_signal[0][blocksize];
+ encoder->private_->integer_signal[1][0] = encoder->private_->integer_signal[1][blocksize];
+ encoder->private_->integer_signal_mid_side[0][0] = encoder->private_->integer_signal_mid_side[0][blocksize];
+ encoder->private_->integer_signal_mid_side[1][0] = encoder->private_->integer_signal_mid_side[1][blocksize];
+ encoder->private_->current_sample_number = 1;
+ }
+ } while(j < samples);
+ }
+ else {
+ /*
+ * independent channel coding: buffer each channel in inner loop
+ */
+ do {
+ if(encoder->protected_->verify)
+ append_to_verify_fifo_interleaved_(&encoder->private_->verify.input_fifo, buffer, j, channels, min(blocksize+OVERREAD_-encoder->private_->current_sample_number, samples-j));
+
+ /* "i <= blocksize" to overread 1 sample; see comment in OVERREAD_ decl */
+ for(i = encoder->private_->current_sample_number; i <= blocksize && j < samples; i++, j++) {
+ for(channel = 0; channel < channels; channel++)
+ encoder->private_->integer_signal[channel][i] = buffer[k++];
+ }
+ encoder->private_->current_sample_number = i;
+ /* we only process if we have a full block + 1 extra sample; final block is always handled by FLAC__stream_encoder_finish() */
+ if(i > blocksize) {
+ if(!process_frame_(encoder, /*is_fractional_block=*/false, /*is_last_block=*/false))
+ return false;
+ /* move unprocessed overread samples to beginnings of arrays */
+ FLAC__ASSERT(i == blocksize+OVERREAD_);
+ FLAC__ASSERT(OVERREAD_ == 1); /* assert we only overread 1 sample which simplifies the rest of the code below */
+ for(channel = 0; channel < channels; channel++)
+ encoder->private_->integer_signal[channel][0] = encoder->private_->integer_signal[channel][blocksize];
+ encoder->private_->current_sample_number = 1;
+ }
+ } while(j < samples);
+ }
+
+ return true;
+}
+
+/***********************************************************************
+ *
+ * Private class methods
+ *
+ ***********************************************************************/
+
+void set_defaults_(FLAC__StreamEncoder *encoder)
+{
+ FLAC__ASSERT(0 != encoder);
+
+#ifdef FLAC__MANDATORY_VERIFY_WHILE_ENCODING
+ encoder->protected_->verify = true;
+#else
+ encoder->protected_->verify = false;
+#endif
+ encoder->protected_->streamable_subset = true;
+ encoder->protected_->do_mid_side_stereo = false;
+ encoder->protected_->loose_mid_side_stereo = false;
+ encoder->protected_->channels = 2;
+ encoder->protected_->bits_per_sample = 16;
+ encoder->protected_->sample_rate = 44100;
+ encoder->protected_->blocksize = 0;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ encoder->protected_->num_apodizations = 1;
+ encoder->protected_->apodizations[0].type = FLAC__APODIZATION_TUKEY;
+ encoder->protected_->apodizations[0].parameters.tukey.p = 0.5;
+#endif
+ encoder->protected_->max_lpc_order = 0;
+ encoder->protected_->qlp_coeff_precision = 0;
+ encoder->protected_->do_qlp_coeff_prec_search = false;
+ encoder->protected_->do_exhaustive_model_search = false;
+ encoder->protected_->do_escape_coding = false;
+ encoder->protected_->min_residual_partition_order = 0;
+ encoder->protected_->max_residual_partition_order = 0;
+ encoder->protected_->rice_parameter_search_dist = 0;
+ encoder->protected_->total_samples_estimate = 0;
+ encoder->protected_->metadata = 0;
+ encoder->protected_->num_metadata_blocks = 0;
+
+ encoder->private_->seek_table = 0;
+ encoder->private_->disable_constant_subframes = false;
+ encoder->private_->disable_fixed_subframes = false;
+ encoder->private_->disable_verbatim_subframes = false;
+#if FLAC__HAS_OGG
+ encoder->private_->is_ogg = false;
+#endif
+ encoder->private_->read_callback = 0;
+ encoder->private_->write_callback = 0;
+ encoder->private_->seek_callback = 0;
+ encoder->private_->tell_callback = 0;
+ encoder->private_->metadata_callback = 0;
+ encoder->private_->progress_callback = 0;
+ encoder->private_->client_data = 0;
+
+#if FLAC__HAS_OGG
+ FLAC__ogg_encoder_aspect_set_defaults(&encoder->protected_->ogg_encoder_aspect);
+#endif
+}
+
+void free_(FLAC__StreamEncoder *encoder)
+{
+ unsigned i, channel;
+
+ FLAC__ASSERT(0 != encoder);
+ if(encoder->protected_->metadata) {
+ free(encoder->protected_->metadata);
+ encoder->protected_->metadata = 0;
+ encoder->protected_->num_metadata_blocks = 0;
+ }
+ for(i = 0; i < encoder->protected_->channels; i++) {
+ if(0 != encoder->private_->integer_signal_unaligned[i]) {
+ free(encoder->private_->integer_signal_unaligned[i]);
+ encoder->private_->integer_signal_unaligned[i] = 0;
+ }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ if(0 != encoder->private_->real_signal_unaligned[i]) {
+ free(encoder->private_->real_signal_unaligned[i]);
+ encoder->private_->real_signal_unaligned[i] = 0;
+ }
+#endif
+ }
+ for(i = 0; i < 2; i++) {
+ if(0 != encoder->private_->integer_signal_mid_side_unaligned[i]) {
+ free(encoder->private_->integer_signal_mid_side_unaligned[i]);
+ encoder->private_->integer_signal_mid_side_unaligned[i] = 0;
+ }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ if(0 != encoder->private_->real_signal_mid_side_unaligned[i]) {
+ free(encoder->private_->real_signal_mid_side_unaligned[i]);
+ encoder->private_->real_signal_mid_side_unaligned[i] = 0;
+ }
+#endif
+ }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ for(i = 0; i < encoder->protected_->num_apodizations; i++) {
+ if(0 != encoder->private_->window_unaligned[i]) {
+ free(encoder->private_->window_unaligned[i]);
+ encoder->private_->window_unaligned[i] = 0;
+ }
+ }
+ if(0 != encoder->private_->windowed_signal_unaligned) {
+ free(encoder->private_->windowed_signal_unaligned);
+ encoder->private_->windowed_signal_unaligned = 0;
+ }
+#endif
+ for(channel = 0; channel < encoder->protected_->channels; channel++) {
+ for(i = 0; i < 2; i++) {
+ if(0 != encoder->private_->residual_workspace_unaligned[channel][i]) {
+ free(encoder->private_->residual_workspace_unaligned[channel][i]);
+ encoder->private_->residual_workspace_unaligned[channel][i] = 0;
+ }
+ }
+ }
+ for(channel = 0; channel < 2; channel++) {
+ for(i = 0; i < 2; i++) {
+ if(0 != encoder->private_->residual_workspace_mid_side_unaligned[channel][i]) {
+ free(encoder->private_->residual_workspace_mid_side_unaligned[channel][i]);
+ encoder->private_->residual_workspace_mid_side_unaligned[channel][i] = 0;
+ }
+ }
+ }
+ if(0 != encoder->private_->abs_residual_partition_sums_unaligned) {
+ free(encoder->private_->abs_residual_partition_sums_unaligned);
+ encoder->private_->abs_residual_partition_sums_unaligned = 0;
+ }
+ if(0 != encoder->private_->raw_bits_per_partition_unaligned) {
+ free(encoder->private_->raw_bits_per_partition_unaligned);
+ encoder->private_->raw_bits_per_partition_unaligned = 0;
+ }
+ if(encoder->protected_->verify) {
+ for(i = 0; i < encoder->protected_->channels; i++) {
+ if(0 != encoder->private_->verify.input_fifo.data[i]) {
+ free(encoder->private_->verify.input_fifo.data[i]);
+ encoder->private_->verify.input_fifo.data[i] = 0;
+ }
+ }
+ }
+ FLAC__bitwriter_free(encoder->private_->frame);
+}
+
+FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize)
+{
+ FLAC__bool ok;
+ unsigned i, channel;
+
+ FLAC__ASSERT(new_blocksize > 0);
+ FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+ FLAC__ASSERT(encoder->private_->current_sample_number == 0);
+
+ /* To avoid excessive malloc'ing, we only grow the buffer; no shrinking. */
+ if(new_blocksize <= encoder->private_->input_capacity)
+ return true;
+
+ ok = true;
+
+ /* WATCHOUT: FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx()
+ * requires that the input arrays (in our case the integer signals)
+ * have a buffer of up to 3 zeroes in front (at negative indices) for
+ * alignment purposes; we use 4 in front to keep the data well-aligned.
+ */
+
+ for(i = 0; ok && i < encoder->protected_->channels; i++) {
+ ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_unaligned[i], &encoder->private_->integer_signal[i]);
+ memset(encoder->private_->integer_signal[i], 0, sizeof(FLAC__int32)*4);
+ encoder->private_->integer_signal[i] += 4;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if 0 /* @@@ currently unused */
+ if(encoder->protected_->max_lpc_order > 0)
+ ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_unaligned[i], &encoder->private_->real_signal[i]);
+#endif
+#endif
+ }
+ for(i = 0; ok && i < 2; i++) {
+ ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize+4+OVERREAD_, &encoder->private_->integer_signal_mid_side_unaligned[i], &encoder->private_->integer_signal_mid_side[i]);
+ memset(encoder->private_->integer_signal_mid_side[i], 0, sizeof(FLAC__int32)*4);
+ encoder->private_->integer_signal_mid_side[i] += 4;
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+#if 0 /* @@@ currently unused */
+ if(encoder->protected_->max_lpc_order > 0)
+ ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize+OVERREAD_, &encoder->private_->real_signal_mid_side_unaligned[i], &encoder->private_->real_signal_mid_side[i]);
+#endif
+#endif
+ }
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ if(ok && encoder->protected_->max_lpc_order > 0) {
+ for(i = 0; ok && i < encoder->protected_->num_apodizations; i++)
+ ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->window_unaligned[i], &encoder->private_->window[i]);
+ ok = ok && FLAC__memory_alloc_aligned_real_array(new_blocksize, &encoder->private_->windowed_signal_unaligned, &encoder->private_->windowed_signal);
+ }
+#endif
+ for(channel = 0; ok && channel < encoder->protected_->channels; channel++) {
+ for(i = 0; ok && i < 2; i++) {
+ ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_unaligned[channel][i], &encoder->private_->residual_workspace[channel][i]);
+ }
+ }
+ for(channel = 0; ok && channel < 2; channel++) {
+ for(i = 0; ok && i < 2; i++) {
+ ok = ok && FLAC__memory_alloc_aligned_int32_array(new_blocksize, &encoder->private_->residual_workspace_mid_side_unaligned[channel][i], &encoder->private_->residual_workspace_mid_side[channel][i]);
+ }
+ }
+ /* the *2 is an approximation to the series 1 + 1/2 + 1/4 + ... that sums tree occupies in a flat array */
+ /*@@@ new_blocksize*2 is too pessimistic, but to fix, we need smarter logic because a smaller new_blocksize can actually increase the # of partitions; would require moving this out into a separate function, then checking its capacity against the need of the current blocksize&min/max_partition_order (and maybe predictor order) */
+ ok = ok && FLAC__memory_alloc_aligned_uint64_array(new_blocksize * 2, &encoder->private_->abs_residual_partition_sums_unaligned, &encoder->private_->abs_residual_partition_sums);
+ if(encoder->protected_->do_escape_coding)
+ ok = ok && FLAC__memory_alloc_aligned_unsigned_array(new_blocksize * 2, &encoder->private_->raw_bits_per_partition_unaligned, &encoder->private_->raw_bits_per_partition);
+
+ /* now adjust the windows if the blocksize has changed */
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ if(ok && new_blocksize != encoder->private_->input_capacity && encoder->protected_->max_lpc_order > 0) {
+ for(i = 0; ok && i < encoder->protected_->num_apodizations; i++) {
+ switch(encoder->protected_->apodizations[i].type) {
+ case FLAC__APODIZATION_BARTLETT:
+ FLAC__window_bartlett(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_BARTLETT_HANN:
+ FLAC__window_bartlett_hann(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_BLACKMAN:
+ FLAC__window_blackman(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE:
+ FLAC__window_blackman_harris_4term_92db_sidelobe(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_CONNES:
+ FLAC__window_connes(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_FLATTOP:
+ FLAC__window_flattop(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_GAUSS:
+ FLAC__window_gauss(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.gauss.stddev);
+ break;
+ case FLAC__APODIZATION_HAMMING:
+ FLAC__window_hamming(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_HANN:
+ FLAC__window_hann(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_KAISER_BESSEL:
+ FLAC__window_kaiser_bessel(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_NUTTALL:
+ FLAC__window_nuttall(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_RECTANGLE:
+ FLAC__window_rectangle(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_TRIANGLE:
+ FLAC__window_triangle(encoder->private_->window[i], new_blocksize);
+ break;
+ case FLAC__APODIZATION_TUKEY:
+ FLAC__window_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.tukey.p);
+ break;
+ case FLAC__APODIZATION_WELCH:
+ FLAC__window_welch(encoder->private_->window[i], new_blocksize);
+ break;
+ default:
+ FLAC__ASSERT(0);
+ /* double protection */
+ FLAC__window_hann(encoder->private_->window[i], new_blocksize);
+ break;
+ }
+ }
+ }
+#endif
+
+ if(ok)
+ encoder->private_->input_capacity = new_blocksize;
+ else
+ encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+
+ return ok;
+}
+
+FLAC__bool write_bitbuffer_(FLAC__StreamEncoder *encoder, unsigned samples, FLAC__bool is_last_block)
+{
+ const FLAC__byte *buffer;
+ size_t bytes;
+
+ FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame));
+
+ if(!FLAC__bitwriter_get_buffer(encoder->private_->frame, &buffer, &bytes)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ if(encoder->protected_->verify) {
+ encoder->private_->verify.output.data = buffer;
+ encoder->private_->verify.output.bytes = bytes;
+ if(encoder->private_->verify.state_hint == ENCODER_IN_MAGIC) {
+ encoder->private_->verify.needs_magic_hack = true;
+ }
+ else {
+ if(!FLAC__stream_decoder_process_single(encoder->private_->verify.decoder)) {
+ FLAC__bitwriter_release_buffer(encoder->private_->frame);
+ FLAC__bitwriter_clear(encoder->private_->frame);
+ if(encoder->protected_->state != FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA)
+ encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+ return false;
+ }
+ }
+ }
+
+ if(write_frame_(encoder, buffer, bytes, samples, is_last_block) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+ FLAC__bitwriter_release_buffer(encoder->private_->frame);
+ FLAC__bitwriter_clear(encoder->private_->frame);
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return false;
+ }
+
+ FLAC__bitwriter_release_buffer(encoder->private_->frame);
+ FLAC__bitwriter_clear(encoder->private_->frame);
+
+ if(samples > 0) {
+ encoder->private_->streaminfo.data.stream_info.min_framesize = min(bytes, encoder->private_->streaminfo.data.stream_info.min_framesize);
+ encoder->private_->streaminfo.data.stream_info.max_framesize = max(bytes, encoder->private_->streaminfo.data.stream_info.max_framesize);
+ }
+
+ return true;
+}
+
+FLAC__StreamEncoderWriteStatus write_frame_(FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, FLAC__bool is_last_block)
+{
+ FLAC__StreamEncoderWriteStatus status;
+ FLAC__uint64 output_position = 0;
+
+ /* FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED just means we didn't get the offset; no error */
+ if(encoder->private_->tell_callback && encoder->private_->tell_callback(encoder, &output_position, encoder->private_->client_data) == FLAC__STREAM_ENCODER_TELL_STATUS_ERROR) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+ }
+
+ /*
+ * Watch for the STREAMINFO block and first SEEKTABLE block to go by and store their offsets.
+ */
+ if(samples == 0) {
+ FLAC__MetadataType type = (buffer[0] & 0x7f);
+ if(type == FLAC__METADATA_TYPE_STREAMINFO)
+ encoder->protected_->streaminfo_offset = output_position;
+ else if(type == FLAC__METADATA_TYPE_SEEKTABLE && encoder->protected_->seektable_offset == 0)
+ encoder->protected_->seektable_offset = output_position;
+ }
+
+ /*
+ * Mark the current seek point if hit (if audio_offset == 0 that
+ * means we're still writing metadata and haven't hit the first
+ * frame yet)
+ */
+ if(0 != encoder->private_->seek_table && encoder->protected_->audio_offset > 0 && encoder->private_->seek_table->num_points > 0) {
+ const unsigned blocksize = FLAC__stream_encoder_get_blocksize(encoder);
+ const FLAC__uint64 frame_first_sample = encoder->private_->samples_written;
+ const FLAC__uint64 frame_last_sample = frame_first_sample + (FLAC__uint64)blocksize - 1;
+ FLAC__uint64 test_sample;
+ unsigned i;
+ for(i = encoder->private_->first_seekpoint_to_check; i < encoder->private_->seek_table->num_points; i++) {
+ test_sample = encoder->private_->seek_table->points[i].sample_number;
+ if(test_sample > frame_last_sample) {
+ break;
+ }
+ else if(test_sample >= frame_first_sample) {
+ encoder->private_->seek_table->points[i].sample_number = frame_first_sample;
+ encoder->private_->seek_table->points[i].stream_offset = output_position - encoder->protected_->audio_offset;
+ encoder->private_->seek_table->points[i].frame_samples = blocksize;
+ encoder->private_->first_seekpoint_to_check++;
+ /* DO NOT: "break;" and here's why:
+ * The seektable template may contain more than one target
+ * sample for any given frame; we will keep looping, generating
+ * duplicate seekpoints for them, and we'll clean it up later,
+ * just before writing the seektable back to the metadata.
+ */
+ }
+ else {
+ encoder->private_->first_seekpoint_to_check++;
+ }
+ }
+ }
+
+#if FLAC__HAS_OGG
+ if(encoder->private_->is_ogg) {
+ status = FLAC__ogg_encoder_aspect_write_callback_wrapper(
+ &encoder->protected_->ogg_encoder_aspect,
+ buffer,
+ bytes,
+ samples,
+ encoder->private_->current_frame_number,
+ is_last_block,
+ (FLAC__OggEncoderAspectWriteCallbackProxy)encoder->private_->write_callback,
+ encoder,
+ encoder->private_->client_data
+ );
+ }
+ else
+#endif
+ status = encoder->private_->write_callback(encoder, buffer, bytes, samples, encoder->private_->current_frame_number, encoder->private_->client_data);
+
+ if(status == FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+ encoder->private_->bytes_written += bytes;
+ encoder->private_->samples_written += samples;
+ /* we keep a high watermark on the number of frames written because
+ * when the encoder goes back to write metadata, 'current_frame'
+ * will drop back to 0.
+ */
+ encoder->private_->frames_written = max(encoder->private_->frames_written, encoder->private_->current_frame_number+1);
+ }
+ else
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+
+ return status;
+}
+
+/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks. */
+void update_metadata_(const FLAC__StreamEncoder *encoder)
+{
+ FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
+ const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo;
+ const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
+ const unsigned min_framesize = metadata->data.stream_info.min_framesize;
+ const unsigned max_framesize = metadata->data.stream_info.max_framesize;
+ const unsigned bps = metadata->data.stream_info.bits_per_sample;
+ FLAC__StreamEncoderSeekStatus seek_status;
+
+ FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
+
+ /* All this is based on intimate knowledge of the stream header
+ * layout, but a change to the header format that would break this
+ * would also break all streams encoded in the previous format.
+ */
+
+ /*
+ * Write MD5 signature
+ */
+ {
+ const unsigned md5_offset =
+ FLAC__STREAM_METADATA_HEADER_LENGTH +
+ (
+ FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN
+ ) / 8;
+
+ if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + md5_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+ if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return;
+ }
+ if(encoder->private_->write_callback(encoder, metadata->data.stream_info.md5sum, 16, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return;
+ }
+ }
+
+ /*
+ * Write total samples
+ */
+ {
+ const unsigned total_samples_byte_offset =
+ FLAC__STREAM_METADATA_HEADER_LENGTH +
+ (
+ FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN
+ - 4
+ ) / 8;
+
+ b[0] = ((FLAC__byte)(bps-1) << 4) | (FLAC__byte)((samples >> 32) & 0x0F);
+ b[1] = (FLAC__byte)((samples >> 24) & 0xFF);
+ b[2] = (FLAC__byte)((samples >> 16) & 0xFF);
+ b[3] = (FLAC__byte)((samples >> 8) & 0xFF);
+ b[4] = (FLAC__byte)(samples & 0xFF);
+ if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + total_samples_byte_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+ if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return;
+ }
+ if(encoder->private_->write_callback(encoder, b, 5, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return;
+ }
+ }
+
+ /*
+ * Write min/max framesize
+ */
+ {
+ const unsigned min_framesize_offset =
+ FLAC__STREAM_METADATA_HEADER_LENGTH +
+ (
+ FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
+ ) / 8;
+
+ b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF);
+ b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF);
+ b[2] = (FLAC__byte)(min_framesize & 0xFF);
+ b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF);
+ b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF);
+ b[5] = (FLAC__byte)(max_framesize & 0xFF);
+ if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->streaminfo_offset + min_framesize_offset, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+ if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return;
+ }
+ if(encoder->private_->write_callback(encoder, b, 6, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return;
+ }
+ }
+
+ /*
+ * Write seektable
+ */
+ if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
+ unsigned i;
+
+ FLAC__format_seektable_sort(encoder->private_->seek_table);
+
+ FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
+
+ if((seek_status = encoder->private_->seek_callback(encoder, encoder->protected_->seektable_offset + FLAC__STREAM_METADATA_HEADER_LENGTH, encoder->private_->client_data)) != FLAC__STREAM_ENCODER_SEEK_STATUS_OK) {
+ if(seek_status == FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR)
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return;
+ }
+
+ for(i = 0; i < encoder->private_->seek_table->num_points; i++) {
+ FLAC__uint64 xx;
+ unsigned x;
+ xx = encoder->private_->seek_table->points[i].sample_number;
+ b[7] = (FLAC__byte)xx; xx >>= 8;
+ b[6] = (FLAC__byte)xx; xx >>= 8;
+ b[5] = (FLAC__byte)xx; xx >>= 8;
+ b[4] = (FLAC__byte)xx; xx >>= 8;
+ b[3] = (FLAC__byte)xx; xx >>= 8;
+ b[2] = (FLAC__byte)xx; xx >>= 8;
+ b[1] = (FLAC__byte)xx; xx >>= 8;
+ b[0] = (FLAC__byte)xx; xx >>= 8;
+ xx = encoder->private_->seek_table->points[i].stream_offset;
+ b[15] = (FLAC__byte)xx; xx >>= 8;
+ b[14] = (FLAC__byte)xx; xx >>= 8;
+ b[13] = (FLAC__byte)xx; xx >>= 8;
+ b[12] = (FLAC__byte)xx; xx >>= 8;
+ b[11] = (FLAC__byte)xx; xx >>= 8;
+ b[10] = (FLAC__byte)xx; xx >>= 8;
+ b[9] = (FLAC__byte)xx; xx >>= 8;
+ b[8] = (FLAC__byte)xx; xx >>= 8;
+ x = encoder->private_->seek_table->points[i].frame_samples;
+ b[17] = (FLAC__byte)x; x >>= 8;
+ b[16] = (FLAC__byte)x; x >>= 8;
+ if(encoder->private_->write_callback(encoder, b, 18, 0, 0, encoder->private_->client_data) != FLAC__STREAM_ENCODER_WRITE_STATUS_OK) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_CLIENT_ERROR;
+ return;
+ }
+ }
+ }
+}
+
+#if FLAC__HAS_OGG
+/* Gets called when the encoding process has finished so that we can update the STREAMINFO and SEEKTABLE blocks. */
+void update_ogg_metadata_(FLAC__StreamEncoder *encoder)
+{
+ /* the # of bytes in the 1st packet that precede the STREAMINFO */
+ static const unsigned FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH =
+ FLAC__OGG_MAPPING_PACKET_TYPE_LENGTH +
+ FLAC__OGG_MAPPING_MAGIC_LENGTH +
+ FLAC__OGG_MAPPING_VERSION_MAJOR_LENGTH +
+ FLAC__OGG_MAPPING_VERSION_MINOR_LENGTH +
+ FLAC__OGG_MAPPING_NUM_HEADERS_LENGTH +
+ FLAC__STREAM_SYNC_LENGTH
+ ;
+ FLAC__byte b[max(6, FLAC__STREAM_METADATA_SEEKPOINT_LENGTH)];
+ const FLAC__StreamMetadata *metadata = &encoder->private_->streaminfo;
+ const FLAC__uint64 samples = metadata->data.stream_info.total_samples;
+ const unsigned min_framesize = metadata->data.stream_info.min_framesize;
+ const unsigned max_framesize = metadata->data.stream_info.max_framesize;
+ ogg_page page;
+
+ FLAC__ASSERT(metadata->type == FLAC__METADATA_TYPE_STREAMINFO);
+ FLAC__ASSERT(0 != encoder->private_->seek_callback);
+
+ /* Pre-check that client supports seeking, since we don't want the
+ * ogg_helper code to ever have to deal with this condition.
+ */
+ if(encoder->private_->seek_callback(encoder, 0, encoder->private_->client_data) == FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED)
+ return;
+
+ /* All this is based on intimate knowledge of the stream header
+ * layout, but a change to the header format that would break this
+ * would also break all streams encoded in the previous format.
+ */
+
+ /**
+ ** Write STREAMINFO stats
+ **/
+ simple_ogg_page__init(&page);
+ if(!simple_ogg_page__get_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
+ simple_ogg_page__clear(&page);
+ return; /* state already set */
+ }
+
+ /*
+ * Write MD5 signature
+ */
+ {
+ const unsigned md5_offset =
+ FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
+ FLAC__STREAM_METADATA_HEADER_LENGTH +
+ (
+ FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN
+ ) / 8;
+
+ if(md5_offset + 16 > (unsigned)page.body_len) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+ simple_ogg_page__clear(&page);
+ return;
+ }
+ memcpy(page.body + md5_offset, metadata->data.stream_info.md5sum, 16);
+ }
+
+ /*
+ * Write total samples
+ */
+ {
+ const unsigned total_samples_byte_offset =
+ FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
+ FLAC__STREAM_METADATA_HEADER_LENGTH +
+ (
+ FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN
+ - 4
+ ) / 8;
+
+ if(total_samples_byte_offset + 5 > (unsigned)page.body_len) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+ simple_ogg_page__clear(&page);
+ return;
+ }
+ b[0] = (FLAC__byte)page.body[total_samples_byte_offset] & 0xF0;
+ b[0] |= (FLAC__byte)((samples >> 32) & 0x0F);
+ b[1] = (FLAC__byte)((samples >> 24) & 0xFF);
+ b[2] = (FLAC__byte)((samples >> 16) & 0xFF);
+ b[3] = (FLAC__byte)((samples >> 8) & 0xFF);
+ b[4] = (FLAC__byte)(samples & 0xFF);
+ memcpy(page.body + total_samples_byte_offset, b, 5);
+ }
+
+ /*
+ * Write min/max framesize
+ */
+ {
+ const unsigned min_framesize_offset =
+ FIRST_OGG_PACKET_STREAMINFO_PREFIX_LENGTH +
+ FLAC__STREAM_METADATA_HEADER_LENGTH +
+ (
+ FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN +
+ FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN
+ ) / 8;
+
+ if(min_framesize_offset + 6 > (unsigned)page.body_len) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+ simple_ogg_page__clear(&page);
+ return;
+ }
+ b[0] = (FLAC__byte)((min_framesize >> 16) & 0xFF);
+ b[1] = (FLAC__byte)((min_framesize >> 8) & 0xFF);
+ b[2] = (FLAC__byte)(min_framesize & 0xFF);
+ b[3] = (FLAC__byte)((max_framesize >> 16) & 0xFF);
+ b[4] = (FLAC__byte)((max_framesize >> 8) & 0xFF);
+ b[5] = (FLAC__byte)(max_framesize & 0xFF);
+ memcpy(page.body + min_framesize_offset, b, 6);
+ }
+ if(!simple_ogg_page__set_at(encoder, encoder->protected_->streaminfo_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
+ simple_ogg_page__clear(&page);
+ return; /* state already set */
+ }
+ simple_ogg_page__clear(&page);
+
+ /*
+ * Write seektable
+ */
+ if(0 != encoder->private_->seek_table && encoder->private_->seek_table->num_points > 0 && encoder->protected_->seektable_offset > 0) {
+ unsigned i;
+ FLAC__byte *p;
+
+ FLAC__format_seektable_sort(encoder->private_->seek_table);
+
+ FLAC__ASSERT(FLAC__format_seektable_is_legal(encoder->private_->seek_table));
+
+ simple_ogg_page__init(&page);
+ if(!simple_ogg_page__get_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->read_callback, encoder->private_->client_data)) {
+ simple_ogg_page__clear(&page);
+ return; /* state already set */
+ }
+
+ if((FLAC__STREAM_METADATA_HEADER_LENGTH + 18*encoder->private_->seek_table->num_points) != (unsigned)page.body_len) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_OGG_ERROR;
+ simple_ogg_page__clear(&page);
+ return;
+ }
+
+ for(i = 0, p = page.body + FLAC__STREAM_METADATA_HEADER_LENGTH; i < encoder->private_->seek_table->num_points; i++, p += 18) {
+ FLAC__uint64 xx;
+ unsigned x;
+ xx = encoder->private_->seek_table->points[i].sample_number;
+ b[7] = (FLAC__byte)xx; xx >>= 8;
+ b[6] = (FLAC__byte)xx; xx >>= 8;
+ b[5] = (FLAC__byte)xx; xx >>= 8;
+ b[4] = (FLAC__byte)xx; xx >>= 8;
+ b[3] = (FLAC__byte)xx; xx >>= 8;
+ b[2] = (FLAC__byte)xx; xx >>= 8;
+ b[1] = (FLAC__byte)xx; xx >>= 8;
+ b[0] = (FLAC__byte)xx; xx >>= 8;
+ xx = encoder->private_->seek_table->points[i].stream_offset;
+ b[15] = (FLAC__byte)xx; xx >>= 8;
+ b[14] = (FLAC__byte)xx; xx >>= 8;
+ b[13] = (FLAC__byte)xx; xx >>= 8;
+ b[12] = (FLAC__byte)xx; xx >>= 8;
+ b[11] = (FLAC__byte)xx; xx >>= 8;
+ b[10] = (FLAC__byte)xx; xx >>= 8;
+ b[9] = (FLAC__byte)xx; xx >>= 8;
+ b[8] = (FLAC__byte)xx; xx >>= 8;
+ x = encoder->private_->seek_table->points[i].frame_samples;
+ b[17] = (FLAC__byte)x; x >>= 8;
+ b[16] = (FLAC__byte)x; x >>= 8;
+ memcpy(p, b, 18);
+ }
+
+ if(!simple_ogg_page__set_at(encoder, encoder->protected_->seektable_offset, &page, encoder->private_->seek_callback, encoder->private_->write_callback, encoder->private_->client_data)) {
+ simple_ogg_page__clear(&page);
+ return; /* state already set */
+ }
+ simple_ogg_page__clear(&page);
+ }
+}
+#endif
+
+FLAC__bool process_frame_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block, FLAC__bool is_last_block)
+{
+ FLAC__uint16 crc;
+ FLAC__ASSERT(encoder->protected_->state == FLAC__STREAM_ENCODER_OK);
+
+ /*
+ * Accumulate raw signal to the MD5 signature
+ */
+ if(!FLAC__MD5Accumulate(&encoder->private_->md5context, (const FLAC__int32 * const *)encoder->private_->integer_signal, encoder->protected_->channels, encoder->protected_->blocksize, (encoder->protected_->bits_per_sample+7) / 8)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ /*
+ * Process the frame header and subframes into the frame bitbuffer
+ */
+ if(!process_subframes_(encoder, is_fractional_block)) {
+ /* the above function sets the state for us in case of an error */
+ return false;
+ }
+
+ /*
+ * Zero-pad the frame to a byte_boundary
+ */
+ if(!FLAC__bitwriter_zero_pad_to_byte_boundary(encoder->private_->frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ /*
+ * CRC-16 the whole thing
+ */
+ FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(encoder->private_->frame));
+ if(
+ !FLAC__bitwriter_get_write_crc16(encoder->private_->frame, &crc) ||
+ !FLAC__bitwriter_write_raw_uint32(encoder->private_->frame, crc, FLAC__FRAME_FOOTER_CRC_LEN)
+ ) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_MEMORY_ALLOCATION_ERROR;
+ return false;
+ }
+
+ /*
+ * Write it
+ */
+ if(!write_bitbuffer_(encoder, encoder->protected_->blocksize, is_last_block)) {
+ /* the above function sets the state for us in case of an error */
+ return false;
+ }
+
+ /*
+ * Get ready for the next frame
+ */
+ encoder->private_->current_sample_number = 0;
+ encoder->private_->current_frame_number++;
+ encoder->private_->streaminfo.data.stream_info.total_samples += (FLAC__uint64)encoder->protected_->blocksize;
+
+ return true;
+}
+
+FLAC__bool process_subframes_(FLAC__StreamEncoder *encoder, FLAC__bool is_fractional_block)
+{
+ FLAC__FrameHeader frame_header;
+ unsigned channel, min_partition_order = encoder->protected_->min_residual_partition_order, max_partition_order;
+ FLAC__bool do_independent, do_mid_side;
+
+ /*
+ * Calculate the min,max Rice partition orders
+ */
+ if(is_fractional_block) {
+ max_partition_order = 0;
+ }
+ else {
+ max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize(encoder->protected_->blocksize);
+ max_partition_order = min(max_partition_order, encoder->protected_->max_residual_partition_order);
+ }
+ min_partition_order = min(min_partition_order, max_partition_order);
+
+ /*
+ * Setup the frame
+ */
+ frame_header.blocksize = encoder->protected_->blocksize;
+ frame_header.sample_rate = encoder->protected_->sample_rate;
+ frame_header.channels = encoder->protected_->channels;
+ frame_header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; /* the default unless the encoder determines otherwise */
+ frame_header.bits_per_sample = encoder->protected_->bits_per_sample;
+ frame_header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER;
+ frame_header.number.frame_number = encoder->private_->current_frame_number;
+
+ /*
+ * Figure out what channel assignments to try
+ */
+ if(encoder->protected_->do_mid_side_stereo) {
+ if(encoder->protected_->loose_mid_side_stereo) {
+ if(encoder->private_->loose_mid_side_stereo_frame_count == 0) {
+ do_independent = true;
+ do_mid_side = true;
+ }
+ else {
+ do_independent = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT);
+ do_mid_side = !do_independent;
+ }
+ }
+ else {
+ do_independent = true;
+ do_mid_side = true;
+ }
+ }
+ else {
+ do_independent = true;
+ do_mid_side = false;
+ }
+
+ FLAC__ASSERT(do_independent || do_mid_side);
+
+ /*
+ * Check for wasted bits; set effective bps for each subframe
+ */
+ if(do_independent) {
+ for(channel = 0; channel < encoder->protected_->channels; channel++) {
+ const unsigned w = get_wasted_bits_(encoder->private_->integer_signal[channel], encoder->protected_->blocksize);
+ encoder->private_->subframe_workspace[channel][0].wasted_bits = encoder->private_->subframe_workspace[channel][1].wasted_bits = w;
+ encoder->private_->subframe_bps[channel] = encoder->protected_->bits_per_sample - w;
+ }
+ }
+ if(do_mid_side) {
+ FLAC__ASSERT(encoder->protected_->channels == 2);
+ for(channel = 0; channel < 2; channel++) {
+ const unsigned w = get_wasted_bits_(encoder->private_->integer_signal_mid_side[channel], encoder->protected_->blocksize);
+ encoder->private_->subframe_workspace_mid_side[channel][0].wasted_bits = encoder->private_->subframe_workspace_mid_side[channel][1].wasted_bits = w;
+ encoder->private_->subframe_bps_mid_side[channel] = encoder->protected_->bits_per_sample - w + (channel==0? 0:1);
+ }
+ }
+
+ /*
+ * First do a normal encoding pass of each independent channel
+ */
+ if(do_independent) {
+ for(channel = 0; channel < encoder->protected_->channels; channel++) {
+ if(!
+ process_subframe_(
+ encoder,
+ min_partition_order,
+ max_partition_order,
+ &frame_header,
+ encoder->private_->subframe_bps[channel],
+ encoder->private_->integer_signal[channel],
+ encoder->private_->subframe_workspace_ptr[channel],
+ encoder->private_->partitioned_rice_contents_workspace_ptr[channel],
+ encoder->private_->residual_workspace[channel],
+ encoder->private_->best_subframe+channel,
+ encoder->private_->best_subframe_bits+channel
+ )
+ )
+ return false;
+ }
+ }
+
+ /*
+ * Now do mid and side channels if requested
+ */
+ if(do_mid_side) {
+ FLAC__ASSERT(encoder->protected_->channels == 2);
+
+ for(channel = 0; channel < 2; channel++) {
+ if(!
+ process_subframe_(
+ encoder,
+ min_partition_order,
+ max_partition_order,
+ &frame_header,
+ encoder->private_->subframe_bps_mid_side[channel],
+ encoder->private_->integer_signal_mid_side[channel],
+ encoder->private_->subframe_workspace_ptr_mid_side[channel],
+ encoder->private_->partitioned_rice_contents_workspace_ptr_mid_side[channel],
+ encoder->private_->residual_workspace_mid_side[channel],
+ encoder->private_->best_subframe_mid_side+channel,
+ encoder->private_->best_subframe_bits_mid_side+channel
+ )
+ )
+ return false;
+ }
+ }
+
+ /*
+ * Compose the frame bitbuffer
+ */
+ if(do_mid_side) {
+ unsigned left_bps = 0, right_bps = 0; /* initialized only to prevent superfluous compiler warning */
+ FLAC__Subframe *left_subframe = 0, *right_subframe = 0; /* initialized only to prevent superfluous compiler warning */
+ FLAC__ChannelAssignment channel_assignment;
+
+ FLAC__ASSERT(encoder->protected_->channels == 2);
+
+ if(encoder->protected_->loose_mid_side_stereo && encoder->private_->loose_mid_side_stereo_frame_count > 0) {
+ channel_assignment = (encoder->private_->last_channel_assignment == FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT? FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT : FLAC__CHANNEL_ASSIGNMENT_MID_SIDE);
+ }
+ else {
+ unsigned bits[4]; /* WATCHOUT - indexed by FLAC__ChannelAssignment */
+ unsigned min_bits;
+ int ca;
+
+ FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT == 0);
+ FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE == 1);
+ FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE == 2);
+ FLAC__ASSERT(FLAC__CHANNEL_ASSIGNMENT_MID_SIDE == 3);
+ FLAC__ASSERT(do_independent && do_mid_side);
+
+ /* We have to figure out which channel assignent results in the smallest frame */
+ bits[FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT] = encoder->private_->best_subframe_bits [0] + encoder->private_->best_subframe_bits [1];
+ bits[FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE ] = encoder->private_->best_subframe_bits [0] + encoder->private_->best_subframe_bits_mid_side[1];
+ bits[FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE ] = encoder->private_->best_subframe_bits [1] + encoder->private_->best_subframe_bits_mid_side[1];
+ bits[FLAC__CHANNEL_ASSIGNMENT_MID_SIDE ] = encoder->private_->best_subframe_bits_mid_side[0] + encoder->private_->best_subframe_bits_mid_side[1];
+
+ channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT;
+ min_bits = bits[channel_assignment];
+ for(ca = 1; ca <= 3; ca++) {
+ if(bits[ca] < min_bits) {
+ min_bits = bits[ca];
+ channel_assignment = (FLAC__ChannelAssignment)ca;
+ }
+ }
+ }
+
+ frame_header.channel_assignment = channel_assignment;
+
+ if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+ return false;
+ }
+
+ switch(channel_assignment) {
+ case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+ left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]];
+ right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ left_subframe = &encoder->private_->subframe_workspace [0][encoder->private_->best_subframe [0]];
+ right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ left_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+ right_subframe = &encoder->private_->subframe_workspace [1][encoder->private_->best_subframe [1]];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+ left_subframe = &encoder->private_->subframe_workspace_mid_side[0][encoder->private_->best_subframe_mid_side[0]];
+ right_subframe = &encoder->private_->subframe_workspace_mid_side[1][encoder->private_->best_subframe_mid_side[1]];
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+
+ switch(channel_assignment) {
+ case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+ left_bps = encoder->private_->subframe_bps [0];
+ right_bps = encoder->private_->subframe_bps [1];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ left_bps = encoder->private_->subframe_bps [0];
+ right_bps = encoder->private_->subframe_bps_mid_side[1];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ left_bps = encoder->private_->subframe_bps_mid_side[1];
+ right_bps = encoder->private_->subframe_bps [1];
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+ left_bps = encoder->private_->subframe_bps_mid_side[0];
+ right_bps = encoder->private_->subframe_bps_mid_side[1];
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+
+ /* note that encoder_add_subframe_ sets the state for us in case of an error */
+ if(!add_subframe_(encoder, frame_header.blocksize, left_bps , left_subframe , encoder->private_->frame))
+ return false;
+ if(!add_subframe_(encoder, frame_header.blocksize, right_bps, right_subframe, encoder->private_->frame))
+ return false;
+ }
+ else {
+ if(!FLAC__frame_add_header(&frame_header, encoder->private_->frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+ return false;
+ }
+
+ for(channel = 0; channel < encoder->protected_->channels; channel++) {
+ if(!add_subframe_(encoder, frame_header.blocksize, encoder->private_->subframe_bps[channel], &encoder->private_->subframe_workspace[channel][encoder->private_->best_subframe[channel]], encoder->private_->frame)) {
+ /* the above function sets the state for us in case of an error */
+ return false;
+ }
+ }
+ }
+
+ if(encoder->protected_->loose_mid_side_stereo) {
+ encoder->private_->loose_mid_side_stereo_frame_count++;
+ if(encoder->private_->loose_mid_side_stereo_frame_count >= encoder->private_->loose_mid_side_stereo_frames)
+ encoder->private_->loose_mid_side_stereo_frame_count = 0;
+ }
+
+ encoder->private_->last_channel_assignment = frame_header.channel_assignment;
+
+ return true;
+}
+
+FLAC__bool process_subframe_(
+ FLAC__StreamEncoder *encoder,
+ unsigned min_partition_order,
+ unsigned max_partition_order,
+ const FLAC__FrameHeader *frame_header,
+ unsigned subframe_bps,
+ const FLAC__int32 integer_signal[],
+ FLAC__Subframe *subframe[2],
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents[2],
+ FLAC__int32 *residual[2],
+ unsigned *best_subframe,
+ unsigned *best_bits
+)
+{
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ FLAC__float fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1];
+#else
+ FLAC__fixedpoint fixed_residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1];
+#endif
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ FLAC__double lpc_residual_bits_per_sample;
+ FLAC__real autoc[FLAC__MAX_LPC_ORDER+1]; /* WATCHOUT: the size is important even though encoder->protected_->max_lpc_order might be less; some asm routines need all the space */
+ FLAC__double lpc_error[FLAC__MAX_LPC_ORDER];
+ unsigned min_lpc_order, max_lpc_order, lpc_order;
+ unsigned min_qlp_coeff_precision, max_qlp_coeff_precision, qlp_coeff_precision;
+#endif
+ unsigned min_fixed_order, max_fixed_order, guess_fixed_order, fixed_order;
+ unsigned rice_parameter;
+ unsigned _candidate_bits, _best_bits;
+ unsigned _best_subframe;
+
+ FLAC__ASSERT(frame_header->blocksize > 0);
+
+ /* verbatim subframe is the baseline against which we measure other compressed subframes */
+ _best_subframe = 0;
+ if(encoder->private_->disable_verbatim_subframes && frame_header->blocksize >= FLAC__MAX_FIXED_ORDER)
+ _best_bits = UINT_MAX;
+ else
+ _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
+
+ if(frame_header->blocksize >= FLAC__MAX_FIXED_ORDER) {
+ unsigned signal_is_constant = false;
+ guess_fixed_order = encoder->private_->local_fixed_compute_best_predictor(integer_signal+FLAC__MAX_FIXED_ORDER, frame_header->blocksize-FLAC__MAX_FIXED_ORDER, fixed_residual_bits_per_sample);
+ /* check for constant subframe */
+ if(
+ !encoder->private_->disable_constant_subframes &&
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ fixed_residual_bits_per_sample[1] == 0.0
+#else
+ fixed_residual_bits_per_sample[1] == FLAC__FP_ZERO
+#endif
+ ) {
+ /* the above means it's possible all samples are the same value; now double-check it: */
+ unsigned i;
+ signal_is_constant = true;
+ for(i = 1; i < frame_header->blocksize; i++) {
+ if(integer_signal[0] != integer_signal[i]) {
+ signal_is_constant = false;
+ break;
+ }
+ }
+ }
+ if(signal_is_constant) {
+ _candidate_bits = evaluate_constant_subframe_(encoder, integer_signal[0], frame_header->blocksize, subframe_bps, subframe[!_best_subframe]);
+ if(_candidate_bits < _best_bits) {
+ _best_subframe = !_best_subframe;
+ _best_bits = _candidate_bits;
+ }
+ }
+ else {
+ if(!encoder->private_->disable_fixed_subframes || (encoder->protected_->max_lpc_order == 0 && _best_bits == UINT_MAX)) {
+ /* encode fixed */
+ if(encoder->protected_->do_exhaustive_model_search) {
+ min_fixed_order = 0;
+ max_fixed_order = FLAC__MAX_FIXED_ORDER;
+ }
+ else {
+ min_fixed_order = max_fixed_order = guess_fixed_order;
+ }
+ if(max_fixed_order >= frame_header->blocksize)
+ max_fixed_order = frame_header->blocksize - 1;
+ for(fixed_order = min_fixed_order; fixed_order <= max_fixed_order; fixed_order++) {
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ if(fixed_residual_bits_per_sample[fixed_order] >= (FLAC__float)subframe_bps)
+ continue; /* don't even try */
+ rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > 0.0)? (unsigned)(fixed_residual_bits_per_sample[fixed_order]+0.5) : 0; /* 0.5 is for rounding */
+#else
+ if(FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]) >= (int)subframe_bps)
+ continue; /* don't even try */
+ rice_parameter = (fixed_residual_bits_per_sample[fixed_order] > FLAC__FP_ZERO)? (unsigned)FLAC__fixedpoint_trunc(fixed_residual_bits_per_sample[fixed_order]+FLAC__FP_ONE_HALF) : 0; /* 0.5 is for rounding */
+#endif
+ rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */
+ if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+ fprintf(stderr, "clipping rice_parameter (%u -> %u) @0\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+ rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+ }
+ _candidate_bits =
+ evaluate_fixed_subframe_(
+ encoder,
+ integer_signal,
+ residual[!_best_subframe],
+ encoder->private_->abs_residual_partition_sums,
+ encoder->private_->raw_bits_per_partition,
+ frame_header->blocksize,
+ subframe_bps,
+ fixed_order,
+ rice_parameter,
+ min_partition_order,
+ max_partition_order,
+ encoder->protected_->do_escape_coding,
+ encoder->protected_->rice_parameter_search_dist,
+ subframe[!_best_subframe],
+ partitioned_rice_contents[!_best_subframe]
+ );
+ if(_candidate_bits < _best_bits) {
+ _best_subframe = !_best_subframe;
+ _best_bits = _candidate_bits;
+ }
+ }
+ }
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+ /* encode lpc */
+ if(encoder->protected_->max_lpc_order > 0) {
+ if(encoder->protected_->max_lpc_order >= frame_header->blocksize)
+ max_lpc_order = frame_header->blocksize-1;
+ else
+ max_lpc_order = encoder->protected_->max_lpc_order;
+ if(max_lpc_order > 0) {
+ unsigned a;
+ for (a = 0; a < encoder->protected_->num_apodizations; a++) {
+ FLAC__lpc_window_data(integer_signal, encoder->private_->window[a], encoder->private_->windowed_signal, frame_header->blocksize);
+ encoder->private_->local_lpc_compute_autocorrelation(encoder->private_->windowed_signal, frame_header->blocksize, max_lpc_order+1, autoc);
+ /* if autoc[0] == 0.0, the signal is constant and we usually won't get here, but it can happen */
+ if(autoc[0] != 0.0) {
+ FLAC__lpc_compute_lp_coefficients(autoc, &max_lpc_order, encoder->private_->lp_coeff, lpc_error);
+ if(encoder->protected_->do_exhaustive_model_search) {
+ min_lpc_order = 1;
+ }
+ else {
+ const unsigned guess_lpc_order =
+ FLAC__lpc_compute_best_order(
+ lpc_error,
+ max_lpc_order,
+ frame_header->blocksize,
+ subframe_bps + (
+ encoder->protected_->do_qlp_coeff_prec_search?
+ FLAC__MIN_QLP_COEFF_PRECISION : /* have to guess; use the min possible size to avoid accidentally favoring lower orders */
+ encoder->protected_->qlp_coeff_precision
+ )
+ );
+ min_lpc_order = max_lpc_order = guess_lpc_order;
+ }
+ if(max_lpc_order >= frame_header->blocksize)
+ max_lpc_order = frame_header->blocksize - 1;
+ for(lpc_order = min_lpc_order; lpc_order <= max_lpc_order; lpc_order++) {
+ lpc_residual_bits_per_sample = FLAC__lpc_compute_expected_bits_per_residual_sample(lpc_error[lpc_order-1], frame_header->blocksize-lpc_order);
+ if(lpc_residual_bits_per_sample >= (FLAC__double)subframe_bps)
+ continue; /* don't even try */
+ rice_parameter = (lpc_residual_bits_per_sample > 0.0)? (unsigned)(lpc_residual_bits_per_sample+0.5) : 0; /* 0.5 is for rounding */
+ rice_parameter++; /* to account for the signed->unsigned conversion during rice coding */
+ if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+ fprintf(stderr, "clipping rice_parameter (%u -> %u) @1\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+ rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+ }
+ if(encoder->protected_->do_qlp_coeff_prec_search) {
+ min_qlp_coeff_precision = FLAC__MIN_QLP_COEFF_PRECISION;
+ /* try to ensure a 32-bit datapath throughout for 16bps(+1bps for side channel) or less */
+ if(subframe_bps <= 17) {
+ max_qlp_coeff_precision = min(32 - subframe_bps - lpc_order, FLAC__MAX_QLP_COEFF_PRECISION);
+ max_qlp_coeff_precision = max(max_qlp_coeff_precision, min_qlp_coeff_precision);
+ }
+ else
+ max_qlp_coeff_precision = FLAC__MAX_QLP_COEFF_PRECISION;
+ }
+ else {
+ min_qlp_coeff_precision = max_qlp_coeff_precision = encoder->protected_->qlp_coeff_precision;
+ }
+ for(qlp_coeff_precision = min_qlp_coeff_precision; qlp_coeff_precision <= max_qlp_coeff_precision; qlp_coeff_precision++) {
+ _candidate_bits =
+ evaluate_lpc_subframe_(
+ encoder,
+ integer_signal,
+ residual[!_best_subframe],
+ encoder->private_->abs_residual_partition_sums,
+ encoder->private_->raw_bits_per_partition,
+ encoder->private_->lp_coeff[lpc_order-1],
+ frame_header->blocksize,
+ subframe_bps,
+ lpc_order,
+ qlp_coeff_precision,
+ rice_parameter,
+ min_partition_order,
+ max_partition_order,
+ encoder->protected_->do_escape_coding,
+ encoder->protected_->rice_parameter_search_dist,
+ subframe[!_best_subframe],
+ partitioned_rice_contents[!_best_subframe]
+ );
+ if(_candidate_bits > 0) { /* if == 0, there was a problem quantizing the lpcoeffs */
+ if(_candidate_bits < _best_bits) {
+ _best_subframe = !_best_subframe;
+ _best_bits = _candidate_bits;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
+ }
+ }
+
+ /* under rare circumstances this can happen when all but lpc subframe types are disabled: */
+ if(_best_bits == UINT_MAX) {
+ FLAC__ASSERT(_best_subframe == 0);
+ _best_bits = evaluate_verbatim_subframe_(encoder, integer_signal, frame_header->blocksize, subframe_bps, subframe[_best_subframe]);
+ }
+
+ *best_subframe = _best_subframe;
+ *best_bits = _best_bits;
+
+ return true;
+}
+
+FLAC__bool add_subframe_(
+ FLAC__StreamEncoder *encoder,
+ unsigned blocksize,
+ unsigned subframe_bps,
+ const FLAC__Subframe *subframe,
+ FLAC__BitWriter *frame
+)
+{
+ switch(subframe->type) {
+ case FLAC__SUBFRAME_TYPE_CONSTANT:
+ if(!FLAC__subframe_add_constant(&(subframe->data.constant), subframe_bps, subframe->wasted_bits, frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+ return false;
+ }
+ break;
+ case FLAC__SUBFRAME_TYPE_FIXED:
+ if(!FLAC__subframe_add_fixed(&(subframe->data.fixed), blocksize - subframe->data.fixed.order, subframe_bps, subframe->wasted_bits, frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+ return false;
+ }
+ break;
+ case FLAC__SUBFRAME_TYPE_LPC:
+ if(!FLAC__subframe_add_lpc(&(subframe->data.lpc), blocksize - subframe->data.lpc.order, subframe_bps, subframe->wasted_bits, frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+ return false;
+ }
+ break;
+ case FLAC__SUBFRAME_TYPE_VERBATIM:
+ if(!FLAC__subframe_add_verbatim(&(subframe->data.verbatim), blocksize, subframe_bps, subframe->wasted_bits, frame)) {
+ encoder->protected_->state = FLAC__STREAM_ENCODER_FRAMING_ERROR;
+ return false;
+ }
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+
+ return true;
+}
+
+#define SPOTCHECK_ESTIMATE 0
+#if SPOTCHECK_ESTIMATE
+static void spotcheck_subframe_estimate_(
+ FLAC__StreamEncoder *encoder,
+ unsigned blocksize,
+ unsigned subframe_bps,
+ const FLAC__Subframe *subframe,
+ unsigned estimate
+)
+{
+ FLAC__bool ret;
+ FLAC__BitWriter *frame = FLAC__bitwriter_new();
+ if(frame == 0) {
+ fprintf(stderr, "EST: can't allocate frame\n");
+ return;
+ }
+ if(!FLAC__bitwriter_init(frame)) {
+ fprintf(stderr, "EST: can't init frame\n");
+ return;
+ }
+ ret = add_subframe_(encoder, blocksize, subframe_bps, subframe, frame);
+ FLAC__ASSERT(ret);
+ {
+ const unsigned actual = FLAC__bitwriter_get_input_bits_unconsumed(frame);
+ if(estimate != actual)
+ fprintf(stderr, "EST: bad, frame#%u sub#%%d type=%8s est=%u, actual=%u, delta=%d\n", encoder->private_->current_frame_number, FLAC__SubframeTypeString[subframe->type], estimate, actual, (int)actual-(int)estimate);
+ }
+ FLAC__bitwriter_delete(frame);
+}
+#endif
+
+unsigned evaluate_constant_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const FLAC__int32 signal,
+ unsigned blocksize,
+ unsigned subframe_bps,
+ FLAC__Subframe *subframe
+)
+{
+ unsigned estimate;
+ subframe->type = FLAC__SUBFRAME_TYPE_CONSTANT;
+ subframe->data.constant.value = signal;
+
+ estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + subframe_bps;
+
+#if SPOTCHECK_ESTIMATE
+ spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#else
+ (void)encoder, (void)blocksize;
+#endif
+
+ return estimate;
+}
+
+unsigned evaluate_fixed_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const FLAC__int32 signal[],
+ FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ unsigned raw_bits_per_partition[],
+ unsigned blocksize,
+ unsigned subframe_bps,
+ unsigned order,
+ unsigned rice_parameter,
+ unsigned min_partition_order,
+ unsigned max_partition_order,
+ FLAC__bool do_escape_coding,
+ unsigned rice_parameter_search_dist,
+ FLAC__Subframe *subframe,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+)
+{
+ unsigned i, residual_bits, estimate;
+ const unsigned residual_samples = blocksize - order;
+
+ FLAC__fixed_compute_residual(signal+order, residual_samples, order, residual);
+
+ subframe->type = FLAC__SUBFRAME_TYPE_FIXED;
+
+ subframe->data.fixed.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
+ subframe->data.fixed.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
+ subframe->data.fixed.residual = residual;
+
+ residual_bits =
+ find_best_partition_order_(
+ encoder->private_,
+ residual,
+ abs_residual_partition_sums,
+ raw_bits_per_partition,
+ residual_samples,
+ order,
+ rice_parameter,
+ min_partition_order,
+ max_partition_order,
+ subframe_bps,
+ do_escape_coding,
+ rice_parameter_search_dist,
+ &subframe->data.fixed.entropy_coding_method.data.partitioned_rice
+ );
+
+ subframe->data.fixed.order = order;
+ for(i = 0; i < order; i++)
+ subframe->data.fixed.warmup[i] = signal[i];
+
+ estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (order * subframe_bps) + residual_bits;
+
+#if SPOTCHECK_ESTIMATE
+ spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#endif
+
+ return estimate;
+}
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+unsigned evaluate_lpc_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const FLAC__int32 signal[],
+ FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ unsigned raw_bits_per_partition[],
+ const FLAC__real lp_coeff[],
+ unsigned blocksize,
+ unsigned subframe_bps,
+ unsigned order,
+ unsigned qlp_coeff_precision,
+ unsigned rice_parameter,
+ unsigned min_partition_order,
+ unsigned max_partition_order,
+ FLAC__bool do_escape_coding,
+ unsigned rice_parameter_search_dist,
+ FLAC__Subframe *subframe,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents
+)
+{
+ FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
+ unsigned i, residual_bits, estimate;
+ int quantization, ret;
+ const unsigned residual_samples = blocksize - order;
+
+ /* try to keep qlp coeff precision such that only 32-bit math is required for decode of <=16bps streams */
+ if(subframe_bps <= 16) {
+ FLAC__ASSERT(order > 0);
+ FLAC__ASSERT(order <= FLAC__MAX_LPC_ORDER);
+ qlp_coeff_precision = min(qlp_coeff_precision, 32 - subframe_bps - FLAC__bitmath_ilog2(order));
+ }
+
+ ret = FLAC__lpc_quantize_coefficients(lp_coeff, order, qlp_coeff_precision, qlp_coeff, &quantization);
+ if(ret != 0)
+ return 0; /* this is a hack to indicate to the caller that we can't do lp at this order on this subframe */
+
+ if(subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order) <= 32)
+ if(subframe_bps <= 16 && qlp_coeff_precision <= 16)
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_16bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+ else
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+ else
+ encoder->private_->local_lpc_compute_residual_from_qlp_coefficients_64bit(signal+order, residual_samples, qlp_coeff, order, quantization, residual);
+
+ subframe->type = FLAC__SUBFRAME_TYPE_LPC;
+
+ subframe->data.lpc.entropy_coding_method.type = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE;
+ subframe->data.lpc.entropy_coding_method.data.partitioned_rice.contents = partitioned_rice_contents;
+ subframe->data.lpc.residual = residual;
+
+ residual_bits =
+ find_best_partition_order_(
+ encoder->private_,
+ residual,
+ abs_residual_partition_sums,
+ raw_bits_per_partition,
+ residual_samples,
+ order,
+ rice_parameter,
+ min_partition_order,
+ max_partition_order,
+ subframe_bps,
+ do_escape_coding,
+ rice_parameter_search_dist,
+ &subframe->data.lpc.entropy_coding_method.data.partitioned_rice
+ );
+
+ subframe->data.lpc.order = order;
+ subframe->data.lpc.qlp_coeff_precision = qlp_coeff_precision;
+ subframe->data.lpc.quantization_level = quantization;
+ memcpy(subframe->data.lpc.qlp_coeff, qlp_coeff, sizeof(FLAC__int32)*FLAC__MAX_LPC_ORDER);
+ for(i = 0; i < order; i++)
+ subframe->data.lpc.warmup[i] = signal[i];
+
+ estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN + FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN + (order * (qlp_coeff_precision + subframe_bps)) + residual_bits;
+
+#if SPOTCHECK_ESTIMATE
+ spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#endif
+
+ return estimate;
+}
+#endif
+
+unsigned evaluate_verbatim_subframe_(
+ FLAC__StreamEncoder *encoder,
+ const FLAC__int32 signal[],
+ unsigned blocksize,
+ unsigned subframe_bps,
+ FLAC__Subframe *subframe
+)
+{
+ unsigned estimate;
+
+ subframe->type = FLAC__SUBFRAME_TYPE_VERBATIM;
+
+ subframe->data.verbatim.data = signal;
+
+ estimate = FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN + subframe->wasted_bits + (blocksize * subframe_bps);
+
+#if SPOTCHECK_ESTIMATE
+ spotcheck_subframe_estimate_(encoder, blocksize, subframe_bps, subframe, estimate);
+#else
+ (void)encoder;
+#endif
+
+ return estimate;
+}
+
+unsigned find_best_partition_order_(
+ FLAC__StreamEncoderPrivate *private_,
+ const FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ unsigned raw_bits_per_partition[],
+ unsigned residual_samples,
+ unsigned predictor_order,
+ unsigned rice_parameter,
+ unsigned min_partition_order,
+ unsigned max_partition_order,
+ unsigned bps,
+ FLAC__bool do_escape_coding,
+ unsigned rice_parameter_search_dist,
+ FLAC__EntropyCodingMethod_PartitionedRice *best_partitioned_rice
+)
+{
+ unsigned residual_bits, best_residual_bits = 0;
+ unsigned best_parameters_index = 0;
+ const unsigned blocksize = residual_samples + predictor_order;
+
+ max_partition_order = FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(max_partition_order, blocksize, predictor_order);
+ min_partition_order = min(min_partition_order, max_partition_order);
+
+ precompute_partition_info_sums_(residual, abs_residual_partition_sums, residual_samples, predictor_order, min_partition_order, max_partition_order, bps);
+
+ if(do_escape_coding)
+ precompute_partition_info_escapes_(residual, raw_bits_per_partition, residual_samples, predictor_order, min_partition_order, max_partition_order);
+
+ {
+ int partition_order;
+ unsigned sum;
+
+ for(partition_order = (int)max_partition_order, sum = 0; partition_order >= (int)min_partition_order; partition_order--) {
+ if(!
+ set_partitioned_rice_(
+#ifdef EXACT_RICE_BITS_CALCULATION
+ residual,
+#endif
+ abs_residual_partition_sums+sum,
+ raw_bits_per_partition+sum,
+ residual_samples,
+ predictor_order,
+ rice_parameter,
+ rice_parameter_search_dist,
+ (unsigned)partition_order,
+ do_escape_coding,
+ &private_->partitioned_rice_contents_extra[!best_parameters_index],
+ &residual_bits
+ )
+ )
+ {
+ FLAC__ASSERT(best_residual_bits != 0);
+ break;
+ }
+ sum += 1u << partition_order;
+ if(best_residual_bits == 0 || residual_bits < best_residual_bits) {
+ best_residual_bits = residual_bits;
+ best_parameters_index = !best_parameters_index;
+ best_partitioned_rice->order = partition_order;
+ }
+ }
+ }
+
+ /*
+ * We are allowed to de-const the pointer based on our special knowledge;
+ * it is const to the outside world.
+ */
+ {
+ FLAC__EntropyCodingMethod_PartitionedRiceContents* best_partitioned_rice_contents = (FLAC__EntropyCodingMethod_PartitionedRiceContents*)best_partitioned_rice->contents;
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(best_partitioned_rice_contents, max(6, best_partitioned_rice->order));
+ memcpy(best_partitioned_rice_contents->parameters, private_->partitioned_rice_contents_extra[best_parameters_index].parameters, sizeof(unsigned)*(1<<(best_partitioned_rice->order)));
+ memcpy(best_partitioned_rice_contents->raw_bits, private_->partitioned_rice_contents_extra[best_parameters_index].raw_bits, sizeof(unsigned)*(1<<(best_partitioned_rice->order)));
+ }
+
+ return best_residual_bits;
+}
+
+#if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
+extern void precompute_partition_info_sums_32bit_asm_ia32_(
+ const FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ unsigned blocksize,
+ unsigned predictor_order,
+ unsigned min_partition_order,
+ unsigned max_partition_order
+);
+#endif
+
+void precompute_partition_info_sums_(
+ const FLAC__int32 residual[],
+ FLAC__uint64 abs_residual_partition_sums[],
+ unsigned residual_samples,
+ unsigned predictor_order,
+ unsigned min_partition_order,
+ unsigned max_partition_order,
+ unsigned bps
+)
+{
+ const unsigned default_partition_samples = (residual_samples + predictor_order) >> max_partition_order;
+ unsigned partitions = 1u << max_partition_order;
+
+ FLAC__ASSERT(default_partition_samples > predictor_order);
+
+#if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM
+ if(FLAC__bitmath_ilog2(default_partition_samples) + bps < 32) { /* very slightly pessimistic but still catches all common cases */
+ precompute_partition_info_sums_32bit_asm_ia32_(residual, abs_residual_partition_sums, residual_samples + predictor_order, predictor_order, min_partition_order, max_partition_order);
+ return;
+ }
+#endif
+
+ /* first do max_partition_order */
+ {
+ unsigned partition, residual_sample, end = (unsigned)(-(int)predictor_order);
+ if(FLAC__bitmath_ilog2(default_partition_samples) + bps < 32) { /* very slightly pessimistic but still catches all common cases */
+ FLAC__uint32 abs_residual_partition_sum;
+
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ end += default_partition_samples;
+ abs_residual_partition_sum = 0;
+ for( ; residual_sample < end; residual_sample++)
+ abs_residual_partition_sum += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */
+ abs_residual_partition_sums[partition] = abs_residual_partition_sum;
+ }
+ }
+ else { /* have to pessimistically use 64 bits for accumulator */
+ FLAC__uint64 abs_residual_partition_sum;
+
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ end += default_partition_samples;
+ abs_residual_partition_sum = 0;
+ for( ; residual_sample < end; residual_sample++)
+ abs_residual_partition_sum += abs(residual[residual_sample]); /* abs(INT_MIN) is undefined, but if the residual is INT_MIN we have bigger problems */
+ abs_residual_partition_sums[partition] = abs_residual_partition_sum;
+ }
+ }
+ }
+
+ /* now merge partitions for lower orders */
+ {
+ unsigned from_partition = 0, to_partition = partitions;
+ int partition_order;
+ for(partition_order = (int)max_partition_order - 1; partition_order >= (int)min_partition_order; partition_order--) {
+ unsigned i;
+ partitions >>= 1;
+ for(i = 0; i < partitions; i++) {
+ abs_residual_partition_sums[to_partition++] =
+ abs_residual_partition_sums[from_partition ] +
+ abs_residual_partition_sums[from_partition+1];
+ from_partition += 2;
+ }
+ }
+ }
+}
+
+void precompute_partition_info_escapes_(
+ const FLAC__int32 residual[],
+ unsigned raw_bits_per_partition[],
+ unsigned residual_samples,
+ unsigned predictor_order,
+ unsigned min_partition_order,
+ unsigned max_partition_order
+)
+{
+ int partition_order;
+ unsigned from_partition, to_partition = 0;
+ const unsigned blocksize = residual_samples + predictor_order;
+
+ /* first do max_partition_order */
+ for(partition_order = (int)max_partition_order; partition_order >= 0; partition_order--) {
+ FLAC__int32 r;
+ FLAC__uint32 rmax;
+ unsigned partition, partition_sample, partition_samples, residual_sample;
+ const unsigned partitions = 1u << partition_order;
+ const unsigned default_partition_samples = blocksize >> partition_order;
+
+ FLAC__ASSERT(default_partition_samples > predictor_order);
+
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ partition_samples = default_partition_samples;
+ if(partition == 0)
+ partition_samples -= predictor_order;
+ rmax = 0;
+ for(partition_sample = 0; partition_sample < partition_samples; partition_sample++) {
+ r = residual[residual_sample++];
+ /* OPT: maybe faster: rmax |= r ^ (r>>31) */
+ if(r < 0)
+ rmax |= ~r;
+ else
+ rmax |= r;
+ }
+ /* now we know all residual values are in the range [-rmax-1,rmax] */
+ raw_bits_per_partition[partition] = rmax? FLAC__bitmath_ilog2(rmax) + 2 : 1;
+ }
+ to_partition = partitions;
+ break; /*@@@ yuck, should remove the 'for' loop instead */
+ }
+
+ /* now merge partitions for lower orders */
+ for(from_partition = 0, --partition_order; partition_order >= (int)min_partition_order; partition_order--) {
+ unsigned m;
+ unsigned i;
+ const unsigned partitions = 1u << partition_order;
+ for(i = 0; i < partitions; i++) {
+ m = raw_bits_per_partition[from_partition];
+ from_partition++;
+ raw_bits_per_partition[to_partition] = max(m, raw_bits_per_partition[from_partition]);
+ from_partition++;
+ to_partition++;
+ }
+ }
+}
+
+#ifdef EXACT_RICE_BITS_CALCULATION
+static FLaC__INLINE unsigned count_rice_bits_in_partition_(
+ const unsigned rice_parameter,
+ const unsigned partition_samples,
+ const FLAC__int32 *residual
+)
+{
+ unsigned i, partition_bits =
+ FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN +
+ (1+rice_parameter) * partition_samples /* 1 for unary stop bit + rice_parameter for the binary portion */
+ ;
+ for(i = 0; i < partition_samples; i++)
+ partition_bits += ( (FLAC__uint32)((residual[i]<<1)^(residual[i]>>31)) >> rice_parameter );
+ return partition_bits;
+}
+#else
+static FLaC__INLINE unsigned count_rice_bits_in_partition_(
+ const unsigned rice_parameter,
+ const unsigned partition_samples,
+ const FLAC__uint64 abs_residual_partition_sum
+)
+{
+ return
+ FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN +
+ (1+rice_parameter) * partition_samples + /* 1 for unary stop bit + rice_parameter for the binary portion */
+ (
+ rice_parameter?
+ (unsigned)(abs_residual_partition_sum >> (rice_parameter-1)) /* rice_parameter-1 because the real coder sign-folds instead of using a sign bit */
+ : (unsigned)(abs_residual_partition_sum << 1) /* can't shift by negative number, so reverse */
+ )
+ - (partition_samples >> 1)
+ /* -(partition_samples>>1) to subtract out extra contributions to the abs_residual_partition_sum.
+ * The actual number of bits used is closer to the sum(for all i in the partition) of abs(residual[i])>>(rice_parameter-1)
+ * By using the abs_residual_partition sum, we also add in bits in the LSBs that would normally be shifted out.
+ * So the subtraction term tries to guess how many extra bits were contributed.
+ * If the LSBs are randomly distributed, this should average to 0.5 extra bits per sample.
+ */
+ ;
+}
+#endif
+
+FLAC__bool set_partitioned_rice_(
+#ifdef EXACT_RICE_BITS_CALCULATION
+ const FLAC__int32 residual[],
+#endif
+ const FLAC__uint64 abs_residual_partition_sums[],
+ const unsigned raw_bits_per_partition[],
+ const unsigned residual_samples,
+ const unsigned predictor_order,
+ const unsigned suggested_rice_parameter,
+ const unsigned rice_parameter_search_dist,
+ const unsigned partition_order,
+ const FLAC__bool search_for_escapes,
+ FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents,
+ unsigned *bits
+)
+{
+ unsigned rice_parameter, partition_bits;
+ unsigned best_partition_bits, best_rice_parameter = 0;
+ unsigned bits_ = FLAC__ENTROPY_CODING_METHOD_TYPE_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN;
+ unsigned *parameters, *raw_bits;
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+ unsigned min_rice_parameter, max_rice_parameter;
+#else
+ (void)rice_parameter_search_dist;
+#endif
+
+ FLAC__ASSERT(suggested_rice_parameter < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER);
+
+ FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, max(6, partition_order));
+ parameters = partitioned_rice_contents->parameters;
+ raw_bits = partitioned_rice_contents->raw_bits;
+
+ if(partition_order == 0) {
+ best_partition_bits = (unsigned)(-1);
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+ if(rice_parameter_search_dist) {
+ if(suggested_rice_parameter < rice_parameter_search_dist)
+ min_rice_parameter = 0;
+ else
+ min_rice_parameter = suggested_rice_parameter - rice_parameter_search_dist;
+ max_rice_parameter = suggested_rice_parameter + rice_parameter_search_dist;
+ if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+ fprintf(stderr, "clipping rice_parameter (%u -> %u) @5\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+ max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+ }
+ }
+ else
+ min_rice_parameter = max_rice_parameter = suggested_rice_parameter;
+
+ for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
+#else
+ rice_parameter = suggested_rice_parameter;
+#endif
+#ifdef EXACT_RICE_BITS_CALCULATION
+ partition_bits = count_rice_bits_in_partition_(rice_parameter, residual_samples, residual);
+#else
+ partition_bits = count_rice_bits_in_partition_(rice_parameter, residual_samples, abs_residual_partition_sums[0]);
+#endif
+ if(partition_bits < best_partition_bits) {
+ best_rice_parameter = rice_parameter;
+ best_partition_bits = partition_bits;
+ }
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+ }
+#endif
+ if(search_for_escapes) {
+ partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[0] * residual_samples;
+ if(partition_bits <= best_partition_bits) {
+ raw_bits[0] = raw_bits_per_partition[0];
+ best_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+ best_partition_bits = partition_bits;
+ }
+ }
+ parameters[0] = best_rice_parameter;
+ bits_ += best_partition_bits;
+ }
+ else {
+ unsigned partition, residual_sample;
+ unsigned partition_samples;
+ FLAC__uint64 mean, k;
+ const unsigned partitions = 1u << partition_order;
+ for(partition = residual_sample = 0; partition < partitions; partition++) {
+ partition_samples = (residual_samples+predictor_order) >> partition_order;
+ if(partition == 0) {
+ if(partition_samples <= predictor_order)
+ return false;
+ else
+ partition_samples -= predictor_order;
+ }
+ mean = abs_residual_partition_sums[partition];
+ /* we are basically calculating the size in bits of the
+ * average residual magnitude in the partition:
+ * rice_parameter = floor(log2(mean/partition_samples))
+ * 'mean' is not a good name for the variable, it is
+ * actually the sum of magnitudes of all residual values
+ * in the partition, so the actual mean is
+ * mean/partition_samples
+ */
+ for(rice_parameter = 0, k = partition_samples; k < mean; rice_parameter++, k <<= 1)
+ ;
+ if(rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+ fprintf(stderr, "clipping rice_parameter (%u -> %u) @6\n", rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+ rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+ }
+
+ best_partition_bits = (unsigned)(-1);
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+ if(rice_parameter_search_dist) {
+ if(rice_parameter < rice_parameter_search_dist)
+ min_rice_parameter = 0;
+ else
+ min_rice_parameter = rice_parameter - rice_parameter_search_dist;
+ max_rice_parameter = rice_parameter + rice_parameter_search_dist;
+ if(max_rice_parameter >= FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+#ifdef DEBUG_VERBOSE
+ fprintf(stderr, "clipping rice_parameter (%u -> %u) @7\n", max_rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1);
+#endif
+ max_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER - 1;
+ }
+ }
+ else
+ min_rice_parameter = max_rice_parameter = rice_parameter;
+
+ for(rice_parameter = min_rice_parameter; rice_parameter <= max_rice_parameter; rice_parameter++) {
+#endif
+#ifdef EXACT_RICE_BITS_CALCULATION
+ partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, residual+residual_sample);
+#else
+ partition_bits = count_rice_bits_in_partition_(rice_parameter, partition_samples, abs_residual_partition_sums[partition]);
+#endif
+ if(partition_bits < best_partition_bits) {
+ best_rice_parameter = rice_parameter;
+ best_partition_bits = partition_bits;
+ }
+#ifdef ENABLE_RICE_PARAMETER_SEARCH
+ }
+#endif
+ if(search_for_escapes) {
+ partition_bits = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN + FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN + raw_bits_per_partition[partition] * partition_samples;
+ if(partition_bits <= best_partition_bits) {
+ raw_bits[partition] = raw_bits_per_partition[partition];
+ best_rice_parameter = FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+ best_partition_bits = partition_bits;
+ }
+ }
+ parameters[partition] = best_rice_parameter;
+ bits_ += best_partition_bits;
+ residual_sample += partition_samples;
+ }
+ }
+
+ *bits = bits_;
+ return true;
+}
+
+unsigned get_wasted_bits_(FLAC__int32 signal[], unsigned samples)
+{
+ unsigned i, shift;
+ FLAC__int32 x = 0;
+
+ for(i = 0; i < samples && !(x&1); i++)
+ x |= signal[i];
+
+ if(x == 0) {
+ shift = 0;
+ }
+ else {
+ for(shift = 0; !(x&1); shift++)
+ x >>= 1;
+ }
+
+ if(shift > 0) {
+ for(i = 0; i < samples; i++)
+ signal[i] >>= shift;
+ }
+
+ return shift;
+}
+
+void append_to_verify_fifo_(verify_input_fifo *fifo, const FLAC__int32 * const input[], unsigned input_offset, unsigned channels, unsigned wide_samples)
+{
+ unsigned channel;
+
+ for(channel = 0; channel < channels; channel++)
+ memcpy(&fifo->data[channel][fifo->tail], &input[channel][input_offset], sizeof(FLAC__int32) * wide_samples);
+
+ fifo->tail += wide_samples;
+
+ FLAC__ASSERT(fifo->tail <= fifo->size);
+}
+
+void append_to_verify_fifo_interleaved_(verify_input_fifo *fifo, const FLAC__int32 input[], unsigned input_offset, unsigned channels, unsigned wide_samples)
+{
+ unsigned channel;
+ unsigned sample, wide_sample;
+ unsigned tail = fifo->tail;
+
+ sample = input_offset * channels;
+ for(wide_sample = 0; wide_sample < wide_samples; wide_sample++) {
+ for(channel = 0; channel < channels; channel++)
+ fifo->data[channel][tail] = input[sample++];
+ tail++;
+ }
+ fifo->tail = tail;
+
+ FLAC__ASSERT(fifo->tail <= fifo->size);
+}
+
+FLAC__StreamDecoderReadStatus verify_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
+ const size_t encoded_bytes = encoder->private_->verify.output.bytes;
+ (void)decoder;
+
+ if(encoder->private_->verify.needs_magic_hack) {
+ FLAC__ASSERT(*bytes >= FLAC__STREAM_SYNC_LENGTH);
+ *bytes = FLAC__STREAM_SYNC_LENGTH;
+ memcpy(buffer, FLAC__STREAM_SYNC_STRING, *bytes);
+ encoder->private_->verify.needs_magic_hack = false;
+ }
+ else {
+ if(encoded_bytes == 0) {
+ /*
+ * If we get here, a FIFO underflow has occurred,
+ * which means there is a bug somewhere.
+ */
+ FLAC__ASSERT(0);
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+ else if(encoded_bytes < *bytes)
+ *bytes = encoded_bytes;
+ memcpy(buffer, encoder->private_->verify.output.data, *bytes);
+ encoder->private_->verify.output.data += *bytes;
+ encoder->private_->verify.output.bytes -= *bytes;
+ }
+
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+}
+
+FLAC__StreamDecoderWriteStatus verify_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder *)client_data;
+ unsigned channel;
+ const unsigned channels = frame->header.channels;
+ const unsigned blocksize = frame->header.blocksize;
+ const unsigned bytes_per_block = sizeof(FLAC__int32) * blocksize;
+
+ (void)decoder;
+
+ for(channel = 0; channel < channels; channel++) {
+ if(0 != memcmp(buffer[channel], encoder->private_->verify.input_fifo.data[channel], bytes_per_block)) {
+ unsigned i, sample = 0;
+ FLAC__int32 expect = 0, got = 0;
+
+ for(i = 0; i < blocksize; i++) {
+ if(buffer[channel][i] != encoder->private_->verify.input_fifo.data[channel][i]) {
+ sample = i;
+ expect = (FLAC__int32)encoder->private_->verify.input_fifo.data[channel][i];
+ got = (FLAC__int32)buffer[channel][i];
+ break;
+ }
+ }
+ FLAC__ASSERT(i < blocksize);
+ FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER);
+ encoder->private_->verify.error_stats.absolute_sample = frame->header.number.sample_number + sample;
+ encoder->private_->verify.error_stats.frame_number = (unsigned)(frame->header.number.sample_number / blocksize);
+ encoder->private_->verify.error_stats.channel = channel;
+ encoder->private_->verify.error_stats.sample = sample;
+ encoder->private_->verify.error_stats.expected = expect;
+ encoder->private_->verify.error_stats.got = got;
+ encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_MISMATCH_IN_AUDIO_DATA;
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ }
+ /* dequeue the frame from the fifo */
+ encoder->private_->verify.input_fifo.tail -= blocksize;
+ FLAC__ASSERT(encoder->private_->verify.input_fifo.tail <= OVERREAD_);
+ for(channel = 0; channel < channels; channel++)
+ memmove(&encoder->private_->verify.input_fifo.data[channel][0], &encoder->private_->verify.input_fifo.data[channel][blocksize], encoder->private_->verify.input_fifo.tail * sizeof(encoder->private_->verify.input_fifo.data[0][0]));
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+void verify_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ (void)decoder, (void)metadata, (void)client_data;
+}
+
+void verify_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ FLAC__StreamEncoder *encoder = (FLAC__StreamEncoder*)client_data;
+ (void)decoder, (void)status;
+ encoder->protected_->state = FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR;
+}
+
+FLAC__StreamEncoderReadStatus file_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ (void)client_data;
+
+ *bytes = fread(buffer, 1, *bytes, encoder->private_->file);
+ if (*bytes == 0) {
+ if (feof(encoder->private_->file))
+ return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
+ else if (ferror(encoder->private_->file))
+ return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+ }
+ return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
+}
+
+FLAC__StreamEncoderSeekStatus file_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+ (void)client_data;
+
+ if(fseeko(encoder->private_->file, (off_t)absolute_byte_offset, SEEK_SET) < 0)
+ return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+ else
+ return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+FLAC__StreamEncoderTellStatus file_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+ off_t offset;
+
+ (void)client_data;
+
+ offset = ftello(encoder->private_->file);
+
+ if(offset < 0) {
+ return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+ }
+ else {
+ *absolute_byte_offset = (FLAC__uint64)offset;
+ return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+ }
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ size_t ret = fwrite(ptr, size, nmemb, stream);
+ if(!ferror(stream))
+ fflush(stream);
+ return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+FLAC__StreamEncoderWriteStatus file_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+ (void)client_data, (void)current_frame;
+
+ if(local__fwrite(buffer, sizeof(FLAC__byte), bytes, encoder->private_->file) == bytes) {
+ FLAC__bool call_it = 0 != encoder->private_->progress_callback && (
+#if FLAC__HAS_OGG
+ /* We would like to be able to use 'samples > 0' in the
+ * clause here but currently because of the nature of our
+ * Ogg writing implementation, 'samples' is always 0 (see
+ * ogg_encoder_aspect.c). The downside is extra progress
+ * callbacks.
+ */
+ encoder->private_->is_ogg? true :
+#endif
+ samples > 0
+ );
+ if(call_it) {
+ /* NOTE: We have to add +bytes, +samples, and +1 to the stats
+ * because at this point in the callback chain, the stats
+ * have not been updated. Only after we return and control
+ * gets back to write_frame_() are the stats updated
+ */
+ encoder->private_->progress_callback(encoder, encoder->private_->bytes_written+bytes, encoder->private_->samples_written+samples, encoder->private_->frames_written+(samples?1:0), encoder->private_->total_frames_estimate, encoder->private_->client_data);
+ }
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+ }
+ else
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+}
+
+/*
+ * This will forcibly set stdout to binary mode (for OSes that require it)
+ */
+FILE *get_binary_stdout_(void)
+{
+ /* if something breaks here it is probably due to the presence or
+ * absence of an underscore before the identifiers 'setmode',
+ * 'fileno', and/or 'O_BINARY'; check your system header files.
+ */
+#if defined _MSC_VER || defined __MINGW32__
+ _setmode(_fileno(stdout), _O_BINARY);
+#elif defined __CYGWIN__
+ /* almost certainly not needed for any modern Cygwin, but let's be safe... */
+ setmode(_fileno(stdout), _O_BINARY);
+#elif defined __EMX__
+ setmode(fileno(stdout), O_BINARY);
+#endif
+
+ return stdout;
+}
diff --git a/src/FLAC/src/libFLAC/stream_encoder_framing.c b/src/FLAC/src/libFLAC/stream_encoder_framing.c
new file mode 100644
index 0000000..8b9558b
--- /dev/null
+++ b/src/FLAC/src/libFLAC/stream_encoder_framing.c
@@ -0,0 +1,515 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h> /* for strlen() */
+#include "private/stream_encoder_framing.h"
+#include "private/crc.h"
+#include "FLAC/assert.h"
+
+#ifdef max
+#undef max
+#endif
+#define max(x,y) ((x)>(y)?(x):(y))
+
+static FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method);
+static FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order);
+
+FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw)
+{
+ unsigned i, j;
+ const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN))
+ return false;
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN))
+ return false;
+
+ /*
+ * First, for VORBIS_COMMENTs, adjust the length to reflect our vendor string
+ */
+ i = metadata->length;
+ if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
+ FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry);
+ i -= metadata->data.vorbis_comment.vendor_string.length;
+ i += vendor_string_length;
+ }
+ FLAC__ASSERT(i < (1u << FLAC__STREAM_METADATA_LENGTH_LEN));
+ if(!FLAC__bitwriter_write_raw_uint32(bw, i, FLAC__STREAM_METADATA_LENGTH_LEN))
+ return false;
+
+ switch(metadata->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ FLAC__ASSERT(metadata->data.stream_info.min_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN));
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN))
+ return false;
+ FLAC__ASSERT(metadata->data.stream_info.max_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN));
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN))
+ return false;
+ FLAC__ASSERT(metadata->data.stream_info.min_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN));
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_framesize, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN))
+ return false;
+ FLAC__ASSERT(metadata->data.stream_info.max_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN));
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_framesize, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN))
+ return false;
+ FLAC__ASSERT(FLAC__format_sample_rate_is_valid(metadata->data.stream_info.sample_rate));
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.sample_rate, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN))
+ return false;
+ FLAC__ASSERT(metadata->data.stream_info.channels > 0);
+ FLAC__ASSERT(metadata->data.stream_info.channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN));
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.channels-1, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN))
+ return false;
+ FLAC__ASSERT(metadata->data.stream_info.bits_per_sample > 0);
+ FLAC__ASSERT(metadata->data.stream_info.bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN));
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.stream_info.md5sum, 16))
+ return false;
+ break;
+ case FLAC__METADATA_TYPE_PADDING:
+ if(!FLAC__bitwriter_write_zeroes(bw, metadata->length * 8))
+ return false;
+ break;
+ case FLAC__METADATA_TYPE_APPLICATION:
+ if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))
+ return false;
+ if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.data, metadata->length - (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)))
+ return false;
+ break;
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ for(i = 0; i < metadata->data.seek_table.num_points; i++) {
+ if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].stream_offset, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.seek_table.points[i].frame_samples, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN))
+ return false;
+ }
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, vendor_string_length))
+ return false;
+ if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.num_comments))
+ return false;
+ for(i = 0; i < metadata->data.vorbis_comment.num_comments; i++) {
+ if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.comments[i].length))
+ return false;
+ if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length))
+ return false;
+ }
+ break;
+ case FLAC__METADATA_TYPE_CUESHEET:
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0);
+ if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.cue_sheet.media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.is_cd? 1 : 0, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.num_tracks, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN))
+ return false;
+ for(i = 0; i < metadata->data.cue_sheet.num_tracks; i++) {
+ const FLAC__StreamMetadata_CueSheet_Track *track = metadata->data.cue_sheet.tracks + i;
+
+ if(!FLAC__bitwriter_write_raw_uint64(bw, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, track->number, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN))
+ return false;
+ FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0);
+ if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, track->num_indices, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN))
+ return false;
+ for(j = 0; j < track->num_indices; j++) {
+ const FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j;
+
+ if(!FLAC__bitwriter_write_raw_uint64(bw, index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, index->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN))
+ return false;
+ }
+ }
+ break;
+ case FLAC__METADATA_TYPE_PICTURE:
+ {
+ size_t len;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN))
+ return false;
+ len = strlen(metadata->data.picture.mime_type);
+ if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.picture.mime_type, len))
+ return false;
+ len = strlen((const char *)metadata->data.picture.description);
+ if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.description, len))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.data_length, FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.data, metadata->data.picture.data_length))
+ return false;
+ }
+ break;
+ default:
+ if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.unknown.data, metadata->length))
+ return false;
+ break;
+ }
+
+ FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
+ return true;
+}
+
+FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw)
+{
+ unsigned u, blocksize_hint, sample_rate_hint;
+ FLAC__byte crc;
+
+ FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw));
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN))
+ return false;
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_RESERVED_LEN))
+ return false;
+
+ FLAC__ASSERT(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE);
+ /* when this assertion holds true, any legal blocksize can be expressed in the frame header */
+ FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535u);
+ blocksize_hint = 0;
+ switch(header->blocksize) {
+ case 192: u = 1; break;
+ case 576: u = 2; break;
+ case 1152: u = 3; break;
+ case 2304: u = 4; break;
+ case 4608: u = 5; break;
+ case 256: u = 8; break;
+ case 512: u = 9; break;
+ case 1024: u = 10; break;
+ case 2048: u = 11; break;
+ case 4096: u = 12; break;
+ case 8192: u = 13; break;
+ case 16384: u = 14; break;
+ case 32768: u = 15; break;
+ default:
+ if(header->blocksize <= 0x100)
+ blocksize_hint = u = 6;
+ else if(header->blocksize <= 0x10000)
+ blocksize_hint = u = 7;
+ else
+ u = 0;
+ break;
+ }
+ if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN))
+ return false;
+
+ FLAC__ASSERT(FLAC__format_sample_rate_is_valid(header->sample_rate));
+ sample_rate_hint = 0;
+ switch(header->sample_rate) {
+ case 8000: u = 4; break;
+ case 16000: u = 5; break;
+ case 22050: u = 6; break;
+ case 24000: u = 7; break;
+ case 32000: u = 8; break;
+ case 44100: u = 9; break;
+ case 48000: u = 10; break;
+ case 96000: u = 11; break;
+ default:
+ if(header->sample_rate <= 255000 && header->sample_rate % 1000 == 0)
+ sample_rate_hint = u = 12;
+ else if(header->sample_rate % 10 == 0)
+ sample_rate_hint = u = 14;
+ else if(header->sample_rate <= 0xffff)
+ sample_rate_hint = u = 13;
+ else
+ u = 0;
+ break;
+ }
+ if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN))
+ return false;
+
+ FLAC__ASSERT(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN) && header->channels <= FLAC__MAX_CHANNELS);
+ switch(header->channel_assignment) {
+ case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT:
+ u = header->channels - 1;
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE:
+ FLAC__ASSERT(header->channels == 2);
+ u = 8;
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE:
+ FLAC__ASSERT(header->channels == 2);
+ u = 9;
+ break;
+ case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE:
+ FLAC__ASSERT(header->channels == 2);
+ u = 10;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+ if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN))
+ return false;
+
+ FLAC__ASSERT(header->bits_per_sample > 0 && header->bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN));
+ switch(header->bits_per_sample) {
+ case 8 : u = 1; break;
+ case 12: u = 2; break;
+ case 16: u = 4; break;
+ case 20: u = 5; break;
+ case 24: u = 6; break;
+ default: u = 0; break;
+ }
+ if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN))
+ return false;
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN))
+ return false;
+
+ FLAC__ASSERT(header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER);
+ if(!FLAC__bitwriter_write_utf8_uint32(bw, header->number.frame_number))
+ return false;
+
+ if(blocksize_hint)
+ if(!FLAC__bitwriter_write_raw_uint32(bw, header->blocksize-1, (blocksize_hint==6)? 8:16))
+ return false;
+
+ switch(sample_rate_hint) {
+ case 12:
+ if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 1000, 8))
+ return false;
+ break;
+ case 13:
+ if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate, 16))
+ return false;
+ break;
+ case 14:
+ if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 10, 16))
+ return false;
+ break;
+ }
+
+ /* write the CRC */
+ if(!FLAC__bitwriter_get_write_crc8(bw, &crc))
+ return false;
+ if(!FLAC__bitwriter_write_raw_uint32(bw, crc, FLAC__FRAME_HEADER_CRC_LEN))
+ return false;
+
+ return true;
+}
+
+FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
+{
+ FLAC__bool ok;
+
+ ok =
+ FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN) &&
+ (wasted_bits? FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1) : true) &&
+ FLAC__bitwriter_write_raw_int32(bw, subframe->value, subframe_bps)
+ ;
+
+ return ok;
+}
+
+FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
+{
+ unsigned i;
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK | (subframe->order<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
+ return false;
+ if(wasted_bits)
+ if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
+ return false;
+
+ for(i = 0; i < subframe->order; i++)
+ if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
+ return false;
+
+ if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method))
+ return false;
+ switch(subframe->entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!add_residual_partitioned_rice_(bw, subframe->residual, residual_samples, subframe->order, subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, subframe->entropy_coding_method.data.partitioned_rice.order))
+ return false;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+
+ return true;
+}
+
+FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
+{
+ unsigned i;
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK | ((subframe->order-1)<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
+ return false;
+ if(wasted_bits)
+ if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
+ return false;
+
+ for(i = 0; i < subframe->order; i++)
+ if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps))
+ return false;
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN))
+ return false;
+ if(!FLAC__bitwriter_write_raw_int32(bw, subframe->quantization_level, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN))
+ return false;
+ for(i = 0; i < subframe->order; i++)
+ if(!FLAC__bitwriter_write_raw_int32(bw, subframe->qlp_coeff[i], subframe->qlp_coeff_precision))
+ return false;
+
+ if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method))
+ return false;
+ switch(subframe->entropy_coding_method.type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!add_residual_partitioned_rice_(bw, subframe->residual, residual_samples, subframe->order, subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, subframe->entropy_coding_method.data.partitioned_rice.order))
+ return false;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+
+ return true;
+}
+
+FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw)
+{
+ unsigned i;
+ const FLAC__int32 *signal = subframe->data;
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN))
+ return false;
+ if(wasted_bits)
+ if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1))
+ return false;
+
+ for(i = 0; i < samples; i++)
+ if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps))
+ return false;
+
+ return true;
+}
+
+FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method)
+{
+ if(!FLAC__bitwriter_write_raw_uint32(bw, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN))
+ return false;
+ switch(method->type) {
+ case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE:
+ if(!FLAC__bitwriter_write_raw_uint32(bw, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN))
+ return false;
+ break;
+ default:
+ FLAC__ASSERT(0);
+ }
+ return true;
+}
+
+FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order)
+{
+ if(partition_order == 0) {
+ unsigned i;
+
+ if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN))
+ return false;
+ if(rice_parameters[0] < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+ if(!FLAC__bitwriter_write_rice_signed_block(bw, residual, residual_samples, rice_parameters[0]))
+ return false;
+ }
+ else {
+ if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+ return false;
+ for(i = 0; i < residual_samples; i++) {
+ if(!FLAC__bitwriter_write_raw_int32(bw, residual[i], raw_bits[0]))
+ return false;
+ }
+ }
+ return true;
+ }
+ else {
+ unsigned i, j, k = 0, k_last = 0;
+ unsigned partition_samples;
+ const unsigned default_partition_samples = (residual_samples+predictor_order) >> partition_order;
+ for(i = 0; i < (1u<<partition_order); i++) {
+ if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN))
+ return false;
+ partition_samples = default_partition_samples;
+ if(i == 0)
+ partition_samples -= predictor_order;
+ k += partition_samples;
+ if(rice_parameters[i] < FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER) {
+ if(!FLAC__bitwriter_write_rice_signed_block(bw, residual+k_last, k-k_last, rice_parameters[i]))
+ return false;
+ }
+ else {
+ if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN))
+ return false;
+ for(j = k_last; j < k; j++) {
+ if(!FLAC__bitwriter_write_raw_int32(bw, residual[j], raw_bits[i]))
+ return false;
+ }
+ }
+ k_last = k;
+ }
+ return true;
+ }
+}
diff --git a/src/FLAC/src/libFLAC/window.c b/src/FLAC/src/libFLAC/window.c
new file mode 100644
index 0000000..cd689c5
--- /dev/null
+++ b/src/FLAC/src/libFLAC/window.c
@@ -0,0 +1,225 @@
+/* libFLAC - Free Lossless Audio Codec library
+ * Copyright (C) 2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "private/window.h"
+
+#ifndef FLAC__INTEGER_ONLY_LIBRARY
+
+#ifndef M_PI
+/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
+#define M_PI 3.14159265358979323846
+#endif
+
+
+void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ if (L & 1) {
+ for (n = 0; n <= N/2; n++)
+ window[n] = 2.0f * n / (float)N;
+ for (; n <= N; n++)
+ window[n] = 2.0f - 2.0f * n / (float)N;
+ }
+ else {
+ for (n = 0; n <= L/2-1; n++)
+ window[n] = 2.0f * n / (float)N;
+ for (; n <= N; n++)
+ window[n] = 2.0f - 2.0f * (N-n) / (float)N;
+ }
+}
+
+void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N+0.5f) + 0.38f * cos(2.0f * M_PI * ((float)n/(float)N+0.5f)));
+}
+
+void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.42f - 0.5f * cos(2.0f * M_PI * n / N) + 0.08f * cos(4.0f * M_PI * n / N));
+}
+
+/* 4-term -92dB side-lobe */
+void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n <= N; n++)
+ window[n] = (FLAC__real)(0.35875f - 0.48829f * cos(2.0f * M_PI * n / N) + 0.14128f * cos(4.0f * M_PI * n / N) - 0.01168f * cos(6.0f * M_PI * n / N));
+}
+
+void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ const double N2 = (double)N / 2.;
+ FLAC__int32 n;
+
+ for (n = 0; n <= N; n++) {
+ double k = ((double)n - N2) / N2;
+ k = 1.0f - k * k;
+ window[n] = (FLAC__real)(k * k);
+ }
+}
+
+void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(1.0f - 1.93f * cos(2.0f * M_PI * n / N) + 1.29f * cos(4.0f * M_PI * n / N) - 0.388f * cos(6.0f * M_PI * n / N) + 0.0322f * cos(8.0f * M_PI * n / N));
+}
+
+void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev)
+{
+ const FLAC__int32 N = L - 1;
+ const double N2 = (double)N / 2.;
+ FLAC__int32 n;
+
+ for (n = 0; n <= N; n++) {
+ const double k = ((double)n - N2) / (stddev * N2);
+ window[n] = (FLAC__real)exp(-0.5f * k * k);
+ }
+}
+
+void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.54f - 0.46f * cos(2.0f * M_PI * n / N));
+}
+
+void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.5f - 0.5f * cos(2.0f * M_PI * n / N));
+}
+
+void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.402f - 0.498f * cos(2.0f * M_PI * n / N) + 0.098f * cos(4.0f * M_PI * n / N) - 0.001f * cos(6.0f * M_PI * n / N));
+}
+
+void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = (FLAC__real)(0.3635819f - 0.4891775f*cos(2.0f*M_PI*n/N) + 0.1365995f*cos(4.0f*M_PI*n/N) - 0.0106411f*cos(6.0f*M_PI*n/N));
+}
+
+void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L)
+{
+ FLAC__int32 n;
+
+ for (n = 0; n < L; n++)
+ window[n] = 1.0f;
+}
+
+void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L)
+{
+ FLAC__int32 n;
+
+ if (L & 1) {
+ for (n = 1; n <= L+1/2; n++)
+ window[n-1] = 2.0f * n / ((float)L + 1.0f);
+ for (; n <= L; n++)
+ window[n-1] = - (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
+ }
+ else {
+ for (n = 1; n <= L/2; n++)
+ window[n-1] = 2.0f * n / (float)L;
+ for (; n <= L; n++)
+ window[n-1] = ((float)(2 * (L - n)) + 1.0f) / (float)L;
+ }
+}
+
+void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p)
+{
+ if (p <= 0.0)
+ FLAC__window_rectangle(window, L);
+ else if (p >= 1.0)
+ FLAC__window_hann(window, L);
+ else {
+ const FLAC__int32 Np = (FLAC__int32)(p / 2.0f * L) - 1;
+ FLAC__int32 n;
+ /* start with rectangle... */
+ FLAC__window_rectangle(window, L);
+ /* ...replace ends with hann */
+ if (Np > 0) {
+ for (n = 0; n <= Np; n++) {
+ window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * n / Np));
+ window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * (n+Np) / Np));
+ }
+ }
+ }
+}
+
+void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L)
+{
+ const FLAC__int32 N = L - 1;
+ const double N2 = (double)N / 2.;
+ FLAC__int32 n;
+
+ for (n = 0; n <= N; n++) {
+ const double k = ((double)n - N2) / N2;
+ window[n] = (FLAC__real)(1.0f - k * k);
+ }
+}
+
+#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */
diff --git a/src/FLAC/src/monkeys_audio_utilities/Makefile.am b/src/FLAC/src/monkeys_audio_utilities/Makefile.am
new file mode 100644
index 0000000..3cfe69a
--- /dev/null
+++ b/src/FLAC/src/monkeys_audio_utilities/Makefile.am
@@ -0,0 +1,18 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under difference licenses. The codec libraries
+# are distributed under Xiph.Org's BSD-like license (see the file
+# COPYING.Xiph in this distribution). All other programs, libraries, and
+# plugins are distributed under the GPL (see COPYING.GPL). The documentation
+# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
+# FLAC distribution contains at the top the terms under which it may be
+# distributed.
+#
+# Since this particular file is relevant to all components of FLAC,
+# it may be distributed under the Xiph.Org license, which is the least
+# restrictive of those mentioned above. See the file COPYING.Xiph in this
+# distribution.
+
+SUBDIRS = flac_mac flac_ren
diff --git a/src/FLAC/src/monkeys_audio_utilities/flac_mac/Makefile.am b/src/FLAC/src/monkeys_audio_utilities/flac_mac/Makefile.am
new file mode 100644
index 0000000..9b03e48
--- /dev/null
+++ b/src/FLAC/src/monkeys_audio_utilities/flac_mac/Makefile.am
@@ -0,0 +1,19 @@
+# flac_mac - wedge utility to add FLAC support to Monkey's Audio
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+EXTRA_DIST = \
+ main.c
diff --git a/src/FLAC/src/monkeys_audio_utilities/flac_mac/main.c b/src/FLAC/src/monkeys_audio_utilities/flac_mac/main.c
new file mode 100644
index 0000000..99109c0
--- /dev/null
+++ b/src/FLAC/src/monkeys_audio_utilities/flac_mac/main.c
@@ -0,0 +1,208 @@
+/* flac_mac - wedge utility to add FLAC support to Monkey's Audio
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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 program can be used to allow FLAC to masquerade as one of the other
+ * supported lossless codecs in Monkey's Audio. See the documentation for
+ * how to do this.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include<stdio.h>
+#include<stdlib.h>
+#include<string.h>
+#include<wtypes.h>
+#include<process.h>
+#include<winbase.h>
+
+static int execit(char *prog, char *args);
+static int forkit(char *prog, char *args);
+
+int main(int argc, char *argv[])
+{
+ int flac_return_val = 0, opt_arg = 1, from_arg = -1, to_arg = -1, flac_level = 5, i;
+ char prog[MAX_PATH], cmdline[MAX_PATH*2], from[MAX_PATH], to[MAX_PATH], macdir[MAX_PATH], options[256], *p;
+ enum { WAVPACK, RKAU, SHORTEN } codec;
+
+ /* get the directory where MAC external codecs reside */
+ if(0 != (p = strrchr(argv[0],'\\'))) {
+ strcpy(macdir, argv[0]);
+ *(strrchr(macdir,'\\')+1) = '\0';
+ }
+ else {
+ strcpy(macdir, "");
+ }
+
+ /* determine which codec we were called as and parse the options */
+ if(p == 0)
+ p = argv[0];
+ else
+ p++;
+ if(0 == strnicmp(p, "short", 5)) {
+ codec = SHORTEN;
+ }
+ else if(0 == strnicmp(p, "rkau", 4)) {
+ codec = RKAU;
+ if(argv[1][0] == '-' && argv[1][1] == 'l') {
+ opt_arg = 2;
+ switch(argv[1][2]) {
+ case '1': flac_level = 1; break;
+ case '2': flac_level = 5; break;
+ case '3': flac_level = 8; break;
+ }
+ }
+ }
+ else if(0 == strnicmp(p, "wavpack", 7)) {
+ codec = WAVPACK;
+ if(argv[1][0] == '-') {
+ opt_arg = 2;
+ switch(argv[1][1]) {
+ case 'f': flac_level = 1; break;
+ case 'h': flac_level = 8; break;
+ default: opt_arg = 1;
+ }
+ }
+ }
+ else {
+ return -5;
+ }
+
+ /* figure out which arguments are the source and destination files */
+ for(i = 1; i < argc; i++)
+ if(argv[i][0] != '-') {
+ from_arg = i++;
+ break;
+ }
+ for( ; i < argc; i++)
+ if(argv[i][0] != '-') {
+ to_arg = i++;
+ break;
+ }
+ if(to_arg < 0)
+ return -4;
+
+ /* build the command to call flac with */
+ sprintf(prog, "%sflac.exe", macdir);
+ sprintf(options, "-%d", flac_level);
+ for(i = opt_arg; i < argc; i++)
+ if(argv[i][0] == '-') {
+ strcat(options, " ");
+ strcat(options, argv[i]);
+ }
+ sprintf(cmdline, "\"%s\" %s -o \"%s\" \"%s\"", prog, options, argv[to_arg], argv[from_arg]);
+
+ flac_return_val = execit(prog, cmdline);
+
+ /*
+ * Now that flac has finished, we need to fork a process that will rename
+ * the resulting file with the correct extension once MAC has moved it to
+ * it's final resting place.
+ */
+ if(0 == flac_return_val) {
+ /* get the destination directory, if any */
+ if(0 != (p = strchr(argv[to_arg],'\\'))) {
+ strcpy(from, argv[to_arg]);
+ *(strrchr(from,'\\')+1) = '\0';
+ }
+ else {
+ strcpy(from, "");
+ }
+
+ /* for the full 'from' and 'to' paths for the renamer process */
+ p = strrchr(argv[from_arg],'\\');
+ strcat(from, p? p+1 : argv[from_arg]);
+ strcpy(to, from);
+ if(0 == strchr(from,'.'))
+ return -3;
+ switch(codec) {
+ case SHORTEN: strcpy(strrchr(from,'.'), ".shn"); break;
+ case WAVPACK: strcpy(strrchr(from,'.'), ".wv"); break;
+ case RKAU: strcpy(strrchr(from,'.'), ".rka"); break;
+ }
+ strcpy(strrchr(to,'.'), ".flac");
+
+ sprintf(prog, "%sflac_ren.exe", macdir);
+ sprintf(cmdline, "\"%s\" \"%s\" \"%s\"", prog, from, to);
+
+ flac_return_val = forkit(prog, cmdline);
+ }
+
+ return flac_return_val;
+}
+
+int execit(char *prog, char *args)
+{
+ BOOL ok;
+ STARTUPINFO startup_info;
+ PROCESS_INFORMATION proc_info;
+
+ GetStartupInfo(&startup_info);
+
+ ok = CreateProcess(
+ prog,
+ args,
+ 0, /*process security attributes*/
+ 0, /*thread security attributes*/
+ FALSE,
+ 0, /*dwCreationFlags*/
+ 0, /*environment*/
+ 0, /*lpCurrentDirectory*/
+ &startup_info,
+ &proc_info
+ );
+ if(ok) {
+ DWORD dw;
+ dw = WaitForSingleObject(proc_info.hProcess, INFINITE);
+ ok = (dw != 0xFFFFFFFF);
+ CloseHandle(proc_info.hThread);
+ CloseHandle(proc_info.hProcess);
+ }
+
+ return ok? 0 : -1;
+}
+
+int forkit(char *prog, char *args)
+{
+ BOOL ok;
+ STARTUPINFO startup_info;
+ PROCESS_INFORMATION proc_info;
+
+ GetStartupInfo(&startup_info);
+
+ ok = CreateProcess(
+ prog,
+ args,
+ 0, /*process security attributes*/
+ 0, /*thread security attributes*/
+ FALSE,
+ DETACHED_PROCESS, /*dwCreationFlags*/
+ 0, /*environment*/
+ 0, /*lpCurrentDirectory*/
+ &startup_info,
+ &proc_info
+ );
+ if(ok) {
+ CloseHandle(proc_info.hThread);
+ CloseHandle(proc_info.hProcess);
+ }
+
+ return ok? 0 : -2;
+}
diff --git a/src/FLAC/src/monkeys_audio_utilities/flac_ren/Makefile.am b/src/FLAC/src/monkeys_audio_utilities/flac_ren/Makefile.am
new file mode 100644
index 0000000..57c6a7c
--- /dev/null
+++ b/src/FLAC/src/monkeys_audio_utilities/flac_ren/Makefile.am
@@ -0,0 +1,19 @@
+# flac_ren - renamer part of utility to add FLAC support to Monkey's Audio
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+EXTRA_DIST = \
+ main.c
diff --git a/src/FLAC/src/monkeys_audio_utilities/flac_ren/main.c b/src/FLAC/src/monkeys_audio_utilities/flac_ren/main.c
new file mode 100644
index 0000000..fa84983
--- /dev/null
+++ b/src/FLAC/src/monkeys_audio_utilities/flac_ren/main.c
@@ -0,0 +1,39 @@
+/* flac_ren - renamer part of utility to add FLAC support to Monkey's Audio
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <io.h>
+#include <sys/stat.h>
+#include <wtypes.h>
+#include <winbase.h>
+
+int main(int argc, char *argv[])
+{
+ struct stat s;
+
+ /* wait till the 'from' file has reached its final destination */
+ do {
+ Sleep(2000);
+ } while(stat(argv[1], &s) < 0);
+
+ /* now rename it */
+ return rename(argv[1], argv[2]);
+}
diff --git a/src/FLAC/src/share/Makefile.am b/src/FLAC/src/share/Makefile.am
new file mode 100644
index 0000000..3ef9960
--- /dev/null
+++ b/src/FLAC/src/share/Makefile.am
@@ -0,0 +1,19 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under difference licenses. The codec libraries
+# are distributed under Xiph.Org's BSD-like license (see the file
+# COPYING.Xiph in this distribution). All other programs, libraries, and
+# plugins are distributed under the GPL (see COPYING.GPL). The documentation
+# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
+# FLAC distribution contains at the top the terms under which it may be
+# distributed.
+#
+# Since this particular file is relevant to all components of FLAC,
+# it may be distributed under the Xiph.Org license, which is the least
+# restrictive of those mentioned above. See the file COPYING.Xiph in this
+# distribution.
+
+SUBDIRS = getopt replaygain_anal replaygain_syn grabbag utf8
+
diff --git a/src/FLAC/src/share/README b/src/FLAC/src/share/README
new file mode 100644
index 0000000..1d4fede
--- /dev/null
+++ b/src/FLAC/src/share/README
@@ -0,0 +1,5 @@
+This directory contains several convenience libraries used by the rest of the
+tools and plugins. Two of them (getopt and utf8) are shamelessly copied from
+vorbistools, one for manipulating UTF-8 strings (GPL) and one for implementing
+getopt (LGPL). libFLAC does not link to either; the only FLAC tools that do
+are GPL'ed.
diff --git a/src/FLAC/src/share/getopt/Makefile.am b/src/FLAC/src/share/getopt/Makefile.am
new file mode 100644
index 0000000..5464c83
--- /dev/null
+++ b/src/FLAC/src/share/getopt/Makefile.am
@@ -0,0 +1,15 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_srcdir)/src/FLAC/include -I$(top_srcdir)/src/FLAC/include
+
+noinst_LIBRARIES = libgetopt.a
+
+libgetopt_a_SOURCES = getopt.c getopt1.c
+
+debug:
+ $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+ $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/FLAC/src/share/getopt/getopt.c b/src/FLAC/src/share/getopt/getopt.c
new file mode 100644
index 0000000..48e3c6e
--- /dev/null
+++ b/src/FLAC/src/share/getopt/getopt.c
@@ -0,0 +1,1064 @@
+/*
+ NOTE:
+ I cannot get the vanilla getopt code to work (i.e. compile only what
+ is needed and not duplicate symbols found in the standard library)
+ on all the platforms that FLAC supports. In particular the gating
+ of code with the ELIDE_CODE #define is not accurate enough on systems
+ that are POSIX but not glibc. If someone has a patch that works on
+ GNU/Linux, Darwin, AND Solaris please submit it on the project page:
+ http://sourceforge.net/projects/flac
+
+ In the meantime I have munged the global symbols and removed gates
+ around code, while at the same time trying to touch the original as
+ little as possible.
+*/
+/* Getopt for GNU.
+ NOTE: getopt is now part of the C library, so if you don't know what
+ "Keep this file name-space clean" means, talk to drepper@gnu.org
+ before changing it!
+
+ Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99
+ Free Software Foundation, Inc.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.
+ Ditto for AIX 3.2 and <stdlib.h>. */
+#ifndef _NO_PROTO
+# define _NO_PROTO
+#endif
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+# ifndef const
+# define const
+# endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+# include <gnu-versions.h>
+# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+# define ELIDE_CODE
+# endif
+#endif
+
+#if 1
+/*[JEC] was:#ifndef ELIDE_CODE*/
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+/* Don't include stdlib.h for non-GNU C libraries because some of them
+ contain conflicting prototypes for getopt. */
+# include <stdlib.h>
+# include <unistd.h>
+#endif /* GNU C library. */
+
+#ifdef VMS
+# include <unixlib.h>
+# if HAVE_STRING_H - 0
+# include <string.h>
+# endif
+#endif
+
+#ifndef _
+/* This is for other GNU distributions with internationalized messages.
+ When compiling libc, the _ macro is predefined. */
+# ifdef HAVE_LIBINTL_H
+# include <libintl.h>
+# define _(msgid) gettext (msgid)
+# else
+# define _(msgid) (msgid)
+# endif
+#endif
+
+/* This version of `share__getopt' appears to the caller like standard Unix `getopt'
+ but it behaves differently for the user, since it allows the user
+ to intersperse the options with the other arguments.
+
+ As `share__getopt' works, it permutes the elements of ARGV so that,
+ when it is done, all the options precede everything else. Thus
+ all application programs are extended to handle flexible argument order.
+
+ Setting the environment variable POSIXLY_CORRECT disables permutation.
+ Then the behavior is completely standard.
+
+ GNU application programs can use a third alternative mode in which
+ they can distinguish the relative order of options and other arguments. */
+
+#include "share/getopt.h"
+/*[JEC] was:#include "getopt.h"*/
+
+/* For communication from `share__getopt' to the caller.
+ When `share__getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+char *share__optarg = 0; /*[JEC] initialize to avoid being a 'Common' symbol */
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `share__getopt'.
+
+ On entry to `share__getopt', zero means this is the first call; initialize.
+
+ When `share__getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `share__optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int share__optind = 1;
+
+/* Formerly, initialization of getopt depended on share__optind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+static int share____getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int share__opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int share__optopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `share__getopt' to return -1 with `share__optind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+#ifdef __GNU_LIBRARY__
+/* We want to avoid inclusion of string.h with non-GNU libraries
+ because there are many ways it can cause trouble.
+ On some systems, it contains special magic macros that don't work
+ in GCC. */
+# include <string.h>
+# define my_index strchr
+#else
+
+#include <string.h>
+
+/* Avoid depending on library functions or files
+ whose names are inconsistent. */
+
+#ifndef getenv
+extern char *getenv (const char *);
+#endif
+
+static const char *
+my_index (const char *str, int chr)
+{
+ while (*str)
+ {
+ if (*str == chr)
+ return str;
+ str++;
+ }
+ return 0;
+}
+
+/* If using GCC, we can safely declare strlen this way.
+ If not using GCC, it is ok not to declare it. */
+#ifdef __GNUC__
+/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
+ That was relevant to code that was here before. */
+# if (!defined __STDC__ || !__STDC__) && !defined strlen
+/* gcc with -traditional declares the built-in strlen to return int,
+ and has done so at least since version 2.4.5. -- rms. */
+extern int strlen (const char *);
+# endif /* not __STDC__ */
+#endif /* __GNUC__ */
+
+#endif /* not __GNU_LIBRARY__ */
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+#ifdef _LIBC
+/* Bash 2.0 gives us an environment variable containing flags
+ indicating ARGV elements that should not be considered arguments. */
+
+/* Defined in getopt_init.c */
+extern char *__getopt_nonoption_flags;
+
+static int nonoption_flags_max_len;
+static int nonoption_flags_len;
+
+static int original_argc;
+static char *const *original_argv;
+
+/* Make sure the environment variable bash 2.0 puts in the environment
+ is valid for the getopt call we must make sure that the ARGV passed
+ to getopt is that one passed to the process. */
+static void
+__attribute__ ((unused))
+store_args_and_env (int argc, char **argv)
+{
+ /* XXX This is no good solution. We should rather copy the args so
+ that we can compare them later. But we must not use malloc(3). */
+ original_argc = argc;
+ original_argv = argv;
+}
+# ifdef text_set_element
+text_set_element (__libc_subinit, store_args_and_env);
+# endif /* text_set_element */
+
+# define SWAP_FLAGS(ch1, ch2) \
+ if (nonoption_flags_len > 0) \
+ { \
+ char __tmp = __getopt_nonoption_flags[ch1]; \
+ __getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
+ __getopt_nonoption_flags[ch2] = __tmp; \
+ }
+#else /* !_LIBC */
+# define SWAP_FLAGS(ch1, ch2)
+#endif /* _LIBC */
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,share__optind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+#if defined __STDC__ && __STDC__
+static void exchange (char **);
+#endif
+
+static void
+exchange (argv)
+ char **argv;
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = share__optind;
+ char *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+#ifdef _LIBC
+ /* First make sure the handling of the `__getopt_nonoption_flags'
+ string can work normally. Our top argument must be in the range
+ of the string. */
+ if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
+ {
+ /* We must extend the array. The user plays games with us and
+ presents new arguments. */
+ char *new_str = malloc (top + 1);
+ if (new_str == NULL)
+ nonoption_flags_len = nonoption_flags_max_len = 0;
+ else
+ {
+ memset (__mempcpy (new_str, __getopt_nonoption_flags,
+ nonoption_flags_max_len),
+ '\0', top + 1 - nonoption_flags_max_len);
+ nonoption_flags_max_len = top + 1;
+ __getopt_nonoption_flags = new_str;
+ }
+ }
+#endif
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ SWAP_FLAGS (bottom + i, middle + i);
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (share__optind - last_nonopt);
+ last_nonopt = share__optind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+#if defined __STDC__ && __STDC__
+static const char *share___getopt_initialize (int, char **, const char *);
+#endif
+static const char *
+share___getopt_initialize (argc, argv, optstring)
+ int argc;
+ char **argv;
+ const char *optstring;
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = share__optind;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == '-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == '+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+#ifdef _LIBC
+ if (posixly_correct == NULL
+ && argc == original_argc && argv == original_argv)
+ {
+ if (nonoption_flags_max_len == 0)
+ {
+ if (__getopt_nonoption_flags == NULL
+ || __getopt_nonoption_flags[0] == '\0')
+ nonoption_flags_max_len = -1;
+ else
+ {
+ const char *orig_str = __getopt_nonoption_flags;
+ int len = nonoption_flags_max_len = strlen (orig_str);
+ if (nonoption_flags_max_len < argc)
+ nonoption_flags_max_len = argc;
+ __getopt_nonoption_flags =
+ (char *) malloc (nonoption_flags_max_len);
+ if (__getopt_nonoption_flags == NULL)
+ nonoption_flags_max_len = -1;
+ else
+ memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
+ '\0', nonoption_flags_max_len - len);
+ }
+ }
+ nonoption_flags_len = nonoption_flags_max_len;
+ }
+ else
+ nonoption_flags_len = 0;
+#else
+ (void)argc, (void)argv;
+#endif
+
+ return optstring;
+}
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `share__getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `share__getopt' finds another option character, it returns that character,
+ updating `share__optind' and `nextchar' so that the next call to `share__getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `share__getopt' returns -1.
+ Then `share__optind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `share__opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `share__optarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `share__optarg', otherwise `share__optarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `share__getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct share__option' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+share___getopt_internal (argc, argv, optstring, longopts, longind, long_only)
+ int argc;
+ char **argv;
+ const char *optstring;
+ const struct share__option *longopts;
+ int *longind;
+ int long_only;
+{
+ share__optarg = NULL;
+
+ if (share__optind == 0 || !share____getopt_initialized)
+ {
+ if (share__optind == 0)
+ share__optind = 1; /* Don't scan ARGV[0], the program name. */
+ optstring = share___getopt_initialize (argc, argv, optstring);
+ share____getopt_initialized = 1;
+ }
+
+ /* Test whether ARGV[share__optind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+#ifdef _LIBC
+# define NONOPTION_P (argv[share__optind][0] != '-' || argv[share__optind][1] == '\0' \
+ || (share__optind < nonoption_flags_len \
+ && __getopt_nonoption_flags[share__optind] == '1'))
+#else
+# define NONOPTION_P (argv[share__optind][0] != '-' || argv[share__optind][1] == '\0')
+#endif
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (last_nonopt > share__optind)
+ last_nonopt = share__optind;
+ if (first_nonopt > share__optind)
+ first_nonopt = share__optind;
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != share__optind)
+ exchange ((char **) argv);
+ else if (last_nonopt != share__optind)
+ first_nonopt = share__optind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (share__optind < argc && NONOPTION_P)
+ share__optind++;
+ last_nonopt = share__optind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (share__optind != argc && !strcmp (argv[share__optind], "--"))
+ {
+ share__optind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != share__optind)
+ exchange ((char **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = share__optind;
+ last_nonopt = argc;
+
+ share__optind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (share__optind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ share__optind = first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (ordering == REQUIRE_ORDER)
+ return -1;
+ share__optarg = argv[share__optind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[share__optind] + 1
+ + (longopts != NULL && argv[share__optind][1] == '-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[share__optind][1] == '-'
+ || (long_only && (argv[share__optind][2] || !my_index (optstring, argv[share__optind][1])))))
+ {
+ char *nameend;
+ const struct share__option *p;
+ const struct share__option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar)
+ == (unsigned int) strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (share__opterr)
+ fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
+ argv[0], argv[share__optind]);
+ nextchar += strlen (nextchar);
+ share__optind++;
+ share__optopt = 0;
+ return '?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ share__optind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ share__optarg = nameend + 1;
+ else
+ {
+ if (share__opterr)
+ {
+ if (argv[share__optind - 1][1] == '-')
+ /* --option */
+ fprintf (stderr,
+ _("%s: option `--%s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fprintf (stderr,
+ _("%s: option `%c%s' doesn't allow an argument\n"),
+ argv[0], argv[share__optind - 1][0], pfound->name);
+ }
+
+ nextchar += strlen (nextchar);
+
+ share__optopt = pfound->val;
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (share__optind < argc)
+ share__optarg = argv[share__optind++];
+ else
+ {
+ if (share__opterr)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[share__optind - 1]);
+ nextchar += strlen (nextchar);
+ share__optopt = pfound->val;
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not share__getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[share__optind][1] == '-'
+ || my_index (optstring, *nextchar) == NULL)
+ {
+ static char empty_string [1] = { 0 } ;
+ if (share__opterr)
+ {
+ if (argv[share__optind][1] == '-')
+ /* --option */
+ fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
+ argv[0], argv[share__optind][0], nextchar);
+ }
+ nextchar = empty_string;
+ share__optind++;
+ share__optopt = 0;
+ return '?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ char c = *nextchar++;
+ const char *temp = my_index (optstring, c);
+
+ /* Increment `share__optind' when we start to process its last character. */
+ if (*nextchar == '\0')
+ ++share__optind;
+
+ if (temp == NULL || c == ':')
+ {
+ if (share__opterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: illegal option -- %c\n"),
+ argv[0], c);
+ else
+ fprintf (stderr, _("%s: invalid option -- %c\n"),
+ argv[0], c);
+ }
+ share__optopt = c;
+ return '?';
+ }
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == 'W' && temp[1] == ';')
+ {
+ char *nameend;
+ const struct share__option *p;
+ const struct share__option *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ share__optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ share__optind++;
+ }
+ else if (share__optind == argc)
+ {
+ if (share__opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr, _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ share__optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ return c;
+ }
+ else
+ /* We already incremented `share__optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ share__optarg = argv[share__optind++];
+
+ /* share__optarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (nextchar = nameend = share__optarg; *nameend && *nameend != '='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!strncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar) == strlen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (share__opterr)
+ fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
+ argv[0], argv[share__optind]);
+ nextchar += strlen (nextchar);
+ share__optind++;
+ return '?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ share__optarg = nameend + 1;
+ else
+ {
+ if (share__opterr)
+ fprintf (stderr, _("\
+%s: option `-W %s' doesn't allow an argument\n"),
+ argv[0], pfound->name);
+
+ nextchar += strlen (nextchar);
+ return '?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (share__optind < argc)
+ share__optarg = argv[share__optind++];
+ else
+ {
+ if (share__opterr)
+ fprintf (stderr,
+ _("%s: option `%s' requires an argument\n"),
+ argv[0], argv[share__optind - 1]);
+ nextchar += strlen (nextchar);
+ return optstring[0] == ':' ? ':' : '?';
+ }
+ }
+ nextchar += strlen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ nextchar = NULL;
+ return 'W'; /* Let the application handle it. */
+ }
+ if (temp[1] == ':')
+ {
+ if (temp[2] == ':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != '\0')
+ {
+ share__optarg = nextchar;
+ share__optind++;
+ }
+ else
+ share__optarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != '\0')
+ {
+ share__optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ share__optind++;
+ }
+ else if (share__optind == argc)
+ {
+ if (share__opterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fprintf (stderr,
+ _("%s: option requires an argument -- %c\n"),
+ argv[0], c);
+ }
+ share__optopt = c;
+ if (optstring[0] == ':')
+ c = ':';
+ else
+ c = '?';
+ }
+ else
+ /* We already incremented `share__optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ share__optarg = argv[share__optind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+share__getopt (argc, argv, optstring)
+ int argc;
+ char **argv;
+ const char *optstring;
+{
+ return share___getopt_internal (argc, argv, optstring,
+ (const struct share__option *) 0,
+ (int *) 0,
+ 0);
+}
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `share__getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = share__optind ? share__optind : 1;
+
+ c = share__getopt (argc, argv, "abc:d:0123456789");
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", share__optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (share__optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (share__optind < argc)
+ printf ("%s ", argv[share__optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/src/FLAC/src/share/getopt/getopt1.c b/src/FLAC/src/share/getopt/getopt1.c
new file mode 100644
index 0000000..969e0ff
--- /dev/null
+++ b/src/FLAC/src/share/getopt/getopt1.c
@@ -0,0 +1,204 @@
+/*
+ NOTE:
+ I cannot get the vanilla getopt code to work (i.e. compile only what
+ is needed and not duplicate symbols found in the standard library)
+ on all the platforms that FLAC supports. In particular the gating
+ of code with the ELIDE_CODE #define is not accurate enough on systems
+ that are POSIX but not glibc. If someone has a patch that works on
+ GNU/Linux, Darwin, AND Solaris please submit it on the project page:
+ http://sourceforge.net/projects/flac
+
+ In the meantime I have munged the global symbols and removed gates
+ around code, while at the same time trying to touch the original as
+ little as possible.
+*/
+/* getopt_long and getopt_long_only entry points for GNU getopt.
+ Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "share/getopt.h"
+/*[JEC] was:#include "getopt.h"*/
+
+#if !defined __STDC__ || !__STDC__
+/* This is a separate conditional since some stdc systems
+ reject `defined (const)'. */
+#ifndef const
+#define const
+#endif
+#endif
+
+#include <stdio.h>
+
+/* Comment out all this code if we are using the GNU C Library, and are not
+ actually compiling the library itself. This code is part of the GNU C
+ Library, but also included in many other GNU distributions. Compiling
+ and linking in this code is a waste when using the GNU C library
+ (especially if it is a shared library). Rather than having every GNU
+ program understand `configure --with-gnu-libc' and omit the object files,
+ it is simpler to just do this in the source for each such file. */
+
+#define GETOPT_INTERFACE_VERSION 2
+#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
+#include <gnu-versions.h>
+#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
+#define ELIDE_CODE
+#endif
+#endif
+
+#if 1
+/*[JEC] was:#ifndef ELIDE_CODE*/
+
+
+/* This needs to come after some library #include
+ to get __GNU_LIBRARY__ defined. */
+#ifdef __GNU_LIBRARY__
+#include <stdlib.h>
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+int
+share__getopt_long (argc, argv, options, long_options, opt_index)
+ int argc;
+ char **argv;
+ const char *options;
+ const struct share__option *long_options;
+ int *opt_index;
+{
+ return share___getopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like share__getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+
+int
+share__getopt_long_only (argc, argv, options, long_options, opt_index)
+ int argc;
+ char **argv;
+ const char *options;
+ const struct share__option *long_options;
+ int *opt_index;
+{
+ return share___getopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
+
+
+#endif /* Not ELIDE_CODE. */
+
+#ifdef TEST
+
+#include <stdio.h>
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_optind = 0;
+
+ while (1)
+ {
+ int this_option_optind = share__optind ? share__optind : 1;
+ int option_index = 0;
+ static struct share__option long_options[] =
+ {
+ {"add", 1, 0, 0},
+ {"append", 0, 0, 0},
+ {"delete", 1, 0, 0},
+ {"verbose", 0, 0, 0},
+ {"create", 0, 0, 0},
+ {"file", 1, 0, 0},
+ {0, 0, 0, 0}
+ };
+
+ c = share__getopt_long (argc, argv, "abc:d:0123456789",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ printf ("option %s", long_options[option_index].name);
+ if (share__optarg)
+ printf (" with arg %s", share__optarg);
+ printf ("\n");
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_optind != 0 && digit_optind != this_option_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_optind = this_option_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", share__optarg);
+ break;
+
+ case 'd':
+ printf ("option d with value `%s'\n", share__optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (share__optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (share__optind < argc)
+ printf ("%s ", argv[share__optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/src/FLAC/src/share/grabbag/Makefile.am b/src/FLAC/src/share/grabbag/Makefile.am
new file mode 100644
index 0000000..10f3bef
--- /dev/null
+++ b/src/FLAC/src/share/grabbag/Makefile.am
@@ -0,0 +1,20 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_srcdir)/src/FLAC/include
+
+noinst_LTLIBRARIES = libgrabbag.la
+
+libgrabbag_la_SOURCES = \
+ cuesheet.c \
+ file.c \
+ picture.c \
+ replaygain.c \
+ seektable.c
+
+debug:
+ $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+ $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/FLAC/src/share/grabbag/cuesheet.c b/src/FLAC/src/share/grabbag/cuesheet.c
new file mode 100644
index 0000000..a30fa03
--- /dev/null
+++ b/src/FLAC/src/share/grabbag/cuesheet.c
@@ -0,0 +1,599 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "share/grabbag.h"
+#include "FLAC/assert.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames)
+{
+ return ((minutes * 60) + seconds) * 75 + frames;
+}
+
+void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames)
+{
+ *frames = frame % 75;
+ frame /= 75;
+ *seconds = frame % 60;
+ frame /= 60;
+ *minutes = frame;
+}
+
+/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */
+static int local__parse_int_(const char *s)
+{
+ int ret = 0;
+ char c;
+
+ if(*s == '\0')
+ return -1;
+
+ while('\0' != (c = *s++))
+ if(c >= '0' && c <= '9')
+ ret = ret * 10 + (c - '0');
+ else
+ return -1;
+
+ return ret;
+}
+
+/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */
+static FLAC__int64 local__parse_int64_(const char *s)
+{
+ FLAC__int64 ret = 0;
+ char c;
+
+ if(*s == '\0')
+ return -1;
+
+ while('\0' != (c = *s++))
+ if(c >= '0' && c <= '9')
+ ret = ret * 10 + (c - '0');
+ else
+ return -1;
+
+ return ret;
+}
+
+/* accept '[0-9]+:[0-9][0-9]?:[0-9][0-9]?', but max second of 59 and max frame of 74, e.g. 0:0:0, 123:45:67
+ * return sample number or <0 for error
+ */
+static FLAC__int64 local__parse_msf_(const char *s)
+{
+ FLAC__int64 ret, field;
+ char c;
+
+ c = *s++;
+ if(c >= '0' && c <= '9')
+ field = (c - '0');
+ else
+ return -1;
+ while(':' != (c = *s++)) {
+ if(c >= '0' && c <= '9')
+ field = field * 10 + (c - '0');
+ else
+ return -1;
+ }
+
+ ret = field * 60 * 44100;
+
+ c = *s++;
+ if(c >= '0' && c <= '9')
+ field = (c - '0');
+ else
+ return -1;
+ if(':' != (c = *s++)) {
+ if(c >= '0' && c <= '9') {
+ field = field * 10 + (c - '0');
+ c = *s++;
+ if(c != ':')
+ return -1;
+ }
+ else
+ return -1;
+ }
+
+ if(field >= 60)
+ return -1;
+
+ ret += field * 44100;
+
+ c = *s++;
+ if(c >= '0' && c <= '9')
+ field = (c - '0');
+ else
+ return -1;
+ if('\0' != (c = *s++)) {
+ if(c >= '0' && c <= '9') {
+ field = field * 10 + (c - '0');
+ c = *s++;
+ }
+ else
+ return -1;
+ }
+
+ if(c != '\0')
+ return -1;
+
+ if(field >= 75)
+ return -1;
+
+ ret += field * (44100 / 75);
+
+ return ret;
+}
+
+static char *local__get_field_(char **s, FLAC__bool allow_quotes)
+{
+ FLAC__bool has_quote = false;
+ char *p;
+
+ FLAC__ASSERT(0 != s);
+
+ if(0 == *s)
+ return 0;
+
+ /* skip leading whitespace */
+ while(**s && 0 != strchr(" \t\r\n", **s))
+ (*s)++;
+
+ if(**s == 0) {
+ *s = 0;
+ return 0;
+ }
+
+ if(allow_quotes && (**s == '"')) {
+ has_quote = true;
+ (*s)++;
+ if(**s == 0) {
+ *s = 0;
+ return 0;
+ }
+ }
+
+ p = *s;
+
+ if(has_quote) {
+ *s = strchr(*s, '\"');
+ /* if there is no matching end quote, it's an error */
+ if(0 == *s)
+ p = *s = 0;
+ else {
+ **s = '\0';
+ (*s)++;
+ }
+ }
+ else {
+ while(**s && 0 == strchr(" \t\r\n", **s))
+ (*s)++;
+ if(**s) {
+ **s = '\0';
+ (*s)++;
+ }
+ else
+ *s = 0;
+ }
+
+ return p;
+}
+
+static FLAC__bool local__cuesheet_parse_(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__StreamMetadata *cuesheet, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+#define FLAC__STRCASECMP stricmp
+#else
+#define FLAC__STRCASECMP strcasecmp
+#endif
+ char buffer[4096], *line, *field;
+ unsigned forced_leadout_track_num = 0;
+ FLAC__uint64 forced_leadout_track_offset = 0;
+ int in_track_num = -1, in_index_num = -1;
+ FLAC__bool disc_has_catalog = false, track_has_flags = false, track_has_isrc = false, has_forced_leadout = false;
+ FLAC__StreamMetadata_CueSheet *cs = &cuesheet->data.cue_sheet;
+
+ cs->lead_in = is_cdda? 2 * 44100 /* The default lead-in size for CD-DA */ : 0;
+ cs->is_cd = is_cdda;
+
+ while(0 != fgets(buffer, sizeof(buffer), file)) {
+ (*last_line_read)++;
+ line = buffer;
+
+ {
+ size_t linelen = strlen(line);
+ if((linelen == sizeof(buffer)-1) && line[linelen-1] != '\n') {
+ *error_message = "line too long";
+ return false;
+ }
+ }
+
+ if(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ if(0 == FLAC__STRCASECMP(field, "CATALOG")) {
+ if(disc_has_catalog) {
+ *error_message = "found multiple CATALOG commands";
+ return false;
+ }
+ if(0 == (field = local__get_field_(&line, /*allow_quotes=*/true))) {
+ *error_message = "CATALOG is missing catalog number";
+ return false;
+ }
+ if(strlen(field) >= sizeof(cs->media_catalog_number)) {
+ *error_message = "CATALOG number is too long";
+ return false;
+ }
+ if(is_cdda && (strlen(field) != 13 || strspn(field, "0123456789") != 13)) {
+ *error_message = "CD-DA CATALOG number must be 13 decimal digits";
+ return false;
+ }
+ strcpy(cs->media_catalog_number, field);
+ disc_has_catalog = true;
+ }
+ else if(0 == FLAC__STRCASECMP(field, "FLAGS")) {
+ if(track_has_flags) {
+ *error_message = "found multiple FLAGS commands";
+ return false;
+ }
+ if(in_track_num < 0 || in_index_num >= 0) {
+ *error_message = "FLAGS command must come after TRACK but before INDEX";
+ return false;
+ }
+ while(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ if(0 == FLAC__STRCASECMP(field, "PRE"))
+ cs->tracks[cs->num_tracks-1].pre_emphasis = 1;
+ }
+ track_has_flags = true;
+ }
+ else if(0 == FLAC__STRCASECMP(field, "INDEX")) {
+ FLAC__int64 xx;
+ FLAC__StreamMetadata_CueSheet_Track *track = &cs->tracks[cs->num_tracks-1];
+ if(in_track_num < 0) {
+ *error_message = "found INDEX before any TRACK";
+ return false;
+ }
+ if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ *error_message = "INDEX is missing index number";
+ return false;
+ }
+ in_index_num = local__parse_int_(field);
+ if(in_index_num < 0) {
+ *error_message = "INDEX has invalid index number";
+ return false;
+ }
+ FLAC__ASSERT(cs->num_tracks > 0);
+ if(track->num_indices == 0) {
+ /* it's the first index point of the track */
+ if(in_index_num > 1) {
+ *error_message = "first INDEX number of a TRACK must be 0 or 1";
+ return false;
+ }
+ }
+ else {
+ if(in_index_num != track->indices[track->num_indices-1].number + 1) {
+ *error_message = "INDEX numbers must be sequential";
+ return false;
+ }
+ }
+ if(is_cdda && in_index_num > 99) {
+ *error_message = "CD-DA INDEX number must be between 0 and 99, inclusive";
+ return false;
+ }
+ /*@@@ search for duplicate track number? */
+ if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ *error_message = "INDEX is missing an offset after the index number";
+ return false;
+ }
+ xx = local__parse_msf_(field);
+ if(xx < 0) {
+ if(is_cdda) {
+ *error_message = "illegal INDEX offset (not of the form MM:SS:FF)";
+ return false;
+ }
+ xx = local__parse_int64_(field);
+ if(xx < 0) {
+ *error_message = "illegal INDEX offset";
+ return false;
+ }
+ }
+ if(is_cdda && cs->num_tracks == 1 && cs->tracks[0].num_indices == 0 && xx != 0) {
+ *error_message = "first INDEX of first TRACK must have an offset of 00:00:00";
+ return false;
+ }
+ if(is_cdda && track->num_indices > 0 && (FLAC__uint64)xx <= track->indices[track->num_indices-1].offset) {
+ *error_message = "CD-DA INDEX offsets must increase in time";
+ return false;
+ }
+ /* fill in track offset if it's the first index of the track */
+ if(track->num_indices == 0)
+ track->offset = (FLAC__uint64)xx;
+ if(is_cdda && cs->num_tracks > 1) {
+ const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-2];
+ if((FLAC__uint64)xx <= prev->offset + prev->indices[prev->num_indices-1].offset) {
+ *error_message = "CD-DA INDEX offsets must increase in time";
+ return false;
+ }
+ }
+ if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, cs->num_tracks-1, track->num_indices)) {
+ *error_message = "memory allocation error";
+ return false;
+ }
+ track->indices[track->num_indices-1].offset = (FLAC__uint64)xx - track->offset;
+ track->indices[track->num_indices-1].number = in_index_num;
+ }
+ else if(0 == FLAC__STRCASECMP(field, "ISRC")) {
+ char *l, *r;
+ if(track_has_isrc) {
+ *error_message = "found multiple ISRC commands";
+ return false;
+ }
+ if(in_track_num < 0 || in_index_num >= 0) {
+ *error_message = "ISRC command must come after TRACK but before INDEX";
+ return false;
+ }
+ if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ *error_message = "ISRC is missing ISRC number";
+ return false;
+ }
+ /* strip out dashes */
+ for(l = r = field; *r; r++) {
+ if(*r != '-')
+ *l++ = *r;
+ }
+ *l = '\0';
+ if(strlen(field) != 12 || strspn(field, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") < 5 || strspn(field+5, "1234567890") != 7) {
+ *error_message = "invalid ISRC number";
+ return false;
+ }
+ strcpy(cs->tracks[cs->num_tracks-1].isrc, field);
+ track_has_isrc = true;
+ }
+ else if(0 == FLAC__STRCASECMP(field, "TRACK")) {
+ if(cs->num_tracks > 0) {
+ const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1];
+ if(
+ prev->num_indices == 0 ||
+ (
+ is_cdda &&
+ (
+ (prev->num_indices == 1 && prev->indices[0].number != 1) ||
+ (prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1)
+ )
+ )
+ ) {
+ *error_message = is_cdda?
+ "previous TRACK must specify at least one INDEX 01" :
+ "previous TRACK must specify at least one INDEX";
+ return false;
+ }
+ }
+ if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ *error_message = "TRACK is missing track number";
+ return false;
+ }
+ in_track_num = local__parse_int_(field);
+ if(in_track_num < 0) {
+ *error_message = "TRACK has invalid track number";
+ return false;
+ }
+ if(in_track_num == 0) {
+ *error_message = "TRACK number must be greater than 0";
+ return false;
+ }
+ if(is_cdda && in_track_num > 99) {
+ *error_message = "CD-DA TRACK number must be between 1 and 99, inclusive";
+ return false;
+ }
+ if(is_cdda && cs->num_tracks > 0 && in_track_num != cs->tracks[cs->num_tracks-1].number + 1) {
+ *error_message = "CD-DA TRACK numbers must be sequential";
+ return false;
+ }
+ /*@@@ search for duplicate track number? */
+ if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ *error_message = "TRACK is missing a track type after the track number";
+ return false;
+ }
+ if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) {
+ *error_message = "memory allocation error";
+ return false;
+ }
+ cs->tracks[cs->num_tracks-1].number = in_track_num;
+ cs->tracks[cs->num_tracks-1].type = (0 == FLAC__STRCASECMP(field, "AUDIO"))? 0 : 1; /*@@@ should we be more strict with the value here? */
+ in_index_num = -1;
+ track_has_flags = false;
+ track_has_isrc = false;
+ }
+ else if(0 == FLAC__STRCASECMP(field, "REM")) {
+ if(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ if(0 == strcmp(field, "FLAC__lead-in")) {
+ FLAC__int64 xx;
+ if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ *error_message = "FLAC__lead-in is missing offset";
+ return false;
+ }
+ xx = local__parse_int64_(field);
+ if(xx < 0) {
+ *error_message = "illegal FLAC__lead-in offset";
+ return false;
+ }
+ if(is_cdda && xx % 588 != 0) {
+ *error_message = "illegal CD-DA FLAC__lead-in offset, must be even multiple of 588 samples";
+ return false;
+ }
+ cs->lead_in = (FLAC__uint64)xx;
+ }
+ else if(0 == strcmp(field, "FLAC__lead-out")) {
+ int track_num;
+ FLAC__int64 offset;
+ if(has_forced_leadout) {
+ *error_message = "multiple FLAC__lead-out commands";
+ return false;
+ }
+ if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ *error_message = "FLAC__lead-out is missing track number";
+ return false;
+ }
+ track_num = local__parse_int_(field);
+ if(track_num < 0) {
+ *error_message = "illegal FLAC__lead-out track number";
+ return false;
+ }
+ forced_leadout_track_num = (unsigned)track_num;
+ /*@@@ search for duplicate track number? */
+ if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
+ *error_message = "FLAC__lead-out is missing offset";
+ return false;
+ }
+ offset = local__parse_int64_(field);
+ if(offset < 0) {
+ *error_message = "illegal FLAC__lead-out offset";
+ return false;
+ }
+ forced_leadout_track_offset = (FLAC__uint64)offset;
+ if(forced_leadout_track_offset != lead_out_offset) {
+ *error_message = "FLAC__lead-out offset does not match end-of-stream offset";
+ return false;
+ }
+ has_forced_leadout = true;
+ }
+ }
+ }
+ }
+ }
+
+ if(cs->num_tracks == 0) {
+ *error_message = "there must be at least one TRACK command";
+ return false;
+ }
+ else {
+ const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1];
+ if(
+ prev->num_indices == 0 ||
+ (
+ is_cdda &&
+ (
+ (prev->num_indices == 1 && prev->indices[0].number != 1) ||
+ (prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1)
+ )
+ )
+ ) {
+ *error_message = is_cdda?
+ "previous TRACK must specify at least one INDEX 01" :
+ "previous TRACK must specify at least one INDEX";
+ return false;
+ }
+ }
+
+ if(!has_forced_leadout) {
+ forced_leadout_track_num = is_cdda? 170 : cs->num_tracks;
+ forced_leadout_track_offset = lead_out_offset;
+ }
+ if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) {
+ *error_message = "memory allocation error";
+ return false;
+ }
+ cs->tracks[cs->num_tracks-1].number = forced_leadout_track_num;
+ cs->tracks[cs->num_tracks-1].offset = forced_leadout_track_offset;
+
+ if(!feof(file)) {
+ *error_message = "read error";
+ return false;
+ }
+ return true;
+#undef FLAC__STRCASECMP
+}
+
+FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+ FLAC__StreamMetadata *cuesheet;
+
+ FLAC__ASSERT(0 != file);
+ FLAC__ASSERT(0 != error_message);
+ FLAC__ASSERT(0 != last_line_read);
+
+ *last_line_read = 0;
+ cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+
+ if(0 == cuesheet) {
+ *error_message = "memory allocation error";
+ return 0;
+ }
+
+ if(!local__cuesheet_parse_(file, error_message, last_line_read, cuesheet, is_cdda, lead_out_offset)) {
+ FLAC__metadata_object_delete(cuesheet);
+ return 0;
+ }
+
+ return cuesheet;
+}
+
+void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference)
+{
+ const FLAC__StreamMetadata_CueSheet *cs;
+ unsigned track_num, index_num;
+
+ FLAC__ASSERT(0 != file);
+ FLAC__ASSERT(0 != cuesheet);
+ FLAC__ASSERT(cuesheet->type == FLAC__METADATA_TYPE_CUESHEET);
+
+ cs = &cuesheet->data.cue_sheet;
+
+ if(*(cs->media_catalog_number))
+ fprintf(file, "CATALOG %s\n", cs->media_catalog_number);
+ fprintf(file, "FILE %s\n", file_reference);
+
+ for(track_num = 0; track_num < cs->num_tracks-1; track_num++) {
+ const FLAC__StreamMetadata_CueSheet_Track *track = cs->tracks + track_num;
+
+ fprintf(file, " TRACK %02u %s\n", (unsigned)track->number, track->type == 0? "AUDIO" : "DATA");
+
+ if(track->pre_emphasis)
+ fprintf(file, " FLAGS PRE\n");
+ if(*(track->isrc))
+ fprintf(file, " ISRC %s\n", track->isrc);
+
+ for(index_num = 0; index_num < track->num_indices; index_num++) {
+ const FLAC__StreamMetadata_CueSheet_Index *indx = track->indices + index_num;
+
+ fprintf(file, " INDEX %02u ", (unsigned)indx->number);
+ if(cs->is_cd) {
+ const unsigned logical_frame = (unsigned)((track->offset + indx->offset) / (44100 / 75));
+ unsigned m, s, f;
+ grabbag__cuesheet_frame_to_msf(logical_frame, &m, &s, &f);
+ fprintf(file, "%02u:%02u:%02u\n", m, s, f);
+ }
+ else
+#ifdef _MSC_VER
+ fprintf(file, "%I64u\n", track->offset + indx->offset);
+#else
+ fprintf(file, "%llu\n", (unsigned long long)(track->offset + indx->offset));
+#endif
+ }
+ }
+
+#ifdef _MSC_VER
+ fprintf(file, "REM FLAC__lead-in %I64u\n", cs->lead_in);
+ fprintf(file, "REM FLAC__lead-out %u %I64u\n", (unsigned)cs->tracks[track_num].number, cs->tracks[track_num].offset);
+#else
+ fprintf(file, "REM FLAC__lead-in %llu\n", (unsigned long long)cs->lead_in);
+ fprintf(file, "REM FLAC__lead-out %u %llu\n", (unsigned)cs->tracks[track_num].number, (unsigned long long)cs->tracks[track_num].offset);
+#endif
+}
diff --git a/src/FLAC/src/share/grabbag/file.c b/src/FLAC/src/share/grabbag/file.c
new file mode 100644
index 0000000..a481f74
--- /dev/null
+++ b/src/FLAC/src/share/grabbag/file.c
@@ -0,0 +1,192 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/utime.h> /* for utime() */
+#include <io.h> /* for chmod(), _setmode(), unlink() */
+#include <fcntl.h> /* for _O_BINARY */
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#endif
+#if defined __CYGWIN__ || defined __EMX__
+#include <io.h> /* for setmode(), O_BINARY */
+#include <fcntl.h> /* for _O_BINARY */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+#if defined _WIN32 && !defined __CYGWIN__
+#else
+#include <unistd.h> /* for unlink() */
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* for strrchr() */
+#if defined _WIN32 && !defined __CYGWIN__
+// for GetFileInformationByHandle() etc
+#include <Windows.h>
+#include <Winbase.h>
+#endif
+#include "share/grabbag.h"
+
+
+void grabbag__file_copy_metadata(const char *srcpath, const char *destpath)
+{
+ struct stat srcstat;
+ struct utimbuf srctime;
+
+ if(0 == stat(srcpath, &srcstat)) {
+ srctime.actime = srcstat.st_atime;
+ srctime.modtime = srcstat.st_mtime;
+ (void)chmod(destpath, srcstat.st_mode);
+ (void)utime(destpath, &srctime);
+ }
+}
+
+off_t grabbag__file_get_filesize(const char *srcpath)
+{
+ struct stat srcstat;
+
+ if(0 == stat(srcpath, &srcstat))
+ return srcstat.st_size;
+ else
+ return -1;
+}
+
+const char *grabbag__file_get_basename(const char *srcpath)
+{
+ const char *p;
+
+ p = strrchr(srcpath, '/');
+ if(0 == p) {
+ p = strrchr(srcpath, '\\');
+ if(0 == p)
+ return srcpath;
+ }
+ return ++p;
+}
+
+FLAC__bool grabbag__file_change_stats(const char *filename, FLAC__bool read_only)
+{
+ struct stat stats;
+
+ if(0 == stat(filename, &stats)) {
+#if !defined _MSC_VER && !defined __MINGW32__
+ if(read_only) {
+ stats.st_mode &= ~S_IWUSR;
+ stats.st_mode &= ~S_IWGRP;
+ stats.st_mode &= ~S_IWOTH;
+ }
+ else {
+ stats.st_mode |= S_IWUSR;
+ }
+#else
+ if(read_only)
+ stats.st_mode &= ~S_IWRITE;
+ else
+ stats.st_mode |= S_IWRITE;
+#endif
+ if(0 != chmod(filename, stats.st_mode))
+ return false;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+FLAC__bool grabbag__file_are_same(const char *f1, const char *f2)
+{
+#if defined _MSC_VER || defined __MINGW32__
+ /* see
+ * http://www.hydrogenaudio.org/forums/index.php?showtopic=49439&pid=444300&st=0
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/getfileinformationbyhandle.asp
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/by_handle_file_information_str.asp
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/createfile.asp
+ * apparently both the files have to be open at the same time for the comparison to work
+ */
+ FLAC__bool same = false;
+ BY_HANDLE_FILE_INFORMATION info1, info2;
+ HANDLE h1, h2;
+ BOOL ok = 1;
+ h1 = CreateFile(f1, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ h2 = CreateFile(f2, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if(h1 == INVALID_HANDLE_VALUE || h2 == INVALID_HANDLE_VALUE)
+ ok = 0;
+ ok &= GetFileInformationByHandle(h1, &info1);
+ ok &= GetFileInformationByHandle(h2, &info2);
+ if(ok)
+ same =
+ info1.dwVolumeSerialNumber == info2.dwVolumeSerialNumber &&
+ info1.nFileIndexHigh == info2.nFileIndexHigh &&
+ info1.nFileIndexLow == info2.nFileIndexLow
+ ;
+ if(h1 != INVALID_HANDLE_VALUE)
+ CloseHandle(h1);
+ if(h2 != INVALID_HANDLE_VALUE)
+ CloseHandle(h2);
+ return same;
+#else
+ struct stat s1, s2;
+ return f1 && f2 && stat(f1, &s1) == 0 && stat(f2, &s2) == 0 && s1.st_ino == s2.st_ino && s1.st_dev == s2.st_dev;
+#endif
+}
+
+FLAC__bool grabbag__file_remove_file(const char *filename)
+{
+ return grabbag__file_change_stats(filename, /*read_only=*/false) && 0 == unlink(filename);
+}
+
+FILE *grabbag__file_get_binary_stdin(void)
+{
+ /* if something breaks here it is probably due to the presence or
+ * absence of an underscore before the identifiers 'setmode',
+ * 'fileno', and/or 'O_BINARY'; check your system header files.
+ */
+#if defined _MSC_VER || defined __MINGW32__
+ _setmode(_fileno(stdin), _O_BINARY);
+#elif defined __CYGWIN__
+ /* almost certainly not needed for any modern Cygwin, but let's be safe... */
+ setmode(_fileno(stdin), _O_BINARY);
+#elif defined __EMX__
+ setmode(fileno(stdin), O_BINARY);
+#endif
+
+ return stdin;
+}
+
+FILE *grabbag__file_get_binary_stdout(void)
+{
+ /* if something breaks here it is probably due to the presence or
+ * absence of an underscore before the identifiers 'setmode',
+ * 'fileno', and/or 'O_BINARY'; check your system header files.
+ */
+#if defined _MSC_VER || defined __MINGW32__
+ _setmode(_fileno(stdout), _O_BINARY);
+#elif defined __CYGWIN__
+ /* almost certainly not needed for any modern Cygwin, but let's be safe... */
+ setmode(_fileno(stdout), _O_BINARY);
+#elif defined __EMX__
+ setmode(fileno(stdout), O_BINARY);
+#endif
+
+ return stdout;
+}
diff --git a/src/FLAC/src/share/grabbag/picture.c b/src/FLAC/src/share/grabbag/picture.c
new file mode 100644
index 0000000..68e1f51
--- /dev/null
+++ b/src/FLAC/src/share/grabbag/picture.c
@@ -0,0 +1,406 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "share/grabbag.h"
+#include "FLAC/assert.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* slightly different that strndup(): this always copies 'size' bytes starting from s into a NUL-terminated string. */
+static char *local__strndup_(const char *s, size_t size)
+{
+ char *x = (char*)malloc(size+1);
+ if(x) {
+ memcpy(x, s, size);
+ x[size] = '\0';
+ }
+ return x;
+}
+
+static FLAC__bool local__parse_type_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture)
+{
+ size_t i;
+ FLAC__uint32 val = 0;
+
+ picture->type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+
+ if(len == 0)
+ return true; /* empty string implies default to 'front cover' */
+
+ for(i = 0; i < len; i++) {
+ if(s[i] >= '0' && s[i] <= '9')
+ val = 10*val + (FLAC__uint32)(s[i] - '0');
+ else
+ return false;
+ }
+
+ if(i == len)
+ picture->type = val;
+ else
+ return false;
+
+ return true;
+}
+
+static FLAC__bool local__parse_resolution_(const char *s, size_t len, FLAC__StreamMetadata_Picture *picture)
+{
+ int state = 0;
+ size_t i;
+ FLAC__uint32 val = 0;
+
+ picture->width = picture->height = picture->depth = picture->colors = 0;
+
+ if(len == 0)
+ return true; /* empty string implies client wants to get info from the file itself */
+
+ for(i = 0; i < len; i++) {
+ if(s[i] == 'x') {
+ if(state == 0)
+ picture->width = val;
+ else if(state == 1)
+ picture->height = val;
+ else
+ return false;
+ state++;
+ val = 0;
+ }
+ else if(s[i] == '/') {
+ if(state == 2)
+ picture->depth = val;
+ else
+ return false;
+ state++;
+ val = 0;
+ }
+ else if(s[i] >= '0' && s[i] <= '9')
+ val = 10*val + (FLAC__uint32)(s[i] - '0');
+ else
+ return false;
+ }
+
+ if(state < 2)
+ return false;
+ else if(state == 2)
+ picture->depth = val;
+ else if(state == 3)
+ picture->colors = val;
+ else
+ return false;
+ if(picture->depth < 32 && 1u<<picture->depth < picture->colors)
+ return false;
+
+ return true;
+}
+
+static FLAC__bool local__extract_mime_type_(FLAC__StreamMetadata *obj)
+{
+ if(obj->data.picture.data_length >= 8 && 0 == memcmp(obj->data.picture.data, "\x89PNG\x0d\x0a\x1a\x0a", 8))
+ return FLAC__metadata_object_picture_set_mime_type(obj, "image/png", /*copy=*/true);
+ else if(obj->data.picture.data_length >= 6 && (0 == memcmp(obj->data.picture.data, "GIF87a", 6) || 0 == memcmp(obj->data.picture.data, "GIF89a", 6)))
+ return FLAC__metadata_object_picture_set_mime_type(obj, "image/gif", /*copy=*/true);
+ else if(obj->data.picture.data_length >= 2 && 0 == memcmp(obj->data.picture.data, "\xff\xd8", 2))
+ return FLAC__metadata_object_picture_set_mime_type(obj, "image/jpeg", /*copy=*/true);
+ return false;
+}
+
+static FLAC__bool local__extract_resolution_color_info_(FLAC__StreamMetadata_Picture *picture)
+{
+ const FLAC__byte *data = picture->data;
+ FLAC__uint32 len = picture->data_length;
+
+ if(0 == strcmp(picture->mime_type, "image/png")) {
+ /* c.f. http://www.w3.org/TR/PNG/ */
+ FLAC__bool need_palette = false; /* if IHDR has color_type=3, we need to also read the PLTE chunk to get the #colors */
+ if(len < 8 || memcmp(data, "\x89PNG\x0d\x0a\x1a\x0a", 8))
+ return false;
+ /* try to find IHDR chunk */
+ data += 8;
+ len -= 8;
+ while(len > 12) { /* every PNG chunk must be at least 12 bytes long */
+ const FLAC__uint32 clen = (FLAC__uint32)data[0] << 24 | (FLAC__uint32)data[1] << 16 | (FLAC__uint32)data[2] << 8 | (FLAC__uint32)data[3];
+ if(0 == memcmp(data+4, "IHDR", 4) && clen == 13) {
+ unsigned color_type = data[17];
+ picture->width = (FLAC__uint32)data[8] << 24 | (FLAC__uint32)data[9] << 16 | (FLAC__uint32)data[10] << 8 | (FLAC__uint32)data[11];
+ picture->height = (FLAC__uint32)data[12] << 24 | (FLAC__uint32)data[13] << 16 | (FLAC__uint32)data[14] << 8 | (FLAC__uint32)data[15];
+ if(color_type == 3) {
+ /* even though the bit depth for color_type==3 can be 1,2,4,or 8,
+ * the spec in 11.2.2 of http://www.w3.org/TR/PNG/ says that the
+ * sample depth is always 8
+ */
+ picture->depth = 8 * 3u;
+ need_palette = true;
+ data += 12 + clen;
+ len -= 12 + clen;
+ }
+ else {
+ if(color_type == 0) /* greyscale, 1 sample per pixel */
+ picture->depth = (FLAC__uint32)data[16];
+ if(color_type == 2) /* truecolor, 3 samples per pixel */
+ picture->depth = (FLAC__uint32)data[16] * 3u;
+ if(color_type == 4) /* greyscale+alpha, 2 samples per pixel */
+ picture->depth = (FLAC__uint32)data[16] * 2u;
+ if(color_type == 6) /* truecolor+alpha, 4 samples per pixel */
+ picture->depth = (FLAC__uint32)data[16] * 4u;
+ picture->colors = 0;
+ return true;
+ }
+ }
+ else if(need_palette && 0 == memcmp(data+4, "PLTE", 4)) {
+ picture->colors = clen / 3u;
+ return true;
+ }
+ else if(clen + 12 > len)
+ return false;
+ else {
+ data += 12 + clen;
+ len -= 12 + clen;
+ }
+ }
+ }
+ else if(0 == strcmp(picture->mime_type, "image/jpeg")) {
+ /* c.f. http://www.w3.org/Graphics/JPEG/itu-t81.pdf and Q22 of http://www.faqs.org/faqs/jpeg-faq/part1/ */
+ if(len < 2 || memcmp(data, "\xff\xd8", 2))
+ return false;
+ data += 2;
+ len -= 2;
+ while(1) {
+ /* look for sync FF byte */
+ for( ; len > 0; data++, len--) {
+ if(*data == 0xff)
+ break;
+ }
+ if(len == 0)
+ return false;
+ /* eat any extra pad FF bytes before marker */
+ for( ; len > 0; data++, len--) {
+ if(*data != 0xff)
+ break;
+ }
+ if(len == 0)
+ return false;
+ /* if we hit SOS or EOI, bail */
+ if(*data == 0xda || *data == 0xd9)
+ return false;
+ /* looking for some SOFn */
+ else if(memchr("\xc0\xc1\xc2\xc3\xc5\xc6\xc7\xc9\xca\xcb\xcd\xce\xcf", *data, 13)) {
+ data++; len--; /* skip marker byte */
+ if(len < 2)
+ return false;
+ else {
+ const FLAC__uint32 clen = (FLAC__uint32)data[0] << 8 | (FLAC__uint32)data[1];
+ if(clen < 8 || len < clen)
+ return false;
+ picture->width = (FLAC__uint32)data[5] << 8 | (FLAC__uint32)data[6];
+ picture->height = (FLAC__uint32)data[3] << 8 | (FLAC__uint32)data[4];
+ picture->depth = (FLAC__uint32)data[2] * (FLAC__uint32)data[7];
+ picture->colors = 0;
+ return true;
+ }
+ }
+ /* else skip it */
+ else {
+ data++; len--; /* skip marker byte */
+ if(len < 2)
+ return false;
+ else {
+ const FLAC__uint32 clen = (FLAC__uint32)data[0] << 8 | (FLAC__uint32)data[1];
+ if(clen < 2 || len < clen)
+ return false;
+ data += clen;
+ len -= clen;
+ }
+ }
+ }
+ }
+ else if(0 == strcmp(picture->mime_type, "image/gif")) {
+ /* c.f. http://www.w3.org/Graphics/GIF/spec-gif89a.txt */
+ if(len < 14)
+ return false;
+ if(memcmp(data, "GIF87a", 6) && memcmp(data, "GIF89a", 6))
+ return false;
+#if 0
+ /* according to the GIF spec, even if the GCTF is 0, the low 3 bits should still tell the total # colors used */
+ if(data[10] & 0x80 == 0)
+ return false;
+#endif
+ picture->width = (FLAC__uint32)data[6] | ((FLAC__uint32)data[7] << 8);
+ picture->height = (FLAC__uint32)data[8] | ((FLAC__uint32)data[9] << 8);
+#if 0
+ /* this value doesn't seem to be reliable... */
+ picture->depth = (((FLAC__uint32)(data[10] & 0x70) >> 4) + 1) * 3u;
+#else
+ /* ...just pessimistically assume it's 24-bit color without scanning all the color tables */
+ picture->depth = 8u * 3u;
+#endif
+ picture->colors = 1u << ((FLAC__uint32)(data[10] & 0x07) + 1u);
+ return true;
+ }
+ return false;
+}
+
+FLAC__StreamMetadata *grabbag__picture_parse_specification(const char *spec, const char **error_message)
+{
+ FLAC__StreamMetadata *obj;
+ int state = 0;
+ static const char *error_messages[] = {
+ "memory allocation error",
+ "invalid picture specification",
+ "invalid picture specification: can't parse resolution/color part",
+ "unable to extract resolution and color info from URL, user must set explicitly",
+ "unable to extract resolution and color info from file, user must set explicitly",
+ "error opening picture file",
+ "error reading picture file",
+ "invalid picture type",
+ "unable to guess MIME type from file, user must set explicitly",
+ "type 1 icon must be a 32x32 pixel PNG"
+ };
+
+ FLAC__ASSERT(0 != spec);
+ FLAC__ASSERT(0 != error_message);
+
+ /* double protection */
+ if(0 == spec)
+ return 0;
+ if(0 == error_message)
+ return 0;
+
+ *error_message = 0;
+
+ if(0 == (obj = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE)))
+ *error_message = error_messages[0];
+
+ if(strchr(spec, '|')) { /* full format */
+ const char *p;
+ char *q;
+ for(p = spec; *error_message==0 && *p; ) {
+ if(*p == '|') {
+ switch(state) {
+ case 0: /* type */
+ if(!local__parse_type_(spec, p-spec, &obj->data.picture))
+ *error_message = error_messages[7];
+ break;
+ case 1: /* mime type */
+ if(p-spec) { /* if blank, we'll try to guess later from the picture data */
+ if(0 == (q = local__strndup_(spec, p-spec)))
+ *error_message = error_messages[0];
+ else if(!FLAC__metadata_object_picture_set_mime_type(obj, q, /*copy=*/false))
+ *error_message = error_messages[0];
+ }
+ break;
+ case 2: /* description */
+ if(0 == (q = local__strndup_(spec, p-spec)))
+ *error_message = error_messages[0];
+ else if(!FLAC__metadata_object_picture_set_description(obj, (FLAC__byte*)q, /*copy=*/false))
+ *error_message = error_messages[0];
+ break;
+ case 3: /* resolution/color (e.g. [300x300x16[/1234]] */
+ if(!local__parse_resolution_(spec, p-spec, &obj->data.picture))
+ *error_message = error_messages[2];
+ break;
+ default:
+ *error_message = error_messages[1];
+ break;
+ }
+ p++;
+ spec = p;
+ state++;
+ }
+ else
+ p++;
+ }
+ }
+ else { /* simple format, filename only, everything else guessed */
+ if(!local__parse_type_("", 0, &obj->data.picture)) /* use default picture type */
+ *error_message = error_messages[7];
+ /* leave MIME type to be filled in later */
+ /* leave description empty */
+ /* leave the rest to be filled in later: */
+ else if(!local__parse_resolution_("", 0, &obj->data.picture))
+ *error_message = error_messages[2];
+ else
+ state = 4;
+ }
+
+ /* parse filename, read file, try to extract resolution/color info if needed */
+ if(*error_message == 0) {
+ if(state != 4)
+ *error_message = error_messages[1];
+ else { /* 'spec' points to filename/URL */
+ if(0 == strcmp(obj->data.picture.mime_type, "-->")) { /* magic MIME type means URL */
+ if(!FLAC__metadata_object_picture_set_data(obj, (const FLAC__byte*)spec, strlen(spec), /*copy=*/true))
+ *error_message = error_messages[0];
+ else if(obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0)
+ *error_message = error_messages[3];
+ }
+ else { /* regular picture file */
+ const off_t size = grabbag__file_get_filesize(spec);
+ if(size < 0)
+ *error_message = error_messages[5];
+ else {
+ FLAC__byte *buffer = (FLAC__byte*)malloc(size);
+ if(0 == buffer)
+ *error_message = error_messages[0];
+ else {
+ FILE *f = fopen(spec, "rb");
+ if(0 == f)
+ *error_message = error_messages[5];
+ else {
+ if(fread(buffer, 1, size, f) != (size_t)size)
+ *error_message = error_messages[6];
+ fclose(f);
+ if(0 == *error_message) {
+ if(!FLAC__metadata_object_picture_set_data(obj, buffer, size, /*copy=*/false))
+ *error_message = error_messages[6];
+ /* try to extract MIME type if user left it blank */
+ else if(*obj->data.picture.mime_type == '\0' && !local__extract_mime_type_(obj))
+ *error_message = error_messages[8];
+ /* try to extract resolution/color info if user left it blank */
+ else if((obj->data.picture.width == 0 || obj->data.picture.height == 0 || obj->data.picture.depth == 0) && !local__extract_resolution_color_info_(&obj->data.picture))
+ *error_message = error_messages[4];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(*error_message == 0) {
+ if(
+ obj->data.picture.type == FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD &&
+ (
+ (strcmp(obj->data.picture.mime_type, "image/png") && strcmp(obj->data.picture.mime_type, "-->")) ||
+ obj->data.picture.width != 32 ||
+ obj->data.picture.height != 32
+ )
+ )
+ *error_message = error_messages[9];
+ }
+
+ if(*error_message && obj) {
+ FLAC__metadata_object_delete(obj);
+ obj = 0;
+ }
+
+ return obj;
+}
diff --git a/src/FLAC/src/share/grabbag/replaygain.c b/src/FLAC/src/share/grabbag/replaygain.c
new file mode 100644
index 0000000..c816a2c
--- /dev/null
+++ b/src/FLAC/src/share/grabbag/replaygain.c
@@ -0,0 +1,670 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "share/grabbag.h"
+#include "share/replaygain_analysis.h"
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "FLAC/stream_decoder.h"
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <io.h> /* for chmod() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+
+#ifdef local_min
+#undef local_min
+#endif
+#define local_min(a,b) ((a)<(b)?(a):(b))
+
+#ifdef local_max
+#undef local_max
+#endif
+#define local_max(a,b) ((a)>(b)?(a):(b))
+
+#define signed_sizeof(x) ((int) (sizeof (x)))
+
+static const char *reference_format_ = "%s=%2.1f dB";
+static const char *gain_format_ = "%s=%+2.2f dB";
+static const char *peak_format_ = "%s=%1.8f";
+
+static double album_peak_, title_peak_;
+
+const unsigned GRABBAG__REPLAYGAIN_MAX_TAG_SPACE_REQUIRED = 190;
+/*
+ FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 29 + 1 + 8 +
+ FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
+ FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12 +
+ FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 10 +
+ FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + 21 + 1 + 12
+*/
+
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS = (const FLAC__byte * const)"REPLAYGAIN_REFERENCE_LOUDNESS";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN = (const FLAC__byte * const)"REPLAYGAIN_TRACK_GAIN";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK = (const FLAC__byte * const)"REPLAYGAIN_TRACK_PEAK";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_GAIN";
+const FLAC__byte * const GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK = (const FLAC__byte * const)"REPLAYGAIN_ALBUM_PEAK";
+
+
+static FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+ return (0 == stat(filename, stats));
+}
+
+static void set_file_stats_(const char *filename, struct stat *stats)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+
+ (void)chmod(filename, stats->st_mode);
+}
+
+static FLAC__bool append_tag_(FLAC__StreamMetadata *block, const char *format, const FLAC__byte *name, float value)
+{
+ char buffer[256];
+ char *saved_locale;
+ FLAC__StreamMetadata_VorbisComment_Entry entry;
+
+ FLAC__ASSERT(0 != block);
+ FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ FLAC__ASSERT(0 != format);
+ FLAC__ASSERT(0 != name);
+
+ buffer[sizeof(buffer)-1] = '\0';
+ /*
+ * We need to save the old locale and switch to "C" because the locale
+ * influences the formatting of %f and we want it a certain way.
+ */
+ saved_locale = strdup(setlocale(LC_ALL, 0));
+ if (0 == saved_locale)
+ return false;
+ setlocale(LC_ALL, "C");
+#if defined _MSC_VER || defined __MINGW32__
+ _snprintf(buffer, sizeof(buffer)-1, format, name, value);
+#else
+ snprintf(buffer, sizeof(buffer)-1, format, name, value);
+#endif
+ setlocale(LC_ALL, saved_locale);
+ free(saved_locale);
+
+ entry.entry = (FLAC__byte *)buffer;
+ entry.length = strlen(buffer);
+
+ return FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true);
+}
+
+FLAC__bool grabbag__replaygain_is_valid_sample_frequency(unsigned sample_frequency)
+{
+ static const unsigned valid_sample_rates[] = {
+ 8000,
+ 11025,
+ 12000,
+ 16000,
+ 22050,
+ 24000,
+ 32000,
+ 44100,
+ 48000
+ };
+ static const unsigned n_valid_sample_rates = sizeof(valid_sample_rates) / sizeof(valid_sample_rates[0]);
+
+ unsigned i;
+
+ for(i = 0; i < n_valid_sample_rates; i++)
+ if(sample_frequency == valid_sample_rates[i])
+ return true;
+ return false;
+}
+
+FLAC__bool grabbag__replaygain_init(unsigned sample_frequency)
+{
+ title_peak_ = album_peak_ = 0.0;
+ return InitGainAnalysis((long)sample_frequency) == INIT_GAIN_ANALYSIS_OK;
+}
+
+FLAC__bool grabbag__replaygain_analyze(const FLAC__int32 * const input[], FLAC__bool is_stereo, unsigned bps, unsigned samples)
+{
+ /* using a small buffer improves data locality; we'd like it to fit easily in the dcache */
+ static Float_t lbuffer[2048], rbuffer[2048];
+ static const unsigned nbuffer = sizeof(lbuffer) / sizeof(lbuffer[0]);
+ FLAC__int32 block_peak = 0, s;
+ unsigned i, j;
+
+ FLAC__ASSERT(bps >= 4 && bps <= FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE);
+ FLAC__ASSERT(FLAC__MIN_BITS_PER_SAMPLE == 4);
+ /*
+ * We use abs() on a FLAC__int32 which is undefined for the most negative value.
+ * If the reference codec ever handles 32bps we will have to write a special
+ * case here.
+ */
+ FLAC__ASSERT(FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE < 32);
+
+ if(bps == 16) {
+ if(is_stereo) {
+ j = 0;
+ while(samples > 0) {
+ const unsigned n = local_min(samples, nbuffer);
+ for(i = 0; i < n; i++, j++) {
+ s = input[0][j];
+ lbuffer[i] = (Float_t)s;
+ s = abs(s);
+ block_peak = local_max(block_peak, s);
+
+ s = input[1][j];
+ rbuffer[i] = (Float_t)s;
+ s = abs(s);
+ block_peak = local_max(block_peak, s);
+ }
+ samples -= n;
+ if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK)
+ return false;
+ }
+ }
+ else {
+ j = 0;
+ while(samples > 0) {
+ const unsigned n = local_min(samples, nbuffer);
+ for(i = 0; i < n; i++, j++) {
+ s = input[0][j];
+ lbuffer[i] = (Float_t)s;
+ s = abs(s);
+ block_peak = local_max(block_peak, s);
+ }
+ samples -= n;
+ if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK)
+ return false;
+ }
+ }
+ }
+ else { /* bps must be < 32 according to above assertion */
+ const double scale = (
+ (bps > 16)?
+ (double)1. / (double)(1u << (bps - 16)) :
+ (double)(1u << (16 - bps))
+ );
+
+ if(is_stereo) {
+ j = 0;
+ while(samples > 0) {
+ const unsigned n = local_min(samples, nbuffer);
+ for(i = 0; i < n; i++, j++) {
+ s = input[0][j];
+ lbuffer[i] = (Float_t)(scale * (double)s);
+ s = abs(s);
+ block_peak = local_max(block_peak, s);
+
+ s = input[1][j];
+ rbuffer[i] = (Float_t)(scale * (double)s);
+ s = abs(s);
+ block_peak = local_max(block_peak, s);
+ }
+ samples -= n;
+ if(AnalyzeSamples(lbuffer, rbuffer, n, 2) != GAIN_ANALYSIS_OK)
+ return false;
+ }
+ }
+ else {
+ j = 0;
+ while(samples > 0) {
+ const unsigned n = local_min(samples, nbuffer);
+ for(i = 0; i < n; i++, j++) {
+ s = input[0][j];
+ lbuffer[i] = (Float_t)(scale * (double)s);
+ s = abs(s);
+ block_peak = local_max(block_peak, s);
+ }
+ samples -= n;
+ if(AnalyzeSamples(lbuffer, 0, n, 1) != GAIN_ANALYSIS_OK)
+ return false;
+ }
+ }
+ }
+
+ {
+ const double peak_scale = (double)(1u << (bps - 1));
+ double peak = (double)block_peak / peak_scale;
+ if(peak > title_peak_)
+ title_peak_ = peak;
+ if(peak > album_peak_)
+ album_peak_ = peak;
+ }
+
+ return true;
+}
+
+void grabbag__replaygain_get_album(float *gain, float *peak)
+{
+ *gain = (float)GetAlbumGain();
+ *peak = (float)album_peak_;
+ album_peak_ = 0.0;
+}
+
+void grabbag__replaygain_get_title(float *gain, float *peak)
+{
+ *gain = (float)GetTitleGain();
+ *peak = (float)title_peak_;
+ title_peak_ = 0.0;
+}
+
+
+typedef struct {
+ unsigned channels;
+ unsigned bits_per_sample;
+ unsigned sample_rate;
+ FLAC__bool error;
+} DecoderInstance;
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ DecoderInstance *instance = (DecoderInstance*)client_data;
+ const unsigned bits_per_sample = frame->header.bits_per_sample;
+ const unsigned channels = frame->header.channels;
+ const unsigned sample_rate = frame->header.sample_rate;
+ const unsigned samples = frame->header.blocksize;
+
+ (void)decoder;
+
+ if(
+ !instance->error &&
+ (channels == 2 || channels == 1) &&
+ bits_per_sample == instance->bits_per_sample &&
+ channels == instance->channels &&
+ sample_rate == instance->sample_rate
+ ) {
+ instance->error = !grabbag__replaygain_analyze(buffer, channels==2, bits_per_sample, samples);
+ }
+ else {
+ instance->error = true;
+ }
+
+ if(!instance->error)
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+ else
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+}
+
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ DecoderInstance *instance = (DecoderInstance*)client_data;
+
+ (void)decoder;
+
+ if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ instance->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+ instance->channels = metadata->data.stream_info.channels;
+ instance->sample_rate = metadata->data.stream_info.sample_rate;
+
+ if(instance->channels != 1 && instance->channels != 2) {
+ instance->error = true;
+ return;
+ }
+
+ if(!grabbag__replaygain_is_valid_sample_frequency(instance->sample_rate)) {
+ instance->error = true;
+ return;
+ }
+ }
+}
+
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ DecoderInstance *instance = (DecoderInstance*)client_data;
+
+ (void)decoder, (void)status;
+
+ instance->error = true;
+}
+
+const char *grabbag__replaygain_analyze_file(const char *filename, float *title_gain, float *title_peak)
+{
+ DecoderInstance instance;
+ FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new();
+
+ if(0 == decoder)
+ return "memory allocation error";
+
+ instance.error = false;
+
+ /* It does these three by default but lets be explicit: */
+ FLAC__stream_decoder_set_md5_checking(decoder, false);
+ FLAC__stream_decoder_set_metadata_ignore_all(decoder);
+ FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_STREAMINFO);
+
+ if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &instance) != FLAC__STREAM_DECODER_INIT_STATUS_OK) {
+ FLAC__stream_decoder_delete(decoder);
+ return "initializing decoder";
+ }
+
+ if(!FLAC__stream_decoder_process_until_end_of_stream(decoder) || instance.error) {
+ FLAC__stream_decoder_delete(decoder);
+ return "decoding file";
+ }
+
+ FLAC__stream_decoder_delete(decoder);
+
+ grabbag__replaygain_get_title(title_gain, title_peak);
+
+ return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment(FLAC__StreamMetadata *block, float album_gain, float album_peak, float title_gain, float title_peak)
+{
+ const char *error;
+
+ if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block)))
+ return error;
+
+ if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak)))
+ return error;
+
+ if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak)))
+ return error;
+
+ return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_reference(FLAC__StreamMetadata *block)
+{
+ FLAC__ASSERT(0 != block);
+ FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ if(FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS) < 0)
+ return "memory allocation error";
+
+ if(!append_tag_(block, reference_format_, GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS, ReplayGainReferenceLoudness))
+ return "memory allocation error";
+
+ return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_album(FLAC__StreamMetadata *block, float album_gain, float album_peak)
+{
+ FLAC__ASSERT(0 != block);
+ FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ if(
+ FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN) < 0 ||
+ FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK) < 0
+ )
+ return "memory allocation error";
+
+ if(
+ !append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN, album_gain) ||
+ !append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK, album_peak)
+ )
+ return "memory allocation error";
+
+ return 0;
+}
+
+const char *grabbag__replaygain_store_to_vorbiscomment_title(FLAC__StreamMetadata *block, float title_gain, float title_peak)
+{
+ FLAC__ASSERT(0 != block);
+ FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ if(
+ FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN) < 0 ||
+ FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, (const char *)GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK) < 0
+ )
+ return "memory allocation error";
+
+ if(
+ !append_tag_(block, gain_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN, title_gain) ||
+ !append_tag_(block, peak_format_, GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK, title_peak)
+ )
+ return "memory allocation error";
+
+ return 0;
+}
+
+static const char *store_to_file_pre_(const char *filename, FLAC__Metadata_Chain **chain, FLAC__StreamMetadata **block)
+{
+ FLAC__Metadata_Iterator *iterator;
+ const char *error;
+ FLAC__bool found_vc_block = false;
+
+ if(0 == (*chain = FLAC__metadata_chain_new()))
+ return "memory allocation error";
+
+ if(!FLAC__metadata_chain_read(*chain, filename)) {
+ error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)];
+ FLAC__metadata_chain_delete(*chain);
+ return error;
+ }
+
+ if(0 == (iterator = FLAC__metadata_iterator_new())) {
+ FLAC__metadata_chain_delete(*chain);
+ return "memory allocation error";
+ }
+
+ FLAC__metadata_iterator_init(iterator, *chain);
+
+ do {
+ *block = FLAC__metadata_iterator_get_block(iterator);
+ if((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
+ found_vc_block = true;
+ } while(!found_vc_block && FLAC__metadata_iterator_next(iterator));
+
+ if(!found_vc_block) {
+ /* create a new block */
+ *block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ if(0 == *block) {
+ FLAC__metadata_chain_delete(*chain);
+ FLAC__metadata_iterator_delete(iterator);
+ return "memory allocation error";
+ }
+ while(FLAC__metadata_iterator_next(iterator))
+ ;
+ if(!FLAC__metadata_iterator_insert_block_after(iterator, *block)) {
+ error = FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(*chain)];
+ FLAC__metadata_chain_delete(*chain);
+ FLAC__metadata_iterator_delete(iterator);
+ return error;
+ }
+ /* iterator is left pointing to new block */
+ FLAC__ASSERT(FLAC__metadata_iterator_get_block(iterator) == *block);
+ }
+
+ FLAC__metadata_iterator_delete(iterator);
+
+ FLAC__ASSERT(0 != *block);
+ FLAC__ASSERT((*block)->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ return 0;
+}
+
+static const char *store_to_file_post_(const char *filename, FLAC__Metadata_Chain *chain, FLAC__bool preserve_modtime)
+{
+ struct stat stats;
+ const FLAC__bool have_stats = get_file_stats_(filename, &stats);
+
+ (void)grabbag__file_change_stats(filename, /*read_only=*/false);
+
+ FLAC__metadata_chain_sort_padding(chain);
+ if(!FLAC__metadata_chain_write(chain, /*use_padding=*/true, preserve_modtime)) {
+ FLAC__metadata_chain_delete(chain);
+ return FLAC__Metadata_ChainStatusString[FLAC__metadata_chain_status(chain)];
+ }
+
+ FLAC__metadata_chain_delete(chain);
+
+ if(have_stats)
+ set_file_stats_(filename, &stats);
+
+ return 0;
+}
+
+const char *grabbag__replaygain_store_to_file(const char *filename, float album_gain, float album_peak, float title_gain, float title_peak, FLAC__bool preserve_modtime)
+{
+ FLAC__Metadata_Chain *chain;
+ FLAC__StreamMetadata *block;
+ const char *error;
+
+ if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+ return error;
+
+ if(0 != (error = grabbag__replaygain_store_to_vorbiscomment(block, album_gain, album_peak, title_gain, title_peak))) {
+ FLAC__metadata_chain_delete(chain);
+ return error;
+ }
+
+ if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+ return error;
+
+ return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_reference(const char *filename, FLAC__bool preserve_modtime)
+{
+ FLAC__Metadata_Chain *chain;
+ FLAC__StreamMetadata *block;
+ const char *error;
+
+ if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+ return error;
+
+ if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_reference(block))) {
+ FLAC__metadata_chain_delete(chain);
+ return error;
+ }
+
+ if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+ return error;
+
+ return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_album(const char *filename, float album_gain, float album_peak, FLAC__bool preserve_modtime)
+{
+ FLAC__Metadata_Chain *chain;
+ FLAC__StreamMetadata *block;
+ const char *error;
+
+ if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+ return error;
+
+ if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_album(block, album_gain, album_peak))) {
+ FLAC__metadata_chain_delete(chain);
+ return error;
+ }
+
+ if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+ return error;
+
+ return 0;
+}
+
+const char *grabbag__replaygain_store_to_file_title(const char *filename, float title_gain, float title_peak, FLAC__bool preserve_modtime)
+{
+ FLAC__Metadata_Chain *chain;
+ FLAC__StreamMetadata *block;
+ const char *error;
+
+ if(0 != (error = store_to_file_pre_(filename, &chain, &block)))
+ return error;
+
+ if(0 != (error = grabbag__replaygain_store_to_vorbiscomment_title(block, title_gain, title_peak))) {
+ FLAC__metadata_chain_delete(chain);
+ return error;
+ }
+
+ if(0 != (error = store_to_file_post_(filename, chain, preserve_modtime)))
+ return error;
+
+ return 0;
+}
+
+static FLAC__bool parse_double_(const FLAC__StreamMetadata_VorbisComment_Entry *entry, double *val)
+{
+ char s[32], *end;
+ const char *p, *q;
+ double v;
+
+ FLAC__ASSERT(0 != entry);
+ FLAC__ASSERT(0 != val);
+
+ p = (const char *)entry->entry;
+ q = strchr(p, '=');
+ if(0 == q)
+ return false;
+ q++;
+ memset(s, 0, sizeof(s)-1);
+ strncpy(s, q, local_min(signed_sizeof(s)-1, entry->length - (q-p)));
+
+ v = strtod(s, &end);
+ if(end == s)
+ return false;
+
+ *val = v;
+ return true;
+}
+
+FLAC__bool grabbag__replaygain_load_from_vorbiscomment(const FLAC__StreamMetadata *block, FLAC__bool album_mode, FLAC__bool strict, double *reference, double *gain, double *peak)
+{
+ int reference_offset, gain_offset, peak_offset;
+
+ FLAC__ASSERT(0 != block);
+ FLAC__ASSERT(0 != reference);
+ FLAC__ASSERT(0 != gain);
+ FLAC__ASSERT(0 != peak);
+ FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_VORBIS_COMMENT);
+
+ /* Default to current level until overridden by a detected tag; this
+ * will always be true until we change replaygain_analysis.c
+ */
+ *reference = ReplayGainReferenceLoudness;
+
+ if(0 <= (reference_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)GRABBAG__REPLAYGAIN_TAG_REFERENCE_LOUDNESS)))
+ (void)parse_double_(block->data.vorbis_comment.comments + reference_offset, reference);
+
+ if(0 > (gain_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_GAIN : GRABBAG__REPLAYGAIN_TAG_TITLE_GAIN))))
+ return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+ if(0 > (peak_offset = FLAC__metadata_object_vorbiscomment_find_entry_from(block, /*offset=*/0, (const char *)(album_mode? GRABBAG__REPLAYGAIN_TAG_ALBUM_PEAK : GRABBAG__REPLAYGAIN_TAG_TITLE_PEAK))))
+ return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+
+ if(!parse_double_(block->data.vorbis_comment.comments + gain_offset, gain))
+ return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+ if(!parse_double_(block->data.vorbis_comment.comments + peak_offset, peak))
+ return !strict && grabbag__replaygain_load_from_vorbiscomment(block, !album_mode, /*strict=*/true, reference, gain, peak);
+
+ return true;
+}
+
+double grabbag__replaygain_compute_scale_factor(double peak, double gain, double preamp, FLAC__bool prevent_clipping)
+{
+ double scale;
+ FLAC__ASSERT(peak >= 0.0);
+ gain += preamp;
+ scale = (float) pow(10.0, gain * 0.05);
+ if(prevent_clipping && peak > 0.0) {
+ const double max_scale = (float)(1.0 / peak);
+ if(scale > max_scale)
+ scale = max_scale;
+ }
+ return scale;
+}
diff --git a/src/FLAC/src/share/grabbag/seektable.c b/src/FLAC/src/share/grabbag/seektable.c
new file mode 100644
index 0000000..55ac766
--- /dev/null
+++ b/src/FLAC/src/share/grabbag/seektable.c
@@ -0,0 +1,132 @@
+/* grabbag - Convenience lib for various routines common to several tools
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "share/grabbag.h"
+#include "FLAC/assert.h"
+#include <stdlib.h> /* for atoi() */
+#include <string.h>
+
+#ifdef _MSC_VER
+/* There's no strtoll() in MSVC6 so we just write a specialized one */
+static FLAC__int64 local__strtoll(const char *src, char **endptr)
+{
+ FLAC__bool neg = false;
+ FLAC__int64 ret = 0;
+ int c;
+ FLAC__ASSERT(0 != src);
+ if(*src == '-') {
+ neg = true;
+ src++;
+ }
+ while(0 != (c = *src)) {
+ c -= '0';
+ if(c >= 0 && c <= 9)
+ ret = (ret * 10) + c;
+ else
+ break;
+ src++;
+ }
+ if(endptr)
+ *endptr = (char*)src;
+ return neg? -ret : ret;
+}
+#endif
+
+FLAC__bool grabbag__seektable_convert_specification_to_template(const char *spec, FLAC__bool only_explicit_placeholders, FLAC__uint64 total_samples_to_encode, unsigned sample_rate, FLAC__StreamMetadata *seektable_template, FLAC__bool *spec_has_real_points)
+{
+ unsigned i;
+ const char *pt;
+
+ FLAC__ASSERT(0 != spec);
+ FLAC__ASSERT(0 != seektable_template);
+ FLAC__ASSERT(seektable_template->type = FLAC__METADATA_TYPE_SEEKTABLE);
+
+ if(0 != spec_has_real_points)
+ *spec_has_real_points = false;
+
+ for(pt = spec, i = 0; pt && *pt; i++) {
+ const char *q = strchr(pt, ';');
+ FLAC__ASSERT(0 != q);
+
+ if(q > pt) {
+ if(0 == strncmp(pt, "X;", 2)) { /* -S X */
+ if(!FLAC__metadata_object_seektable_template_append_placeholders(seektable_template, 1))
+ return false;
+ }
+ else if(q[-1] == 'x') { /* -S #x */
+ if(total_samples_to_encode > 0) { /* we can only do these if we know the number of samples to encode up front */
+ if(0 != spec_has_real_points)
+ *spec_has_real_points = true;
+ if(!only_explicit_placeholders) {
+ const int n = (unsigned)atoi(pt);
+ if(n > 0)
+ if(!FLAC__metadata_object_seektable_template_append_spaced_points(seektable_template, (unsigned)n, total_samples_to_encode))
+ return false;
+ }
+ }
+ }
+ else if(q[-1] == 's') { /* -S #s */
+ if(total_samples_to_encode > 0) { /* we can only do these if we know the number of samples to encode up front */
+ FLAC__ASSERT(sample_rate > 0);
+ if(0 != spec_has_real_points)
+ *spec_has_real_points = true;
+ if(!only_explicit_placeholders) {
+ const double sec = atof(pt);
+ if(sec > 0.0) {
+ unsigned samples = (unsigned)(sec * (double)sample_rate);
+ if(samples > 0) {
+ /* +1 for the initial point at sample 0 */
+ if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(seektable_template, samples, total_samples_to_encode))
+ return false;
+ }
+ }
+ }
+ }
+ }
+ else { /* -S # */
+ if(0 != spec_has_real_points)
+ *spec_has_real_points = true;
+ if(!only_explicit_placeholders) {
+ char *endptr;
+#ifdef _MSC_VER
+ const FLAC__int64 n = local__strtoll(pt, &endptr);
+#else
+ const FLAC__int64 n = (FLAC__int64)strtoll(pt, &endptr, 10);
+#endif
+ if(
+ (n > 0 || (endptr > pt && *endptr == ';')) && /* is a valid number (extra check needed for "0") */
+ (total_samples_to_encode == 0 || (FLAC__uint64)n < total_samples_to_encode) /* number is not >= the known total_samples_to_encode */
+ )
+ if(!FLAC__metadata_object_seektable_template_append_point(seektable_template, (FLAC__uint64)n))
+ return false;
+ }
+ }
+ }
+
+ pt = ++q;
+ }
+
+ if(!FLAC__metadata_object_seektable_template_sort(seektable_template, /*compact=*/true))
+ return false;
+
+ return true;
+}
diff --git a/src/FLAC/src/share/replaygain_anal/Makefile.am b/src/FLAC/src/share/replaygain_anal/Makefile.am
new file mode 100644
index 0000000..b8c064e
--- /dev/null
+++ b/src/FLAC/src/share/replaygain_anal/Makefile.am
@@ -0,0 +1,15 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_srcdir)/src/FLAC/include/share
+
+noinst_LTLIBRARIES = libreplaygain_analysis.la
+
+libreplaygain_analysis_la_SOURCES = replaygain_analysis.c
+
+debug:
+ $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+ $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/FLAC/src/share/replaygain_anal/replaygain_analysis.c b/src/FLAC/src/share/replaygain_anal/replaygain_analysis.c
new file mode 100644
index 0000000..ad9e5ec
--- /dev/null
+++ b/src/FLAC/src/share/replaygain_anal/replaygain_analysis.c
@@ -0,0 +1,419 @@
+/*
+ * ReplayGainAnalysis - analyzes input samples and give the recommended dB change
+ * Copyright (C) 2001 David Robinson and Glen Sawyer
+ *
+ * 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
+ *
+ * concept and filter values by David Robinson (David@Robinson.org)
+ * -- blame him if you think the idea is flawed
+ * original coding by Glen Sawyer (glensawyer@hotmail.com)
+ * -- blame him if you think this runs too slowly, or the coding is otherwise flawed
+ *
+ * lots of code improvements by Frank Klemm ( http://www.uni-jena.de/~pfk/mpp/ )
+ * -- credit him for all the _good_ programming ;)
+ *
+ * minor cosmetic tweaks to integrate with FLAC by Josh Coalson
+ *
+ *
+ * For an explanation of the concepts and the basic algorithms involved, go to:
+ * http://www.replaygain.org/
+ */
+
+/*
+ * Here's the deal. Call
+ *
+ * InitGainAnalysis ( long samplefreq );
+ *
+ * to initialize everything. Call
+ *
+ * AnalyzeSamples ( const Float_t* left_samples,
+ * const Float_t* right_samples,
+ * size_t num_samples,
+ * int num_channels );
+ *
+ * as many times as you want, with as many or as few samples as you want.
+ * If mono, pass the sample buffer in through left_samples, leave
+ * right_samples NULL, and make sure num_channels = 1.
+ *
+ * GetTitleGain()
+ *
+ * will return the recommended dB level change for all samples analyzed
+ * SINCE THE LAST TIME you called GetTitleGain() OR InitGainAnalysis().
+ *
+ * GetAlbumGain()
+ *
+ * will return the recommended dB level change for all samples analyzed
+ * since InitGainAnalysis() was called and finalized with GetTitleGain().
+ *
+ * Pseudo-code to process an album:
+ *
+ * Float_t l_samples [4096];
+ * Float_t r_samples [4096];
+ * size_t num_samples;
+ * unsigned int num_songs;
+ * unsigned int i;
+ *
+ * InitGainAnalysis ( 44100 );
+ * for ( i = 1; i <= num_songs; i++ ) {
+ * while ( ( num_samples = getSongSamples ( song[i], left_samples, right_samples ) ) > 0 )
+ * AnalyzeSamples ( left_samples, right_samples, num_samples, 2 );
+ * fprintf ("Recommended dB change for song %2d: %+6.2f dB\n", i, GetTitleGain() );
+ * }
+ * fprintf ("Recommended dB change for whole album: %+6.2f dB\n", GetAlbumGain() );
+ */
+
+/*
+ * So here's the main source of potential code confusion:
+ *
+ * The filters applied to the incoming samples are IIR filters,
+ * meaning they rely on up to <filter order> number of previous samples
+ * AND up to <filter order> number of previous filtered samples.
+ *
+ * I set up the AnalyzeSamples routine to minimize memory usage and interface
+ * complexity. The speed isn't compromised too much (I don't think), but the
+ * internal complexity is higher than it should be for such a relatively
+ * simple routine.
+ *
+ * Optimization/clarity suggestions are welcome.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "replaygain_analysis.h"
+
+Float_t ReplayGainReferenceLoudness = 89.0; /* in dB SPL */
+
+typedef unsigned short Uint16_t;
+typedef signed short Int16_t;
+typedef unsigned int Uint32_t;
+typedef signed int Int32_t;
+
+#define YULE_ORDER 10
+#define BUTTER_ORDER 2
+#define RMS_PERCENTILE 0.95 /* percentile which is louder than the proposed level */
+#define MAX_SAMP_FREQ 48000. /* maximum allowed sample frequency [Hz] */
+#define RMS_WINDOW_TIME 0.050 /* Time slice size [s] */
+#define STEPS_per_dB 100. /* Table entries per dB */
+#define MAX_dB 120. /* Table entries for 0...MAX_dB (normal max. values are 70...80 dB) */
+
+#define MAX_ORDER (BUTTER_ORDER > YULE_ORDER ? BUTTER_ORDER : YULE_ORDER)
+/* [JEC] the following was originally #defined as:
+ * (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME)
+ * but that seemed to fail to take into account the ceil() part of the
+ * sampleWindow calculation in ResetSampleFrequency(), and was causing
+ * buffer overflows for 48kHz analysis, hence the +1.
+ */
+#define MAX_SAMPLES_PER_WINDOW (size_t) (MAX_SAMP_FREQ * RMS_WINDOW_TIME + 1.) /* max. Samples per Time slice */
+#define PINK_REF 64.82 /* 298640883795 */ /* calibration value */
+
+static Float_t linprebuf [MAX_ORDER * 2];
+static Float_t* linpre; /* left input samples, with pre-buffer */
+static Float_t lstepbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t* lstep; /* left "first step" (i.e. post first filter) samples */
+static Float_t loutbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t* lout; /* left "out" (i.e. post second filter) samples */
+static Float_t rinprebuf [MAX_ORDER * 2];
+static Float_t* rinpre; /* right input samples ... */
+static Float_t rstepbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t* rstep;
+static Float_t routbuf [MAX_SAMPLES_PER_WINDOW + MAX_ORDER];
+static Float_t* rout;
+static unsigned int sampleWindow; /* number of samples required to reach number of milliseconds required for RMS window */
+static unsigned long totsamp;
+static double lsum;
+static double rsum;
+static int freqindex;
+static Uint32_t A [(size_t)(STEPS_per_dB * MAX_dB)];
+static Uint32_t B [(size_t)(STEPS_per_dB * MAX_dB)];
+
+/* for each filter:
+ [0] 48 kHz, [1] 44.1 kHz, [2] 32 kHz, [3] 24 kHz, [4] 22050 Hz, [5] 16 kHz, [6] 12 kHz, [7] is 11025 Hz, [8] 8 kHz */
+
+#ifdef WIN32
+#pragma warning ( disable : 4305 )
+#endif
+
+static const Float_t AYule [9] [11] = {
+ { 1., -3.84664617118067, 7.81501653005538,-11.34170355132042, 13.05504219327545,-12.28759895145294, 9.48293806319790, -5.87257861775999, 2.75465861874613, -0.86984376593551, 0.13919314567432 },
+ { 1., -3.47845948550071, 6.36317777566148, -8.54751527471874, 9.47693607801280, -8.81498681370155, 6.85401540936998, -4.39470996079559, 2.19611684890774, -0.75104302451432, 0.13149317958808 },
+ { 1., -2.37898834973084, 2.84868151156327, -2.64577170229825, 2.23697657451713, -1.67148153367602, 1.00595954808547, -0.45953458054983, 0.16378164858596, -0.05032077717131, 0.02347897407020 },
+ { 1., -1.61273165137247, 1.07977492259970, -0.25656257754070, -0.16276719120440, -0.22638893773906, 0.39120800788284, -0.22138138954925, 0.04500235387352, 0.02005851806501, 0.00302439095741 },
+ { 1., -1.49858979367799, 0.87350271418188, 0.12205022308084, -0.80774944671438, 0.47854794562326, -0.12453458140019, -0.04067510197014, 0.08333755284107, -0.04237348025746, 0.02977207319925 },
+ { 1., -0.62820619233671, 0.29661783706366, -0.37256372942400, 0.00213767857124, -0.42029820170918, 0.22199650564824, 0.00613424350682, 0.06747620744683, 0.05784820375801, 0.03222754072173 },
+ { 1., -1.04800335126349, 0.29156311971249, -0.26806001042947, 0.00819999645858, 0.45054734505008, -0.33032403314006, 0.06739368333110, -0.04784254229033, 0.01639907836189, 0.01807364323573 },
+ { 1., -0.51035327095184, -0.31863563325245, -0.20256413484477, 0.14728154134330, 0.38952639978999, -0.23313271880868, -0.05246019024463, -0.02505961724053, 0.02442357316099, 0.01818801111503 },
+ { 1., -0.25049871956020, -0.43193942311114, -0.03424681017675, -0.04678328784242, 0.26408300200955, 0.15113130533216, -0.17556493366449, -0.18823009262115, 0.05477720428674, 0.04704409688120 }
+};
+
+static const Float_t BYule [9] [11] = {
+ { 0.03857599435200, -0.02160367184185, -0.00123395316851, -0.00009291677959, -0.01655260341619, 0.02161526843274, -0.02074045215285, 0.00594298065125, 0.00306428023191, 0.00012025322027, 0.00288463683916 },
+ { 0.05418656406430, -0.02911007808948, -0.00848709379851, -0.00851165645469, -0.00834990904936, 0.02245293253339, -0.02596338512915, 0.01624864962975, -0.00240879051584, 0.00674613682247, -0.00187763777362 },
+ { 0.15457299681924, -0.09331049056315, -0.06247880153653, 0.02163541888798, -0.05588393329856, 0.04781476674921, 0.00222312597743, 0.03174092540049, -0.01390589421898, 0.00651420667831, -0.00881362733839 },
+ { 0.30296907319327, -0.22613988682123, -0.08587323730772, 0.03282930172664, -0.00915702933434, -0.02364141202522, -0.00584456039913, 0.06276101321749, -0.00000828086748, 0.00205861885564, -0.02950134983287 },
+ { 0.33642304856132, -0.25572241425570, -0.11828570177555, 0.11921148675203, -0.07834489609479, -0.00469977914380, -0.00589500224440, 0.05724228140351, 0.00832043980773, -0.01635381384540, -0.01760176568150 },
+ { 0.44915256608450, -0.14351757464547, -0.22784394429749, -0.01419140100551, 0.04078262797139, -0.12398163381748, 0.04097565135648, 0.10478503600251, -0.01863887810927, -0.03193428438915, 0.00541907748707 },
+ { 0.56619470757641, -0.75464456939302, 0.16242137742230, 0.16744243493672, -0.18901604199609, 0.30931782841830, -0.27562961986224, 0.00647310677246, 0.08647503780351, -0.03788984554840, -0.00588215443421 },
+ { 0.58100494960553, -0.53174909058578, -0.14289799034253, 0.17520704835522, 0.02377945217615, 0.15558449135573, -0.25344790059353, 0.01628462406333, 0.06920467763959, -0.03721611395801, -0.00749618797172 },
+ { 0.53648789255105, -0.42163034350696, -0.00275953611929, 0.04267842219415, -0.10214864179676, 0.14590772289388, -0.02459864859345, -0.11202315195388, -0.04060034127000, 0.04788665548180, -0.02217936801134 }
+};
+
+static const Float_t AButter [9] [3] = {
+ { 1., -1.97223372919527, 0.97261396931306 },
+ { 1., -1.96977855582618, 0.97022847566350 },
+ { 1., -1.95835380975398, 0.95920349965459 },
+ { 1., -1.95002759149878, 0.95124613669835 },
+ { 1., -1.94561023566527, 0.94705070426118 },
+ { 1., -1.92783286977036, 0.93034775234268 },
+ { 1., -1.91858953033784, 0.92177618768381 },
+ { 1., -1.91542108074780, 0.91885558323625 },
+ { 1., -1.88903307939452, 0.89487434461664 }
+};
+
+static const Float_t BButter [9] [3] = {
+ { 0.98621192462708, -1.97242384925416, 0.98621192462708 },
+ { 0.98500175787242, -1.97000351574484, 0.98500175787242 },
+ { 0.97938932735214, -1.95877865470428, 0.97938932735214 },
+ { 0.97531843204928, -1.95063686409857, 0.97531843204928 },
+ { 0.97316523498161, -1.94633046996323, 0.97316523498161 },
+ { 0.96454515552826, -1.92909031105652, 0.96454515552826 },
+ { 0.96009142950541, -1.92018285901082, 0.96009142950541 },
+ { 0.95856916599601, -1.91713833199203, 0.95856916599601 },
+ { 0.94597685600279, -1.89195371200558, 0.94597685600279 }
+};
+
+#ifdef WIN32
+#pragma warning ( default : 4305 )
+#endif
+
+/* When calling this procedure, make sure that ip[-order] and op[-order] point to real data! */
+
+static void
+filter ( const Float_t* input, Float_t* output, size_t nSamples, const Float_t* a, const Float_t* b, size_t order )
+{
+ double y;
+ size_t i;
+ size_t k;
+
+ for ( i = 0; i < nSamples; i++ ) {
+ y = input[i] * b[0];
+ for ( k = 1; k <= order; k++ )
+ y += input[i-k] * b[k] - output[i-k] * a[k];
+ output[i] = (Float_t)y;
+ }
+}
+
+/* returns a INIT_GAIN_ANALYSIS_OK if successful, INIT_GAIN_ANALYSIS_ERROR if not */
+
+int
+ResetSampleFrequency ( long samplefreq ) {
+ int i;
+
+ /* zero out initial values */
+ for ( i = 0; i < MAX_ORDER; i++ )
+ linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.;
+
+ switch ( (int)(samplefreq) ) {
+ case 48000: freqindex = 0; break;
+ case 44100: freqindex = 1; break;
+ case 32000: freqindex = 2; break;
+ case 24000: freqindex = 3; break;
+ case 22050: freqindex = 4; break;
+ case 16000: freqindex = 5; break;
+ case 12000: freqindex = 6; break;
+ case 11025: freqindex = 7; break;
+ case 8000: freqindex = 8; break;
+ default: return INIT_GAIN_ANALYSIS_ERROR;
+ }
+
+ sampleWindow = ceil (samplefreq * RMS_WINDOW_TIME);
+
+ lsum = 0.;
+ rsum = 0.;
+ totsamp = 0;
+
+ memset ( A, 0, sizeof(A) );
+
+ return INIT_GAIN_ANALYSIS_OK;
+}
+
+int
+InitGainAnalysis ( long samplefreq )
+{
+ if (ResetSampleFrequency(samplefreq) != INIT_GAIN_ANALYSIS_OK) {
+ return INIT_GAIN_ANALYSIS_ERROR;
+ }
+
+ linpre = linprebuf + MAX_ORDER;
+ rinpre = rinprebuf + MAX_ORDER;
+ lstep = lstepbuf + MAX_ORDER;
+ rstep = rstepbuf + MAX_ORDER;
+ lout = loutbuf + MAX_ORDER;
+ rout = routbuf + MAX_ORDER;
+
+ memset ( B, 0, sizeof(B) );
+
+ return INIT_GAIN_ANALYSIS_OK;
+}
+
+/* returns GAIN_ANALYSIS_OK if successful, GAIN_ANALYSIS_ERROR if not */
+
+int
+AnalyzeSamples ( const Float_t* left_samples, const Float_t* right_samples, size_t num_samples, int num_channels )
+{
+ const Float_t* curleft;
+ const Float_t* curright;
+ long batchsamples;
+ long cursamples;
+ long cursamplepos;
+ int i;
+
+ if ( num_samples == 0 )
+ return GAIN_ANALYSIS_OK;
+
+ cursamplepos = 0;
+ batchsamples = num_samples;
+
+ switch ( num_channels) {
+ case 1: right_samples = left_samples;
+ case 2: break;
+ default: return GAIN_ANALYSIS_ERROR;
+ }
+
+ if ( num_samples < MAX_ORDER ) {
+ memcpy ( linprebuf + MAX_ORDER, left_samples , num_samples * sizeof(Float_t) );
+ memcpy ( rinprebuf + MAX_ORDER, right_samples, num_samples * sizeof(Float_t) );
+ }
+ else {
+ memcpy ( linprebuf + MAX_ORDER, left_samples, MAX_ORDER * sizeof(Float_t) );
+ memcpy ( rinprebuf + MAX_ORDER, right_samples, MAX_ORDER * sizeof(Float_t) );
+ }
+
+ while ( batchsamples > 0 ) {
+ cursamples = batchsamples > (long)(sampleWindow-totsamp) ? (long)(sampleWindow - totsamp) : batchsamples;
+ if ( cursamplepos < MAX_ORDER ) {
+ curleft = linpre+cursamplepos;
+ curright = rinpre+cursamplepos;
+ if (cursamples > MAX_ORDER - cursamplepos )
+ cursamples = MAX_ORDER - cursamplepos;
+ }
+ else {
+ curleft = left_samples + cursamplepos;
+ curright = right_samples + cursamplepos;
+ }
+
+ filter ( curleft , lstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER );
+ filter ( curright, rstep + totsamp, cursamples, AYule[freqindex], BYule[freqindex], YULE_ORDER );
+
+ filter ( lstep + totsamp, lout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER );
+ filter ( rstep + totsamp, rout + totsamp, cursamples, AButter[freqindex], BButter[freqindex], BUTTER_ORDER );
+
+ for ( i = 0; i < cursamples; i++ ) { /* Get the squared values */
+ lsum += lout [totsamp+i] * lout [totsamp+i];
+ rsum += rout [totsamp+i] * rout [totsamp+i];
+ }
+
+ batchsamples -= cursamples;
+ cursamplepos += cursamples;
+ totsamp += cursamples;
+ if ( totsamp == sampleWindow ) { /* Get the Root Mean Square (RMS) for this set of samples */
+ double val = STEPS_per_dB * 10. * log10 ( (lsum+rsum) / totsamp * 0.5 + 1.e-37 );
+ int ival = (int) val;
+ if ( ival < 0 ) ival = 0;
+ if ( ival >= (int)(sizeof(A)/sizeof(*A)) ) ival = (int)(sizeof(A)/sizeof(*A)) - 1;
+ A [ival]++;
+ lsum = rsum = 0.;
+ memmove ( loutbuf , loutbuf + totsamp, MAX_ORDER * sizeof(Float_t) );
+ memmove ( routbuf , routbuf + totsamp, MAX_ORDER * sizeof(Float_t) );
+ memmove ( lstepbuf, lstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) );
+ memmove ( rstepbuf, rstepbuf + totsamp, MAX_ORDER * sizeof(Float_t) );
+ totsamp = 0;
+ }
+ if ( totsamp > sampleWindow ) /* somehow I really screwed up: Error in programming! Contact author about totsamp > sampleWindow */
+ return GAIN_ANALYSIS_ERROR;
+ }
+ if ( num_samples < MAX_ORDER ) {
+ memmove ( linprebuf, linprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) );
+ memmove ( rinprebuf, rinprebuf + num_samples, (MAX_ORDER-num_samples) * sizeof(Float_t) );
+ memcpy ( linprebuf + MAX_ORDER - num_samples, left_samples, num_samples * sizeof(Float_t) );
+ memcpy ( rinprebuf + MAX_ORDER - num_samples, right_samples, num_samples * sizeof(Float_t) );
+ }
+ else {
+ memcpy ( linprebuf, left_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) );
+ memcpy ( rinprebuf, right_samples + num_samples - MAX_ORDER, MAX_ORDER * sizeof(Float_t) );
+ }
+
+ return GAIN_ANALYSIS_OK;
+}
+
+
+static Float_t
+analyzeResult ( Uint32_t* Array, size_t len )
+{
+ Uint32_t elems;
+ Int32_t upper;
+ size_t i;
+
+ elems = 0;
+ for ( i = 0; i < len; i++ )
+ elems += Array[i];
+ if ( elems == 0 )
+ return GAIN_NOT_ENOUGH_SAMPLES;
+
+ upper = ceil (elems * (1. - RMS_PERCENTILE));
+ for ( i = len; i-- > 0; ) {
+ if ( (upper -= Array[i]) <= 0 )
+ break;
+ }
+
+ return (Float_t) ((Float_t)PINK_REF - (Float_t)i / (Float_t)STEPS_per_dB);
+}
+
+
+Float_t
+GetTitleGain ( void )
+{
+ Float_t retval;
+ unsigned int i;
+
+ retval = analyzeResult ( A, sizeof(A)/sizeof(*A) );
+
+ for ( i = 0; i < sizeof(A)/sizeof(*A); i++ ) {
+ B[i] += A[i];
+ A[i] = 0;
+ }
+
+ for ( i = 0; i < MAX_ORDER; i++ )
+ linprebuf[i] = lstepbuf[i] = loutbuf[i] = rinprebuf[i] = rstepbuf[i] = routbuf[i] = 0.f;
+
+ totsamp = 0;
+ lsum = rsum = 0.;
+ return retval;
+}
+
+
+Float_t
+GetAlbumGain ( void )
+{
+ return analyzeResult ( B, sizeof(B)/sizeof(*B) );
+}
+
+/* end of replaygain_analysis.c */
diff --git a/src/FLAC/src/share/replaygain_syn/Makefile.am b/src/FLAC/src/share/replaygain_syn/Makefile.am
new file mode 100644
index 0000000..cf05b33
--- /dev/null
+++ b/src/FLAC/src/share/replaygain_syn/Makefile.am
@@ -0,0 +1,18 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+SUBDIRS = include .
+
+INCLUDES = -I$(top_srcdir)/src/FLAC/include -I$(top_srcdir)/src/FLAC/include/share \
+ -I$(top_srcdir)/src/FLAC/src/share/replaygain_syn/include
+
+noinst_LTLIBRARIES = libreplaygain_synthesis.la
+
+libreplaygain_synthesis_la_SOURCES = replaygain_synthesis.c
+
+debug:
+ $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+ $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/FLAC/src/share/replaygain_syn/include/Makefile.am b/src/FLAC/src/share/replaygain_syn/include/Makefile.am
new file mode 100644
index 0000000..4418640
--- /dev/null
+++ b/src/FLAC/src/share/replaygain_syn/include/Makefile.am
@@ -0,0 +1,18 @@
+# replaygain_synthesis - Routines for applying ReplayGain to a signal
+# Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SUBDIRS = private
diff --git a/src/FLAC/src/share/replaygain_syn/include/private/Makefile.am b/src/FLAC/src/share/replaygain_syn/include/private/Makefile.am
new file mode 100644
index 0000000..081d7ba
--- /dev/null
+++ b/src/FLAC/src/share/replaygain_syn/include/private/Makefile.am
@@ -0,0 +1,19 @@
+# replaygain_synthesis - Routines for applying ReplayGain to a signal
+# Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+noinst_HEADERS = \
+ fast_float_math_hack.h
diff --git a/src/FLAC/src/share/replaygain_syn/include/private/fast_float_math_hack.h b/src/FLAC/src/share/replaygain_syn/include/private/fast_float_math_hack.h
new file mode 100644
index 0000000..d8608fc
--- /dev/null
+++ b/src/FLAC/src/share/replaygain_syn/include/private/fast_float_math_hack.h
@@ -0,0 +1,39 @@
+# ifdef __ICL /* only Intel C compiler has fmath ??? */
+
+ #include <mathf.h>
+
+/* Nearest integer, absolute value, etc. */
+
+ #define ceil ceilf
+ #define fabs fabsf
+ #define floor floorf
+ #define fmod fmodf
+ #define rint rintf
+ #define hypot hypotf
+
+/* Power functions */
+
+ #define pow powf
+ #define sqrt sqrtf
+
+/* Exponential and logarithmic functions */
+
+ #define exp expf
+ #define log logf
+ #define log10 log10f
+
+/* Trigonometric functions */
+
+ #define acos acosf
+ #define asin asinf
+ #define atan atanf
+ #define cos cosf
+ #define sin sinf
+ #define tan tanf
+
+/* Hyperbolic functions */
+ #define cosh coshf
+ #define sinh sinhf
+ #define tanh tanhf
+
+# endif
diff --git a/src/FLAC/src/share/replaygain_syn/replaygain_synthesis.c b/src/FLAC/src/share/replaygain_syn/replaygain_synthesis.c
new file mode 100644
index 0000000..fa85021
--- /dev/null
+++ b/src/FLAC/src/share/replaygain_syn/replaygain_synthesis.c
@@ -0,0 +1,467 @@
+/* replaygain_synthesis - Routines for applying ReplayGain to a signal
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+/*
+ * This is an aggregation of pieces of code from John Edwards' WaveGain
+ * program. Mostly cosmetic changes were made; otherwise, the dithering
+ * code is almost untouched and the gain processing was converted from
+ * processing a whole file to processing chunks of samples.
+ *
+ * The original copyright notices for WaveGain's dither.c and wavegain.c
+ * appear below:
+ */
+/*
+ * (c) 2002 John Edwards
+ * mostly lifted from work by Frank Klemm
+ * random functions for dithering.
+ */
+/*
+ * Copyright (C) 2002 John Edwards
+ * Additional code by Magnus Holmgren and Gian-Carlo Pascutto
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h> /* for memset() */
+#include <math.h>
+#include "private/fast_float_math_hack.h"
+#include "replaygain_synthesis.h"
+#include "FLAC/assert.h"
+
+#ifndef FLaC__INLINE
+#define FLaC__INLINE
+#endif
+
+/* adjust for compilers that can't understand using LL suffix for int64_t literals */
+#ifdef _MSC_VER
+#define FLAC__I64L(x) x
+#else
+#define FLAC__I64L(x) x##LL
+#endif
+
+
+/*
+ * the following is based on parts of dither.c
+ */
+
+
+/*
+ * This is a simple random number generator with good quality for audio purposes.
+ * It consists of two polycounters with opposite rotation direction and different
+ * periods. The periods are coprime, so the total period is the product of both.
+ *
+ * -------------------------------------------------------------------------------------------------
+ * +-> |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0|
+ * | -------------------------------------------------------------------------------------------------
+ * | | | | | | |
+ * | +--+--+--+-XOR-+--------+
+ * | |
+ * +--------------------------------------------------------------------------------------+
+ *
+ * -------------------------------------------------------------------------------------------------
+ * |31:30:29:28:27:26:25:24:23:22:21:20:19:18:17:16:15:14:13:12:11:10: 9: 8: 7: 6: 5: 4: 3: 2: 1: 0| <-+
+ * ------------------------------------------------------------------------------------------------- |
+ * | | | | |
+ * +--+----XOR----+--+ |
+ * | |
+ * +----------------------------------------------------------------------------------------+
+ *
+ *
+ * The first has an period of 3*5*17*257*65537, the second of 7*47*73*178481,
+ * which gives a period of 18.410.713.077.675.721.215. The result is the
+ * XORed values of both generators.
+ */
+
+static unsigned int random_int_(void)
+{
+ static const unsigned char parity_[256] = {
+ 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+ 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+ 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+ 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+ 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,
+ 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+ 0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0,1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,
+ 1,0,0,1,0,1,1,0,0,1,1,0,1,0,0,1,0,1,1,0,1,0,0,1,1,0,0,1,0,1,1,0
+ };
+ static unsigned int r1_ = 1;
+ static unsigned int r2_ = 1;
+
+ unsigned int t1, t2, t3, t4;
+
+ /* Parity calculation is done via table lookup, this is also available
+ * on CPUs without parity, can be implemented in C and avoid unpredictable
+ * jumps and slow rotate through the carry flag operations.
+ */
+ t3 = t1 = r1_; t4 = t2 = r2_;
+ t1 &= 0xF5; t2 >>= 25;
+ t1 = parity_[t1]; t2 &= 0x63;
+ t1 <<= 31; t2 = parity_[t2];
+
+ return (r1_ = (t3 >> 1) | t1 ) ^ (r2_ = (t4 + t4) | t2 );
+}
+
+/* gives a equal distributed random number */
+/* between -2^31*mult and +2^31*mult */
+static double random_equi_(double mult)
+{
+ return mult * (int) random_int_();
+}
+
+/* gives a triangular distributed random number */
+/* between -2^32*mult and +2^32*mult */
+static double random_triangular_(double mult)
+{
+ return mult * ( (double) (int) random_int_() + (double) (int) random_int_() );
+}
+
+
+static const float F44_0 [16 + 32] = {
+ (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+ (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+
+ (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+ (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+
+ (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0,
+ (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0, (float)0
+};
+
+
+static const float F44_1 [16 + 32] = { /* SNR(w) = 4.843163 dB, SNR = -3.192134 dB */
+ (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+ (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+ (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+ (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+
+ (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+ (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+ (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+ (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+
+ (float) 0.85018292704024355931, (float) 0.29089597350995344721, (float)-0.05021866022121039450, (float)-0.23545456294599161833,
+ (float)-0.58362726442227032096, (float)-0.67038978965193036429, (float)-0.38566861572833459221, (float)-0.15218663390367969967,
+ (float)-0.02577543084864530676, (float) 0.14119295297688728127, (float) 0.22398848581628781612, (float) 0.15401727203382084116,
+ (float) 0.05216161232906000929, (float)-0.00282237820999675451, (float)-0.03042794608323867363, (float)-0.03109780942998826024,
+};
+
+
+static const float F44_2 [16 + 32] = { /* SNR(w) = 10.060213 dB, SNR = -12.766730 dB */
+ (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+ (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+ (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+ (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+
+ (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+ (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+ (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+ (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+
+ (float) 1.78827593892108555290, (float) 0.95508210637394326553, (float)-0.18447626783899924429, (float)-0.44198126506275016437,
+ (float)-0.88404052492547413497, (float)-1.42218907262407452967, (float)-1.02037566838362314995, (float)-0.34861755756425577264,
+ (float)-0.11490230170431934434, (float) 0.12498899339968611803, (float) 0.38065885268563131927, (float) 0.31883491321310506562,
+ (float) 0.10486838686563442765, (float)-0.03105361685110374845, (float)-0.06450524884075370758, (float)-0.02939198261121969816,
+};
+
+
+static const float F44_3 [16 + 32] = { /* SNR(w) = 15.382598 dB, SNR = -29.402334 dB */
+ (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+ (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+ (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+ (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099,
+
+ (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+ (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+ (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+ (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099,
+
+ (float) 2.89072132015058161445, (float) 2.68932810943698754106, (float) 0.21083359339410251227, (float)-0.98385073324997617515,
+ (float)-1.11047823227097316719, (float)-2.18954076314139673147, (float)-2.36498032881953056225, (float)-0.95484132880101140785,
+ (float)-0.23924057925542965158, (float)-0.13865235703915925642, (float) 0.43587843191057992846, (float) 0.65903257226026665927,
+ (float) 0.24361815372443152787, (float)-0.00235974960154720097, (float) 0.01844166574603346289, (float) 0.01722945988740875099
+};
+
+
+static double scalar16_(const float* x, const float* y)
+{
+ return
+ x[ 0]*y[ 0] + x[ 1]*y[ 1] + x[ 2]*y[ 2] + x[ 3]*y[ 3] +
+ x[ 4]*y[ 4] + x[ 5]*y[ 5] + x[ 6]*y[ 6] + x[ 7]*y[ 7] +
+ x[ 8]*y[ 8] + x[ 9]*y[ 9] + x[10]*y[10] + x[11]*y[11] +
+ x[12]*y[12] + x[13]*y[13] + x[14]*y[14] + x[15]*y[15];
+}
+
+
+void FLAC__replaygain_synthesis__init_dither_context(DitherContext *d, int bits, int shapingtype)
+{
+ static unsigned char default_dither [] = { 92, 92, 88, 84, 81, 78, 74, 67, 0, 0 };
+ static const float* F [] = { F44_0, F44_1, F44_2, F44_3 };
+
+ int indx;
+
+ if (shapingtype < 0) shapingtype = 0;
+ if (shapingtype > 3) shapingtype = 3;
+ d->ShapingType = (NoiseShaping)shapingtype;
+ indx = bits - 11 - shapingtype;
+ if (indx < 0) indx = 0;
+ if (indx > 9) indx = 9;
+
+ memset ( d->ErrorHistory , 0, sizeof (d->ErrorHistory ) );
+ memset ( d->DitherHistory, 0, sizeof (d->DitherHistory) );
+
+ d->FilterCoeff = F [shapingtype];
+ d->Mask = ((FLAC__uint64)-1) << (32 - bits);
+ d->Add = 0.5 * ((1L << (32 - bits)) - 1);
+ d->Dither = 0.01f*default_dither[indx] / (((FLAC__int64)1) << bits);
+ d->LastHistoryIndex = 0;
+}
+
+/*
+ * the following is based on parts of wavegain.c
+ */
+
+static FLaC__INLINE FLAC__int64 dither_output_(DitherContext *d, FLAC__bool do_dithering, int shapingtype, int i, double Sum, int k)
+{
+ union {
+ double d;
+ FLAC__int64 i;
+ } doubletmp;
+ double Sum2;
+ FLAC__int64 val;
+
+#define ROUND64(x) ( doubletmp.d = (x) + d->Add + (FLAC__int64)FLAC__I64L(0x001FFFFD80000000), doubletmp.i - (FLAC__int64)FLAC__I64L(0x433FFFFD80000000) )
+
+ if(do_dithering) {
+ if(shapingtype == 0) {
+ double tmp = random_equi_(d->Dither);
+ Sum2 = tmp - d->LastRandomNumber [k];
+ d->LastRandomNumber [k] = (int)tmp;
+ Sum2 = Sum += Sum2;
+ val = ROUND64(Sum2) & d->Mask;
+ }
+ else {
+ Sum2 = random_triangular_(d->Dither) - scalar16_(d->DitherHistory[k], d->FilterCoeff + i);
+ Sum += d->DitherHistory [k] [(-1-i)&15] = (float)Sum2;
+ Sum2 = Sum + scalar16_(d->ErrorHistory [k], d->FilterCoeff + i);
+ val = ROUND64(Sum2) & d->Mask;
+ d->ErrorHistory [k] [(-1-i)&15] = (float)(Sum - val);
+ }
+ return val;
+ }
+ else
+ return ROUND64(Sum);
+
+#undef ROUND64
+}
+
+#if 0
+ float peak = 0.f,
+ new_peak,
+ factor_clip
+ double scale,
+ dB;
+
+ ...
+
+ peak is in the range -32768.0 .. 32767.0
+
+ /* calculate factors for ReplayGain and ClippingPrevention */
+ *track_gain = GetTitleGain() + settings->man_gain;
+ scale = (float) pow(10., *track_gain * 0.05);
+ if(settings->clip_prev) {
+ factor_clip = (float) (32767./( peak + 1));
+ if(scale < factor_clip)
+ factor_clip = 1.f;
+ else
+ factor_clip /= scale;
+ scale *= factor_clip;
+ }
+ new_peak = (float) peak * scale;
+
+ dB = 20. * log10(scale);
+ *track_gain = (float) dB;
+
+ const double scale = pow(10., (double)gain * 0.05);
+#endif
+
+
+size_t FLAC__replaygain_synthesis__apply_gain(FLAC__byte *data_out, FLAC__bool little_endian_data_out, FLAC__bool unsigned_data_out, const FLAC__int32 * const input[], unsigned wide_samples, unsigned channels, const unsigned source_bps, const unsigned target_bps, const double scale, const FLAC__bool hard_limit, FLAC__bool do_dithering, DitherContext *dither_context)
+{
+ static const FLAC__int32 conv_factors_[33] = {
+ -1, /* 0 bits-per-sample (not supported) */
+ -1, /* 1 bits-per-sample (not supported) */
+ -1, /* 2 bits-per-sample (not supported) */
+ -1, /* 3 bits-per-sample (not supported) */
+ 268435456, /* 4 bits-per-sample */
+ 134217728, /* 5 bits-per-sample */
+ 67108864, /* 6 bits-per-sample */
+ 33554432, /* 7 bits-per-sample */
+ 16777216, /* 8 bits-per-sample */
+ 8388608, /* 9 bits-per-sample */
+ 4194304, /* 10 bits-per-sample */
+ 2097152, /* 11 bits-per-sample */
+ 1048576, /* 12 bits-per-sample */
+ 524288, /* 13 bits-per-sample */
+ 262144, /* 14 bits-per-sample */
+ 131072, /* 15 bits-per-sample */
+ 65536, /* 16 bits-per-sample */
+ 32768, /* 17 bits-per-sample */
+ 16384, /* 18 bits-per-sample */
+ 8192, /* 19 bits-per-sample */
+ 4096, /* 20 bits-per-sample */
+ 2048, /* 21 bits-per-sample */
+ 1024, /* 22 bits-per-sample */
+ 512, /* 23 bits-per-sample */
+ 256, /* 24 bits-per-sample */
+ 128, /* 25 bits-per-sample */
+ 64, /* 26 bits-per-sample */
+ 32, /* 27 bits-per-sample */
+ 16, /* 28 bits-per-sample */
+ 8, /* 29 bits-per-sample */
+ 4, /* 30 bits-per-sample */
+ 2, /* 31 bits-per-sample */
+ 1 /* 32 bits-per-sample */
+ };
+ static const FLAC__int64 hard_clip_factors_[33] = {
+ 0, /* 0 bits-per-sample (not supported) */
+ 0, /* 1 bits-per-sample (not supported) */
+ 0, /* 2 bits-per-sample (not supported) */
+ 0, /* 3 bits-per-sample (not supported) */
+ -8, /* 4 bits-per-sample */
+ -16, /* 5 bits-per-sample */
+ -32, /* 6 bits-per-sample */
+ -64, /* 7 bits-per-sample */
+ -128, /* 8 bits-per-sample */
+ -256, /* 9 bits-per-sample */
+ -512, /* 10 bits-per-sample */
+ -1024, /* 11 bits-per-sample */
+ -2048, /* 12 bits-per-sample */
+ -4096, /* 13 bits-per-sample */
+ -8192, /* 14 bits-per-sample */
+ -16384, /* 15 bits-per-sample */
+ -32768, /* 16 bits-per-sample */
+ -65536, /* 17 bits-per-sample */
+ -131072, /* 18 bits-per-sample */
+ -262144, /* 19 bits-per-sample */
+ -524288, /* 20 bits-per-sample */
+ -1048576, /* 21 bits-per-sample */
+ -2097152, /* 22 bits-per-sample */
+ -4194304, /* 23 bits-per-sample */
+ -8388608, /* 24 bits-per-sample */
+ -16777216, /* 25 bits-per-sample */
+ -33554432, /* 26 bits-per-sample */
+ -67108864, /* 27 bits-per-sample */
+ -134217728, /* 28 bits-per-sample */
+ -268435456, /* 29 bits-per-sample */
+ -536870912, /* 30 bits-per-sample */
+ -1073741824, /* 31 bits-per-sample */
+ (FLAC__int64)(-1073741824) * 2 /* 32 bits-per-sample */
+ };
+ const FLAC__int32 conv_factor = conv_factors_[target_bps];
+ const FLAC__int64 hard_clip_factor = hard_clip_factors_[target_bps];
+ /*
+ * The integer input coming in has a varying range based on the
+ * source_bps. We want to normalize it to [-1.0, 1.0) so instead
+ * of doing two multiplies on each sample, we just multiple
+ * 'scale' by 1/(2^(source_bps-1))
+ */
+ const double multi_scale = scale / (double)(1u << (source_bps-1));
+
+ FLAC__byte * const start = data_out;
+ unsigned i, channel;
+ const FLAC__int32 *input_;
+ double sample;
+ const unsigned bytes_per_sample = target_bps / 8;
+ const unsigned last_history_index = dither_context->LastHistoryIndex;
+ NoiseShaping noise_shaping = dither_context->ShapingType;
+ FLAC__int64 val64;
+ FLAC__int32 val32;
+ FLAC__int32 uval32;
+ const FLAC__uint32 twiggle = 1u << (target_bps - 1);
+
+ FLAC__ASSERT(channels > 0 && channels <= FLAC_SHARE__MAX_SUPPORTED_CHANNELS);
+ FLAC__ASSERT(source_bps >= 4);
+ FLAC__ASSERT(target_bps >= 4);
+ FLAC__ASSERT(source_bps <= 32);
+ FLAC__ASSERT(target_bps < 32);
+ FLAC__ASSERT((target_bps & 7) == 0);
+
+ for(channel = 0; channel < channels; channel++) {
+ const unsigned incr = bytes_per_sample * channels;
+ data_out = start + bytes_per_sample * channel;
+ input_ = input[channel];
+ for(i = 0; i < wide_samples; i++, data_out += incr) {
+ sample = (double)input_[i] * multi_scale;
+
+ if(hard_limit) {
+ /* hard 6dB limiting */
+ if(sample < -0.5)
+ sample = tanh((sample + 0.5) / (1-0.5)) * (1-0.5) - 0.5;
+ else if(sample > 0.5)
+ sample = tanh((sample - 0.5) / (1-0.5)) * (1-0.5) + 0.5;
+ }
+ sample *= 2147483647.f;
+
+ val64 = dither_output_(dither_context, do_dithering, noise_shaping, (i + last_history_index) % 32, sample, channel) / conv_factor;
+
+ val32 = (FLAC__int32)val64;
+ if(val64 >= -hard_clip_factor)
+ val32 = (FLAC__int32)(-(hard_clip_factor+1));
+ else if(val64 < hard_clip_factor)
+ val32 = (FLAC__int32)hard_clip_factor;
+
+ uval32 = (FLAC__uint32)val32;
+ if (unsigned_data_out)
+ uval32 ^= twiggle;
+
+ if (little_endian_data_out) {
+ switch(target_bps) {
+ case 24:
+ data_out[2] = (FLAC__byte)(uval32 >> 16);
+ /* fall through */
+ case 16:
+ data_out[1] = (FLAC__byte)(uval32 >> 8);
+ /* fall through */
+ case 8:
+ data_out[0] = (FLAC__byte)uval32;
+ break;
+ }
+ }
+ else {
+ switch(target_bps) {
+ case 24:
+ data_out[0] = (FLAC__byte)(uval32 >> 16);
+ data_out[1] = (FLAC__byte)(uval32 >> 8);
+ data_out[2] = (FLAC__byte)uval32;
+ break;
+ case 16:
+ data_out[0] = (FLAC__byte)(uval32 >> 8);
+ data_out[1] = (FLAC__byte)uval32;
+ break;
+ case 8:
+ data_out[0] = (FLAC__byte)uval32;
+ break;
+ }
+ }
+ }
+ }
+ dither_context->LastHistoryIndex = (last_history_index + wide_samples) % 32;
+
+ return wide_samples * channels * (target_bps/8);
+}
diff --git a/src/FLAC/src/share/utf8/Makefile.am b/src/FLAC/src/share/utf8/Makefile.am
new file mode 100644
index 0000000..9b3282d
--- /dev/null
+++ b/src/FLAC/src/share/utf8/Makefile.am
@@ -0,0 +1,21 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = foreign
+
+INCLUDES = -I$(top_srcdir)/src/FLAC/include/share
+
+noinst_LTLIBRARIES = libutf8.la
+
+libutf8_la_SOURCES = charset.c charset.h iconvert.c utf8.c
+
+EXTRA_DIST = \
+ charmaps.h \
+ makemap.c \
+ charset_test.c \
+ charsetmap.h
+
+debug:
+ $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+ $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/FLAC/src/share/utf8/charmaps.h b/src/FLAC/src/share/utf8/charmaps.h
new file mode 100644
index 0000000..690d890
--- /dev/null
+++ b/src/FLAC/src/share/utf8/charmaps.h
@@ -0,0 +1,57 @@
+
+/*
+ * If you need to generate more maps, use makemap.c on a system
+ * with a decent iconv.
+ */
+
+static const unsigned short mapping_iso_8859_2[256] = {
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+ 0x00a0, 0x0104, 0x02d8, 0x0141, 0x00a4, 0x013d, 0x015a, 0x00a7,
+ 0x00a8, 0x0160, 0x015e, 0x0164, 0x0179, 0x00ad, 0x017d, 0x017b,
+ 0x00b0, 0x0105, 0x02db, 0x0142, 0x00b4, 0x013e, 0x015b, 0x02c7,
+ 0x00b8, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c,
+ 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7,
+ 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e,
+ 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7,
+ 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df,
+ 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7,
+ 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f,
+ 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7,
+ 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9
+};
+
+static struct {
+ const char *name;
+ const unsigned short *map;
+ struct charset *charset;
+} maps[] = {
+ { "ISO-8859-2", mapping_iso_8859_2, 0 },
+ { 0, 0, 0 }
+};
+
+static const struct {
+ const char *bad;
+ const char *good;
+} names[] = {
+ { "ANSI_X3.4-1968", "us-ascii" },
+ { 0, 0 }
+};
diff --git a/src/FLAC/src/share/utf8/charset.c b/src/FLAC/src/share/utf8/charset.c
new file mode 100644
index 0000000..1610ad2
--- /dev/null
+++ b/src/FLAC/src/share/utf8/charset.c
@@ -0,0 +1,532 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * 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
+ */
+
+/*
+ * See the corresponding header file for a description of the functions
+ * that this file provides.
+ *
+ * This was first written for Ogg Vorbis but could be of general use.
+ *
+ * The only deliberate assumption about data sizes is that a short has
+ * at least 16 bits, but this code has only been tested on systems with
+ * 8-bit char, 16-bit short and 32-bit int.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */
+
+#include <stdlib.h>
+
+#include "charset.h"
+
+#include "charmaps.h"
+
+/*
+ * This is like the standard strcasecmp, but it does not depend
+ * on the locale. Locale-dependent functions can be dangerous:
+ * we once had a bug involving strcasecmp("iso", "ISO") in a
+ * Turkish locale!
+ *
+ * (I'm not really sure what the official standard says
+ * about the sign of strcasecmp("Z", "["), but usually
+ * we're only interested in whether it's zero.)
+ */
+
+static int ascii_strcasecmp(const char *s1, const char *s2)
+{
+ char c1, c2;
+
+ for (;; s1++, s2++) {
+ if (!*s1 || !*s1)
+ break;
+ if (*s1 == *s2)
+ continue;
+ c1 = *s1;
+ if ('a' <= c1 && c1 <= 'z')
+ c1 += 'A' - 'a';
+ c2 = *s2;
+ if ('a' <= c2 && c2 <= 'z')
+ c2 += 'A' - 'a';
+ if (c1 != c2)
+ break;
+ }
+ return (unsigned char)*s1 - (unsigned char)*s2;
+}
+
+/*
+ * UTF-8 equivalents of the C library's wctomb() and mbtowc().
+ */
+
+int utf8_mbtowc(int *pwc, const char *s, size_t n)
+{
+ unsigned char c;
+ int wc, i, k;
+
+ if (!n || !s)
+ return 0;
+
+ c = *s;
+ if (c < 0x80) {
+ if (pwc)
+ *pwc = c;
+ return c ? 1 : 0;
+ }
+ else if (c < 0xc2)
+ return -1;
+ else if (c < 0xe0) {
+ if (n >= 2 && (s[1] & 0xc0) == 0x80) {
+ if (pwc)
+ *pwc = ((c & 0x1f) << 6) | (s[1] & 0x3f);
+ return 2;
+ }
+ else
+ return -1;
+ }
+ else if (c < 0xf0)
+ k = 3;
+ else if (c < 0xf8)
+ k = 4;
+ else if (c < 0xfc)
+ k = 5;
+ else if (c < 0xfe)
+ k = 6;
+ else
+ return -1;
+
+ if (n < (size_t)k)
+ return -1;
+ wc = *s++ & ((1 << (7 - k)) - 1);
+ for (i = 1; i < k; i++) {
+ if ((*s & 0xc0) != 0x80)
+ return -1;
+ wc = (wc << 6) | (*s++ & 0x3f);
+ }
+ if (wc < (1 << (5 * k - 4)))
+ return -1;
+ if (pwc)
+ *pwc = wc;
+ return k;
+}
+
+int utf8_wctomb(char *s, int wc1)
+{
+ unsigned int wc = wc1;
+
+ if (!s)
+ return 0;
+ if (wc < (1u << 7)) {
+ *s++ = wc;
+ return 1;
+ }
+ else if (wc < (1u << 11)) {
+ *s++ = 0xc0 | (wc >> 6);
+ *s++ = 0x80 | (wc & 0x3f);
+ return 2;
+ }
+ else if (wc < (1u << 16)) {
+ *s++ = 0xe0 | (wc >> 12);
+ *s++ = 0x80 | ((wc >> 6) & 0x3f);
+ *s++ = 0x80 | (wc & 0x3f);
+ return 3;
+ }
+ else if (wc < (1u << 21)) {
+ *s++ = 0xf0 | (wc >> 18);
+ *s++ = 0x80 | ((wc >> 12) & 0x3f);
+ *s++ = 0x80 | ((wc >> 6) & 0x3f);
+ *s++ = 0x80 | (wc & 0x3f);
+ return 4;
+ }
+ else if (wc < (1u << 26)) {
+ *s++ = 0xf8 | (wc >> 24);
+ *s++ = 0x80 | ((wc >> 18) & 0x3f);
+ *s++ = 0x80 | ((wc >> 12) & 0x3f);
+ *s++ = 0x80 | ((wc >> 6) & 0x3f);
+ *s++ = 0x80 | (wc & 0x3f);
+ return 5;
+ }
+ else if (wc < (1u << 31)) {
+ *s++ = 0xfc | (wc >> 30);
+ *s++ = 0x80 | ((wc >> 24) & 0x3f);
+ *s++ = 0x80 | ((wc >> 18) & 0x3f);
+ *s++ = 0x80 | ((wc >> 12) & 0x3f);
+ *s++ = 0x80 | ((wc >> 6) & 0x3f);
+ *s++ = 0x80 | (wc & 0x3f);
+ return 6;
+ }
+ else
+ return -1;
+}
+
+/*
+ * The charset "object" and methods.
+ */
+
+struct charset {
+ int max;
+ int (*mbtowc)(void *table, int *pwc, const char *s, size_t n);
+ int (*wctomb)(void *table, char *s, int wc);
+ void *map;
+};
+
+int charset_mbtowc(struct charset *charset, int *pwc, const char *s, size_t n)
+{
+ return (*charset->mbtowc)(charset->map, pwc, s, n);
+}
+
+int charset_wctomb(struct charset *charset, char *s, int wc)
+{
+ return (*charset->wctomb)(charset->map, s, wc);
+}
+
+int charset_max(struct charset *charset)
+{
+ return charset->max;
+}
+
+/*
+ * Implementation of UTF-8.
+ */
+
+static int mbtowc_utf8(void *map, int *pwc, const char *s, size_t n)
+{
+ (void)map;
+ return utf8_mbtowc(pwc, s, n);
+}
+
+static int wctomb_utf8(void *map, char *s, int wc)
+{
+ (void)map;
+ return utf8_wctomb(s, wc);
+}
+
+/*
+ * Implementation of US-ASCII.
+ * Probably on most architectures this compiles to less than 256 bytes
+ * of code, so we can save space by not having a table for this one.
+ */
+
+static int mbtowc_ascii(void *map, int *pwc, const char *s, size_t n)
+{
+ int wc;
+
+ (void)map;
+ if (!n || !s)
+ return 0;
+ wc = (unsigned char)*s;
+ if (wc & ~0x7f)
+ return -1;
+ if (pwc)
+ *pwc = wc;
+ return wc ? 1 : 0;
+}
+
+static int wctomb_ascii(void *map, char *s, int wc)
+{
+ (void)map;
+ if (!s)
+ return 0;
+ if (wc & ~0x7f)
+ return -1;
+ *s = wc;
+ return 1;
+}
+
+/*
+ * Implementation of ISO-8859-1.
+ * Probably on most architectures this compiles to less than 256 bytes
+ * of code, so we can save space by not having a table for this one.
+ */
+
+static int mbtowc_iso1(void *map, int *pwc, const char *s, size_t n)
+{
+ int wc;
+
+ (void)map;
+ if (!n || !s)
+ return 0;
+ wc = (unsigned char)*s;
+ if (wc & ~0xff)
+ return -1;
+ if (pwc)
+ *pwc = wc;
+ return wc ? 1 : 0;
+}
+
+static int wctomb_iso1(void *map, char *s, int wc)
+{
+ (void)map;
+ if (!s)
+ return 0;
+ if (wc & ~0xff)
+ return -1;
+ *s = wc;
+ return 1;
+}
+
+/*
+ * Implementation of any 8-bit charset.
+ */
+
+struct map {
+ const unsigned short *from;
+ struct inverse_map *to;
+};
+
+static int mbtowc_8bit(void *map1, int *pwc, const char *s, size_t n)
+{
+ struct map *map = map1;
+ unsigned short wc;
+
+ if (!n || !s)
+ return 0;
+ wc = map->from[(unsigned char)*s];
+ if (wc == 0xffff)
+ return -1;
+ if (pwc)
+ *pwc = (int)wc;
+ return wc ? 1 : 0;
+}
+
+/*
+ * For the inverse map we use a hash table, which has the advantages
+ * of small constant memory requirement and simple memory allocation,
+ * but the disadvantage of slow conversion in the worst case.
+ * If you need real-time performance while letting a potentially
+ * malicious user define their own map, then the method used in
+ * linux/drivers/char/consolemap.c would be more appropriate.
+ */
+
+struct inverse_map {
+ unsigned char first[256];
+ unsigned char next[256];
+};
+
+/*
+ * The simple hash is good enough for this application.
+ * Use the alternative trivial hashes for testing.
+ */
+#define HASH(i) ((i) & 0xff)
+/* #define HASH(i) 0 */
+/* #define HASH(i) 99 */
+
+static struct inverse_map *make_inverse_map(const unsigned short *from)
+{
+ struct inverse_map *to;
+ char used[256];
+ int i, j, k;
+
+ to = (struct inverse_map *)malloc(sizeof(struct inverse_map));
+ if (!to)
+ return 0;
+ for (i = 0; i < 256; i++)
+ to->first[i] = to->next[i] = used[i] = 0;
+ for (i = 255; i >= 0; i--)
+ if (from[i] != 0xffff) {
+ k = HASH(from[i]);
+ to->next[i] = to->first[k];
+ to->first[k] = i;
+ used[k] = 1;
+ }
+
+ /* Point the empty buckets at an empty list. */
+ for (i = 0; i < 256; i++)
+ if (!to->next[i])
+ break;
+ if (i < 256)
+ for (j = 0; j < 256; j++)
+ if (!used[j])
+ to->first[j] = i;
+
+ return to;
+}
+
+static
+int wctomb_8bit(void *map1, char *s, int wc1)
+{
+ struct map *map = map1;
+ unsigned short wc = wc1;
+ int i;
+
+ if (!s)
+ return 0;
+
+ if (wc1 & ~0xffff)
+ return -1;
+
+ if (1) /* Change 1 to 0 to test the case where malloc fails. */
+ if (!map->to)
+ map->to = make_inverse_map(map->from);
+
+ if (map->to) {
+ /* Use the inverse map. */
+ i = map->to->first[HASH(wc)];
+ for (;;) {
+ if (map->from[i] == wc) {
+ *s = i;
+ return 1;
+ }
+ if (!(i = map->to->next[i]))
+ break;
+ }
+ }
+ else {
+ /* We don't have an inverse map, so do a linear search. */
+ for (i = 0; i < 256; i++)
+ if (map->from[i] == wc) {
+ *s = i;
+ return 1;
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * The "constructor" charset_find().
+ */
+
+struct charset charset_utf8 = {
+ 6,
+ &mbtowc_utf8,
+ &wctomb_utf8,
+ 0
+};
+
+struct charset charset_iso1 = {
+ 1,
+ &mbtowc_iso1,
+ &wctomb_iso1,
+ 0
+};
+
+struct charset charset_ascii = {
+ 1,
+ &mbtowc_ascii,
+ &wctomb_ascii,
+ 0
+};
+
+struct charset *charset_find(const char *code)
+{
+ int i;
+
+ /* Find good (MIME) name. */
+ for (i = 0; names[i].bad; i++)
+ if (!ascii_strcasecmp(code, names[i].bad)) {
+ code = names[i].good;
+ break;
+ }
+
+ /* Recognise some charsets for which we avoid using a table. */
+ if (!ascii_strcasecmp(code, "UTF-8"))
+ return &charset_utf8;
+ if (!ascii_strcasecmp(code, "US-ASCII"))
+ return &charset_ascii;
+ if (!ascii_strcasecmp(code, "ISO-8859-1"))
+ return &charset_iso1;
+
+ /* Look for a mapping for a simple 8-bit encoding. */
+ for (i = 0; maps[i].name; i++)
+ if (!ascii_strcasecmp(code, maps[i].name)) {
+ if (!maps[i].charset) {
+ maps[i].charset = (struct charset *)malloc(sizeof(struct charset));
+ if (maps[i].charset) {
+ struct map *map = (struct map *)malloc(sizeof(struct map));
+ if (!map) {
+ free(maps[i].charset);
+ maps[i].charset = 0;
+ }
+ else {
+ maps[i].charset->max = 1;
+ maps[i].charset->mbtowc = &mbtowc_8bit;
+ maps[i].charset->wctomb = &wctomb_8bit;
+ maps[i].charset->map = map;
+ map->from = maps[i].map;
+ map->to = 0; /* inverse mapping is created when required */
+ }
+ }
+ }
+ return maps[i].charset;
+ }
+
+ return 0;
+}
+
+/*
+ * Function to convert a buffer from one encoding to another.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ * Each of TO and TOLEN may be zero, if the result is not needed.
+ * The output buffer is null-terminated, so it is all right to
+ * use charset_convert(fromcode, tocode, s, strlen(s), &t, 0).
+ */
+
+int charset_convert(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen)
+{
+ int ret = 0;
+ struct charset *charset1, *charset2;
+ char *tobuf, *p, *newbuf;
+ int i, j, wc;
+
+ charset1 = charset_find(fromcode);
+ charset2 = charset_find(tocode);
+ if (!charset1 || !charset2 )
+ return -1;
+
+ tobuf = (char *)malloc(fromlen * charset2->max + 1);
+ if (!tobuf)
+ return -2;
+
+ for (p = tobuf; fromlen; from += i, fromlen -= i, p += j) {
+ i = charset_mbtowc(charset1, &wc, from, fromlen);
+ if (!i)
+ i = 1;
+ else if (i == -1) {
+ i = 1;
+ wc = '#';
+ ret = 2;
+ }
+ j = charset_wctomb(charset2, p, wc);
+ if (j == -1) {
+ if (!ret)
+ ret = 1;
+ j = charset_wctomb(charset2, p, '?');
+ if (j == -1)
+ j = 0;
+ }
+ }
+
+ if (tolen)
+ *tolen = p - tobuf;
+ *p++ = '\0';
+ if (to) {
+ newbuf = realloc(tobuf, p - tobuf);
+ *to = newbuf ? newbuf : tobuf;
+ }
+ else
+ free(tobuf);
+
+ return ret;
+}
+
+#endif /* USE_CHARSET_ICONV */
diff --git a/src/FLAC/src/share/utf8/charset.h b/src/FLAC/src/share/utf8/charset.h
new file mode 100644
index 0000000..b5e2fb7
--- /dev/null
+++ b/src/FLAC/src/share/utf8/charset.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * 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 <stdlib.h>
+
+/*
+ * These functions are like the C library's mbtowc() and wctomb(),
+ * but instead of depending on the locale they always work in UTF-8,
+ * and they use int instead of wchar_t.
+ */
+
+int utf8_mbtowc(int *pwc, const char *s, size_t n);
+int utf8_wctomb(char *s, int wc);
+
+/*
+ * This is an object-oriented version of mbtowc() and wctomb().
+ * The caller first uses charset_find() to get a pointer to struct
+ * charset, then uses the mbtowc() and wctomb() methods on it.
+ * The function charset_max() gives the maximum length of a
+ * multibyte character in that encoding.
+ * This API is only appropriate for stateless encodings like UTF-8
+ * or ISO-8859-3, but I have no intention of implementing anything
+ * other than UTF-8 and 8-bit encodings.
+ *
+ * MINOR BUG: If there is no memory charset_find() may return 0 and
+ * there is no way to distinguish this case from an unknown encoding.
+ */
+
+struct charset;
+
+struct charset *charset_find(const char *code);
+
+int charset_mbtowc(struct charset *charset, int *pwc, const char *s, size_t n);
+int charset_wctomb(struct charset *charset, char *s, int wc);
+int charset_max(struct charset *charset);
+
+/*
+ * Function to convert a buffer from one encoding to another.
+ * Invalid bytes are replaced by '#', and characters that are
+ * not available in the target encoding are replaced by '?'.
+ * Each of TO and TOLEN may be zero if the result is not wanted.
+ * The input or output may contain null bytes, but the output
+ * buffer is also null-terminated, so it is all right to
+ * use charset_convert(fromcode, tocode, s, strlen(s), &t, 0).
+ *
+ * Return value:
+ *
+ * -2 : memory allocation failed
+ * -1 : unknown encoding
+ * 0 : data was converted exactly
+ * 1 : valid data was converted approximately (using '?')
+ * 2 : input was invalid (but still converted, using '#')
+ */
+
+int charset_convert(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen);
diff --git a/src/FLAC/src/share/utf8/charset_test.c b/src/FLAC/src/share/utf8/charset_test.c
new file mode 100644
index 0000000..1d5bf71
--- /dev/null
+++ b/src/FLAC/src/share/utf8/charset_test.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * 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
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "charset.h"
+
+void test_any(struct charset *charset)
+{
+ int wc;
+ char s[2];
+
+ assert(charset);
+
+ /* Decoder */
+
+ assert(charset_mbtowc(charset, 0, 0, 0) == 0);
+ assert(charset_mbtowc(charset, 0, 0, 1) == 0);
+ assert(charset_mbtowc(charset, 0, (char *)(-1), 0) == 0);
+
+ assert(charset_mbtowc(charset, 0, "a", 0) == 0);
+ assert(charset_mbtowc(charset, 0, "", 1) == 0);
+ assert(charset_mbtowc(charset, 0, "b", 1) == 1);
+ assert(charset_mbtowc(charset, 0, "", 2) == 0);
+ assert(charset_mbtowc(charset, 0, "c", 2) == 1);
+
+ wc = 'x';
+ assert(charset_mbtowc(charset, &wc, "a", 0) == 0 && wc == 'x');
+ assert(charset_mbtowc(charset, &wc, "", 1) == 0 && wc == 0);
+ assert(charset_mbtowc(charset, &wc, "b", 1) == 1 && wc == 'b');
+ assert(charset_mbtowc(charset, &wc, "", 2) == 0 && wc == 0);
+ assert(charset_mbtowc(charset, &wc, "c", 2) == 1 && wc == 'c');
+
+ /* Encoder */
+
+ assert(charset_wctomb(charset, 0, 0) == 0);
+
+ s[0] = s[1] = '.';
+ assert(charset_wctomb(charset, s, 0) == 1 &&
+ s[0] == '\0' && s[1] == '.');
+ assert(charset_wctomb(charset, s, 'x') == 1 &&
+ s[0] == 'x' && s[1] == '.');
+}
+
+void test_utf8()
+{
+ struct charset *charset;
+ int wc;
+ char s[8];
+
+ charset = charset_find("UTF-8");
+ test_any(charset);
+
+ /* Decoder */
+ wc = 0;
+ assert(charset_mbtowc(charset, &wc, "\177", 1) == 1 && wc == 127);
+ assert(charset_mbtowc(charset, &wc, "\200", 2) == -1);
+ assert(charset_mbtowc(charset, &wc, "\301\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\302\200", 1) == -1);
+ assert(charset_mbtowc(charset, &wc, "\302\200", 2) == 2 && wc == 128);
+ assert(charset_mbtowc(charset, &wc, "\302\200", 3) == 2 && wc == 128);
+ assert(charset_mbtowc(charset, &wc, "\340\237\200", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\340\240\200", 9) == 3 &&
+ wc == 1 << 11);
+ assert(charset_mbtowc(charset, &wc, "\360\217\277\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\360\220\200\200", 9) == 4 &&
+ wc == 1 << 16);
+ assert(charset_mbtowc(charset, &wc, "\370\207\277\277\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\370\210\200\200\200", 9) == 5 &&
+ wc == 1 << 21);
+ assert(charset_mbtowc(charset, &wc, "\374\203\277\277\277\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\374\204\200\200\200\200", 9) == 6 &&
+ wc == 1 << 26);
+ assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\277", 9) == 6 &&
+ wc == 0x7fffffff);
+
+ assert(charset_mbtowc(charset, &wc, "\302\000", 2) == -1);
+ assert(charset_mbtowc(charset, &wc, "\302\300", 2) == -1);
+ assert(charset_mbtowc(charset, &wc, "\340\040\200", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\340\340\200", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\340\240\000", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\340\240\300", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\360\020\200\200", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\360\320\200\200", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\360\220\000\200", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\360\220\300\200", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\360\220\200\000", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\360\220\200\300", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\375\077\277\277\277\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\375\377\277\277\277\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\375\277\077\277\277\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\375\277\377\277\277\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\375\277\277\277\077\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\375\277\277\277\377\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\077", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\375\277\277\277\277\377", 9) == -1);
+
+ assert(charset_mbtowc(charset, &wc, "\376\277\277\277\277\277", 9) == -1);
+ assert(charset_mbtowc(charset, &wc, "\377\277\277\277\277\277", 9) == -1);
+
+ /* Encoder */
+ strcpy(s, ".......");
+ assert(charset_wctomb(charset, s, 1 << 31) == -1 &&
+ !strcmp(s, "......."));
+ assert(charset_wctomb(charset, s, 127) == 1 &&
+ !strcmp(s, "\177......"));
+ assert(charset_wctomb(charset, s, 128) == 2 &&
+ !strcmp(s, "\302\200....."));
+ assert(charset_wctomb(charset, s, 0x7ff) == 2 &&
+ !strcmp(s, "\337\277....."));
+ assert(charset_wctomb(charset, s, 0x800) == 3 &&
+ !strcmp(s, "\340\240\200...."));
+ assert(charset_wctomb(charset, s, 0xffff) == 3 &&
+ !strcmp(s, "\357\277\277...."));
+ assert(charset_wctomb(charset, s, 0x10000) == 4 &&
+ !strcmp(s, "\360\220\200\200..."));
+ assert(charset_wctomb(charset, s, 0x1fffff) == 4 &&
+ !strcmp(s, "\367\277\277\277..."));
+ assert(charset_wctomb(charset, s, 0x200000) == 5 &&
+ !strcmp(s, "\370\210\200\200\200.."));
+ assert(charset_wctomb(charset, s, 0x3ffffff) == 5 &&
+ !strcmp(s, "\373\277\277\277\277.."));
+ assert(charset_wctomb(charset, s, 0x4000000) == 6 &&
+ !strcmp(s, "\374\204\200\200\200\200."));
+ assert(charset_wctomb(charset, s, 0x7fffffff) == 6 &&
+ !strcmp(s, "\375\277\277\277\277\277."));
+}
+
+void test_ascii()
+{
+ struct charset *charset;
+ int wc;
+ char s[3];
+
+ charset = charset_find("us-ascii");
+ test_any(charset);
+
+ /* Decoder */
+ wc = 0;
+ assert(charset_mbtowc(charset, &wc, "\177", 2) == 1 && wc == 127);
+ assert(charset_mbtowc(charset, &wc, "\200", 2) == -1);
+
+ /* Encoder */
+ strcpy(s, "..");
+ assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, ".."));
+ assert(charset_wctomb(charset, s, 255) == -1);
+ assert(charset_wctomb(charset, s, 128) == -1);
+ assert(charset_wctomb(charset, s, 127) == 1 && !strcmp(s, "\177."));
+}
+
+void test_iso1()
+{
+ struct charset *charset;
+ int wc;
+ char s[3];
+
+ charset = charset_find("iso-8859-1");
+ test_any(charset);
+
+ /* Decoder */
+ wc = 0;
+ assert(charset_mbtowc(charset, &wc, "\302\200", 9) == 1 && wc == 0xc2);
+
+ /* Encoder */
+ strcpy(s, "..");
+ assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, ".."));
+ assert(charset_wctomb(charset, s, 255) == 1 && !strcmp(s, "\377."));
+ assert(charset_wctomb(charset, s, 128) == 1 && !strcmp(s, "\200."));
+}
+
+void test_iso2()
+{
+ struct charset *charset;
+ int wc;
+ char s[3];
+
+ charset = charset_find("iso-8859-2");
+ test_any(charset);
+
+ /* Decoder */
+ wc = 0;
+ assert(charset_mbtowc(charset, &wc, "\302\200", 9) == 1 && wc == 0xc2);
+ assert(charset_mbtowc(charset, &wc, "\377", 2) == 1 && wc == 0x2d9);
+
+ /* Encoder */
+ strcpy(s, "..");
+ assert(charset_wctomb(charset, s, 256) == -1 && !strcmp(s, ".."));
+ assert(charset_wctomb(charset, s, 255) == -1 && !strcmp(s, ".."));
+ assert(charset_wctomb(charset, s, 258) == 1 && !strcmp(s, "\303."));
+ assert(charset_wctomb(charset, s, 128) == 1 && !strcmp(s, "\200."));
+}
+
+void test_convert()
+{
+ const char *p;
+ char *q, *r;
+ char s[256];
+ size_t n, n2;
+ int i;
+
+ p = "\000x\302\200\375\277\277\277\277\277";
+ assert(charset_convert("UTF-8", "UTF-8", p, 10, &q, &n) == 0 &&
+ n == 10 && !strcmp(p, q));
+ assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, &q, &n) == 2 &&
+ n == 4 && !strcmp(q, "x##y"));
+ assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, 0, &n) == 2 &&
+ n == 4);
+ assert(charset_convert("UTF-8", "UTF-8", "x\301\277y", 4, &q, 0) == 2 &&
+ !strcmp(q, "x##y"));
+ assert(charset_convert("UTF-8", "iso-8859-1",
+ "\302\200\304\200x", 5, &q, &n) == 1 &&
+ n == 3 && !strcmp(q, "\200?x"));
+ assert(charset_convert("iso-8859-1", "UTF-8",
+ "\000\200\377", 3, &q, &n) == 0 &&
+ n == 5 && !memcmp(q, "\000\302\200\303\277", 5));
+ assert(charset_convert("iso-8859-1", "iso-8859-1",
+ "\000\200\377", 3, &q, &n) == 0 &&
+ n == 3 && !memcmp(q, "\000\200\377", 3));
+
+ assert(charset_convert("iso-8859-2", "utf-8", "\300", 1, &q, &n) == 0 &&
+ n == 2 && !strcmp(q, "\305\224"));
+ assert(charset_convert("utf-8", "iso-8859-2", "\305\224", 2, &q, &n) == 0 &&
+ n == 1 && !strcmp(q, "\300"));
+
+ for (i = 0; i < 256; i++)
+ s[i] = i;
+
+ assert(charset_convert("iso-8859-2", "utf-8", s, 256, &q, &n) == 0);
+ assert(charset_convert("utf-8", "iso-8859-2", q, n, &r, &n2) == 0);
+ assert(n2 == 256 && !memcmp(r, s, n2));
+}
+
+int main()
+{
+ test_utf8();
+ test_ascii();
+ test_iso1();
+ test_iso2();
+
+ test_convert();
+
+ return 0;
+}
diff --git a/src/FLAC/src/share/utf8/charsetmap.h b/src/FLAC/src/share/utf8/charsetmap.h
new file mode 100644
index 0000000..b812590
--- /dev/null
+++ b/src/FLAC/src/share/utf8/charsetmap.h
@@ -0,0 +1,79 @@
+/* This file was automatically generated by make_code_map.pl
+ please don't edit directly
+ Daniel Resare <noa@metamatrix.se>
+*/
+charset_map maps[] = {
+ {"ISO-8859-1",
+ {
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+ 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+ 0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
+ 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+ 0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+ 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+ 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F,
+ 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+ 0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
+ 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+ 0x0088,0x0089,0x008A,0x008B,0x008C,0x008D,0x008E,0x008F,
+ 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+ 0x0098,0x0099,0x009A,0x009B,0x009C,0x009D,0x009E,0x009F,
+ 0x00A0,0x00A1,0x00A2,0x00A3,0x00A4,0x00A5,0x00A6,0x00A7,
+ 0x00A8,0x00A9,0x00AA,0x00AB,0x00AC,0x00AD,0x00AE,0x00AF,
+ 0x00B0,0x00B1,0x00B2,0x00B3,0x00B4,0x00B5,0x00B6,0x00B7,
+ 0x00B8,0x00B9,0x00BA,0x00BB,0x00BC,0x00BD,0x00BE,0x00BF,
+ 0x00C0,0x00C1,0x00C2,0x00C3,0x00C4,0x00C5,0x00C6,0x00C7,
+ 0x00C8,0x00C9,0x00CA,0x00CB,0x00CC,0x00CD,0x00CE,0x00CF,
+ 0x00D0,0x00D1,0x00D2,0x00D3,0x00D4,0x00D5,0x00D6,0x00D7,
+ 0x00D8,0x00D9,0x00DA,0x00DB,0x00DC,0x00DD,0x00DE,0x00DF,
+ 0x00E0,0x00E1,0x00E2,0x00E3,0x00E4,0x00E5,0x00E6,0x00E7,
+ 0x00E8,0x00E9,0x00EA,0x00EB,0x00EC,0x00ED,0x00EE,0x00EF,
+ 0x00F0,0x00F1,0x00F2,0x00F3,0x00F4,0x00F5,0x00F6,0x00F7,
+ 0x00F8,0x00F9,0x00FA,0x00FB,0x00FC,0x00FD,0x00FE,0x00FF
+ }
+ },
+ {"ISO-8859-2",
+ {
+ 0x0000,0x0001,0x0002,0x0003,0x0004,0x0005,0x0006,0x0007,
+ 0x0008,0x0009,0x000A,0x000B,0x000C,0x000D,0x000E,0x000F,
+ 0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
+ 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F,
+ 0x0020,0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,
+ 0x0028,0x0029,0x002A,0x002B,0x002C,0x002D,0x002E,0x002F,
+ 0x0030,0x0031,0x0032,0x0033,0x0034,0x0035,0x0036,0x0037,
+ 0x0038,0x0039,0x003A,0x003B,0x003C,0x003D,0x003E,0x003F,
+ 0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,
+ 0x0048,0x0049,0x004A,0x004B,0x004C,0x004D,0x004E,0x004F,
+ 0x0050,0x0051,0x0052,0x0053,0x0054,0x0055,0x0056,0x0057,
+ 0x0058,0x0059,0x005A,0x005B,0x005C,0x005D,0x005E,0x005F,
+ 0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,0x0067,
+ 0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
+ 0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
+ 0x0078,0x0079,0x007A,0x007B,0x007C,0x007D,0x007E,0x007F,
+ 0x0080,0x0081,0x0082,0x0083,0x0084,0x0085,0x0086,0x0087,
+ 0x0088,0x0089,0x008A,0x008B,0x008C,0x008D,0x008E,0x008F,
+ 0x0090,0x0091,0x0092,0x0093,0x0094,0x0095,0x0096,0x0097,
+ 0x0098,0x0099,0x009A,0x009B,0x009C,0x009D,0x009E,0x009F,
+ 0x00A0,0x0104,0x02D8,0x0141,0x00A4,0x013D,0x015A,0x00A7,
+ 0x00A8,0x0160,0x015E,0x0164,0x0179,0x00AD,0x017D,0x017B,
+ 0x00B0,0x0105,0x02DB,0x0142,0x00B4,0x013E,0x015B,0x02C7,
+ 0x00B8,0x0161,0x015F,0x0165,0x017A,0x02DD,0x017E,0x017C,
+ 0x0154,0x00C1,0x00C2,0x0102,0x00C4,0x0139,0x0106,0x00C7,
+ 0x010C,0x00C9,0x0118,0x00CB,0x011A,0x00CD,0x00CE,0x010E,
+ 0x0110,0x0143,0x0147,0x00D3,0x00D4,0x0150,0x00D6,0x00D7,
+ 0x0158,0x016E,0x00DA,0x0170,0x00DC,0x00DD,0x0162,0x00DF,
+ 0x0155,0x00E1,0x00E2,0x0103,0x00E4,0x013A,0x0107,0x00E7,
+ 0x010D,0x00E9,0x0119,0x00EB,0x011B,0x00ED,0x00EE,0x010F,
+ 0x0111,0x0144,0x0148,0x00F3,0x00F4,0x0151,0x00F6,0x00F7,
+ 0x0159,0x016F,0x00FA,0x0171,0x00FC,0x00FD,0x0163,0x02D9
+ }
+ },
+ {NULL}
+};
diff --git a/src/FLAC/src/share/utf8/iconvert.c b/src/FLAC/src/share/utf8/iconvert.c
new file mode 100644
index 0000000..b72ad86
--- /dev/null
+++ b/src/FLAC/src/share/utf8/iconvert.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * 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
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_ICONV
+
+#include <assert.h>
+#include <errno.h>
+#include <iconv.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Convert data from one encoding to another. Return:
+ *
+ * -2 : memory allocation failed
+ * -1 : unknown encoding
+ * 0 : data was converted exactly
+ * 1 : data was converted inexactly
+ * 2 : data was invalid (but still converted)
+ *
+ * We convert in two steps, via UTF-8, as this is the only
+ * reliable way of distinguishing between invalid input
+ * and valid input which iconv refuses to transliterate.
+ * We convert from UTF-8 twice, because we have no way of
+ * knowing whether the conversion was exact if iconv returns
+ * E2BIG (due to a bug in the specification of iconv).
+ * An alternative approach is to assume that the output of
+ * iconv is never more than 4 times as long as the input,
+ * but I prefer to avoid that assumption if possible.
+ */
+
+int iconvert(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen)
+{
+ int ret = 0;
+ iconv_t cd1, cd2;
+ char *ib;
+ char *ob;
+ char *utfbuf = 0, *outbuf, *newbuf;
+ size_t utflen, outlen, ibl, obl, k;
+ char tbuf[2048];
+
+ cd1 = iconv_open("UTF-8", fromcode);
+ if (cd1 == (iconv_t)(-1))
+ return -1;
+
+ cd2 = (iconv_t)(-1);
+ /* Don't use strcasecmp() as it's locale-dependent. */
+ if (!strchr("Uu", tocode[0]) ||
+ !strchr("Tt", tocode[1]) ||
+ !strchr("Ff", tocode[2]) ||
+ tocode[3] != '-' ||
+ tocode[4] != '8' ||
+ tocode[5] != '\0') {
+ char *tocode1;
+
+ /*
+ * Try using this non-standard feature of glibc and libiconv.
+ * This is deliberately not a config option as people often
+ * change their iconv library without rebuilding applications.
+ */
+ tocode1 = (char *)malloc(strlen(tocode) + 11);
+ if (!tocode1)
+ goto fail;
+
+ strcpy(tocode1, tocode);
+ strcat(tocode1, "//TRANSLIT");
+ cd2 = iconv_open(tocode1, "UTF-8");
+ free(tocode1);
+
+ if (cd2 == (iconv_t)(-1))
+ cd2 = iconv_open(tocode, fromcode);
+
+ if (cd2 == (iconv_t)(-1)) {
+ iconv_close(cd1);
+ return -1;
+ }
+ }
+
+ utflen = 1; /*fromlen * 2 + 1; XXX */
+ utfbuf = (char *)malloc(utflen);
+ if (!utfbuf)
+ goto fail;
+
+ /* Convert to UTF-8 */
+ ib = (char *)from;
+ ibl = fromlen;
+ ob = utfbuf;
+ obl = utflen;
+ for (;;) {
+ k = iconv(cd1, &ib, &ibl, &ob, &obl);
+ assert((!k && !ibl) ||
+ (k == (size_t)(-1) && errno == E2BIG && ibl && obl < 6) ||
+ (k == (size_t)(-1) &&
+ (errno == EILSEQ || errno == EINVAL) && ibl));
+ if (!ibl)
+ break;
+ if (obl < 6) {
+ /* Enlarge the buffer */
+ utflen *= 2;
+ newbuf = (char *)realloc(utfbuf, utflen);
+ if (!newbuf)
+ goto fail;
+ ob = (ob - utfbuf) + newbuf;
+ obl = utflen - (ob - newbuf);
+ utfbuf = newbuf;
+ }
+ else {
+ /* Invalid input */
+ ib++, ibl--;
+ *ob++ = '#', obl--;
+ ret = 2;
+ iconv(cd1, 0, 0, 0, 0);
+ }
+ }
+
+ if (cd2 == (iconv_t)(-1)) {
+ /* The target encoding was UTF-8 */
+ if (tolen)
+ *tolen = ob - utfbuf;
+ if (!to) {
+ free(utfbuf);
+ iconv_close(cd1);
+ return ret;
+ }
+ newbuf = (char *)realloc(utfbuf, (ob - utfbuf) + 1);
+ if (!newbuf)
+ goto fail;
+ ob = (ob - utfbuf) + newbuf;
+ *ob = '\0';
+ *to = newbuf;
+ iconv_close(cd1);
+ return ret;
+ }
+
+ /* Truncate the buffer to be tidy */
+ utflen = ob - utfbuf;
+ newbuf = (char *)realloc(utfbuf, utflen);
+ if (!newbuf)
+ goto fail;
+ utfbuf = newbuf;
+
+ /* Convert from UTF-8 to discover how long the output is */
+ outlen = 0;
+ ib = utfbuf;
+ ibl = utflen;
+ while (ibl) {
+ ob = tbuf;
+ obl = sizeof(tbuf);
+ k = iconv(cd2, &ib, &ibl, &ob, &obl);
+ assert((k != (size_t)(-1) && !ibl) ||
+ (k == (size_t)(-1) && errno == E2BIG && ibl) ||
+ (k == (size_t)(-1) && errno == EILSEQ && ibl));
+ if (ibl && !(k == (size_t)(-1) && errno == E2BIG)) {
+ /* Replace one character */
+ char *tb = "?";
+ size_t tbl = 1;
+
+ outlen += ob - tbuf;
+ ob = tbuf;
+ obl = sizeof(tbuf);
+ k = iconv(cd2, &tb, &tbl, &ob, &obl);
+ assert((!k && !tbl) ||
+ (k == (size_t)(-1) && errno == EILSEQ && tbl));
+ for (++ib, --ibl; ibl && (*ib & 0x80); ib++, ibl--)
+ ;
+ }
+ outlen += ob - tbuf;
+ }
+ ob = tbuf;
+ obl = sizeof(tbuf);
+ k = iconv(cd2, 0, 0, &ob, &obl);
+ assert(!k);
+ outlen += ob - tbuf;
+
+ /* Convert from UTF-8 for real */
+ outbuf = (char *)malloc(outlen + 1);
+ if (!outbuf)
+ goto fail;
+ ib = utfbuf;
+ ibl = utflen;
+ ob = outbuf;
+ obl = outlen;
+ while (ibl) {
+ k = iconv(cd2, &ib, &ibl, &ob, &obl);
+ assert((k != (size_t)(-1) && !ibl) ||
+ (k == (size_t)(-1) && errno == EILSEQ && ibl));
+ if (k && !ret)
+ ret = 1;
+ if (ibl && !(k == (size_t)(-1) && errno == E2BIG)) {
+ /* Replace one character */
+ char *tb = "?";
+ size_t tbl = 1;
+
+ k = iconv(cd2, &tb, &tbl, &ob, &obl);
+ assert((!k && !tbl) ||
+ (k == (size_t)(-1) && errno == EILSEQ && tbl));
+ for (++ib, --ibl; ibl && (*ib & 0x80); ib++, ibl--)
+ ;
+ }
+ }
+ k = iconv(cd2, 0, 0, &ob, &obl);
+ assert(!k);
+ assert(!obl);
+ *ob = '\0';
+
+ free(utfbuf);
+ iconv_close(cd1);
+ iconv_close(cd2);
+ if (tolen)
+ *tolen = outlen;
+ if (!to) {
+ free(outbuf);
+ return ret;
+ }
+ *to = outbuf;
+ return ret;
+
+ fail:
+ if(0 != utfbuf)
+ free(utfbuf);
+ iconv_close(cd1);
+ if (cd2 != (iconv_t)(-1))
+ iconv_close(cd2);
+ return -2;
+}
+
+#endif /* HAVE_ICONV */
diff --git a/src/FLAC/src/share/utf8/makemap.c b/src/FLAC/src/share/utf8/makemap.c
new file mode 100644
index 0000000..72a9de1
--- /dev/null
+++ b/src/FLAC/src/share/utf8/makemap.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * 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
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <iconv.h>
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ iconv_t cd;
+ const char *ib;
+ char *ob;
+ size_t ibl, obl, k;
+ unsigned char c, buf[4];
+ int i, wc;
+
+ if (argc != 2) {
+ printf("Usage: %s ENCODING\n", argv[0]);
+ printf("Output a charset map for the 8-bit ENCODING.\n");
+ return 1;
+ }
+
+ cd = iconv_open("UCS-4", argv[1]);
+ if (cd == (iconv_t)(-1)) {
+ perror("iconv_open");
+ return 1;
+ }
+
+ for (i = 0; i < 256; i++) {
+ c = i;
+ ib = &c;
+ ibl = 1;
+ ob = buf;
+ obl = 4;
+ k = iconv(cd, &ib, &ibl, &ob, &obl);
+ if (!k && !ibl && !obl) {
+ wc = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3];
+ if (wc >= 0xffff) {
+ printf("Dodgy value.\n");
+ return 1;
+ }
+ }
+ else if (k == (size_t)(-1) && errno == EILSEQ)
+ wc = 0xffff;
+ else {
+ printf("Non-standard iconv.\n");
+ return 1;
+ }
+
+ if (i % 8 == 0)
+ printf(" ");
+ printf("0x%04x", wc);
+ if (i == 255)
+ printf("\n");
+ else if (i % 8 == 7)
+ printf(",\n");
+ else
+ printf(", ");
+ }
+
+ return 0;
+}
diff --git a/src/FLAC/src/share/utf8/utf8.c b/src/FLAC/src/share/utf8/utf8.c
new file mode 100644
index 0000000..fc2c69b
--- /dev/null
+++ b/src/FLAC/src/share/utf8/utf8.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2001 Peter Harris <peter.harris@hummingbird.com>
+ * Copyright (C) 2001 Edmund Grimley Evans <edmundo@rano.org>
+ *
+ * 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
+ */
+
+/*
+ * Convert a string between UTF-8 and the locale's charset.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "utf8.h"
+#include "charset.h"
+
+
+#ifdef _WIN32
+
+ /* Thanks to Peter Harris <peter.harris@hummingbird.com> for this win32
+ * code.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+
+static unsigned char *make_utf8_string(const wchar_t *unicode)
+{
+ int size = 0, index = 0, out_index = 0;
+ unsigned char *out;
+ unsigned short c;
+
+ /* first calculate the size of the target string */
+ c = unicode[index++];
+ while(c) {
+ if(c < 0x0080) {
+ size += 1;
+ } else if(c < 0x0800) {
+ size += 2;
+ } else {
+ size += 3;
+ }
+ c = unicode[index++];
+ }
+
+ out = malloc(size + 1);
+ if (out == NULL)
+ return NULL;
+ index = 0;
+
+ c = unicode[index++];
+ while(c)
+ {
+ if(c < 0x080) {
+ out[out_index++] = (unsigned char)c;
+ } else if(c < 0x800) {
+ out[out_index++] = 0xc0 | (c >> 6);
+ out[out_index++] = 0x80 | (c & 0x3f);
+ } else {
+ out[out_index++] = 0xe0 | (c >> 12);
+ out[out_index++] = 0x80 | ((c >> 6) & 0x3f);
+ out[out_index++] = 0x80 | (c & 0x3f);
+ }
+ c = unicode[index++];
+ }
+ out[out_index] = 0x00;
+
+ return out;
+}
+
+static wchar_t *make_unicode_string(const unsigned char *utf8)
+{
+ int size = 0, index = 0, out_index = 0;
+ wchar_t *out;
+ unsigned char c;
+
+ /* first calculate the size of the target string */
+ c = utf8[index++];
+ while(c) {
+ if((c & 0x80) == 0) {
+ index += 0;
+ } else if((c & 0xe0) == 0xe0) {
+ index += 2;
+ } else {
+ index += 1;
+ }
+ size += 1;
+ c = utf8[index++];
+ }
+
+ out = malloc((size + 1) * sizeof(wchar_t));
+ if (out == NULL)
+ return NULL;
+ index = 0;
+
+ c = utf8[index++];
+ while(c)
+ {
+ if((c & 0x80) == 0) {
+ out[out_index++] = c;
+ } else if((c & 0xe0) == 0xe0) {
+ out[out_index] = (c & 0x1F) << 12;
+ c = utf8[index++];
+ out[out_index] |= (c & 0x3F) << 6;
+ c = utf8[index++];
+ out[out_index++] |= (c & 0x3F);
+ } else {
+ out[out_index] = (c & 0x3F) << 6;
+ c = utf8[index++];
+ out[out_index++] |= (c & 0x3F);
+ }
+ c = utf8[index++];
+ }
+ out[out_index] = 0;
+
+ return out;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+ wchar_t *unicode;
+ int wchars, err;
+
+ wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from,
+ strlen(from), NULL, 0);
+
+ if(wchars == 0)
+ {
+ fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ return -1;
+ }
+
+ unicode = calloc(wchars + 1, sizeof(unsigned short));
+ if(unicode == NULL)
+ {
+ fprintf(stderr, "Out of memory processing string to UTF8\n");
+ return -1;
+ }
+
+ err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from,
+ strlen(from), unicode, wchars);
+ if(err != wchars)
+ {
+ free(unicode);
+ fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ return -1;
+ }
+
+ /* On NT-based windows systems, we could use WideCharToMultiByte(), but
+ * MS doesn't actually have a consistent API across win32.
+ */
+ *to = make_utf8_string(unicode);
+
+ free(unicode);
+ return 0;
+}
+
+int utf8_decode(const char *from, char **to)
+{
+ wchar_t *unicode;
+ int chars, err;
+
+ /* On NT-based windows systems, we could use MultiByteToWideChar(CP_UTF8), but
+ * MS doesn't actually have a consistent API across win32.
+ */
+ unicode = make_unicode_string(from);
+ if(unicode == NULL)
+ {
+ fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n");
+ return -1;
+ }
+
+ chars = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode,
+ -1, NULL, 0, NULL, NULL);
+
+ if(chars == 0)
+ {
+ fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ free(unicode);
+ return -1;
+ }
+
+ *to = calloc(chars + 1, sizeof(unsigned char));
+ if(*to == NULL)
+ {
+ fprintf(stderr, "Out of memory processing string to local charset\n");
+ free(unicode);
+ return -1;
+ }
+
+ err = WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode,
+ -1, *to, chars, NULL, NULL);
+ if(err != chars)
+ {
+ fprintf(stderr, "Unicode translation error %d\n", GetLastError());
+ free(unicode);
+ free(*to);
+ *to = NULL;
+ return -1;
+ }
+
+ free(unicode);
+ return 0;
+}
+
+#else /* End win32. Rest is for real operating systems */
+
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+int iconvert(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen);
+
+static const char *current_charset(void)
+{
+ const char *c = 0;
+#ifdef HAVE_LANGINFO_CODESET
+ c = nl_langinfo(CODESET);
+#endif
+
+ if (!c)
+ c = getenv("CHARSET");
+
+ return c? c : "US-ASCII";
+}
+
+static int convert_buffer(const char *fromcode, const char *tocode,
+ const char *from, size_t fromlen,
+ char **to, size_t *tolen)
+{
+ int ret = -1;
+
+#ifdef HAVE_ICONV
+ ret = iconvert(fromcode, tocode, from, fromlen, to, tolen);
+ if (ret != -1)
+ return ret;
+#endif
+
+#ifndef HAVE_ICONV /* should be ifdef USE_CHARSET_CONVERT */
+ ret = charset_convert(fromcode, tocode, from, fromlen, to, tolen);
+ if (ret != -1)
+ return ret;
+#endif
+
+ return ret;
+}
+
+static int convert_string(const char *fromcode, const char *tocode,
+ const char *from, char **to, char replace)
+{
+ int ret;
+ size_t fromlen;
+ char *s;
+
+ fromlen = strlen(from);
+ ret = convert_buffer(fromcode, tocode, from, fromlen, to, 0);
+ if (ret == -2)
+ return -1;
+ if (ret != -1)
+ return ret;
+
+ s = malloc(fromlen + 1);
+ if (!s)
+ return -1;
+ strcpy(s, from);
+ *to = s;
+ for (; *s; s++)
+ if (*s & ~0x7f)
+ *s = replace;
+ return 3;
+}
+
+int utf8_encode(const char *from, char **to)
+{
+ return convert_string(current_charset(), "UTF-8", from, to, '#');
+}
+
+int utf8_decode(const char *from, char **to)
+{
+ return convert_string("UTF-8", current_charset(), from, to, '?');
+}
+
+#endif
diff --git a/src/FLAC/src/test_grabbag/Makefile.am b/src/FLAC/src/test_grabbag/Makefile.am
new file mode 100644
index 0000000..6e614aa
--- /dev/null
+++ b/src/FLAC/src/test_grabbag/Makefile.am
@@ -0,0 +1,19 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under difference licenses. The codec libraries
+# are distributed under Xiph.Org's BSD-like license (see the file
+# COPYING.Xiph in this distribution). All other programs, libraries, and
+# plugins are distributed under the GPL (see COPYING.GPL). The documentation
+# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
+# FLAC distribution contains at the top the terms under which it may be
+# distributed.
+#
+# Since this particular file is relevant to all components of FLAC,
+# it may be distributed under the Xiph.Org license, which is the least
+# restrictive of those mentioned above. See the file COPYING.Xiph in this
+# distribution.
+
+SUBDIRS = cuesheet picture
+
diff --git a/src/FLAC/src/test_grabbag/cuesheet/Makefile.am b/src/FLAC/src/test_grabbag/cuesheet/Makefile.am
new file mode 100644
index 0000000..e4ea0fd
--- /dev/null
+++ b/src/FLAC/src/test_grabbag/cuesheet/Makefile.am
@@ -0,0 +1,30 @@
+# test_cuesheet - Simple tester for cuesheet routines in grabbag
+# Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+INCLUDES = -I$(top_srcdir)/src/FLAC/include
+
+noinst_PROGRAMS = test_cuesheet
+test_cuesheet_SOURCES = \
+ main.c
+test_cuesheet_LDADD = \
+ $(top_builddir)/src/FLAC/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/FLAC/src/share/replaygain_anal/libreplaygain_analysis.la \
+ $(top_builddir)/src/FLAC/src/libFLAC/libFLAC.la \
+ $(top_builddir)/src/OGG/libogg.la \
+ -lm
+
+CLEANFILES = $(wildcard *.raw)
diff --git a/src/FLAC/src/test_grabbag/cuesheet/main.c b/src/FLAC/src/test_grabbag/cuesheet/main.c
new file mode 100644
index 0000000..bb99834
--- /dev/null
+++ b/src/FLAC/src/test_grabbag/cuesheet/main.c
@@ -0,0 +1,138 @@
+/* test_cuesheet - Simple tester for cuesheet routines in grabbag
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+
+static int do_cuesheet(const char *infilename, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
+{
+ FILE *fin, *fout;
+ const char *error_message;
+ char tmpfilename[4096];
+ unsigned last_line_read;
+ FLAC__StreamMetadata *cuesheet;
+
+ FLAC__ASSERT(strlen(infilename) + 2 < sizeof(tmpfilename));
+
+ /*
+ * pass 1
+ */
+ if(0 == strcmp(infilename, "-")) {
+ fin = stdin;
+ }
+ else if(0 == (fin = fopen(infilename, "r"))) {
+ fprintf(stderr, "can't open file %s for reading: %s\n", infilename, strerror(errno));
+ return 255;
+ }
+ if(0 != (cuesheet = grabbag__cuesheet_parse(fin, &error_message, &last_line_read, is_cdda, lead_out_offset))) {
+ if(fin != stdin)
+ fclose(fin);
+ }
+ else {
+ printf("pass1: parse error, line %u: \"%s\"\n", last_line_read, error_message);
+ if(fin != stdin)
+ fclose(fin);
+ return 1;
+ }
+ if(!FLAC__metadata_object_cuesheet_is_legal(cuesheet, is_cdda, &error_message)) {
+ printf("pass1: illegal cuesheet: \"%s\"\n", error_message);
+ FLAC__metadata_object_delete(cuesheet);
+ return 1;
+ }
+ sprintf(tmpfilename, "%s.1", infilename);
+ if(0 == (fout = fopen(tmpfilename, "w"))) {
+ fprintf(stderr, "can't open file %s for writing: %s\n", tmpfilename, strerror(errno));
+ FLAC__metadata_object_delete(cuesheet);
+ return 255;
+ }
+ grabbag__cuesheet_emit(fout, cuesheet, "\"dummy.wav\" WAVE");
+ FLAC__metadata_object_delete(cuesheet);
+ fclose(fout);
+
+ /*
+ * pass 2
+ */
+ if(0 == (fin = fopen(tmpfilename, "r"))) {
+ fprintf(stderr, "can't open file %s for reading: %s\n", tmpfilename, strerror(errno));
+ return 255;
+ }
+ if(0 != (cuesheet = grabbag__cuesheet_parse(fin, &error_message, &last_line_read, is_cdda, lead_out_offset))) {
+ if(fin != stdin)
+ fclose(fin);
+ }
+ else {
+ printf("pass2: parse error, line %u: \"%s\"\n", last_line_read, error_message);
+ if(fin != stdin)
+ fclose(fin);
+ return 1;
+ }
+ if(!FLAC__metadata_object_cuesheet_is_legal(cuesheet, is_cdda, &error_message)) {
+ printf("pass2: illegal cuesheet: \"%s\"\n", error_message);
+ FLAC__metadata_object_delete(cuesheet);
+ return 1;
+ }
+ sprintf(tmpfilename, "%s.2", infilename);
+ if(0 == (fout = fopen(tmpfilename, "w"))) {
+ fprintf(stderr, "can't open file %s for writing: %s\n", tmpfilename, strerror(errno));
+ FLAC__metadata_object_delete(cuesheet);
+ return 255;
+ }
+ grabbag__cuesheet_emit(fout, cuesheet, "\"dummy.wav\" WAVE");
+ FLAC__metadata_object_delete(cuesheet);
+ fclose(fout);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ FLAC__uint64 lead_out_offset;
+ FLAC__bool is_cdda = false;
+ const char *usage = "usage: test_cuesheet cuesheet_file lead_out_offset [ cdda ]\n";
+
+ if(argc > 1 && 0 == strcmp(argv[1], "-h")) {
+ printf(usage);
+ return 0;
+ }
+
+ if(argc < 3 || argc > 4) {
+ fprintf(stderr, usage);
+ return 255;
+ }
+
+ lead_out_offset = (FLAC__uint64)strtoul(argv[2], 0, 10);
+ if(argc == 4) {
+ if(0 == strcmp(argv[3], "cdda"))
+ is_cdda = true;
+ else {
+ fprintf(stderr, usage);
+ return 255;
+ }
+ }
+
+ return do_cuesheet(argv[1], is_cdda, lead_out_offset);
+}
diff --git a/src/FLAC/src/test_grabbag/picture/Makefile.am b/src/FLAC/src/test_grabbag/picture/Makefile.am
new file mode 100644
index 0000000..9abcb47
--- /dev/null
+++ b/src/FLAC/src/test_grabbag/picture/Makefile.am
@@ -0,0 +1,29 @@
+# test_picture - Simple tester for picture routines in grabbag
+# Copyright (C) 2006,2007 Josh Coalson
+#
+# 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.
+
+INCLUDES = -I$(top_srcdir)/src/FLAC/include
+
+noinst_PROGRAMS = test_picture
+test_picture_SOURCES = \
+ main.c
+test_picture_LDADD = \
+ $(top_builddir)/src/FLAC/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/FLAC/src/libFLAC/libFLAC.la \
+ $(top_builddir)/src/OGG/libogg.la \
+ -lm
+
+CLEANFILES = $(wildcard *.raw)
diff --git a/src/FLAC/src/test_grabbag/picture/main.c b/src/FLAC/src/test_grabbag/picture/main.c
new file mode 100644
index 0000000..2ca34a6
--- /dev/null
+++ b/src/FLAC/src/test_grabbag/picture/main.c
@@ -0,0 +1,224 @@
+/* test_picture - Simple tester for picture routines in grabbag
+ * Copyright (C) 2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include "FLAC/assert.h"
+#include "share/grabbag.h"
+
+typedef struct {
+ const char *path;
+ const char *mime_type;
+ const char *description;
+ FLAC__uint32 width;
+ FLAC__uint32 height;
+ FLAC__uint32 depth;
+ FLAC__uint32 colors;
+ FLAC__StreamMetadata_Picture_Type type;
+} PictureFile;
+
+PictureFile picturefiles[] = {
+ { "0.gif", "image/gif" , "", 24, 24, 24, 2, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "1.gif", "image/gif" , "", 12, 8, 24, 256, FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER },
+ { "2.gif", "image/gif" , "", 16, 14, 24, 128, FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER },
+ { "0.jpg", "image/jpeg", "", 30, 20, 8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "4.jpg", "image/jpeg", "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "0.png", "image/png" , "", 30, 20, 8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "1.png", "image/png" , "", 30, 20, 8, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "2.png", "image/png" , "", 30, 20, 24, 7, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "3.png", "image/png" , "", 30, 20, 24, 7, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "4.png", "image/png" , "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "5.png", "image/png" , "", 31, 47, 24, 0, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "6.png", "image/png" , "", 31, 47, 24, 23, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "7.png", "image/png" , "", 31, 47, 24, 23, FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER },
+ { "8.png", "image/png" , "", 32, 32, 32, 0, 999 }
+};
+
+static FLAC__bool debug_ = false;
+
+static FLAC__bool failed_(const char *msg)
+{
+ if(msg)
+ printf("FAILED, %s\n", msg);
+ else
+ printf("FAILED\n");
+
+ return false;
+}
+
+static FLAC__bool test_one_picture(const char *prefix, const PictureFile *pf, const char *res, FLAC__bool fn_only)
+{
+ FLAC__StreamMetadata *obj;
+ const char *error;
+ char s[4096];
+ if(fn_only)
+#if defined _MSC_VER || defined __MINGW32__
+ _snprintf(s, sizeof(s)-1, "%s/%s", prefix, pf->path);
+#else
+ snprintf(s, sizeof(s)-1, "%s/%s", prefix, pf->path);
+#endif
+ else
+#if defined _MSC_VER || defined __MINGW32__
+ _snprintf(s, sizeof(s)-1, "%u|%s|%s|%s|%s/%s", (unsigned)pf->type, pf->mime_type, pf->description, res, prefix, pf->path);
+#else
+ snprintf(s, sizeof(s)-1, "%u|%s|%s|%s|%s/%s", (unsigned)pf->type, pf->mime_type, pf->description, res, prefix, pf->path);
+#endif
+
+ printf("testing grabbag__picture_parse_specification(\"%s\")... ", s);
+ if(0 == (obj = grabbag__picture_parse_specification(s, &error)))
+ return failed_(error);
+ if(debug_) {
+ printf("\ntype=%u (%s)\nmime_type=%s\ndescription=%s\nwidth=%u\nheight=%u\ndepth=%u\ncolors=%u\ndata_length=%u\n",
+ obj->data.picture.type,
+ obj->data.picture.type < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED?
+ FLAC__StreamMetadata_Picture_TypeString[obj->data.picture.type] : "UNDEFINED",
+ obj->data.picture.mime_type,
+ obj->data.picture.description,
+ obj->data.picture.width,
+ obj->data.picture.height,
+ obj->data.picture.depth,
+ obj->data.picture.colors,
+ obj->data.picture.data_length
+ );
+ }
+ if(obj->data.picture.type != (fn_only? FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER : pf->type))
+ return failed_("picture type mismatch");
+ if(strcmp(obj->data.picture.mime_type, pf->mime_type))
+ return failed_("picture MIME type mismatch");
+ if(strcmp((const char *)obj->data.picture.description, (const char *)pf->description))
+ return failed_("picture description mismatch");
+ if(obj->data.picture.width != pf->width)
+ return failed_("picture width mismatch");
+ if(obj->data.picture.height != pf->height)
+ return failed_("picture height mismatch");
+ if(obj->data.picture.depth != pf->depth)
+ return failed_("picture depth mismatch");
+ if(obj->data.picture.colors != pf->colors)
+ return failed_("picture colors mismatch");
+ printf("OK\n");
+ FLAC__metadata_object_delete(obj);
+ return true;
+}
+
+static FLAC__bool do_picture(const char *prefix)
+{
+ FLAC__StreamMetadata *obj;
+ const char *error;
+ size_t i;
+
+ printf("\n+++ grabbag unit test: picture\n\n");
+
+ /* invalid spec: no filename */
+ printf("testing grabbag__picture_parse_specification(\"\")... ");
+ if(0 != (obj = grabbag__picture_parse_specification("", &error)))
+ return failed_("expected error, got object");
+ printf("OK (failed as expected, error: %s)\n", error);
+
+ /* invalid spec: no filename */
+ printf("testing grabbag__picture_parse_specification(\"||||\")... ");
+ if(0 != (obj = grabbag__picture_parse_specification("||||", &error)))
+ return failed_("expected error, got object");
+ printf("OK (failed as expected: %s)\n", error);
+
+ /* invalid spec: no filename */
+ printf("testing grabbag__picture_parse_specification(\"|image/gif|||\")... ");
+ if(0 != (obj = grabbag__picture_parse_specification("|image/gif|||", &error)))
+ return failed_("expected error, got object");
+ printf("OK (failed as expected: %s)\n", error);
+
+ /* invalid spec: bad resolution */
+ printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320|0.gif\")... ");
+ if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320|0.gif", &error)))
+ return failed_("expected error, got object");
+ printf("OK (failed as expected: %s)\n", error);
+
+ /* invalid spec: bad resolution */
+ printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240|0.gif\")... ");
+ if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240|0.gif", &error)))
+ return failed_("expected error, got object");
+ printf("OK (failed as expected: %s)\n", error);
+
+ /* invalid spec: no filename */
+ printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240x9|\")... ");
+ if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240x9|", &error)))
+ return failed_("expected error, got object");
+ printf("OK (failed as expected: %s)\n", error);
+
+ /* invalid spec: #colors exceeds color depth */
+ printf("testing grabbag__picture_parse_specification(\"|image/gif|desc|320x240x9/2345|0.gif\")... ");
+ if(0 != (obj = grabbag__picture_parse_specification("|image/gif|desc|320x240x9/2345|0.gif", &error)))
+ return failed_("expected error, got object");
+ printf("OK (failed as expected: %s)\n", error);
+
+ /* invalid spec: standard icon has to be 32x32 PNG */
+ printf("testing grabbag__picture_parse_specification(\"1|-->|desc|32x24x9|0.gif\")... ");
+ if(0 != (obj = grabbag__picture_parse_specification("1|-->|desc|32x24x9|0.gif", &error)))
+ return failed_("expected error, got object");
+ printf("OK (failed as expected: %s)\n", error);
+
+ /* invalid spec: need resolution for linked URL */
+ printf("testing grabbag__picture_parse_specification(\"|-->|desc||http://blah.blah.blah/z.gif\")... ");
+ if(0 != (obj = grabbag__picture_parse_specification("|-->|desc||http://blah.blah.blah/z.gif", &error)))
+ return failed_("expected error, got object");
+ printf("OK (failed as expected: %s)\n", error);
+
+ printf("testing grabbag__picture_parse_specification(\"|-->|desc|320x240x9|http://blah.blah.blah/z.gif\")... ");
+ if(0 == (obj = grabbag__picture_parse_specification("|-->|desc|320x240x9|http://blah.blah.blah/z.gif", &error)))
+ return failed_(error);
+ printf("OK\n");
+ FLAC__metadata_object_delete(obj);
+
+ /* test automatic parsing of picture files from only the file name */
+ for(i = 0; i < sizeof(picturefiles)/sizeof(picturefiles[0]); i++)
+ if(!test_one_picture(prefix, picturefiles+i, "", /*fn_only=*/true))
+ return false;
+
+ /* test automatic parsing of picture files to get resolution/color info */
+ for(i = 0; i < sizeof(picturefiles)/sizeof(picturefiles[0]); i++)
+ if(!test_one_picture(prefix, picturefiles+i, "", /*fn_only=*/false))
+ return false;
+
+ picturefiles[0].width = 320;
+ picturefiles[0].height = 240;
+ picturefiles[0].depth = 3;
+ picturefiles[0].colors = 2;
+ if(!test_one_picture(prefix, picturefiles+0, "320x240x3/2", /*fn_only=*/false))
+ return false;
+
+ return true;
+}
+
+int main(int argc, char *argv[])
+{
+ const char *usage = "usage: test_pictures path_prefix\n";
+
+ if(argc > 1 && 0 == strcmp(argv[1], "-h")) {
+ printf(usage);
+ return 0;
+ }
+
+ if(argc != 2) {
+ fprintf(stderr, usage);
+ return 255;
+ }
+
+ return do_picture(argv[1])? 0 : 1;
+}
diff --git a/src/FLAC/src/test_libFLAC/Makefile.am b/src/FLAC/src/test_libFLAC/Makefile.am
new file mode 100644
index 0000000..62f0342
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/Makefile.am
@@ -0,0 +1,42 @@
+# test_libFLAC - Unit tester for libFLAC
+# Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+INCLUDES = -I$(top_srcdir)/src/FLAC/src/libFLAC/include -I$(top_srcdir)/src/FLAC/include
+
+noinst_PROGRAMS = test_libFLAC
+test_libFLAC_LDADD = \
+ $(top_builddir)/src/FLAC/src/share/grabbag/libgrabbag.la \
+ $(top_builddir)/src/FLAC/src/share/replaygain_anal/libreplaygain_analysis.la \
+ $(top_builddir)/src/FLAC/src/test_libs_common/libtest_libs_common.la \
+ $(top_builddir)/src/FLAC/src/libFLAC/libFLAC.la \
+ $(top_builddir)/src/OGG/libogg.la \
+ -lm
+
+test_libFLAC_SOURCES = \
+ bitwriter.c \
+ decoders.c \
+ encoders.c \
+ format.c \
+ main.c \
+ metadata.c \
+ metadata_manip.c \
+ metadata_object.c \
+ bitwriter.h \
+ decoders.h \
+ encoders.h \
+ format.h \
+ metadata.h
diff --git a/src/FLAC/src/test_libFLAC/bitwriter.c b/src/FLAC/src/test_libFLAC/bitwriter.c
new file mode 100644
index 0000000..7bc23a8
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/bitwriter.c
@@ -0,0 +1,584 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "private/bitwriter.h" /* from the libFLAC private include area */
+#include "bitwriter.h"
+#include <stdio.h>
+#include <string.h> /* for memcmp() */
+
+/* adjust for compilers that can't understand using LLU suffix for uint64_t literals */
+#ifdef _MSC_VER
+#define FLAC__U64L(x) x
+#else
+#define FLAC__U64L(x) x##LLU
+#endif
+
+/*
+ * WATCHOUT! Since FLAC__BitWriter is a private structure, we use a copy of
+ * the definition here to get at the internals. Make sure this is kept up
+ * to date with what is in ../libFLAC/bitwriter.c
+ */
+typedef FLAC__uint32 bwword;
+
+struct FLAC__BitWriter {
+ bwword *buffer;
+ bwword accum; /* accumulator; when full, accum is appended to buffer */
+ unsigned capacity; /* of buffer in words */
+ unsigned words; /* # of complete words in buffer */
+ unsigned bits; /* # of used bits in accum */
+};
+
+#define TOTAL_BITS(bw) ((bw)->words*sizeof(bwword)*8 + (bw)->bits)
+
+
+FLAC__bool test_bitwriter(void)
+{
+ FLAC__BitWriter *bw;
+ FLAC__bool ok;
+ unsigned i, j;
+#if WORDS_BIGENDIAN
+ static bwword test_pattern1[5] = { 0xaaf0aabe, 0xaaaaaaa8, 0x300aaaaa, 0xaaadeadb, 0x00eeface };
+#else
+ static bwword test_pattern1[5] = { 0xbeaaf0aa, 0xa8aaaaaa, 0xaaaa0a30, 0xdbeaadaa, 0x00eeface };
+#endif
+ unsigned words, bits; /* what we think bw->words and bw->bits should be */
+
+ printf("\n+++ libFLAC unit test: bitwriter\n\n");
+
+ /*
+ * test new -> delete
+ */
+ printf("testing new... ");
+ bw = FLAC__bitwriter_new();
+ if(0 == bw) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing delete... ");
+ FLAC__bitwriter_delete(bw);
+ printf("OK\n");
+
+ /*
+ * test new -> init -> delete
+ */
+ printf("testing new... ");
+ bw = FLAC__bitwriter_new();
+ if(0 == bw) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing init... ");
+ FLAC__bitwriter_init(bw);
+ if(0 == bw) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing delete... ");
+ FLAC__bitwriter_delete(bw);
+ printf("OK\n");
+
+ /*
+ * test new -> init -> clear -> delete
+ */
+ printf("testing new... ");
+ bw = FLAC__bitwriter_new();
+ if(0 == bw) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing init... ");
+ FLAC__bitwriter_init(bw);
+ if(0 == bw) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing clear... ");
+ FLAC__bitwriter_clear(bw);
+ if(0 == bw) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing delete... ");
+ FLAC__bitwriter_delete(bw);
+ printf("OK\n");
+
+ /*
+ * test normal usage
+ */
+ printf("testing new... ");
+ bw = FLAC__bitwriter_new();
+ if(0 == bw) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing init... ");
+ ok = FLAC__bitwriter_init(bw);
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok)
+ return false;
+
+ printf("testing clear... ");
+ FLAC__bitwriter_clear(bw);
+ printf("OK\n");
+
+ words = bits = 0;
+
+ printf("capacity = %u\n", bw->capacity);
+
+ printf("testing zeroes, raw_uint32*... ");
+ ok =
+ FLAC__bitwriter_write_raw_uint32(bw, 0x1, 1) &&
+ FLAC__bitwriter_write_raw_uint32(bw, 0x1, 2) &&
+ FLAC__bitwriter_write_raw_uint32(bw, 0xa, 5) &&
+ FLAC__bitwriter_write_raw_uint32(bw, 0xf0, 8) &&
+ FLAC__bitwriter_write_raw_uint32(bw, 0x2aa, 10) &&
+ FLAC__bitwriter_write_raw_uint32(bw, 0xf, 4) &&
+ FLAC__bitwriter_write_raw_uint32(bw, 0xaaaaaaaa, 32) &&
+ FLAC__bitwriter_write_zeroes(bw, 4) &&
+ FLAC__bitwriter_write_raw_uint32(bw, 0x3, 2) &&
+ FLAC__bitwriter_write_zeroes(bw, 8) &&
+ FLAC__bitwriter_write_raw_uint64(bw, FLAC__U64L(0xaaaaaaaadeadbeef), 64) &&
+ FLAC__bitwriter_write_raw_uint32(bw, 0xace, 12)
+ ;
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ words = 4;
+ bits = 24;
+ if(bw->words != words) {
+ printf("FAILED byte count %u != %u\n", bw->words, words);
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ if(bw->bits != bits) {
+ printf("FAILED bit count %u != %u\n", bw->bits, bits);
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ if(memcmp(bw->buffer, test_pattern1, sizeof(bwword)*words) != 0) {
+ printf("FAILED pattern match (buffer)\n");
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ if((bw->accum & 0x00ffffff) != test_pattern1[words]) {
+ printf("FAILED pattern match (bw->accum=%08X != %08X)\n", bw->accum&0x00ffffff, test_pattern1[words]);
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ printf("OK\n");
+ FLAC__bitwriter_dump(bw, stdout);
+
+ printf("testing raw_uint32 some more... ");
+ ok = FLAC__bitwriter_write_raw_uint32(bw, 0x3d, 6);
+ if(!ok) {
+ printf("FAILED\n");
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ bits += 6;
+ test_pattern1[words] <<= 6;
+ test_pattern1[words] |= 0x3d;
+ if(bw->words != words) {
+ printf("FAILED byte count %u != %u\n", bw->words, words);
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ if(bw->bits != bits) {
+ printf("FAILED bit count %u != %u\n", bw->bits, bits);
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ if(memcmp(bw->buffer, test_pattern1, sizeof(bwword)*words) != 0) {
+ printf("FAILED pattern match (buffer)\n");
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ if((bw->accum & 0x3fffffff) != test_pattern1[words]) {
+ printf("FAILED pattern match (bw->accum=%08X != %08X)\n", bw->accum&0x3fffffff, test_pattern1[words]);
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ printf("OK\n");
+ FLAC__bitwriter_dump(bw, stdout);
+
+ printf("testing utf8_uint32(0x00000000)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x00000000);
+ ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x0000007F)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x0000007F);
+ ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0x7F;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x00000080)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x00000080);
+ ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xC280;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x000007FF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x000007FF);
+ ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xDFBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x00000800)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x00000800);
+ ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xE0A080;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x0000FFFF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x0000FFFF);
+ ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xEFBFBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x00010000)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x00010000);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF0908080;
+#else
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0x808090F0;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x001FFFFF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x001FFFFF);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF7BFBFBF;
+#else
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xBFBFBFF7;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x00200000)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x00200000);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xF8888080 && (bw->accum & 0xff) == 0x80;
+#else
+ ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0x808088F8 && (bw->accum & 0xff) == 0x80;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x03FFFFFF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x03FFFFFF);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xFBBFBFBF && (bw->accum & 0xff) == 0xBF;
+#else
+ ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xBFBFBFFB && (bw->accum & 0xff) == 0xBF;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x04000000)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x04000000);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFC848080 && (bw->accum & 0xffff) == 0x8080;
+#else
+ ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0x808084FC && (bw->accum & 0xffff) == 0x8080;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint32(0x7FFFFFFF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint32(bw, 0x7FFFFFFF);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFDBFBFBF && (bw->accum & 0xffff) == 0xBFBF;
+#else
+ ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xBFBFBFFD && (bw->accum & 0xffff) == 0xBFBF;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x0000000000000000)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000000000000);
+ ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x000000000000007F)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x000000000000007F);
+ ok = TOTAL_BITS(bw) == 8 && (bw->accum & 0xff) == 0x7F;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x0000000000000080)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000000000080);
+ ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xC280;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x00000000000007FF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x00000000000007FF);
+ ok = TOTAL_BITS(bw) == 16 && (bw->accum & 0xffff) == 0xDFBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x0000000000000800)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000000000800);
+ ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xE0A080;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x000000000000FFFF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x000000000000FFFF);
+ ok = TOTAL_BITS(bw) == 24 && (bw->accum & 0xffffff) == 0xEFBFBF;
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x0000000000010000)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000000010000);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF0908080;
+#else
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0x808090F0;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x00000000001FFFFF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x00000000001FFFFF);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xF7BFBFBF;
+#else
+ ok = TOTAL_BITS(bw) == 32 && bw->buffer[0] == 0xBFBFBFF7;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x0000000000200000)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000000200000);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xF8888080 && (bw->accum & 0xff) == 0x80;
+#else
+ ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0x808088F8 && (bw->accum & 0xff) == 0x80;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x0000000003FFFFFF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000003FFFFFF);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xFBBFBFBF && (bw->accum & 0xff) == 0xBF;
+#else
+ ok = TOTAL_BITS(bw) == 40 && bw->buffer[0] == 0xBFBFBFFB && (bw->accum & 0xff) == 0xBF;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x0000000004000000)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000004000000);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFC848080 && (bw->accum & 0xffff) == 0x8080;
+#else
+ ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0x808084FC && (bw->accum & 0xffff) == 0x8080;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x000000007FFFFFFF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x000000007FFFFFFF);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xFDBFBFBF && (bw->accum & 0xffff) == 0xBFBF;
+#else
+ ok = TOTAL_BITS(bw) == 48 && bw->buffer[0] == 0xBFBFBFFD && (bw->accum & 0xffff) == 0xBFBF;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x0000000080000000)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, 0x0000000080000000);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xFE828080 && (bw->accum & 0xffffff) == 0x808080;
+#else
+ ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0x808082FE && (bw->accum & 0xffffff) == 0x808080;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing utf8_uint64(0x0000000FFFFFFFFF)... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_utf8_uint64(bw, FLAC__U64L(0x0000000FFFFFFFFF));
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xFEBFBFBF && (bw->accum & 0xffffff) == 0xBFBFBF;
+#else
+ ok = TOTAL_BITS(bw) == 56 && bw->buffer[0] == 0xBFBFBFFE && (bw->accum & 0xffffff) == 0xBFBFBF;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+
+ printf("testing grow... ");
+ FLAC__bitwriter_clear(bw);
+ FLAC__bitwriter_write_raw_uint32(bw, 0x5, 4);
+ j = bw->capacity;
+ for(i = 0; i < j; i++)
+ FLAC__bitwriter_write_raw_uint32(bw, 0xaaaaaaaa, 32);
+#if WORDS_BIGENDIAN
+ ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == 0x5aaaaaaa && (bw->accum & 0xf) == 0xa;
+#else
+ ok = TOTAL_BITS(bw) == i*32+4 && bw->buffer[0] == 0xaaaaaa5a && (bw->accum & 0xf) == 0xa;
+#endif
+ printf("%s\n", ok?"OK":"FAILED");
+ if(!ok) {
+ FLAC__bitwriter_dump(bw, stdout);
+ return false;
+ }
+ printf("capacity = %u\n", bw->capacity);
+
+ printf("testing free... ");
+ FLAC__bitwriter_free(bw);
+ printf("OK\n");
+
+ printf("testing delete... ");
+ FLAC__bitwriter_delete(bw);
+ printf("OK\n");
+
+ printf("\nPASSED!\n");
+ return true;
+}
diff --git a/src/FLAC/src/test_libFLAC/bitwriter.h b/src/FLAC/src/test_libFLAC/bitwriter.h
new file mode 100644
index 0000000..44b6ade
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/bitwriter.h
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_BITBUFFER_H
+#define FLAC__TEST_LIBFLAC_BITBUFFER_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_bitwriter(void);
+
+#endif
diff --git a/src/FLAC/src/test_libFLAC/decoders.c b/src/FLAC/src/test_libFLAC/decoders.c
new file mode 100644
index 0000000..9e77cac
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/decoders.c
@@ -0,0 +1,1048 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#if _MSC_VER <= 1600 /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#endif
+#include "decoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "share/grabbag.h"
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+
+typedef enum {
+ LAYER_STREAM = 0, /* FLAC__stream_decoder_init_[ogg_]stream() without seeking */
+ LAYER_SEEKABLE_STREAM, /* FLAC__stream_decoder_init_[ogg_]stream() with seeking */
+ LAYER_FILE, /* FLAC__stream_decoder_init_[ogg_]FILE() */
+ LAYER_FILENAME /* FLAC__stream_decoder_init_[ogg_]file() */
+} Layer;
+
+static const char * const LayerString[] = {
+ "Stream",
+ "Seekable Stream",
+ "FILE*",
+ "Filename"
+};
+
+typedef struct {
+ Layer layer;
+ FILE *file;
+ unsigned current_metadata_number;
+ FLAC__bool ignore_errors;
+ FLAC__bool error_occurred;
+} StreamDecoderClientData;
+
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *expected_metadata_sequence_[9];
+static unsigned num_expected_;
+static off_t flacfilesize_;
+
+static const char *flacfilename(FLAC__bool is_ogg)
+{
+ return is_ogg? "metadata.ogg" : "metadata.flac";
+}
+
+static FLAC__bool die_(const char *msg)
+{
+ printf("ERROR: %s\n", msg);
+ return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder)
+{
+ FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder);
+
+ if(msg)
+ printf("FAILED, %s", msg);
+ else
+ printf("FAILED");
+
+ printf(", state = %u (%s)\n", (unsigned)state, FLAC__StreamDecoderStateString[state]);
+
+ return false;
+}
+
+static void init_metadata_blocks_(void)
+{
+ mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_(void)
+{
+ mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static FLAC__bool generate_file_(FLAC__bool is_ogg)
+{
+ printf("\n\ngenerating %sFLAC file for decoder tests...\n", is_ogg? "Ogg ":"");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ /* WATCHOUT: for Ogg FLAC the encoder should move the VORBIS_COMMENT block to the front, right after STREAMINFO */
+
+ if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), &flacfilesize_, 512 * 1024, &streaminfo_, expected_metadata_sequence_, num_expected_))
+ return die_("creating the encoded file");
+
+ return true;
+}
+
+static FLAC__StreamDecoderReadStatus stream_decoder_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+ const size_t requested_bytes = *bytes;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in read callback is NULL\n");
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+
+ if(feof(dcd->file)) {
+ *bytes = 0;
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ }
+ else if(requested_bytes > 0) {
+ *bytes = fread(buffer, 1, requested_bytes, dcd->file);
+ if(*bytes == 0) {
+ if(feof(dcd->file))
+ return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ }
+ else {
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+ }
+ else
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */
+}
+
+static FLAC__StreamDecoderSeekStatus stream_decoder_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in seek callback is NULL\n");
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+
+ if(fseeko(dcd->file, (off_t)absolute_byte_offset, SEEK_SET) < 0) {
+ dcd->error_occurred = true;
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ }
+
+ return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+
+static FLAC__StreamDecoderTellStatus stream_decoder_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+ off_t offset;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in tell callback is NULL\n");
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+
+ offset = ftello(dcd->file);
+ *absolute_byte_offset = (FLAC__uint64)offset;
+
+ if(offset < 0) {
+ dcd->error_occurred = true;
+ return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
+ }
+
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+
+static FLAC__StreamDecoderLengthStatus stream_decoder_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in length callback is NULL\n");
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
+
+ *stream_length = (FLAC__uint64)flacfilesize_;
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+
+static FLAC__bool stream_decoder_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in eof callback is NULL\n");
+ return true;
+ }
+
+ if(dcd->error_occurred)
+ return true;
+
+ return feof(dcd->file);
+}
+
+static FLAC__StreamDecoderWriteStatus stream_decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder, (void)buffer;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in write callback is NULL\n");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+ if(
+ (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
+ (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
+ ) {
+ printf("content... ");
+ fflush(stdout);
+ }
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void stream_decoder_metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in metadata callback is NULL\n");
+ return;
+ }
+
+ if(dcd->error_occurred)
+ return;
+
+ printf("%d... ", dcd->current_metadata_number);
+ fflush(stdout);
+
+ if(dcd->current_metadata_number >= num_expected_) {
+ (void)die_("got more metadata blocks than expected");
+ dcd->error_occurred = true;
+ }
+ else {
+ if(!mutils__compare_block(expected_metadata_sequence_[dcd->current_metadata_number], metadata)) {
+ (void)die_("metadata block mismatch");
+ dcd->error_occurred = true;
+ }
+ }
+ dcd->current_metadata_number++;
+}
+
+static void stream_decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ StreamDecoderClientData *dcd = (StreamDecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in error callback is NULL\n");
+ return;
+ }
+
+ if(!dcd->ignore_errors) {
+ printf("ERROR: got error callback: err = %u (%s)\n", (unsigned)status, FLAC__StreamDecoderErrorStatusString[status]);
+ dcd->error_occurred = true;
+ }
+}
+
+static FLAC__bool stream_decoder_test_respond_(FLAC__StreamDecoder *decoder, StreamDecoderClientData *dcd, FLAC__bool is_ogg)
+{
+ FLAC__StreamDecoderInitStatus init_status;
+
+ if(!FLAC__stream_decoder_set_md5_checking(decoder, true))
+ return die_s_("at FLAC__stream_decoder_set_md5_checking(), returned false", decoder);
+
+ /* for FLAC__stream_encoder_init_FILE(), the FLAC__stream_encoder_finish() closes the file so we have to keep re-opening: */
+ if(dcd->layer == LAYER_FILE) {
+ printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+ dcd->file = fopen(flacfilename(is_ogg), "rb");
+ if(0 == dcd->file) {
+ printf("ERROR (%s)\n", strerror(errno));
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ switch(dcd->layer) {
+ case LAYER_STREAM:
+ printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+ FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd)
+ ;
+ break;
+ case LAYER_SEEKABLE_STREAM:
+ printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+ FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+ break;
+ case LAYER_FILE:
+ printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+ FLAC__stream_decoder_init_FILE(decoder, dcd->file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+ break;
+ case LAYER_FILENAME:
+ printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd) :
+ FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, dcd);
+ break;
+ default:
+ die_("internal error 000");
+ return false;
+ }
+ if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+ return die_s_(0, decoder);
+ printf("OK\n");
+
+ dcd->current_metadata_number = 0;
+
+ if(dcd->layer < LAYER_FILE && fseeko(dcd->file, 0, SEEK_SET) < 0) {
+ printf("FAILED rewinding input, errno = %d\n", errno);
+ return false;
+ }
+
+ printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+ if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_finish()... ");
+ if(!FLAC__stream_decoder_finish(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ return true;
+}
+
+static FLAC__bool test_stream_decoder(Layer layer, FLAC__bool is_ogg)
+{
+ FLAC__StreamDecoder *decoder;
+ FLAC__StreamDecoderInitStatus init_status;
+ FLAC__StreamDecoderState state;
+ StreamDecoderClientData decoder_client_data;
+ FLAC__bool expect;
+
+ decoder_client_data.layer = layer;
+
+ printf("\n+++ libFLAC unit test: FLAC__StreamDecoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC" : "FLAC");
+
+ printf("testing FLAC__stream_decoder_new()... ");
+ decoder = FLAC__stream_decoder_new();
+ if(0 == decoder) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_delete()... ");
+ FLAC__stream_decoder_delete(decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_new()... ");
+ decoder = FLAC__stream_decoder_new();
+ if(0 == decoder) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ switch(layer) {
+ case LAYER_STREAM:
+ case LAYER_SEEKABLE_STREAM:
+ printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0) :
+ FLAC__stream_decoder_init_stream(decoder, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ break;
+ case LAYER_FILE:
+ printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_FILE(decoder, stdin, 0, 0, 0, 0) :
+ FLAC__stream_decoder_init_FILE(decoder, stdin, 0, 0, 0, 0);
+ break;
+ case LAYER_FILENAME:
+ printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0) :
+ FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), 0, 0, 0, 0);
+ break;
+ default:
+ die_("internal error 003");
+ return false;
+ }
+ if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS)
+ return die_s_(0, decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_delete()... ");
+ FLAC__stream_decoder_delete(decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+
+ printf("testing FLAC__stream_decoder_new()... ");
+ decoder = FLAC__stream_decoder_new();
+ if(0 == decoder) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ if(is_ogg) {
+ printf("testing FLAC__stream_decoder_set_ogg_serial_number()... ");
+ if(!FLAC__stream_decoder_set_ogg_serial_number(decoder, file_utils__ogg_serial_number))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+ }
+
+ printf("testing FLAC__stream_decoder_set_md5_checking()... ");
+ if(!FLAC__stream_decoder_set_md5_checking(decoder, true))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ if(layer < LAYER_FILENAME) {
+ printf("opening %sFLAC file... ", is_ogg? "Ogg ":"");
+ decoder_client_data.file = fopen(flacfilename(is_ogg), "rb");
+ if(0 == decoder_client_data.file) {
+ printf("ERROR (%s)\n", strerror(errno));
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ switch(layer) {
+ case LAYER_STREAM:
+ printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+ FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, /*seek_callback=*/0, /*tell_callback=*/0, /*length_callback=*/0, /*eof_callback=*/0, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+ break;
+ case LAYER_SEEKABLE_STREAM:
+ printf("testing FLAC__stream_decoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+ FLAC__stream_decoder_init_stream(decoder, stream_decoder_read_callback_, stream_decoder_seek_callback_, stream_decoder_tell_callback_, stream_decoder_length_callback_, stream_decoder_eof_callback_, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+ break;
+ case LAYER_FILE:
+ printf("testing FLAC__stream_decoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+ FLAC__stream_decoder_init_FILE(decoder, decoder_client_data.file, stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+ break;
+ case LAYER_FILENAME:
+ printf("testing FLAC__stream_decoder_init_%sfile()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_decoder_init_ogg_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data) :
+ FLAC__stream_decoder_init_file(decoder, flacfilename(is_ogg), stream_decoder_write_callback_, stream_decoder_metadata_callback_, stream_decoder_error_callback_, &decoder_client_data);
+ break;
+ default:
+ die_("internal error 009");
+ return false;
+ }
+ if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+ return die_s_(0, decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_get_state()... ");
+ state = FLAC__stream_decoder_get_state(decoder);
+ printf("returned state = %u (%s)... OK\n", state, FLAC__StreamDecoderStateString[state]);
+
+ decoder_client_data.current_metadata_number = 0;
+ decoder_client_data.ignore_errors = false;
+ decoder_client_data.error_occurred = false;
+
+ printf("testing FLAC__stream_decoder_get_md5_checking()... ");
+ if(!FLAC__stream_decoder_get_md5_checking(decoder)) {
+ printf("FAILED, returned false, expected true\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_process_until_end_of_metadata()... ");
+ if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_process_single()... ");
+ if(!FLAC__stream_decoder_process_single(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_skip_single_frame()... ");
+ if(!FLAC__stream_decoder_skip_single_frame(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ if(layer < LAYER_FILE) {
+ printf("testing FLAC__stream_decoder_flush()... ");
+ if(!FLAC__stream_decoder_flush(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ decoder_client_data.ignore_errors = true;
+ printf("testing FLAC__stream_decoder_process_single()... ");
+ if(!FLAC__stream_decoder_process_single(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+ decoder_client_data.ignore_errors = false;
+ }
+
+ expect = (layer != LAYER_STREAM);
+ printf("testing FLAC__stream_decoder_seek_absolute()... ");
+ if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect)
+ return die_s_(expect? "returned false" : "returned true", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+ if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ expect = (layer != LAYER_STREAM);
+ printf("testing FLAC__stream_decoder_seek_absolute()... ");
+ if(FLAC__stream_decoder_seek_absolute(decoder, 0) != expect)
+ return die_s_(expect? "returned false" : "returned true", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_get_channels()... ");
+ {
+ unsigned channels = FLAC__stream_decoder_get_channels(decoder);
+ if(channels != streaminfo_.data.stream_info.channels) {
+ printf("FAILED, returned %u, expected %u\n", channels, streaminfo_.data.stream_info.channels);
+ return false;
+ }
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_get_bits_per_sample()... ");
+ {
+ unsigned bits_per_sample = FLAC__stream_decoder_get_bits_per_sample(decoder);
+ if(bits_per_sample != streaminfo_.data.stream_info.bits_per_sample) {
+ printf("FAILED, returned %u, expected %u\n", bits_per_sample, streaminfo_.data.stream_info.bits_per_sample);
+ return false;
+ }
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_get_sample_rate()... ");
+ {
+ unsigned sample_rate = FLAC__stream_decoder_get_sample_rate(decoder);
+ if(sample_rate != streaminfo_.data.stream_info.sample_rate) {
+ printf("FAILED, returned %u, expected %u\n", sample_rate, streaminfo_.data.stream_info.sample_rate);
+ return false;
+ }
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_get_blocksize()... ");
+ {
+ unsigned blocksize = FLAC__stream_decoder_get_blocksize(decoder);
+ /* value could be anything since we're at the last block, so accept any reasonable answer */
+ printf("returned %u... %s\n", blocksize, blocksize>0? "OK" : "FAILED");
+ if(blocksize == 0)
+ return false;
+ }
+
+ printf("testing FLAC__stream_decoder_get_channel_assignment()... ");
+ {
+ FLAC__ChannelAssignment ca = FLAC__stream_decoder_get_channel_assignment(decoder);
+ printf("returned %u (%s)... OK\n", (unsigned)ca, FLAC__ChannelAssignmentString[ca]);
+ }
+
+ if(layer < LAYER_FILE) {
+ printf("testing FLAC__stream_decoder_reset()... ");
+ if(!FLAC__stream_decoder_reset(decoder)) {
+ state = FLAC__stream_decoder_get_state(decoder);
+ printf("FAILED, returned false, state = %u (%s)\n", state, FLAC__StreamDecoderStateString[state]);
+ return false;
+ }
+ printf("OK\n");
+
+ if(layer == LAYER_STREAM) {
+ /* after a reset() we have to rewind the input ourselves */
+ printf("rewinding input... ");
+ if(fseeko(decoder_client_data.file, 0, SEEK_SET) < 0) {
+ printf("FAILED, errno = %d\n", errno);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ decoder_client_data.current_metadata_number = 0;
+
+ printf("testing FLAC__stream_decoder_process_until_end_of_stream()... ");
+ if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+ }
+
+ printf("testing FLAC__stream_decoder_finish()... ");
+ if(!FLAC__stream_decoder_finish(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ /*
+ * respond all
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * respond all, ignore VORBIS_COMMENT
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore(VORBIS_COMMENT)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * respond all, ignore APPLICATION
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * respond all, ignore APPLICATION id of app#1
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * respond all, ignore APPLICATION id of app#1 & app#2
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #2)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application2_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all, respond VORBIS_COMMENT
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond(VORBIS_COMMENT)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all, respond APPLICATION
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all, respond APPLICATION id of app#1
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all, respond APPLICATION id of app#1 & app#2
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #2)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application2_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * respond all, ignore APPLICATION, respond APPLICATION id of app#1
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore(APPLICATION)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore(decoder, FLAC__METADATA_TYPE_APPLICATION))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ if(is_ogg) { /* encoder moves vorbis comment after streaminfo according to ogg mapping */
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+ else {
+ expected_metadata_sequence_[num_expected_++] = &streaminfo_;
+ expected_metadata_sequence_[num_expected_++] = &padding_;
+ expected_metadata_sequence_[num_expected_++] = &seektable_;
+ expected_metadata_sequence_[num_expected_++] = &application1_;
+ expected_metadata_sequence_[num_expected_++] = &vorbiscomment_;
+ expected_metadata_sequence_[num_expected_++] = &cuesheet_;
+ expected_metadata_sequence_[num_expected_++] = &picture_;
+ expected_metadata_sequence_[num_expected_++] = &unknown_;
+ }
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ /*
+ * ignore all, respond APPLICATION, ignore APPLICATION id of app#1
+ */
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_all()... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_all(decoder))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_respond(APPLICATION)... ");
+ if(!FLAC__stream_decoder_set_metadata_respond(decoder, FLAC__METADATA_TYPE_APPLICATION))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_decoder_set_metadata_ignore_application(of app block #1)... ");
+ if(!FLAC__stream_decoder_set_metadata_ignore_application(decoder, application1_.data.application.id))
+ return die_s_("returned false", decoder);
+ printf("OK\n");
+
+ num_expected_ = 0;
+ expected_metadata_sequence_[num_expected_++] = &application2_;
+
+ if(!stream_decoder_test_respond_(decoder, &decoder_client_data, is_ogg))
+ return false;
+
+ if(layer < LAYER_FILE) /* for LAYER_FILE, FLAC__stream_decoder_finish() closes the file */
+ fclose(decoder_client_data.file);
+
+ printf("testing FLAC__stream_decoder_delete()... ");
+ FLAC__stream_decoder_delete(decoder);
+ printf("OK\n");
+
+ printf("\nPASSED!\n");
+
+ return true;
+}
+
+FLAC__bool test_decoders(void)
+{
+ FLAC__bool is_ogg = false;
+
+ while(1) {
+ init_metadata_blocks_();
+
+ if(!generate_file_(is_ogg))
+ return false;
+
+ if(!test_stream_decoder(LAYER_STREAM, is_ogg))
+ return false;
+
+ if(!test_stream_decoder(LAYER_SEEKABLE_STREAM, is_ogg))
+ return false;
+
+ if(!test_stream_decoder(LAYER_FILE, is_ogg))
+ return false;
+
+ if(!test_stream_decoder(LAYER_FILENAME, is_ogg))
+ return false;
+
+ (void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+ free_metadata_blocks_();
+
+ if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+ break;
+ is_ogg = true;
+ }
+
+ return true;
+}
diff --git a/src/FLAC/src/test_libFLAC/decoders.h b/src/FLAC/src/test_libFLAC/decoders.h
new file mode 100644
index 0000000..11df106
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/decoders.h
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_DECODERS_H
+#define FLAC__TEST_LIBFLAC_DECODERS_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_decoders(void);
+
+#endif
diff --git a/src/FLAC/src/test_libFLAC/encoders.c b/src/FLAC/src/test_libFLAC/encoders.c
new file mode 100644
index 0000000..c1de7ba
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/encoders.c
@@ -0,0 +1,521 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "encoders.h"
+#include "FLAC/assert.h"
+#include "FLAC/stream_encoder.h"
+#include "share/grabbag.h"
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+
+typedef enum {
+ LAYER_STREAM = 0, /* FLAC__stream_encoder_init_[ogg_]stream() without seeking */
+ LAYER_SEEKABLE_STREAM, /* FLAC__stream_encoder_init_[ogg_]stream() with seeking */
+ LAYER_FILE, /* FLAC__stream_encoder_init_[ogg_]FILE() */
+ LAYER_FILENAME /* FLAC__stream_encoder_init_[ogg_]file() */
+} Layer;
+
+static const char * const LayerString[] = {
+ "Stream",
+ "Seekable Stream",
+ "FILE*",
+ "Filename"
+};
+
+static FLAC__StreamMetadata streaminfo_, padding_, seektable_, application1_, application2_, vorbiscomment_, cuesheet_, picture_, unknown_;
+static FLAC__StreamMetadata *metadata_sequence_[] = { &vorbiscomment_, &padding_, &seektable_, &application1_, &application2_, &cuesheet_, &picture_, &unknown_ };
+static const unsigned num_metadata_ = sizeof(metadata_sequence_) / sizeof(metadata_sequence_[0]);
+
+static const char *flacfilename(FLAC__bool is_ogg)
+{
+ return is_ogg? "metadata.ogg" : "metadata.flac";
+}
+
+static FLAC__bool die_(const char *msg)
+{
+ printf("ERROR: %s\n", msg);
+ return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC__StreamEncoder *encoder)
+{
+ FLAC__StreamEncoderState state = FLAC__stream_encoder_get_state(encoder);
+
+ if(msg)
+ printf("FAILED, %s", msg);
+ else
+ printf("FAILED");
+
+ printf(", state = %u (%s)\n", (unsigned)state, FLAC__StreamEncoderStateString[state]);
+ if(state == FLAC__STREAM_ENCODER_VERIFY_DECODER_ERROR) {
+ FLAC__StreamDecoderState dstate = FLAC__stream_encoder_get_verify_decoder_state(encoder);
+ printf(" verify decoder state = %u (%s)\n", (unsigned)dstate, FLAC__StreamDecoderStateString[dstate]);
+ }
+
+ return false;
+}
+
+static void init_metadata_blocks_(void)
+{
+ mutils__init_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static void free_metadata_blocks_(void)
+{
+ mutils__free_metadata_blocks(&streaminfo_, &padding_, &seektable_, &application1_, &application2_, &vorbiscomment_, &cuesheet_, &picture_, &unknown_);
+}
+
+static FLAC__StreamEncoderReadStatus stream_encoder_read_callback_(const FLAC__StreamEncoder *encoder, FLAC__byte buffer[], size_t *bytes, void *client_data)
+{
+ FILE *f = (FILE*)client_data;
+ (void)encoder;
+ if(*bytes > 0) {
+ *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, f);
+ if(ferror(f))
+ return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+ else if(*bytes == 0)
+ return FLAC__STREAM_ENCODER_READ_STATUS_END_OF_STREAM;
+ else
+ return FLAC__STREAM_ENCODER_READ_STATUS_CONTINUE;
+ }
+ else
+ return FLAC__STREAM_ENCODER_READ_STATUS_ABORT;
+}
+
+static FLAC__StreamEncoderWriteStatus stream_encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+ FILE *f = (FILE*)client_data;
+ (void)encoder, (void)samples, (void)current_frame;
+ if(fwrite(buffer, 1, bytes, f) != bytes)
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+ else
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+static FLAC__StreamEncoderSeekStatus stream_encoder_seek_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 absolute_byte_offset, void *client_data)
+{
+ FILE *f = (FILE*)client_data;
+ (void)encoder;
+ if(fseek(f, (long)absolute_byte_offset, SEEK_SET) < 0)
+ return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
+ else
+ return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
+}
+
+static FLAC__StreamEncoderTellStatus stream_encoder_tell_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_byte_offset, void *client_data)
+{
+ FILE *f = (FILE*)client_data;
+ long pos;
+ (void)encoder;
+ if((pos = ftell(f)) < 0)
+ return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR;
+ else {
+ *absolute_byte_offset = (FLAC__uint64)pos;
+ return FLAC__STREAM_ENCODER_TELL_STATUS_OK;
+ }
+}
+
+static void stream_encoder_metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ (void)encoder, (void)metadata, (void)client_data;
+}
+
+static void stream_encoder_progress_callback_(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
+{
+ (void)encoder, (void)bytes_written, (void)samples_written, (void)frames_written, (void)total_frames_estimate, (void)client_data;
+}
+
+static FLAC__bool test_stream_encoder(Layer layer, FLAC__bool is_ogg)
+{
+ FLAC__StreamEncoder *encoder;
+ FLAC__StreamEncoderInitStatus init_status;
+ FLAC__StreamEncoderState state;
+ FLAC__StreamDecoderState dstate;
+ FILE *file = 0;
+ FLAC__int32 samples[1024];
+ FLAC__int32 *samples_array[1];
+ unsigned i;
+
+ samples_array[0] = samples;
+
+ printf("\n+++ libFLAC unit test: FLAC__StreamEncoder (layer: %s, format: %s)\n\n", LayerString[layer], is_ogg? "Ogg FLAC":"FLAC");
+
+ printf("testing FLAC__stream_encoder_new()... ");
+ encoder = FLAC__stream_encoder_new();
+ if(0 == encoder) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ if(is_ogg) {
+ printf("testing FLAC__stream_encoder_set_ogg_serial_number()... ");
+ if(!FLAC__stream_encoder_set_ogg_serial_number(encoder, file_utils__ogg_serial_number))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+ }
+
+ printf("testing FLAC__stream_encoder_set_verify()... ");
+ if(!FLAC__stream_encoder_set_verify(encoder, true))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_streamable_subset()... ");
+ if(!FLAC__stream_encoder_set_streamable_subset(encoder, true))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_channels()... ");
+ if(!FLAC__stream_encoder_set_channels(encoder, streaminfo_.data.stream_info.channels))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_bits_per_sample()... ");
+ if(!FLAC__stream_encoder_set_bits_per_sample(encoder, streaminfo_.data.stream_info.bits_per_sample))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_sample_rate()... ");
+ if(!FLAC__stream_encoder_set_sample_rate(encoder, streaminfo_.data.stream_info.sample_rate))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_compression_level()... ");
+ if(!FLAC__stream_encoder_set_compression_level(encoder, (unsigned)(-1)))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_blocksize()... ");
+ if(!FLAC__stream_encoder_set_blocksize(encoder, streaminfo_.data.stream_info.min_blocksize))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_do_mid_side_stereo()... ");
+ if(!FLAC__stream_encoder_set_do_mid_side_stereo(encoder, false))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_loose_mid_side_stereo()... ");
+ if(!FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, false))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_max_lpc_order()... ");
+ if(!FLAC__stream_encoder_set_max_lpc_order(encoder, 0))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_qlp_coeff_precision()... ");
+ if(!FLAC__stream_encoder_set_qlp_coeff_precision(encoder, 0))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_do_qlp_coeff_prec_search()... ");
+ if(!FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, false))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_do_escape_coding()... ");
+ if(!FLAC__stream_encoder_set_do_escape_coding(encoder, false))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_do_exhaustive_model_search()... ");
+ if(!FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, false))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_min_residual_partition_order()... ");
+ if(!FLAC__stream_encoder_set_min_residual_partition_order(encoder, 0))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_max_residual_partition_order()... ");
+ if(!FLAC__stream_encoder_set_max_residual_partition_order(encoder, 0))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_rice_parameter_search_dist()... ");
+ if(!FLAC__stream_encoder_set_rice_parameter_search_dist(encoder, 0))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_total_samples_estimate()... ");
+ if(!FLAC__stream_encoder_set_total_samples_estimate(encoder, streaminfo_.data.stream_info.total_samples))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_set_metadata()... ");
+ if(!FLAC__stream_encoder_set_metadata(encoder, metadata_sequence_, num_metadata_))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ if(layer < LAYER_FILENAME) {
+ printf("opening file for FLAC output... ");
+ file = fopen(flacfilename(is_ogg), "w+b");
+ if(0 == file) {
+ printf("ERROR (%s)\n", strerror(errno));
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ switch(layer) {
+ case LAYER_STREAM:
+ printf("testing FLAC__stream_encoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_encoder_init_ogg_stream(encoder, /*read_callback=*/0, stream_encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, stream_encoder_metadata_callback_, /*client_data=*/file) :
+ FLAC__stream_encoder_init_stream(encoder, stream_encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, stream_encoder_metadata_callback_, /*client_data=*/file);
+ break;
+ case LAYER_SEEKABLE_STREAM:
+ printf("testing FLAC__stream_encoder_init_%sstream()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_encoder_init_ogg_stream(encoder, stream_encoder_read_callback_, stream_encoder_write_callback_, stream_encoder_seek_callback_, stream_encoder_tell_callback_, /*metadata_callback=*/0, /*client_data=*/file) :
+ FLAC__stream_encoder_init_stream(encoder, stream_encoder_write_callback_, stream_encoder_seek_callback_, stream_encoder_tell_callback_, /*metadata_callback=*/0, /*client_data=*/file);
+ break;
+ case LAYER_FILE:
+ printf("testing FLAC__stream_encoder_init_%sFILE()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_encoder_init_ogg_FILE(encoder, file, stream_encoder_progress_callback_, /*client_data=*/0) :
+ FLAC__stream_encoder_init_FILE(encoder, file, stream_encoder_progress_callback_, /*client_data=*/0);
+ break;
+ case LAYER_FILENAME:
+ printf("testing FLAC__stream_encoder_init_%sfile()... ", is_ogg? "ogg_":"");
+ init_status = is_ogg?
+ FLAC__stream_encoder_init_ogg_file(encoder, flacfilename(is_ogg), stream_encoder_progress_callback_, /*client_data=*/0) :
+ FLAC__stream_encoder_init_file(encoder, flacfilename(is_ogg), stream_encoder_progress_callback_, /*client_data=*/0);
+ break;
+ default:
+ die_("internal error 001");
+ return false;
+ }
+ if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK)
+ return die_s_(0, encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_state()... ");
+ state = FLAC__stream_encoder_get_state(encoder);
+ printf("returned state = %u (%s)... OK\n", (unsigned)state, FLAC__StreamEncoderStateString[state]);
+
+ printf("testing FLAC__stream_encoder_get_verify_decoder_state()... ");
+ dstate = FLAC__stream_encoder_get_verify_decoder_state(encoder);
+ printf("returned state = %u (%s)... OK\n", (unsigned)dstate, FLAC__StreamDecoderStateString[dstate]);
+
+ {
+ FLAC__uint64 absolute_sample;
+ unsigned frame_number;
+ unsigned channel;
+ unsigned sample;
+ FLAC__int32 expected;
+ FLAC__int32 got;
+
+ printf("testing FLAC__stream_encoder_get_verify_decoder_error_stats()... ");
+ FLAC__stream_encoder_get_verify_decoder_error_stats(encoder, &absolute_sample, &frame_number, &channel, &sample, &expected, &got);
+ printf("OK\n");
+ }
+
+ printf("testing FLAC__stream_encoder_get_verify()... ");
+ if(FLAC__stream_encoder_get_verify(encoder) != true) {
+ printf("FAILED, expected true, got false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_streamable_subset()... ");
+ if(FLAC__stream_encoder_get_streamable_subset(encoder) != true) {
+ printf("FAILED, expected true, got false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_do_mid_side_stereo()... ");
+ if(FLAC__stream_encoder_get_do_mid_side_stereo(encoder) != false) {
+ printf("FAILED, expected false, got true\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_loose_mid_side_stereo()... ");
+ if(FLAC__stream_encoder_get_loose_mid_side_stereo(encoder) != false) {
+ printf("FAILED, expected false, got true\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_channels()... ");
+ if(FLAC__stream_encoder_get_channels(encoder) != streaminfo_.data.stream_info.channels) {
+ printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.channels, FLAC__stream_encoder_get_channels(encoder));
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_bits_per_sample()... ");
+ if(FLAC__stream_encoder_get_bits_per_sample(encoder) != streaminfo_.data.stream_info.bits_per_sample) {
+ printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.bits_per_sample, FLAC__stream_encoder_get_bits_per_sample(encoder));
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_sample_rate()... ");
+ if(FLAC__stream_encoder_get_sample_rate(encoder) != streaminfo_.data.stream_info.sample_rate) {
+ printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.sample_rate, FLAC__stream_encoder_get_sample_rate(encoder));
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_blocksize()... ");
+ if(FLAC__stream_encoder_get_blocksize(encoder) != streaminfo_.data.stream_info.min_blocksize) {
+ printf("FAILED, expected %u, got %u\n", streaminfo_.data.stream_info.min_blocksize, FLAC__stream_encoder_get_blocksize(encoder));
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_max_lpc_order()... ");
+ if(FLAC__stream_encoder_get_max_lpc_order(encoder) != 0) {
+ printf("FAILED, expected %u, got %u\n", 0, FLAC__stream_encoder_get_max_lpc_order(encoder));
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_qlp_coeff_precision()... ");
+ (void)FLAC__stream_encoder_get_qlp_coeff_precision(encoder);
+ /* we asked the encoder to auto select this so we accept anything */
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_do_qlp_coeff_prec_search()... ");
+ if(FLAC__stream_encoder_get_do_qlp_coeff_prec_search(encoder) != false) {
+ printf("FAILED, expected false, got true\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_do_escape_coding()... ");
+ if(FLAC__stream_encoder_get_do_escape_coding(encoder) != false) {
+ printf("FAILED, expected false, got true\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_do_exhaustive_model_search()... ");
+ if(FLAC__stream_encoder_get_do_exhaustive_model_search(encoder) != false) {
+ printf("FAILED, expected false, got true\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_min_residual_partition_order()... ");
+ if(FLAC__stream_encoder_get_min_residual_partition_order(encoder) != 0) {
+ printf("FAILED, expected %u, got %u\n", 0, FLAC__stream_encoder_get_min_residual_partition_order(encoder));
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_max_residual_partition_order()... ");
+ if(FLAC__stream_encoder_get_max_residual_partition_order(encoder) != 0) {
+ printf("FAILED, expected %u, got %u\n", 0, FLAC__stream_encoder_get_max_residual_partition_order(encoder));
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_rice_parameter_search_dist()... ");
+ if(FLAC__stream_encoder_get_rice_parameter_search_dist(encoder) != 0) {
+ printf("FAILED, expected %u, got %u\n", 0, FLAC__stream_encoder_get_rice_parameter_search_dist(encoder));
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_get_total_samples_estimate()... ");
+ if(FLAC__stream_encoder_get_total_samples_estimate(encoder) != streaminfo_.data.stream_info.total_samples) {
+#ifdef _MSC_VER
+ printf("FAILED, expected %I64u, got %I64u\n", streaminfo_.data.stream_info.total_samples, FLAC__stream_encoder_get_total_samples_estimate(encoder));
+#else
+ printf("FAILED, expected %llu, got %llu\n", (unsigned long long)streaminfo_.data.stream_info.total_samples, (unsigned long long)FLAC__stream_encoder_get_total_samples_estimate(encoder));
+#endif
+ return false;
+ }
+ printf("OK\n");
+
+ /* init the dummy sample buffer */
+ for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
+ samples[i] = i & 7;
+
+ printf("testing FLAC__stream_encoder_process()... ");
+ if(!FLAC__stream_encoder_process(encoder, (const FLAC__int32 * const *)samples_array, sizeof(samples) / sizeof(FLAC__int32)))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_process_interleaved()... ");
+ if(!FLAC__stream_encoder_process_interleaved(encoder, samples, sizeof(samples) / sizeof(FLAC__int32)))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ printf("testing FLAC__stream_encoder_finish()... ");
+ if(!FLAC__stream_encoder_finish(encoder))
+ return die_s_("returned false", encoder);
+ printf("OK\n");
+
+ if(layer < LAYER_FILE)
+ fclose(file);
+
+ printf("testing FLAC__stream_encoder_delete()... ");
+ FLAC__stream_encoder_delete(encoder);
+ printf("OK\n");
+
+ printf("\nPASSED!\n");
+
+ return true;
+}
+
+FLAC__bool test_encoders(void)
+{
+ FLAC__bool is_ogg = false;
+
+ while(1) {
+ init_metadata_blocks_();
+
+ if(!test_stream_encoder(LAYER_STREAM, is_ogg))
+ return false;
+
+ if(!test_stream_encoder(LAYER_SEEKABLE_STREAM, is_ogg))
+ return false;
+
+ if(!test_stream_encoder(LAYER_FILE, is_ogg))
+ return false;
+
+ if(!test_stream_encoder(LAYER_FILENAME, is_ogg))
+ return false;
+
+ (void) grabbag__file_remove_file(flacfilename(is_ogg));
+
+ free_metadata_blocks_();
+
+ if(!FLAC_API_SUPPORTS_OGG_FLAC || is_ogg)
+ break;
+ is_ogg = true;
+ }
+
+ return true;
+}
diff --git a/src/FLAC/src/test_libFLAC/encoders.h b/src/FLAC/src/test_libFLAC/encoders.h
new file mode 100644
index 0000000..86c3690
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/encoders.h
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_ENCODERS_H
+#define FLAC__TEST_LIBFLAC_ENCODERS_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_encoders(void);
+
+#endif
diff --git a/src/FLAC/src/test_libFLAC/format.c b/src/FLAC/src/test_libFLAC/format.c
new file mode 100644
index 0000000..7ac115d
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/format.c
@@ -0,0 +1,256 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/format.h"
+#include "format.h"
+#include <stdio.h>
+
+static const char *true_false_string_[2] = { "false", "true" };
+
+static struct {
+ unsigned rate;
+ FLAC__bool valid;
+ FLAC__bool subset;
+} SAMPLE_RATES[] = {
+ { 0 , false, false },
+ { 1 , true , true },
+ { 9 , true , true },
+ { 10 , true , true },
+ { 4000 , true , true },
+ { 8000 , true , true },
+ { 11025 , true , true },
+ { 12000 , true , true },
+ { 16000 , true , true },
+ { 22050 , true , true },
+ { 24000 , true , true },
+ { 32000 , true , true },
+ { 32768 , true , true },
+ { 44100 , true , true },
+ { 48000 , true , true },
+ { 65000 , true , true },
+ { 65535 , true , true },
+ { 65536 , true , false },
+ { 65540 , true , true },
+ { 65550 , true , true },
+ { 65555 , true , false },
+ { 66000 , true , true },
+ { 66001 , true , false },
+ { 96000 , true , true },
+ { 100000 , true , true },
+ { 100001 , true , false },
+ { 192000 , true , true },
+ { 500000 , true , true },
+ { 500001 , true , false },
+ { 500010 , true , true },
+ { 655349 , true , false },
+ { 655350 , true , true },
+ { 655351 , false, false },
+ { 655360 , false, false },
+ { 700000 , false, false },
+ { 700010 , false, false },
+ { 1000000, false, false },
+ { 1100000, false, false }
+};
+
+static struct {
+ const char *string;
+ FLAC__bool valid;
+} VCENTRY_NAMES[] = {
+ { "" , true },
+ { "a" , true },
+ { "=" , false },
+ { "a=" , false },
+ { "\x01", false },
+ { "\x1f", false },
+ { "\x7d", true },
+ { "\x7e", false },
+ { "\xff", false }
+};
+
+static struct {
+ unsigned length;
+ const FLAC__byte *string;
+ FLAC__bool valid;
+} VCENTRY_VALUES[] = {
+ { 0, (const FLAC__byte*)"" , true },
+ { 1, (const FLAC__byte*)"" , true },
+ { 1, (const FLAC__byte*)"\x01" , true },
+ { 1, (const FLAC__byte*)"\x7f" , true },
+ { 1, (const FLAC__byte*)"\x80" , false },
+ { 1, (const FLAC__byte*)"\x81" , false },
+ { 1, (const FLAC__byte*)"\xc0" , false },
+ { 1, (const FLAC__byte*)"\xe0" , false },
+ { 1, (const FLAC__byte*)"\xf0" , false },
+ { 2, (const FLAC__byte*)"\xc0\x41" , false },
+ { 2, (const FLAC__byte*)"\xc1\x41" , false },
+ { 2, (const FLAC__byte*)"\xc0\x85" , false }, /* non-shortest form */
+ { 2, (const FLAC__byte*)"\xc1\x85" , false }, /* non-shortest form */
+ { 2, (const FLAC__byte*)"\xc2\x85" , true },
+ { 2, (const FLAC__byte*)"\xe0\x41" , false },
+ { 2, (const FLAC__byte*)"\xe1\x41" , false },
+ { 2, (const FLAC__byte*)"\xe0\x85" , false },
+ { 2, (const FLAC__byte*)"\xe1\x85" , false },
+ { 3, (const FLAC__byte*)"\xe0\x85\x41", false },
+ { 3, (const FLAC__byte*)"\xe1\x85\x41", false },
+ { 3, (const FLAC__byte*)"\xe0\x85\x80", false }, /* non-shortest form */
+ { 3, (const FLAC__byte*)"\xe0\x95\x80", false }, /* non-shortest form */
+ { 3, (const FLAC__byte*)"\xe0\xa5\x80", true },
+ { 3, (const FLAC__byte*)"\xe1\x85\x80", true },
+ { 3, (const FLAC__byte*)"\xe1\x95\x80", true },
+ { 3, (const FLAC__byte*)"\xe1\xa5\x80", true }
+};
+
+static struct {
+ const FLAC__byte *string;
+ FLAC__bool valid;
+} VCENTRY_VALUES_NT[] = {
+ { (const FLAC__byte*)"" , true },
+ { (const FLAC__byte*)"\x01" , true },
+ { (const FLAC__byte*)"\x7f" , true },
+ { (const FLAC__byte*)"\x80" , false },
+ { (const FLAC__byte*)"\x81" , false },
+ { (const FLAC__byte*)"\xc0" , false },
+ { (const FLAC__byte*)"\xe0" , false },
+ { (const FLAC__byte*)"\xf0" , false },
+ { (const FLAC__byte*)"\xc0\x41" , false },
+ { (const FLAC__byte*)"\xc1\x41" , false },
+ { (const FLAC__byte*)"\xc0\x85" , false }, /* non-shortest form */
+ { (const FLAC__byte*)"\xc1\x85" , false }, /* non-shortest form */
+ { (const FLAC__byte*)"\xc2\x85" , true },
+ { (const FLAC__byte*)"\xe0\x41" , false },
+ { (const FLAC__byte*)"\xe1\x41" , false },
+ { (const FLAC__byte*)"\xe0\x85" , false },
+ { (const FLAC__byte*)"\xe1\x85" , false },
+ { (const FLAC__byte*)"\xe0\x85\x41", false },
+ { (const FLAC__byte*)"\xe1\x85\x41", false },
+ { (const FLAC__byte*)"\xe0\x85\x80", false }, /* non-shortest form */
+ { (const FLAC__byte*)"\xe0\x95\x80", false }, /* non-shortest form */
+ { (const FLAC__byte*)"\xe0\xa5\x80", true },
+ { (const FLAC__byte*)"\xe1\x85\x80", true },
+ { (const FLAC__byte*)"\xe1\x95\x80", true },
+ { (const FLAC__byte*)"\xe1\xa5\x80", true }
+};
+
+static struct {
+ unsigned length;
+ const FLAC__byte *string;
+ FLAC__bool valid;
+} VCENTRIES[] = {
+ { 0, (const FLAC__byte*)"" , false },
+ { 1, (const FLAC__byte*)"a" , false },
+ { 1, (const FLAC__byte*)"=" , true },
+ { 2, (const FLAC__byte*)"a=" , true },
+ { 2, (const FLAC__byte*)"\x01=" , false },
+ { 2, (const FLAC__byte*)"\x1f=" , false },
+ { 2, (const FLAC__byte*)"\x7d=" , true },
+ { 2, (const FLAC__byte*)"\x7e=" , false },
+ { 2, (const FLAC__byte*)"\xff=" , false },
+ { 3, (const FLAC__byte*)"a=\x01" , true },
+ { 3, (const FLAC__byte*)"a=\x7f" , true },
+ { 3, (const FLAC__byte*)"a=\x80" , false },
+ { 3, (const FLAC__byte*)"a=\x81" , false },
+ { 3, (const FLAC__byte*)"a=\xc0" , false },
+ { 3, (const FLAC__byte*)"a=\xe0" , false },
+ { 3, (const FLAC__byte*)"a=\xf0" , false },
+ { 4, (const FLAC__byte*)"a=\xc0\x41" , false },
+ { 4, (const FLAC__byte*)"a=\xc1\x41" , false },
+ { 4, (const FLAC__byte*)"a=\xc0\x85" , false }, /* non-shortest form */
+ { 4, (const FLAC__byte*)"a=\xc1\x85" , false }, /* non-shortest form */
+ { 4, (const FLAC__byte*)"a=\xc2\x85" , true },
+ { 4, (const FLAC__byte*)"a=\xe0\x41" , false },
+ { 4, (const FLAC__byte*)"a=\xe1\x41" , false },
+ { 4, (const FLAC__byte*)"a=\xe0\x85" , false },
+ { 4, (const FLAC__byte*)"a=\xe1\x85" , false },
+ { 5, (const FLAC__byte*)"a=\xe0\x85\x41", false },
+ { 5, (const FLAC__byte*)"a=\xe1\x85\x41", false },
+ { 5, (const FLAC__byte*)"a=\xe0\x85\x80", false }, /* non-shortest form */
+ { 5, (const FLAC__byte*)"a=\xe0\x95\x80", false }, /* non-shortest form */
+ { 5, (const FLAC__byte*)"a=\xe0\xa5\x80", true },
+ { 5, (const FLAC__byte*)"a=\xe1\x85\x80", true },
+ { 5, (const FLAC__byte*)"a=\xe1\x95\x80", true },
+ { 5, (const FLAC__byte*)"a=\xe1\xa5\x80", true }
+};
+
+FLAC__bool test_format(void)
+{
+ unsigned i;
+
+ printf("\n+++ libFLAC unit test: format\n\n");
+
+ for(i = 0; i < sizeof(SAMPLE_RATES)/sizeof(SAMPLE_RATES[0]); i++) {
+ printf("testing FLAC__format_sample_rate_is_valid(%u)... ", SAMPLE_RATES[i].rate);
+ if(FLAC__format_sample_rate_is_valid(SAMPLE_RATES[i].rate) != SAMPLE_RATES[i].valid) {
+ printf("FAILED, expected %s, got %s\n", true_false_string_[SAMPLE_RATES[i].valid], true_false_string_[!SAMPLE_RATES[i].valid]);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ for(i = 0; i < sizeof(SAMPLE_RATES)/sizeof(SAMPLE_RATES[0]); i++) {
+ printf("testing FLAC__format_sample_rate_is_subset(%u)... ", SAMPLE_RATES[i].rate);
+ if(FLAC__format_sample_rate_is_subset(SAMPLE_RATES[i].rate) != SAMPLE_RATES[i].subset) {
+ printf("FAILED, expected %s, got %s\n", true_false_string_[SAMPLE_RATES[i].subset], true_false_string_[!SAMPLE_RATES[i].subset]);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ for(i = 0; i < sizeof(VCENTRY_NAMES)/sizeof(VCENTRY_NAMES[0]); i++) {
+ printf("testing FLAC__format_vorbiscomment_entry_name_is_legal(\"%s\")... ", VCENTRY_NAMES[i].string);
+ if(FLAC__format_vorbiscomment_entry_name_is_legal(VCENTRY_NAMES[i].string) != VCENTRY_NAMES[i].valid) {
+ printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_NAMES[i].valid], true_false_string_[!VCENTRY_NAMES[i].valid]);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ for(i = 0; i < sizeof(VCENTRY_VALUES)/sizeof(VCENTRY_VALUES[0]); i++) {
+ printf("testing FLAC__format_vorbiscomment_entry_value_is_legal(\"%s\", %u)... ", VCENTRY_VALUES[i].string, VCENTRY_VALUES[i].length);
+ if(FLAC__format_vorbiscomment_entry_value_is_legal(VCENTRY_VALUES[i].string, VCENTRY_VALUES[i].length) != VCENTRY_VALUES[i].valid) {
+ printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_VALUES[i].valid], true_false_string_[!VCENTRY_VALUES[i].valid]);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ for(i = 0; i < sizeof(VCENTRY_VALUES_NT)/sizeof(VCENTRY_VALUES_NT[0]); i++) {
+ printf("testing FLAC__format_vorbiscomment_entry_value_is_legal(\"%s\", -1)... ", VCENTRY_VALUES_NT[i].string);
+ if(FLAC__format_vorbiscomment_entry_value_is_legal(VCENTRY_VALUES_NT[i].string, (unsigned)(-1)) != VCENTRY_VALUES_NT[i].valid) {
+ printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRY_VALUES_NT[i].valid], true_false_string_[!VCENTRY_VALUES_NT[i].valid]);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ for(i = 0; i < sizeof(VCENTRIES)/sizeof(VCENTRIES[0]); i++) {
+ printf("testing FLAC__format_vorbiscomment_entry_is_legal(\"%s\", %u)... ", VCENTRIES[i].string, VCENTRIES[i].length);
+ if(FLAC__format_vorbiscomment_entry_is_legal(VCENTRIES[i].string, VCENTRIES[i].length) != VCENTRIES[i].valid) {
+ printf("FAILED, expected %s, got %s\n", true_false_string_[VCENTRIES[i].valid], true_false_string_[!VCENTRIES[i].valid]);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ printf("\nPASSED!\n");
+ return true;
+}
diff --git a/src/FLAC/src/test_libFLAC/format.h b/src/FLAC/src/test_libFLAC/format.h
new file mode 100644
index 0000000..e48a0e0
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/format.h
@@ -0,0 +1,26 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_FORMAT_H
+#define FLAC__TEST_LIBFLAC_FORMAT_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_format(void);
+
+#endif
diff --git a/src/FLAC/src/test_libFLAC/main.c b/src/FLAC/src/test_libFLAC/main.c
new file mode 100644
index 0000000..1807ff5
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/main.c
@@ -0,0 +1,49 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "bitwriter.h"
+#include "decoders.h"
+#include "encoders.h"
+#include "format.h"
+#include "metadata.h"
+
+int main(int argc, char *argv[])
+{
+ (void)argc, (void)argv;
+
+ if(!test_bitwriter())
+ return 1;
+
+ if(!test_format())
+ return 1;
+
+ if(!test_encoders())
+ return 1;
+
+ if(!test_decoders())
+ return 1;
+
+ if(!test_metadata())
+ return 1;
+
+ return 0;
+}
diff --git a/src/FLAC/src/test_libFLAC/metadata.c b/src/FLAC/src/test_libFLAC/metadata.c
new file mode 100644
index 0000000..aacb6bf
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/metadata.c
@@ -0,0 +1,40 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "metadata.h"
+#include <stdio.h>
+
+extern FLAC__bool test_metadata_object(void);
+extern FLAC__bool test_metadata_file_manipulation(void);
+
+FLAC__bool test_metadata(void)
+{
+ if(!test_metadata_object())
+ return false;
+
+ if(!test_metadata_file_manipulation())
+ return false;
+
+ printf("\nPASSED!\n");
+
+ return true;
+}
diff --git a/src/FLAC/src/test_libFLAC/metadata.h b/src/FLAC/src/test_libFLAC/metadata.h
new file mode 100644
index 0000000..5ebdea1
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/metadata.h
@@ -0,0 +1,28 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#ifndef FLAC__TEST_LIBFLAC_METADATA_H
+#define FLAC__TEST_LIBFLAC_METADATA_H
+
+#include "FLAC/ordinals.h"
+
+FLAC__bool test_metadata(void);
+FLAC__bool test_metadata_file_manipulation(void);
+FLAC__bool test_metadata_object(void) ;
+
+#endif
diff --git a/src/FLAC/src/test_libFLAC/metadata_manip.c b/src/FLAC/src/test_libFLAC/metadata_manip.c
new file mode 100644
index 0000000..2647d37
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/metadata_manip.c
@@ -0,0 +1,2138 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcpy()/memset() */
+#if defined _MSC_VER || defined __MINGW32__
+#include <sys/utime.h> /* for utime() */
+#include <io.h> /* for chmod() */
+#if _MSC_VER <= 1600 /* @@@ [2G limit] */
+#define fseeko fseek
+#define ftello ftell
+#endif
+#else
+#include <sys/types.h> /* some flavors of BSD (like OS X) require this to get time_t */
+#include <utime.h> /* for utime() */
+#include <unistd.h> /* for chown(), unlink() */
+#endif
+#include <sys/stat.h> /* for stat(), maybe chmod() */
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+#include "FLAC/metadata.h"
+#include "share/grabbag.h"
+#include "test_libs_common/file_utils_flac.h"
+#include "test_libs_common/metadata_utils.h"
+#include "metadata.h"
+
+
+/******************************************************************************
+ The general strategy of these tests (for interface levels 1 and 2) is
+ to create a dummy FLAC file with a known set of initial metadata
+ blocks, then keep a mirror locally of what we expect the metadata to be
+ after each operation. Then testing becomes a simple matter of running
+ a FLAC__StreamDecoder over the dummy file after each operation, comparing
+ the decoded metadata to what's in our local copy. If there are any
+ differences in the metadata, or the actual audio data is corrupted, we
+ will catch it while decoding.
+******************************************************************************/
+
+typedef struct {
+ FLAC__bool error_occurred;
+} decoder_client_struct;
+
+typedef struct {
+ FLAC__StreamMetadata *blocks[64];
+ unsigned num_blocks;
+} our_metadata_struct;
+
+/* our copy of the metadata in flacfilename() */
+static our_metadata_struct our_metadata_;
+
+/* the current block number that corresponds to the position of the iterator we are testing */
+static unsigned mc_our_block_number_ = 0;
+
+static const char *flacfilename(FLAC__bool is_ogg)
+{
+ return is_ogg? "metadata.ogg" : "metadata.flac";
+}
+
+static FLAC__bool die_(const char *msg)
+{
+ printf("ERROR: %s\n", msg);
+ return false;
+}
+
+static FLAC__bool die_c_(const char *msg, FLAC__Metadata_ChainStatus status)
+{
+ printf("ERROR: %s\n", msg);
+ printf(" status=%s\n", FLAC__Metadata_ChainStatusString[status]);
+ return false;
+}
+
+static FLAC__bool die_ss_(const char *msg, FLAC__Metadata_SimpleIterator *iterator)
+{
+ printf("ERROR: %s\n", msg);
+ printf(" status=%s\n", FLAC__Metadata_SimpleIteratorStatusString[FLAC__metadata_simple_iterator_status(iterator)]);
+ return false;
+}
+
+static void *malloc_or_die_(size_t size)
+{
+ void *x = malloc(size);
+ if(0 == x) {
+ fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
+ exit(1);
+ }
+ return x;
+}
+
+static char *strdup_or_die_(const char *s)
+{
+ char *x = strdup(s);
+ if(0 == x) {
+ fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+ exit(1);
+ }
+ return x;
+}
+
+/* functions for working with our metadata copy */
+
+static FLAC__bool replace_in_our_metadata_(FLAC__StreamMetadata *block, unsigned position, FLAC__bool copy)
+{
+ unsigned i;
+ FLAC__StreamMetadata *obj = block;
+ FLAC__ASSERT(position < our_metadata_.num_blocks);
+ if(copy) {
+ if(0 == (obj = FLAC__metadata_object_clone(block)))
+ return die_("during FLAC__metadata_object_clone()");
+ }
+ FLAC__metadata_object_delete(our_metadata_.blocks[position]);
+ our_metadata_.blocks[position] = obj;
+
+ /* set the is_last flags */
+ for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+ our_metadata_.blocks[i]->is_last = false;
+ our_metadata_.blocks[i]->is_last = true;
+
+ return true;
+}
+
+static FLAC__bool insert_to_our_metadata_(FLAC__StreamMetadata *block, unsigned position, FLAC__bool copy)
+{
+ unsigned i;
+ FLAC__StreamMetadata *obj = block;
+ if(copy) {
+ if(0 == (obj = FLAC__metadata_object_clone(block)))
+ return die_("during FLAC__metadata_object_clone()");
+ }
+ if(position > our_metadata_.num_blocks) {
+ position = our_metadata_.num_blocks;
+ }
+ else {
+ for(i = our_metadata_.num_blocks; i > position; i--)
+ our_metadata_.blocks[i] = our_metadata_.blocks[i-1];
+ }
+ our_metadata_.blocks[position] = obj;
+ our_metadata_.num_blocks++;
+
+ /* set the is_last flags */
+ for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+ our_metadata_.blocks[i]->is_last = false;
+ our_metadata_.blocks[i]->is_last = true;
+
+ return true;
+}
+
+static void delete_from_our_metadata_(unsigned position)
+{
+ unsigned i;
+ FLAC__ASSERT(position < our_metadata_.num_blocks);
+ FLAC__metadata_object_delete(our_metadata_.blocks[position]);
+ for(i = position; i < our_metadata_.num_blocks - 1; i++)
+ our_metadata_.blocks[i] = our_metadata_.blocks[i+1];
+ our_metadata_.num_blocks--;
+
+ /* set the is_last flags */
+ if(our_metadata_.num_blocks > 0) {
+ for(i = 0; i < our_metadata_.num_blocks - 1; i++)
+ our_metadata_.blocks[i]->is_last = false;
+ our_metadata_.blocks[i]->is_last = true;
+ }
+}
+
+/*
+ * This wad of functions supports filename- and callback-based chain reading/writing.
+ * Everything up to set_file_stats_() is copied from libFLAC/metadata_iterators.c
+ */
+static
+FLAC__bool open_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
+{
+ static const char *tempfile_suffix = ".metadata_edit";
+
+ if(0 == (*tempfilename = (char*)malloc(strlen(filename) + strlen(tempfile_suffix) + 1)))
+ return false;
+ strcpy(*tempfilename, filename);
+ strcat(*tempfilename, tempfile_suffix);
+
+ if(0 == (*tempfile = fopen(*tempfilename, "wb")))
+ return false;
+
+ return true;
+}
+
+static
+void cleanup_tempfile_(FILE **tempfile, char **tempfilename)
+{
+ if(0 != *tempfile) {
+ (void)fclose(*tempfile);
+ *tempfile = 0;
+ }
+
+ if(0 != *tempfilename) {
+ (void)unlink(*tempfilename);
+ free(*tempfilename);
+ *tempfilename = 0;
+ }
+}
+
+static
+FLAC__bool transport_tempfile_(const char *filename, FILE **tempfile, char **tempfilename)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != tempfile);
+ FLAC__ASSERT(0 != tempfilename);
+ FLAC__ASSERT(0 != *tempfilename);
+
+ if(0 != *tempfile) {
+ (void)fclose(*tempfile);
+ *tempfile = 0;
+ }
+
+#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
+ /* on some flavors of windows, rename() will fail if the destination already exists */
+ if(unlink(filename) < 0) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+#endif
+
+ if(0 != rename(*tempfilename, filename)) {
+ cleanup_tempfile_(tempfile, tempfilename);
+ return false;
+ }
+
+ cleanup_tempfile_(tempfile, tempfilename);
+
+ return true;
+}
+
+static
+FLAC__bool get_file_stats_(const char *filename, struct stat *stats)
+{
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+ return (0 == stat(filename, stats));
+}
+
+static
+void set_file_stats_(const char *filename, struct stat *stats)
+{
+ struct utimbuf srctime;
+
+ FLAC__ASSERT(0 != filename);
+ FLAC__ASSERT(0 != stats);
+
+ srctime.actime = stats->st_atime;
+ srctime.modtime = stats->st_mtime;
+ (void)chmod(filename, stats->st_mode);
+ (void)utime(filename, &srctime);
+#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
+ (void)chown(filename, stats->st_uid, -1);
+ (void)chown(filename, -1, stats->st_gid);
+#endif
+}
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t chain_write_cb_(const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
+{
+ FILE *stream = (FILE*)handle;
+ size_t ret = fwrite(ptr, size, nmemb, stream);
+ if(!ferror(stream))
+ fflush(stream);
+ return ret;
+}
+#endif
+
+static int chain_seek_cb_(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
+{
+ off_t o = (off_t)offset;
+ FLAC__ASSERT(offset == o);
+ return fseeko((FILE*)handle, o, whence);
+}
+
+static FLAC__int64 chain_tell_cb_(FLAC__IOHandle handle)
+{
+ return ftello((FILE*)handle);
+}
+
+static int chain_eof_cb_(FLAC__IOHandle handle)
+{
+ return feof((FILE*)handle);
+}
+
+static FLAC__bool write_chain_(FLAC__Metadata_Chain *chain, FLAC__bool use_padding, FLAC__bool preserve_file_stats, FLAC__bool filename_based, const char *filename)
+{
+ if(filename_based)
+ return FLAC__metadata_chain_write(chain, use_padding, preserve_file_stats);
+ else {
+ FLAC__IOCallbacks callbacks;
+
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.read = (FLAC__IOCallback_Read)fread;
+#ifdef FLAC__VALGRIND_TESTING
+ callbacks.write = chain_write_cb_;
+#else
+ callbacks.write = (FLAC__IOCallback_Write)fwrite;
+#endif
+ callbacks.seek = chain_seek_cb_;
+ callbacks.eof = chain_eof_cb_;
+
+ if(FLAC__metadata_chain_check_if_tempfile_needed(chain, use_padding)) {
+ struct stat stats;
+ FILE *file, *tempfile;
+ char *tempfilename;
+ if(preserve_file_stats) {
+ if(!get_file_stats_(filename, &stats))
+ return false;
+ }
+ if(0 == (file = fopen(filename, "rb")))
+ return false; /*@@@@ chain status still says OK though */
+ if(!open_tempfile_(filename, &tempfile, &tempfilename)) {
+ fclose(file);
+ cleanup_tempfile_(&tempfile, &tempfilename);
+ return false; /*@@@@ chain status still says OK though */
+ }
+ if(!FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, use_padding, (FLAC__IOHandle)file, callbacks, (FLAC__IOHandle)tempfile, callbacks)) {
+ fclose(file);
+ fclose(tempfile);
+ return false;
+ }
+ fclose(file);
+ fclose(tempfile);
+ file = tempfile = 0;
+ if(!transport_tempfile_(filename, &tempfile, &tempfilename))
+ return false;
+ if(preserve_file_stats)
+ set_file_stats_(filename, &stats);
+ }
+ else {
+ FILE *file = fopen(filename, "r+b");
+ if(0 == file)
+ return false; /*@@@@ chain status still says OK though */
+ if(!FLAC__metadata_chain_write_with_callbacks(chain, use_padding, (FLAC__IOHandle)file, callbacks))
+ return false;
+ fclose(file);
+ }
+ }
+
+ return true;
+}
+
+static FLAC__bool read_chain_(FLAC__Metadata_Chain *chain, const char *filename, FLAC__bool filename_based, FLAC__bool is_ogg)
+{
+ if(filename_based)
+ return is_ogg?
+ FLAC__metadata_chain_read_ogg(chain, flacfilename(is_ogg)) :
+ FLAC__metadata_chain_read(chain, flacfilename(is_ogg))
+ ;
+ else {
+ FLAC__IOCallbacks callbacks;
+
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.read = (FLAC__IOCallback_Read)fread;
+ callbacks.seek = chain_seek_cb_;
+ callbacks.tell = chain_tell_cb_;
+
+ {
+ FLAC__bool ret;
+ FILE *file = fopen(filename, "rb");
+ if(0 == file)
+ return false; /*@@@@ chain status still says OK though */
+ ret = is_ogg?
+ FLAC__metadata_chain_read_ogg_with_callbacks(chain, (FLAC__IOHandle)file, callbacks) :
+ FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)
+ ;
+ fclose(file);
+ return ret;
+ }
+ }
+}
+
+/* function for comparing our metadata to a FLAC__Metadata_Chain */
+
+static FLAC__bool compare_chain_(FLAC__Metadata_Chain *chain, unsigned current_position, FLAC__StreamMetadata *current_block)
+{
+ unsigned i;
+ FLAC__Metadata_Iterator *iterator;
+ FLAC__StreamMetadata *block;
+ FLAC__bool next_ok = true;
+
+ FLAC__ASSERT(0 != chain);
+
+ printf("\tcomparing chain... ");
+ fflush(stdout);
+
+ if(0 == (iterator = FLAC__metadata_iterator_new()))
+ return die_("allocating memory for iterator");
+
+ FLAC__metadata_iterator_init(iterator, chain);
+
+ i = 0;
+ do {
+ printf("%u... ", i);
+ fflush(stdout);
+
+ if(0 == (block = FLAC__metadata_iterator_get_block(iterator))) {
+ FLAC__metadata_iterator_delete(iterator);
+ return die_("getting block from iterator");
+ }
+
+ if(!mutils__compare_block(our_metadata_.blocks[i], block)) {
+ FLAC__metadata_iterator_delete(iterator);
+ return die_("metadata block mismatch");
+ }
+
+ i++;
+ next_ok = FLAC__metadata_iterator_next(iterator);
+ } while(i < our_metadata_.num_blocks && next_ok);
+
+ FLAC__metadata_iterator_delete(iterator);
+
+ if(next_ok)
+ return die_("chain has more blocks than expected");
+
+ if(i < our_metadata_.num_blocks)
+ return die_("short block count in chain");
+
+ if(0 != current_block) {
+ printf("CURRENT_POSITION... ");
+ fflush(stdout);
+
+ if(!mutils__compare_block(our_metadata_.blocks[current_position], current_block))
+ return die_("metadata block mismatch");
+ }
+
+ printf("PASSED\n");
+
+ return true;
+}
+
+/* decoder callbacks for checking the file */
+
+static FLAC__StreamDecoderWriteStatus decoder_write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ (void)decoder, (void)buffer, (void)client_data;
+
+ if(
+ (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER && frame->header.number.frame_number == 0) ||
+ (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER && frame->header.number.sample_number == 0)
+ ) {
+ printf("content... ");
+ fflush(stdout);
+ }
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+/* this version pays no attention to the metadata */
+static void decoder_metadata_callback_null_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ (void)decoder, (void)metadata, (void)client_data;
+
+ printf("%d... ", mc_our_block_number_);
+ fflush(stdout);
+
+ mc_our_block_number_++;
+}
+
+/* this version is used when we want to compare to our metadata copy */
+static void decoder_metadata_callback_compare_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ decoder_client_struct *dcd = (decoder_client_struct*)client_data;
+
+ (void)decoder;
+
+ /* don't bother checking if we've already hit an error */
+ if(dcd->error_occurred)
+ return;
+
+ printf("%d... ", mc_our_block_number_);
+ fflush(stdout);
+
+ if(mc_our_block_number_ >= our_metadata_.num_blocks) {
+ (void)die_("got more metadata blocks than expected");
+ dcd->error_occurred = true;
+ }
+ else {
+ if(!mutils__compare_block(our_metadata_.blocks[mc_our_block_number_], metadata)) {
+ (void)die_("metadata block mismatch");
+ dcd->error_occurred = true;
+ }
+ }
+ mc_our_block_number_++;
+}
+
+static void decoder_error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ decoder_client_struct *dcd = (decoder_client_struct*)client_data;
+ (void)decoder;
+
+ dcd->error_occurred = true;
+ printf("ERROR: got error callback, status = %s (%u)\n", FLAC__StreamDecoderErrorStatusString[status], (unsigned)status);
+}
+
+static FLAC__bool generate_file_(FLAC__bool include_extras, FLAC__bool is_ogg)
+{
+ FLAC__StreamMetadata streaminfo, vorbiscomment, *cuesheet, picture, padding;
+ FLAC__StreamMetadata *metadata[4];
+ unsigned i = 0, n = 0;
+
+ printf("generating %sFLAC file for test\n", is_ogg? "Ogg " : "");
+
+ while(our_metadata_.num_blocks > 0)
+ delete_from_our_metadata_(0);
+
+ streaminfo.is_last = false;
+ streaminfo.type = FLAC__METADATA_TYPE_STREAMINFO;
+ streaminfo.length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+ streaminfo.data.stream_info.min_blocksize = 576;
+ streaminfo.data.stream_info.max_blocksize = 576;
+ streaminfo.data.stream_info.min_framesize = 0;
+ streaminfo.data.stream_info.max_framesize = 0;
+ streaminfo.data.stream_info.sample_rate = 44100;
+ streaminfo.data.stream_info.channels = 1;
+ streaminfo.data.stream_info.bits_per_sample = 8;
+ streaminfo.data.stream_info.total_samples = 0;
+ memset(streaminfo.data.stream_info.md5sum, 0, 16);
+
+ {
+ const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
+ vorbiscomment.is_last = false;
+ vorbiscomment.type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+ vorbiscomment.length = (4 + vendor_string_length) + 4;
+ vorbiscomment.data.vorbis_comment.vendor_string.length = vendor_string_length;
+ vorbiscomment.data.vorbis_comment.vendor_string.entry = malloc_or_die_(vendor_string_length+1);
+ memcpy(vorbiscomment.data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
+ vorbiscomment.data.vorbis_comment.num_comments = 0;
+ vorbiscomment.data.vorbis_comment.comments = 0;
+ }
+
+ {
+ if (0 == (cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET)))
+ return die_("priming our metadata");
+ cuesheet->is_last = false;
+ strcpy(cuesheet->data.cue_sheet.media_catalog_number, "bogo-MCN");
+ cuesheet->data.cue_sheet.lead_in = 123;
+ cuesheet->data.cue_sheet.is_cd = false;
+ if (!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, 0))
+ return die_("priming our metadata");
+ cuesheet->data.cue_sheet.tracks[0].number = 1;
+ if (!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, 0, 0))
+ return die_("priming our metadata");
+ }
+
+ {
+ picture.is_last = false;
+ picture.type = FLAC__METADATA_TYPE_PICTURE;
+ picture.length =
+ (
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+ FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+ FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+ FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
+ ) / 8
+ ;
+ picture.data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+ picture.data.picture.mime_type = strdup_or_die_("image/jpeg");
+ picture.length += strlen(picture.data.picture.mime_type);
+ picture.data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+ picture.length += strlen((const char *)picture.data.picture.description);
+ picture.data.picture.width = 300;
+ picture.data.picture.height = 300;
+ picture.data.picture.depth = 24;
+ picture.data.picture.colors = 0;
+ picture.data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+ picture.data.picture.data_length = strlen((const char *)picture.data.picture.data);
+ picture.length += picture.data.picture.data_length;
+ }
+
+ padding.is_last = true;
+ padding.type = FLAC__METADATA_TYPE_PADDING;
+ padding.length = 1234;
+
+ metadata[n++] = &vorbiscomment;
+ if(include_extras) {
+ metadata[n++] = cuesheet;
+ metadata[n++] = &picture;
+ }
+ metadata[n++] = &padding;
+
+ if(
+ !insert_to_our_metadata_(&streaminfo, i++, /*copy=*/true) ||
+ !insert_to_our_metadata_(&vorbiscomment, i++, /*copy=*/true) ||
+ (include_extras && !insert_to_our_metadata_(cuesheet, i++, /*copy=*/false)) ||
+ (include_extras && !insert_to_our_metadata_(&picture, i++, /*copy=*/true)) ||
+ !insert_to_our_metadata_(&padding, i++, /*copy=*/true)
+ )
+ return die_("priming our metadata");
+
+ if(!file_utils__generate_flacfile(is_ogg, flacfilename(is_ogg), 0, 512 * 1024, &streaminfo, metadata, n))
+ return die_("creating the encoded file");
+
+ free(vorbiscomment.data.vorbis_comment.vendor_string.entry);
+ free(picture.data.picture.mime_type);
+ free(picture.data.picture.description);
+ free(picture.data.picture.data);
+ if(!include_extras)
+ FLAC__metadata_object_delete(cuesheet);
+
+ return true;
+}
+
+static FLAC__bool test_file_(FLAC__bool is_ogg, FLAC__StreamDecoderMetadataCallback metadata_callback)
+{
+ const char *filename = flacfilename(is_ogg);
+ FLAC__StreamDecoder *decoder;
+ decoder_client_struct decoder_client_data;
+
+ FLAC__ASSERT(0 != metadata_callback);
+
+ mc_our_block_number_ = 0;
+ decoder_client_data.error_occurred = false;
+
+ printf("\ttesting '%s'... ", filename);
+ fflush(stdout);
+
+ if(0 == (decoder = FLAC__stream_decoder_new()))
+ return die_("couldn't allocate decoder instance");
+
+ FLAC__stream_decoder_set_md5_checking(decoder, true);
+ FLAC__stream_decoder_set_metadata_respond_all(decoder);
+ if(
+ (is_ogg?
+ FLAC__stream_decoder_init_ogg_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data) :
+ FLAC__stream_decoder_init_file(decoder, filename, decoder_write_callback_, metadata_callback, decoder_error_callback_, &decoder_client_data)
+ ) != FLAC__STREAM_DECODER_INIT_STATUS_OK
+ ) {
+ (void)FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+ return die_("initializing decoder\n");
+ }
+ if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) {
+ (void)FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+ return die_("decoding file\n");
+ }
+
+ (void)FLAC__stream_decoder_finish(decoder);
+ FLAC__stream_decoder_delete(decoder);
+
+ if(decoder_client_data.error_occurred)
+ return false;
+
+ if(mc_our_block_number_ != our_metadata_.num_blocks)
+ return die_("short metadata block count");
+
+ printf("PASSED\n");
+ return true;
+}
+
+static FLAC__bool change_stats_(const char *filename, FLAC__bool read_only)
+{
+ if(!grabbag__file_change_stats(filename, read_only))
+ return die_("during grabbag__file_change_stats()");
+
+ return true;
+}
+
+static FLAC__bool remove_file_(const char *filename)
+{
+ while(our_metadata_.num_blocks > 0)
+ delete_from_our_metadata_(0);
+
+ if(!grabbag__file_remove_file(filename))
+ return die_("removing file");
+
+ return true;
+}
+
+static FLAC__bool test_level_0_(void)
+{
+ FLAC__StreamMetadata streaminfo;
+ FLAC__StreamMetadata *tags = 0;
+ FLAC__StreamMetadata *cuesheet = 0;
+ FLAC__StreamMetadata *picture = 0;
+
+ printf("\n\n++++++ testing level 0 interface\n");
+
+ if(!generate_file_(/*include_extras=*/true, /*is_ogg=*/false))
+ return false;
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_))
+ return false;
+
+ printf("testing FLAC__metadata_get_streaminfo()... ");
+
+ if(!FLAC__metadata_get_streaminfo(flacfilename(/*is_ogg=*/false), &streaminfo))
+ return die_("during FLAC__metadata_get_streaminfo()");
+
+ /* check to see if some basic data matches (c.f. generate_file_()) */
+ if(streaminfo.data.stream_info.channels != 1)
+ return die_("mismatch in streaminfo.data.stream_info.channels");
+ if(streaminfo.data.stream_info.bits_per_sample != 8)
+ return die_("mismatch in streaminfo.data.stream_info.bits_per_sample");
+ if(streaminfo.data.stream_info.sample_rate != 44100)
+ return die_("mismatch in streaminfo.data.stream_info.sample_rate");
+ if(streaminfo.data.stream_info.min_blocksize != 576)
+ return die_("mismatch in streaminfo.data.stream_info.min_blocksize");
+ if(streaminfo.data.stream_info.max_blocksize != 576)
+ return die_("mismatch in streaminfo.data.stream_info.max_blocksize");
+
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_get_tags()... ");
+
+ if(!FLAC__metadata_get_tags(flacfilename(/*is_ogg=*/false), &tags))
+ return die_("during FLAC__metadata_get_tags()");
+
+ /* check to see if some basic data matches (c.f. generate_file_()) */
+ if(tags->data.vorbis_comment.num_comments != 0)
+ return die_("mismatch in tags->data.vorbis_comment.num_comments");
+
+ printf("OK\n");
+
+ FLAC__metadata_object_delete(tags);
+
+ printf("testing FLAC__metadata_get_cuesheet()... ");
+
+ if(!FLAC__metadata_get_cuesheet(flacfilename(/*is_ogg=*/false), &cuesheet))
+ return die_("during FLAC__metadata_get_cuesheet()");
+
+ /* check to see if some basic data matches (c.f. generate_file_()) */
+ if(cuesheet->data.cue_sheet.lead_in != 123)
+ return die_("mismatch in cuesheet->data.cue_sheet.lead_in");
+
+ printf("OK\n");
+
+ FLAC__metadata_object_delete(cuesheet);
+
+ printf("testing FLAC__metadata_get_picture()... ");
+
+ if(!FLAC__metadata_get_picture(flacfilename(/*is_ogg=*/false), &picture, /*type=*/(FLAC__StreamMetadata_Picture_Type)(-1), /*mime_type=*/0, /*description=*/0, /*max_width=*/(unsigned)(-1), /*max_height=*/(unsigned)(-1), /*max_depth=*/(unsigned)(-1), /*max_colors=*/(unsigned)(-1)))
+ return die_("during FLAC__metadata_get_picture()");
+
+ /* check to see if some basic data matches (c.f. generate_file_()) */
+ if(picture->data.picture.type != FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER)
+ return die_("mismatch in picture->data.picture.type");
+
+ printf("OK\n");
+
+ FLAC__metadata_object_delete(picture);
+
+ if(!remove_file_(flacfilename(/*is_ogg=*/false)))
+ return false;
+
+ return true;
+}
+
+static FLAC__bool test_level_1_(void)
+{
+ FLAC__Metadata_SimpleIterator *iterator;
+ FLAC__StreamMetadata *block, *app, *padding;
+ FLAC__byte data[1000];
+ unsigned our_current_position = 0;
+
+ /* initialize 'data' to avoid Valgrind errors */
+ memset(data, 0, sizeof(data));
+
+ printf("\n\n++++++ testing level 1 interface\n");
+
+ /************************************************************/
+
+ printf("simple iterator on read-only file\n");
+
+ if(!generate_file_(/*include_extras=*/false, /*is_ogg=*/false))
+ return false;
+
+ if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read_only=*/true))
+ return false;
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_null_))
+ return false;
+
+ if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
+ return die_("FLAC__metadata_simple_iterator_new()");
+
+ if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
+ return die_("FLAC__metadata_simple_iterator_init() returned false");
+
+ printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(iterator));
+ if(FLAC__metadata_simple_iterator_is_writable(iterator))
+ return die_("iterator claims file is writable when tester thinks it should not be; are you running as root?\n");
+
+ printf("iterate forwards\n");
+
+ if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_STREAMINFO)
+ return die_("expected STREAMINFO type from FLAC__metadata_simple_iterator_get_block_type()");
+ if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
+ return die_("getting block 0");
+ if(block->type != FLAC__METADATA_TYPE_STREAMINFO)
+ return die_("expected STREAMINFO type");
+ if(block->is_last)
+ return die_("expected is_last to be false");
+ if(block->length != FLAC__STREAM_METADATA_STREAMINFO_LENGTH)
+ return die_("bad STREAMINFO length");
+ /* check to see if some basic data matches (c.f. generate_file_()) */
+ if(block->data.stream_info.channels != 1)
+ return die_("mismatch in channels");
+ if(block->data.stream_info.bits_per_sample != 8)
+ return die_("mismatch in bits_per_sample");
+ if(block->data.stream_info.sample_rate != 44100)
+ return die_("mismatch in sample_rate");
+ if(block->data.stream_info.min_blocksize != 576)
+ return die_("mismatch in min_blocksize");
+ if(block->data.stream_info.max_blocksize != 576)
+ return die_("mismatch in max_blocksize");
+ FLAC__metadata_object_delete(block);
+
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("forward iterator ended early");
+ our_current_position++;
+
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("forward iterator ended early");
+ our_current_position++;
+
+ if(FLAC__metadata_simple_iterator_get_block_type(iterator) != FLAC__METADATA_TYPE_PADDING)
+ return die_("expected PADDING type from FLAC__metadata_simple_iterator_get_block_type()");
+ if(0 == (block = FLAC__metadata_simple_iterator_get_block(iterator)))
+ return die_("getting block 2");
+ if(block->type != FLAC__METADATA_TYPE_PADDING)
+ return die_("expected PADDING type");
+ if(!block->is_last)
+ return die_("expected is_last to be true");
+ /* check to see if some basic data matches (c.f. generate_file_()) */
+ if(block->length != 1234)
+ return die_("bad PADDING length");
+ FLAC__metadata_object_delete(block);
+
+ if(FLAC__metadata_simple_iterator_next(iterator))
+ return die_("forward iterator returned true but should have returned false");
+
+ printf("iterate backwards\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("reverse iterator ended early");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("reverse iterator ended early");
+ if(FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("reverse iterator returned true but should have returned false");
+
+ printf("testing FLAC__metadata_simple_iterator_set_block() on read-only file...\n");
+
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, (FLAC__StreamMetadata*)99, false))
+ printf("OK: FLAC__metadata_simple_iterator_set_block() returned false like it should\n");
+ else
+ return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
+
+ FLAC__metadata_simple_iterator_delete(iterator);
+
+ /************************************************************/
+
+ printf("simple iterator on writable file\n");
+
+ if(!change_stats_(flacfilename(/*is_ogg=*/false), /*read-only=*/false))
+ return false;
+
+ printf("creating APPLICATION block\n");
+
+ if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
+ return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
+ memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+
+ printf("creating PADDING block\n");
+
+ if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+ return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)");
+ padding->length = 20;
+
+ if(0 == (iterator = FLAC__metadata_simple_iterator_new()))
+ return die_("FLAC__metadata_simple_iterator_new()");
+
+ if(!FLAC__metadata_simple_iterator_init(iterator, flacfilename(/*is_ogg=*/false), /*read_only=*/false, /*preserve_file_stats=*/false))
+ return die_("FLAC__metadata_simple_iterator_init() returned false");
+ our_current_position = 0;
+
+ printf("is writable = %u\n", (unsigned)FLAC__metadata_simple_iterator_is_writable(iterator));
+
+ printf("[S]VP\ttry to write over STREAMINFO block...\n");
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
+ printf("\tFLAC__metadata_simple_iterator_set_block() returned false like it should\n");
+ else
+ return die_("FLAC__metadata_simple_iterator_set_block() returned true but shouldn't have");
+
+ printf("[S]VP\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("S[V]P\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SV[P]\tinsert PADDING after, don't expand into padding\n");
+ padding->length = 25;
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+ if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+ return false;
+
+ printf("SVP[P]\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("SV[P]P\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("S[V]PP\tinsert PADDING after, don't expand into padding\n");
+ padding->length = 30;
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+ if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+ return false;
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[P]PP\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("S[V]PPP\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("[S]VPPP\tdelete (STREAMINFO block), must fail\n");
+ if(FLAC__metadata_simple_iterator_delete_block(iterator, false))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false) should have returned false", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("[S]VPPP\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("S[V]PPP\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SV[P]PP\tdelete (middle block), replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, true)", iterator);
+ our_current_position--;
+
+ printf("S[V]PPP\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SV[P]PP\tdelete (middle block), don't replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+ delete_from_our_metadata_(our_current_position--);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("S[V]PP\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SV[P]P\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SVP[P]\tdelete (last block), replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, true))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+ our_current_position--;
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[P]P\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SVP[P]\tdelete (last block), don't replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+ delete_from_our_metadata_(our_current_position--);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[P]\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("S[V]P\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("[S]VP\tset STREAMINFO (change sample rate)\n");
+ FLAC__ASSERT(our_current_position == 0);
+ block = FLAC__metadata_simple_iterator_get_block(iterator);
+ block->data.stream_info.sample_rate = 32000;
+ if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, block, false))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, block, false)", iterator);
+ FLAC__metadata_object_delete(block);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("[S]VP\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("S[V]P\tinsert APPLICATION after, expand into padding of exceeding size\n");
+ app->data.application.id[0] = 'e'; /* twiddle the id so that our comparison doesn't miss transposition */
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+ if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+ return false;
+ our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]P\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SVA[P]\tset APPLICATION, expand into padding of exceeding size\n");
+ app->data.application.id[0] = 'f'; /* twiddle the id */
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+ if(!insert_to_our_metadata_(app, our_current_position, /*copy=*/true))
+ return false;
+ our_metadata_.blocks[our_current_position+1]->length -= (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) + app->length;
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVA[A]P\tset APPLICATION (grow), don't expand into padding\n");
+ app->data.application.id[0] = 'g'; /* twiddle the id */
+ if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVA[A]P\tset APPLICATION (shrink), don't fill in with padding\n");
+ app->data.application.id[0] = 'h'; /* twiddle the id */
+ if(!FLAC__metadata_object_application_set_data(app, data, 12, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVA[A]P\tset APPLICATION (grow), expand into padding of exceeding size\n");
+ app->data.application.id[0] = 'i'; /* twiddle the id */
+ if(!FLAC__metadata_object_application_set_data(app, data, sizeof(data), true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ our_metadata_.blocks[our_current_position+1]->length -= (sizeof(data) - 12);
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVA[A]P\tset APPLICATION (shrink), fill in with padding\n");
+ app->data.application.id[0] = 'j'; /* twiddle the id */
+ if(!FLAC__metadata_object_application_set_data(app, data, 23, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/true))
+ return die_("copying object");
+ our_metadata_.blocks[our_current_position+1]->length = sizeof(data) - 23 - FLAC__STREAM_METADATA_HEADER_LENGTH;
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVA[A]PP\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SVAA[P]P\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SVAAP[P]\tset PADDING (shrink), don't fill in with padding\n");
+ padding->length = 5;
+ if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVAAP[P]\tset APPLICATION (grow)\n");
+ app->data.application.id[0] = 'k'; /* twiddle the id */
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, false))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, false)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVAAP[A]\tset PADDING (equal)\n");
+ padding->length = 27;
+ if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, false))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, false)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVAAP[P]\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("SVAA[P]P\tdelete (middle block), don't replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+ delete_from_our_metadata_(our_current_position--);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVA[A]P\tdelete (middle block), don't replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+ delete_from_our_metadata_(our_current_position--);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]P\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SVA[P]\tinsert PADDING after\n");
+ padding->length = 5;
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+ if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+ return false;
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVAP[P]\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("SVA[P]P\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is too small\n");
+ if(!FLAC__metadata_object_application_set_data(app, data, 32, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]PP\tset APPLICATION (grow), try to expand into padding which is 'close' but still too small\n");
+ if(!FLAC__metadata_object_application_set_data(app, data, 60, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]PP\tset APPLICATION (grow), expand into padding which will leave 0-length pad\n");
+ if(!FLAC__metadata_object_application_set_data(app, data, 87, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ our_metadata_.blocks[our_current_position+1]->length = 0;
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]PP\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
+ if(!FLAC__metadata_object_application_set_data(app, data, 91, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ delete_from_our_metadata_(our_current_position+1);
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]P\tset APPLICATION (grow), expand into padding which is exactly consumed\n");
+ if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ delete_from_our_metadata_(our_current_position+1);
+ our_metadata_.blocks[our_current_position]->is_last = true;
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]\tset PADDING (equal size)\n");
+ padding->length = app->length;
+ if(!replace_in_our_metadata_(padding, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_set_block(iterator, padding, true))
+ return die_ss_("FLAC__metadata_simple_iterator_set_block(iterator, padding, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[P]\tinsert PADDING after\n");
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+ if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+ return false;
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVP[P]\tinsert PADDING after\n");
+ padding->length = 5;
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, padding, false)", iterator);
+ if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+ return false;
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVPP[P]\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("SVP[P]P\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("SV[P]PP\tprev\n");
+ if(!FLAC__metadata_simple_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is too small\n");
+ if(!FLAC__metadata_object_application_set_data(app, data, 101, true))
+ return die_("setting APPLICATION data");
+ if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+ delete_from_our_metadata_(our_current_position--);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("S[V]PPP\tinsert APPLICATION after, try to expand into padding which is 'close' but still too small\n");
+ if(!FLAC__metadata_object_application_set_data(app, data, 97, true))
+ return die_("setting APPLICATION data");
+ if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]PPP\tdelete (middle block), don't replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+ delete_from_our_metadata_(our_current_position--);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("S[V]PPP\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
+ if(!FLAC__metadata_object_application_set_data(app, data, 100, true))
+ return die_("setting APPLICATION data");
+ if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+ return die_("copying object");
+ delete_from_our_metadata_(our_current_position+1);
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+ delete_from_our_metadata_(our_current_position--);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("S[V]PP\tinsert APPLICATION after, expand into padding which will leave 0-length pad\n");
+ if(!FLAC__metadata_object_application_set_data(app, data, 96, true))
+ return die_("setting APPLICATION data");
+ if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+ return die_("copying object");
+ our_metadata_.blocks[our_current_position+1]->length = 0;
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]PP\tdelete (middle block), don't replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+ delete_from_our_metadata_(our_current_position--);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("S[V]PP\tnext\n");
+ if(!FLAC__metadata_simple_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SV[P]P\tdelete (middle block), don't replace with padding\n");
+ if(!FLAC__metadata_simple_iterator_delete_block(iterator, false))
+ return die_ss_("FLAC__metadata_simple_iterator_delete_block(iterator, false)", iterator);
+ delete_from_our_metadata_(our_current_position--);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("S[V]P\tinsert APPLICATION after, expand into padding which is exactly consumed\n");
+ if(!FLAC__metadata_object_application_set_data(app, data, 1, true))
+ return die_("setting APPLICATION data");
+ if(!insert_to_our_metadata_(app, ++our_current_position, /*copy=*/true))
+ return die_("copying object");
+ delete_from_our_metadata_(our_current_position+1);
+ if(!FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true))
+ return die_ss_("FLAC__metadata_simple_iterator_insert_block_after(iterator, app, true)", iterator);
+
+ if(!test_file_(/*is_ogg=*/false, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("delete simple iterator\n");
+
+ FLAC__metadata_simple_iterator_delete(iterator);
+
+ FLAC__metadata_object_delete(app);
+ FLAC__metadata_object_delete(padding);
+
+ if(!remove_file_(flacfilename(/*is_ogg=*/false)))
+ return false;
+
+ return true;
+}
+
+static FLAC__bool test_level_2_(FLAC__bool filename_based, FLAC__bool is_ogg)
+{
+ FLAC__Metadata_Iterator *iterator;
+ FLAC__Metadata_Chain *chain;
+ FLAC__StreamMetadata *block, *app, *padding;
+ FLAC__byte data[2000];
+ unsigned our_current_position;
+
+ /* initialize 'data' to avoid Valgrind errors */
+ memset(data, 0, sizeof(data));
+
+ printf("\n\n++++++ testing level 2 interface (%s-based, %s FLAC)\n", filename_based? "filename":"callback", is_ogg? "Ogg":"native");
+
+ printf("generate read-only file\n");
+
+ if(!generate_file_(/*include_extras=*/false, is_ogg))
+ return false;
+
+ if(!change_stats_(flacfilename(is_ogg), /*read_only=*/true))
+ return false;
+
+ printf("create chain\n");
+
+ if(0 == (chain = FLAC__metadata_chain_new()))
+ return die_("allocating chain");
+
+ printf("read chain\n");
+
+ if(!read_chain_(chain, flacfilename(is_ogg), filename_based, is_ogg))
+ return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+
+ printf("[S]VP\ttest initial metadata\n");
+
+ if(!compare_chain_(chain, 0, 0))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ if(is_ogg)
+ goto end;
+
+ printf("switch file to read-write\n");
+
+ if(!change_stats_(flacfilename(is_ogg), /*read-only=*/false))
+ return false;
+
+ printf("create iterator\n");
+ if(0 == (iterator = FLAC__metadata_iterator_new()))
+ return die_("allocating memory for iterator");
+
+ our_current_position = 0;
+
+ FLAC__metadata_iterator_init(iterator, chain);
+
+ if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
+ return die_("getting block from iterator");
+
+ FLAC__ASSERT(block->type == FLAC__METADATA_TYPE_STREAMINFO);
+
+ printf("[S]VP\tmodify STREAMINFO, write\n");
+
+ block->data.stream_info.sample_rate = 32000;
+ if(!replace_in_our_metadata_(block, our_current_position, /*copy=*/true))
+ return die_("copying object");
+
+ if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/true, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, false, true)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("[S]VP\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("S[V]P\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SV[P]\treplace PADDING with identical-size APPLICATION\n");
+ if(0 == (block = FLAC__metadata_iterator_get_block(iterator)))
+ return die_("getting block from iterator");
+ if(0 == (app = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)))
+ return die_("FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION)");
+ memcpy(app->data.application.id, "duh", (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8));
+ if(!FLAC__metadata_object_application_set_data(app, data, block->length-(FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_iterator_set_block(iterator, app))
+ return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+ if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]\tshrink APPLICATION, don't use padding\n");
+ if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("copying object");
+ if(!FLAC__metadata_object_application_set_data(app, data, 26, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_iterator_set_block(iterator, app))
+ return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+ if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]\tgrow APPLICATION, don't use padding\n");
+ if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("copying object");
+ if(!FLAC__metadata_object_application_set_data(app, data, 28, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_iterator_set_block(iterator, app))
+ return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+ if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]\tgrow APPLICATION, use padding, but last block is not padding\n");
+ if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("copying object");
+ if(!FLAC__metadata_object_application_set_data(app, data, 36, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_iterator_set_block(iterator, app))
+ return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+ if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, but delta is too small for new PADDING block\n");
+ if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("copying object");
+ if(!FLAC__metadata_object_application_set_data(app, data, 33, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_iterator_set_block(iterator, app))
+ return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+ if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]\tshrink APPLICATION, use padding, last block is not padding, delta is enough for new PADDING block\n");
+ if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+ return die_("creating PADDING block");
+ if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("copying object");
+ if(!FLAC__metadata_object_application_set_data(app, data, 29, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ padding->length = 0;
+ if(!insert_to_our_metadata_(padding, our_current_position+1, /*copy=*/false))
+ return die_("internal error");
+ if(!FLAC__metadata_iterator_set_block(iterator, app))
+ return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+ if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]P\tshrink APPLICATION, use padding, last block is padding\n");
+ if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("copying object");
+ if(!FLAC__metadata_object_application_set_data(app, data, 16, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ our_metadata_.blocks[our_current_position+1]->length = 13;
+ if(!FLAC__metadata_iterator_set_block(iterator, app))
+ return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+ if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding, but delta is too small\n");
+ if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("copying object");
+ if(!FLAC__metadata_object_application_set_data(app, data, 50, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ if(!FLAC__metadata_iterator_set_block(iterator, app))
+ return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+ if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exceeding size\n");
+ if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("copying object");
+ if(!FLAC__metadata_object_application_set_data(app, data, 56, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ our_metadata_.blocks[our_current_position+1]->length -= (56 - 50);
+ if(!FLAC__metadata_iterator_set_block(iterator, app))
+ return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+ if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]P\tgrow APPLICATION, use padding, last block is padding of exact size\n");
+ if(0 == (app = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("copying object");
+ if(!FLAC__metadata_object_application_set_data(app, data, 67, true))
+ return die_("setting APPLICATION data");
+ if(!replace_in_our_metadata_(app, our_current_position, /*copy=*/true))
+ return die_("copying object");
+ delete_from_our_metadata_(our_current_position+1);
+ if(!FLAC__metadata_iterator_set_block(iterator, app))
+ return die_c_("FLAC__metadata_iterator_set_block(iterator, app)", FLAC__metadata_chain_status(chain));
+
+ if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV[A]\tprev\n");
+ if(!FLAC__metadata_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("S[V]A\tprev\n");
+ if(!FLAC__metadata_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("[S]VA\tinsert PADDING before STREAMINFO (should fail)\n");
+ if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+ return die_("creating PADDING block");
+ padding->length = 30;
+ if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+ printf("\tFLAC__metadata_iterator_insert_block_before() returned false like it should\n");
+ else
+ return die_("FLAC__metadata_iterator_insert_block_before() should have returned false");
+
+ printf("[S]VP\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("S[V]A\tinsert PADDING after\n");
+ if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+ return die_("copying metadata");
+ if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
+ return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
+
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+
+ printf("SV[P]A\tinsert PADDING before\n");
+ if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("creating PADDING block");
+ padding->length = 17;
+ if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+ return die_("copying metadata");
+ if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+ return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
+
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+
+ printf("SV[P]PA\tinsert PADDING before\n");
+ if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[our_current_position])))
+ return die_("creating PADDING block");
+ padding->length = 0;
+ if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+ return die_("copying metadata");
+ if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+ return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
+
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+
+ printf("SV[P]PPA\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SVP[P]PA\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SVPP[P]A\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SVPPP[A]\tinsert PADDING after\n");
+ if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
+ return die_("creating PADDING block");
+ padding->length = 57;
+ if(!insert_to_our_metadata_(padding, ++our_current_position, /*copy=*/true))
+ return die_("copying metadata");
+ if(!FLAC__metadata_iterator_insert_block_after(iterator, padding))
+ return die_("FLAC__metadata_iterator_insert_block_after(iterator, padding)");
+
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+
+ printf("SVPPPA[P]\tinsert PADDING before\n");
+ if(0 == (padding = FLAC__metadata_object_clone(our_metadata_.blocks[2])))
+ return die_("creating PADDING block");
+ padding->length = 99;
+ if(!insert_to_our_metadata_(padding, our_current_position, /*copy=*/true))
+ return die_("copying metadata");
+ if(!FLAC__metadata_iterator_insert_block_before(iterator, padding))
+ return die_("FLAC__metadata_iterator_insert_block_before(iterator, padding)");
+
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+
+ printf("delete iterator\n");
+ FLAC__metadata_iterator_delete(iterator);
+ our_current_position = 0;
+
+ printf("SVPPPAPP\tmerge padding\n");
+ FLAC__metadata_chain_merge_padding(chain);
+ our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[3]->length);
+ our_metadata_.blocks[2]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[4]->length);
+ our_metadata_.blocks[6]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[7]->length);
+ delete_from_our_metadata_(7);
+ delete_from_our_metadata_(4);
+ delete_from_our_metadata_(3);
+
+ if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, 0, 0))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SVPAP\tsort padding\n");
+ FLAC__metadata_chain_sort_padding(chain);
+ our_metadata_.blocks[4]->length += (FLAC__STREAM_METADATA_HEADER_LENGTH + our_metadata_.blocks[2]->length);
+ delete_from_our_metadata_(2);
+
+ if(!write_chain_(chain, /*use_padding=*/true, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, true, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, 0, 0))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("create iterator\n");
+ if(0 == (iterator = FLAC__metadata_iterator_new()))
+ return die_("allocating memory for iterator");
+
+ our_current_position = 0;
+
+ FLAC__metadata_iterator_init(iterator, chain);
+
+ printf("[S]VAP\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("S[V]AP\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SV[A]P\tdelete middle block, replace with padding\n");
+ if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+ return die_("creating PADDING block");
+ padding->length = 71;
+ if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
+ return die_("copying object");
+ if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
+ return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
+
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+
+ printf("S[V]PP\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SV[P]P\tdelete middle block, don't replace with padding\n");
+ delete_from_our_metadata_(our_current_position--);
+ if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+ return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
+
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+
+ printf("S[V]P\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SV[P]\tdelete last block, replace with padding\n");
+ if(0 == (padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING)))
+ return die_("creating PADDING block");
+ padding->length = 219;
+ if(!replace_in_our_metadata_(padding, our_current_position--, /*copy=*/false))
+ return die_("copying object");
+ if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/true))
+ return die_c_("FLAC__metadata_iterator_delete_block(iterator, true)", FLAC__metadata_chain_status(chain));
+
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+
+ printf("S[V]P\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+ our_current_position++;
+
+ printf("SV[P]\tdelete last block, don't replace with padding\n");
+ delete_from_our_metadata_(our_current_position--);
+ if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+ return die_c_("FLAC__metadata_iterator_delete_block(iterator, false)", FLAC__metadata_chain_status(chain));
+
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+
+ printf("S[V]\tprev\n");
+ if(!FLAC__metadata_iterator_prev(iterator))
+ return die_("iterator ended early\n");
+ our_current_position--;
+
+ printf("[S]V\tdelete STREAMINFO block, should fail\n");
+ if(FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+ return die_("FLAC__metadata_iterator_delete_block() on STREAMINFO should have failed but didn't");
+
+ if(!compare_chain_(chain, our_current_position, FLAC__metadata_iterator_get_block(iterator)))
+ return false;
+
+ printf("delete iterator\n");
+ FLAC__metadata_iterator_delete(iterator);
+ our_current_position = 0;
+
+ printf("SV\tmerge padding\n");
+ FLAC__metadata_chain_merge_padding(chain);
+
+ if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, 0, 0))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+ printf("SV\tsort padding\n");
+ FLAC__metadata_chain_sort_padding(chain);
+
+ if(!write_chain_(chain, /*use_padding=*/false, /*preserve_file_stats=*/false, filename_based, flacfilename(is_ogg)))
+ return die_c_("during FLAC__metadata_chain_write(chain, false, false)", FLAC__metadata_chain_status(chain));
+ if(!compare_chain_(chain, 0, 0))
+ return false;
+ if(!test_file_(is_ogg, decoder_metadata_callback_compare_))
+ return false;
+
+end:
+ printf("delete chain\n");
+
+ FLAC__metadata_chain_delete(chain);
+
+ if(!remove_file_(flacfilename(is_ogg)))
+ return false;
+
+ return true;
+}
+
+static FLAC__bool test_level_2_misc_(FLAC__bool is_ogg)
+{
+ FLAC__Metadata_Iterator *iterator;
+ FLAC__Metadata_Chain *chain;
+ FLAC__IOCallbacks callbacks;
+
+ memset(&callbacks, 0, sizeof(callbacks));
+ callbacks.read = (FLAC__IOCallback_Read)fread;
+#ifdef FLAC__VALGRIND_TESTING
+ callbacks.write = chain_write_cb_;
+#else
+ callbacks.write = (FLAC__IOCallback_Write)fwrite;
+#endif
+ callbacks.seek = chain_seek_cb_;
+ callbacks.tell = chain_tell_cb_;
+ callbacks.eof = chain_eof_cb_;
+
+ printf("\n\n++++++ testing level 2 interface (mismatched read/write protections)\n");
+
+ printf("generate file\n");
+
+ if(!generate_file_(/*include_extras=*/false, is_ogg))
+ return false;
+
+ printf("create chain\n");
+
+ if(0 == (chain = FLAC__metadata_chain_new()))
+ return die_("allocating chain");
+
+ printf("read chain (filename-based)\n");
+
+ if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
+ return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+
+ printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
+ {
+ if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
+ return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+ if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+ return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
+ printf(" OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+ }
+
+ printf("read chain (filename-based)\n");
+
+ if(!FLAC__metadata_chain_read(chain, flacfilename(is_ogg)))
+ return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+
+ printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
+ {
+ if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
+ return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+ if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+ return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
+ printf(" OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+ }
+
+ printf("read chain (callback-based)\n");
+ {
+ FILE *file = fopen(flacfilename(is_ogg), "rb");
+ if(0 == file)
+ return die_("opening file");
+ if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
+ fclose(file);
+ return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+ }
+ fclose(file);
+ }
+
+ printf("write chain with wrong method FLAC__metadata_chain_write()\n");
+ {
+ if(FLAC__metadata_chain_write(chain, /*use_padding=*/false, /*preserve_file_stats=*/false))
+ return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+ if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH)
+ return die_c_("expected FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH", FLAC__metadata_chain_status(chain));
+ printf(" OK: FLAC__metadata_chain_write() returned false,FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH like it should\n");
+ }
+
+ printf("read chain (callback-based)\n");
+ {
+ FILE *file = fopen(flacfilename(is_ogg), "rb");
+ if(0 == file)
+ return die_("opening file");
+ if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
+ fclose(file);
+ return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+ }
+ fclose(file);
+ }
+
+ printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
+
+ if(!FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
+ printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned false like it should\n");
+ else
+ return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned true but shouldn't have");
+
+ printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks_and_tempfile()\n");
+ {
+ if(FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, /*use_padding=*/false, 0, callbacks, 0, callbacks))
+ return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+ if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
+ return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
+ printf(" OK: FLAC__metadata_chain_write_with_callbacks_and_tempfile() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
+ }
+
+ printf("read chain (callback-based)\n");
+ {
+ FILE *file = fopen(flacfilename(is_ogg), "rb");
+ if(0 == file)
+ return die_("opening file");
+ if(!FLAC__metadata_chain_read_with_callbacks(chain, (FLAC__IOHandle)file, callbacks)) {
+ fclose(file);
+ return die_c_("reading chain", FLAC__metadata_chain_status(chain));
+ }
+ fclose(file);
+ }
+
+ printf("create iterator\n");
+ if(0 == (iterator = FLAC__metadata_iterator_new()))
+ return die_("allocating memory for iterator");
+
+ FLAC__metadata_iterator_init(iterator, chain);
+
+ printf("[S]VP\tnext\n");
+ if(!FLAC__metadata_iterator_next(iterator))
+ return die_("iterator ended early\n");
+
+ printf("S[V]P\tdelete VORBIS_COMMENT, write\n");
+ if(!FLAC__metadata_iterator_delete_block(iterator, /*replace_with_padding=*/false))
+ return die_c_("block delete failed\n", FLAC__metadata_chain_status(chain));
+
+ printf("testing FLAC__metadata_chain_check_if_tempfile_needed()... ");
+
+ if(FLAC__metadata_chain_check_if_tempfile_needed(chain, /*use_padding=*/false))
+ printf("OK: FLAC__metadata_chain_check_if_tempfile_needed() returned true like it should\n");
+ else
+ return die_("FLAC__metadata_chain_check_if_tempfile_needed() returned false but shouldn't have");
+
+ printf("write chain with wrong method FLAC__metadata_chain_write_with_callbacks()\n");
+ {
+ if(FLAC__metadata_chain_write_with_callbacks(chain, /*use_padding=*/false, 0, callbacks))
+ return die_c_("mismatched write should have failed", FLAC__metadata_chain_status(chain));
+ if(FLAC__metadata_chain_status(chain) != FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL)
+ return die_c_("expected FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL", FLAC__metadata_chain_status(chain));
+ printf(" OK: FLAC__metadata_chain_write_with_callbacks() returned false,FLAC__METADATA_CHAIN_STATUS_WRONG_WRITE_CALL like it should\n");
+ }
+
+ printf("delete iterator\n");
+
+ FLAC__metadata_iterator_delete(iterator);
+
+ printf("delete chain\n");
+
+ FLAC__metadata_chain_delete(chain);
+
+ if(!remove_file_(flacfilename(is_ogg)))
+ return false;
+
+ return true;
+}
+
+FLAC__bool test_metadata_file_manipulation(void)
+{
+ printf("\n+++ libFLAC unit test: metadata manipulation\n\n");
+
+ our_metadata_.num_blocks = 0;
+
+ if(!test_level_0_())
+ return false;
+
+ if(!test_level_1_())
+ return false;
+
+ if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/false)) /* filename-based */
+ return false;
+ if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/false)) /* callback-based */
+ return false;
+ if(!test_level_2_misc_(/*is_ogg=*/false))
+ return false;
+
+ if(FLAC_API_SUPPORTS_OGG_FLAC) {
+ if(!test_level_2_(/*filename_based=*/true, /*is_ogg=*/true)) /* filename-based */
+ return false;
+ if(!test_level_2_(/*filename_based=*/false, /*is_ogg=*/true)) /* callback-based */
+ return false;
+#if 0
+ /* when ogg flac write is supported, will have to add this: */
+ if(!test_level_2_misc_(/*is_ogg=*/true))
+ return false;
+#endif
+ }
+
+ return true;
+}
diff --git a/src/FLAC/src/test_libFLAC/metadata_object.c b/src/FLAC/src/test_libFLAC/metadata_object.c
new file mode 100644
index 0000000..e3089aa
--- /dev/null
+++ b/src/FLAC/src/test_libFLAC/metadata_object.c
@@ -0,0 +1,2299 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/metadata.h"
+#include "test_libs_common/metadata_utils.h"
+#include "metadata.h"
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp() */
+
+static FLAC__byte *make_dummydata_(FLAC__byte *dummydata, unsigned len)
+{
+ FLAC__byte *ret;
+
+ if(0 == (ret = (FLAC__byte*)malloc(len))) {
+ printf("FAILED, malloc error\n");
+ exit(1);
+ }
+ else
+ memcpy(ret, dummydata, len);
+
+ return ret;
+}
+
+static FLAC__bool compare_track_(const FLAC__StreamMetadata_CueSheet_Track *from, const FLAC__StreamMetadata_CueSheet_Track *to)
+{
+ unsigned i;
+
+ if(from->offset != to->offset) {
+#ifdef _MSC_VER
+ printf("FAILED, track offset mismatch, expected %I64u, got %I64u\n", to->offset, from->offset);
+#else
+ printf("FAILED, track offset mismatch, expected %llu, got %llu\n", (unsigned long long)to->offset, (unsigned long long)from->offset);
+#endif
+ return false;
+ }
+ if(from->number != to->number) {
+ printf("FAILED, track number mismatch, expected %u, got %u\n", (unsigned)to->number, (unsigned)from->number);
+ return false;
+ }
+ if(0 != strcmp(from->isrc, to->isrc)) {
+ printf("FAILED, track number mismatch, expected %s, got %s\n", to->isrc, from->isrc);
+ return false;
+ }
+ if(from->type != to->type) {
+ printf("FAILED, track type mismatch, expected %u, got %u\n", (unsigned)to->type, (unsigned)from->type);
+ return false;
+ }
+ if(from->pre_emphasis != to->pre_emphasis) {
+ printf("FAILED, track pre_emphasis mismatch, expected %u, got %u\n", (unsigned)to->pre_emphasis, (unsigned)from->pre_emphasis);
+ return false;
+ }
+ if(from->num_indices != to->num_indices) {
+ printf("FAILED, track num_indices mismatch, expected %u, got %u\n", (unsigned)to->num_indices, (unsigned)from->num_indices);
+ return false;
+ }
+ if(0 == to->indices || 0 == from->indices) {
+ if(to->indices != from->indices) {
+ printf("FAILED, track indices mismatch\n");
+ return false;
+ }
+ }
+ else {
+ for(i = 0; i < to->num_indices; i++) {
+ if(from->indices[i].offset != to->indices[i].offset) {
+#ifdef _MSC_VER
+ printf("FAILED, track indices[%u].offset mismatch, expected %I64u, got %I64u\n", i, to->indices[i].offset, from->indices[i].offset);
+#else
+ printf("FAILED, track indices[%u].offset mismatch, expected %llu, got %llu\n", i, (unsigned long long)to->indices[i].offset, (unsigned long long)from->indices[i].offset);
+#endif
+ return false;
+ }
+ if(from->indices[i].number != to->indices[i].number) {
+ printf("FAILED, track indices[%u].number mismatch, expected %u, got %u\n", i, (unsigned)to->indices[i].number, (unsigned)from->indices[i].number);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static FLAC__bool compare_seekpoint_array_(const FLAC__StreamMetadata_SeekPoint *from, const FLAC__StreamMetadata_SeekPoint *to, unsigned n)
+{
+ unsigned i;
+
+ FLAC__ASSERT(0 != from);
+ FLAC__ASSERT(0 != to);
+
+ for(i = 0; i < n; i++) {
+ if(from[i].sample_number != to[i].sample_number) {
+#ifdef _MSC_VER
+ printf("FAILED, point[%u].sample_number mismatch, expected %I64u, got %I64u\n", i, to[i].sample_number, from[i].sample_number);
+#else
+ printf("FAILED, point[%u].sample_number mismatch, expected %llu, got %llu\n", i, (unsigned long long)to[i].sample_number, (unsigned long long)from[i].sample_number);
+#endif
+ return false;
+ }
+ if(from[i].stream_offset != to[i].stream_offset) {
+#ifdef _MSC_VER
+ printf("FAILED, point[%u].stream_offset mismatch, expected %I64u, got %I64u\n", i, to[i].stream_offset, from[i].stream_offset);
+#else
+ printf("FAILED, point[%u].stream_offset mismatch, expected %llu, got %llu\n", i, (unsigned long long)to[i].stream_offset, (unsigned long long)from[i].stream_offset);
+#endif
+ return false;
+ }
+ if(from[i].frame_samples != to[i].frame_samples) {
+ printf("FAILED, point[%u].frame_samples mismatch, expected %u, got %u\n", i, to[i].frame_samples, from[i].frame_samples);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static FLAC__bool check_seektable_(const FLAC__StreamMetadata *block, unsigned num_points, const FLAC__StreamMetadata_SeekPoint *array)
+{
+ const unsigned expected_length = num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+
+ if(block->length != expected_length) {
+ printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+ return false;
+ }
+ if(block->data.seek_table.num_points != num_points) {
+ printf("FAILED, expected %u point, got %u\n", num_points, block->data.seek_table.num_points);
+ return false;
+ }
+ if(0 == array) {
+ if(0 != block->data.seek_table.points) {
+ printf("FAILED, 'points' pointer is not null\n");
+ return false;
+ }
+ }
+ else {
+ if(!compare_seekpoint_array_(block->data.seek_table.points, array, num_points))
+ return false;
+ }
+ printf("OK\n");
+
+ return true;
+}
+
+static void entry_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, const char *field)
+{
+ entry->length = strlen(field);
+ entry->entry = (FLAC__byte*)malloc(entry->length+1);
+ FLAC__ASSERT(0 != entry->entry);
+ memcpy(entry->entry, field, entry->length);
+ entry->entry[entry->length] = '\0';
+}
+
+static void entry_clone_(FLAC__StreamMetadata_VorbisComment_Entry *entry)
+{
+ FLAC__byte *x = (FLAC__byte*)malloc(entry->length+1);
+ FLAC__ASSERT(0 != x);
+ memcpy(x, entry->entry, entry->length);
+ x[entry->length] = '\0';
+ entry->entry = x;
+}
+
+static void vc_calc_len_(FLAC__StreamMetadata *block)
+{
+ const FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
+ unsigned i;
+
+ block->length = FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+ block->length += vc->vendor_string.length;
+ block->length += FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN / 8;
+ for(i = 0; i < vc->num_comments; i++) {
+ block->length += FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN / 8;
+ block->length += vc->comments[i].length;
+ }
+}
+
+static void vc_resize_(FLAC__StreamMetadata *block, unsigned num)
+{
+ FLAC__StreamMetadata_VorbisComment *vc = &block->data.vorbis_comment;
+
+ if(vc->num_comments != 0) {
+ FLAC__ASSERT(0 != vc->comments);
+ if(num < vc->num_comments) {
+ unsigned i;
+ for(i = num; i < vc->num_comments; i++) {
+ if(0 != vc->comments[i].entry)
+ free(vc->comments[i].entry);
+ }
+ }
+ }
+ if(num == 0) {
+ if(0 != vc->comments) {
+ free(vc->comments);
+ vc->comments = 0;
+ }
+ }
+ else {
+ vc->comments = (FLAC__StreamMetadata_VorbisComment_Entry*)realloc(vc->comments, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*num);
+ FLAC__ASSERT(0 != vc->comments);
+ if(num > vc->num_comments)
+ memset(vc->comments+vc->num_comments, 0, sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(num-vc->num_comments));
+ }
+
+ vc->num_comments = num;
+ vc_calc_len_(block);
+}
+
+static int vc_find_from_(FLAC__StreamMetadata *block, const char *name, unsigned start)
+{
+ const unsigned n = strlen(name);
+ unsigned i;
+ for(i = start; i < block->data.vorbis_comment.num_comments; i++) {
+ const FLAC__StreamMetadata_VorbisComment_Entry *entry = &block->data.vorbis_comment.comments[i];
+ if(entry->length > n && 0 == strncmp((const char *)entry->entry, name, n) && entry->entry[n] == '=')
+ return (int)i;
+ }
+ return -1;
+}
+
+static void vc_set_vs_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, const char *field)
+{
+ if(0 != block->data.vorbis_comment.vendor_string.entry)
+ free(block->data.vorbis_comment.vendor_string.entry);
+ entry_new_(entry, field);
+ block->data.vorbis_comment.vendor_string = *entry;
+ vc_calc_len_(block);
+}
+
+static void vc_set_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, unsigned pos, const char *field)
+{
+ if(0 != block->data.vorbis_comment.comments[pos].entry)
+ free(block->data.vorbis_comment.comments[pos].entry);
+ entry_new_(entry, field);
+ block->data.vorbis_comment.comments[pos] = *entry;
+ vc_calc_len_(block);
+}
+
+static void vc_insert_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, unsigned pos, const char *field)
+{
+ vc_resize_(block, block->data.vorbis_comment.num_comments+1);
+ memmove(&block->data.vorbis_comment.comments[pos+1], &block->data.vorbis_comment.comments[pos], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(block->data.vorbis_comment.num_comments-1-pos));
+ memset(&block->data.vorbis_comment.comments[pos], 0, sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+ vc_set_new_(entry, block, pos, field);
+ vc_calc_len_(block);
+}
+
+static void vc_delete_(FLAC__StreamMetadata *block, unsigned pos)
+{
+ if(0 != block->data.vorbis_comment.comments[pos].entry)
+ free(block->data.vorbis_comment.comments[pos].entry);
+ memmove(&block->data.vorbis_comment.comments[pos], &block->data.vorbis_comment.comments[pos+1], sizeof(FLAC__StreamMetadata_VorbisComment_Entry)*(block->data.vorbis_comment.num_comments-pos-1));
+ block->data.vorbis_comment.comments[block->data.vorbis_comment.num_comments-1].entry = 0;
+ block->data.vorbis_comment.comments[block->data.vorbis_comment.num_comments-1].length = 0;
+ vc_resize_(block, block->data.vorbis_comment.num_comments-1);
+ vc_calc_len_(block);
+}
+
+static void vc_replace_new_(FLAC__StreamMetadata_VorbisComment_Entry *entry, FLAC__StreamMetadata *block, const char *field, FLAC__bool all)
+{
+ int indx;
+ char field_name[256];
+ const char *eq = strchr(field, '=');
+ FLAC__ASSERT(eq>field && (unsigned)(eq-field) < sizeof(field_name));
+ memcpy(field_name, field, eq-field);
+ field_name[eq-field]='\0';
+
+ indx = vc_find_from_(block, field_name, 0);
+ if(indx < 0)
+ vc_insert_new_(entry, block, block->data.vorbis_comment.num_comments, field);
+ else {
+ vc_set_new_(entry, block, (unsigned)indx, field);
+ if(all) {
+ for(indx = indx+1; indx >= 0 && (unsigned)indx < block->data.vorbis_comment.num_comments; )
+ if((indx = vc_find_from_(block, field_name, (unsigned)indx)) >= 0)
+ vc_delete_(block, (unsigned)indx);
+ }
+ }
+
+ vc_calc_len_(block);
+}
+
+static void track_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+ track->offset = offset;
+ track->number = number;
+ memcpy(track->isrc, isrc, sizeof(track->isrc));
+ track->type = data;
+ track->pre_emphasis = pre_em;
+ track->num_indices = 0;
+ track->indices = 0;
+}
+
+static void track_clone_(FLAC__StreamMetadata_CueSheet_Track *track)
+{
+ if(track->num_indices > 0) {
+ size_t bytes = sizeof(FLAC__StreamMetadata_CueSheet_Index) * track->num_indices;
+ FLAC__StreamMetadata_CueSheet_Index *x = (FLAC__StreamMetadata_CueSheet_Index*)malloc(bytes);
+ FLAC__ASSERT(0 != x);
+ memcpy(x, track->indices, bytes);
+ track->indices = x;
+ }
+}
+
+static void cs_calc_len_(FLAC__StreamMetadata *block)
+{
+ const FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet;
+ unsigned i;
+
+ block->length = (
+ FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+ ) / 8;
+ block->length += cs->num_tracks * (
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+ ) / 8;
+ for(i = 0; i < cs->num_tracks; i++) {
+ block->length += cs->tracks[i].num_indices * (
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+ ) / 8;
+ }
+}
+
+static void tr_resize_(FLAC__StreamMetadata *block, unsigned track_num, unsigned num)
+{
+ FLAC__StreamMetadata_CueSheet_Track *tr;
+
+ FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+ tr = &block->data.cue_sheet.tracks[track_num];
+
+ if(tr->num_indices != 0) {
+ FLAC__ASSERT(0 != tr->indices);
+ }
+ if(num == 0) {
+ if(0 != tr->indices) {
+ free(tr->indices);
+ tr->indices = 0;
+ }
+ }
+ else {
+ tr->indices = (FLAC__StreamMetadata_CueSheet_Index*)realloc(tr->indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)*num);
+ FLAC__ASSERT(0 != tr->indices);
+ if(num > tr->num_indices)
+ memset(tr->indices+tr->num_indices, 0, sizeof(FLAC__StreamMetadata_CueSheet_Index)*(num-tr->num_indices));
+ }
+
+ tr->num_indices = num;
+ cs_calc_len_(block);
+}
+
+static void tr_set_new_(FLAC__StreamMetadata *block, unsigned track_num, unsigned pos, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+ FLAC__StreamMetadata_CueSheet_Track *tr;
+
+ FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+ tr = &block->data.cue_sheet.tracks[track_num];
+
+ FLAC__ASSERT(pos < tr->num_indices);
+
+ tr->indices[pos] = indx;
+
+ cs_calc_len_(block);
+}
+
+static void tr_insert_new_(FLAC__StreamMetadata *block, unsigned track_num, unsigned pos, FLAC__StreamMetadata_CueSheet_Index indx)
+{
+ FLAC__StreamMetadata_CueSheet_Track *tr;
+
+ FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+ tr = &block->data.cue_sheet.tracks[track_num];
+
+ FLAC__ASSERT(pos <= tr->num_indices);
+
+ tr_resize_(block, track_num, tr->num_indices+1);
+ memmove(&tr->indices[pos+1], &tr->indices[pos], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(tr->num_indices-1-pos));
+ tr_set_new_(block, track_num, pos, indx);
+ cs_calc_len_(block);
+}
+
+static void tr_delete_(FLAC__StreamMetadata *block, unsigned track_num, unsigned pos)
+{
+ FLAC__StreamMetadata_CueSheet_Track *tr;
+
+ FLAC__ASSERT(track_num < block->data.cue_sheet.num_tracks);
+
+ tr = &block->data.cue_sheet.tracks[track_num];
+
+ FLAC__ASSERT(pos <= tr->num_indices);
+
+ memmove(&tr->indices[pos], &tr->indices[pos+1], sizeof(FLAC__StreamMetadata_CueSheet_Index)*(tr->num_indices-pos-1));
+ tr_resize_(block, track_num, tr->num_indices-1);
+ cs_calc_len_(block);
+}
+
+static void cs_resize_(FLAC__StreamMetadata *block, unsigned num)
+{
+ FLAC__StreamMetadata_CueSheet *cs = &block->data.cue_sheet;
+
+ if(cs->num_tracks != 0) {
+ FLAC__ASSERT(0 != cs->tracks);
+ if(num < cs->num_tracks) {
+ unsigned i;
+ for(i = num; i < cs->num_tracks; i++) {
+ if(0 != cs->tracks[i].indices)
+ free(cs->tracks[i].indices);
+ }
+ }
+ }
+ if(num == 0) {
+ if(0 != cs->tracks) {
+ free(cs->tracks);
+ cs->tracks = 0;
+ }
+ }
+ else {
+ cs->tracks = (FLAC__StreamMetadata_CueSheet_Track*)realloc(cs->tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)*num);
+ FLAC__ASSERT(0 != cs->tracks);
+ if(num > cs->num_tracks)
+ memset(cs->tracks+cs->num_tracks, 0, sizeof(FLAC__StreamMetadata_CueSheet_Track)*(num-cs->num_tracks));
+ }
+
+ cs->num_tracks = num;
+ cs_calc_len_(block);
+}
+
+static void cs_set_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__StreamMetadata *block, unsigned pos, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+ track_new_(track, offset, number, isrc, data, pre_em);
+ block->data.cue_sheet.tracks[pos] = *track;
+ cs_calc_len_(block);
+}
+
+static void cs_insert_new_(FLAC__StreamMetadata_CueSheet_Track *track, FLAC__StreamMetadata *block, unsigned pos, FLAC__uint64 offset, FLAC__byte number, const char *isrc, FLAC__bool data, FLAC__bool pre_em)
+{
+ cs_resize_(block, block->data.cue_sheet.num_tracks+1);
+ memmove(&block->data.cue_sheet.tracks[pos+1], &block->data.cue_sheet.tracks[pos], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(block->data.cue_sheet.num_tracks-1-pos));
+ cs_set_new_(track, block, pos, offset, number, isrc, data, pre_em);
+ cs_calc_len_(block);
+}
+
+static void cs_delete_(FLAC__StreamMetadata *block, unsigned pos)
+{
+ if(0 != block->data.cue_sheet.tracks[pos].indices)
+ free(block->data.cue_sheet.tracks[pos].indices);
+ memmove(&block->data.cue_sheet.tracks[pos], &block->data.cue_sheet.tracks[pos+1], sizeof(FLAC__StreamMetadata_CueSheet_Track)*(block->data.cue_sheet.num_tracks-pos-1));
+ block->data.cue_sheet.tracks[block->data.cue_sheet.num_tracks-1].indices = 0;
+ block->data.cue_sheet.tracks[block->data.cue_sheet.num_tracks-1].num_indices = 0;
+ cs_resize_(block, block->data.cue_sheet.num_tracks-1);
+ cs_calc_len_(block);
+}
+
+static void pi_set_mime_type(FLAC__StreamMetadata *block, const char *s)
+{
+ if(block->data.picture.mime_type) {
+ block->length -= strlen(block->data.picture.mime_type);
+ free(block->data.picture.mime_type);
+ }
+ block->data.picture.mime_type = strdup(s);
+ FLAC__ASSERT(block->data.picture.mime_type);
+ block->length += strlen(block->data.picture.mime_type);
+}
+
+static void pi_set_description(FLAC__StreamMetadata *block, const FLAC__byte *s)
+{
+ if(block->data.picture.description) {
+ block->length -= strlen((const char *)block->data.picture.description);
+ free(block->data.picture.description);
+ }
+ block->data.picture.description = (FLAC__byte*)strdup((const char *)s);
+ FLAC__ASSERT(block->data.picture.description);
+ block->length += strlen((const char *)block->data.picture.description);
+}
+
+static void pi_set_data(FLAC__StreamMetadata *block, const FLAC__byte *data, FLAC__uint32 len)
+{
+ if(block->data.picture.data) {
+ block->length -= block->data.picture.data_length;
+ free(block->data.picture.data);
+ }
+ block->data.picture.data = (FLAC__byte*)strdup((const char *)data);
+ FLAC__ASSERT(block->data.picture.data);
+ block->data.picture.data_length = len;
+ block->length += len;
+}
+
+FLAC__bool test_metadata_object(void)
+{
+ FLAC__StreamMetadata *block, *blockcopy, *vorbiscomment, *cuesheet, *picture;
+ FLAC__StreamMetadata_SeekPoint seekpoint_array[14];
+ FLAC__StreamMetadata_VorbisComment_Entry entry;
+ FLAC__StreamMetadata_CueSheet_Index indx;
+ FLAC__StreamMetadata_CueSheet_Track track;
+ unsigned i, expected_length, seekpoints;
+ int j;
+ static FLAC__byte dummydata[4] = { 'a', 'b', 'c', 'd' };
+
+ printf("\n+++ libFLAC unit test: metadata objects\n\n");
+
+
+ printf("testing STREAMINFO\n");
+
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_STREAMINFO);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ expected_length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+ if(block->length != expected_length) {
+ printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+
+ printf("testing PADDING\n");
+
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ expected_length = 0;
+ if(block->length != expected_length) {
+ printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+
+ printf("testing APPLICATION\n");
+
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ expected_length = FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8;
+ if(block->length != expected_length) {
+ printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_application_set_data(copy)... ");
+ if(!FLAC__metadata_object_application_set_data(block, dummydata, sizeof(dummydata), true/*copy*/)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ expected_length = (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) + sizeof(dummydata);
+ if(block->length != expected_length) {
+ printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+ return false;
+ }
+ if(0 != memcmp(block->data.application.data, dummydata, sizeof(dummydata))) {
+ printf("FAILED, data mismatch\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_application_set_data(own)... ");
+ if(!FLAC__metadata_object_application_set_data(block, make_dummydata_(dummydata, sizeof(dummydata)), sizeof(dummydata), false/*own*/)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ expected_length = (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8) + sizeof(dummydata);
+ if(block->length != expected_length) {
+ printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+ return false;
+ }
+ if(0 != memcmp(block->data.application.data, dummydata, sizeof(dummydata))) {
+ printf("FAILED, data mismatch\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+
+ printf("testing SEEKTABLE\n");
+
+ for(i = 0; i < sizeof(seekpoint_array) / sizeof(FLAC__StreamMetadata_SeekPoint); i++) {
+ seekpoint_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ seekpoint_array[i].stream_offset = 0;
+ seekpoint_array[i].frame_samples = 0;
+ }
+
+ seekpoints = 0;
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, 0))
+ return false;
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ printf("OK\n");
+
+ seekpoints = 2;
+ printf("testing FLAC__metadata_object_seektable_resize_points(grow to %u)...", seekpoints);
+ if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ seekpoints = 1;
+ printf("testing FLAC__metadata_object_seektable_resize_points(shrink to %u)...", seekpoints);
+ if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ printf("testing FLAC__metadata_object_seektable_is_legal()...");
+ if(!FLAC__metadata_object_seektable_is_legal(block)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ seekpoints = 0;
+ printf("testing FLAC__metadata_object_seektable_resize_points(shrink to %u)...", seekpoints);
+ if(!FLAC__metadata_object_seektable_resize_points(block, seekpoints)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, 0))
+ return false;
+
+ seekpoints++;
+ printf("testing FLAC__metadata_object_seektable_insert_point() on empty array...");
+ if(!FLAC__metadata_object_seektable_insert_point(block, 0, seekpoint_array[0])) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ seekpoint_array[0].sample_number = 1;
+ seekpoints++;
+ printf("testing FLAC__metadata_object_seektable_insert_point() on beginning of non-empty array...");
+ if(!FLAC__metadata_object_seektable_insert_point(block, 0, seekpoint_array[0])) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ seekpoint_array[1].sample_number = 2;
+ seekpoints++;
+ printf("testing FLAC__metadata_object_seektable_insert_point() on middle of non-empty array...");
+ if(!FLAC__metadata_object_seektable_insert_point(block, 1, seekpoint_array[1])) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ seekpoint_array[3].sample_number = 3;
+ seekpoints++;
+ printf("testing FLAC__metadata_object_seektable_insert_point() on end of non-empty array...");
+ if(!FLAC__metadata_object_seektable_insert_point(block, 3, seekpoint_array[3])) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ printf("OK\n");
+
+ seekpoint_array[2].sample_number = seekpoint_array[3].sample_number;
+ seekpoints--;
+ printf("testing FLAC__metadata_object_seektable_delete_point() on middle of array...");
+ if(!FLAC__metadata_object_seektable_delete_point(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ seekpoints--;
+ printf("testing FLAC__metadata_object_seektable_delete_point() on end of array...");
+ if(!FLAC__metadata_object_seektable_delete_point(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ seekpoints--;
+ printf("testing FLAC__metadata_object_seektable_delete_point() on beginning of array...");
+ if(!FLAC__metadata_object_seektable_delete_point(block, 0)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array+1))
+ return false;
+
+ printf("testing FLAC__metadata_object_seektable_set_point()...");
+ FLAC__metadata_object_seektable_set_point(block, 0, seekpoint_array[0]);
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+ /* seektable template functions */
+
+ for(i = 0; i < sizeof(seekpoint_array) / sizeof(FLAC__StreamMetadata_SeekPoint); i++) {
+ seekpoint_array[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ seekpoint_array[i].stream_offset = 0;
+ seekpoint_array[i].frame_samples = 0;
+ }
+
+ seekpoints = 0;
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, 0))
+ return false;
+
+ seekpoints += 2;
+ printf("testing FLAC__metadata_object_seekpoint_template_append_placeholders()... ");
+ if(!FLAC__metadata_object_seektable_template_append_placeholders(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ seekpoint_array[seekpoints++].sample_number = 7;
+ printf("testing FLAC__metadata_object_seekpoint_template_append_point()... ");
+ if(!FLAC__metadata_object_seektable_template_append_point(block, 7)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ {
+ FLAC__uint64 nums[2] = { 3, 7 };
+ seekpoint_array[seekpoints++].sample_number = nums[0];
+ seekpoint_array[seekpoints++].sample_number = nums[1];
+ printf("testing FLAC__metadata_object_seekpoint_template_append_points()... ");
+ if(!FLAC__metadata_object_seektable_template_append_points(block, nums, sizeof(nums)/sizeof(FLAC__uint64))) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+ }
+
+ seekpoint_array[seekpoints++].sample_number = 0;
+ seekpoint_array[seekpoints++].sample_number = 10;
+ seekpoint_array[seekpoints++].sample_number = 20;
+ printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points()... ");
+ if(!FLAC__metadata_object_seektable_template_append_spaced_points(block, 3, 30)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ seekpoints--;
+ seekpoint_array[0].sample_number = 0;
+ seekpoint_array[1].sample_number = 3;
+ seekpoint_array[2].sample_number = 7;
+ seekpoint_array[3].sample_number = 10;
+ seekpoint_array[4].sample_number = 20;
+ seekpoint_array[5].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ seekpoint_array[6].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ printf("testing FLAC__metadata_object_seekpoint_template_sort(compact=true)... ");
+ if(!FLAC__metadata_object_seektable_template_sort(block, /*compact=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!FLAC__metadata_object_seektable_is_legal(block)) {
+ printf("FAILED, seek table is illegal\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ printf("testing FLAC__metadata_object_seekpoint_template_sort(compact=false)... ");
+ if(!FLAC__metadata_object_seektable_template_sort(block, /*compact=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!FLAC__metadata_object_seektable_is_legal(block)) {
+ printf("FAILED, seek table is illegal\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ seekpoint_array[seekpoints++].sample_number = 0;
+ seekpoint_array[seekpoints++].sample_number = 10;
+ seekpoint_array[seekpoints++].sample_number = 20;
+ printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points_by_samples()... ");
+ if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(block, 10, 30)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ seekpoint_array[seekpoints++].sample_number = 0;
+ seekpoint_array[seekpoints++].sample_number = 11;
+ seekpoint_array[seekpoints++].sample_number = 22;
+ printf("testing FLAC__metadata_object_seekpoint_template_append_spaced_points_by_samples()... ");
+ if(!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(block, 11, 30)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!check_seektable_(block, seekpoints, seekpoint_array))
+ return false;
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+
+ printf("testing VORBIS_COMMENT\n");
+
+ {
+ FLAC__StreamMetadata_VorbisComment_Entry entry_;
+ char *field_name, *field_value;
+
+ printf("testing FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair()... ");
+ if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry_, "name", "value")) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(strcmp((const char *)entry_.entry, "name=value")) {
+ printf("FAILED, field mismatch\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair()... ");
+ if(!FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(entry_, &field_name, &field_value)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(strcmp(field_name, "name")) {
+ printf("FAILED, field name mismatch\n");
+ return false;
+ }
+ if(strcmp(field_value, "value")) {
+ printf("FAILED, field value mismatch\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_entry_matches()... ");
+ if(!FLAC__metadata_object_vorbiscomment_entry_matches(entry_, field_name, strlen(field_name))) {
+ printf("FAILED, expected true, returned false\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_entry_matches()... ");
+ if(FLAC__metadata_object_vorbiscomment_entry_matches(entry_, "blah", strlen("blah"))) {
+ printf("FAILED, expected false, returned true\n");
+ return false;
+ }
+ printf("OK\n");
+
+ free(entry_.entry);
+ free(field_name);
+ free(field_value);
+ }
+
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ expected_length = (FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN/8 + strlen(FLAC__VENDOR_STRING) + FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN/8);
+ if(block->length != expected_length) {
+ printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ vorbiscomment = FLAC__metadata_object_clone(block);
+ if(0 == vorbiscomment) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ vc_resize_(vorbiscomment, 2);
+ printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(grow to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+ if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ vc_resize_(vorbiscomment, 1);
+ printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+ if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ vc_resize_(vorbiscomment, 0);
+ printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+ if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 1, "name2=field2");
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ vc_resize_(vorbiscomment, 0);
+ printf("testing FLAC__metadata_object_vorbiscomment_resize_comments(shrink to %u)...", vorbiscomment->data.vorbis_comment.num_comments);
+ if(!FLAC__metadata_object_vorbiscomment_resize_comments(block, vorbiscomment->data.vorbis_comment.num_comments)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on beginning of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 0, "name2=field2");
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on middle of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 1, "name3=field3");
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 1, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 3, "name4=field4");
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 3, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 4, "name3=field3dup1");
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 4, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(copy) on end of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 5, "name3=field3dup1");
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 5, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "name3")) != 1) {
+ printf("FAILED, expected 1, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name3")) != 4) {
+ printf("FAILED, expected 4, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name3")) != 5) {
+ printf("FAILED, expected 5, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "name2")) != 0) {
+ printf("FAILED, expected 0, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, j+1, "name2")) != -1) {
+ printf("FAILED, expected -1, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_find_entry_from()...");
+ if((j = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, "blah")) != -1) {
+ printf("FAILED, expected -1, got %d\n", j);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(first, copy)...");
+ vc_replace_new_(&entry, vorbiscomment, "name3=field3new1", /*all=*/false);
+ if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/false, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ if(block->data.vorbis_comment.num_comments != 6) {
+ printf("FAILED, expected 6 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(all, copy)...");
+ vc_replace_new_(&entry, vorbiscomment, "name3=field3new2", /*all=*/true);
+ if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/true, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ if(block->data.vorbis_comment.num_comments != 4) {
+ printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on middle of array...");
+ vc_delete_(vorbiscomment, 2);
+ if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on end of array...");
+ vc_delete_(vorbiscomment, 2);
+ if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on beginning of array...");
+ vc_delete_(vorbiscomment, 0);
+ if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 0)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 1, "rem0=val0");
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 2, "rem0=val1");
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(copy) on non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 3, "rem0=val2");
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_remove_entry_matching(\"blah\")...");
+ if((j = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, "blah")) != 0) {
+ printf("FAILED, expected 0, got %d\n", j);
+ return false;
+ }
+ if(block->data.vorbis_comment.num_comments != 4) {
+ printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_remove_entry_matching(\"rem0\")...");
+ vc_delete_(vorbiscomment, 1);
+ if((j = FLAC__metadata_object_vorbiscomment_remove_entry_matching(block, "rem0")) != 1) {
+ printf("FAILED, expected 1, got %d\n", j);
+ return false;
+ }
+ if(block->data.vorbis_comment.num_comments != 3) {
+ printf("FAILED, expected 3 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_remove_entries_matching(\"blah\")...");
+ if((j = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, "blah")) != 0) {
+ printf("FAILED, expected 0, got %d\n", j);
+ return false;
+ }
+ if(block->data.vorbis_comment.num_comments != 3) {
+ printf("FAILED, expected 3 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_remove_entries_matching(\"rem0\")...");
+ vc_delete_(vorbiscomment, 1);
+ vc_delete_(vorbiscomment, 1);
+ if((j = FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, "rem0")) != 2) {
+ printf("FAILED, expected 2, got %d\n", j);
+ return false;
+ }
+ if(block->data.vorbis_comment.num_comments != 1) {
+ printf("FAILED, expected 1 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_set_comment(copy)...");
+ vc_set_new_(&entry, vorbiscomment, 0, "name5=field5");
+ FLAC__metadata_object_vorbiscomment_set_comment(block, 0, entry, /*copy=*/true);
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_set_vendor_string(copy)...");
+ vc_set_vs_new_(&entry, vorbiscomment, "name6=field6");
+ FLAC__metadata_object_vorbiscomment_set_vendor_string(block, entry, /*copy=*/true);
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(vorbiscomment);
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ vorbiscomment = FLAC__metadata_object_clone(block);
+ if(0 == vorbiscomment) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(own) on empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_append_comment(own) on non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 1, "name2=field2");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_append_comment(block, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(vorbiscomment);
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ vorbiscomment = FLAC__metadata_object_clone(block);
+ if(0 == vorbiscomment) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 0, "name1=field1");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on beginning of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 0, "name2=field2");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 0, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on middle of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 1, "name3=field3");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 1, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 3, "name4=field4");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 3, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 4, "name3=field3dup1");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 4, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_insert_comment(own) on end of non-empty array...");
+ vc_insert_new_(&entry, vorbiscomment, 5, "name3=field3dup1");
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_insert_comment(block, 5, entry, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(first, own)...");
+ vc_replace_new_(&entry, vorbiscomment, "name3=field3new1", /*all=*/false);
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/false, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ if(block->data.vorbis_comment.num_comments != 6) {
+ printf("FAILED, expected 6 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_replace_comment(all, own)...");
+ vc_replace_new_(&entry, vorbiscomment, "name3=field3new2", /*all=*/true);
+ entry_clone_(&entry);
+ if(!FLAC__metadata_object_vorbiscomment_replace_comment(block, entry, /*all=*/true, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ if(block->data.vorbis_comment.num_comments != 4) {
+ printf("FAILED, expected 4 comments, got %u\n", block->data.vorbis_comment.num_comments);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on middle of array...");
+ vc_delete_(vorbiscomment, 2);
+ if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on end of array...");
+ vc_delete_(vorbiscomment, 2);
+ if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_delete_comment() on beginning of array...");
+ vc_delete_(vorbiscomment, 0);
+ if(!FLAC__metadata_object_vorbiscomment_delete_comment(block, 0)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_set_comment(own)...");
+ vc_set_new_(&entry, vorbiscomment, 0, "name5=field5");
+ entry_clone_(&entry);
+ FLAC__metadata_object_vorbiscomment_set_comment(block, 0, entry, /*copy=*/false);
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_vorbiscomment_set_vendor_string(own)...");
+ vc_set_vs_new_(&entry, vorbiscomment, "name6=field6");
+ entry_clone_(&entry);
+ FLAC__metadata_object_vorbiscomment_set_vendor_string(block, entry, /*copy=*/false);
+ if(!mutils__compare_block(vorbiscomment, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(vorbiscomment);
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+
+ printf("testing CUESHEET\n");
+
+ {
+ FLAC__StreamMetadata_CueSheet_Track *track_, *trackcopy_;
+
+ printf("testing FLAC__metadata_object_cuesheet_track_new()... ");
+ track_ = FLAC__metadata_object_cuesheet_track_new();
+ if(0 == track_) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_track_clone()... ");
+ trackcopy_ = FLAC__metadata_object_cuesheet_track_clone(track_);
+ if(0 == trackcopy_) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!compare_track_(trackcopy_, track_))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_track_delete()... ");
+ FLAC__metadata_object_cuesheet_track_delete(trackcopy_);
+ FLAC__metadata_object_cuesheet_track_delete(track_);
+ printf("OK\n");
+ }
+
+
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ expected_length = (
+ FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+ ) / 8;
+ if(block->length != expected_length) {
+ printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ cuesheet = FLAC__metadata_object_clone(block);
+ if(0 == cuesheet) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ cs_resize_(cuesheet, 2);
+ printf("testing FLAC__metadata_object_cuesheet_resize_tracks(grow to %u)...", cuesheet->data.cue_sheet.num_tracks);
+ if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ cs_resize_(cuesheet, 1);
+ printf("testing FLAC__metadata_object_cuesheet_resize_tracks(shrink to %u)...", cuesheet->data.cue_sheet.num_tracks);
+ if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ cs_resize_(cuesheet, 0);
+ printf("testing FLAC__metadata_object_cuesheet_resize_tracks(shrink to %u)...", cuesheet->data.cue_sheet.num_tracks);
+ if(!FLAC__metadata_object_cuesheet_resize_tracks(block, cuesheet->data.cue_sheet.num_tracks)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on empty array...");
+ cs_insert_new_(&track, cuesheet, 0, 0, 1, "ABCDE1234567", false, false);
+ if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on beginning of non-empty array...");
+ cs_insert_new_(&track, cuesheet, 0, 10, 2, "BBCDE1234567", false, false);
+ if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on middle of non-empty array...");
+ cs_insert_new_(&track, cuesheet, 1, 20, 3, "CBCDE1234567", false, false);
+ if(!FLAC__metadata_object_cuesheet_insert_track(block, 1, &track, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_insert_track(copy) on end of non-empty array...");
+ cs_insert_new_(&track, cuesheet, 3, 30, 4, "DBCDE1234567", false, false);
+ if(!FLAC__metadata_object_cuesheet_insert_track(block, 3, &track, /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_insert_blank_track() on end of non-empty array...");
+ cs_insert_new_(&track, cuesheet, 4, 0, 0, "\0\0\0\0\0\0\0\0\0\0\0\0", false, false);
+ if(!FLAC__metadata_object_cuesheet_insert_blank_track(block, 4)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+ cs_delete_(cuesheet, 4);
+ if(!FLAC__metadata_object_cuesheet_delete_track(block, 4)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_delete_track() on middle of array...");
+ cs_delete_(cuesheet, 2);
+ if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+ cs_delete_(cuesheet, 2);
+ if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_delete_track() on beginning of array...");
+ cs_delete_(cuesheet, 0);
+ if(!FLAC__metadata_object_cuesheet_delete_track(block, 0)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_set_track(copy)...");
+ cs_set_new_(&track, cuesheet, 0, 40, 5, "EBCDE1234567", false, false);
+ FLAC__metadata_object_cuesheet_set_track(block, 0, &track, /*copy=*/true);
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ tr_resize_(cuesheet, 0, 2);
+ printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(grow to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices);
+ if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ tr_resize_(cuesheet, 0, 1);
+ printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(shrink to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices);
+ if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ tr_resize_(cuesheet, 0, 0);
+ printf("testing FLAC__metadata_object_cuesheet_track_resize_indices(shrink to %u)...", cuesheet->data.cue_sheet.tracks[0].num_indices);
+ if(!FLAC__metadata_object_cuesheet_track_resize_indices(block, 0, cuesheet->data.cue_sheet.tracks[0].num_indices)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ indx.offset = 0;
+ indx.number = 1;
+ printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on empty array...");
+ tr_insert_new_(cuesheet, 0, 0, indx);
+ if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 0, indx)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ indx.offset = 10;
+ indx.number = 2;
+ printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on beginning of non-empty array...");
+ tr_insert_new_(cuesheet, 0, 0, indx);
+ if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 0, indx)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ indx.offset = 20;
+ indx.number = 3;
+ printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on middle of non-empty array...");
+ tr_insert_new_(cuesheet, 0, 1, indx);
+ if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 1, indx)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ indx.offset = 30;
+ indx.number = 4;
+ printf("testing FLAC__metadata_object_cuesheet_track_insert_index() on end of non-empty array...");
+ tr_insert_new_(cuesheet, 0, 3, indx);
+ if(!FLAC__metadata_object_cuesheet_track_insert_index(block, 0, 3, indx)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ indx.offset = 0;
+ indx.number = 0;
+ printf("testing FLAC__metadata_object_cuesheet_track_insert_blank_index() on end of non-empty array...");
+ tr_insert_new_(cuesheet, 0, 4, indx);
+ if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(block, 0, 4)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on end of array...");
+ tr_delete_(cuesheet, 0, 4);
+ if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 4)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on middle of array...");
+ tr_delete_(cuesheet, 0, 2);
+ if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on end of array...");
+ tr_delete_(cuesheet, 0, 2);
+ if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_track_delete_index() on beginning of array...");
+ tr_delete_(cuesheet, 0, 0);
+ if(!FLAC__metadata_object_cuesheet_track_delete_index(block, 0, 0)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(cuesheet);
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ cuesheet = FLAC__metadata_object_clone(block);
+ if(0 == cuesheet) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on empty array...");
+ cs_insert_new_(&track, cuesheet, 0, 60, 7, "GBCDE1234567", false, false);
+ track_clone_(&track);
+ if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on beginning of non-empty array...");
+ cs_insert_new_(&track, cuesheet, 0, 70, 8, "HBCDE1234567", false, false);
+ track_clone_(&track);
+ if(!FLAC__metadata_object_cuesheet_insert_track(block, 0, &track, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on middle of non-empty array...");
+ cs_insert_new_(&track, cuesheet, 1, 80, 9, "IBCDE1234567", false, false);
+ track_clone_(&track);
+ if(!FLAC__metadata_object_cuesheet_insert_track(block, 1, &track, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_insert_track(own) on end of non-empty array...");
+ cs_insert_new_(&track, cuesheet, 3, 90, 10, "JBCDE1234567", false, false);
+ track_clone_(&track);
+ if(!FLAC__metadata_object_cuesheet_insert_track(block, 3, &track, /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_delete_track() on middle of array...");
+ cs_delete_(cuesheet, 2);
+ if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_delete_track() on end of array...");
+ cs_delete_(cuesheet, 2);
+ if(!FLAC__metadata_object_cuesheet_delete_track(block, 2)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_delete_track() on beginning of array...");
+ cs_delete_(cuesheet, 0);
+ if(!FLAC__metadata_object_cuesheet_delete_track(block, 0)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_set_track(own)...");
+ cs_set_new_(&track, cuesheet, 0, 100, 11, "KBCDE1234567", false, false);
+ track_clone_(&track);
+ FLAC__metadata_object_cuesheet_set_track(block, 0, &track, /*copy=*/false);
+ if(!mutils__compare_block(cuesheet, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_cuesheet_is_legal()...");
+ {
+ const char *violation;
+ if(FLAC__metadata_object_cuesheet_is_legal(block, /*check_cd_da_subset=*/true, &violation)) {
+ printf("FAILED, returned true when expecting false\n");
+ return false;
+ }
+ printf("returned false as expected, violation=\"%s\" OK\n", violation);
+ }
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(cuesheet);
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+
+ printf("testing PICTURE\n");
+
+ printf("testing FLAC__metadata_object_new()... ");
+ block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE);
+ if(0 == block) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ expected_length = (
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+ FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN
+ ) / 8;
+ if(block->length != expected_length) {
+ printf("FAILED, bad length, expected %u, got %u\n", expected_length, block->length);
+ return false;
+ }
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ picture = FLAC__metadata_object_clone(block);
+ if(0 == picture) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ pi_set_mime_type(picture, "image/png\t");
+ printf("testing FLAC__metadata_object_picture_set_mime_type(copy)...");
+ if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png\t", /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_picture_is_legal()...");
+ {
+ const char *violation;
+ if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+ printf("FAILED, returned true when expecting false\n");
+ return false;
+ }
+ printf("returned false as expected, violation=\"%s\" OK\n", violation);
+ }
+
+ pi_set_mime_type(picture, "image/png");
+ printf("testing FLAC__metadata_object_picture_set_mime_type(copy)...");
+ if(!FLAC__metadata_object_picture_set_mime_type(block, "image/png", /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_picture_is_legal()...");
+ {
+ const char *violation;
+ if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+ printf("FAILED, returned false, violation=\"%s\"\n", violation);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff");
+ printf("testing FLAC__metadata_object_picture_set_description(copy)...");
+ if(!FLAC__metadata_object_picture_set_description(block, (const FLAC__byte *)"DESCRIPTION\xff", /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_picture_is_legal()...");
+ {
+ const char *violation;
+ if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+ printf("FAILED, returned true when expecting false\n");
+ return false;
+ }
+ printf("returned false as expected, violation=\"%s\" OK\n", violation);
+ }
+
+ pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION");
+ printf("testing FLAC__metadata_object_picture_set_description(copy)...");
+ if(!FLAC__metadata_object_picture_set_description(block, (const FLAC__byte *)"DESCRIPTION", /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_picture_is_legal()...");
+ {
+ const char *violation;
+ if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+ printf("FAILED, returned false, violation=\"%s\"\n", violation);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+
+ pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA"));
+ printf("testing FLAC__metadata_object_picture_set_data(copy)...");
+ if(!FLAC__metadata_object_picture_set_data(block, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA"), /*copy=*/true)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ printf("OK\n");
+
+ pi_set_mime_type(picture, "image/png\t");
+ printf("testing FLAC__metadata_object_picture_set_mime_type(own)...");
+ if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png\t"), /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_picture_is_legal()...");
+ {
+ const char *violation;
+ if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+ printf("FAILED, returned true when expecting false\n");
+ return false;
+ }
+ printf("returned false as expected, violation=\"%s\" OK\n", violation);
+ }
+
+ pi_set_mime_type(picture, "image/png");
+ printf("testing FLAC__metadata_object_picture_set_mime_type(own)...");
+ if(!FLAC__metadata_object_picture_set_mime_type(block, strdup("image/png"), /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_picture_is_legal()...");
+ {
+ const char *violation;
+ if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+ printf("FAILED, returned false, violation=\"%s\"\n", violation);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION\xff");
+ printf("testing FLAC__metadata_object_picture_set_description(own)...");
+ if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION\xff"), /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_picture_is_legal()...");
+ {
+ const char *violation;
+ if(FLAC__metadata_object_picture_is_legal(block, &violation)) {
+ printf("FAILED, returned true when expecting false\n");
+ return false;
+ }
+ printf("returned false as expected, violation=\"%s\" OK\n", violation);
+ }
+
+ pi_set_description(picture, (const FLAC__byte *)"DESCRIPTION");
+ printf("testing FLAC__metadata_object_picture_set_description(own)...");
+ if(!FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)strdup("DESCRIPTION"), /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_picture_is_legal()...");
+ {
+ const char *violation;
+ if(!FLAC__metadata_object_picture_is_legal(block, &violation)) {
+ printf("FAILED, returned false, violation=\"%s\"\n", violation);
+ return false;
+ }
+ printf("OK\n");
+ }
+
+ pi_set_data(picture, (const FLAC__byte*)"PNGDATA", strlen("PNGDATA"));
+ printf("testing FLAC__metadata_object_picture_set_data(own)...");
+ if(!FLAC__metadata_object_picture_set_data(block, (FLAC__byte*)strdup("PNGDATA"), strlen("PNGDATA"), /*copy=*/false)) {
+ printf("FAILED, returned false\n");
+ return false;
+ }
+ if(!mutils__compare_block(picture, block))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_clone()... ");
+ blockcopy = FLAC__metadata_object_clone(block);
+ if(0 == blockcopy) {
+ printf("FAILED, returned NULL\n");
+ return false;
+ }
+ if(!mutils__compare_block(block, blockcopy))
+ return false;
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(blockcopy);
+ printf("OK\n");
+
+ printf("testing FLAC__metadata_object_delete()... ");
+ FLAC__metadata_object_delete(picture);
+ FLAC__metadata_object_delete(block);
+ printf("OK\n");
+
+
+ return true;
+}
diff --git a/src/FLAC/src/test_libs_common/Makefile.am b/src/FLAC/src/test_libs_common/Makefile.am
new file mode 100644
index 0000000..498b247
--- /dev/null
+++ b/src/FLAC/src/test_libs_common/Makefile.am
@@ -0,0 +1,27 @@
+# test_libs_common - Common code to library unit tests
+# Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+INCLUDES = -I$(top_srcdir)/src/FLAC/include
+
+noinst_LTLIBRARIES = libtest_libs_common.la
+
+libtest_libs_common_la_SOURCES = \
+ file_utils_flac.c \
+ metadata_utils.c
+
+EXTRA_DIST = \
+ README
diff --git a/src/FLAC/src/test_libs_common/README b/src/FLAC/src/test_libs_common/README
new file mode 100644
index 0000000..6a704c2
--- /dev/null
+++ b/src/FLAC/src/test_libs_common/README
@@ -0,0 +1,2 @@
+This directory contains a convenience library of routines that are
+common to the library unit testers.
diff --git a/src/FLAC/src/test_libs_common/file_utils_flac.c b/src/FLAC/src/test_libs_common/file_utils_flac.c
new file mode 100644
index 0000000..a52fee0
--- /dev/null
+++ b/src/FLAC/src/test_libs_common/file_utils_flac.c
@@ -0,0 +1,153 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/assert.h"
+#include "FLAC/stream_encoder.h"
+#include "test_libs_common/file_utils_flac.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h> /* for stat() */
+
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a)<(b)?(a):(b))
+
+const long file_utils__ogg_serial_number = 12345;
+
+#ifdef FLAC__VALGRIND_TESTING
+static size_t local__fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ size_t ret = fwrite(ptr, size, nmemb, stream);
+ if(!ferror(stream))
+ fflush(stream);
+ return ret;
+}
+#else
+#define local__fwrite fwrite
+#endif
+
+typedef struct {
+ FILE *file;
+} encoder_client_struct;
+
+static FLAC__StreamEncoderWriteStatus encoder_write_callback_(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data)
+{
+ encoder_client_struct *ecd = (encoder_client_struct*)client_data;
+
+ (void)encoder, (void)samples, (void)current_frame;
+
+ if(local__fwrite(buffer, 1, bytes, ecd->file) != bytes)
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
+ else
+ return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
+}
+
+static void encoder_metadata_callback_(const FLAC__StreamEncoder *encoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ (void)encoder, (void)metadata, (void)client_data;
+}
+
+FLAC__bool file_utils__generate_flacfile(FLAC__bool is_ogg, const char *output_filename, off_t *output_filesize, unsigned length, const FLAC__StreamMetadata *streaminfo, FLAC__StreamMetadata **metadata, unsigned num_metadata)
+{
+ FLAC__int32 samples[1024];
+ FLAC__StreamEncoder *encoder;
+ FLAC__StreamEncoderInitStatus init_status;
+ encoder_client_struct encoder_client_data;
+ unsigned i, n;
+
+ FLAC__ASSERT(0 != output_filename);
+ FLAC__ASSERT(0 != streaminfo);
+ FLAC__ASSERT(streaminfo->type == FLAC__METADATA_TYPE_STREAMINFO);
+ FLAC__ASSERT((streaminfo->is_last && num_metadata == 0) || (!streaminfo->is_last && num_metadata > 0));
+
+ if(0 == (encoder_client_data.file = fopen(output_filename, "wb")))
+ return false;
+
+ encoder = FLAC__stream_encoder_new();
+ if(0 == encoder) {
+ fclose(encoder_client_data.file);
+ return false;
+ }
+
+ FLAC__stream_encoder_set_ogg_serial_number(encoder, file_utils__ogg_serial_number);
+ FLAC__stream_encoder_set_verify(encoder, true);
+ FLAC__stream_encoder_set_streamable_subset(encoder, true);
+ FLAC__stream_encoder_set_do_mid_side_stereo(encoder, false);
+ FLAC__stream_encoder_set_loose_mid_side_stereo(encoder, false);
+ FLAC__stream_encoder_set_channels(encoder, streaminfo->data.stream_info.channels);
+ FLAC__stream_encoder_set_bits_per_sample(encoder, streaminfo->data.stream_info.bits_per_sample);
+ FLAC__stream_encoder_set_sample_rate(encoder, streaminfo->data.stream_info.sample_rate);
+ FLAC__stream_encoder_set_blocksize(encoder, streaminfo->data.stream_info.min_blocksize);
+ FLAC__stream_encoder_set_max_lpc_order(encoder, 0);
+ FLAC__stream_encoder_set_qlp_coeff_precision(encoder, 0);
+ FLAC__stream_encoder_set_do_qlp_coeff_prec_search(encoder, false);
+ FLAC__stream_encoder_set_do_escape_coding(encoder, false);
+ FLAC__stream_encoder_set_do_exhaustive_model_search(encoder, false);
+ FLAC__stream_encoder_set_min_residual_partition_order(encoder, 0);
+ FLAC__stream_encoder_set_max_residual_partition_order(encoder, 0);
+ FLAC__stream_encoder_set_rice_parameter_search_dist(encoder, 0);
+ FLAC__stream_encoder_set_total_samples_estimate(encoder, streaminfo->data.stream_info.total_samples);
+ FLAC__stream_encoder_set_metadata(encoder, metadata, num_metadata);
+
+ if(is_ogg)
+ init_status = FLAC__stream_encoder_init_ogg_stream(encoder, /*read_callback=*/0, encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, encoder_metadata_callback_, &encoder_client_data);
+ else
+ init_status = FLAC__stream_encoder_init_stream(encoder, encoder_write_callback_, /*seek_callback=*/0, /*tell_callback=*/0, encoder_metadata_callback_, &encoder_client_data);
+
+ if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
+ fclose(encoder_client_data.file);
+ return false;
+ }
+
+ /* init the dummy sample buffer */
+ for(i = 0; i < sizeof(samples) / sizeof(FLAC__int32); i++)
+ samples[i] = i & 7;
+
+ while(length > 0) {
+ n = min(length, sizeof(samples) / sizeof(FLAC__int32));
+
+ if(!FLAC__stream_encoder_process_interleaved(encoder, samples, n)) {
+ fclose(encoder_client_data.file);
+ return false;
+ }
+
+ length -= n;
+ }
+
+ (void)FLAC__stream_encoder_finish(encoder);
+
+ fclose(encoder_client_data.file);
+
+ FLAC__stream_encoder_delete(encoder);
+
+ if(0 != output_filesize) {
+ struct stat filestats;
+
+ if(stat(output_filename, &filestats) != 0)
+ return false;
+ else
+ *output_filesize = filestats.st_size;
+ }
+
+ return true;
+}
diff --git a/src/FLAC/src/test_libs_common/metadata_utils.c b/src/FLAC/src/test_libs_common/metadata_utils.c
new file mode 100644
index 0000000..fe192e7
--- /dev/null
+++ b/src/FLAC/src/test_libs_common/metadata_utils.c
@@ -0,0 +1,657 @@
+/* test_libFLAC - Unit tester for libFLAC
+ * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+/*
+ * These are not tests, just utility functions used by the metadata tests
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "FLAC/metadata.h"
+#include "test_libs_common/metadata_utils.h"
+#include <stdio.h>
+#include <stdlib.h> /* for malloc() */
+#include <string.h> /* for memcmp() */
+
+FLAC__bool mutils__compare_block_data_streaminfo(const FLAC__StreamMetadata_StreamInfo *block, const FLAC__StreamMetadata_StreamInfo *blockcopy)
+{
+ if(blockcopy->min_blocksize != block->min_blocksize) {
+ printf("FAILED, min_blocksize mismatch, expected %u, got %u\n", block->min_blocksize, blockcopy->min_blocksize);
+ return false;
+ }
+ if(blockcopy->max_blocksize != block->max_blocksize) {
+ printf("FAILED, max_blocksize mismatch, expected %u, got %u\n", block->max_blocksize, blockcopy->max_blocksize);
+ return false;
+ }
+ if(blockcopy->min_framesize != block->min_framesize) {
+ printf("FAILED, min_framesize mismatch, expected %u, got %u\n", block->min_framesize, blockcopy->min_framesize);
+ return false;
+ }
+ if(blockcopy->max_framesize != block->max_framesize) {
+ printf("FAILED, max_framesize mismatch, expected %u, got %u\n", block->max_framesize, blockcopy->max_framesize);
+ return false;
+ }
+ if(blockcopy->sample_rate != block->sample_rate) {
+ printf("FAILED, sample_rate mismatch, expected %u, got %u\n", block->sample_rate, blockcopy->sample_rate);
+ return false;
+ }
+ if(blockcopy->channels != block->channels) {
+ printf("FAILED, channels mismatch, expected %u, got %u\n", block->channels, blockcopy->channels);
+ return false;
+ }
+ if(blockcopy->bits_per_sample != block->bits_per_sample) {
+ printf("FAILED, bits_per_sample mismatch, expected %u, got %u\n", block->bits_per_sample, blockcopy->bits_per_sample);
+ return false;
+ }
+ if(blockcopy->total_samples != block->total_samples) {
+#ifdef _MSC_VER
+ printf("FAILED, total_samples mismatch, expected %I64u, got %I64u\n", block->total_samples, blockcopy->total_samples);
+#else
+ printf("FAILED, total_samples mismatch, expected %llu, got %llu\n", (unsigned long long)block->total_samples, (unsigned long long)blockcopy->total_samples);
+#endif
+ return false;
+ }
+ if(0 != memcmp(blockcopy->md5sum, block->md5sum, sizeof(block->md5sum))) {
+ printf("FAILED, md5sum mismatch, expected %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X, got %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n",
+ (unsigned)block->md5sum[0],
+ (unsigned)block->md5sum[1],
+ (unsigned)block->md5sum[2],
+ (unsigned)block->md5sum[3],
+ (unsigned)block->md5sum[4],
+ (unsigned)block->md5sum[5],
+ (unsigned)block->md5sum[6],
+ (unsigned)block->md5sum[7],
+ (unsigned)block->md5sum[8],
+ (unsigned)block->md5sum[9],
+ (unsigned)block->md5sum[10],
+ (unsigned)block->md5sum[11],
+ (unsigned)block->md5sum[12],
+ (unsigned)block->md5sum[13],
+ (unsigned)block->md5sum[14],
+ (unsigned)block->md5sum[15],
+ (unsigned)blockcopy->md5sum[0],
+ (unsigned)blockcopy->md5sum[1],
+ (unsigned)blockcopy->md5sum[2],
+ (unsigned)blockcopy->md5sum[3],
+ (unsigned)blockcopy->md5sum[4],
+ (unsigned)blockcopy->md5sum[5],
+ (unsigned)blockcopy->md5sum[6],
+ (unsigned)blockcopy->md5sum[7],
+ (unsigned)blockcopy->md5sum[8],
+ (unsigned)blockcopy->md5sum[9],
+ (unsigned)blockcopy->md5sum[10],
+ (unsigned)blockcopy->md5sum[11],
+ (unsigned)blockcopy->md5sum[12],
+ (unsigned)blockcopy->md5sum[13],
+ (unsigned)blockcopy->md5sum[14],
+ (unsigned)blockcopy->md5sum[15]
+ );
+ return false;
+ }
+ return true;
+}
+
+FLAC__bool mutils__compare_block_data_padding(const FLAC__StreamMetadata_Padding *block, const FLAC__StreamMetadata_Padding *blockcopy, unsigned block_length)
+{
+ /* we don't compare the padding guts */
+ (void)block, (void)blockcopy, (void)block_length;
+ return true;
+}
+
+FLAC__bool mutils__compare_block_data_application(const FLAC__StreamMetadata_Application *block, const FLAC__StreamMetadata_Application *blockcopy, unsigned block_length)
+{
+ if(block_length < sizeof(block->id)) {
+ printf("FAILED, bad block length = %u\n", block_length);
+ return false;
+ }
+ if(0 != memcmp(blockcopy->id, block->id, sizeof(block->id))) {
+ printf("FAILED, id mismatch, expected %02X%02X%02X%02X, got %02X%02X%02X%02X\n",
+ (unsigned)block->id[0],
+ (unsigned)block->id[1],
+ (unsigned)block->id[2],
+ (unsigned)block->id[3],
+ (unsigned)blockcopy->id[0],
+ (unsigned)blockcopy->id[1],
+ (unsigned)blockcopy->id[2],
+ (unsigned)blockcopy->id[3]
+ );
+ return false;
+ }
+ if(0 == block->data || 0 == blockcopy->data) {
+ if(block->data != blockcopy->data) {
+ printf("FAILED, data mismatch (%s's data pointer is null)\n", 0==block->data?"original":"copy");
+ return false;
+ }
+ else if(block_length - sizeof(block->id) > 0) {
+ printf("FAILED, data pointer is null but block length is not 0\n");
+ return false;
+ }
+ }
+ else {
+ if(block_length - sizeof(block->id) == 0) {
+ printf("FAILED, data pointer is not null but block length is 0\n");
+ return false;
+ }
+ else if(0 != memcmp(blockcopy->data, block->data, block_length - sizeof(block->id))) {
+ printf("FAILED, data mismatch\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+FLAC__bool mutils__compare_block_data_seektable(const FLAC__StreamMetadata_SeekTable *block, const FLAC__StreamMetadata_SeekTable *blockcopy)
+{
+ unsigned i;
+ if(blockcopy->num_points != block->num_points) {
+ printf("FAILED, num_points mismatch, expected %u, got %u\n", block->num_points, blockcopy->num_points);
+ return false;
+ }
+ for(i = 0; i < block->num_points; i++) {
+ if(blockcopy->points[i].sample_number != block->points[i].sample_number) {
+#ifdef _MSC_VER
+ printf("FAILED, points[%u].sample_number mismatch, expected %I64u, got %I64u\n", i, block->points[i].sample_number, blockcopy->points[i].sample_number);
+#else
+ printf("FAILED, points[%u].sample_number mismatch, expected %llu, got %llu\n", i, (unsigned long long)block->points[i].sample_number, (unsigned long long)blockcopy->points[i].sample_number);
+#endif
+ return false;
+ }
+ if(blockcopy->points[i].stream_offset != block->points[i].stream_offset) {
+#ifdef _MSC_VER
+ printf("FAILED, points[%u].stream_offset mismatch, expected %I64u, got %I64u\n", i, block->points[i].stream_offset, blockcopy->points[i].stream_offset);
+#else
+ printf("FAILED, points[%u].stream_offset mismatch, expected %llu, got %llu\n", i, (unsigned long long)block->points[i].stream_offset, (unsigned long long)blockcopy->points[i].stream_offset);
+#endif
+ return false;
+ }
+ if(blockcopy->points[i].frame_samples != block->points[i].frame_samples) {
+ printf("FAILED, points[%u].frame_samples mismatch, expected %u, got %u\n", i, block->points[i].frame_samples, blockcopy->points[i].frame_samples);
+ return false;
+ }
+ }
+ return true;
+}
+
+FLAC__bool mutils__compare_block_data_vorbiscomment(const FLAC__StreamMetadata_VorbisComment *block, const FLAC__StreamMetadata_VorbisComment *blockcopy)
+{
+ unsigned i;
+ if(blockcopy->vendor_string.length != block->vendor_string.length) {
+ printf("FAILED, vendor_string.length mismatch, expected %u, got %u\n", block->vendor_string.length, blockcopy->vendor_string.length);
+ return false;
+ }
+ if(0 == block->vendor_string.entry || 0 == blockcopy->vendor_string.entry) {
+ if(block->vendor_string.entry != blockcopy->vendor_string.entry) {
+ printf("FAILED, vendor_string.entry mismatch\n");
+ return false;
+ }
+ }
+ else if(0 != memcmp(blockcopy->vendor_string.entry, block->vendor_string.entry, block->vendor_string.length)) {
+ printf("FAILED, vendor_string.entry mismatch\n");
+ return false;
+ }
+ if(blockcopy->num_comments != block->num_comments) {
+ printf("FAILED, num_comments mismatch, expected %u, got %u\n", block->num_comments, blockcopy->num_comments);
+ return false;
+ }
+ for(i = 0; i < block->num_comments; i++) {
+ if(blockcopy->comments[i].length != block->comments[i].length) {
+ printf("FAILED, comments[%u].length mismatch, expected %u, got %u\n", i, block->comments[i].length, blockcopy->comments[i].length);
+ return false;
+ }
+ if(0 == block->comments[i].entry || 0 == blockcopy->comments[i].entry) {
+ if(block->comments[i].entry != blockcopy->comments[i].entry) {
+ printf("FAILED, comments[%u].entry mismatch\n", i);
+ return false;
+ }
+ }
+ else {
+ if(0 != memcmp(blockcopy->comments[i].entry, block->comments[i].entry, block->comments[i].length)) {
+ printf("FAILED, comments[%u].entry mismatch\n", i);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+FLAC__bool mutils__compare_block_data_cuesheet(const FLAC__StreamMetadata_CueSheet *block, const FLAC__StreamMetadata_CueSheet *blockcopy)
+{
+ unsigned i, j;
+
+ if(0 != strcmp(blockcopy->media_catalog_number, block->media_catalog_number)) {
+ printf("FAILED, media_catalog_number mismatch, expected %s, got %s\n", block->media_catalog_number, blockcopy->media_catalog_number);
+ return false;
+ }
+ if(blockcopy->lead_in != block->lead_in) {
+#ifdef _MSC_VER
+ printf("FAILED, lead_in mismatch, expected %I64u, got %I64u\n", block->lead_in, blockcopy->lead_in);
+#else
+ printf("FAILED, lead_in mismatch, expected %llu, got %llu\n", (unsigned long long)block->lead_in, (unsigned long long)blockcopy->lead_in);
+#endif
+ return false;
+ }
+ if(blockcopy->is_cd != block->is_cd) {
+ printf("FAILED, is_cd mismatch, expected %u, got %u\n", (unsigned)block->is_cd, (unsigned)blockcopy->is_cd);
+ return false;
+ }
+ if(blockcopy->num_tracks != block->num_tracks) {
+ printf("FAILED, num_tracks mismatch, expected %u, got %u\n", block->num_tracks, blockcopy->num_tracks);
+ return false;
+ }
+ for(i = 0; i < block->num_tracks; i++) {
+ if(blockcopy->tracks[i].offset != block->tracks[i].offset) {
+#ifdef _MSC_VER
+ printf("FAILED, tracks[%u].offset mismatch, expected %I64u, got %I64u\n", i, block->tracks[i].offset, blockcopy->tracks[i].offset);
+#else
+ printf("FAILED, tracks[%u].offset mismatch, expected %llu, got %llu\n", i, (unsigned long long)block->tracks[i].offset, (unsigned long long)blockcopy->tracks[i].offset);
+#endif
+ return false;
+ }
+ if(blockcopy->tracks[i].number != block->tracks[i].number) {
+ printf("FAILED, tracks[%u].number mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].number, (unsigned)blockcopy->tracks[i].number);
+ return false;
+ }
+ if(blockcopy->tracks[i].num_indices != block->tracks[i].num_indices) {
+ printf("FAILED, tracks[%u].num_indices mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].num_indices, (unsigned)blockcopy->tracks[i].num_indices);
+ return false;
+ }
+ /* num_indices == 0 means lead-out track so only the track offset and number are valid */
+ if(block->tracks[i].num_indices > 0) {
+ if(0 != strcmp(blockcopy->tracks[i].isrc, block->tracks[i].isrc)) {
+ printf("FAILED, tracks[%u].isrc mismatch, expected %s, got %s\n", i, block->tracks[i].isrc, blockcopy->tracks[i].isrc);
+ return false;
+ }
+ if(blockcopy->tracks[i].type != block->tracks[i].type) {
+ printf("FAILED, tracks[%u].type mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].type, (unsigned)blockcopy->tracks[i].type);
+ return false;
+ }
+ if(blockcopy->tracks[i].pre_emphasis != block->tracks[i].pre_emphasis) {
+ printf("FAILED, tracks[%u].pre_emphasis mismatch, expected %u, got %u\n", i, (unsigned)block->tracks[i].pre_emphasis, (unsigned)blockcopy->tracks[i].pre_emphasis);
+ return false;
+ }
+ if(0 == block->tracks[i].indices || 0 == blockcopy->tracks[i].indices) {
+ if(block->tracks[i].indices != blockcopy->tracks[i].indices) {
+ printf("FAILED, tracks[%u].indices mismatch\n", i);
+ return false;
+ }
+ }
+ else {
+ for(j = 0; j < block->tracks[i].num_indices; j++) {
+ if(blockcopy->tracks[i].indices[j].offset != block->tracks[i].indices[j].offset) {
+#ifdef _MSC_VER
+ printf("FAILED, tracks[%u].indices[%u].offset mismatch, expected %I64u, got %I64u\n", i, j, block->tracks[i].indices[j].offset, blockcopy->tracks[i].indices[j].offset);
+#else
+ printf("FAILED, tracks[%u].indices[%u].offset mismatch, expected %llu, got %llu\n", i, j, (unsigned long long)block->tracks[i].indices[j].offset, (unsigned long long)blockcopy->tracks[i].indices[j].offset);
+#endif
+ return false;
+ }
+ if(blockcopy->tracks[i].indices[j].number != block->tracks[i].indices[j].number) {
+ printf("FAILED, tracks[%u].indices[%u].number mismatch, expected %u, got %u\n", i, j, (unsigned)block->tracks[i].indices[j].number, (unsigned)blockcopy->tracks[i].indices[j].number);
+ return false;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+FLAC__bool mutils__compare_block_data_picture(const FLAC__StreamMetadata_Picture *block, const FLAC__StreamMetadata_Picture *blockcopy)
+{
+ size_t len, lencopy;
+ if(blockcopy->type != block->type) {
+ printf("FAILED, type mismatch, expected %u, got %u\n", (unsigned)block->type, (unsigned)blockcopy->type);
+ return false;
+ }
+ len = strlen(block->mime_type);
+ lencopy = strlen(blockcopy->mime_type);
+ if(lencopy != len) {
+ printf("FAILED, mime_type length mismatch, expected %u, got %u\n", (unsigned)len, (unsigned)lencopy);
+ return false;
+ }
+ if(strcmp(blockcopy->mime_type, block->mime_type)) {
+ printf("FAILED, mime_type mismatch, expected %s, got %s\n", block->mime_type, blockcopy->mime_type);
+ return false;
+ }
+ len = strlen((const char *)block->description);
+ lencopy = strlen((const char *)blockcopy->description);
+ if(lencopy != len) {
+ printf("FAILED, description length mismatch, expected %u, got %u\n", (unsigned)len, (unsigned)lencopy);
+ return false;
+ }
+ if(strcmp((const char *)blockcopy->description, (const char *)block->description)) {
+ printf("FAILED, description mismatch, expected %s, got %s\n", block->description, blockcopy->description);
+ return false;
+ }
+ if(blockcopy->width != block->width) {
+ printf("FAILED, width mismatch, expected %u, got %u\n", block->width, blockcopy->width);
+ return false;
+ }
+ if(blockcopy->height != block->height) {
+ printf("FAILED, height mismatch, expected %u, got %u\n", block->height, blockcopy->height);
+ return false;
+ }
+ if(blockcopy->depth != block->depth) {
+ printf("FAILED, depth mismatch, expected %u, got %u\n", block->depth, blockcopy->depth);
+ return false;
+ }
+ if(blockcopy->colors != block->colors) {
+ printf("FAILED, colors mismatch, expected %u, got %u\n", block->colors, blockcopy->colors);
+ return false;
+ }
+ if(blockcopy->data_length != block->data_length) {
+ printf("FAILED, data_length mismatch, expected %u, got %u\n", block->data_length, blockcopy->data_length);
+ return false;
+ }
+ if(memcmp(blockcopy->data, block->data, block->data_length)) {
+ printf("FAILED, data mismatch\n");
+ return false;
+ }
+ return true;
+}
+
+FLAC__bool mutils__compare_block_data_unknown(const FLAC__StreamMetadata_Unknown *block, const FLAC__StreamMetadata_Unknown *blockcopy, unsigned block_length)
+{
+ if(0 == block->data || 0 == blockcopy->data) {
+ if(block->data != blockcopy->data) {
+ printf("FAILED, data mismatch (%s's data pointer is null)\n", 0==block->data?"original":"copy");
+ return false;
+ }
+ else if(block_length > 0) {
+ printf("FAILED, data pointer is null but block length is not 0\n");
+ return false;
+ }
+ }
+ else {
+ if(block_length == 0) {
+ printf("FAILED, data pointer is not null but block length is 0\n");
+ return false;
+ }
+ else if(0 != memcmp(blockcopy->data, block->data, block_length)) {
+ printf("FAILED, data mismatch\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+FLAC__bool mutils__compare_block(const FLAC__StreamMetadata *block, const FLAC__StreamMetadata *blockcopy)
+{
+ if(blockcopy->type != block->type) {
+ printf("FAILED, type mismatch, expected %s, got %s\n", FLAC__MetadataTypeString[block->type], FLAC__MetadataTypeString[blockcopy->type]);
+ return false;
+ }
+ if(blockcopy->is_last != block->is_last) {
+ printf("FAILED, is_last mismatch, expected %u, got %u\n", (unsigned)block->is_last, (unsigned)blockcopy->is_last);
+ return false;
+ }
+ if(blockcopy->length != block->length) {
+ printf("FAILED, length mismatch, expected %u, got %u\n", block->length, blockcopy->length);
+ return false;
+ }
+ switch(block->type) {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ return mutils__compare_block_data_streaminfo(&block->data.stream_info, &blockcopy->data.stream_info);
+ case FLAC__METADATA_TYPE_PADDING:
+ return mutils__compare_block_data_padding(&block->data.padding, &blockcopy->data.padding, block->length);
+ case FLAC__METADATA_TYPE_APPLICATION:
+ return mutils__compare_block_data_application(&block->data.application, &blockcopy->data.application, block->length);
+ case FLAC__METADATA_TYPE_SEEKTABLE:
+ return mutils__compare_block_data_seektable(&block->data.seek_table, &blockcopy->data.seek_table);
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ return mutils__compare_block_data_vorbiscomment(&block->data.vorbis_comment, &blockcopy->data.vorbis_comment);
+ case FLAC__METADATA_TYPE_CUESHEET:
+ return mutils__compare_block_data_cuesheet(&block->data.cue_sheet, &blockcopy->data.cue_sheet);
+ case FLAC__METADATA_TYPE_PICTURE:
+ return mutils__compare_block_data_picture(&block->data.picture, &blockcopy->data.picture);
+ default:
+ return mutils__compare_block_data_unknown(&block->data.unknown, &blockcopy->data.unknown, block->length);
+ }
+}
+
+static void *malloc_or_die_(size_t size)
+{
+ void *x = malloc(size);
+ if(0 == x) {
+ fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)size);
+ exit(1);
+ }
+ return x;
+}
+
+static void *calloc_or_die_(size_t n, size_t size)
+{
+ void *x = calloc(n, size);
+ if(0 == x) {
+ fprintf(stderr, "ERROR: out of memory allocating %u bytes\n", (unsigned)n * (unsigned)size);
+ exit(1);
+ }
+ return x;
+}
+
+static char *strdup_or_die_(const char *s)
+{
+ char *x = strdup(s);
+ if(0 == x) {
+ fprintf(stderr, "ERROR: out of memory copying string \"%s\"\n", s);
+ exit(1);
+ }
+ return x;
+}
+
+void mutils__init_metadata_blocks(
+ FLAC__StreamMetadata *streaminfo,
+ FLAC__StreamMetadata *padding,
+ FLAC__StreamMetadata *seektable,
+ FLAC__StreamMetadata *application1,
+ FLAC__StreamMetadata *application2,
+ FLAC__StreamMetadata *vorbiscomment,
+ FLAC__StreamMetadata *cuesheet,
+ FLAC__StreamMetadata *picture,
+ FLAC__StreamMetadata *unknown
+)
+{
+ /*
+ most of the actual numbers and data in the blocks don't matter,
+ we just want to make sure the decoder parses them correctly
+
+ remember, the metadata interface gets tested after the decoders,
+ so we do all the metadata manipulation here without it.
+ */
+
+ /* min/max_framesize and md5sum don't get written at first, so we have to leave them 0 */
+ streaminfo->is_last = false;
+ streaminfo->type = FLAC__METADATA_TYPE_STREAMINFO;
+ streaminfo->length = FLAC__STREAM_METADATA_STREAMINFO_LENGTH;
+ streaminfo->data.stream_info.min_blocksize = 576;
+ streaminfo->data.stream_info.max_blocksize = 576;
+ streaminfo->data.stream_info.min_framesize = 0;
+ streaminfo->data.stream_info.max_framesize = 0;
+ streaminfo->data.stream_info.sample_rate = 44100;
+ streaminfo->data.stream_info.channels = 1;
+ streaminfo->data.stream_info.bits_per_sample = 8;
+ streaminfo->data.stream_info.total_samples = 0;
+ memset(streaminfo->data.stream_info.md5sum, 0, 16);
+
+ padding->is_last = false;
+ padding->type = FLAC__METADATA_TYPE_PADDING;
+ padding->length = 1234;
+
+ seektable->is_last = false;
+ seektable->type = FLAC__METADATA_TYPE_SEEKTABLE;
+ seektable->data.seek_table.num_points = 2;
+ seektable->length = seektable->data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH;
+ seektable->data.seek_table.points = (FLAC__StreamMetadata_SeekPoint*)malloc_or_die_(seektable->data.seek_table.num_points * sizeof(FLAC__StreamMetadata_SeekPoint));
+ seektable->data.seek_table.points[0].sample_number = 0;
+ seektable->data.seek_table.points[0].stream_offset = 0;
+ seektable->data.seek_table.points[0].frame_samples = streaminfo->data.stream_info.min_blocksize;
+ seektable->data.seek_table.points[1].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
+ seektable->data.seek_table.points[1].stream_offset = 1000;
+ seektable->data.seek_table.points[1].frame_samples = streaminfo->data.stream_info.min_blocksize;
+
+ application1->is_last = false;
+ application1->type = FLAC__METADATA_TYPE_APPLICATION;
+ application1->length = 8;
+ memcpy(application1->data.application.id, "\xfe\xdc\xba\x98", 4);
+ application1->data.application.data = (FLAC__byte*)malloc_or_die_(4);
+ memcpy(application1->data.application.data, "\xf0\xe1\xd2\xc3", 4);
+
+ application2->is_last = false;
+ application2->type = FLAC__METADATA_TYPE_APPLICATION;
+ application2->length = 4;
+ memcpy(application2->data.application.id, "\x76\x54\x32\x10", 4);
+ application2->data.application.data = 0;
+
+ {
+ const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING);
+ vorbiscomment->is_last = false;
+ vorbiscomment->type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
+ vorbiscomment->length = (4 + vendor_string_length) + 4 + (4 + 5) + (4 + 0);
+ vorbiscomment->data.vorbis_comment.vendor_string.length = vendor_string_length;
+ vorbiscomment->data.vorbis_comment.vendor_string.entry = (FLAC__byte*)malloc_or_die_(vendor_string_length+1);
+ memcpy(vorbiscomment->data.vorbis_comment.vendor_string.entry, FLAC__VENDOR_STRING, vendor_string_length+1);
+ vorbiscomment->data.vorbis_comment.num_comments = 2;
+ vorbiscomment->data.vorbis_comment.comments = (FLAC__StreamMetadata_VorbisComment_Entry*)malloc_or_die_(vorbiscomment->data.vorbis_comment.num_comments * sizeof(FLAC__StreamMetadata_VorbisComment_Entry));
+ vorbiscomment->data.vorbis_comment.comments[0].length = 5;
+ vorbiscomment->data.vorbis_comment.comments[0].entry = (FLAC__byte*)malloc_or_die_(5+1);
+ memcpy(vorbiscomment->data.vorbis_comment.comments[0].entry, "ab=cd", 5+1);
+ vorbiscomment->data.vorbis_comment.comments[1].length = 0;
+ vorbiscomment->data.vorbis_comment.comments[1].entry = 0;
+ }
+
+ cuesheet->is_last = false;
+ cuesheet->type = FLAC__METADATA_TYPE_CUESHEET;
+ cuesheet->length =
+ /* cuesheet guts */
+ (
+ FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN
+ ) / 8 +
+ /* 2 tracks */
+ 3 * (
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN
+ ) / 8 +
+ /* 3 index points */
+ 3 * (
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN +
+ FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN
+ ) / 8
+ ;
+ memset(cuesheet->data.cue_sheet.media_catalog_number, 0, sizeof(cuesheet->data.cue_sheet.media_catalog_number));
+ cuesheet->data.cue_sheet.media_catalog_number[0] = 'j';
+ cuesheet->data.cue_sheet.media_catalog_number[1] = 'C';
+ cuesheet->data.cue_sheet.lead_in = 2 * 44100;
+ cuesheet->data.cue_sheet.is_cd = true;
+ cuesheet->data.cue_sheet.num_tracks = 3;
+ cuesheet->data.cue_sheet.tracks = (FLAC__StreamMetadata_CueSheet_Track*)calloc_or_die_(cuesheet->data.cue_sheet.num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track));
+ cuesheet->data.cue_sheet.tracks[0].offset = 0;
+ cuesheet->data.cue_sheet.tracks[0].number = 1;
+ memcpy(cuesheet->data.cue_sheet.tracks[0].isrc, "ACBDE1234567", sizeof(cuesheet->data.cue_sheet.tracks[0].isrc));
+ cuesheet->data.cue_sheet.tracks[0].type = 0;
+ cuesheet->data.cue_sheet.tracks[0].pre_emphasis = 1;
+ cuesheet->data.cue_sheet.tracks[0].num_indices = 2;
+ cuesheet->data.cue_sheet.tracks[0].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet->data.cue_sheet.tracks[0].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+ cuesheet->data.cue_sheet.tracks[0].indices[0].offset = 0;
+ cuesheet->data.cue_sheet.tracks[0].indices[0].number = 0;
+ cuesheet->data.cue_sheet.tracks[0].indices[1].offset = 123 * 588;
+ cuesheet->data.cue_sheet.tracks[0].indices[1].number = 1;
+ cuesheet->data.cue_sheet.tracks[1].offset = 1234 * 588;
+ cuesheet->data.cue_sheet.tracks[1].number = 2;
+ memcpy(cuesheet->data.cue_sheet.tracks[1].isrc, "ACBDE7654321", sizeof(cuesheet->data.cue_sheet.tracks[1].isrc));
+ cuesheet->data.cue_sheet.tracks[1].type = 1;
+ cuesheet->data.cue_sheet.tracks[1].pre_emphasis = 0;
+ cuesheet->data.cue_sheet.tracks[1].num_indices = 1;
+ cuesheet->data.cue_sheet.tracks[1].indices = (FLAC__StreamMetadata_CueSheet_Index*)malloc_or_die_(cuesheet->data.cue_sheet.tracks[1].num_indices * sizeof(FLAC__StreamMetadata_CueSheet_Index));
+ cuesheet->data.cue_sheet.tracks[1].indices[0].offset = 0;
+ cuesheet->data.cue_sheet.tracks[1].indices[0].number = 1;
+ cuesheet->data.cue_sheet.tracks[2].offset = 12345 * 588;
+ cuesheet->data.cue_sheet.tracks[2].number = 170;
+ cuesheet->data.cue_sheet.tracks[2].num_indices = 0;
+
+ picture->is_last = false;
+ picture->type = FLAC__METADATA_TYPE_PICTURE;
+ picture->length =
+ (
+ FLAC__STREAM_METADATA_PICTURE_TYPE_LEN +
+ FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN + /* will add the length for the string later */
+ FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN + /* will add the length for the string later */
+ FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN +
+ FLAC__STREAM_METADATA_PICTURE_COLORS_LEN +
+ FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN /* will add the length for the data later */
+ ) / 8
+ ;
+ picture->data.picture.type = FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER;
+ picture->data.picture.mime_type = strdup_or_die_("image/jpeg");
+ picture->length += strlen(picture->data.picture.mime_type);
+ picture->data.picture.description = (FLAC__byte*)strdup_or_die_("desc");
+ picture->length += strlen((const char *)picture->data.picture.description);
+ picture->data.picture.width = 300;
+ picture->data.picture.height = 300;
+ picture->data.picture.depth = 24;
+ picture->data.picture.colors = 0;
+ picture->data.picture.data = (FLAC__byte*)strdup_or_die_("SOMEJPEGDATA");
+ picture->data.picture.data_length = strlen((const char *)picture->data.picture.data);
+ picture->length += picture->data.picture.data_length;
+
+ unknown->is_last = true;
+ unknown->type = 126;
+ unknown->length = 8;
+ unknown->data.unknown.data = (FLAC__byte*)malloc_or_die_(unknown->length);
+ memcpy(unknown->data.unknown.data, "\xfe\xdc\xba\x98\xf0\xe1\xd2\xc3", unknown->length);
+}
+
+void mutils__free_metadata_blocks(
+ FLAC__StreamMetadata *streaminfo,
+ FLAC__StreamMetadata *padding,
+ FLAC__StreamMetadata *seektable,
+ FLAC__StreamMetadata *application1,
+ FLAC__StreamMetadata *application2,
+ FLAC__StreamMetadata *vorbiscomment,
+ FLAC__StreamMetadata *cuesheet,
+ FLAC__StreamMetadata *picture,
+ FLAC__StreamMetadata *unknown
+)
+{
+ (void)streaminfo, (void)padding, (void)application2;
+ free(seektable->data.seek_table.points);
+ free(application1->data.application.data);
+ free(vorbiscomment->data.vorbis_comment.vendor_string.entry);
+ free(vorbiscomment->data.vorbis_comment.comments[0].entry);
+ free(vorbiscomment->data.vorbis_comment.comments);
+ free(cuesheet->data.cue_sheet.tracks[0].indices);
+ free(cuesheet->data.cue_sheet.tracks[1].indices);
+ free(cuesheet->data.cue_sheet.tracks);
+ free(picture->data.picture.mime_type);
+ free(picture->data.picture.description);
+ free(picture->data.picture.data);
+ free(unknown->data.unknown.data);
+}
diff --git a/src/FLAC/src/test_seeking/Makefile.am b/src/FLAC/src/test_seeking/Makefile.am
new file mode 100644
index 0000000..09cc5ef
--- /dev/null
+++ b/src/FLAC/src/test_seeking/Makefile.am
@@ -0,0 +1,28 @@
+# test_seeking - Seeking tester for libFLAC
+# Copyright (C) 2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+AM_CFLAGS = -I$(top_srcdir)/src/FLAC/include -I$(top_srcdir)/src/OGG/include
+
+INCLUDES =
+
+noinst_PROGRAMS = test_seeking
+test_seeking_LDADD = \
+ $(top_builddir)/src/FLAC/src/libFLAC/libFLAC.la \
+ $(top_builddir)/src/OGG/libogg.la \
+ -lm
+test_seeking_SOURCES = \
+ main.c
diff --git a/src/FLAC/src/test_seeking/main.c b/src/FLAC/src/test_seeking/main.c
new file mode 100644
index 0000000..1a2f3a0
--- /dev/null
+++ b/src/FLAC/src/test_seeking/main.c
@@ -0,0 +1,399 @@
+/* test_seeking - Seeking tester for libFLAC
+ * Copyright (C) 2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+#include <sys/stat.h> /* for stat() */
+#include "FLAC/assert.h"
+#include "FLAC/stream_decoder.h"
+
+typedef struct {
+ FLAC__bool got_data;
+ FLAC__uint64 total_samples;
+ unsigned channels;
+ unsigned bits_per_sample;
+ FLAC__bool quiet;
+ FLAC__bool ignore_errors;
+ FLAC__bool error_occurred;
+} DecoderClientData;
+
+static FLAC__bool stop_signal_ = false;
+
+static void our_sigint_handler_(int signo)
+{
+ (void)signo;
+ printf("(caught SIGINT) ");
+ fflush(stdout);
+ stop_signal_ = true;
+}
+
+static FLAC__bool die_(const char *msg)
+{
+ printf("ERROR: %s\n", msg);
+ return false;
+}
+
+static FLAC__bool die_s_(const char *msg, const FLAC__StreamDecoder *decoder)
+{
+ FLAC__StreamDecoderState state = FLAC__stream_decoder_get_state(decoder);
+
+ if(msg)
+ printf("FAILED, %s", msg);
+ else
+ printf("FAILED");
+
+ printf(", state = %u (%s)\n", (unsigned)state, FLAC__StreamDecoderStateString[state]);
+
+ return false;
+}
+
+static off_t get_filesize_(const char *srcpath)
+{
+ struct stat srcstat;
+
+ if(0 == stat(srcpath, &srcstat))
+ return srcstat.st_size;
+ else
+ return -1;
+}
+
+static FLAC__StreamDecoderWriteStatus write_callback_(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
+{
+ DecoderClientData *dcd = (DecoderClientData*)client_data;
+
+ (void)decoder, (void)buffer;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in write callback is NULL\n");
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+
+ if(dcd->error_occurred)
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+
+ if (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) {
+ if (!dcd->quiet)
+ printf("frame@%uf(%u)... ", frame->header.number.frame_number, frame->header.blocksize);
+ }
+ else if (frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER) {
+ if (!dcd->quiet)
+#ifdef _MSC_VER
+ printf("frame@%I64u(%u)... ", frame->header.number.sample_number, frame->header.blocksize);
+#else
+ printf("frame@%llu(%u)... ", (unsigned long long)frame->header.number.sample_number, frame->header.blocksize);
+#endif
+ }
+ else {
+ FLAC__ASSERT(0);
+ dcd->error_occurred = true;
+ return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
+ }
+ fflush(stdout);
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+static void metadata_callback_(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+{
+ DecoderClientData *dcd = (DecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in metadata callback is NULL\n");
+ return;
+ }
+
+ if(dcd->error_occurred)
+ return;
+
+ if (!dcd->got_data && metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+ dcd->got_data = true;
+ dcd->total_samples = metadata->data.stream_info.total_samples;
+ dcd->channels = metadata->data.stream_info.channels;
+ dcd->bits_per_sample = metadata->data.stream_info.bits_per_sample;
+ }
+}
+
+static void error_callback_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data)
+{
+ DecoderClientData *dcd = (DecoderClientData*)client_data;
+
+ (void)decoder;
+
+ if(0 == dcd) {
+ printf("ERROR: client_data in error callback is NULL\n");
+ return;
+ }
+
+ if(!dcd->ignore_errors) {
+ printf("ERROR: got error callback: err = %u (%s)\n", (unsigned)status, FLAC__StreamDecoderErrorStatusString[status]);
+ dcd->error_occurred = true;
+ }
+}
+
+/* read mode:
+ * 0 - no read after seek
+ * 1 - read 2 frames
+ * 2 - read until end
+ */
+static FLAC__bool seek_barrage(FLAC__bool is_ogg, const char *filename, off_t filesize, unsigned count, FLAC__int64 total_samples, unsigned read_mode)
+{
+ FLAC__StreamDecoder *decoder;
+ DecoderClientData decoder_client_data;
+ unsigned i;
+ long int n;
+
+ decoder_client_data.got_data = false;
+ decoder_client_data.total_samples = 0;
+ decoder_client_data.quiet = false;
+ decoder_client_data.ignore_errors = false;
+ decoder_client_data.error_occurred = false;
+
+ printf("\n+++ seek test: FLAC__StreamDecoder (%s FLAC, read_mode=%u)\n\n", is_ogg? "Ogg":"native", read_mode);
+
+ decoder = FLAC__stream_decoder_new();
+ if(0 == decoder)
+ return die_("FLAC__stream_decoder_new() FAILED, returned NULL\n");
+
+ if(is_ogg) {
+ if(FLAC__stream_decoder_init_ogg_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &decoder_client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+ return die_s_("FLAC__stream_decoder_init_file() FAILED", decoder);
+ }
+ else {
+ if(FLAC__stream_decoder_init_file(decoder, filename, write_callback_, metadata_callback_, error_callback_, &decoder_client_data) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
+ return die_s_("FLAC__stream_decoder_init_file() FAILED", decoder);
+ }
+
+ if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder))
+ return die_s_("FLAC__stream_decoder_process_until_end_of_metadata() FAILED", decoder);
+
+ if(!is_ogg) { /* not necessary to do this for Ogg because of its seeking method */
+ /* process until end of stream to make sure we can still seek in that state */
+ decoder_client_data.quiet = true;
+ if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+ return die_s_("FLAC__stream_decoder_process_until_end_of_stream() FAILED", decoder);
+ decoder_client_data.quiet = false;
+
+ printf("stream decoder state is %s\n", FLAC__stream_decoder_get_resolved_state_string(decoder));
+ if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_END_OF_STREAM)
+ return die_s_("expected FLAC__STREAM_DECODER_END_OF_STREAM", decoder);
+ }
+
+#ifdef _MSC_VER
+ printf("file's total_samples is %I64u\n", decoder_client_data.total_samples);
+#else
+ printf("file's total_samples is %llu\n", (unsigned long long)decoder_client_data.total_samples);
+#endif
+#if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__
+ if (decoder_client_data.total_samples > (FLAC__uint64)RAND_MAX) {
+ printf("ERROR: must be total_samples < %u\n", (unsigned)RAND_MAX);
+ return false;
+ }
+#endif
+ n = (long int)decoder_client_data.total_samples;
+
+ if(n == 0 && total_samples >= 0)
+ n = (long int)total_samples;
+
+ /* if we don't have a total samples count, just guess based on the file size */
+ /* @@@ for is_ogg we should get it from last page's granulepos */
+ if(n == 0) {
+ /* 8 would imply no compression, 9 guarantees that we will get some samples off the end of the stream to test that case */
+ n = 9 * filesize / (decoder_client_data.channels * decoder_client_data.bits_per_sample);
+#if !defined _MSC_VER && !defined __MINGW32__
+ if(n > RAND_MAX)
+ n = RAND_MAX;
+#endif
+ }
+
+ printf("Begin seek barrage, count=%u\n", count);
+
+ for (i = 0; !stop_signal_ && (count == 0 || i < count); i++) {
+ FLAC__uint64 pos;
+
+ /* for the first 10, seek to the first 10 samples */
+ if (n >= 10 && i < 10) {
+ pos = i;
+ }
+ /* for the second 10, seek to the last 10 samples */
+ else if (n >= 10 && i < 20) {
+ pos = n - 1 - (i-10);
+ }
+ /* for the third 10, seek past the end and make sure we fail properly as expected */
+ else if (i < 30) {
+ pos = n + (i-20);
+ }
+ else {
+#if !defined _MSC_VER && !defined __MINGW32__
+ pos = (FLAC__uint64)(random() % n);
+#else
+ /* RAND_MAX is only 32767 in my MSVC */
+ pos = (FLAC__uint64)((rand()<<15|rand()) % n);
+#endif
+ }
+
+#ifdef _MSC_VER
+ printf("seek(%I64u)... ", pos);
+#else
+ printf("seek(%llu)... ", (unsigned long long)pos);
+#endif
+ fflush(stdout);
+ if(!FLAC__stream_decoder_seek_absolute(decoder, pos)) {
+ if(pos >= (FLAC__uint64)n)
+ printf("seek past end failed as expected... ");
+ else if(decoder_client_data.total_samples == 0 && total_samples <= 0)
+ printf("seek failed, assuming it was past EOF... ");
+ else
+ return die_s_("FLAC__stream_decoder_seek_absolute() FAILED", decoder);
+ if(!FLAC__stream_decoder_flush(decoder))
+ return die_s_("FLAC__stream_decoder_flush() FAILED", decoder);
+ }
+ else if(read_mode == 1) {
+ printf("decode_frame... ");
+ fflush(stdout);
+ if(!FLAC__stream_decoder_process_single(decoder))
+ return die_s_("FLAC__stream_decoder_process_single() FAILED", decoder);
+
+ printf("decode_frame... ");
+ fflush(stdout);
+ if(!FLAC__stream_decoder_process_single(decoder))
+ return die_s_("FLAC__stream_decoder_process_single() FAILED", decoder);
+ }
+ else if(read_mode == 2) {
+ printf("decode_all... ");
+ fflush(stdout);
+ decoder_client_data.quiet = true;
+ if(!FLAC__stream_decoder_process_until_end_of_stream(decoder))
+ return die_s_("FLAC__stream_decoder_process_until_end_of_stream() FAILED", decoder);
+ decoder_client_data.quiet = false;
+ }
+
+ printf("OK\n");
+ fflush(stdout);
+ }
+
+ if(FLAC__stream_decoder_get_state(decoder) != FLAC__STREAM_DECODER_UNINITIALIZED) {
+ if(!FLAC__stream_decoder_finish(decoder))
+ return die_s_("FLAC__stream_decoder_finish() FAILED", decoder);
+ }
+
+ FLAC__stream_decoder_delete(decoder);
+ printf("\nPASSED!\n");
+
+ return true;
+}
+
+#ifdef _MSC_VER
+/* There's no strtoull() in MSVC6 so we just write a specialized one */
+static FLAC__uint64 local__strtoull(const char *src)
+{
+ FLAC__uint64 ret = 0;
+ int c;
+ FLAC__ASSERT(0 != src);
+ while(0 != (c = *src++)) {
+ c -= '0';
+ if(c >= 0 && c <= 9)
+ ret = (ret * 10) + c;
+ else
+ break;
+ }
+ return ret;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ const char *filename;
+ unsigned count = 0, read_mode;
+ FLAC__int64 samples = -1;
+ off_t filesize;
+
+ static const char * const usage = "usage: test_seeking file.flac [#seeks] [#samples-in-file.flac]\n";
+
+ if (argc < 2 || argc > 4) {
+ fprintf(stderr, usage);
+ return 1;
+ }
+
+ filename = argv[1];
+
+ if (argc > 2)
+ count = strtoul(argv[2], 0, 10);
+ if (argc > 3)
+#ifdef _MSC_VER
+ samples = local__strtoull(argv[3]);
+#else
+ samples = strtoull(argv[3], 0, 10);
+#endif
+
+ if (count < 30)
+ fprintf(stderr, "WARNING: random seeks don't kick in until after 30 preprogrammed ones\n");
+
+#if !defined _MSC_VER && !defined __MINGW32__
+ {
+ struct timeval tv;
+
+ if (gettimeofday(&tv, 0) < 0) {
+ fprintf(stderr, "WARNING: couldn't seed RNG with time\n");
+ tv.tv_usec = 4321;
+ }
+ srandom(tv.tv_usec);
+ }
+#else
+ srand((unsigned)time(0));
+#endif
+
+ filesize = get_filesize_(filename);
+ if (filesize < 0) {
+ fprintf(stderr, "ERROR: can't determine filesize for %s\n", filename);
+ return 1;
+ }
+
+ (void) signal(SIGINT, our_sigint_handler_);
+
+ for (read_mode = 0; read_mode <= 2; read_mode++) {
+ FLAC__bool ok;
+ if (strlen(filename) > 4 && 0 == strcmp(filename+strlen(filename)-4, ".ogg")) {
+#if FLAC__HAS_OGG
+ ok = seek_barrage(/*is_ogg=*/true, filename, filesize, count, samples, read_mode);
+#else
+ fprintf(stderr, "ERROR: Ogg FLAC not supported\n");
+ ok = false;
+#endif
+ }
+ else {
+ ok = seek_barrage(/*is_ogg=*/false, filename, filesize, count, samples, read_mode);
+ }
+ if (!ok)
+ return 2;
+ }
+
+ return 0;
+}
diff --git a/src/FLAC/src/test_streams/Makefile.am b/src/FLAC/src/test_streams/Makefile.am
new file mode 100644
index 0000000..422bcde
--- /dev/null
+++ b/src/FLAC/src/test_streams/Makefile.am
@@ -0,0 +1,26 @@
+# test_streams - Simple test pattern generator
+# Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# 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.
+
+noinst_PROGRAMS = test_streams
+
+INCLUDES = -I$(top_srcdir)/src/FLAC/include
+
+test_streams_SOURCES = \
+ main.c
+test_streams_LDADD = -lm
+
+CLEANFILES = $(wildcard *.raw)
diff --git a/src/FLAC/src/test_streams/main.c b/src/FLAC/src/test_streams/main.c
new file mode 100644
index 0000000..f3f14ec
--- /dev/null
+++ b/src/FLAC/src/test_streams/main.c
@@ -0,0 +1,933 @@
+/* test_streams - Simple test pattern generator
+ * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+ *
+ * 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.
+ */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if defined _MSC_VER || defined __MINGW32__
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+#include "FLAC/assert.h"
+#include "FLAC/ordinals.h"
+
+#ifndef M_PI
+/* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */
+#define M_PI 3.14159265358979323846
+#endif
+
+#if defined _WIN32 || defined __EMX__
+ static const char *mode = "wb";
+#else
+ static const char *mode = "w";
+#endif
+
+#if !defined _MSC_VER && !defined __MINGW32__
+#define GET_RANDOM_BYTE (((unsigned)random()) & 0xff)
+#else
+#define GET_RANDOM_BYTE (((unsigned)rand()) & 0xff)
+#endif
+
+static FLAC__bool is_big_endian_host;
+
+
+static FLAC__bool write_little_endian(FILE *f, FLAC__int32 x, size_t bytes)
+{
+ while(bytes) {
+ if(fputc(x, f) == EOF)
+ return false;
+ x >>= 8;
+ bytes--;
+ }
+ return true;
+}
+
+static FLAC__bool write_little_endian_uint16(FILE *f, FLAC__uint16 x)
+{
+ return
+ fputc(x, f) != EOF &&
+ fputc(x >> 8, f) != EOF
+ ;
+}
+
+static FLAC__bool write_little_endian_int16(FILE *f, FLAC__int16 x)
+{
+ return write_little_endian_uint16(f, (FLAC__uint16)x);
+}
+
+static FLAC__bool write_little_endian_uint24(FILE *f, FLAC__uint32 x)
+{
+ return
+ fputc(x, f) != EOF &&
+ fputc(x >> 8, f) != EOF &&
+ fputc(x >> 16, f) != EOF
+ ;
+}
+
+static FLAC__bool write_little_endian_int24(FILE *f, FLAC__int32 x)
+{
+ return write_little_endian_uint24(f, (FLAC__uint32)x);
+}
+
+static FLAC__bool write_little_endian_uint32(FILE *f, FLAC__uint32 x)
+{
+ return
+ fputc(x, f) != EOF &&
+ fputc(x >> 8, f) != EOF &&
+ fputc(x >> 16, f) != EOF &&
+ fputc(x >> 24, f) != EOF
+ ;
+}
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_little_endian_int32(FILE *f, FLAC__int32 x)
+{
+ return write_little_endian_uint32(f, (FLAC__uint32)x);
+}
+#endif
+
+static FLAC__bool write_big_endian(FILE *f, FLAC__int32 x, size_t bytes)
+{
+ if(bytes < 4)
+ x <<= 8*(4-bytes);
+ while(bytes) {
+ if(fputc(x>>24, f) == EOF)
+ return false;
+ x <<= 8;
+ bytes--;
+ }
+ return true;
+}
+
+static FLAC__bool write_big_endian_uint16(FILE *f, FLAC__uint16 x)
+{
+ return
+ fputc(x >> 8, f) != EOF &&
+ fputc(x, f) != EOF
+ ;
+}
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_int16(FILE *f, FLAC__int16 x)
+{
+ return write_big_endian_uint16(f, (FLAC__uint16)x);
+}
+#endif
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_uint24(FILE *f, FLAC__uint32 x)
+{
+ return
+ fputc(x >> 16, f) != EOF &&
+ fputc(x >> 8, f) != EOF &&
+ fputc(x, f) != EOF
+ ;
+}
+#endif
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_int24(FILE *f, FLAC__int32 x)
+{
+ return write_big_endian_uint24(f, (FLAC__uint32)x);
+}
+#endif
+
+static FLAC__bool write_big_endian_uint32(FILE *f, FLAC__uint32 x)
+{
+ return
+ fputc(x >> 24, f) != EOF &&
+ fputc(x >> 16, f) != EOF &&
+ fputc(x >> 8, f) != EOF &&
+ fputc(x, f) != EOF
+ ;
+}
+
+#if 0
+/* @@@ not used (yet) */
+static FLAC__bool write_big_endian_int32(FILE *f, FLAC__int32 x)
+{
+ return write_big_endian_uint32(f, (FLAC__uint32)x);
+}
+#endif
+
+static FLAC__bool write_sane_extended(FILE *f, unsigned val)
+ /* Write to 'f' a SANE extended representation of 'val'. Return false if
+ * the write succeeds; return true otherwise.
+ *
+ * SANE extended is an 80-bit IEEE-754 representation with sign bit, 15 bits
+ * of exponent, and 64 bits of significand (mantissa). Unlike most IEEE-754
+ * representations, it does not imply a 1 above the MSB of the significand.
+ *
+ * Preconditions:
+ * val!=0U
+ */
+{
+ unsigned int shift, exponent;
+
+ FLAC__ASSERT(val!=0U); /* handling 0 would require a special case */
+
+ for(shift= 0U; (val>>(31-shift))==0U; ++shift)
+ ;
+ val<<= shift;
+ exponent= 63U-(shift+32U); /* add 32 for unused second word */
+
+ if(!write_big_endian_uint16(f, (FLAC__uint16)(exponent+0x3FFF)))
+ return false;
+ if(!write_big_endian_uint32(f, val))
+ return false;
+ if(!write_big_endian_uint32(f, 0)) /* unused second word */
+ return false;
+
+ return true;
+}
+
+/* a mono one-sample 16bps stream */
+static FLAC__bool generate_01(void)
+{
+ FILE *f;
+ FLAC__int16 x = -32768;
+
+ if(0 == (f = fopen("test01.raw", mode)))
+ return false;
+
+ if(!write_little_endian_int16(f, x))
+ goto foo;
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a stereo one-sample 16bps stream */
+static FLAC__bool generate_02(void)
+{
+ FILE *f;
+ FLAC__int16 xl = -32768, xr = 32767;
+
+ if(0 == (f = fopen("test02.raw", mode)))
+ return false;
+
+ if(!write_little_endian_int16(f, xl))
+ goto foo;
+ if(!write_little_endian_int16(f, xr))
+ goto foo;
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono five-sample 16bps stream */
+static FLAC__bool generate_03(void)
+{
+ FILE *f;
+ FLAC__int16 x[] = { -25, 0, 25, 50, 100 };
+ unsigned i;
+
+ if(0 == (f = fopen("test03.raw", mode)))
+ return false;
+
+ for(i = 0; i < 5; i++)
+ if(!write_little_endian_int16(f, x[i]))
+ goto foo;
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a stereo five-sample 16bps stream */
+static FLAC__bool generate_04(void)
+{
+ FILE *f;
+ FLAC__int16 x[] = { -25, 500, 0, 400, 25, 300, 50, 200, 100, 100 };
+ unsigned i;
+
+ if(0 == (f = fopen("test04.raw", mode)))
+ return false;
+
+ for(i = 0; i < 10; i++)
+ if(!write_little_endian_int16(f, x[i]))
+ goto foo;
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono full-scale deflection 8bps stream */
+static FLAC__bool generate_fsd8(const char *fn, const int pattern[], unsigned reps)
+{
+ FILE *f;
+ unsigned rep, p;
+
+ FLAC__ASSERT(pattern != 0);
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(rep = 0; rep < reps; rep++) {
+ for(p = 0; pattern[p]; p++) {
+ signed char x = pattern[p] > 0? 127 : -128;
+ if(fwrite(&x, sizeof(x), 1, f) < 1)
+ goto foo;
+ }
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono full-scale deflection 16bps stream */
+static FLAC__bool generate_fsd16(const char *fn, const int pattern[], unsigned reps)
+{
+ FILE *f;
+ unsigned rep, p;
+
+ FLAC__ASSERT(pattern != 0);
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(rep = 0; rep < reps; rep++) {
+ for(p = 0; pattern[p]; p++) {
+ FLAC__int16 x = pattern[p] > 0? 32767 : -32768;
+ if(!write_little_endian_int16(f, x))
+ goto foo;
+ }
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a stereo wasted-bits-per-sample 16bps stream */
+static FLAC__bool generate_wbps16(const char *fn, unsigned samples)
+{
+ FILE *f;
+ unsigned sample;
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(sample = 0; sample < samples; sample++) {
+ FLAC__int16 l = (sample % 2000) << 2;
+ FLAC__int16 r = (sample % 1000) << 3;
+ if(!write_little_endian_int16(f, l))
+ goto foo;
+ if(!write_little_endian_int16(f, r))
+ goto foo;
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono full-scale deflection 24bps stream */
+static FLAC__bool generate_fsd24(const char *fn, const int pattern[], unsigned reps)
+{
+ FILE *f;
+ unsigned rep, p;
+
+ FLAC__ASSERT(pattern != 0);
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(rep = 0; rep < reps; rep++) {
+ for(p = 0; pattern[p]; p++) {
+ FLAC__int32 x = pattern[p] > 0? 8388607 : -8388608;
+ if(!write_little_endian_int24(f, x))
+ goto foo;
+ }
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono sine-wave 8bps stream */
+static FLAC__bool generate_sine8_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2)
+{
+ const FLAC__int8 full_scale = 127;
+ const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+ const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+ FILE *f;
+ double theta1, theta2;
+ unsigned i;
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+ double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+ FLAC__int8 v = (FLAC__int8)(val + 0.5);
+ if(fwrite(&v, sizeof(v), 1, f) < 1)
+ goto foo;
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a stereo sine-wave 8bps stream */
+static FLAC__bool generate_sine8_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult)
+{
+ const FLAC__int8 full_scale = 127;
+ const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+ const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+ FILE *f;
+ double theta1, theta2;
+ unsigned i;
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+ double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+ FLAC__int8 v = (FLAC__int8)(val + 0.5);
+ if(fwrite(&v, sizeof(v), 1, f) < 1)
+ goto foo;
+ val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale;
+ v = (FLAC__int8)(val + 0.5);
+ if(fwrite(&v, sizeof(v), 1, f) < 1)
+ goto foo;
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono sine-wave 16bps stream */
+static FLAC__bool generate_sine16_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2)
+{
+ const FLAC__int16 full_scale = 32767;
+ const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+ const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+ FILE *f;
+ double theta1, theta2;
+ unsigned i;
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+ double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+ FLAC__int16 v = (FLAC__int16)(val + 0.5);
+ if(!write_little_endian_int16(f, v))
+ goto foo;
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a stereo sine-wave 16bps stream */
+static FLAC__bool generate_sine16_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult)
+{
+ const FLAC__int16 full_scale = 32767;
+ const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+ const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+ FILE *f;
+ double theta1, theta2;
+ unsigned i;
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+ double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+ FLAC__int16 v = (FLAC__int16)(val + 0.5);
+ if(!write_little_endian_int16(f, v))
+ goto foo;
+ val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale;
+ v = (FLAC__int16)(val + 0.5);
+ if(!write_little_endian_int16(f, v))
+ goto foo;
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a mono sine-wave 24bps stream */
+static FLAC__bool generate_sine24_1(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2)
+{
+ const FLAC__int32 full_scale = 0x7fffff;
+ const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+ const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+ FILE *f;
+ double theta1, theta2;
+ unsigned i;
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+ double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+ FLAC__int32 v = (FLAC__int32)(val + 0.5);
+ if(!write_little_endian_int24(f, v))
+ goto foo;
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+/* a stereo sine-wave 24bps stream */
+static FLAC__bool generate_sine24_2(const char *fn, const double sample_rate, const unsigned samples, const double f1, const double a1, const double f2, const double a2, double fmult)
+{
+ const FLAC__int32 full_scale = 0x7fffff;
+ const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+ const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+ FILE *f;
+ double theta1, theta2;
+ unsigned i;
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+ double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+ FLAC__int32 v = (FLAC__int32)(val + 0.5);
+ if(!write_little_endian_int24(f, v))
+ goto foo;
+ val = -(a1*sin(theta1*fmult) + a2*sin(theta2*fmult))*(double)full_scale;
+ v = (FLAC__int32)(val + 0.5);
+ if(!write_little_endian_int24(f, v))
+ goto foo;
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+static FLAC__bool generate_noise(const char *fn, unsigned bytes)
+{
+ FILE *f;
+ unsigned b;
+
+ if(0 == (f = fopen(fn, mode)))
+ return false;
+
+ for(b = 0; b < bytes; b++) {
+#if !defined _MSC_VER && !defined __MINGW32__
+ FLAC__byte x = (FLAC__byte)(((unsigned)random()) & 0xff);
+#else
+ FLAC__byte x = (FLAC__byte)(((unsigned)rand()) & 0xff);
+#endif
+ if(fwrite(&x, sizeof(x), 1, f) < 1)
+ goto foo;
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+static FLAC__bool generate_raw(const char *filename, unsigned channels, unsigned bytes_per_sample, unsigned samples)
+{
+ const FLAC__int32 full_scale = (1 << (bytes_per_sample*8-1)) - 1;
+ const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
+ const double delta1 = 2.0 * M_PI / ( 44100.0 / f1);
+ const double delta2 = 2.0 * M_PI / ( 44100.0 / f2);
+ double theta1, theta2;
+ FILE *f;
+ unsigned i, j;
+
+ if(0 == (f = fopen(filename, mode)))
+ return false;
+
+ for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+ for(j = 0; j < channels; j++) {
+ double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+ FLAC__int32 v = (FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8);
+ if(!write_little_endian(f, v, bytes_per_sample))
+ goto foo;
+ }
+ }
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+static FLAC__bool generate_aiff(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples)
+{
+ const unsigned bytes_per_sample = (bps+7)/8;
+ const unsigned true_size = channels * bytes_per_sample * samples;
+ const unsigned padded_size = (true_size + 1) & (~1u);
+ const unsigned shift = (bps%8)? 8 - (bps%8) : 0;
+ const FLAC__int32 full_scale = (1 << (bps-1)) - 1;
+ const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
+ const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+ const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+ double theta1, theta2;
+ FILE *f;
+ unsigned i, j;
+
+ if(0 == (f = fopen(filename, mode)))
+ return false;
+ if(fwrite("FORM", 1, 4, f) < 4)
+ goto foo;
+ if(!write_big_endian_uint32(f, padded_size + 46))
+ goto foo;
+ if(fwrite("AIFFCOMM\000\000\000\022", 1, 12, f) < 12)
+ goto foo;
+ if(!write_big_endian_uint16(f, (FLAC__uint16)channels))
+ goto foo;
+ if(!write_big_endian_uint32(f, samples))
+ goto foo;
+ if(!write_big_endian_uint16(f, (FLAC__uint16)bps))
+ goto foo;
+ if(!write_sane_extended(f, sample_rate))
+ goto foo;
+ if(fwrite("SSND", 1, 4, f) < 4)
+ goto foo;
+ if(!write_big_endian_uint32(f, true_size + 8))
+ goto foo;
+ if(fwrite("\000\000\000\000\000\000\000\000", 1, 8, f) < 8)
+ goto foo;
+
+ for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+ for(j = 0; j < channels; j++) {
+ double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+ FLAC__int32 v = ((FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8)) << shift;
+ if(!write_big_endian(f, v, bytes_per_sample))
+ goto foo;
+ }
+ }
+ for(i = true_size; i < padded_size; i++)
+ if(fputc(0, f) == EOF)
+ goto foo;
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples, FLAC__bool strict)
+{
+ const FLAC__bool waveformatextensible = strict && (channels > 2 || (bps%8));
+ /* ^^^^^^^
+ * (bps%8) allows 24 bps which is technically supposed to be WAVEFORMATEXTENSIBLE but we
+ * write 24bps as WAVEFORMATEX since it's unambiguous and matches how flac writes it
+ */
+ const unsigned bytes_per_sample = (bps+7)/8;
+ const unsigned true_size = channels * bytes_per_sample * samples;
+ const unsigned padded_size = (true_size + 1) & (~1u);
+ const unsigned shift = (bps%8)? 8 - (bps%8) : 0;
+ const FLAC__int32 full_scale = (1 << (bps-1)) - 1;
+ const double f1 = 441.0, a1 = 0.61, f2 = 661.5, a2 = 0.37;
+ const double delta1 = 2.0 * M_PI / ( sample_rate / f1);
+ const double delta2 = 2.0 * M_PI / ( sample_rate / f2);
+ double theta1, theta2;
+ FILE *f;
+ unsigned i, j;
+
+ if(0 == (f = fopen(filename, mode)))
+ return false;
+ if(fwrite("RIFF", 1, 4, f) < 4)
+ goto foo;
+ if(!write_little_endian_uint32(f, padded_size + (waveformatextensible?60:36)))
+ goto foo;
+ if(fwrite("WAVEfmt ", 1, 8, f) < 8)
+ goto foo;
+ if(!write_little_endian_uint32(f, waveformatextensible?40:16))
+ goto foo;
+ if(!write_little_endian_uint16(f, (FLAC__uint16)(waveformatextensible?65534:1)))
+ goto foo;
+ if(!write_little_endian_uint16(f, (FLAC__uint16)channels))
+ goto foo;
+ if(!write_little_endian_uint32(f, sample_rate))
+ goto foo;
+ if(!write_little_endian_uint32(f, sample_rate * channels * bytes_per_sample))
+ goto foo;
+ if(!write_little_endian_uint16(f, (FLAC__uint16)(channels * bytes_per_sample))) /* block align */
+ goto foo;
+ if(!write_little_endian_uint16(f, (FLAC__uint16)(bps+shift)))
+ goto foo;
+ if(waveformatextensible) {
+ if(!write_little_endian_uint16(f, (FLAC__uint16)22)) /* cbSize */
+ goto foo;
+ if(!write_little_endian_uint16(f, (FLAC__uint16)bps)) /* validBitsPerSample */
+ goto foo;
+ if(!write_little_endian_uint32(f, 0)) /* channelMask */
+ goto foo;
+ /* GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} */
+ if(fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16)
+ goto foo;
+ }
+ if(fwrite("data", 1, 4, f) < 4)
+ goto foo;
+ if(!write_little_endian_uint32(f, true_size))
+ goto foo;
+
+ for(i = 0, theta1 = theta2 = 0.0; i < samples; i++, theta1 += delta1, theta2 += delta2) {
+ for(j = 0; j < channels; j++) {
+ double val = (a1*sin(theta1) + a2*sin(theta2))*(double)full_scale;
+ FLAC__int32 v = ((FLAC__int32)(val + 0.5) + ((GET_RANDOM_BYTE>>4)-8)) << shift;
+ if(!write_little_endian(f, v, bytes_per_sample))
+ goto foo;
+ }
+ }
+ for(i = true_size; i < padded_size; i++)
+ if(fputc(0, f) == EOF)
+ goto foo;
+
+ fclose(f);
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+static FLAC__bool generate_wackywavs(void)
+{
+ FILE *f;
+ FLAC__byte wav[] = {
+ 'R', 'I', 'F', 'F', 76, 0, 0, 0,
+ 'W', 'A', 'V', 'E', 'f', 'a', 'c', 't',
+ 4, 0, 0, 0 , 'b', 'l', 'a', 'h',
+ 'p', 'a', 'd', ' ', 4, 0, 0, 0,
+ 'B', 'L', 'A', 'H', 'f', 'm', 't', ' ',
+ 16, 0, 0, 0, 1, 0, 1, 0,
+ 0x44,0xAC, 0, 0, 0, 0, 0, 0,
+ 2, 0, 16, 0, 'd', 'a', 't', 'a',
+ 16, 0, 0, 0, 0, 0, 1, 0,
+ 4, 0, 9, 0, 16, 0, 25, 0,
+ 36, 0, 49, 0, 'p', 'a', 'd', ' ',
+ 4, 0, 0, 0, 'b', 'l', 'a', 'h'
+ };
+
+ if(0 == (f = fopen("wacky1.wav", mode)))
+ return false;
+ if(fwrite(wav, 1, 84, f) < 84)
+ goto foo;
+ fclose(f);
+
+ wav[4] += 12;
+ if(0 == (f = fopen("wacky2.wav", mode)))
+ return false;
+ if(fwrite(wav, 1, 96, f) < 96)
+ goto foo;
+ fclose(f);
+
+ return true;
+foo:
+ fclose(f);
+ return false;
+}
+
+int main(int argc, char *argv[])
+{
+ FLAC__uint32 test = 1;
+ unsigned channels;
+
+ int pattern01[] = { 1, -1, 0 };
+ int pattern02[] = { 1, 1, -1, 0 };
+ int pattern03[] = { 1, -1, -1, 0 };
+ int pattern04[] = { 1, -1, 1, -1, 0 };
+ int pattern05[] = { 1, -1, -1, 1, 0 };
+ int pattern06[] = { 1, -1, 1, 1, -1, 0 };
+ int pattern07[] = { 1, -1, -1, 1, -1, 0 };
+
+ (void)argc;
+ (void)argv;
+ is_big_endian_host = (*((FLAC__byte*)(&test)))? false : true;
+
+#if !defined _MSC_VER && !defined __MINGW32__
+ {
+ struct timeval tv;
+
+ if(gettimeofday(&tv, 0) < 0) {
+ fprintf(stderr, "WARNING: couldn't seed RNG with time\n");
+ tv.tv_usec = 4321;
+ }
+ srandom(tv.tv_usec);
+ }
+#else
+ srand((unsigned)time(0));
+#endif
+
+ if(!generate_01()) return 1;
+ if(!generate_02()) return 1;
+ if(!generate_03()) return 1;
+ if(!generate_04()) return 1;
+
+ if(!generate_fsd8("fsd8-01.raw", pattern01, 100)) return 1;
+ if(!generate_fsd8("fsd8-02.raw", pattern02, 100)) return 1;
+ if(!generate_fsd8("fsd8-03.raw", pattern03, 100)) return 1;
+ if(!generate_fsd8("fsd8-04.raw", pattern04, 100)) return 1;
+ if(!generate_fsd8("fsd8-05.raw", pattern05, 100)) return 1;
+ if(!generate_fsd8("fsd8-06.raw", pattern06, 100)) return 1;
+ if(!generate_fsd8("fsd8-07.raw", pattern07, 100)) return 1;
+
+ if(!generate_fsd16("fsd16-01.raw", pattern01, 100)) return 1;
+ if(!generate_fsd16("fsd16-02.raw", pattern02, 100)) return 1;
+ if(!generate_fsd16("fsd16-03.raw", pattern03, 100)) return 1;
+ if(!generate_fsd16("fsd16-04.raw", pattern04, 100)) return 1;
+ if(!generate_fsd16("fsd16-05.raw", pattern05, 100)) return 1;
+ if(!generate_fsd16("fsd16-06.raw", pattern06, 100)) return 1;
+ if(!generate_fsd16("fsd16-07.raw", pattern07, 100)) return 1;
+
+ if(!generate_fsd24("fsd24-01.raw", pattern01, 100)) return 1;
+ if(!generate_fsd24("fsd24-02.raw", pattern02, 100)) return 1;
+ if(!generate_fsd24("fsd24-03.raw", pattern03, 100)) return 1;
+ if(!generate_fsd24("fsd24-04.raw", pattern04, 100)) return 1;
+ if(!generate_fsd24("fsd24-05.raw", pattern05, 100)) return 1;
+ if(!generate_fsd24("fsd24-06.raw", pattern06, 100)) return 1;
+ if(!generate_fsd24("fsd24-07.raw", pattern07, 100)) return 1;
+
+ if(!generate_wbps16("wbps16-01.raw", 1000)) return 1;
+
+ if(!generate_sine8_1("sine8-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1;
+ if(!generate_sine8_1("sine8-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1;
+ if(!generate_sine8_1("sine8-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1;
+ if(!generate_sine8_1("sine8-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+ if(!generate_sine8_1("sine8-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+ if(!generate_sine8_2("sine8-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1;
+ if(!generate_sine8_2("sine8-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1;
+ if(!generate_sine8_2("sine8-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1;
+ if(!generate_sine8_2("sine8-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1;
+ if(!generate_sine8_2("sine8-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1;
+ if(!generate_sine8_2("sine8-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1;
+ if(!generate_sine8_2("sine8-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1;
+ if(!generate_sine8_2("sine8-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1;
+ if(!generate_sine8_2("sine8-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1;
+ if(!generate_sine8_2("sine8-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1;
+
+ if(!generate_sine16_1("sine16-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1;
+ if(!generate_sine16_1("sine16-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1;
+ if(!generate_sine16_1("sine16-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1;
+ if(!generate_sine16_1("sine16-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+ if(!generate_sine16_1("sine16-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+ if(!generate_sine16_2("sine16-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1;
+ if(!generate_sine16_2("sine16-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1;
+ if(!generate_sine16_2("sine16-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1;
+ if(!generate_sine16_2("sine16-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1;
+ if(!generate_sine16_2("sine16-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1;
+ if(!generate_sine16_2("sine16-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1;
+ if(!generate_sine16_2("sine16-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1;
+ if(!generate_sine16_2("sine16-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1;
+ if(!generate_sine16_2("sine16-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1;
+ if(!generate_sine16_2("sine16-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1;
+
+ if(!generate_sine24_1("sine24-00.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49)) return 1;
+ if(!generate_sine24_1("sine24-01.raw", 96000.0, 200000, 441.0, 0.61, 661.5, 0.37)) return 1;
+ if(!generate_sine24_1("sine24-02.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49)) return 1;
+ if(!generate_sine24_1("sine24-03.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49)) return 1;
+ if(!generate_sine24_1("sine24-04.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29)) return 1;
+
+ if(!generate_sine24_2("sine24-10.raw", 48000.0, 200000, 441.0, 0.50, 441.0, 0.49, 1.0)) return 1;
+ if(!generate_sine24_2("sine24-11.raw", 48000.0, 200000, 441.0, 0.61, 661.5, 0.37, 1.0)) return 1;
+ if(!generate_sine24_2("sine24-12.raw", 96000.0, 200000, 441.0, 0.50, 882.0, 0.49, 1.0)) return 1;
+ if(!generate_sine24_2("sine24-13.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.0)) return 1;
+ if(!generate_sine24_2("sine24-14.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 1.0)) return 1;
+ if(!generate_sine24_2("sine24-15.raw", 44100.0, 200000, 441.0, 0.50, 441.0, 0.49, 0.5)) return 1;
+ if(!generate_sine24_2("sine24-16.raw", 44100.0, 200000, 441.0, 0.61, 661.5, 0.37, 2.0)) return 1;
+ if(!generate_sine24_2("sine24-17.raw", 44100.0, 200000, 441.0, 0.50, 882.0, 0.49, 0.7)) return 1;
+ if(!generate_sine24_2("sine24-18.raw", 44100.0, 200000, 441.0, 0.50, 4410.0, 0.49, 1.3)) return 1;
+ if(!generate_sine24_2("sine24-19.raw", 44100.0, 200000, 8820.0, 0.70, 4410.0, 0.29, 0.1)) return 1;
+
+ /* WATCHOUT: the size of noise.raw is hardcoded into test/test_flac.sh */
+ if(!generate_noise("noise.raw", 65536 * 8 * 3)) return 1;
+ if(!generate_noise("noise8m32.raw", 32)) return 1;
+ if(!generate_wackywavs()) return 1;
+ for(channels = 1; channels <= 8; channels++) {
+ unsigned bits_per_sample;
+ for(bits_per_sample = 4; bits_per_sample <= 24; bits_per_sample++) {
+ static const unsigned nsamples[] = { 1, 111, 4777 } ;
+ unsigned samples;
+ for(samples = 0; samples < sizeof(nsamples)/sizeof(nsamples[0]); samples++) {
+ char fn[64];
+
+ sprintf(fn, "rt-%u-%u-%u.aiff", channels, bits_per_sample, nsamples[samples]);
+ if(!generate_aiff(fn, 44100, channels, bits_per_sample, nsamples[samples]))
+ return 1;
+
+ sprintf(fn, "rt-%u-%u-%u.wav", channels, bits_per_sample, nsamples[samples]);
+ if(!generate_wav(fn, 44100, channels, bits_per_sample, nsamples[samples], /*strict=*/true))
+ return 1;
+
+ if(bits_per_sample % 8 == 0) {
+ sprintf(fn, "rt-%u-%u-%u.raw", channels, bits_per_sample, nsamples[samples]);
+ if(!generate_raw(fn, channels, bits_per_sample/8, nsamples[samples]))
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/src/FLAC/strip_non_asm_libtool_args.sh b/src/FLAC/strip_non_asm_libtool_args.sh
new file mode 100755
index 0000000..d5a61f1
--- /dev/null
+++ b/src/FLAC/strip_non_asm_libtool_args.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+#
+# libtool assumes that the compiler can handle the -fPIC flag.
+# This isn't always true (for example, nasm can't handle it).
+# Also, on some versions of OS X it tries to pass -fno-common
+# to 'as' which causes problems.
+command=""
+while [ $1 ]; do
+ if [ "$1" != "-fPIC" ]; then
+ if [ "$1" != "-DPIC" ]; then
+ if [ "$1" != "-fno-common" ]; then
+ command="$command $1"
+ fi
+ fi
+ fi
+ shift
+done
+echo $command
+exec $command
diff --git a/src/FLAC/test/Makefile.am b/src/FLAC/test/Makefile.am
new file mode 100644
index 0000000..8da031a
--- /dev/null
+++ b/src/FLAC/test/Makefile.am
@@ -0,0 +1,36 @@
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under difference licenses. The codec libraries
+# are distributed under Xiph.Org's BSD-like license (see the file
+# COPYING.Xiph in this distribution). All other programs, libraries, and
+# plugins are distributed under the GPL (see COPYING.GPL). The documentation
+# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
+# FLAC distribution contains at the top the terms under which it may be
+# distributed.
+#
+# Since this particular file is relevant to all components of FLAC,
+# it may be distributed under the Xiph.Org license, which is the least
+# restrictive of those mentioned above. See the file COPYING.Xiph in this
+# distribution.
+
+TESTS_ENVIRONMENT = FLAC__TEST_LEVEL=@FLAC__TEST_LEVEL@ FLAC__TEST_WITH_VALRGIND=@FLAC__TEST_WITH_VALGRIND@
+
+TESTS = \
+ ./test_libFLAC.sh
+
+EXTRA_DIST = \
+ test_libFLAC.sh
+
+CLEANFILES = \
+ $(wildcard *.raw) \
+ $(wildcard *.flac) \
+ $(wildcard *.ogg) \
+ $(wildcard *.cmp) \
+ $(wildcard *.aiff) \
+ $(wildcard *.wav) \
+ $(wildcard *.diff) \
+ $(wildcard *.log) \
+ $(wildcard *.cue) \
+ core
diff --git a/src/FLAC/test/test_bins.sh b/src/FLAC/test/test_bins.sh
new file mode 100755
index 0000000..a8c6517
--- /dev/null
+++ b/src/FLAC/test/test_bins.sh
@@ -0,0 +1,114 @@
+#!/bin/sh
+
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under difference licenses. The codec libraries
+# are distributed under Xiph.Org's BSD-like license (see the file
+# COPYING.Xiph in this distribution). All other programs, libraries, and
+# plugins are distributed under the GPL (see COPYING.GPL). The documentation
+# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
+# FLAC distribution contains at the top the terms under which it may be
+# distributed.
+#
+# Since this particular file is relevant to all components of FLAC,
+# it may be distributed under the Xiph.Org license, which is the least
+# restrictive of those mentioned above. See the file COPYING.Xiph in this
+# distribution.
+
+die ()
+{
+ echo $* 1>&2
+ exit 1
+}
+
+if [ x = x"$1" ] ; then
+ BUILD=debug
+else
+ BUILD="$1"
+fi
+
+LD_LIBRARY_PATH=../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/grabbag/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/getopt/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/replaygain_analysis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/replaygain_synthesis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/utf8/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../obj/$BUILD/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH
+PATH=../src/flac:$PATH
+PATH=../obj/$BUILD/bin:$PATH
+BINS_PATH=../../test_files/bins
+
+if [ x"$FLAC__TEST_LEVEL" = x ] ; then
+ FLAC__TEST_LEVEL=1
+fi
+
+flac --help 1>/dev/null 2>/dev/null || die "ERROR can't find flac executable"
+
+run_flac ()
+{
+ if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+ echo "valgrind --leak-check=yes --show-reachable=yes --num-callers=100 flac $*" >>test_bins.valgrind.log
+ valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --logfile-fd=4 flac $* 4>>test_bins.valgrind.log
+ else
+ flac $*
+ fi
+}
+
+test -d ${BINS_PATH} || exit 77
+
+test_file ()
+{
+ name=$1
+ channels=$2
+ bps=$3
+ encode_options="$4"
+
+ echo -n "$name.bin (--channels=$channels --bps=$bps $encode_options): encode..."
+ cmd="run_flac --verify --silent --force --force-raw-format --endian=big --sign=signed --sample-rate=44100 --bps=$bps --channels=$channels $encode_options --no-padding $name.bin"
+ echo "### ENCODE $name #######################################################" >> ./streams.log
+ echo "### cmd=$cmd" >> ./streams.log
+ $cmd 2>>./streams.log || die "ERROR during encode of $name"
+
+ echo -n "decode..."
+ cmd="run_flac --silent --force --endian=big --sign=signed --decode --force-raw-format $name.flac";
+ echo "### DECODE $name #######################################################" >> ./streams.log
+ echo "### cmd=$cmd" >> ./streams.log
+ $cmd 2>>./streams.log || die "ERROR during decode of $name"
+
+ ls -1l $name.bin >> ./streams.log
+ ls -1l $name.flac >> ./streams.log
+ ls -1l $name.raw >> ./streams.log
+
+ echo -n "compare..."
+ cmp $name.bin $name.raw || die "ERROR during compare of $name"
+
+ echo OK
+}
+
+echo "Testing bins..."
+for f in b00 b01 b02 b03 b04 ; do
+ binfile=$BINS_PATH/$f
+ if [ -f $binfile.bin ] ; then
+ for disable in '' '--disable-verbatim-subframes --disable-constant-subframes' '--disable-verbatim-subframes --disable-constant-subframes --disable-fixed-subframes' ; do
+ for channels in 1 2 4 8 ; do
+ for bps in 8 16 24 ; do
+ for opt in 0 1 2 4 5 6 8 ; do
+ for extras in '' '-p' '-e' ; do
+ for blocksize in '' '--lax -b 32' '--lax -b 32768' '--lax -b 65535' ; do
+ test_file $binfile $channels $bps "-$opt $extras $blocksize $disable"
+ done
+ done
+ done
+ if [ "$FLAC__TEST_LEVEL" -gt 1 ] ; then
+ test_file $binfile $channels $bps "--lax -b 16384 -m -r 8 -l 32 -e -p $disable"
+ fi
+ done
+ done
+ done
+ else
+ echo "$binfile not found, skipping."
+ fi
+done
diff --git a/src/FLAC/test/test_libFLAC.sh b/src/FLAC/test/test_libFLAC.sh
new file mode 100755
index 0000000..0a4e7c0
--- /dev/null
+++ b/src/FLAC/test/test_libFLAC.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+# FLAC - Free Lossless Audio Codec
+# Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson
+#
+# This file is part the FLAC project. FLAC is comprised of several
+# components distributed under difference licenses. The codec libraries
+# are distributed under Xiph.Org's BSD-like license (see the file
+# COPYING.Xiph in this distribution). All other programs, libraries, and
+# plugins are distributed under the GPL (see COPYING.GPL). The documentation
+# is distributed under the Gnu FDL (see COPYING.FDL). Each file in the
+# FLAC distribution contains at the top the terms under which it may be
+# distributed.
+#
+# Since this particular file is relevant to all components of FLAC,
+# it may be distributed under the Xiph.Org license, which is the least
+# restrictive of those mentioned above. See the file COPYING.Xiph in this
+# distribution.
+
+die ()
+{
+ echo $* 1>&2
+ exit 1
+}
+
+if [ x = x"$1" ] ; then
+ BUILD=debug
+else
+ BUILD="$1"
+fi
+
+LD_LIBRARY_PATH=../src/libFLAC/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/grabbag/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../src/share/replaygain_analysis/.libs:$LD_LIBRARY_PATH
+LD_LIBRARY_PATH=../obj/$BUILD/lib:$LD_LIBRARY_PATH
+export LD_LIBRARY_PATH
+PATH=../src/test_libFLAC:$PATH
+PATH=../obj/$BUILD/bin:$PATH
+
+run_test_libFLAC ()
+{
+ if [ x"$FLAC__TEST_WITH_VALGRIND" = xyes ] ; then
+ valgrind --leak-check=yes --show-reachable=yes --num-callers=100 --logfile-fd=4 test_libFLAC $* 4>>test_libFLAC.valgrind.log
+ else
+ test_libFLAC $*
+ fi
+}
+
+run_test_libFLAC || die "ERROR during test_libFLAC"
diff --git a/src/G72x/ChangeLog b/src/G72x/ChangeLog
new file mode 100644
index 0000000..aa108df
--- /dev/null
+++ b/src/G72x/ChangeLog
@@ -0,0 +1,50 @@
+2001-06-05 Erik de Castro Lopo <erikd@mega-nerd.com>
+
+ * g72x.c
+ Added {} in function update () to prevent 'ambiguous else' warning messages.
+
+2000-07-14 Erik de Castro Lopo <erikd@mega-nerd.com>
+
+ * 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 <erikd@mega-nerd.com>
+
+ * 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 <erikd@mega-nerd.com>
+
+ * 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/src/G72x/Makefile.am b/src/G72x/Makefile.am
new file mode 100644
index 0000000..8fb2909
--- /dev/null
+++ b/src/G72x/Makefile.am
@@ -0,0 +1,28 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = README README.original ChangeLog
+
+noinst_HEADERS = g72x.h g72x_priv.h
+noinst_LTLIBRARIES = libg72x.la
+
+noinst_PROGRAMS = g72x_test$(EXEEXT)
+
+CFILES = g72x.c g721.c g723_16.c g723_24.c g723_40.c
+
+libg72x_la_SOURCES = $(CFILES) $(noinst_HEADERS)
+
+g72x_test_SOURCES = g72x_test.c
+g72x_test_LDADD = ./libg72x.la -lm
+
+check: g72x_test
+ ./g72x_test all
+
+# Disable autoheader.
+AUTOHEADER=echo
+
+## Do not edit or modify anything in this comment block.
+## The arch-tag line is a file identity tag for the GNU Arch
+## revision control system.
+##
+## arch-tag: d417a8e8-da7f-423d-884d-f03c93379348
+
diff --git a/src/G72x/README b/src/G72x/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/G72x/README
diff --git a/src/G72x/README.original b/src/G72x/README.original
new file mode 100644
index 0000000..23b0e7d
--- /dev/null
+++ b/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] <infile >outfile
+ decode [-3|4|5] [-a|u|l] <infile >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 <pcmfile >g721file
+
+ # Read 40Kbps G.723 and output A-law
+ decode -5 -a <g723file >alawfile
+
+ # Compress and then decompress u-law data using 24Kbps G.723
+ encode -3 <ulawin | deoced -3 >ulawout
+
diff --git a/src/G72x/g721.c b/src/G72x/g721.c
new file mode 100644
index 0000000..4f51bb1
--- /dev/null
+++ b/src/G72x/g721.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
+ */
+
+/*
+ * 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, _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, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr);
+
+ /* sr was 14-bit dynamic range */
+ return (sr << 2);
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 101b6e25-457d-490a-99ae-e2e74a26ea24
+*/
+
diff --git a/src/G72x/g723_16.c b/src/G72x/g723_16.c
new file mode 100644
index 0000000..0c31745
--- /dev/null
+++ b/src/G72x/g723_16.c
@@ -0,0 +1,169 @@
+/*
+ * 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);
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: ae265466-c3fc-4f83-bb32-edae488a5ca5
+*/
+
diff --git a/src/G72x/g723_24.c b/src/G72x/g723_24.c
new file mode 100644
index 0000000..8748459
--- /dev/null
+++ b/src/G72x/g723_24.c
@@ -0,0 +1,146 @@
+/*
+ * 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 (sr << 2); /* sr was of 14-bit dynamic range */
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 75389236-650b-4427-98f3-0df6e8fb24bc
+*/
+
diff --git a/src/G72x/g723_40.c b/src/G72x/g723_40.c
new file mode 100644
index 0000000..6ddb577
--- /dev/null
+++ b/src/G72x/g723_40.c
@@ -0,0 +1,160 @@
+/*
+ * 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 (sr << 2); /* sr was of 14-bit dynamic range */
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: eb8d9a00-32bf-4dd2-b287-01b0336d72bf
+*/
+
diff --git a/src/G72x/g72x.c b/src/G72x/g72x.c
new file mode 100644
index 0000000..fe366f4
--- /dev/null
+++ b/src/G72x/g72x.c
@@ -0,0 +1,652 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 */
+ else
+ 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 6298dc75-fd0f-4062-9b90-f73ed69f22d4
+*/
+
diff --git a/src/G72x/g72x.h b/src/G72x/g72x.h
new file mode 100644
index 0000000..e6319e6
--- /dev/null
+++ b/src/G72x/g72x.h
@@ -0,0 +1,99 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 6ca84e5f-f932-4ba1-87ee-37056d921621
+*/
+
diff --git a/src/G72x/g72x_priv.h b/src/G72x/g72x_priv.h
new file mode 100644
index 0000000..a88e96d
--- /dev/null
+++ b/src/G72x/g72x_priv.h
@@ -0,0 +1,118 @@
+/*
+ * 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) ;
+
+#endif /* G72X_PRIVATE_H */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: d9ad4da7-0fa3-471d-8020-720b5cfb5e5b
+*/
+
diff --git a/src/G72x/g72x_test.c b/src/G72x/g72x_test.c
new file mode 100644
index 0000000..caf5846
--- /dev/null
+++ b/src/G72x/g72x_test.c
@@ -0,0 +1,222 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "g72x.h"
+#include "g72x_priv.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846264338
+#endif
+
+#define BUFFER_SIZE (1<<14) /* Should be (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 <test>\n", argv [0]) ;
+ printf (" Where <test> 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 0597b442-a5b0-4abf-92a4-92f6c24e85a6
+*/
+
diff --git a/src/GSM610/COPYRIGHT b/src/GSM610/COPYRIGHT
new file mode 100644
index 0000000..eba0e52
--- /dev/null
+++ b/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/src/GSM610/ChangeLog b/src/GSM610/ChangeLog
new file mode 100644
index 0000000..24f5248
--- /dev/null
+++ b/src/GSM610/ChangeLog
@@ -0,0 +1,56 @@
+2004-05-12 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * 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 <erikd AT mega-nerd DOT com>
+
+ * rpe.c
+ Renamed variables "exp" to "expon" to avoid shadowed parameter warnigns.
+
+2002-06-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * long_term.c
+ Changes tp removed compiler warnings about shadowed parameters.
+
+2002-06-08 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * 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 <erikd AT mega-nerd DOT com>
+
+ * *.[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 <erikd AT mega-nerd DOT com>
+
+ * code.c
+ Added #includes for string.h and stdlib.h.
+
+2000-10-27 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * 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 <erikd AT mega-nerd DOT com>
+
+ * private.h
+ Added #defines to emulate normal compile time options.
+
+2000-02-28 Erik de Castro Lopo <erikd AT mega-nerd DOT com>
+
+ * everthing
+ Created this directory and copied files from libgsm.
+ http://kbs.cs.tu-berlin.de/~jutta/toast.html
diff --git a/src/GSM610/Makefile.am b/src/GSM610/Makefile.am
new file mode 100644
index 0000000..e754ba9
--- /dev/null
+++ b/src/GSM610/Makefile.am
@@ -0,0 +1,21 @@
+## Process this file with automake to produce Makefile.in
+
+EXTRA_DIST = README COPYRIGHT ChangeLog
+
+noinst_HEADERS = gsm.h config.h gsm610_priv.h
+noinst_LTLIBRARIES = libgsm.la
+
+CFILES = add.c decode.c gsm_decode.c gsm_encode.c long_term.c preprocess.c \
+ short_term.c code.c gsm_create.c gsm_destroy.c gsm_option.c lpc.c rpe.c table.c
+
+libgsm_la_SOURCES = $(CFILES) $(noinst_HEADERS)
+
+# Disable autoheader.
+AUTOHEADER=echo
+
+## Do not edit or modify anything in this comment block.
+## The arch-tag line is a file identity tag for the GNU Arch
+## revision control system.
+##
+## arch-tag: ba91ffbe-9d1d-4044-a1de-e8ee2f890560
+
diff --git a/src/GSM610/README b/src/GSM610/README
new file mode 100644
index 0000000..b57132b
--- /dev/null
+++ b/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/src/GSM610/add.c b/src/GSM610/add.c
new file mode 100644
index 0000000..fbf7cf1
--- /dev/null
+++ b/src/GSM610/add.c
@@ -0,0 +1,248 @@
+/*
+ * 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 <stdio.h>
+#include <assert.h>
+
+#include "gsm610_priv.h"
+#include "gsm.h"
+
+#define saturate(x) \
+ ((x) < MIN_WORD ? MIN_WORD : (x) > MAX_WORD ? MAX_WORD: (x))
+
+word gsm_add ( word a, word b)
+{
+ longword sum = (longword)a + (longword)b;
+ return saturate(sum);
+}
+
+word gsm_sub ( word a, word b)
+{
+ longword diff = (longword)a - (longword)b;
+ return saturate(diff);
+}
+
+word gsm_mult ( word a, word b)
+{
+ if (a == MIN_WORD && b == MIN_WORD)
+ return MAX_WORD;
+
+ return SASR_L( (longword)a * (longword)b, 15 );
+}
+
+word gsm_mult_r ( word a, word b)
+{
+ if (b == MIN_WORD && a == MIN_WORD) return MAX_WORD;
+ else {
+ longword prod = (longword)a * (longword)b + 16384;
+ prod >>= 15;
+ return prod & 0xFFFF;
+ }
+}
+
+word gsm_abs (word a)
+{
+ return a < 0 ? (a == MIN_WORD ? MAX_WORD : -a) : a;
+}
+
+longword gsm_L_mult (word a, word b)
+{
+ assert( a != MIN_WORD || b != MIN_WORD );
+ return ((longword)a * (longword)b) << 1;
+}
+
+longword gsm_L_add ( longword a, longword b)
+{
+ if (a < 0) {
+ if (b >= 0) return a + b;
+ else {
+ ulongword A = (ulongword)-(a + 1) + (ulongword)-(b + 1);
+ return A >= MAX_LONGWORD ? MIN_LONGWORD :-(longword)A-2;
+ }
+ }
+ else if (b <= 0) return a + b;
+ else {
+ ulongword A = (ulongword)a + (ulongword)b;
+ return A > MAX_LONGWORD ? MAX_LONGWORD : A;
+ }
+}
+
+longword gsm_L_sub ( longword a, longword b)
+{
+ if (a >= 0) {
+ if (b >= 0) return a - b;
+ else {
+ /* a>=0, b<0 */
+
+ ulongword A = (ulongword)a + -(b + 1);
+ return A >= MAX_LONGWORD ? MAX_LONGWORD : (A + 1);
+ }
+ }
+ else if (b <= 0) return a - b;
+ else {
+ /* a<0, b>0 */
+
+ ulongword A = (ulongword)-(a + 1) + b;
+ return A >= MAX_LONGWORD ? MIN_LONGWORD : -(longword)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
+};
+
+word gsm_norm (longword 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 ] );
+}
+
+longword gsm_L_asl (longword 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;
+}
+
+word gsm_asr (word a, int n)
+{
+ if (n >= 16) return -(a < 0);
+ if (n <= -16) return 0;
+ if (n < 0) return a << -n;
+
+ return SASR_W (a, (word) n);
+}
+
+word gsm_asl (word 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;
+}
+
+longword gsm_L_asr (longword a, int n)
+{
+ if (n >= 32) return -(a < 0);
+ if (n <= -32) return 0;
+ if (n < 0) return a << -n;
+
+ return SASR_L (a, (word) n);
+}
+
+/*
+** word gsm_asr (word 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 -(word)( -(uword)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
+ */
+
+word gsm_div (word num, word denum)
+{
+ longword L_num = num;
+ longword L_denum = denum;
+ word 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;
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: a7398579-e2e1-4733-aa2d-4c6efc0c58ff
+*/
+
diff --git a/src/GSM610/code.c b/src/GSM610/code.c
new file mode 100644
index 0000000..02ec75b
--- /dev/null
+++ b/src/GSM610/code.c
@@ -0,0 +1,97 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+#include "gsm610_priv.h"
+#include "gsm.h"
+
+/*
+ * 4.2 FIXED POINT IMPLEMENTATION OF THE RPE-LTP CODER
+ */
+
+void Gsm_Coder (
+
+ struct gsm_state * State,
+
+ word * 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:
+ */
+
+ word * 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:
+ */
+
+ word * Nc, /* [0..3] LTP lag OUT */
+ word * bc, /* [0..3] coded LTP gain OUT */
+ word * Mc, /* [0..3] RPE grid selection OUT */
+ word * xmaxc,/* [0..3] Coded maximum amplitude OUT */
+ word * xMc /* [13*4] normalized RPE samples OUT */
+)
+{
+ int k;
+ word * dp = State->dp0 + 120; /* [ -120...-1 ] */
+ word * dpp = dp; /* [ 0...39 ] */
+
+ word 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, 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;
+
+ }
+ (void)memcpy( (char *)State->dp0, (char *)(State->dp0 + 160),
+ 120 * sizeof(*State->dp0) );
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: ae8ef1b2-5a1e-4263-94cd-42b15dca81a3
+*/
+
diff --git a/src/GSM610/config.h b/src/GSM610/config.h
new file mode 100644
index 0000000..23ac5ad
--- /dev/null
+++ b/src/GSM610/config.h
@@ -0,0 +1,33 @@
+/*
+ * 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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 5338dfef-8e59-4f51-af47-627c9ea85353
+*/
+
diff --git a/src/GSM610/decode.c b/src/GSM610/decode.c
new file mode 100644
index 0000000..46db318
--- /dev/null
+++ b/src/GSM610/decode.c
@@ -0,0 +1,67 @@
+/*
+ * 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 <stdio.h>
+
+#include "gsm610_priv.h"
+#include "gsm.h"
+
+/*
+ * 4.3 FIXED POINT IMPLEMENTATION OF THE RPE-LTP DECODER
+ */
+
+static void Postprocessing (
+ struct gsm_state * S,
+ register word * s)
+{
+ register int k;
+ register word msr = S->msr;
+ register word 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,
+
+ word * LARcr, /* [0..7] IN */
+
+ word * Ncr, /* [0..3] IN */
+ word * bcr, /* [0..3] IN */
+ word * Mcr, /* [0..3] IN */
+ word * xmaxcr, /* [0..3] IN */
+ word * xMcr, /* [0..13*4] IN */
+
+ word * s) /* [0..159] OUT */
+{
+ int j, k;
+ word erp[40], wt[160];
+ word * 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);
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 11ae5b90-2e8b-400b-ac64-a69a1fc6cc41
+*/
+
diff --git a/src/GSM610/gsm.h b/src/GSM610/gsm.h
new file mode 100644
index 0000000..a13a606
--- /dev/null
+++ b/src/GSM610/gsm.h
@@ -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.
+ */
+
+#ifndef GSM_H
+#define GSM_H
+
+#include <stdio.h> /* 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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 8cfc7698-5433-4b6f-aeca-967c6fda4dec
+*/
+
diff --git a/src/GSM610/gsm610_priv.h b/src/GSM610/gsm610_priv.h
new file mode 100644
index 0000000..c9ab3f2
--- /dev/null
+++ b/src/GSM610/gsm610_priv.h
@@ -0,0 +1,308 @@
+/*
+ * 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
+
+/* 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 */
+
+
+
+typedef short word; /* 16 bit signed int */
+typedef int longword; /* 32 bit signed int */
+
+typedef unsigned short uword; /* unsigned word */
+typedef unsigned int ulongword; /* unsigned longword */
+
+struct gsm_state
+{ word dp0[ 280 ] ;
+
+ word z1; /* preprocessing.c, Offset_com. */
+ longword L_z2; /* Offset_com. */
+ int mp; /* Preemphasis */
+
+ word u[8] ; /* short_term_aly_filter.c */
+ word LARpp[2][8] ; /* */
+ word j; /* */
+
+ word ltp_cut; /* long_term.c, LTP crosscorr. */
+ word nrp; /* 40 */ /* long_term.c, synthesis */
+ word v[9] ; /* short_term.c, synthesis */
+ word 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 */
+ word 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 word
+SASR_W (word x, word by)
+{ return (x >> by) ;
+} /* SASR */
+
+static inline longword
+SASR_L (longword x, word by)
+{ return (x >> by) ;
+} /* SASR */
+
+/*
+ * Prototypes from add.c
+ */
+word gsm_mult (word a, word b) ;
+longword gsm_L_mult (word a, word b) ;
+word gsm_mult_r (word a, word b) ;
+
+word gsm_div (word num, word denum) ;
+
+word gsm_add (word a, word b ) ;
+longword gsm_L_add (longword a, longword b ) ;
+
+word gsm_sub (word a, word b) ;
+longword gsm_L_sub (longword a, longword b) ;
+
+word gsm_abs (word a) ;
+
+word gsm_norm (longword a ) ;
+
+longword gsm_L_asl (longword a, int n) ;
+word gsm_asl (word a, int n) ;
+
+longword gsm_L_asr (longword a, int n) ;
+word gsm_asr (word a, int n) ;
+
+/*
+ * Inlined functions from add.h
+ */
+
+static inline longword
+GSM_MULT_R (word a, word b)
+{ return (((longword) (a)) * ((longword) (b)) + 16384) >> 15 ;
+} /* GSM_MULT_R */
+
+static inline longword
+GSM_MULT (word a, word b)
+{ return (((longword) (a)) * ((longword) (b))) >> 15 ;
+} /* GSM_MULT */
+
+static inline longword
+GSM_L_MULT (word a, word b)
+{ return ((longword) (a)) * ((longword) (b)) << 1 ;
+} /* GSM_L_MULT */
+
+static inline longword
+GSM_L_ADD (longword a, longword b)
+{ ulongword utmp ;
+
+ if (a < 0 && b < 0)
+ { utmp = (ulongword)-((a) + 1) + (ulongword)-((b) + 1) ;
+ return (utmp >= (ulongword) MAX_LONGWORD) ? MIN_LONGWORD : -(longword)utmp-2 ;
+ } ;
+
+ if (a > 0 && b > 0)
+ { utmp = (ulongword) a + (ulongword) b ;
+ return (utmp >= (ulongword) MAX_LONGWORD) ? MAX_LONGWORD : utmp ;
+ } ;
+
+ return a + b ;
+} /* GSM_L_ADD */
+
+static inline longword
+GSM_ADD (word a, word b)
+{ longword ltmp ;
+
+ ltmp = ((longword) a) + ((longword) b) ;
+
+ if (ltmp >= MAX_WORD)
+ return MAX_WORD ;
+ if (ltmp <= MIN_WORD)
+ return MIN_WORD ;
+
+ return ltmp ;
+} /* GSM_ADD */
+
+static inline longword
+GSM_SUB (word a, word b)
+{ longword ltmp ;
+
+ ltmp = ((longword) a) - ((longword) b) ;
+
+ if (ltmp >= MAX_WORD)
+ ltmp = MAX_WORD ;
+ else if (ltmp <= MIN_WORD)
+ ltmp = MIN_WORD ;
+
+ return ltmp ;
+} /* GSM_SUB */
+
+static inline word
+GSM_ABS (word 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,
+ word * s, /* [0..159] samples IN */
+ word * LARc, /* [0..7] LAR coefficients OUT */
+ word * Nc, /* [0..3] LTP lag OUT */
+ word * bc, /* [0..3] coded LTP gain OUT */
+ word * Mc, /* [0..3] RPE grid selection OUT */
+ word * xmaxc,/* [0..3] Coded maximum amplitude OUT */
+ word * xMc) ;/* [13*4] normalized RPE samples OUT */
+
+void Gsm_Long_Term_Predictor ( /* 4x for 160 samples */
+ struct gsm_state * S,
+ word * d, /* [0..39] residual signal IN */
+ word * dp, /* [-120..-1] d' IN */
+ word * e, /* [0..40] OUT */
+ word * dpp, /* [0..40] OUT */
+ word * Nc, /* correlation lag OUT */
+ word * bc) ; /* gain factor OUT */
+
+void Gsm_LPC_Analysis (
+ struct gsm_state * S,
+ word * s, /* 0..159 signals IN/OUT */
+ word * LARc) ; /* 0..7 LARc's OUT */
+
+void Gsm_Preprocess (
+ struct gsm_state * S,
+ word * s, word * so) ;
+
+void Gsm_Encoding (
+ struct gsm_state * S,
+ word * e,
+ word * ep,
+ word * xmaxc,
+ word * Mc,
+ word * xMc) ;
+
+void Gsm_Short_Term_Analysis_Filter (
+ struct gsm_state * S,
+ word * LARc, /* coded log area ratio [0..7] IN */
+ word * d) ; /* st res. signal [0..159] IN/OUT */
+
+void Gsm_Decoder (
+ struct gsm_state * S,
+ word * LARcr, /* [0..7] IN */
+ word * Ncr, /* [0..3] IN */
+ word * bcr, /* [0..3] IN */
+ word * Mcr, /* [0..3] IN */
+ word * xmaxcr, /* [0..3] IN */
+ word * xMcr, /* [0..13*4] IN */
+ word * s) ; /* [0..159] OUT */
+
+void Gsm_Decoding (
+ struct gsm_state * S,
+ word xmaxcr,
+ word Mcr,
+ word * xMcr, /* [0..12] IN */
+ word * erp) ; /* [0..39] OUT */
+
+void Gsm_Long_Term_Synthesis_Filtering (
+ struct gsm_state* S,
+ word Ncr,
+ word bcr,
+ word * erp, /* [0..39] IN */
+ word * drp) ; /* [-120..-1] IN, [0..40] OUT */
+
+void Gsm_RPE_Decoding (
+ /*-struct gsm_state *S,-*/
+ word xmaxcr,
+ word Mcr,
+ word * xMcr, /* [0..12], 3 bits IN */
+ word * erp) ; /* [0..39] OUT */
+
+void Gsm_RPE_Encoding (
+ /*-struct gsm_state * S,-*/
+ word * e, /* -5..-1][0..39][40..44 IN/OUT */
+ word * xmaxc, /* OUT */
+ word * Mc, /* OUT */
+ word * xMc) ; /* [0..12] OUT */
+
+void Gsm_Short_Term_Synthesis_Filter (
+ struct gsm_state * S,
+ word * LARcr, /* log area ratios [0..7] IN */
+ word * drp, /* received d [0...39] IN */
+ word * s) ; /* signal s [0..159] OUT */
+
+void Gsm_Update_of_reconstructed_short_time_residual_signal (
+ word * dpp, /* [0...39] IN */
+ word * ep, /* [0...39] IN */
+ word * dp) ; /* [-120...-1] IN/OUT */
+
+/*
+ * Tables from table.c
+ */
+#ifndef GSM_TABLE_C
+
+extern word gsm_A [8], gsm_B [8], gsm_MIC [8], gsm_MAC [8] ;
+extern word gsm_INVA [8] ;
+extern word gsm_DLB [4], gsm_QLB [4] ;
+extern word gsm_H [11] ;
+extern word gsm_NRFAC [8] ;
+extern word gsm_FAC [8] ;
+
+#endif /* GSM_TABLE_C */
+
+/*
+ * Debugging
+ */
+#ifdef NDEBUG
+
+# define gsm_debug_words(a, b, c, d) /* nil */
+# define gsm_debug_longwords(a, b, c, d) /* nil */
+# define gsm_debug_word(a, b) /* nil */
+# define gsm_debug_longword(a, b) /* nil */
+
+#else /* !NDEBUG => DEBUG */
+
+ void gsm_debug_words (char * name, int, int, word *) ;
+ void gsm_debug_longwords (char * name, int, int, longword *) ;
+ void gsm_debug_longword (char * name, longword) ;
+ void gsm_debug_word (char * name, word) ;
+
+#endif /* !NDEBUG */
+
+#endif /* PRIVATE_H */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 8bc5fdf2-e8c8-4686-9bd7-a30b512bef0c
+*/
+
diff --git a/src/GSM610/gsm_create.c b/src/GSM610/gsm_create.c
new file mode 100644
index 0000000..94e8d7d
--- /dev/null
+++ b/src/GSM610/gsm_create.c
@@ -0,0 +1,44 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+#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 ;
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 9fedb6b3-ed99-40c2-aac1-484c536261fe
+*/
+
diff --git a/src/GSM610/gsm_decode.c b/src/GSM610/gsm_decode.c
new file mode 100644
index 0000000..e642558
--- /dev/null
+++ b/src/GSM610/gsm_decode.c
@@ -0,0 +1,366 @@
+/*
+ * 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)
+{
+ word LARc[8], Nc[4], Mc[4], bc[4], xmaxc[4], xmc[13*4];
+
+#ifdef WAV49
+ if (s->wav_fmt) {
+
+ uword sr = 0;
+
+ s->frame_index = !s->frame_index;
+ if (s->frame_index) {
+
+ sr = *c++;
+ LARc[0] = sr & 0x3f; sr >>= 6;
+ sr |= (uword)*c++ << 2;
+ LARc[1] = sr & 0x3f; sr >>= 6;
+ sr |= (uword)*c++ << 4;
+ LARc[2] = sr & 0x1f; sr >>= 5;
+ LARc[3] = sr & 0x1f; sr >>= 5;
+ sr |= (uword)*c++ << 2;
+ LARc[4] = sr & 0xf; sr >>= 4;
+ LARc[5] = sr & 0xf; sr >>= 4;
+ sr |= (uword)*c++ << 2; /* 5 */
+ LARc[6] = sr & 0x7; sr >>= 3;
+ LARc[7] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*c++ << 4;
+ Nc[0] = sr & 0x7f; sr >>= 7;
+ bc[0] = sr & 0x3; sr >>= 2;
+ Mc[0] = sr & 0x3; sr >>= 2;
+ sr |= (uword)*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 |= (uword)*c++ << 2;
+ xmc[3] = sr & 0x7; sr >>= 3;
+ xmc[4] = sr & 0x7; sr >>= 3;
+ xmc[5] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*c++ << 2;
+ xmc[11] = sr & 0x7; sr >>= 3;
+ xmc[12] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*c++ << 4;
+ Nc[1] = sr & 0x7f; sr >>= 7;
+ bc[1] = sr & 0x3; sr >>= 2;
+ Mc[1] = sr & 0x3; sr >>= 2;
+ sr |= (uword)*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 |= (uword)*c++ << 2;
+ xmc[16] = sr & 0x7; sr >>= 3;
+ xmc[17] = sr & 0x7; sr >>= 3;
+ xmc[18] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*c++ << 2;
+ xmc[24] = sr & 0x7; sr >>= 3;
+ xmc[25] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*c++ << 4; /* 20 */
+ Nc[2] = sr & 0x7f; sr >>= 7;
+ bc[2] = sr & 0x3; sr >>= 2;
+ Mc[2] = sr & 0x3; sr >>= 2;
+ sr |= (uword)*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 |= (uword)*c++ << 2;
+ xmc[29] = sr & 0x7; sr >>= 3;
+ xmc[30] = sr & 0x7; sr >>= 3;
+ xmc[31] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*c++ << 2;
+ xmc[37] = sr & 0x7; sr >>= 3;
+ xmc[38] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*c++ << 4;
+ Nc[3] = sr & 0x7f; sr >>= 7;
+ bc[3] = sr & 0x3; sr >>= 2;
+ Mc[3] = sr & 0x3; sr >>= 2;
+ sr |= (uword)*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 |= (uword)*c++ << 2; /* 30 */
+ xmc[42] = sr & 0x7; sr >>= 3;
+ xmc[43] = sr & 0x7; sr >>= 3;
+ xmc[44] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*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 |= (uword)*c++ << 4; /* 1 */
+ LARc[0] = sr & 0x3f; sr >>= 6;
+ LARc[1] = sr & 0x3f; sr >>= 6;
+ sr = *c++;
+ LARc[2] = sr & 0x1f; sr >>= 5;
+ sr |= (uword)*c++ << 3;
+ LARc[3] = sr & 0x1f; sr >>= 5;
+ LARc[4] = sr & 0xf; sr >>= 4;
+ sr |= (uword)*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 |= (uword)*c++ << 1;
+ bc[0] = sr & 0x3; sr >>= 2;
+ Mc[0] = sr & 0x3; sr >>= 2;
+ sr |= (uword)*c++ << 5;
+ xmaxc[0] = sr & 0x3f; sr >>= 6;
+ xmc[0] = sr & 0x7; sr >>= 3;
+ xmc[1] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*c++ << 2; /* 10 */
+ xmc[7] = sr & 0x7; sr >>= 3;
+ xmc[8] = sr & 0x7; sr >>= 3;
+ xmc[9] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*c++ << 1;
+ bc[1] = sr & 0x3; sr >>= 2;
+ Mc[1] = sr & 0x3; sr >>= 2;
+ sr |= (uword)*c++ << 5;
+ xmaxc[1] = sr & 0x3f; sr >>= 6;
+ xmc[13] = sr & 0x7; sr >>= 3;
+ xmc[14] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*c++ << 2;
+ xmc[20] = sr & 0x7; sr >>= 3;
+ xmc[21] = sr & 0x7; sr >>= 3;
+ xmc[22] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*c++ << 1; /* 20 */
+ bc[2] = sr & 0x3; sr >>= 2;
+ Mc[2] = sr & 0x3; sr >>= 2;
+ sr |= (uword)*c++ << 5;
+ xmaxc[2] = sr & 0x3f; sr >>= 6;
+ xmc[26] = sr & 0x7; sr >>= 3;
+ xmc[27] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*c++ << 2;
+ xmc[33] = sr & 0x7; sr >>= 3;
+ xmc[34] = sr & 0x7; sr >>= 3;
+ xmc[35] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*c++ << 1;
+ bc[3] = sr & 0x3; sr >>= 2;
+ Mc[3] = sr & 0x3; sr >>= 2;
+ sr |= (uword)*c++ << 5;
+ xmaxc[3] = sr & 0x3f; sr >>= 6;
+ xmc[39] = sr & 0x7; sr >>= 3;
+ xmc[40] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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 |= (uword)*c++ << 2;
+ xmc[46] = sr & 0x7; sr >>= 3;
+ xmc[47] = sr & 0x7; sr >>= 3;
+ xmc[48] = sr & 0x7; sr >>= 3;
+ sr |= (uword)*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;
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 6a9b6628-821c-4a96-84c1-485ebd35f170
+*/
+
diff --git a/src/GSM610/gsm_destroy.c b/src/GSM610/gsm_destroy.c
new file mode 100644
index 0000000..9e2d6a4
--- /dev/null
+++ b/src/GSM610/gsm_destroy.c
@@ -0,0 +1,31 @@
+/*
+ * 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 <stdlib.h>
+#else
+# ifdef HAS_MALLOC_H
+# include <malloc.h>
+# else
+ extern void free();
+# endif
+#endif
+
+void gsm_destroy (gsm S)
+{
+ if (S) free((char *)S);
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: f423d09b-6ccc-47e0-9b18-ee1cf7a8e473
+*/
+
diff --git a/src/GSM610/gsm_encode.c b/src/GSM610/gsm_encode.c
new file mode 100644
index 0000000..02af4ba
--- /dev/null
+++ b/src/GSM610/gsm_encode.c
@@ -0,0 +1,456 @@
+/*
+ * 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)
+{
+ word 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) {
+
+ uword 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 {
+ uword 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);
+
+ }
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: cfe9c43d-d97c-4216-b5e5-ccd6a25b582b
+*/
+
diff --git a/src/GSM610/gsm_option.c b/src/GSM610/gsm_option.c
new file mode 100644
index 0000000..5c56d78
--- /dev/null
+++ b/src/GSM610/gsm_option.c
@@ -0,0 +1,74 @@
+/*
+ * 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;
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 963ff156-506f-4359-9145-371e9060b030
+*/
+
diff --git a/src/GSM610/long_term.c b/src/GSM610/long_term.c
new file mode 100644
index 0000000..b782d11
--- /dev/null
+++ b/src/GSM610/long_term.c
@@ -0,0 +1,969 @@
+/*
+ * 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 <stdio.h>
+#include <assert.h>
+
+#include "gsm610_priv.h"
+
+#include "gsm.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 word * d, /* [0..39] IN */
+ register word * dp, /* [-120..-1] IN */
+ word * bc_out, /* OUT */
+ word * Nc_out /* OUT */
+)
+{
+ register int k, lambda;
+ word Nc, bc;
+ word wt[40];
+
+ longword L_result;
+ longword L_max, L_power;
+ word R, S, dmax, scal, best_k;
+ word ltp_cut;
+
+ register word 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( (longword)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 = (longword)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 longword 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 word * d, /* [0..39] IN */
+ register word * dp, /* [-120..-1] IN */
+ word * bc_out, /* OUT */
+ word * Nc_out /* OUT */
+)
+{
+ register int k, lambda;
+ word Nc, bc;
+ word wt[40];
+
+ longword L_max, L_power;
+ word R, S, dmax, scal;
+ register word 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( (longword)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) (longword)wt[k] * dp[k - lambda]
+
+ register longword 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 longword 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 word * d, /* [0..39] IN */
+ register word * dp, /* [-120..-1] IN */
+ word * bc_out, /* OUT */
+ word * Nc_out /* OUT */
+)
+{
+ register int k, lambda;
+ word Nc, bc;
+ word ltp_cut;
+
+ float wt_float[40];
+ float dp_float_base[120], * dp_float = dp_float_base + 120;
+
+ longword L_max, L_power;
+ word R, S, dmax, scal;
+ register word 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( (longword)dmax << 16 );
+ }
+
+ if (temp > 6) scal = 0;
+ else scal = 6 - temp;
+
+ assert(scal >= 0);
+ ltp_cut = (longword)SASR_W(dmax, scal) * st->ltp_cut / 100;
+
+
+ /* Initialization of a working array wt
+ */
+
+ for (k = 0; k < 40; k++) {
+ register word 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 longword 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 word * din, /* [0..39] IN */
+ register word * dp, /* [-120..-1] IN */
+ word * bc_out, /* OUT */
+ word * Nc_out /* OUT */
+)
+{
+ register int k, lambda;
+ word Nc, bc;
+
+ float wt_float[40];
+ float dp_float_base[120], * dp_float = dp_float_base + 120;
+
+ longword L_max, L_power;
+ word R, S, dmax, scal;
+ register word 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( (longword)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 longword 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 word * d, /* [0..39] IN */
+ register word * dp, /* [-120..-1] IN */
+ word * bc_out, /* OUT */
+ word * Nc_out /* OUT */
+)
+{
+ register int k, lambda;
+ register float wt_float;
+ word Nc, bc;
+ word 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.;
+ 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 word * din, /* [0..39] IN */
+ register word * dp, /* [-120..-1] IN */
+ word * bc_out, /* OUT */
+ word * Nc_out /* OUT */
+)
+{
+ register int k, lambda;
+ word 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.) {
+ *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.;
+ 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 (
+ word bc, /* IN */
+ word Nc, /* IN */
+ register word * dp, /* previous d [-120..-1] IN */
+ register word * d, /* d [0..39] IN */
+ register word * dpp, /* estimate [0..39] OUT */
+ register word * 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,
+
+ word * d, /* [0..39] residual signal IN */
+ word * dp, /* [-120..-1] d' IN */
+
+ word * e, /* [0..39] OUT */
+ word * dpp, /* [0..39] OUT */
+ word * Nc, /* correlation lag OUT */
+ word * 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,
+
+ word Ncr,
+ word bcr,
+ register word * erp, /* [0..39] IN */
+ register word * 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;
+ word 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 ];
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: b369b90d-0284-42a0-87b0-99a25bbd93ac
+*/
+
diff --git a/src/GSM610/lpc.c b/src/GSM610/lpc.c
new file mode 100644
index 0000000..0a879f3
--- /dev/null
+++ b/src/GSM610/lpc.c
@@ -0,0 +1,341 @@
+/*
+ * 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 <stdio.h>
+#include <assert.h>
+
+#include "gsm610_priv.h"
+
+#include "gsm.h"
+
+/*
+ * 4.2.4 .. 4.2.7 LPC ANALYSIS SECTION
+ */
+
+/* 4.2.4 */
+
+
+static void Autocorrelation (
+ word * s, /* [0..159] IN/OUT */
+ longword * 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;
+
+ word 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( (longword)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] += (longword)(sl * sp[ -(k) ]);
+# else
+ word * sp = s;
+ word sl = *sp;
+
+# define STEP(k) L_ACF[k] += ((longword)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] <<= 1) ;
+
+ }
+ /* Rescaling of the array s[0..159]
+ */
+ if (scalauto > 0) {
+ assert(scalauto <= 4);
+ for (k = 160; k--; *s++ <<= scalauto) ;
+ }
+}
+
+#if defined(USE_FLOAT_MUL) && defined(FAST)
+
+static void Fast_Autocorrelation (
+ word * s, /* [0..159] IN/OUT */
+ longword * 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 = MAX_LONGWORD / 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 (
+ longword * L_ACF, /* 0...8 IN */
+ register word * r /* 0...7 OUT */
+)
+{
+ register int i, m, n;
+ register word temp;
+ word ACF[9]; /* 0..8 */
+ word P[ 9]; /* 0..8 */
+ word K[ 9]; /* 2..8 */
+
+ /* Schur recursion with 16 bits arithmetic.
+ */
+
+ if (L_ACF[0] == 0) {
+ for (i = 8; i--; *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( 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 word * 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 word 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 word * LAR /* [0..7] IN/OUT */
+)
+{
+ register word 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,
+ word * s, /* 0..159 signals IN/OUT */
+ word * LARc) /* 0..7 LARc's OUT */
+{
+ longword 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);
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 63146664-a002-4e1e-8b7b-f0cc8a6a53da
+*/
+
diff --git a/src/GSM610/preprocess.c b/src/GSM610/preprocess.c
new file mode 100644
index 0000000..d1b473d
--- /dev/null
+++ b/src/GSM610/preprocess.c
@@ -0,0 +1,115 @@
+/*
+ * 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 <stdio.h>
+#include <assert.h>
+
+#include "gsm610_priv.h"
+
+#include "gsm.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,
+ word * s,
+ word * so ) /* [0..159] IN/OUT */
+{
+
+ word z1 = S->z1;
+ longword L_z2 = S->L_z2;
+ word mp = S->mp;
+
+ word s1;
+ longword L_s2;
+
+ longword L_temp;
+
+ word msp, lsp;
+ word SO;
+
+ register int k = 160;
+
+ while (k--) {
+
+ /* 4.2.1 Downscaling of the input signal
+ */
+ SO = 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 <<= 15;
+
+ /* Execution of a 31 bv 16 bits multiplication
+ */
+
+ msp = SASR_L( L_z2, 15 );
+ lsp = L_z2-((longword)msp<<15); /* gsm_L_sub(L_z2,(msp<<15)); */
+
+ L_s2 += GSM_MULT_R( lsp, 32735 );
+ L_temp = (longword)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;
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: b760b0d9-3a05-4da3-9dc9-441ffb905d87
+*/
+
diff --git a/src/GSM610/rpe.c b/src/GSM610/rpe.c
new file mode 100644
index 0000000..1d91f38
--- /dev/null
+++ b/src/GSM610/rpe.c
@@ -0,0 +1,490 @@
+/*
+ * 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 <stdio.h>
+#include <assert.h>
+
+#include "gsm610_priv.h"
+
+#include "gsm.h"
+
+/* 4.2.13 .. 4.2.17 RPE ENCODING SECTION
+ */
+
+/* 4.2.13 */
+
+static void Weighting_filter (
+ register word * e, /* signal [-5..0.39.44] IN */
+ word * 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 );
+ */
+{
+ /* word wt[ 50 ]; */
+
+ register longword 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 ] * (longword)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 (
+ word * x, /* [0..39] IN */
+ word * xM, /* [0..12] OUT */
+ word * Mc_out /* OUT */
+)
+/*
+ * The signal x[0..39] is used to select the RPE grid which is
+ * represented by Mc.
+ */
+{
+ /* register word temp1; */
+ register int /* m, */ i;
+ register longword L_result, L_temp;
+ longword EM; /* xxx should be L_EM? */
+ word Mc;
+
+ longword 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 (
+ word xmaxc, /* IN */
+ word * expon_out, /* OUT */
+ word * mant_out ) /* OUT */
+{
+ word 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 (
+ word * xM, /* [0..12] IN */
+ word * xMc, /* [0..12] OUT */
+ word * mant_out, /* OUT */
+ word * expon_out, /* OUT */
+ word * xmaxc_out /* OUT */
+)
+{
+ int i, itest;
+
+ word xmax, xmaxc, temp, temp1, temp2;
+ word 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), (word) (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 = 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 word * xMc, /* [0..12] IN */
+ word mant,
+ word expon,
+ register word * 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;
+ word 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 <<= 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 (
+ word Mc, /* grid position IN */
+ register word * xMp, /* [0..12] IN */
+ register word * 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;
+ case 2: do {
+ *ep++ = 0;
+ case 1: *ep++ = 0;
+ case 0: *ep++ = *xMp++;
+ } while (--i);
+ }
+ while (++Mc < 4) *ep++ = 0;
+
+ /*
+
+ int i, k;
+ for (k = 0; k <= 39; k++) ep[k] = 0;
+ for (i = 0; i <= 12; i++) {
+ ep[ Mc + (3*i) ] = xMp[i];
+ }
+ */
+}
+
+/* 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 (
+ word * dpp, /* [0...39] IN */
+ word * ep, /* [0...39] IN */
+ word * 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 (
+ /*-struct gsm_state * S,-*/
+
+ word * e, /* -5..-1][0..39][40..44 IN/OUT */
+ word * xmaxc, /* OUT */
+ word * Mc, /* OUT */
+ word * xMc) /* [0..12] OUT */
+{
+ word x[40];
+ word xM[13], xMp[13];
+ word 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 (
+ /*-struct gsm_state * S,-*/
+
+ word xmaxcr,
+ word Mcr,
+ word * xMcr, /* [0..12], 3 bits IN */
+ word * erp /* [0..39] OUT */
+)
+{
+ word expon, mant;
+ word xMp[ 13 ];
+
+ APCM_quantization_xmaxc_to_exp_mant( xmaxcr, &expon, &mant );
+ APCM_inverse_quantization( xMcr, mant, expon, xMp );
+ RPE_grid_positioning( Mcr, xMp, erp );
+
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 82005b9e-1560-4e94-9ddb-00cb14867295
+*/
+
diff --git a/src/GSM610/short_term.c b/src/GSM610/short_term.c
new file mode 100644
index 0000000..0174b05
--- /dev/null
+++ b/src/GSM610/short_term.c
@@ -0,0 +1,427 @@
+/*
+ * 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 <stdio.h>
+#include <assert.h>
+
+#include "gsm610_priv.h"
+
+#include "gsm.h"
+
+/*
+ * SHORT TERM ANALYSIS FILTERING SECTION
+ */
+
+/* 4.2.8 */
+
+static void Decoding_of_the_coded_Log_Area_Ratios (
+ word * LARc, /* coded log area ratio [0..7] IN */
+ word * LARpp) /* out: decoded .. */
+{
+ register word temp1 /* , temp2 */;
+
+ /* 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 = GSM_ADD( *LARc++, MIC ) << 10; \
+ temp1 = GSM_SUB( temp1, B << 1 ); \
+ 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 word * LARpp_j_1,
+ register word * LARpp_j,
+ register word * 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 word * LARpp_j_1,
+ register word * LARpp_j,
+ register word * 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 word * LARpp_j_1,
+ register word * LARpp_j,
+ register word * 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 word * LARpp_j,
+ register word * 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 word * 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 word 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( (word) (temp >> 2), (word) 26112 )));
+ } else {
+ temp = *LARp;
+ *LARp = (temp < 11059) ? temp << 1
+ : ((temp < 20070) ? temp + 11059
+ : GSM_ADD( (word) (temp >> 2), (word) 26112 ));
+ }
+ }
+}
+
+
+/* 4.2.10 */
+static void Short_term_analysis_filtering (
+ struct gsm_state * S,
+ register word * rp, /* [0..7] IN */
+ register int k_n, /* k_end - k_start */
+ register word * 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 word * u = S->u;
+ register int i;
+ register word 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 word * rp, /* [0..7] IN */
+ register int k_n, /* k_end - k_start */
+ register word * s /* [0..n-1] IN/OUT */
+)
+{
+ register word * 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 word * rrp, /* [0..7] IN */
+ register int k, /* k_end - k_start */
+ register word * wt, /* [0..k-1] IN */
+ register word * sr /* [0..k-1] OUT */
+)
+{
+ register word * v = S->v;
+ register int i;
+ register word 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 & (( (longword)tmp1 * (longword)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 & (( (longword)tmp1 * (longword)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 word * rrp, /* [0..7] IN */
+ register int k, /* k_end - k_start */
+ register word * wt, /* [0..k-1] IN */
+ register word * sr /* [0..k-1] OUT */
+)
+{
+ register word * 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.) sri = -32768.;
+ else if (sri > 32767.) sri = 32767.;
+
+ temp = va[i] + rrpa[i] * sri;
+ if (temp < -32768.) temp = -32768.;
+ else if (temp > 32767.) temp = 32767.;
+ 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,
+
+ word * LARc, /* coded log area ratio [0..7] IN */
+ word * s /* signal [0..159] IN/OUT */
+)
+{
+ word * LARpp_j = S->LARpp[ S->j ];
+ word * LARpp_j_1 = S->LARpp[ S->j ^= 1 ];
+
+ word 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,
+
+ word * LARcr, /* received log area ratios [0..7] IN */
+ word * wt, /* received d [0..159] IN */
+
+ word * s /* signal s [0..159] OUT */
+)
+{
+ word * LARpp_j = S->LARpp[ S->j ];
+ word * LARpp_j_1 = S->LARpp[ S->j ^=1 ];
+
+ word 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);
+}
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 019ac7ba-c6dd-4540-abf0-8644b6c4a633
+*/
+
diff --git a/src/GSM610/table.c b/src/GSM610/table.c
new file mode 100644
index 0000000..b5aa881
--- /dev/null
+++ b/src/GSM610/table.c
@@ -0,0 +1,69 @@
+/*
+ * 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"
+#include "gsm.h"
+
+/* Table 4.1 Quantization of the Log.-Area Ratios
+ */
+/* i 1 2 3 4 5 6 7 8 */
+word gsm_A[8] = {20480, 20480, 20480, 20480, 13964, 15360, 8534, 9036};
+word gsm_B[8] = { 0, 0, 2048, -2560, 94, -1792, -341, -1144};
+word gsm_MIC[8] = { -32, -32, -16, -16, -8, -8, -4, -4 };
+word gsm_MAC[8] = { 31, 31, 15, 15, 7, 7, 3, 3 };
+
+
+/* Table 4.2 Tabulation of 1/A[1..8]
+ */
+word 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 */
+word gsm_DLB[4] = { 6554, 16384, 26214, 32767 };
+
+
+/* Table 4.3b Quantization levels of the LTP gain quantizer
+ */
+/* bc 0 1 2 3 */
+word 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 */
+word 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 */
+word 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 */
+word gsm_FAC[8] = { 18431, 20479, 22527, 24575, 26623, 28671, 30719, 32767 };
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 8957c531-e6b0-4097-9202-da7ca42729ca
+*/
+
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..24d852d
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,121 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = OGG FLAC GSM610 G72x
+
+lib_LTLIBRARIES = libsndfile.la
+include_HEADERS = sndfile.hh
+nodist_include_HEADERS = sndfile.h
+
+noinst_LTLIBRARIES = libcommon.la
+
+OS_SPECIFIC_CFLAGS = @OS_SPECIFIC_CFLAGS@
+OS_SPECIFIC_LINKS = @OS_SPECIFIC_LINKS@
+
+EXTRA_DIST = sndfile.h.in config.h.in test_endswap.tpl test_endswap.def \
+ Symbols.linux Symbols.darwin libsndfile.def cygsndfile.def \
+ create_symbols_file.py binheader_writef_check.py
+
+noinst_HEADERS = common.h sfconfig.h sfendian.h float_cast.h wav_w64.h sf_unistd.h
+
+noinst_PROGRAMS = test_endswap test_file_io test_conversions test_log_printf \
+ test_audio_detect
+
+COMMON = common.c file_io.c command.c pcm.c ulaw.c alaw.c float32.c \
+ double64.c ima_adpcm.c ms_adpcm.c gsm610.c dwvw.c vox_adpcm.c \
+ interleave.c strings.c dither.c broadcast.c audio_detect.c
+
+FILESPECIFIC = sndfile.c aiff.c au.c avr.c caf.c dwd.c flac.c g72x.c htk.c ircam.c \
+ macbinary3.c macos.c mat4.c mat5.c nist.c ogg.c paf.c pvf.c raw.c rx2.c sd2.c \
+ sds.c svx.c txw.c voc.c wve.c w64.c wav_w64.c wav.c xi.c
+
+# MinGW requires -no-undefined if a DLL is to be built.
+libsndfile_la_LDFLAGS = -no-undefined -version-info @SHARED_VERSION_INFO@ @SHLIB_VERSION_ARG@
+libsndfile_la_SOURCES = $(FILESPECIFIC) $(noinst_HEADERS)
+nodist_libsndfile_la_SOURCES = $(nodist_include_HEADERS)
+libsndfile_la_LIBADD = libcommon.la FLAC/src/libFLAC/libFLAC.la GSM610/libgsm.la \
+ G72x/libg72x.la OGG/libogg.la -lm
+
+libcommon_la_SOURCES = $(COMMON)
+
+test_endswap_SOURCES = test_endswap.c
+
+test_file_io_CFLAGS = $(AM_CFLAGS)
+test_file_io_SOURCES = test_file_io.c
+test_file_io_LDADD = libcommon.la
+
+test_log_printf_CFLAGS = $(AM_CFLAGS)
+test_log_printf_SOURCES = test_log_printf.c
+test_log_printf_LDADD = libcommon.la
+
+test_conversions_CFLAGS = $(AM_CFLAGS)
+test_conversions_SOURCES = test_conversions.c
+test_conversions_LDADD = libcommon.la
+
+test_audio_detect_CFLAGS = $(AM_CFLAGS)
+test_audio_detect_SOURCES = test_audio_detect.c
+test_audio_detect_LDADD = libcommon.la
+
+test_endswap.c: test_endswap.def test_endswap.tpl
+ autogen --writable test_endswap.def
+
+genfiles : test_endswap.c Symbols.linux Symbols.darwin libsndfile.def cygsndfile.def
+
+# Two test programs.
+# It is not possible to place these in the tests/ directory because they
+# need access to the internals of the SF_PRIVATE struct.
+
+check: test_endswap test_file_io test_conversions test_log_printf
+ @echo
+ @echo
+ @echo
+ @echo "============================================================"
+ @if [ -x /usr/bin/python2.4 ]; then $(srcdir)/binheader_writef_check.py $(srcdir)/*.c ; fi
+ ./test_endswap
+ ./test_file_io
+ ./test_conversions
+ ./test_log_printf
+ ./test_audio_detect
+ @echo "============================================================"
+ @echo
+ @echo
+ @echo
+
+#======================================================================
+# 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.
+
+Symbols.linux: create_symbols_file.py
+ ./create_symbols_file.py linux $(VERSION) > Symbols.linux
+
+Symbols.darwin: create_symbols_file.py
+ ./create_symbols_file.py darwin $(VERSION) > Symbols.darwin
+
+libsndfile.def: create_symbols_file.py
+ ./create_symbols_file.py win32 $(VERSION) > libsndfile.def
+
+cygsndfile.def: create_symbols_file.py
+ ./create_symbols_file.py cygwin $(VERSION) > cygsndfile.def
+
+# Fake dependancy to force the creation of these files.
+sndfile.o : Symbols.linux Symbols.darwin libsndfile.def cygsndfile.def
+
+#======================================================================
+# Disable autoheader.
+AUTOHEADER=echo
+
+# Dependancies.
+
+aiff.c au.c g72x.c ircam.c mat4.c mat5.c nist.c paf.c pvf.c : sndfile.h common.h
+raw.c svx.c voc.c w64.c wav.c wav_w64.c htk.c sd2.c rx2.c txw.c : sndfile.h common.h
+sds.c wve.c dwd.c ogg.c xi.c sndfile.c common.c file_io.c : sndfile.h common.h
+command.c pcm.c ulaw.c alaw.c float32.c double64.c ima_adpcm.c : sndfile.h common.h
+ms_adpcm.c gsm610.c dwvw.c vox_adpcm.c interleave.c strings.c : sndfile.h common.h
+dither.c : sndfile.h common.h
+
+## Do not edit or modify anything in this comment block.
+## The arch-tag line is a file identity tag for the GNU Arch
+## revision control system.
+##
+## arch-tag: fc3511e6-4230-4bcb-9c86-f728d7a06fe7
+
diff --git a/src/OGG/Makefile.am b/src/OGG/Makefile.am
new file mode 100644
index 0000000..b597096
--- /dev/null
+++ b/src/OGG/Makefile.am
@@ -0,0 +1,29 @@
+## Process this file with automake to produce Makefile.in
+
+INCLUDES = -I$(top_srcdir)/src/OGG/include -I$(top_builddir)/src/OGG/include
+
+SUBDIRS = include
+
+noinst_LTLIBRARIES = libogg.la
+
+libogg_la_SOURCES = framing.c bitwise.c
+
+# build and run the self tests on 'make check'
+
+noinst_PROGRAMS = test_bitwise test_framing
+
+test_bitwise_SOURCES = bitwise.c
+test_bitwise_CFLAGS = -D_V_SELFTEST
+
+test_framing_SOURCES = framing.c
+test_framing_CFLAGS = -D_V_SELFTEST
+
+check: test_bitwise test_framing
+ ./test_bitwise
+ ./test_framing
+
+debug:
+ $(MAKE) all CFLAGS="@DEBUG@"
+
+profile:
+ $(MAKE) all CFLAGS="@PROFILE@"
diff --git a/src/OGG/README.txt b/src/OGG/README.txt
new file mode 100644
index 0000000..5cb7102
--- /dev/null
+++ b/src/OGG/README.txt
@@ -0,0 +1,7 @@
+All code in this directory and below is from the libogg by Mony of the Xiph
+Foundation and others. Please see the individual files for their
+copyrights and licensing.
+
+The version here is from the file :
+
+ libogg-1.1.3.tar.gz md5sum : eaf7dc6ebbff30975de7527a80831585
diff --git a/src/OGG/bitwise.c b/src/OGG/bitwise.c
new file mode 100644
index 0000000..f2a89dd
--- /dev/null
+++ b/src/OGG/bitwise.c
@@ -0,0 +1,788 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: packing variable sized words into an octet stream
+ last mod: $Id: bitwise.c 7675 2004-09-01 00:34:39Z xiphmont $
+
+ ********************************************************************/
+
+/* We're 'LSb' endian; if we write a word but read individual bits,
+ then we'll read the lsb first */
+
+#include <string.h>
+#include <stdlib.h>
+#include <ogg/ogg.h>
+
+#define BUFFER_INCREMENT 256
+
+static const unsigned long mask[]=
+{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
+ 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
+ 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,
+ 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
+ 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff,
+ 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
+ 0x3fffffff,0x7fffffff,0xffffffff };
+
+static const unsigned int mask8B[]=
+{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};
+
+void oggpack_writeinit(oggpack_buffer *b){
+ memset(b,0,sizeof(*b));
+ b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT);
+ b->buffer[0]='\0';
+ b->storage=BUFFER_INCREMENT;
+}
+
+void oggpackB_writeinit(oggpack_buffer *b){
+ oggpack_writeinit(b);
+}
+
+void oggpack_writetrunc(oggpack_buffer *b,long bits){
+ long bytes=bits>>3;
+ bits-=bytes*8;
+ b->ptr=b->buffer+bytes;
+ b->endbit=bits;
+ b->endbyte=bytes;
+ *b->ptr&=mask[bits];
+}
+
+void oggpackB_writetrunc(oggpack_buffer *b,long bits){
+ long bytes=bits>>3;
+ bits-=bytes*8;
+ b->ptr=b->buffer+bytes;
+ b->endbit=bits;
+ b->endbyte=bytes;
+ *b->ptr&=mask8B[bits];
+}
+
+/* Takes only up to 32 bits. */
+void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){
+ if(b->endbyte+4>=b->storage){
+ b->buffer=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
+ b->storage+=BUFFER_INCREMENT;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ value&=mask[bits];
+ bits+=b->endbit;
+
+ b->ptr[0]|=value<<b->endbit;
+
+ if(bits>=8){
+ b->ptr[1]=(unsigned char)(value>>(8-b->endbit));
+ if(bits>=16){
+ b->ptr[2]=(unsigned char)(value>>(16-b->endbit));
+ if(bits>=24){
+ b->ptr[3]=(unsigned char)(value>>(24-b->endbit));
+ if(bits>=32){
+ if(b->endbit)
+ b->ptr[4]=(unsigned char)(value>>(32-b->endbit));
+ else
+ b->ptr[4]=0;
+ }
+ }
+ }
+ }
+
+ b->endbyte+=bits/8;
+ b->ptr+=bits/8;
+ b->endbit=bits&7;
+}
+
+/* Takes only up to 32 bits. */
+void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){
+ if(b->endbyte+4>=b->storage){
+ b->buffer=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
+ b->storage+=BUFFER_INCREMENT;
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ value=(value&mask[bits])<<(32-bits);
+ bits+=b->endbit;
+
+ b->ptr[0]|=value>>(24+b->endbit);
+
+ if(bits>=8){
+ b->ptr[1]=(unsigned char)(value>>(16+b->endbit));
+ if(bits>=16){
+ b->ptr[2]=(unsigned char)(value>>(8+b->endbit));
+ if(bits>=24){
+ b->ptr[3]=(unsigned char)(value>>(b->endbit));
+ if(bits>=32){
+ if(b->endbit)
+ b->ptr[4]=(unsigned char)(value<<(8-b->endbit));
+ else
+ b->ptr[4]=0;
+ }
+ }
+ }
+ }
+
+ b->endbyte+=bits/8;
+ b->ptr+=bits/8;
+ b->endbit=bits&7;
+}
+
+void oggpack_writealign(oggpack_buffer *b){
+ int bits=8-b->endbit;
+ if(bits<8)
+ oggpack_write(b,0,bits);
+}
+
+void oggpackB_writealign(oggpack_buffer *b){
+ int bits=8-b->endbit;
+ if(bits<8)
+ oggpackB_write(b,0,bits);
+}
+
+static void oggpack_writecopy_helper(oggpack_buffer *b,
+ void *source,
+ long bits,
+ void (*w)(oggpack_buffer *,
+ unsigned long,
+ int),
+ int msb){
+ unsigned char *ptr=(unsigned char *)source;
+
+ long bytes=bits/8;
+ bits-=bytes*8;
+
+ if(b->endbit){
+ int i;
+ /* unaligned copy. Do it the hard way. */
+ for(i=0;i<bytes;i++)
+ w(b,(unsigned long)(ptr[i]),8);
+ }else{
+ /* aligned block copy */
+ if(b->endbyte+bytes+1>=b->storage){
+ b->storage=b->endbyte+bytes+BUFFER_INCREMENT;
+ b->buffer=_ogg_realloc(b->buffer,b->storage);
+ b->ptr=b->buffer+b->endbyte;
+ }
+
+ memmove(b->ptr,source,bytes);
+ b->ptr+=bytes;
+ b->endbyte+=bytes;
+ *b->ptr=0;
+
+ }
+ if(bits){
+ if(msb)
+ w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits);
+ else
+ w(b,(unsigned long)(ptr[bytes]),bits);
+ }
+}
+
+void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){
+ oggpack_writecopy_helper(b,source,bits,oggpack_write,0);
+}
+
+void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){
+ oggpack_writecopy_helper(b,source,bits,oggpackB_write,1);
+}
+
+void oggpack_reset(oggpack_buffer *b){
+ b->ptr=b->buffer;
+ b->buffer[0]=0;
+ b->endbit=b->endbyte=0;
+}
+
+void oggpackB_reset(oggpack_buffer *b){
+ oggpack_reset(b);
+}
+
+void oggpack_writeclear(oggpack_buffer *b){
+ _ogg_free(b->buffer);
+ memset(b,0,sizeof(*b));
+}
+
+void oggpackB_writeclear(oggpack_buffer *b){
+ oggpack_writeclear(b);
+}
+
+void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
+ memset(b,0,sizeof(*b));
+ b->buffer=b->ptr=buf;
+ b->storage=bytes;
+}
+
+void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
+ oggpack_readinit(b,buf,bytes);
+}
+
+/* Read in bits without advancing the bitptr; bits <= 32 */
+long oggpack_look(oggpack_buffer *b,int bits){
+ unsigned long ret;
+ unsigned long m=mask[bits];
+
+ bits+=b->endbit;
+
+ if(b->endbyte+4>=b->storage){
+ /* not the main path */
+ if(b->endbyte*8+bits>b->storage*8)return(-1);
+ }
+
+ ret=b->ptr[0]>>b->endbit;
+ if(bits>8){
+ ret|=b->ptr[1]<<(8-b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(16-b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(24-b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]<<(32-b->endbit);
+ }
+ }
+ }
+ return(m&ret);
+}
+
+/* Read in bits without advancing the bitptr; bits <= 32 */
+long oggpackB_look(oggpack_buffer *b,int bits){
+ unsigned long ret;
+ int m=32-bits;
+
+ bits+=b->endbit;
+
+ if(b->endbyte+4>=b->storage){
+ /* not the main path */
+ if(b->endbyte*8+bits>b->storage*8)return(-1);
+ }
+
+ ret=b->ptr[0]<<(24+b->endbit);
+ if(bits>8){
+ ret|=b->ptr[1]<<(16+b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(8+b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]>>(8-b->endbit);
+ }
+ }
+ }
+ return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1);
+}
+
+long oggpack_look1(oggpack_buffer *b){
+ if(b->endbyte>=b->storage)return(-1);
+ return((b->ptr[0]>>b->endbit)&1);
+}
+
+long oggpackB_look1(oggpack_buffer *b){
+ if(b->endbyte>=b->storage)return(-1);
+ return((b->ptr[0]>>(7-b->endbit))&1);
+}
+
+void oggpack_adv(oggpack_buffer *b,int bits){
+ bits+=b->endbit;
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+}
+
+void oggpackB_adv(oggpack_buffer *b,int bits){
+ oggpack_adv(b,bits);
+}
+
+void oggpack_adv1(oggpack_buffer *b){
+ if(++(b->endbit)>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+}
+
+void oggpackB_adv1(oggpack_buffer *b){
+ oggpack_adv1(b);
+}
+
+/* bits <= 32 */
+long oggpack_read(oggpack_buffer *b,int bits){
+ long ret;
+ unsigned long m=mask[bits];
+
+ bits+=b->endbit;
+
+ if(b->endbyte+4>=b->storage){
+ /* not the main path */
+ ret=-1L;
+ if(b->endbyte*8+bits>b->storage*8)goto overflow;
+ }
+
+ ret=b->ptr[0]>>b->endbit;
+ if(bits>8){
+ ret|=b->ptr[1]<<(8-b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(16-b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(24-b->endbit);
+ if(bits>32 && b->endbit){
+ ret|=b->ptr[4]<<(32-b->endbit);
+ }
+ }
+ }
+ }
+ ret&=m;
+
+ overflow:
+
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return(ret);
+}
+
+/* bits <= 32 */
+long oggpackB_read(oggpack_buffer *b,int bits){
+ long ret;
+ long m=32-bits;
+
+ bits+=b->endbit;
+
+ if(b->endbyte+4>=b->storage){
+ /* not the main path */
+ ret=-1L;
+ if(b->endbyte*8+bits>b->storage*8)goto overflow;
+ }
+
+ ret=b->ptr[0]<<(24+b->endbit);
+ if(bits>8){
+ ret|=b->ptr[1]<<(16+b->endbit);
+ if(bits>16){
+ ret|=b->ptr[2]<<(8+b->endbit);
+ if(bits>24){
+ ret|=b->ptr[3]<<(b->endbit);
+ if(bits>32 && b->endbit)
+ ret|=b->ptr[4]>>(8-b->endbit);
+ }
+ }
+ }
+ ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1);
+
+ overflow:
+
+ b->ptr+=bits/8;
+ b->endbyte+=bits/8;
+ b->endbit=bits&7;
+ return(ret);
+}
+
+long oggpack_read1(oggpack_buffer *b){
+ long ret;
+
+ if(b->endbyte>=b->storage){
+ /* not the main path */
+ ret=-1L;
+ goto overflow;
+ }
+
+ ret=(b->ptr[0]>>b->endbit)&1;
+
+ overflow:
+
+ b->endbit++;
+ if(b->endbit>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+ return(ret);
+}
+
+long oggpackB_read1(oggpack_buffer *b){
+ long ret;
+
+ if(b->endbyte>=b->storage){
+ /* not the main path */
+ ret=-1L;
+ goto overflow;
+ }
+
+ ret=(b->ptr[0]>>(7-b->endbit))&1;
+
+ overflow:
+
+ b->endbit++;
+ if(b->endbit>7){
+ b->endbit=0;
+ b->ptr++;
+ b->endbyte++;
+ }
+ return(ret);
+}
+
+long oggpack_bytes(oggpack_buffer *b){
+ return(b->endbyte+(b->endbit+7)/8);
+}
+
+long oggpack_bits(oggpack_buffer *b){
+ return(b->endbyte*8+b->endbit);
+}
+
+long oggpackB_bytes(oggpack_buffer *b){
+ return oggpack_bytes(b);
+}
+
+long oggpackB_bits(oggpack_buffer *b){
+ return oggpack_bits(b);
+}
+
+unsigned char *oggpack_get_buffer(oggpack_buffer *b){
+ return(b->buffer);
+}
+
+unsigned char *oggpackB_get_buffer(oggpack_buffer *b){
+ return oggpack_get_buffer(b);
+}
+
+/* Self test of the bitwise routines; everything else is based on
+ them, so they damned well better be solid. */
+
+#ifdef _V_SELFTEST
+#include <stdio.h>
+
+static int ilog(unsigned int v){
+ int ret=0;
+ while(v){
+ ret++;
+ v>>=1;
+ }
+ return(ret);
+}
+
+oggpack_buffer o;
+oggpack_buffer r;
+
+static
+void report(const char *in){
+ fprintf(stderr,"%s",in);
+ exit(1);
+}
+
+static
+void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){
+ long bytes,i;
+ unsigned char *buffer;
+
+ oggpack_reset(&o);
+ for(i=0;i<vals;i++)
+ oggpack_write(&o,b[i],bits?bits:ilog(b[i]));
+ buffer=oggpack_get_buffer(&o);
+ bytes=oggpack_bytes(&o);
+ if(bytes!=compsize)report("wrong number of bytes!\n");
+ for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){
+ for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]);
+ report("wrote incorrect value!\n");
+ }
+ oggpack_readinit(&r,buffer,bytes);
+ for(i=0;i<vals;i++){
+ int tbit=bits?bits:ilog(b[i]);
+ if(oggpack_look(&r,tbit)==-1)
+ report("out of data!\n");
+ if(oggpack_look(&r,tbit)!=(long)(b[i]&mask[tbit]))
+ report("looked at incorrect value!\n");
+ if(tbit==1)
+ if(oggpack_look1(&r)!=(long)(b[i]&mask[tbit]))
+ report("looked at single bit incorrect value!\n");
+ if(tbit==1){
+ if(oggpack_read1(&r)!=(long)(b[i]&mask[tbit]))
+ report("read incorrect single bit value!\n");
+ }else{
+ if(oggpack_read(&r,tbit)!=(long)(b[i]&mask[tbit]))
+ report("read incorrect value!\n");
+ }
+ }
+ if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+}
+
+static
+void cliptestB(unsigned long *b,int vals,int bits,int *comp,int compsize){
+ long bytes,i;
+ unsigned char *buffer;
+
+ oggpackB_reset(&o);
+ for(i=0;i<vals;i++)
+ oggpackB_write(&o,b[i],bits?bits:ilog(b[i]));
+ buffer=oggpackB_get_buffer(&o);
+ bytes=oggpackB_bytes(&o);
+ if(bytes!=compsize)report("wrong number of bytes!\n");
+ for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){
+ for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]);
+ report("wrote incorrect value!\n");
+ }
+ oggpackB_readinit(&r,buffer,bytes);
+ for(i=0;i<vals;i++){
+ int tbit=bits?bits:ilog(b[i]);
+ if(oggpackB_look(&r,tbit)==-1)
+ report("out of data!\n");
+ if(oggpackB_look(&r,tbit)!=(long)(b[i]&mask[tbit]))
+ report("looked at incorrect value!\n");
+ if(tbit==1)
+ if(oggpackB_look1(&r)!=(long)(b[i]&mask[tbit]))
+ report("looked at single bit incorrect value!\n");
+ if(tbit==1){
+ if(oggpackB_read1(&r)!=(long)(b[i]&mask[tbit]))
+ report("read incorrect single bit value!\n");
+ }else{
+ if(oggpackB_read(&r,tbit)!=(long)(b[i]&mask[tbit]))
+ report("read incorrect value!\n");
+ }
+ }
+ if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+}
+
+int main(void){
+ unsigned char *buffer;
+ long bytes,i;
+ static unsigned long testbuffer1[]=
+ {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
+ 567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
+ int test1size=43;
+
+ static unsigned long testbuffer2[]=
+ {216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212,
+ 1233432,534,5,346435231,14436467,7869299,76326614,167548585,
+ 85525151,0,12321,1,349528352};
+ int test2size=21;
+
+ static unsigned long testbuffer3[]=
+ {1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1,
+ 0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1};
+ int test3size=56;
+
+ static unsigned long large[]=
+ {2136531625L,2137861823,56732452,131,3212421,12325343,34547562,12313212,
+ 1233432,534,5,2146435231,14436467,7869299,76326614,167548585,
+ 85525151,0,12321,1,2146528352};
+
+ int onesize=33;
+ static int one[33]={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40,
+ 34,242,223,136,35,222,211,86,171,50,225,135,214,75,172,
+ 223,4};
+ static int oneB[33]={150,101,131,33,203,15,204,216,105,193,156,65,84,85,222,
+ 8,139,145,227,126,34,55,244,171,85,100,39,195,173,18,
+ 245,251,128};
+
+ int twosize=6;
+ static int two[6]={61,255,255,251,231,29};
+ static int twoB[6]={247,63,255,253,249,120};
+
+ int threesize=54;
+ static int three[54]={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254,
+ 142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83,
+ 58,135,196,61,55,129,183,54,101,100,170,37,127,126,10,
+ 100,52,4,14,18,86,77,1};
+ static int threeB[54]={206,128,42,153,57,8,183,251,13,89,36,30,32,144,183,
+ 130,59,240,121,59,85,223,19,228,180,134,33,107,74,98,
+ 233,253,196,135,63,2,110,114,50,155,90,127,37,170,104,
+ 200,20,254,4,58,106,176,144,0};
+
+ int foursize=38;
+ static int four[38]={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72,
+ 132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169,
+ 28,2,133,0,1};
+ static int fourB[38]={36,48,102,83,243,24,52,7,4,35,132,10,145,21,2,93,2,41,
+ 1,219,184,16,33,184,54,149,170,132,18,30,29,98,229,67,
+ 129,10,4,32};
+
+ int fivesize=45;
+ static int five[45]={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62,
+ 241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169,
+ 84,75,159,2,1,0,132,192,8,0,0,18,22};
+ static int fiveB[45]={1,84,145,111,245,100,128,8,56,36,40,71,126,78,213,226,
+ 124,105,12,0,133,128,0,162,233,242,67,152,77,205,77,
+ 172,150,169,129,79,128,0,6,4,32,0,27,9,0};
+
+ int sixsize=7;
+ static int six[7]={17,177,170,242,169,19,148};
+ static int sixB[7]={136,141,85,79,149,200,41};
+ static unsigned char eight_zero_bytes [8] = { 0, 0, 0, 0, 0, 0, 0 } ;
+
+ /* Test read/write together */
+ /* Later we test against pregenerated bitstreams */
+ oggpack_writeinit(&o);
+
+ fprintf(stderr,"\nSmall preclipped packing (LSb): ");
+ cliptest(testbuffer1,test1size,0,one,onesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nNull bit call (LSb): ");
+ cliptest(testbuffer3,test3size,0,two,twosize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge preclipped packing (LSb): ");
+ cliptest(testbuffer2,test2size,0,three,threesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\n32 bit preclipped packing (LSb): ");
+ oggpack_reset(&o);
+ for(i=0;i<test2size;i++)
+ oggpack_write(&o,large[i],32);
+ buffer=oggpack_get_buffer(&o);
+ bytes=oggpack_bytes(&o);
+ oggpack_readinit(&r,buffer,bytes);
+ for(i=0;i<test2size;i++){
+ if(oggpack_look(&r,32)==-1)report("out of data. failed!");
+ if(oggpack_look(&r,32)!=(long)large[i]){
+ fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpack_look(&r,32),large[i],
+ oggpack_look(&r,32),large[i]);
+ report("read incorrect value!\n");
+ }
+ oggpack_adv(&r,32);
+ }
+ if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSmall unclipped packing (LSb): ");
+ cliptest(testbuffer1,test1size,7,four,foursize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge unclipped packing (LSb): ");
+ cliptest(testbuffer2,test2size,17,five,fivesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSingle bit unclipped packing (LSb): ");
+ cliptest(testbuffer3,test3size,1,six,sixsize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nTesting read past end (LSb): ");
+ oggpack_readinit(&r,eight_zero_bytes,8);
+ for(i=0;i<64;i++){
+ if(oggpack_read(&r,1)!=0){
+ fprintf(stderr,"failed; got -1 prematurely.\n");
+ exit(1);
+ }
+ }
+ if(oggpack_look(&r,1)!=-1 ||
+ oggpack_read(&r,1)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpack_readinit(&r,eight_zero_bytes,8);
+ if(oggpack_read(&r,30)!=0 || oggpack_read(&r,16)!=0){
+ fprintf(stderr,"failed 2; got -1 prematurely.\n");
+ exit(1);
+ }
+
+ if(oggpack_look(&r,18)!=0 ||
+ oggpack_look(&r,18)!=0){
+ fprintf(stderr,"failed 3; got -1 prematurely.\n");
+ exit(1);
+ }
+ if(oggpack_look(&r,19)!=-1 ||
+ oggpack_look(&r,19)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ if(oggpack_look(&r,32)!=-1 ||
+ oggpack_look(&r,32)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpack_writeclear(&o);
+ fprintf(stderr,"ok.\n");
+
+ /********** lazy, cut-n-paste retest with MSb packing ***********/
+
+ /* Test read/write together */
+ /* Later we test against pregenerated bitstreams */
+ oggpackB_writeinit(&o);
+
+ fprintf(stderr,"\nSmall preclipped packing (MSb): ");
+ cliptestB(testbuffer1,test1size,0,oneB,onesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nNull bit call (MSb): ");
+ cliptestB(testbuffer3,test3size,0,twoB,twosize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge preclipped packing (MSb): ");
+ cliptestB(testbuffer2,test2size,0,threeB,threesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\n32 bit preclipped packing (MSb): ");
+ oggpackB_reset(&o);
+ for(i=0;i<test2size;i++)
+ oggpackB_write(&o,large[i],32);
+ buffer=oggpackB_get_buffer(&o);
+ bytes=oggpackB_bytes(&o);
+ oggpackB_readinit(&r,buffer,bytes);
+ for(i=0;i<test2size;i++){
+ if(oggpackB_look(&r,32)==-1)report("out of data. failed!");
+ if(oggpackB_look(&r,32)!=(long)large[i]){
+ fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpackB_look(&r,32),large[i],
+ oggpackB_look(&r,32),large[i]);
+ report("read incorrect value!\n");
+ }
+ oggpackB_adv(&r,32);
+ }
+ if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n");
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSmall unclipped packing (MSb): ");
+ cliptestB(testbuffer1,test1size,7,fourB,foursize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nLarge unclipped packing (MSb): ");
+ cliptestB(testbuffer2,test2size,17,fiveB,fivesize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nSingle bit unclipped packing (MSb): ");
+ cliptestB(testbuffer3,test3size,1,sixB,sixsize);
+ fprintf(stderr,"ok.");
+
+ fprintf(stderr,"\nTesting read past end (MSb): ");
+ oggpackB_readinit(&r,eight_zero_bytes,8);
+ for(i=0;i<64;i++){
+ if(oggpackB_read(&r,1)!=0){
+ fprintf(stderr,"failed; got -1 prematurely.\n");
+ exit(1);
+ }
+ }
+ if(oggpackB_look(&r,1)!=-1 ||
+ oggpackB_read(&r,1)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpackB_readinit(&r,eight_zero_bytes,8);
+ if(oggpackB_read(&r,30)!=0 || oggpackB_read(&r,16)!=0){
+ fprintf(stderr,"failed 2; got -1 prematurely.\n");
+ exit(1);
+ }
+
+ if(oggpackB_look(&r,18)!=0 ||
+ oggpackB_look(&r,18)!=0){
+ fprintf(stderr,"failed 3; got -1 prematurely.\n");
+ exit(1);
+ }
+ if(oggpackB_look(&r,19)!=-1 ||
+ oggpackB_look(&r,19)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ if(oggpackB_look(&r,32)!=-1 ||
+ oggpackB_look(&r,32)!=-1){
+ fprintf(stderr,"failed; read past end without -1.\n");
+ exit(1);
+ }
+ oggpackB_writeclear(&o);
+ fprintf(stderr,"ok.\n\n");
+
+
+ return(0);
+}
+#endif /* _V_SELFTEST */
+
+#undef BUFFER_INCREMENT
diff --git a/src/OGG/framing.c b/src/OGG/framing.c
new file mode 100644
index 0000000..871d691
--- /dev/null
+++ b/src/OGG/framing.c
@@ -0,0 +1,1808 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: code raw [Vorbis] packets into framed OggSquish stream and
+ decode Ogg streams back into raw packets
+ last mod: $Id: framing.c 9601 2005-07-23 00:19:14Z giles $
+
+ note: The CRC code is directly derived from public domain code by
+ Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
+ for details.
+
+ ********************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ogg/ogg.h>
+
+/* A complete description of Ogg framing exists in docs/framing.html */
+
+int ogg_page_version(ogg_page *og){
+ return((int)(og->header[4]));
+}
+
+int ogg_page_continued(ogg_page *og){
+ return((int)(og->header[5]&0x01));
+}
+
+int ogg_page_bos(ogg_page *og){
+ return((int)(og->header[5]&0x02));
+}
+
+int ogg_page_eos(ogg_page *og){
+ return((int)(og->header[5]&0x04));
+}
+
+ogg_int64_t ogg_page_granulepos(ogg_page *og){
+ unsigned char *page=og->header;
+ ogg_int64_t granulepos=page[13]&(0xff);
+ granulepos= (granulepos<<8)|(page[12]&0xff);
+ granulepos= (granulepos<<8)|(page[11]&0xff);
+ granulepos= (granulepos<<8)|(page[10]&0xff);
+ granulepos= (granulepos<<8)|(page[9]&0xff);
+ granulepos= (granulepos<<8)|(page[8]&0xff);
+ granulepos= (granulepos<<8)|(page[7]&0xff);
+ granulepos= (granulepos<<8)|(page[6]&0xff);
+ return(granulepos);
+}
+
+int ogg_page_serialno(ogg_page *og){
+ return(og->header[14] |
+ (og->header[15]<<8) |
+ (og->header[16]<<16) |
+ (og->header[17]<<24));
+}
+
+long ogg_page_pageno(ogg_page *og){
+ return(og->header[18] |
+ (og->header[19]<<8) |
+ (og->header[20]<<16) |
+ (og->header[21]<<24));
+}
+
+
+
+/* returns the number of packets that are completed on this page (if
+ the leading packet is begun on a previous page, but ends on this
+ page, it's counted */
+
+/* NOTE:
+If a page consists of a packet begun on a previous page, and a new
+packet begun (but not completed) on this page, the return will be:
+ ogg_page_packets(page) ==1,
+ ogg_page_continued(page) !=0
+
+If a page happens to be a single packet that was begun on a
+previous page, and spans to the next page (in the case of a three or
+more page packet), the return will be:
+ ogg_page_packets(page) ==0,
+ ogg_page_continued(page) !=0
+*/
+
+int ogg_page_packets(ogg_page *og){
+ int i,n=og->header[26],count=0;
+ for(i=0;i<n;i++)
+ if(og->header[27+i]<255)count++;
+ return(count);
+}
+
+
+#if 0
+/* helper to initialize lookup for direct-table CRC (illustrative; we
+ use the static init below) */
+
+static ogg_uint32_t _ogg_crc_entry(unsigned long index){
+ int i;
+ unsigned long r;
+
+ r = index << 24;
+ for (i=0; i<8; i++)
+ if (r & 0x80000000UL)
+ r = (r << 1) ^ 0x04c11db7; /* The same as the ethernet generator
+ polynomial, although we use an
+ unreflected alg and an init/final
+ of 0, not 0xffffffff */
+ else
+ r<<=1;
+ return (r & 0xffffffffUL);
+}
+#endif
+
+static const ogg_uint32_t crc_lookup[256]={
+ 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
+ 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
+ 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
+ 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
+ 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
+ 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
+ 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
+ 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
+ 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
+ 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
+ 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
+ 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
+ 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
+ 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
+ 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
+ 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
+ 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
+ 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
+ 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
+ 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
+ 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
+ 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
+ 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
+ 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
+ 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
+ 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
+ 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
+ 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
+ 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
+ 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
+ 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
+ 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
+ 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
+ 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
+ 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
+ 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
+ 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
+ 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
+ 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
+ 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
+ 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
+ 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
+ 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
+ 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
+ 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
+ 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
+ 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
+ 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
+ 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
+ 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
+ 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
+ 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
+ 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
+ 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
+ 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
+ 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
+ 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
+ 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
+ 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
+ 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
+ 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
+ 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
+ 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
+ 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
+
+/* init the encode/decode logical stream state */
+
+int ogg_stream_init(ogg_stream_state *os,int serialno){
+ if(os){
+ memset(os,0,sizeof(*os));
+ os->body_storage=16*1024;
+ os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
+
+ os->lacing_storage=1024;
+ os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
+ os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
+
+ os->serialno=serialno;
+
+ return(0);
+ }
+ return(-1);
+}
+
+/* _clear does not free os, only the non-flat storage within */
+int ogg_stream_clear(ogg_stream_state *os){
+ if(os){
+ if(os->body_data)_ogg_free(os->body_data);
+ if(os->lacing_vals)_ogg_free(os->lacing_vals);
+ if(os->granule_vals)_ogg_free(os->granule_vals);
+
+ memset(os,0,sizeof(*os));
+ }
+ return(0);
+}
+
+int ogg_stream_destroy(ogg_stream_state *os){
+ if(os){
+ ogg_stream_clear(os);
+ _ogg_free(os);
+ }
+ return(0);
+}
+
+/* Helpers for ogg_stream_encode; this keeps the structure and
+ what's happening fairly clear */
+
+static void _os_body_expand(ogg_stream_state *os,int needed){
+ if(os->body_storage<=os->body_fill+needed){
+ os->body_storage+=(needed+1024);
+ os->body_data=_ogg_realloc(os->body_data,os->body_storage*sizeof(*os->body_data));
+ }
+}
+
+static void _os_lacing_expand(ogg_stream_state *os,int needed){
+ if(os->lacing_storage<=os->lacing_fill+needed){
+ os->lacing_storage+=(needed+32);
+ os->lacing_vals=_ogg_realloc(os->lacing_vals,os->lacing_storage*sizeof(*os->lacing_vals));
+ os->granule_vals=_ogg_realloc(os->granule_vals,os->lacing_storage*sizeof(*os->granule_vals));
+ }
+}
+
+/* checksum the page */
+/* Direct table CRC; note that this will be faster in the future if we
+ perform the checksum silmultaneously with other copies */
+
+void ogg_page_checksum_set(ogg_page *og){
+ if(og){
+ ogg_uint32_t crc_reg=0;
+ int i;
+
+ /* safety; needed for API behavior, but not framing code */
+ og->header[22]=0;
+ og->header[23]=0;
+ og->header[24]=0;
+ og->header[25]=0;
+
+ for(i=0;i<og->header_len;i++)
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
+ for(i=0;i<og->body_len;i++)
+ crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
+
+ og->header[22]=(unsigned char)(crc_reg&0xff);
+ og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
+ og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
+ og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
+ }
+}
+
+/* submit data to the internal buffer of the framing engine */
+int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
+ int lacing_vals=op->bytes/255+1,i;
+
+ if(os->body_returned){
+ /* advance packet data according to the body_returned pointer. We
+ had to keep it around to return a pointer into the buffer last
+ call */
+
+ os->body_fill-=os->body_returned;
+ if(os->body_fill)
+ memmove(os->body_data,os->body_data+os->body_returned,
+ os->body_fill);
+ os->body_returned=0;
+ }
+
+ /* make sure we have the buffer storage */
+ _os_body_expand(os,op->bytes);
+ _os_lacing_expand(os,lacing_vals);
+
+ /* Copy in the submitted packet. Yes, the copy is a waste; this is
+ the liability of overly clean abstraction for the time being. It
+ will actually be fairly easy to eliminate the extra copy in the
+ future */
+
+ memcpy(os->body_data+os->body_fill,op->packet,op->bytes);
+ os->body_fill+=op->bytes;
+
+ /* Store lacing vals for this packet */
+ for(i=0;i<lacing_vals-1;i++){
+ os->lacing_vals[os->lacing_fill+i]=255;
+ os->granule_vals[os->lacing_fill+i]=os->granulepos;
+ }
+ os->lacing_vals[os->lacing_fill+i]=(op->bytes)%255;
+ os->granulepos=os->granule_vals[os->lacing_fill+i]=op->granulepos;
+
+ /* flag the first segment as the beginning of the packet */
+ os->lacing_vals[os->lacing_fill]|= 0x100;
+
+ os->lacing_fill+=lacing_vals;
+
+ /* for the sake of completeness */
+ os->packetno++;
+
+ if(op->e_o_s)os->e_o_s=1;
+
+ return(0);
+}
+
+/* This will flush remaining packets into a page (returning nonzero),
+ even if there is not enough data to trigger a flush normally
+ (undersized page). If there are no packets or partial packets to
+ flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
+ try to flush a normal sized page like ogg_stream_pageout; a call to
+ ogg_stream_flush does not guarantee that all packets have flushed.
+ Only a return value of 0 from ogg_stream_flush indicates all packet
+ data is flushed into pages.
+
+ since ogg_stream_flush will flush the last page in a stream even if
+ it's undersized, you almost certainly want to use ogg_stream_pageout
+ (and *not* ogg_stream_flush) unless you specifically need to flush
+ an page regardless of size in the middle of a stream. */
+
+int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
+ int i;
+ int vals=0;
+ int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
+ int bytes=0;
+ long acc=0;
+ ogg_int64_t granule_pos=-1;
+
+ if(maxvals==0)return(0);
+
+ /* construct a page */
+ /* decide how many segments to include */
+
+ /* If this is the initial header case, the first page must only include
+ the initial header packet */
+ if(os->b_o_s==0){ /* 'initial header page' case */
+ granule_pos=0;
+ for(vals=0;vals<maxvals;vals++){
+ if((os->lacing_vals[vals]&0x0ff)<255){
+ vals++;
+ break;
+ }
+ }
+ }else{
+ for(vals=0;vals<maxvals;vals++){
+ if(acc>4096)break;
+ acc+=os->lacing_vals[vals]&0x0ff;
+ if((os->lacing_vals[vals]&0xff)<255)
+ granule_pos=os->granule_vals[vals];
+ }
+ }
+
+ /* construct the header in temp storage */
+ memcpy(os->header,"OggS",4);
+
+ /* stream structure version */
+ os->header[4]=0x00;
+
+ /* continued packet flag? */
+ os->header[5]=0x00;
+ if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
+ /* first page flag? */
+ if(os->b_o_s==0)os->header[5]|=0x02;
+ /* last page flag? */
+ if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
+ os->b_o_s=1;
+
+ /* 64 bits of PCM position */
+ for(i=6;i<14;i++){
+ os->header[i]=(unsigned char)(granule_pos&0xff);
+ granule_pos>>=8;
+ }
+
+ /* 32 bits of stream serial number */
+ {
+ long serialno=os->serialno;
+ for(i=14;i<18;i++){
+ os->header[i]=(unsigned char)(serialno&0xff);
+ serialno>>=8;
+ }
+ }
+
+ /* 32 bits of page counter (we have both counter and page header
+ because this val can roll over) */
+ if(os->pageno==-1)os->pageno=0; /* because someone called
+ stream_reset; this would be a
+ strange thing to do in an
+ encode stream, but it has
+ plausible uses */
+ {
+ long pageno=os->pageno++;
+ for(i=18;i<22;i++){
+ os->header[i]=(unsigned char)(pageno&0xff);
+ pageno>>=8;
+ }
+ }
+
+ /* zero for computation; filled in later */
+ os->header[22]=0;
+ os->header[23]=0;
+ os->header[24]=0;
+ os->header[25]=0;
+
+ /* segment table */
+ os->header[26]=(unsigned char)(vals&0xff);
+ for(i=0;i<vals;i++)
+ bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
+
+ /* set pointers in the ogg_page struct */
+ og->header=os->header;
+ og->header_len=os->header_fill=vals+27;
+ og->body=os->body_data+os->body_returned;
+ og->body_len=bytes;
+
+ /* advance the lacing data and set the body_returned pointer */
+
+ os->lacing_fill-=vals;
+ memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
+ memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
+ os->body_returned+=bytes;
+
+ /* calculate the checksum */
+
+ ogg_page_checksum_set(og);
+
+ /* done */
+ return(1);
+}
+
+
+/* This constructs pages from buffered packet segments. The pointers
+returned are to static buffers; do not free. The returned buffers are
+good only until the next call (using the same ogg_stream_state) */
+
+int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
+
+ if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
+ os->body_fill-os->body_returned > 4096 ||/* 'page nominal size' case */
+ os->lacing_fill>=255 || /* 'segment table full' case */
+ (os->lacing_fill&&!os->b_o_s)){ /* 'initial header page' case */
+
+ return(ogg_stream_flush(os,og));
+ }
+
+ /* not enough data to construct a page and not end of stream */
+ return(0);
+}
+
+int ogg_stream_eos(ogg_stream_state *os){
+ return os->e_o_s;
+}
+
+/* DECODING PRIMITIVES: packet streaming layer **********************/
+
+/* This has two layers to place more of the multi-serialno and paging
+ control in the application's hands. First, we expose a data buffer
+ using ogg_sync_buffer(). The app either copies into the
+ buffer, or passes it directly to read(), etc. We then call
+ ogg_sync_wrote() to tell how many bytes we just added.
+
+ Pages are returned (pointers into the buffer in ogg_sync_state)
+ by ogg_sync_pageout(). The page is then submitted to
+ ogg_stream_pagein() along with the appropriate
+ ogg_stream_state* (ie, matching serialno). We then get raw
+ packets out calling ogg_stream_packetout() with a
+ ogg_stream_state. */
+
+/* initialize the struct to a known state */
+int ogg_sync_init(ogg_sync_state *oy){
+ if(oy){
+ memset(oy,0,sizeof(*oy));
+ }
+ return(0);
+}
+
+/* clear non-flat storage within */
+int ogg_sync_clear(ogg_sync_state *oy){
+ if(oy){
+ if(oy->data)_ogg_free(oy->data);
+ ogg_sync_init(oy);
+ }
+ return(0);
+}
+
+int ogg_sync_destroy(ogg_sync_state *oy){
+ if(oy){
+ ogg_sync_clear(oy);
+ _ogg_free(oy);
+ }
+ return(0);
+}
+
+char *ogg_sync_buffer(ogg_sync_state *oy, long size){
+
+ /* first, clear out any space that has been previously returned */
+ if(oy->returned){
+ oy->fill-=oy->returned;
+ if(oy->fill>0)
+ memmove(oy->data,oy->data+oy->returned,oy->fill);
+ oy->returned=0;
+ }
+
+ if(size>oy->storage-oy->fill){
+ /* We need to extend the internal buffer */
+ long newsize=size+oy->fill+4096; /* an extra page to be nice */
+
+ if(oy->data)
+ oy->data=_ogg_realloc(oy->data,newsize);
+ else
+ oy->data=_ogg_malloc(newsize);
+ oy->storage=newsize;
+ }
+
+ /* expose a segment at least as large as requested at the fill mark */
+ return((char *)oy->data+oy->fill);
+}
+
+int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
+ if(oy->fill+bytes>oy->storage)return(-1);
+ oy->fill+=bytes;
+ return(0);
+}
+
+/* sync the stream. This is meant to be useful for finding page
+ boundaries.
+
+ return values for this:
+ -n) skipped n bytes
+ 0) page not ready; more data (no bytes skipped)
+ n) page synced at current location; page length n bytes
+
+*/
+
+long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
+ unsigned char *outerpage=oy->data+oy->returned;
+ unsigned char *next;
+ long outerbytes=oy->fill-oy->returned;
+
+ if(oy->headerbytes==0){
+ int headerbytes,i;
+ if(outerbytes<27)return(0); /* not enough for a header */
+
+ /* verify capture pattern */
+ if(memcmp(outerpage,"OggS",4))goto sync_fail;
+
+ headerbytes=outerpage[26]+27;
+ if(outerbytes<headerbytes)return(0); /* not enough for header + seg table */
+
+ /* count up body length in the segment table */
+
+ for(i=0;i<outerpage[26];i++)
+ oy->bodybytes+=outerpage[27+i];
+ oy->headerbytes=headerbytes;
+ }
+
+ if(oy->bodybytes+oy->headerbytes>outerbytes)return(0);
+
+ /* The whole test page is buffered. Verify the checksum */
+ {
+ /* Grab the checksum bytes, set the header field to zero */
+ char chksum[4];
+ ogg_page log;
+
+ memcpy(chksum,outerpage+22,4);
+ memset(outerpage+22,0,4);
+
+ /* set up a temp page struct and recompute the checksum */
+ log.header=outerpage;
+ log.header_len=oy->headerbytes;
+ log.body=outerpage+oy->headerbytes;
+ log.body_len=oy->bodybytes;
+ ogg_page_checksum_set(&log);
+
+ /* Compare */
+ if(memcmp(chksum,outerpage+22,4)){
+ /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
+ at all) */
+ /* replace the computed checksum with the one actually read in */
+ memcpy(outerpage+22,chksum,4);
+
+ /* Bad checksum. Lose sync */
+ goto sync_fail;
+ }
+ }
+
+ /* yes, have a whole page all ready to go */
+ {
+ unsigned char *page=oy->data+oy->returned;
+ long bytes;
+
+ if(og){
+ og->header=page;
+ og->header_len=oy->headerbytes;
+ og->body=page+oy->headerbytes;
+ og->body_len=oy->bodybytes;
+ }
+
+ oy->unsynced=0;
+ oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+ return(bytes);
+ }
+
+ sync_fail:
+
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+
+ /* search for possible capture */
+ next=memchr(outerpage+1,'O',outerbytes-1);
+ if(!next)
+ next=oy->data+oy->fill;
+
+ oy->returned=next-oy->data;
+ return(-(next-outerpage));
+}
+
+/* sync the stream and get a page. Keep trying until we find a page.
+ Supress 'sync errors' after reporting the first.
+
+ return values:
+ -1) recapture (hole in data)
+ 0) need more data
+ 1) page returned
+
+ Returns pointers into buffered data; invalidated by next call to
+ _stream, _clear, _init, or _buffer */
+
+int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
+
+ /* all we need to do is verify a page at the head of the stream
+ buffer. If it doesn't verify, we look for the next potential
+ frame */
+
+ for(;;){
+ long ret=ogg_sync_pageseek(oy,og);
+ if(ret>0){
+ /* have a page */
+ return(1);
+ }
+ if(ret==0){
+ /* need more data */
+ return(0);
+ }
+
+ /* head did not start a synced page... skipped some bytes */
+ if(!oy->unsynced){
+ oy->unsynced=1;
+ return(-1);
+ }
+
+ /* loop. keep looking */
+
+ }
+}
+
+/* add the incoming page to the stream state; we decompose the page
+ into packet segments here as well. */
+
+int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
+ unsigned char *header=og->header;
+ unsigned char *body=og->body;
+ long bodysize=og->body_len;
+ int segptr=0;
+
+ int version=ogg_page_version(og);
+ int continued=ogg_page_continued(og);
+ int bos=ogg_page_bos(og);
+ int eos=ogg_page_eos(og);
+ ogg_int64_t granulepos=ogg_page_granulepos(og);
+ int serialno=ogg_page_serialno(og);
+ long pageno=ogg_page_pageno(og);
+ int segments=header[26];
+
+ /* clean up 'returned data' */
+ {
+ long lr=os->lacing_returned;
+ long br=os->body_returned;
+
+ /* body data */
+ if(br){
+ os->body_fill-=br;
+ if(os->body_fill)
+ memmove(os->body_data,os->body_data+br,os->body_fill);
+ os->body_returned=0;
+ }
+
+ if(lr){
+ /* segment table */
+ if(os->lacing_fill-lr){
+ memmove(os->lacing_vals,os->lacing_vals+lr,
+ (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
+ memmove(os->granule_vals,os->granule_vals+lr,
+ (os->lacing_fill-lr)*sizeof(*os->granule_vals));
+ }
+ os->lacing_fill-=lr;
+ os->lacing_packet-=lr;
+ os->lacing_returned=0;
+ }
+ }
+
+ /* check the serial number */
+ if(serialno!=os->serialno)return(-1);
+ if(version>0)return(-1);
+
+ _os_lacing_expand(os,segments+1);
+
+ /* are we in sequence? */
+ if(pageno!=os->pageno){
+ int i;
+
+ /* unroll previous partial packet (if any) */
+ for(i=os->lacing_packet;i<os->lacing_fill;i++)
+ os->body_fill-=os->lacing_vals[i]&0xff;
+ os->lacing_fill=os->lacing_packet;
+
+ /* make a note of dropped data in segment table */
+ if(os->pageno!=-1){
+ os->lacing_vals[os->lacing_fill++]=0x400;
+ os->lacing_packet++;
+ }
+ }
+
+ /* are we a 'continued packet' page? If so, we may need to skip
+ some segments */
+ if(continued){
+ if(os->lacing_fill<1 ||
+ os->lacing_vals[os->lacing_fill-1]==0x400){
+ bos=0;
+ for(;segptr<segments;segptr++){
+ int val=header[27+segptr];
+ body+=val;
+ bodysize-=val;
+ if(val<255){
+ segptr++;
+ break;
+ }
+ }
+ }
+ }
+
+ if(bodysize){
+ _os_body_expand(os,bodysize);
+ memcpy(os->body_data+os->body_fill,body,bodysize);
+ os->body_fill+=bodysize;
+ }
+
+ {
+ int saved=-1;
+ while(segptr<segments){
+ int val=header[27+segptr];
+ os->lacing_vals[os->lacing_fill]=val;
+ os->granule_vals[os->lacing_fill]=-1;
+
+ if(bos){
+ os->lacing_vals[os->lacing_fill]|=0x100;
+ bos=0;
+ }
+
+ if(val<255)saved=os->lacing_fill;
+
+ os->lacing_fill++;
+ segptr++;
+
+ if(val<255)os->lacing_packet=os->lacing_fill;
+ }
+
+ /* set the granulepos on the last granuleval of the last full packet */
+ if(saved!=-1){
+ os->granule_vals[saved]=granulepos;
+ }
+
+ }
+
+ if(eos){
+ os->e_o_s=1;
+ if(os->lacing_fill>0)
+ os->lacing_vals[os->lacing_fill-1]|=0x200;
+ }
+
+ os->pageno=pageno+1;
+
+ return(0);
+}
+
+/* clear things to an initial state. Good to call, eg, before seeking */
+int ogg_sync_reset(ogg_sync_state *oy){
+ oy->fill=0;
+ oy->returned=0;
+ oy->unsynced=0;
+ oy->headerbytes=0;
+ oy->bodybytes=0;
+ return(0);
+}
+
+int ogg_stream_reset(ogg_stream_state *os){
+ os->body_fill=0;
+ os->body_returned=0;
+
+ os->lacing_fill=0;
+ os->lacing_packet=0;
+ os->lacing_returned=0;
+
+ os->header_fill=0;
+
+ os->e_o_s=0;
+ os->b_o_s=0;
+ os->pageno=-1;
+ os->packetno=0;
+ os->granulepos=0;
+
+ return(0);
+}
+
+int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
+ ogg_stream_reset(os);
+ os->serialno=serialno;
+ return(0);
+}
+
+static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
+
+ /* The last part of decode. We have the stream broken into packet
+ segments. Now we need to group them into packets (or return the
+ out of sync markers) */
+
+ int ptr=os->lacing_returned;
+
+ if(os->lacing_packet<=ptr)return(0);
+
+ if(os->lacing_vals[ptr]&0x400){
+ /* we need to tell the codec there's a gap; it might need to
+ handle previous packet dependencies. */
+ os->lacing_returned++;
+ os->packetno++;
+ return(-1);
+ }
+
+ if(!op && !adv)return(1); /* just using peek as an inexpensive way
+ to ask if there's a whole packet
+ waiting */
+
+ /* Gather the whole packet. We'll have no holes or a partial packet */
+ {
+ int size=os->lacing_vals[ptr]&0xff;
+ int bytes=size;
+ int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
+ int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
+
+ while(size==255){
+ int val=os->lacing_vals[++ptr];
+ size=val&0xff;
+ if(val&0x200)eos=0x200;
+ bytes+=size;
+ }
+
+ if(op){
+ op->e_o_s=eos;
+ op->b_o_s=bos;
+ op->packet=os->body_data+os->body_returned;
+ op->packetno=os->packetno;
+ op->granulepos=os->granule_vals[ptr];
+ op->bytes=bytes;
+ }
+
+ if(adv){
+ os->body_returned+=bytes;
+ os->lacing_returned=ptr+1;
+ os->packetno++;
+ }
+ }
+ return(1);
+}
+
+int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
+ return _packetout(os,op,1);
+}
+
+int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
+ return _packetout(os,op,0);
+}
+
+void ogg_packet_clear(ogg_packet *op) {
+ _ogg_free(op->packet);
+ memset(op, 0, sizeof(*op));
+}
+
+#ifdef _V_SELFTEST
+#include <stdio.h>
+
+ogg_stream_state os_en, os_de;
+ogg_sync_state oy;
+
+static
+void checkpacket(ogg_packet *op,int len, int no, int pos){
+ long j;
+ static int sequence=0;
+ static int lastno=0;
+
+ if(op->bytes!=len){
+ fprintf(stderr,"incorrect packet length!\n");
+ exit(1);
+ }
+ if(op->granulepos!=pos){
+ fprintf(stderr,"incorrect packet position!\n");
+ exit(1);
+ }
+
+ /* packet number just follows sequence/gap; adjust the input number
+ for that */
+ if(no==0){
+ sequence=0;
+ }else{
+ sequence++;
+ if(no>lastno+1)
+ sequence++;
+ }
+ lastno=no;
+ if(op->packetno!=sequence){
+ fprintf(stderr,"incorrect packet sequence %ld != %d\n",
+ (long)(op->packetno),sequence);
+ exit(1);
+ }
+
+ /* Test data */
+ for(j=0;j<op->bytes;j++)
+ if(op->packet[j]!=((j+no)&0xff)){
+ fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
+ j,op->packet[j],(j+no)&0xff);
+ exit(1);
+ }
+}
+
+static
+void check_page(unsigned char *data,const int *header,ogg_page *og){
+ long j;
+ /* Test data */
+ for(j=0;j<og->body_len;j++)
+ if(og->body[j]!=data[j]){
+ fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
+ j,data[j],og->body[j]);
+ exit(1);
+ }
+
+ /* Test header */
+ for(j=0;j<og->header_len;j++){
+ if(og->header[j]!=header[j]){
+ fprintf(stderr,"header content mismatch at pos %ld:\n",j);
+ for(j=0;j<header[26]+27;j++)
+ fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
+ fprintf(stderr,"\n");
+ exit(1);
+ }
+ }
+ if(og->header_len!=header[26]+27){
+ fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
+ og->header_len,header[26]+27);
+ exit(1);
+ }
+}
+
+void print_header(ogg_page *og);
+void print_header(ogg_page *og){
+ int j;
+ fprintf(stderr,"\nHEADER:\n");
+ fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
+ og->header[0],og->header[1],og->header[2],og->header[3],
+ (int)og->header[4],(int)og->header[5]);
+
+ fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
+ (og->header[9]<<24)|(og->header[8]<<16)|
+ (og->header[7]<<8)|og->header[6],
+ (og->header[17]<<24)|(og->header[16]<<16)|
+ (og->header[15]<<8)|og->header[14],
+ ((long)(og->header[21])<<24)|(og->header[20]<<16)|
+ (og->header[19]<<8)|og->header[18]);
+
+ fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
+ (int)og->header[22],(int)og->header[23],
+ (int)og->header[24],(int)og->header[25],
+ (int)og->header[26]);
+
+ for(j=27;j<og->header_len;j++)
+ fprintf(stderr,"%d ",(int)og->header[j]);
+ fprintf(stderr,")\n\n");
+}
+
+static
+void copy_page(ogg_page *og){
+ unsigned char *temp=_ogg_malloc(og->header_len);
+ memcpy(temp,og->header,og->header_len);
+ og->header=temp;
+
+ temp=_ogg_malloc(og->body_len);
+ memcpy(temp,og->body,og->body_len);
+ og->body=temp;
+}
+
+static
+void free_page(ogg_page *og){
+ _ogg_free (og->header);
+ _ogg_free (og->body);
+}
+
+static
+void error(void){
+ fprintf(stderr,"error!\n");
+ exit(1);
+}
+
+/* 17 only */
+static
+const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x15,0xed,0xec,0x91,
+ 1,
+ 17};
+
+/* 17, 254, 255, 256, 500, 510, 600 byte, pad */
+const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x59,0x10,0x6c,0x2c,
+ 1,
+ 17};
+const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x89,0x33,0x85,0xce,
+ 13,
+ 254,255,0,255,1,255,245,255,255,0,
+ 255,255,90};
+
+/* nil packets; beginning,middle,end */
+const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x5c,0x3f,0x66,0xcb,
+ 17,
+ 17,254,255,0,0,255,1,0,255,245,255,255,0,
+ 255,255,90,0};
+
+/* large initial packet */
+const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0x01,0x27,0x31,0xaa,
+ 18,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255,10};
+
+const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x7f,0x4e,0x8a,0xd2,
+ 4,
+ 255,4,255,0};
+
+
+/* continuing packet test */
+const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x54,0x05,0x51,0xc8,
+ 17,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255};
+
+const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xc8,0xc3,0xcb,0xed,
+ 5,
+ 10,255,4,255,0};
+
+
+/* page with the 255 segment limit */
+const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0xed,0x2a,0x2e,0xa7,
+ 255,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10};
+
+const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
+ 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x6c,0x3b,0x82,0x3d,
+ 1,
+ 50};
+
+
+/* packet that overspans over an entire page */
+const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x3c,0xd9,0x4d,0x3f,
+ 17,
+ 100,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+
+const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0x01,0xd2,0xe5,0xe5,
+ 17,
+ 255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255,255};
+
+const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,3,0,0,0,
+ 0xef,0xdd,0x88,0xde,
+ 7,
+ 255,255,75,255,4,255,0};
+
+/* packet that overspans over an entire page */
+const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,0,0,0,0,
+ 0xff,0x7b,0x23,0x17,
+ 1,
+ 0};
+
+const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
+ 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,1,0,0,0,
+ 0x3c,0xd9,0x4d,0x3f,
+ 17,
+ 100,255,255,255,255,255,255,255,255,
+ 255,255,255,255,255,255,255,255};
+
+const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
+ 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x02,0x03,0x04,2,0,0,0,
+ 0xd4,0xe0,0x60,0xe5,
+ 1,0};
+
+static
+void test_pack(const int *pl, const int **headers, int byteskip,
+ int pageskip, int packetskip){
+ unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
+ long inptr=0;
+ long outptr=0;
+ long deptr=0;
+ long depacket=0;
+ long granule_pos=7,pageno=0;
+ int i,j,packets,pageout=pageskip;
+ int eosflag=0;
+ int bosflag=0;
+
+ int byteskipcount=0;
+
+ ogg_stream_reset(&os_en);
+ ogg_stream_reset(&os_de);
+ ogg_sync_reset(&oy);
+
+ for(packets=0;packets<packetskip;packets++)
+ depacket+=pl[packets];
+
+ for(packets=0;;packets++)if(pl[packets]==-1)break;
+
+ for(i=0;i<packets;i++){
+ /* construct a test packet */
+ ogg_packet op;
+ int len=pl[i];
+
+ op.packet=data+inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=granule_pos;
+
+ granule_pos+=1024;
+
+ for(j=0;j<len;j++)data[inptr++]=i+j;
+
+ /* submit the test packet */
+ ogg_stream_packetin(&os_en,&op);
+
+ /* retrieve any finished pages */
+ {
+ ogg_page og;
+
+ while(ogg_stream_pageout(&os_en,&og)){
+ /* We have a page. Check it carefully */
+
+ fprintf(stderr,"%ld, ",pageno);
+
+ if(headers[pageno]==NULL){
+ fprintf(stderr,"coded too many pages!\n");
+ exit(1);
+ }
+
+ check_page(data+outptr,headers[pageno],&og);
+
+ outptr+=og.body_len;
+ pageno++;
+ if(pageskip){
+ bosflag=1;
+ pageskip--;
+ deptr+=og.body_len;
+ }
+
+ /* have a complete page; submit it to sync/decode */
+
+ {
+ ogg_page og_de;
+ ogg_packet op_de,op_de2;
+ char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
+ char *next=buf;
+ byteskipcount+=og.header_len;
+ if(byteskipcount>byteskip){
+ memcpy(next,og.header,byteskipcount-byteskip);
+ next+=byteskipcount-byteskip;
+ byteskipcount=byteskip;
+ }
+
+ byteskipcount+=og.body_len;
+ if(byteskipcount>byteskip){
+ memcpy(next,og.body,byteskipcount-byteskip);
+ next+=byteskipcount-byteskip;
+ byteskipcount=byteskip;
+ }
+
+ ogg_sync_wrote(&oy,next-buf);
+
+ while(1){
+ int ret=ogg_sync_pageout(&oy,&og_de);
+ if(ret==0)break;
+ if(ret<0)continue;
+ /* got a page. Happy happy. Verify that it's good. */
+
+ fprintf(stderr,"(%d), ",pageout);
+
+ check_page(data+deptr,headers[pageout],&og_de);
+ deptr+=og_de.body_len;
+ pageout++;
+
+ /* submit it to deconstitution */
+ ogg_stream_pagein(&os_de,&og_de);
+
+ /* packets out? */
+ while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
+ ogg_stream_packetpeek(&os_de,NULL);
+ ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
+
+ /* verify peek and out match */
+ if(memcmp(&op_de,&op_de2,sizeof(op_de))){
+ fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
+ depacket);
+ exit(1);
+ }
+
+ /* verify the packet! */
+ /* check data */
+ if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
+ fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
+ depacket);
+ exit(1);
+ }
+ /* check bos flag */
+ if(bosflag==0 && op_de.b_o_s==0){
+ fprintf(stderr,"b_o_s flag not set on packet!\n");
+ exit(1);
+ }
+ if(bosflag && op_de.b_o_s){
+ fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
+ exit(1);
+ }
+ bosflag=1;
+ depacket+=op_de.bytes;
+
+ /* check eos flag */
+ if(eosflag){
+ fprintf(stderr,"Multiple decoded packets with eos flag!\n");
+ exit(1);
+ }
+
+ if(op_de.e_o_s)eosflag=1;
+
+ /* check granulepos flag */
+ if(op_de.granulepos!=-1){
+ fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ _ogg_free(data);
+ if(headers[pageno]!=NULL){
+ fprintf(stderr,"did not write last page!\n");
+ exit(1);
+ }
+ if(headers[pageout]!=NULL){
+ fprintf(stderr,"did not decode last page!\n");
+ exit(1);
+ }
+ if(inptr!=outptr){
+ fprintf(stderr,"encoded page data incomplete!\n");
+ exit(1);
+ }
+ if(inptr!=deptr){
+ fprintf(stderr,"decoded page data incomplete!\n");
+ exit(1);
+ }
+ if(inptr!=depacket){
+ fprintf(stderr,"decoded packet data incomplete!\n");
+ exit(1);
+ }
+ if(!eosflag){
+ fprintf(stderr,"Never got a packet with EOS set!\n");
+ exit(1);
+ }
+ fprintf(stderr,"ok.\n");
+}
+
+int main(void){
+
+ ogg_stream_init(&os_en,0x04030201);
+ ogg_stream_init(&os_de,0x04030201);
+ ogg_sync_init(&oy);
+
+ /* Exercise each code path in the framing code. Also verify that
+ the checksums are working. */
+
+ {
+ /* 17 only */
+ const int packets[]={17, -1};
+ const int *headret[]={head1_0,NULL};
+
+ fprintf(stderr,"testing single page encoding... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
+ const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
+ const int *headret[]={head1_1,head2_1,NULL};
+
+ fprintf(stderr,"testing basic page encoding... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* nil packets; beginning,middle,end */
+ const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
+ const int *headret[]={head1_2,head2_2,NULL};
+
+ fprintf(stderr,"testing basic nil packets... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* large initial packet */
+ const int packets[]={4345,259,255,-1};
+ const int *headret[]={head1_3,head2_3,NULL};
+
+ fprintf(stderr,"testing initial-packet lacing > 4k... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* continuing packet test */
+ const int packets[]={0,4345,259,255,-1};
+ const int *headret[]={head1_4,head2_4,head3_4,NULL};
+
+ fprintf(stderr,"testing single packet page span... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ /* page with the 255 segment limit */
+ {
+
+ const int packets[]={0,10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,10,
+ 10,10,10,10,10,10,10,50,-1};
+ const int *headret[]={head1_5,head2_5,head3_5,NULL};
+
+ fprintf(stderr,"testing max packet segments... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* packet that overspans over an entire page */
+ const int packets[]={0,100,9000,259,255,-1};
+ const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
+
+ fprintf(stderr,"testing very large packets... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+ {
+ /* test for the libogg 1.1.1 resync in large continuation bug
+ found by Josh Coalson) */
+ const int packets[]={0,100,9000,259,255,-1};
+ const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
+
+ fprintf(stderr,"testing continuation resync in very large packets... ");
+ test_pack(packets,headret,100,2,3);
+ }
+
+ {
+ /* term only page. why not? */
+ const int packets[]={0,100,4080,-1};
+ const int *headret[]={head1_7,head2_7,head3_7,NULL};
+
+ fprintf(stderr,"testing zero data page (1 nil packet)... ");
+ test_pack(packets,headret,0,0,0);
+ }
+
+
+
+ {
+ /* build a bunch of pages for testing */
+ unsigned char *data=_ogg_malloc(1024*1024);
+ int pl[]={0,100,4079,2956,2057,76,34,912,0,234,1000,1000,1000,300,-1};
+ int inptr=0,i,j;
+ ogg_page og[5];
+
+ ogg_stream_reset(&os_en);
+
+ for(i=0;pl[i]!=-1;i++){
+ ogg_packet op;
+ int len=pl[i];
+
+ op.packet=data+inptr;
+ op.bytes=len;
+ op.e_o_s=(pl[i+1]<0?1:0);
+ op.granulepos=(i+1)*1000;
+
+ for(j=0;j<len;j++)data[inptr++]=i+j;
+ ogg_stream_packetin(&os_en,&op);
+ }
+
+ _ogg_free(data);
+
+ /* retrieve finished pages */
+ for(i=0;i<5;i++){
+ if(ogg_stream_pageout(&os_en,&og[i])==0){
+ fprintf(stderr,"Too few pages output building sync tests!\n");
+ exit(1);
+ }
+ copy_page(&og[i]);
+ }
+
+ /* Test lost pages on pagein/packetout: no rollback */
+ {
+ ogg_page temp;
+ ogg_packet test;
+
+ fprintf(stderr,"Testing loss of pages... ");
+
+ ogg_sync_reset(&oy);
+ ogg_stream_reset(&os_de);
+ for(i=0;i<5;i++){
+ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
+ og[i].header_len);
+ ogg_sync_wrote(&oy,og[i].header_len);
+ memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
+ ogg_sync_wrote(&oy,og[i].body_len);
+ }
+
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ /* skip */
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+
+ /* do we get the expected results/packets? */
+
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,0,0,0);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,100,1,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,4079,2,3000);
+ if(ogg_stream_packetout(&os_de,&test)!=-1){
+ fprintf(stderr,"Error: loss of page did not return error\n");
+ exit(1);
+ }
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,76,5,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,34,6,-1);
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test lost pages on pagein/packetout: rollback with continuation */
+ {
+ ogg_page temp;
+ ogg_packet test;
+
+ fprintf(stderr,"Testing loss of pages (rollback required)... ");
+
+ ogg_sync_reset(&oy);
+ ogg_stream_reset(&os_de);
+ for(i=0;i<5;i++){
+ memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
+ og[i].header_len);
+ ogg_sync_wrote(&oy,og[i].header_len);
+ memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
+ ogg_sync_wrote(&oy,og[i].body_len);
+ }
+
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+ ogg_sync_pageout(&oy,&temp);
+ /* skip */
+ ogg_sync_pageout(&oy,&temp);
+ ogg_stream_pagein(&os_de,&temp);
+
+ /* do we get the expected results/packets? */
+
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,0,0,0);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,100,1,-1);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,4079,2,3000);
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,2956,3,4000);
+ if(ogg_stream_packetout(&os_de,&test)!=-1){
+ fprintf(stderr,"Error: loss of page did not return error\n");
+ exit(1);
+ }
+ if(ogg_stream_packetout(&os_de,&test)!=1)error();
+ checkpacket(&test,300,13,14000);
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* the rest only test sync */
+ {
+ ogg_page og_de;
+ /* Test fractional page inputs: incomplete capture */
+ fprintf(stderr,"Testing sync on partial inputs... ");
+ ogg_sync_reset(&oy);
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ 3);
+ ogg_sync_wrote(&oy,3);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete fixed header */
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete header */
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
+ 5);
+ ogg_sync_wrote(&oy,5);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ /* Test fractional page inputs: incomplete body */
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
+ og[1].header_len-28);
+ ogg_sync_wrote(&oy,og[1].header_len-28);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
+ ogg_sync_wrote(&oy,1000);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
+ og[1].body_len-1000);
+ ogg_sync_wrote(&oy,og[1].body_len-1000);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test fractional page inputs: page + incomplete capture */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing sync on 1+partial inputs... ");
+ ogg_sync_reset(&oy);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
+ og[1].header_len-20);
+ ogg_sync_wrote(&oy,og[1].header_len-20);
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test recapture: garbage + page */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing search for capture... ");
+ ogg_sync_reset(&oy);
+
+ /* 'garbage' */
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ 20);
+ ogg_sync_wrote(&oy,20);
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
+ og[2].header_len-20);
+ ogg_sync_wrote(&oy,og[2].header_len-20);
+ memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
+ og[2].body_len);
+ ogg_sync_wrote(&oy,og[2].body_len);
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Test recapture: page + garbage + page */
+ {
+ ogg_page og_de;
+ fprintf(stderr,"Testing recapture... ");
+ ogg_sync_reset(&oy);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
+ og[1].header_len);
+ ogg_sync_wrote(&oy,og[1].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
+ og[1].body_len);
+ ogg_sync_wrote(&oy,og[1].body_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ og[2].header_len);
+ ogg_sync_wrote(&oy,og[2].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
+ og[2].header_len);
+ ogg_sync_wrote(&oy,og[2].header_len);
+
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
+ og[2].body_len-5);
+ ogg_sync_wrote(&oy,og[2].body_len-5);
+
+ memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
+ og[3].header_len);
+ ogg_sync_wrote(&oy,og[3].header_len);
+
+ memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
+ og[3].body_len);
+ ogg_sync_wrote(&oy,og[3].body_len);
+
+ if(ogg_sync_pageout(&oy,&og_de)>0)error();
+ if(ogg_sync_pageout(&oy,&og_de)<=0)error();
+
+ fprintf(stderr,"ok.\n");
+ }
+
+ /* Free page data that was previously copied */
+ {
+ for(i=0;i<5;i++){
+ free_page(&og[i]);
+ }
+ }
+ }
+
+ return(0);
+}
+
+#endif
+
+
+
+
diff --git a/src/OGG/include/Makefile.am b/src/OGG/include/Makefile.am
new file mode 100644
index 0000000..0084e4d
--- /dev/null
+++ b/src/OGG/include/Makefile.am
@@ -0,0 +1,3 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = ogg
diff --git a/src/OGG/include/ogg/Makefile.am b/src/OGG/include/ogg/Makefile.am
new file mode 100644
index 0000000..bc32393
--- /dev/null
+++ b/src/OGG/include/ogg/Makefile.am
@@ -0,0 +1,3 @@
+## Process this file with automake to produce Makefile.in
+
+noinst_HEADERS = ogg.h os_types.h config_types.h
diff --git a/src/OGG/include/ogg/config_types.h b/src/OGG/include/ogg/config_types.h
new file mode 100644
index 0000000..aa3341c
--- /dev/null
+++ b/src/OGG/include/ogg/config_types.h
@@ -0,0 +1,12 @@
+#ifndef __CONFIG_TYPES_H__
+#define __CONFIG_TYPES_H__
+
+#include <stdint.h>
+
+typedef int16_t ogg_int16_t;
+typedef uint16_t ogg_uint16_t;
+typedef int32_t ogg_int32_t;
+typedef uint32_t ogg_uint32_t;
+typedef int64_t ogg_int64_t;
+
+#endif
diff --git a/src/OGG/include/ogg/ogg.h b/src/OGG/include/ogg/ogg.h
new file mode 100644
index 0000000..9082679
--- /dev/null
+++ b/src/OGG/include/ogg/ogg.h
@@ -0,0 +1,202 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: toplevel libogg include
+ last mod: $Id: ogg.h 7188 2004-07-20 07:26:04Z xiphmont $
+
+ ********************************************************************/
+#ifndef _OGG_H
+#define _OGG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ogg/os_types.h>
+
+typedef struct {
+ long endbyte;
+ int endbit;
+
+ unsigned char *buffer;
+ unsigned char *ptr;
+ long storage;
+} oggpack_buffer;
+
+/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
+
+typedef struct {
+ unsigned char *header;
+ long header_len;
+ unsigned char *body;
+ long body_len;
+} ogg_page;
+
+/* ogg_stream_state contains the current encode/decode state of a logical
+ Ogg bitstream **********************************************************/
+
+typedef struct {
+ unsigned char *body_data; /* bytes from packet bodies */
+ long body_storage; /* storage elements allocated */
+ long body_fill; /* elements stored; fill mark */
+ long body_returned; /* elements of fill returned */
+
+
+ int *lacing_vals; /* The values that will go to the segment table */
+ ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
+ this way, but it is simple coupled to the
+ lacing fifo */
+ long lacing_storage;
+ long lacing_fill;
+ long lacing_packet;
+ long lacing_returned;
+
+ unsigned char header[282]; /* working space for header encode */
+ int header_fill;
+
+ int e_o_s; /* set when we have buffered the last packet in the
+ logical bitstream */
+ int b_o_s; /* set after we've written the initial page
+ of a logical bitstream */
+ long serialno;
+ long pageno;
+ ogg_int64_t packetno; /* sequence number for decode; the framing
+ knows where there's a hole in the data,
+ but we need coupling so that the codec
+ (which is in a seperate abstraction
+ layer) also knows about the gap */
+ ogg_int64_t granulepos;
+
+} ogg_stream_state;
+
+/* ogg_packet is used to encapsulate the data and metadata belonging
+ to a single raw Ogg/Vorbis packet *************************************/
+
+typedef struct {
+ unsigned char *packet;
+ long bytes;
+ long b_o_s;
+ long e_o_s;
+
+ ogg_int64_t granulepos;
+
+ ogg_int64_t packetno; /* sequence number for decode; the framing
+ knows where there's a hole in the data,
+ but we need coupling so that the codec
+ (which is in a seperate abstraction
+ layer) also knows about the gap */
+} ogg_packet;
+
+typedef struct {
+ unsigned char *data;
+ int storage;
+ int fill;
+ int returned;
+
+ int unsynced;
+ int headerbytes;
+ int bodybytes;
+} ogg_sync_state;
+
+/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
+
+extern void oggpack_writeinit(oggpack_buffer *b);
+extern void oggpack_writetrunc(oggpack_buffer *b,long bits);
+extern void oggpack_writealign(oggpack_buffer *b);
+extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
+extern void oggpack_reset(oggpack_buffer *b);
+extern void oggpack_writeclear(oggpack_buffer *b);
+extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
+extern long oggpack_look(oggpack_buffer *b,int bits);
+extern long oggpack_look1(oggpack_buffer *b);
+extern void oggpack_adv(oggpack_buffer *b,int bits);
+extern void oggpack_adv1(oggpack_buffer *b);
+extern long oggpack_read(oggpack_buffer *b,int bits);
+extern long oggpack_read1(oggpack_buffer *b);
+extern long oggpack_bytes(oggpack_buffer *b);
+extern long oggpack_bits(oggpack_buffer *b);
+extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);
+
+extern void oggpackB_writeinit(oggpack_buffer *b);
+extern void oggpackB_writetrunc(oggpack_buffer *b,long bits);
+extern void oggpackB_writealign(oggpack_buffer *b);
+extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);
+extern void oggpackB_reset(oggpack_buffer *b);
+extern void oggpackB_writeclear(oggpack_buffer *b);
+extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
+extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);
+extern long oggpackB_look(oggpack_buffer *b,int bits);
+extern long oggpackB_look1(oggpack_buffer *b);
+extern void oggpackB_adv(oggpack_buffer *b,int bits);
+extern void oggpackB_adv1(oggpack_buffer *b);
+extern long oggpackB_read(oggpack_buffer *b,int bits);
+extern long oggpackB_read1(oggpack_buffer *b);
+extern long oggpackB_bytes(oggpack_buffer *b);
+extern long oggpackB_bits(oggpack_buffer *b);
+extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);
+
+/* Ogg BITSTREAM PRIMITIVES: encoding **************************/
+
+extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
+extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
+extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
+
+/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
+
+extern int ogg_sync_init(ogg_sync_state *oy);
+extern int ogg_sync_clear(ogg_sync_state *oy);
+extern int ogg_sync_reset(ogg_sync_state *oy);
+extern int ogg_sync_destroy(ogg_sync_state *oy);
+
+extern char *ogg_sync_buffer(ogg_sync_state *oy, long size);
+extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
+extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
+extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
+extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
+extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
+extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
+
+/* Ogg BITSTREAM PRIMITIVES: general ***************************/
+
+extern int ogg_stream_init(ogg_stream_state *os,int serialno);
+extern int ogg_stream_clear(ogg_stream_state *os);
+extern int ogg_stream_reset(ogg_stream_state *os);
+extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
+extern int ogg_stream_destroy(ogg_stream_state *os);
+extern int ogg_stream_eos(ogg_stream_state *os);
+
+extern void ogg_page_checksum_set(ogg_page *og);
+
+extern int ogg_page_version(ogg_page *og);
+extern int ogg_page_continued(ogg_page *og);
+extern int ogg_page_bos(ogg_page *og);
+extern int ogg_page_eos(ogg_page *og);
+extern ogg_int64_t ogg_page_granulepos(ogg_page *og);
+extern int ogg_page_serialno(ogg_page *og);
+extern long ogg_page_pageno(ogg_page *og);
+extern int ogg_page_packets(ogg_page *og);
+
+extern void ogg_packet_clear(ogg_packet *op);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _OGG_H */
+
+
+
+
+
+
diff --git a/src/OGG/include/ogg/os_types.h b/src/OGG/include/ogg/os_types.h
new file mode 100644
index 0000000..32dcb8b
--- /dev/null
+++ b/src/OGG/include/ogg/os_types.h
@@ -0,0 +1,127 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
+ * by the Xiph.Org Foundation http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: #ifdef jail to whip a few platforms into the UNIX ideal.
+ last mod: $Id: os_types.h 7524 2004-08-11 04:20:36Z conrad $
+
+ ********************************************************************/
+#ifndef _OS_TYPES_H
+#define _OS_TYPES_H
+
+/* make it easy on the folks that want to compile the libs with a
+ different malloc than stdlib */
+#define _ogg_malloc malloc
+#define _ogg_calloc calloc
+#define _ogg_realloc realloc
+#define _ogg_free free
+
+#if defined(_WIN32)
+
+# if defined(__CYGWIN__)
+# include <_G_config.h>
+ typedef _G_int64_t ogg_int64_t;
+ typedef _G_int32_t ogg_int32_t;
+ typedef _G_uint32_t ogg_uint32_t;
+ typedef _G_int16_t ogg_int16_t;
+ typedef _G_uint16_t ogg_uint16_t;
+# elif defined(__MINGW32__)
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+ typedef unsigned long long ogg_uint64_t;
+# elif defined(__MWERKS__)
+ typedef long long ogg_int64_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+# else
+ /* MSVC/Borland */
+ typedef __int64 ogg_int64_t;
+ typedef __int32 ogg_int32_t;
+ typedef unsigned __int32 ogg_uint32_t;
+ typedef __int16 ogg_int16_t;
+ typedef unsigned __int16 ogg_uint16_t;
+# endif
+
+#elif defined(__MACOS__)
+
+# include <sys/types.h>
+ typedef SInt16 ogg_int16_t;
+ typedef UInt16 ogg_uint16_t;
+ typedef SInt32 ogg_int32_t;
+ typedef UInt32 ogg_uint32_t;
+ typedef SInt64 ogg_int64_t;
+
+#elif defined(__MACOSX__) /* MacOS X Framework build */
+
+# include <sys/types.h>
+ typedef int16_t ogg_int16_t;
+ typedef u_int16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
+ typedef u_int32_t ogg_uint32_t;
+ typedef int64_t ogg_int64_t;
+
+#elif defined(__BEOS__)
+
+ /* Be */
+# include <inttypes.h>
+ typedef int16_t ogg_int16_t;
+ typedef u_int16_t ogg_uint16_t;
+ typedef int32_t ogg_int32_t;
+ typedef u_int32_t ogg_uint32_t;
+ typedef int64_t ogg_int64_t;
+
+#elif defined (__EMX__)
+
+ /* OS/2 GCC */
+ typedef short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+
+#elif defined (DJGPP)
+
+ /* DJGPP */
+ typedef short ogg_int16_t;
+ typedef int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long ogg_int64_t;
+
+#elif defined(R5900)
+
+ /* PS2 EE */
+ typedef long ogg_int64_t;
+ typedef int ogg_int32_t;
+ typedef unsigned ogg_uint32_t;
+ typedef short ogg_int16_t;
+
+#elif defined(__SYMBIAN32__)
+
+ /* Symbian GCC */
+ typedef signed short ogg_int16_t;
+ typedef unsigned short ogg_uint16_t;
+ typedef signed int ogg_int32_t;
+ typedef unsigned int ogg_uint32_t;
+ typedef long long int ogg_int64_t;
+
+#else
+
+# include <sys/types.h>
+# include <ogg/config_types.h>
+
+#endif
+
+#endif /* _OS_TYPES_H */
diff --git a/src/aiff.c b/src/aiff.c
new file mode 100644
index 0000000..6348477
--- /dev/null
+++ b/src/aiff.c
@@ -0,0 +1,1522 @@
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+** Copyright (C) 2005 David Viens <davidv@plogue.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <ctype.h>
+
+#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 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 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'))
+
+/* 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
+{ unsigned int size ;
+ short numChannels ;
+ unsigned int numSampleFrames ;
+ short sampleSize ;
+ unsigned char sampleRate [10] ;
+ unsigned int encoding ;
+ char zero_bytes [2] ;
+} COMM_CHUNK ;
+
+typedef struct
+{ unsigned int offset ;
+ unsigned int blocksize ;
+} SSND_CHUNK ;
+
+typedef struct
+{ short playMode ;
+ unsigned short beginLoop ;
+ unsigned short endLoop ;
+} INST_LOOP ;
+
+typedef struct
+{ char baseNote ; /* all notes are MIDI note numbers */
+ char detune ; /* cents off, only -50 to +50 are significant */
+ char lowNote ;
+ char highNote ;
+ char lowVelocity ; /* 1 to 127 */
+ char highVelocity ; /* 1 to 127 */
+ short 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
+{ unsigned int version ;
+ unsigned int numBeats ;
+ unsigned short rootNote ;
+ unsigned short scaleType ;
+ unsigned short sigNumerator ;
+ unsigned short sigDenominator ;
+ unsigned short loopType ;
+} basc_CHUNK ;
+
+typedef struct
+{ unsigned short markerID ;
+ unsigned int position ;
+} MARK_ID_POS ;
+
+typedef struct
+{ sf_count_t comm_offset ;
+ sf_count_t ssnd_offset ;
+} AIFF_PRIVATE ;
+
+/*------------------------------------------------------------------------------
+ * Private static functions.
+ */
+
+static int aiff_close (SF_PRIVATE *psf) ;
+
+static int tenbytefloat2int (unsigned char *bytes) ;
+static void uint2tenbytefloat (unsigned int num, unsigned char *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 (short mode) ;
+
+static short get_loop_mode (short mode) ;
+
+static int aiff_read_basc_chunk (SF_PRIVATE * psf, int) ;
+
+static unsigned int marker_to_position (const MARK_ID_POS *m, unsigned short n, int marksize) ;
+
+/*------------------------------------------------------------------------------
+** Public function.
+*/
+
+int
+aiff_open (SF_PRIVATE *psf)
+{ COMM_CHUNK comm_fmt ;
+ int error, subformat ;
+
+ memset (&comm_fmt, 0, sizeof (comm_fmt)) ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if ((psf->container_data = calloc (1, sizeof (AIFF_PRIVATE))) == NULL)
+ return SFE_MALLOC_FAILED ;
+
+ if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = aiff_read_header (psf, &comm_fmt)))
+ return error ;
+
+ psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
+ } ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if (psf->is_pipe)
+ return SFE_NO_PIPE_WRITE ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_AIFF)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ if (psf->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->mode != SFM_RDWR || psf->filelength < 40)
+ { psf->filelength = 0 ;
+ psf->datalength = 0 ;
+ psf->dataoffset = 0 ;
+ psf->sf.frames = 0 ;
+ } ;
+
+ psf->str_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->container_close = aiff_close ;
+ psf->command = aiff_command ;
+
+ switch (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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 :
+ 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_DWVW_N :
+ if (psf->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) ;
+ 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) ;
+ break ;
+
+ default : return SFE_UNIMPLEMENTED ;
+ } ;
+
+
+ return error ;
+} /* aiff_open */
+
+/*==========================================================================================
+** Private functions.
+*/
+
+/* This function ought to check size */
+static unsigned int
+marker_to_position (const MARK_ID_POS *m, unsigned short 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 ;
+ MARK_ID_POS *markstr = NULL ;
+ AIFF_PRIVATE *paiff ;
+ unsigned marker, dword, FORMsize, SSNDsize, bytesread ;
+ int k, found_chunk = 0, done = 0, error = 0 ;
+ char *cptr, byte ;
+ int instr_found = 0, mark_found = 0, mark_count = 0 ;
+
+ if (psf->filelength > SF_PLATFORM_S64 (0xffffffff))
+ 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)
+ { psf_binheader_readf (psf, "m", &marker) ;
+
+ if (psf->mode == SFM_RDWR && (found_chunk & HAVE_SSND))
+ return SFE_AIFF_RW_SSND_NOT_LAST ;
+
+ switch (marker)
+ { case FORM_MARKER :
+ if (found_chunk)
+ return SFE_AIFF_NO_FORM ;
+
+ psf_binheader_readf (psf, "E4", &FORMsize) ;
+
+ if (psf->fileoffset > 0 && psf->filelength > FORMsize + 8)
+ { /* Set file length. */
+ psf->filelength = FORMsize + 8 ;
+ psf_log_printf (psf, "FORM : %u\n", FORMsize) ;
+ }
+ else if (FORMsize != psf->filelength - 2 * SIGNED_SIZEOF (dword))
+ { dword = psf->filelength - 2 * sizeof (dword) ;
+ psf_log_printf (psf, "FORM : %u (should be %u)\n", FORMsize, dword) ;
+ FORMsize = dword ;
+ }
+ else
+ psf_log_printf (psf, "FORM : %u\n", FORMsize) ;
+ found_chunk |= HAVE_FORM ;
+ break ;
+
+ case AIFC_MARKER :
+ case AIFF_MARKER :
+ if ((found_chunk & HAVE_FORM) == 0)
+ return SFE_AIFF_AIFF_NO_FORM ;
+ psf_log_printf (psf, " %M\n", marker) ;
+ found_chunk |= (marker == AIFC_MARKER) ? (HAVE_AIFC | HAVE_AIFF) : HAVE_AIFF ;
+ break ;
+
+ case COMM_MARKER :
+ paiff->comm_offset = psf_ftell (psf) - 4 ;
+ error = aiff_read_comm_chunk (psf, comm_fmt) ;
+
+ psf->sf.samplerate = tenbytefloat2int (comm_fmt->sampleRate) ;
+ psf->sf.frames = comm_fmt->numSampleFrames ;
+ psf->sf.channels = comm_fmt->numChannels ;
+ psf->bytewidth = BITWIDTH2BYTES (comm_fmt->sampleSize) ;
+
+ if (error)
+ 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_binheader_readf (psf, "E4", &dword) ;
+
+ psf_log_printf (psf, "%M : %d\n", marker, dword) ;
+ if (dword != AIFF_PEAK_CHUNK_SIZE (psf->sf.channels))
+ { psf_binheader_readf (psf, "j", dword) ;
+ psf_log_printf (psf, "*** File PEAK chunk too big.\n") ;
+ return SFE_WAV_BAD_PEAK ;
+ } ;
+
+ 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 = psf->u.cbuf ;
+ for (dword = 0 ; dword < (unsigned) psf->sf.channels ; dword++)
+ { float value ;
+ unsigned int position ;
+
+ psf_binheader_readf (psf, "Ef4", &value, &position) ;
+ psf->peak_info->peaks [dword].value = value ;
+ psf->peak_info->peaks [dword].position = position ;
+
+ LSF_SNPRINTF (cptr, sizeof (psf->u.scbuf), " %2d %-12ld %g\n",
+ dword, (long) psf->peak_info->peaks [dword].position, psf->peak_info->peaks [dword].value) ;
+ cptr [sizeof (psf->u.scbuf) - 1] = 0 ;
+ psf_log_printf (psf, cptr) ;
+ } ;
+
+ 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) - 4 ;
+ psf_binheader_readf (psf, "E444", &SSNDsize, &(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) ;
+
+ /* 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_log_printf (psf, " Offset : %u\n", ssnd_fmt.offset) ;
+ psf_log_printf (psf, " Block Size : %u\n", ssnd_fmt.blocksize) ;
+
+ found_chunk |= HAVE_SSND ;
+
+ if (! psf->sf.seekable)
+ break ;
+
+ /* Seek to end of SSND chunk. */
+ psf_fseek (psf, psf->dataoffset + psf->datalength + (SSNDsize & 1), SEEK_SET) ;
+ break ;
+
+ case c_MARKER :
+ psf_binheader_readf (psf, "E4", &dword) ;
+ if (dword == 0)
+ break ;
+ if (dword > SIGNED_SIZEOF (psf->u.scbuf) - 1)
+ { psf_log_printf (psf, " %M : %d (too big)\n", marker, dword) ;
+ return SFE_INTERNAL ;
+ } ;
+
+ cptr = psf->u.cbuf ;
+ psf_binheader_readf (psf, "b", cptr, dword + (dword & 1)) ;
+ cptr [dword] = 0 ;
+
+ psf_sanitize_string (cptr, dword) ;
+
+ psf_log_printf (psf, " %M : %s\n", marker, cptr) ;
+ psf_store_string (psf, SF_STR_COPYRIGHT, cptr) ;
+ break ;
+
+ case AUTH_MARKER :
+ psf_binheader_readf (psf, "E4", &dword) ;
+ if (dword == 0)
+ break ;
+ if (dword > SIGNED_SIZEOF (psf->u.scbuf) - 1)
+ { psf_log_printf (psf, " %M : %d (too big)\n", marker, dword) ;
+ return SFE_INTERNAL ;
+ } ;
+
+ cptr = psf->u.cbuf ;
+ psf_binheader_readf (psf, "b", cptr, dword + (dword & 1)) ;
+ cptr [dword] = 0 ;
+ psf_log_printf (psf, " %M : %s\n", marker, cptr) ;
+ psf_store_string (psf, SF_STR_ARTIST, cptr) ;
+ break ;
+
+ case COMT_MARKER :
+ { unsigned short count, id, len ;
+ unsigned int timestamp ;
+
+ psf_binheader_readf (psf, "E42", &dword, &count) ;
+ psf_log_printf (psf, " %M : %d\n count : %d\n", marker, dword, count) ;
+ dword += (dword & 1) ;
+ if (dword == 0)
+ break ;
+ dword -= 2 ;
+
+ for (k = 0 ; k < count ; k++)
+ { dword -= psf_binheader_readf (psf, "E422", &timestamp, &id, &len) ;
+ psf_log_printf (psf, " time : 0x%x\n marker : %x\n length : %d\n", timestamp, id, len) ;
+
+ if (len + 1 > SIGNED_SIZEOF (psf->u.scbuf))
+ { psf_log_printf (psf, "\nError : string length (%d) too big.\n", len) ;
+ return SFE_INTERNAL ;
+ } ;
+
+ cptr = psf->u.cbuf ;
+ dword -= psf_binheader_readf (psf, "b", cptr, len) ;
+ cptr [len] = 0 ;
+ psf_log_printf (psf, " string : %s\n", cptr) ;
+ } ;
+
+ if (dword > 0)
+ psf_binheader_readf (psf, "j", dword) ;
+ } ;
+ break ;
+
+ case APPL_MARKER :
+ psf_binheader_readf (psf, "E4", &dword) ;
+ if (dword == 0)
+ break ;
+ if (dword >= SIGNED_SIZEOF (psf->u.scbuf) - 1)
+ { psf_log_printf (psf, " %M : %d (too big, skipping)\n", marker, dword) ;
+ psf_binheader_readf (psf, "j", dword + (dword & 1)) ;
+ break ;
+ } ;
+
+ cptr = psf->u.cbuf ;
+ psf_binheader_readf (psf, "b", cptr, dword + (dword & 1)) ;
+ cptr [dword] = 0 ;
+
+ for (k = 0 ; k < (int) dword ; k++)
+ if (! isprint (cptr [k]))
+ { cptr [k] = 0 ;
+ break ;
+ } ;
+
+ psf_log_printf (psf, " %M : %s\n", marker, cptr) ;
+ psf_store_string (psf, SF_STR_SOFTWARE, cptr) ;
+ break ;
+
+ case NAME_MARKER :
+ psf_binheader_readf (psf, "E4", &dword) ;
+ if (dword == 0)
+ break ;
+ if (dword > SIGNED_SIZEOF (psf->u.scbuf) - 2)
+ { psf_log_printf (psf, " %M : %d (too big)\n", marker, dword) ;
+ return SFE_INTERNAL ;
+ } ;
+
+ cptr = psf->u.cbuf ;
+ psf_binheader_readf (psf, "b", cptr, dword + (dword & 1)) ;
+ cptr [dword] = 0 ;
+ psf_log_printf (psf, " %M : %s\n", marker, cptr) ;
+ psf_store_string (psf, SF_STR_TITLE, cptr) ;
+ break ;
+
+ case ANNO_MARKER :
+ psf_binheader_readf (psf, "E4", &dword) ;
+ if (dword == 0)
+ break ;
+ if (dword > SIGNED_SIZEOF (psf->u.scbuf) - 2)
+ { psf_log_printf (psf, " %M : %d (too big)\n", marker, dword) ;
+ return SFE_INTERNAL ;
+ } ;
+
+ cptr = psf->u.cbuf ;
+ psf_binheader_readf (psf, "b", cptr, dword + (dword & 1)) ;
+ cptr [dword] = 0 ;
+ psf_log_printf (psf, " %M : %s\n", marker, cptr) ;
+ psf_store_string (psf, SF_STR_COMMENT, cptr) ;
+ break ;
+
+ case INST_MARKER :
+ psf_binheader_readf (psf, "E4", &dword) ;
+ if (dword != SIZEOF_INST_CHUNK)
+ { psf_log_printf (psf, " %M : %d (should be %d)\n", marker, dword, SIZEOF_INST_CHUNK) ;
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+ } ;
+ psf_log_printf (psf, " %M : %d\n", marker, dword) ;
+ { unsigned char bytes [6] ;
+ short 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) ;
+ } ;
+ { short mode ; /* 0 - no loop, 1 - forward looping, 2 - backward looping */
+ const char *loop_mode ;
+ unsigned short 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 [0].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_binheader_readf (psf, "E4", &dword) ;
+ psf_log_printf (psf, " basc : %u\n", dword) ;
+
+ if ((error = aiff_read_basc_chunk (psf, dword)))
+ return error ;
+ break ;
+
+ case MARK_MARKER :
+ psf_binheader_readf (psf, "E4", &dword) ;
+ psf_log_printf (psf, " %M : %d\n", marker, dword) ;
+ { unsigned short mark_id, n = 0 ;
+ unsigned char pstr_len ;
+ unsigned int position ;
+
+ bytesread = psf_binheader_readf (psf, "E2", &n) ;
+ mark_count = n ;
+ markstr = calloc (mark_count, sizeof (MARK_ID_POS)) ;
+ psf_log_printf (psf, " Count : %d\n", mark_count) ;
+
+ for (n = 0 ; n < mark_count && bytesread < dword ; n++)
+ { bytesread += psf_binheader_readf (psf, "E241", &mark_id, &position, &pstr_len) ;
+ psf_log_printf (psf, " Mark ID : %u\n Position : %u\n", mark_id, position) ;
+
+ pstr_len += (pstr_len & 1) ? 0 : 1 ;
+
+ bytesread += psf_binheader_readf (psf, "b", psf->u.scbuf, pstr_len) ;
+ psf->u.scbuf [pstr_len] = 0 ;
+ psf_log_printf (psf, " Name : %s\n", psf->u.scbuf) ;
+
+ markstr [n].markerID = mark_id ;
+ markstr [n].position = position ;
+ /*
+ ** TODO if psf->u.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", dword - bytesread) ;
+ break ;
+
+ case FVER_MARKER :
+ found_chunk |= HAVE_FVER ;
+ /* Fall through to next case. */
+
+ case SFX_MARKER :
+ psf_binheader_readf (psf, "E4", &dword) ;
+ psf_log_printf (psf, " %M : %d\n", marker, dword) ;
+
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+
+ case NONE_MARKER :
+ /* Fix for broken AIFC files with incorrect COMM chunk length. */
+ psf_binheader_readf (psf, "1", &byte) ;
+ dword = byte ;
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+
+ default :
+ if (isprint ((marker >> 24) & 0xFF) && isprint ((marker >> 16) & 0xFF)
+ && isprint ((marker >> 8) & 0xFF) && isprint (marker & 0xFF))
+ { psf_binheader_readf (psf, "E4", &dword) ;
+ psf_log_printf (psf, " %M : %d (unknown marker)\n", marker, dword) ;
+
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+ } ;
+ if ((dword = psf_ftell (psf)) & 0x03)
+ { psf_log_printf (psf, " Unknown chunk marker %X at position %d. Resyncing.\n", marker, dword - 4) ;
+
+ 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 = 1 ;
+ break ;
+ } ; /* switch (marker) */
+
+ if ((! psf->sf.seekable) && (found_chunk & HAVE_SSND))
+ break ;
+
+ if (psf_ftell (psf) >= psf->filelength - (2 * SIGNED_SIZEOF (dword)))
+ break ;
+ } ; /* while (1) */
+
+ if (instr_found && mark_found)
+ { int j ;
+
+ for (j = 0 ; j<psf->instrument->loop_count ; j ++)
+ { if (j < ARRAY_LEN (psf->instrument->loops))
+ { psf->instrument->loops [j].start = marker_to_position (markstr, psf->instrument->loops [j].start, mark_count) ;
+ psf->instrument->loops [j].end = marker_to_position (markstr, psf->instrument->loops [j].end, mark_count) ;
+ psf->instrument->loops [j].mode = SF_LOOP_FORWARD ;
+ } ;
+ } ;
+ } ;
+
+ if (markstr)
+ free (markstr) ;
+
+ 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)
+{
+ if (psf->mode == SFM_WRITE || psf->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)
+{ int error = 0, bytesread, subformat ;
+
+ psf->u.scbuf [0] = 0 ;
+
+ bytesread = psf_binheader_readf (psf, "E4", &(comm_fmt->size)) ;
+
+ /* The COMM chunk has an int aligned to an odd word boundary. Some
+ ** procesors are not able to deal with this (ie bus fault) so we have
+ ** to take special care.
+ */
+ comm_fmt->size += comm_fmt->size & 1 ;
+
+ bytesread +=
+ 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 == SIZEOF_AIFF_COMM)
+ comm_fmt->encoding = NONE_MARKER ;
+ else if (comm_fmt->size == SIZEOF_AIFC_COMM_MIN)
+ bytesread += psf_binheader_readf (psf, "Em", &(comm_fmt->encoding)) ;
+ else if (comm_fmt->size >= SIZEOF_AIFC_COMM)
+ { unsigned char encoding_len ;
+
+ bytesread += psf_binheader_readf (psf, "Em1", &(comm_fmt->encoding), &encoding_len) ;
+
+ memset (psf->u.scbuf, 0, comm_fmt->size) ;
+
+ bytesread += psf_binheader_readf (psf, "b", psf->u.scbuf,
+ comm_fmt->size - SIZEOF_AIFC_COMM + 1) ;
+ psf->u.scbuf [encoding_len] = 0 ;
+ } ;
+
+ psf_log_printf (psf, " COMM : %d\n", comm_fmt->size) ;
+ psf_log_printf (psf, " Sample Rate : %d\n", tenbytefloat2int (comm_fmt->sampleRate)) ;
+ psf_log_printf (psf, " Frames : %u%s\n", comm_fmt->numSampleFrames, (comm_fmt->numSampleFrames == 0 && psf->filelength > 104) ? " (Should not be 0)" : "") ;
+ 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) ;
+
+ subformat = s_bitwidth_to_subformat (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 ;
+ 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) ;
+ error = SFE_UNIMPLEMENTED ;
+ } ;
+
+ if (! psf->u.scbuf [0])
+ psf_log_printf (psf, " Encoding : %M\n", comm_fmt->encoding) ;
+ else
+ psf_log_printf (psf, " Encoding : %M => %s\n", comm_fmt->encoding, psf->u.scbuf) ;
+
+ return error ;
+} /* aiff_read_comm_chunk */
+
+
+static int
+aiff_write_header (SF_PRIVATE *psf, int calc_length)
+{ sf_count_t current ;
+ AIFF_PRIVATE *paiff ;
+ unsigned char comm_sample_rate [10], comm_zero_bytes [2] = { 0, 0 } ;
+ unsigned int comm_type, comm_size, comm_encoding, comm_frames ;
+ int k, endian ;
+ short bit_width ;
+
+ if ((paiff = psf->container_data) == NULL)
+ return SFE_INTERNAL ;
+
+ 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->mode == SFM_RDWR && psf->dataoffset > 0)
+ { /* 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.
+ */
+
+ /* First write new FORM chunk. */
+ psf->headindex = 0 ;
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ psf_binheader_writef (psf, "Etm8", FORM_MARKER, psf->filelength - 8) ;
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ /* Now write frame count field of COMM chunk header. */
+ psf->headindex = 0 ;
+ psf_fseek (psf, paiff->comm_offset + 10, SEEK_SET) ;
+
+ psf_binheader_writef (psf, "Et8", psf->sf.frames) ;
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ /* Now write new SSND chunk header. */
+ psf->headindex = 0 ;
+ psf_fseek (psf, paiff->ssnd_offset, SEEK_SET) ;
+
+ psf_binheader_writef (psf, "Etm8", SSND_MARKER, psf->datalength + SIZEOF_SSND_CHUNK) ;
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (current < psf->dataoffset)
+ psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
+ else if (current > 0)
+ psf_fseek (psf, current, SEEK_SET) ;
+
+ return 0 ;
+ } ;
+
+ endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+ 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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { case SF_FORMAT_PCM_S8 :
+ case SF_FORMAT_PCM_16 :
+ case SF_FORMAT_PCM_24 :
+ case SF_FORMAT_PCM_32 :
+ switch (endian)
+ { case SF_ENDIAN_BIG :
+ psf->endian = SF_ENDIAN_BIG ;
+ comm_type = AIFC_MARKER ;
+ comm_size = SIZEOF_AIFC_COMM ;
+ comm_encoding = twos_MARKER ;
+ break ;
+
+ case SF_ENDIAN_LITTLE :
+ psf->endian = SF_ENDIAN_LITTLE ;
+ comm_type = AIFC_MARKER ;
+ comm_size = SIZEOF_AIFC_COMM ;
+ comm_encoding = sowt_MARKER ;
+ break ;
+
+ default : /* SF_ENDIAN_FILE */
+ psf->endian = SF_ENDIAN_BIG ;
+ comm_type = AIFF_MARKER ;
+ comm_size = SIZEOF_AIFF_COMM ;
+ comm_encoding = 0 ;
+ break ;
+ } ;
+ 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 [0] = 0 ;
+ psf->headindex = 0 ;
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ psf_binheader_writef (psf, "Etm8", FORM_MARKER, 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, "Emm44m4", comm_type, FVER_MARKER, 4, 0xA2805140, COMM_MARKER, comm_size) ;
+ else
+ psf_binheader_writef (psf, "Emm4", comm_type, COMM_MARKER, comm_size) ;
+
+ paiff->comm_offset = psf->headindex - 8 ;
+
+ memset (comm_sample_rate, 0, sizeof (comm_sample_rate)) ;
+ uint2tenbytefloat (psf->sf.samplerate, comm_sample_rate) ;
+
+ psf_binheader_writef (psf, "Et242", psf->sf.channels, comm_frames, bit_width) ;
+ psf_binheader_writef (psf, "b", comm_sample_rate, sizeof (comm_sample_rate)) ;
+
+ /* AIFC chunks have some extra data. */
+ if (comm_type == AIFC_MARKER)
+ psf_binheader_writef (psf, "mb", comm_encoding, comm_zero_bytes, sizeof (comm_zero_bytes)) ;
+
+ if (psf->instrument != NULL)
+ { MARK_ID_POS m [4] ;
+ INST_CHUNK ch ;
+ unsigned short ct = 0 ;
+
+ memset (m, 0, sizeof (m)) ;
+ memset (&ch, 0, sizeof (ch)) ;
+
+ ch.baseNote = psf->instrument->basenote ;
+ ch.detune = psf->instrument->detune ;
+ ch.lowNote = psf->instrument->key_lo ;
+ ch.highNote = psf->instrument->key_hi ;
+ ch.lowVelocity = psf->instrument->velocity_lo ;
+ ch.highVelocity = psf->instrument->velocity_hi ;
+ ch.gain = psf->instrument->gain ;
+ if (psf->instrument->loops [0].mode != SF_LOOP_NONE)
+ { ch.sustain_loop.playMode = 1 ;
+ ch.sustain_loop.beginLoop = ct ;
+ m [0].markerID = ct++ ;
+ m [0].position = psf->instrument->loops [0].start ;
+ ch.sustain_loop.endLoop = ct ;
+ m [1].markerID = ct++ ;
+ m [1].position = psf->instrument->loops [0].end ;
+ } ;
+ if (psf->instrument->loops [1].mode != SF_LOOP_NONE)
+ { ch.release_loop.playMode = 1 ;
+ ch.release_loop.beginLoop = ct ;
+ m [2].markerID = ct++ ;
+ m [2].position = psf->instrument->loops [1].start ;
+ ch.release_loop.endLoop = ct ;
+ m [3].markerID = ct++ ;
+ m [3].position = psf->instrument->loops [1].end ;
+ }
+ else
+ { ch.release_loop.playMode = 0 ;
+ ch.release_loop.beginLoop = 0 ;
+ ch.release_loop.endLoop = 0 ;
+ } ;
+
+ psf_binheader_writef (psf, "Em4111111", INST_MARKER, SIZEOF_INST_CHUNK, ch.baseNote, ch.detune,
+ ch.lowNote, ch.highNote, ch.lowVelocity, ch.highVelocity) ;
+ psf_binheader_writef (psf, "2222222", ch.gain, ch.sustain_loop.playMode,
+ ch.sustain_loop.beginLoop, ch.sustain_loop.endLoop, ch.release_loop.playMode,
+ ch.release_loop.beginLoop, ch.release_loop.endLoop) ;
+
+ if (ct == 2)
+ psf_binheader_writef (psf, "Em42241b241b",
+ MARK_MARKER, 2 + 2 * (2 + 4 + 1 + 9), 2,
+ m [0].markerID, m [0].position, 8, "beg loop", make_size_t (9),
+ m [1].markerID, m [1].position, 8, "end loop", make_size_t (9)) ;
+ else if (ct == 4)
+ psf_binheader_writef (psf, "Em42 241b 241b 241b 241b",
+ MARK_MARKER, 2 + 4 * (2 + 4 + 1 + 9), 4,
+ m [0].markerID, m [0].position, 8, "beg loop", make_size_t (9),
+ m [1].markerID, m [1].position, 8, "end loop", make_size_t (9),
+ m [2].markerID, m [2].position, 8, "beg loop", make_size_t (9),
+ m [3].markerID, m [3].position, 8, "end loop", make_size_t (9)) ;
+ } ;
+
+ if (psf->str_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", PEAK_MARKER, AIFF_PEAK_CHUNK_SIZE (psf->sf.channels)) ;
+ psf_binheader_writef (psf, "E44", 1, time (NULL)) ;
+ for (k = 0 ; k < psf->sf.channels ; k++)
+ psf_binheader_writef (psf, "Eft8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ;
+ } ;
+
+ /* Write SSND chunk. */
+ paiff->ssnd_offset = psf->headindex ;
+ psf_binheader_writef (psf, "Etm844", SSND_MARKER, psf->datalength + SIZEOF_SSND_CHUNK, 0, 0) ;
+
+ /* Header construction complete so write it out. */
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ if (current < psf->dataoffset)
+ 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 [0] = 0 ;
+ psf->headindex = 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, 1, 1, psf) ;
+ psf->dataend ++ ;
+ } ;
+
+ if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_END)
+ { psf_binheader_writef (psf, "Em4", PEAK_MARKER, AIFF_PEAK_CHUNK_SIZE (psf->sf.channels)) ;
+ psf_binheader_writef (psf, "E44", 1, time (NULL)) ;
+ for (k = 0 ; k < psf->sf.channels ; k++)
+ psf_binheader_writef (psf, "Eft8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ;
+ } ;
+
+ if (psf->str_flags & SF_STR_LOCATE_END)
+ aiff_write_strings (psf, SF_STR_LOCATE_END) ;
+
+ /* Write the tailer. */
+ if (psf->headindex > 0)
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ return 0 ;
+} /* aiff_write_tailer */
+
+static void
+aiff_write_strings (SF_PRIVATE *psf, int location)
+{ int k ;
+
+ for (k = 0 ; k < SF_MAX_STRINGS ; k++)
+ { if (psf->strings [k].type == 0)
+ break ;
+
+ if (psf->strings [k].flags != location)
+ continue ;
+
+ switch (psf->strings [k].type)
+ { case SF_STR_SOFTWARE :
+ psf_binheader_writef (psf, "EmS", APPL_MARKER, psf->strings [k].str) ;
+ break ;
+
+ case SF_STR_TITLE :
+ psf_binheader_writef (psf, "EmS", NAME_MARKER, psf->strings [k].str) ;
+ break ;
+
+ case SF_STR_COPYRIGHT :
+ psf_binheader_writef (psf, "EmS", c_MARKER, psf->strings [k].str) ;
+ break ;
+
+ case SF_STR_ARTIST :
+ psf_binheader_writef (psf, "EmS", AUTH_MARKER, psf->strings [k].str) ;
+ break ;
+
+ case SF_STR_COMMENT :
+ psf_binheader_writef (psf, "EmS", ANNO_MARKER, psf->strings [k].str) ;
+ break ;
+
+ /*
+ case SF_STR_DATE :
+ psf_binheader_writef (psf, "Ems", ICRD_MARKER, psf->strings [k].str) ;
+ break ;
+ */
+ } ;
+ } ;
+
+ return ;
+} /* aiff_write_strings */
+
+static int
+aiff_command (SF_PRIVATE * UNUSED (psf), int UNUSED (command), void * UNUSED (data), int UNUSED (datasize))
+{
+ return 0 ;
+} /* aiff_command */
+
+static const char*
+get_loop_mode_str (short mode)
+{ switch (mode)
+ { case 0 : return "none" ;
+ case 1 : return "forward" ;
+ case 2 : return "backward" ;
+ } ;
+
+ return "*** unknown" ;
+} /* get_loop_mode_str */
+
+static short
+get_loop_mode (short 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 (unsigned char *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 (unsigned int num, unsigned char *bytes)
+{ unsigned int 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 + 1 ;
+ 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 = 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 7dec56ca-d6f2-48cf-863b-a72e7e17a5d9
+*/
diff --git a/src/alaw.c b/src/alaw.c
new file mode 100644
index 0000000..a2d27cb
--- /dev/null
+++ b/src/alaw.c
@@ -0,0 +1,544 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 "sndfile.h"
+#include "float_cast.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->mode == SFM_READ || psf->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->mode == SFM_WRITE || psf->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->datalength / psf->blockwidth ;
+
+ 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, 0x2a
+} ; /* alaw_encode */
+
+static inline void
+alaw2s_array (unsigned char *buffer, int count, short *ptr)
+{ while (--count >= 0)
+ ptr [count] = alaw_decode [(int) buffer [count]] ;
+} /* alaw2s_array */
+
+static inline void
+alaw2i_array (unsigned char *buffer, int count, int *ptr)
+{ while (--count >= 0)
+ ptr [count] = alaw_decode [(int) buffer [count]] << 16 ;
+} /* alaw2i_array */
+
+static inline void
+alaw2f_array (unsigned char *buffer, int count, float *ptr, float normfact)
+{ while (--count >= 0)
+ ptr [count] = normfact * alaw_decode [(int) buffer [count]] ;
+} /* alaw2f_array */
+
+static inline void
+alaw2d_array (unsigned char *buffer, int count, double *ptr, double normfact)
+{ while (--count >= 0)
+ ptr [count] = normfact * alaw_decode [(int) buffer [count]] ;
+} /* alaw2d_array */
+
+static inline void
+s2alaw_array (const short *ptr, int count, unsigned char *buffer)
+{ while (--count >= 0)
+ { if (ptr [count] >= 0)
+ buffer [count] = alaw_encode [ptr [count] / 16] ;
+ else
+ buffer [count] = 0x7F & alaw_encode [ptr [count] / -16] ;
+ } ;
+} /* s2alaw_array */
+
+static inline void
+i2alaw_array (const int *ptr, int count, unsigned char *buffer)
+{ while (--count >= 0)
+ { if (ptr [count] >= 0)
+ buffer [count] = alaw_encode [ptr [count] >> (16 + 4)] ;
+ else
+ buffer [count] = 0x7F & alaw_encode [- ptr [count] >> (16 + 4)] ;
+ } ;
+} /* i2alaw_array */
+
+static inline void
+f2alaw_array (const float *ptr, int count, unsigned char *buffer, float normfact)
+{ while (--count >= 0)
+ { if (ptr [count] >= 0)
+ buffer [count] = alaw_encode [lrintf (normfact * ptr [count])] ;
+ else
+ buffer [count] = 0x7F & alaw_encode [- lrintf (normfact * ptr [count])] ;
+ } ;
+} /* f2alaw_array */
+
+static inline void
+d2alaw_array (const double *ptr, int count, unsigned char *buffer, double normfact)
+{ while (--count >= 0)
+ { if (ptr [count] >= 0)
+ buffer [count] = alaw_encode [lrint (normfact * ptr [count])] ;
+ else
+ buffer [count] = 0x7F & alaw_encode [- lrint (normfact * ptr [count])] ;
+ } ;
+} /* d2alaw_array */
+
+/*==============================================================================
+*/
+
+static sf_count_t
+alaw_read_alaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
+ alaw2s_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
+ alaw2i_array (psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
+ alaw2f_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+ double normfact ;
+
+ normfact = (psf->norm_double) ? 1.0 / ((double) 0x8000) : 1.0 ;
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
+ alaw2d_array (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2alaw_array (ptr + total, bufferlen, psf->u.ucbuf) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2alaw_array (ptr + total, bufferlen, psf->u.ucbuf) ;
+ writecount = psf_fwrite (psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ f2alaw_array (ptr + total, bufferlen, psf->u.ucbuf, normfact) ;
+ writecount = psf_fwrite (psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ d2alaw_array (ptr + total, bufferlen, psf->u.ucbuf, normfact) ;
+ writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ;
+ total += writecount ;
+ if (writecount < bufferlen)
+ break ;
+ len -= writecount ;
+ } ;
+
+ return total ;
+} /* alaw_write_d2alaw */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 289ccfc2-42a6-4f1f-a29f-4dcc9bfa8752
+*/
diff --git a/src/au.c b/src/au.c
new file mode 100644
index 0000000..3a5f93b
--- /dev/null
+++ b/src/au.c
@@ -0,0 +1,453 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = au_read_header (psf)))
+ return error ;
+ } ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_AU)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+ 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->mode == SFM_WRITE || psf->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 ;
+
+ psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
+ } ;
+
+ encoding = au_format_to_encoding (psf->sf.format & SF_FORMAT_SUBMASK) ;
+ if (! encoding)
+ return (psf->error = SFE_BAD_OPEN_FORMAT) ;
+
+ /* Reset the current header length to zero. */
+ psf->header [0] = 0 ;
+ psf->headindex = 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", DOTSND_MARKER, AU_DATA_OFFSET) ;
+ psf_binheader_writef (psf, "E4444", datalength, encoding, psf->sf.samplerate, psf->sf.channels) ;
+ }
+ else if (psf->endian == SF_ENDIAN_LITTLE)
+ { psf_binheader_writef (psf, "em4", DNSDOT_MARKER, AU_DATA_OFFSET) ;
+ psf_binheader_writef (psf, "e4444", datalength, encoding, psf->sf.samplerate, psf->sf.channels) ;
+ }
+ else
+ return (psf->error = SFE_BAD_OPEN_FORMAT) ;
+
+ /* Header construction complete so write it out. */
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ 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 = psf->sf.format & SF_FORMAT_ENDMASK ;
+
+ 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) ;
+ 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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 31f691b1-cde9-4ed2-9469-6bca60fb9cd0
+*/
diff --git a/src/audio_detect.c b/src/audio_detect.c
new file mode 100644
index 0000000..5a1e436
--- /dev/null
+++ b/src/audio_detect.c
@@ -0,0 +1,106 @@
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include "common.h"
+#include "sfendian.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->logbuffer) ;
+
+ 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/src/avr.c b/src/avr.c
new file mode 100644
index 0000000..ad02c04
--- /dev/null
+++ b/src/avr.c
@@ -0,0 +1,254 @@
+/*
+** Copyright (C) 2004-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <string.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+
+#define TWOBIT_MARKER (MAKE_MARKER ('2', 'B', 'I', 'T'))
+#define AVR_HDR_SIZE 128
+
+#define SFE_AVR_X 666
+
+/*
+** 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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = avr_read_header (psf)))
+ return error ;
+ } ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_AVR)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+ 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_X ;
+
+ 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 ((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_X ;
+ } ;
+
+ 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 [0] = 0 ;
+ psf->headindex = 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", TWOBIT_MARKER, make_size_t (8),
+ psf->sf.channels == 2 ? 0xFFFF : 0, psf->bytewidth * 8) ;
+
+ sign = ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_U8) ? 0 : 0xFFFF ;
+
+ psf_binheader_writef (psf, "E222", sign, 0, 0xFFFF) ;
+ psf_binheader_writef (psf, "E4444", psf->sf.samplerate, psf->sf.frames, 0, 0) ;
+
+ psf_binheader_writef (psf, "E222zz", 0, 0, 0, make_size_t (20), make_size_t (64)) ;
+
+ /* Header construction complete so write it out. */
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ if (current > 0)
+ psf_fseek (psf, current, SEEK_SET) ;
+
+ return psf->error ;
+} /* avr_write_header */
+
+static int
+avr_close (SF_PRIVATE *psf)
+{
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ avr_write_header (psf, SF_TRUE) ;
+
+ return 0 ;
+} /* avr_close */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 0823d454-f39a-4a28-a776-607f1ef33b52
+*/
diff --git a/src/binheader_writef_check.py b/src/binheader_writef_check.py
new file mode 100755
index 0000000..422d285
--- /dev/null
+++ b/src/binheader_writef_check.py
@@ -0,0 +1,114 @@
+#!/usr/bin/python2.4
+
+# Copyright (C) 2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+#
+# 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, 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 = string.split (dlist, ",")
+ dlist = [string.strip (x) for x in dlist]
+ return dlist [2:]
+
+def handle_file (fname):
+ errors = 0
+ data = open (fname, "r").read ()
+
+ 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
+
+ # print " param [%d] %c : %s" % (param_index, ch, params [param_index])
+
+ if ch != 'b':
+ param_index += 1
+ continue
+
+ # print item
+ # print " param [%d] %c : %s <-> %s" % (param_index, ch, params [param_index], params [param_index + 1])
+
+ if string.find (params [param_index + 1], "sizeof") < 0 \
+ and string.find (params [param_index + 1], "make_size_t") < 0 \
+ and string.find (params [param_index + 1], "strlen") < 0:
+ if errors == 0: print
+ print "\n%s :" % fname
+ print " param [%d] %c : %s <-> %s" % (param_index, ch, params [param_index], params [param_index + 1])
+ print " %s" % item
+ errors += 1
+ param_index += 2
+
+ return errors
+
+#===============================================================================
+
+if len (sys.argv) > 1:
+ print "%s\n binheader_writef_check :" % sys.argv [0],
+ 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"
+
+# Do not edit or modify anything in this comment block.
+# The following line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: 4ed34789-925a-4135-af90-2e51523ca1ce
diff --git a/src/broadcast.c b/src/broadcast.c
new file mode 100644
index 0000000..e332277
--- /dev/null
+++ b/src/broadcast.c
@@ -0,0 +1,89 @@
+/*
+** Copyright (C) 2006 Paul Davis <paul@linuxaudiosystems.com>
+** Copyright (C) 2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <string.h>
+
+#include "common.h"
+
+/*
+** Allocate and initialize a broadcast info structure.
+*/
+
+SF_BROADCAST_INFO*
+broadcast_info_alloc (void)
+{ SF_BROADCAST_INFO* bext ;
+
+ if ((bext = calloc (1, sizeof (SF_BROADCAST_INFO))) == NULL)
+ return NULL ;
+
+ return bext ;
+} /* broadcast_info_alloc */
+
+int
+broadcast_info_copy (SF_BROADCAST_INFO* dst, SF_BROADCAST_INFO* src)
+{ memcpy (dst, src, sizeof (SF_BROADCAST_INFO)) ;
+
+ /* Currently writing this version. */
+ dst->version = 1 ;
+
+ return SF_TRUE ;
+} /* broadcast_info_copy */
+
+int
+broadcast_add_coding_history (SF_BROADCAST_INFO* bext, unsigned int channels, unsigned int samplerate)
+{ char chnstr [16] ;
+ int count ;
+
+ switch (channels)
+ { case 0 :
+ return SF_FALSE ;
+
+ case 1 :
+ strncpy (chnstr, "mono", sizeof (chnstr)) ;
+ break ;
+
+ case 2 :
+ strncpy (chnstr, "stereo", sizeof (chnstr)) ;
+ break ;
+
+ default :
+ LSF_SNPRINTF (chnstr, sizeof (chnstr), "%uchn", channels) ;
+ break ;
+ }
+
+ count = LSF_SNPRINTF (bext->coding_history, sizeof (bext->coding_history), "F=%u,A=PCM,M=%s,W=24,T=%s-%s", samplerate, chnstr, PACKAGE, VERSION) ;
+
+ if (count >= SIGNED_SIZEOF (bext->coding_history))
+ bext->coding_history_size = sizeof (bext->coding_history) ;
+ else
+ { count += count & 1 ;
+ bext->coding_history_size = count ;
+ } ;
+
+ return SF_TRUE ;
+} /* broadcast_add_coding_history */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The following line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 4b3b69c7-d710-4424-9da0-5048534a0beb
+*/
diff --git a/src/caf.c b/src/caf.c
new file mode 100644
index 0000000..7a1e5c9
--- /dev/null
+++ b/src/caf.c
@@ -0,0 +1,538 @@
+/*
+** Copyright (C) 2005, 2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "float_cast.h"
+#include "common.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)))
+
+#define SFE_CAF_NOT_CAF 666
+#define SFE_CAF_NO_DESC 667
+#define SFE_CAF_BAD_PEAK 668
+
+/*------------------------------------------------------------------------------
+** Typedefs.
+*/
+
+typedef struct
+{ unsigned char srate [8] ;
+ unsigned int fmt_id ;
+ unsigned int fmt_flags ;
+ unsigned int pkt_bytes ;
+ unsigned int pkt_frames ;
+ unsigned int channels_per_frame ;
+ unsigned int bits_per_chan ;
+} DESC_CHUNK ;
+
+/*------------------------------------------------------------------------------
+** 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) ;
+
+/*------------------------------------------------------------------------------
+** Public function.
+*/
+
+int
+caf_open (SF_PRIVATE *psf)
+{ int subformat, format, error = 0 ;
+
+ if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = caf_read_header (psf)))
+ return error ;
+ } ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if (psf->is_pipe)
+ return SFE_NO_PIPE_WRITE ;
+
+ format = psf->sf.format & SF_FORMAT_TYPEMASK ;
+ if (format != SF_FORMAT_CAF)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ psf->blockwidth = psf->bytewidth * psf->sf.channels ;
+
+ if (psf->mode != SFM_RDWR || psf->filelength < 44)
+ { psf->filelength = 0 ;
+ psf->datalength = 0 ;
+ psf->dataoffset = 0 ;
+ psf->sf.frames = 0 ;
+ } ;
+
+ psf->str_flags = SF_STR_ALLOW_START ;
+
+ /*
+ ** 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->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->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 ;
+ /* Lite remove end */
+
+ default :
+ return SFE_UNSUPPORTED_ENCODING ;
+ } ;
+
+ return error ;
+} /* caf_open */
+
+static int
+caf_close (SF_PRIVATE *psf)
+{
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ caf_write_header (psf, SF_TRUE) ;
+
+ return 0 ;
+} /* caf_close */
+
+/*------------------------------------------------------------------------------
+*/
+
+static int
+decode_desc_chunk (SF_PRIVATE *psf, const DESC_CHUNK *desc)
+{ int format ;
+
+ psf->sf.channels = desc->channels_per_frame ;
+
+ format = SF_FORMAT_CAF | (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_flags & 1) != 0)
+ { psf_log_printf (psf, "**** Ooops, 'desc' chunk suggests float data, but other info invalid.\n") ;
+ return 0 ;
+ } ;
+
+ if (desc->fmt_id == lpcm_MARKER)
+ { /* 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 ;
+ } ;
+
+ return 0 ;
+} /* decode_desc_chunk */
+
+static int
+caf_read_header (SF_PRIVATE *psf)
+{ DESC_CHUNK desc ;
+ sf_count_t chunk_size ;
+ double srate ;
+ short version, flags ;
+ int marker, k, have_data = 0 ;
+
+ 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, psf->u.ucbuf, 8) ;
+ srate = double64_be_read (psf->u.ucbuf) ;
+ LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%5.3f", srate) ;
+ psf_log_printf (psf, "%M : %D\n Sample rate : %s\n", marker, chunk_size, psf->u.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 = lrint (srate) ;
+
+ psf_binheader_readf (psf, "mE44444", &desc.fmt_id, &desc.fmt_flags, &desc.pkt_bytes, &desc.pkt_frames,
+ &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.pkt_frames, desc.channels_per_frame, desc.bits_per_chan) ;
+
+ 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 (have_data == 0 && psf_ftell (psf) < psf->filelength - SIGNED_SIZEOF (marker))
+ { psf_binheader_readf (psf, "mE8", &marker, &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", (int) 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 = 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 ;
+
+ LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), " %2d %-12ld %g\n", k, (long) position, value) ;
+ psf_log_printf (psf, psf->u.cbuf) ;
+ } ;
+
+ psf->peak_info->peak_loc = SF_PEAK_START ;
+ break ;
+
+ case free_MARKER :
+ psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
+ psf_binheader_readf (psf, "j", (int) chunk_size) ;
+ break ;
+
+ case data_MARKER :
+ psf_log_printf (psf, "%M : %D\n", marker, chunk_size) ;
+ psf_binheader_readf (psf, "E4", &k) ;
+ psf_log_printf (psf, " edit : %u\n", k) ;
+ have_data = 1 ;
+ break ;
+
+ default :
+ psf_log_printf (psf, " %M : %D (skipped)\n", marker, chunk_size) ;
+ psf_binheader_readf (psf, "j", (int) chunk_size) ;
+ break ;
+ } ;
+ } ;
+
+ if (have_data == 0)
+ { psf_log_printf (psf, "**** Error, could not find 'data' chunk.\n") ;
+ return SFE_MALFORMED_FILE ;
+ } ;
+
+ psf_log_printf (psf, "End\n") ;
+
+ psf->dataoffset = psf_ftell (psf) ;
+ psf->datalength = psf->filelength - psf->dataoffset ;
+ psf->endian = (desc.fmt_flags & 2) ? SF_ENDIAN_LITTLE : SF_ENDIAN_BIG ;
+
+ 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)
+{ DESC_CHUNK desc ;
+ sf_count_t current, free_len ;
+ int subformat ;
+
+ 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 [0] = 0 ;
+ psf->headindex = 0 ;
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ /* 'caff' marker, version and flags. */
+ psf_binheader_writef (psf, "Em22", caff_MARKER, 1, 0) ;
+
+ /* 'desc' marker and chunk size. */
+ psf_binheader_writef (psf, "Em8", desc_MARKER, (sf_count_t) (sizeof (DESC_CHUNK))) ;
+
+ double64_be_write (1.0 * psf->sf.samplerate, psf->u.ucbuf) ;
+ psf_binheader_writef (psf, "b", psf->u.ucbuf, make_size_t (8)) ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+
+ 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.pkt_frames = 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.pkt_frames = 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.pkt_frames = 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.pkt_frames = 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.pkt_frames = 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.pkt_frames = 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.pkt_frames = 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.pkt_frames = 1 ;
+ desc.channels_per_frame = psf->sf.channels ;
+ desc.bits_per_chan = 8 ;
+ break ;
+
+ default :
+ return SFE_UNIMPLEMENTED ;
+ } ;
+
+ psf_binheader_writef (psf, "mE44444", desc.fmt_id, desc.fmt_flags, desc.pkt_bytes, desc.pkt_frames, desc.channels_per_frame, desc.bits_per_chan) ;
+
+#if 0
+ if (psf->str_flags & SF_STR_LOCATE_START)
+ caf_write_strings (psf, SF_STR_LOCATE_START) ;
+#endif
+
+ if (psf->peak_info != NULL)
+ { int k ;
+ psf_binheader_writef (psf, "Em84", peak_MARKER, (sf_count_t) CAF_PEAK_CHUNK_SIZE (psf->sf.channels), psf->peak_info->edit_number) ;
+ for (k = 0 ; k < psf->sf.channels ; k++)
+ psf_binheader_writef (psf, "Ef8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ;
+ } ;
+
+ /* Add free chunk so that the actual audio data starts at a multiple 0x1000. */
+ free_len = 0x1000 - psf->headindex - 16 - 12 ;
+ while (free_len < 0)
+ free_len += 0x1000 ;
+ psf_binheader_writef (psf, "Em8z", free_MARKER, free_len, (int) free_len) ;
+
+ psf_binheader_writef (psf, "Em84", data_MARKER, psf->datalength, 0) ;
+
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+ 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 65883e65-bd3c-4618-9241-d3c02fd630bd
+*/
diff --git a/src/command.c b/src/command.c
new file mode 100644
index 0000000..d2b697b
--- /dev/null
+++ b/src/command.c
@@ -0,0 +1,363 @@
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#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_PCM_16,
+ "CAF (Apple 16 bit PCM)", "caf"
+ },
+
+ { SF_FORMAT_FLAC | SF_FORMAT_PCM_16,
+ "FLAC 16 bit", "flac"
+ },
+
+ { SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM,
+ "OKI Dialogic VOX ADPCM", "vox"
+ },
+
+ { 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_CONTROL_CMD ;
+
+ 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" },
+ { SF_FORMAT_FLAC, "FLAC (FLAC Lossless Audio Codec)", "flac" },
+ { 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_PAF, "PAF (Ensoniq PARIS)", "paf" },
+ { SF_FORMAT_PVF, "PVF (Portable Voice Format)", "pvf" },
+ { SF_FORMAT_RAW, "RAW (header-less)", "raw" },
+ { 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_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_CONTROL_CMD ;
+
+ 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_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_DPCM_16, "16 bit DPCM", NULL },
+ { SF_FORMAT_DPCM_8, "8 bit DPCM", 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)))
+ return SFE_BAD_CONTROL_CMD ;
+
+ 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 (data->format & SF_FORMAT_TYPEMASK)
+ { format = data->format & SF_FORMAT_TYPEMASK ;
+
+ 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 (data->format & SF_FORMAT_SUBMASK)
+ { format = data->format & SF_FORMAT_SUBMASK ;
+
+ 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_CONTROL_CMD ;
+} /* psf_get_format_info */
+
+/*==============================================================================
+*/
+
+double
+psf_calc_signal_max (SF_PRIVATE *psf, int normalize)
+{ 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 = psf->u.dbuf ;
+ len = ARRAY_LEN (psf->u.dbuf) ;
+
+ for (readcount = 1, max_val = 0.0 ; readcount > 0 ; /* nothing */)
+ { readcount = 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)
+{ 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 (psf->u.dbuf) ;
+
+ data = psf->u.dbuf ;
+
+ chan = 0 ;
+ readcount = len ;
+ while (readcount > 0)
+ { readcount = 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 */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 0aae0d9d-ab2b-4d70-ade3-47a534666f8e
+*/
diff --git a/src/common.c b/src/common.c
new file mode 100644
index 0000000..8e86146
--- /dev/null
+++ b/src/common.c
@@ -0,0 +1,1291 @@
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <time.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+
+/*-----------------------------------------------------------------------------------------------
+** psf_log_printf allows libsndfile internal functions to print to an internal logbuffer 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 logbuffer 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
+** logbuffer array.
+*/
+
+static inline void
+log_putchar (SF_PRIVATE *psf, char ch)
+{ if (psf->logindex < SIGNED_SIZEOF (psf->logbuffer) - 1)
+ { psf->logbuffer [psf->logindex++] = ch ;
+ psf->logbuffer [psf->logindex] = 0 ;
+ } ;
+ return ;
+} /* log_putchar */
+
+void
+psf_log_printf (SF_PRIVATE *psf, const char *format, ...)
+{ va_list ap ;
+ unsigned int u ;
+ int d, tens, shift, width, width_specifier, left_align ;
+ 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') ;
+
+ switch (c)
+ { case 0 : /* NULL character. */
+ va_end (ap) ;
+ return ;
+
+ case 's': /* string */
+ strptr = va_arg (ap, char *) ;
+ if (strptr == NULL)
+ break ;
+ width_specifier -= strlen (strptr) ;
+ if (left_align == SF_FALSE)
+ while (width_specifier -- > 0)
+ log_putchar (psf, ' ') ;
+ while (*strptr)
+ log_putchar (psf, *strptr++) ;
+ while (width_specifier -- > 0)
+ log_putchar (psf, ' ') ;
+ break ;
+
+ case 'd': /* int */
+ d = va_arg (ap, int) ;
+
+ if (d < 0)
+ { d = -d ;
+ sign_char = '-' ;
+ if (lead_char != '0' && left_align == SF_FALSE)
+ width_specifier -- ;
+ } ;
+
+ tens = 1 ;
+ width = 1 ;
+ while (d / 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' + d / tens) ;
+ d %= tens ;
+ tens /= 10 ;
+ } ;
+
+ while (width_specifier -- > 0)
+ log_putchar (psf, lead_char) ;
+ break ;
+
+ case 'D': /* sf_count_t */
+ { sf_count_t D, 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 ;
+ }
+ if (D < 0)
+ { log_putchar (psf, '-') ;
+ D = -D ;
+ } ;
+ Tens = 1 ;
+ width = 1 ;
+ while (D / Tens >= 10)
+ { Tens *= 10 ;
+ width ++ ;
+ } ;
+
+ while (width_specifier > width)
+ { log_putchar (psf, lead_char) ;
+ width_specifier-- ;
+ } ;
+
+ while (Tens > 0)
+ { log_putchar (psf, '0' + D / Tens) ;
+ D %= 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 (! ((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, 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 ;
+
+ maxlen = strlen ((char*) psf->header) ;
+ start = ((char*) psf->header) + maxlen ;
+ maxlen = sizeof (psf->header) - maxlen ;
+
+ va_start (argptr, format) ;
+ LSF_VSNPRINTF (start, maxlen, format, argptr) ;
+ va_end (argptr) ;
+
+ /* Make sure the string is properly terminated. */
+ start [maxlen - 1] = 0 ;
+
+ psf->headindex = strlen ((char*) psf->header) ;
+
+ 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
+** 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)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 1)
+ psf->header [psf->headindex++] = x ;
+} /* header_put_byte */
+
+#if (CPU_IS_BIG_ENDIAN == 1)
+static inline void
+header_put_marker (SF_PRIVATE *psf, int x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
+ { psf->header [psf->headindex++] = (x >> 24) ;
+ psf->header [psf->headindex++] = (x >> 16) ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = x ;
+ } ;
+} /* header_put_marker */
+
+#elif (CPU_IS_LITTLE_ENDIAN == 1)
+static inline void
+header_put_marker (SF_PRIVATE *psf, int x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
+ { psf->header [psf->headindex++] = x ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = (x >> 16) ;
+ psf->header [psf->headindex++] = (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)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 2)
+ { psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = x ;
+ } ;
+} /* header_put_be_short */
+
+static inline void
+header_put_le_short (SF_PRIVATE *psf, int x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 2)
+ { psf->header [psf->headindex++] = x ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ } ;
+} /* header_put_le_short */
+
+static inline void
+header_put_be_3byte (SF_PRIVATE *psf, int x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 3)
+ { psf->header [psf->headindex++] = (x >> 16) ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = x ;
+ } ;
+} /* header_put_be_3byte */
+
+static inline void
+header_put_le_3byte (SF_PRIVATE *psf, int x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 3)
+ { psf->header [psf->headindex++] = x ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = (x >> 16) ;
+ } ;
+} /* header_put_le_3byte */
+
+static inline void
+header_put_be_int (SF_PRIVATE *psf, int x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
+ { psf->header [psf->headindex++] = (x >> 24) ;
+ psf->header [psf->headindex++] = (x >> 16) ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = x ;
+ } ;
+} /* header_put_be_int */
+
+static inline void
+header_put_le_int (SF_PRIVATE *psf, int x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 4)
+ { psf->header [psf->headindex++] = x ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = (x >> 16) ;
+ psf->header [psf->headindex++] = (x >> 24) ;
+ } ;
+} /* header_put_le_int */
+
+#if (SIZEOF_SF_COUNT_T == 4)
+
+static inline void
+header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
+ { psf->header [psf->headindex++] = 0 ;
+ psf->header [psf->headindex++] = 0 ;
+ psf->header [psf->headindex++] = 0 ;
+ psf->header [psf->headindex++] = 0 ;
+ psf->header [psf->headindex++] = (x >> 24) ;
+ psf->header [psf->headindex++] = (x >> 16) ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = x ;
+ } ;
+} /* header_put_be_8byte */
+
+static inline void
+header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
+ { psf->header [psf->headindex++] = x ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = (x >> 16) ;
+ psf->header [psf->headindex++] = (x >> 24) ;
+ psf->header [psf->headindex++] = 0 ;
+ psf->header [psf->headindex++] = 0 ;
+ psf->header [psf->headindex++] = 0 ;
+ psf->header [psf->headindex++] = 0 ;
+ } ;
+} /* header_put_le_8byte */
+
+#elif (SIZEOF_SF_COUNT_T == 8)
+
+static inline void
+header_put_be_8byte (SF_PRIVATE *psf, sf_count_t x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
+ { psf->header [psf->headindex++] = (x >> 56) ;
+ psf->header [psf->headindex++] = (x >> 48) ;
+ psf->header [psf->headindex++] = (x >> 40) ;
+ psf->header [psf->headindex++] = (x >> 32) ;
+ psf->header [psf->headindex++] = (x >> 24) ;
+ psf->header [psf->headindex++] = (x >> 16) ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = x ;
+ } ;
+} /* header_put_be_8byte */
+
+static inline void
+header_put_le_8byte (SF_PRIVATE *psf, sf_count_t x)
+{ if (psf->headindex < SIGNED_SIZEOF (psf->header) - 8)
+ { psf->header [psf->headindex++] = x ;
+ psf->header [psf->headindex++] = (x >> 8) ;
+ psf->header [psf->headindex++] = (x >> 16) ;
+ psf->header [psf->headindex++] = (x >> 24) ;
+ psf->header [psf->headindex++] = (x >> 32) ;
+ psf->header [psf->headindex++] = (x >> 40) ;
+ psf->header [psf->headindex++] = (x >> 48) ;
+ psf->header [psf->headindex++] = (x >> 56) ;
+ } ;
+} /* header_put_le_8byte */
+
+#else
+#error "SIZEOF_SF_COUNT_T is not defined."
+#endif
+
+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 ;
+
+ trunc_8to4 = SF_FALSE ;
+
+ va_start (argptr, format) ;
+
+ while ((c = *format++))
+ { 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 + psf->headindex) ;
+ else
+ float32_le_write (floatdata, psf->header + psf->headindex) ;
+ psf->headindex += 4 ;
+ count += 4 ;
+ break ;
+
+ case 'd' :
+ doubledata = va_arg (argptr, double) ;
+ if (psf->rwf_endian == SF_ENDIAN_BIG)
+ double64_be_write (doubledata, psf->header + psf->headindex) ;
+ else
+ double64_le_write (doubledata, psf->header + psf->headindex) ;
+ psf->headindex += 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 ;
+ size += (size & 1) ;
+ if (psf->rwf_endian == SF_ENDIAN_BIG)
+ header_put_be_int (psf, size) ;
+ else
+ header_put_le_int (psf, size) ;
+ memcpy (&(psf->header [psf->headindex]), strptr, size) ;
+ psf->headindex += size ;
+ psf->header [psf->headindex - 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->rwf_endian == SF_ENDIAN_BIG)
+ header_put_be_int (psf, size) ;
+ else
+ header_put_le_int (psf, size) ;
+ memcpy (&(psf->header [psf->headindex]), strptr, size + 1) ;
+ size += (size & 1) ;
+ psf->headindex += size ;
+ psf->header [psf->headindex] = 0 ;
+ count += 4 + size ;
+ break ;
+
+ case 'b' :
+ bindata = va_arg (argptr, void *) ;
+ size = va_arg (argptr, size_t) ;
+ memcpy (&(psf->header [psf->headindex]), bindata, size) ;
+ psf->headindex += size ;
+ count += size ;
+ break ;
+
+ case 'z' :
+ size = va_arg (argptr, size_t) ;
+ count += size ;
+ while (size)
+ { psf->header [psf->headindex] = 0 ;
+ psf->headindex ++ ;
+ size -- ;
+ } ;
+ break ;
+
+ case 'h' :
+ bindata = va_arg (argptr, void *) ;
+ memcpy (&(psf->header [psf->headindex]), bindata, 16) ;
+ psf->headindex += 16 ;
+ count += 16 ;
+ break ;
+
+ case 'j' :
+ size = va_arg (argptr, size_t) ;
+ psf->headindex += size ;
+ count = 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) ( ((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) | ((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->headindex >= SIGNED_SIZEOF (psf->header))
+ { memset (ptr, 0, SIGNED_SIZEOF (psf->header) - psf->headindex) ;
+
+ /* This is the best that we can do. */
+ psf_fseek (psf, bytes, SEEK_CUR) ;
+ return bytes ;
+ } ;
+
+ if (psf->headindex + bytes > SIGNED_SIZEOF (psf->header))
+ { int most ;
+
+ most = SIGNED_SIZEOF (psf->header) - psf->headindex ;
+ psf_fread (psf->header + psf->headend, 1, most, psf) ;
+ memset ((char *) ptr + most, 0, bytes - most) ;
+
+ psf_fseek (psf, bytes - most, SEEK_CUR) ;
+ return bytes ;
+ } ;
+
+ if (psf->headindex + bytes > psf->headend)
+ { count = psf_fread (psf->header + psf->headend, 1, bytes - (psf->headend - psf->headindex), psf) ;
+ if (count != bytes - (int) (psf->headend - psf->headindex))
+ { psf_log_printf (psf, "Error : psf_fread returned short count.\n") ;
+ return 0 ;
+ } ;
+ psf->headend += count ;
+ } ;
+
+ memcpy (ptr, psf->header + psf->headindex, bytes) ;
+ psf->headindex += bytes ;
+
+ return bytes ;
+} /* header_read */
+
+static void
+header_seek (SF_PRIVATE *psf, sf_count_t position, int whence)
+{
+
+ switch (whence)
+ { case SEEK_SET :
+ if (position > SIGNED_SIZEOF (psf->header))
+ { /* Too much header to cache so just seek instead. */
+ psf_fseek (psf, position, whence) ;
+ return ;
+ } ;
+ if (position > psf->headend)
+ psf->headend += psf_fread (psf->header + psf->headend, 1, position - psf->headend, psf) ;
+ psf->headindex = position ;
+ break ;
+
+ case SEEK_CUR :
+ if (psf->headindex + position < 0)
+ break ;
+
+ if (psf->headindex >= SIGNED_SIZEOF (psf->header))
+ { psf_fseek (psf, position, whence) ;
+ return ;
+ } ;
+
+ if (psf->headindex + position <= psf->headend)
+ { psf->headindex += position ;
+ break ;
+ } ;
+
+ if (psf->headindex + position > SIGNED_SIZEOF (psf->header))
+ { /* Need to jump this without caching it. */
+ psf->headindex = psf->headend ;
+ psf_fseek (psf, position, SEEK_CUR) ;
+ break ;
+ } ;
+
+ psf->headend += psf_fread (psf->header + psf->headend, 1, position - (psf->headend - psf->headindex), psf) ;
+ psf->headindex = psf->headend ;
+ 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 ;
+
+ for (k = 0 ; k < bufsize - 1 ; k++)
+ { if (psf->headindex < psf->headend)
+ { ptr [k] = psf->header [psf->headindex] ;
+ psf->headindex ++ ;
+ }
+ else
+ { psf->headend += psf_fread (psf->header + psf->headend, 1, 1, psf) ;
+ ptr [k] = psf->header [psf->headindex] ;
+ psf->headindex = psf->headend ;
+ } ;
+
+ 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] ;
+ unsigned int *intptr, intdata ;
+ unsigned short *shortptr ;
+ char *charptr ;
+ float *floatptr ;
+ double *doubleptr ;
+ char c ;
+ int byte_count = 0, count ;
+
+ if (! format)
+ return psf_ftell (psf) ;
+
+ va_start (argptr, format) ;
+
+ while ((c = *format++))
+ { 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' :
+ intptr = va_arg (argptr, unsigned int*) ;
+ 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*) ;
+ 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' :
+ 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' :
+ 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' :
+ 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 = GET_BE_INT (ucptr) ;
+ else
+ *intptr = GET_LE_INT (ucptr) ;
+ break ;
+
+ case '8' :
+ 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 = GET_BE_8BYTE (sixteen_bytes) ;
+ else
+ countdata = GET_LE_8BYTE (sixteen_bytes) ;
+ *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_INT (size) ;
+ get_int (psf, longdata) ;
+ memcpy (&(psf->header [psf->headindex]), strptr, size) ;
+ psf->headindex += size ;
+ */
+ break ;
+
+ case 'b' :
+ charptr = va_arg (argptr, char*) ;
+ count = va_arg (argptr, int) ;
+ if (count > 0)
+ byte_count += header_read (psf, charptr, count) ;
+ break ;
+
+ case 'G' :
+ charptr = va_arg (argptr, char*) ;
+ count = va_arg (argptr, int) ;
+ if (count > 0)
+ 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 [psf->headindex] = 0 ;
+ psf->headindex ++ ;
+ size -- ;
+ } ;
+ */
+ break ;
+
+ case 'p' :
+ /* Get the seek position first. */
+ count = va_arg (argptr, int) ;
+ header_seek (psf, count, SEEK_SET) ;
+ byte_count = count ;
+ break ;
+
+ case 'j' :
+ /* Get the seek position first. */
+ count = va_arg (argptr, int) ;
+ header_seek (psf, count, SEEK_CUR) ;
+ byte_count += count ;
+ 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] = 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) ;
+ 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 */
+
+/*========================================================================================
+*/
+
+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 */
+
+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] = 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 (&current) ;
+
+#if defined (HAVE_GMTIME_R)
+ /* If the re-entrant version is available, use it. */
+ tmptr = gmtime_r (&current, &timedata) ;
+#elif defined (HAVE_GMTIME)
+ /* Otherwise use the standard one and copy the data to local storage. */
+ tmptr = gmtime (&current) ;
+ memcpy (&timedata, tmptr, sizeof (timedata)) ;
+#else
+ tmptr = NULL ;
+#endif
+
+ if (tmptr)
+ LSF_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
+ LSF_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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 33e9795e-f717-461a-9feb-65d083a56395
+*/
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 0000000..5ba2cc6
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,813 @@
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdlib.h>
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#endif
+
+#ifndef SNDFILE_H
+#include "sndfile.h"
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#ifdef __cplusplus
+#error "This code is not designed to be compiled with a C++ compiler."
+#endif
+
+#if (SIZEOF_LONG == 8)
+# define SF_PLATFORM_S64(x) x##l
+#elif COMPILER_IS_GCC
+# define SF_PLATFORM_S64(x) x##ll
+#elif OS_IS_WIN32
+# define SF_PLATFORM_S64(x) x##I64
+#else
+# error "Don't know how to define a 64 bit integer constant."
+#endif
+
+
+
+#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*2)
+#define SF_FILENAME_LEN (512)
+#define SF_SYSERR_LEN (256)
+#define SF_MAX_STRINGS (16)
+#define SF_STR_BUFFER_LEN (8192)
+#define SF_HEADER_LEN (4100 + SF_STR_BUFFER_LEN)
+
+#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])))
+
+#if (COMPILER_IS_GCC == 1)
+#define SF_MAX(x,y) ({ \
+ typeof(x) _x = (x); \
+ typeof(y) _y = (y); \
+ (void) (&_x == &_y); \
+ _x > _y ? _x : _y; })
+
+#define SF_MIN(x,y) ({ \
+ typeof(x) _x = (x); \
+ typeof(y) _y = (y); \
+ (void) (&_x == &_y); \
+ _x < _y ? _x : _y; })
+#else
+#define SF_MAX(a,b) ((a) > (b) ? (a) : (b))
+#define SF_MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+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. */
+
+ /* 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_OGG = 0x4090000,
+
+ 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_VORBIS = 0x1001,
+
+ SF_FORMAT_SVX_FIB = 0x1020, /* SVX Fibonacci Delta encoding. */
+ SF_FORMAT_SVX_EXP = 0x1021, /* SVX Exponential Delta encoding. */
+
+ SF_FORMAT_PCM_N = 0x1030
+} ;
+
+/*---------------------------------------------------------------------------------------
+** 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 ;
+
+#if HAVE_FLEXIBLE_ARRAY
+ /* the per channel peak info */
+ PEAK_POS peaks [] ;
+#else
+ /*
+ ** This is not ISO compliant C. It works on some compilers which
+ ** don't support the ISO standard flexible struct array which is
+ ** used above. If your compiler doesn't like this I suggest you find
+ ** youself a 1999 ISO C standards compilant compiler. GCC-3.X is
+ ** highly recommended.
+ */
+ PEAK_POS peaks [0] ;
+#endif
+} 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 ;
+ char *str ;
+} STR_DATA ;
+
+static inline size_t
+make_size_t (int x)
+{ return (size_t) x ;
+} /* size_t_of_int */
+
+/*=======================================================================================
+** 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 sf_private_tag
+{ /* Force the compiler to double align the start of buffer. */
+ 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)] ;
+ } u ;
+
+ char filepath [SF_FILENAME_LEN] ;
+ char rsrcpath [SF_FILENAME_LEN] ;
+ char directory [SF_FILENAME_LEN] ;
+ char filename [SF_FILENAME_LEN / 4] ;
+
+ char syserr [SF_SYSERR_LEN] ;
+
+ /* logbuffer and logindex should only be changed within the logging functions
+ ** of common.c
+ */
+ char logbuffer [SF_BUFFER_LEN] ;
+ unsigned char header [SF_HEADER_LEN] ; /* Must be unsigned */
+ int rwf_endian ; /* Header endian-ness flag. */
+
+ /* Storage and housekeeping data for adding/reading strings from
+ ** sound files.
+ */
+ STR_DATA strings [SF_MAX_STRINGS] ;
+ char str_storage [SF_STR_BUFFER_LEN] ;
+ char *str_end ;
+ int str_flags ;
+
+ /* Guard value. If this changes the buffers above have overflowed. */
+ int Magick ;
+
+ /* Index variables for maintaining logbuffer and header above. */
+ int logindex ;
+ int headindex, headend ;
+ int has_text ;
+ int do_not_close_descriptor ;
+
+#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 *hfile, *hrsrc, *hsaved ;
+#else
+ /* These fields can only be used in src/file_io.c. */
+ int filedes, rsrcdes, savedes ;
+#endif
+
+ int error ;
+
+ int mode ; /* Open mode : SFM_READ, SFM_WRITE or SFM_RDWR. */
+ int endian ; /* File endianness : SF_ENDIAN_LITTLE or SF_ENDIAN_BIG. */
+ int float_endswap ; /* Need to endswap float32s? */
+
+ /*
+ ** Maximum float value for calculating the multiplier for
+ ** float/double to short/int conversions.
+ */
+ int float_int_mult ;
+ float float_max ;
+
+ /* 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 ;
+
+ /* Loop Info */
+ SF_LOOP_INFO *loop_info ;
+ SF_INSTRUMENT *instrument ;
+
+ /* Broadcast (EBU) Info */
+ SF_BROADCAST_INFO *broadcast_info ;
+
+ /* 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 ;
+
+ /* For ambisonic commands */
+ int wavex_ambisonic ;
+
+ /* 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) ;
+
+ /*
+ ** 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 ;
+} 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_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_MALLOC_FAILED,
+ SFE_UNIMPLEMENTED,
+ SFE_BAD_READ_ALIGN,
+ SFE_BAD_WRITE_ALIGN,
+ SFE_UNKNOWN_FORMAT,
+ 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_CONTROL_CMD,
+ SFE_BAD_ENDIAN,
+ SFE_CHANNEL_COUNT,
+ SFE_BAD_RDWR_FORMAT,
+
+ 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_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_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_GSM610_FORMAT,
+ SFE_WAV_UNKNOWN_CHUNK,
+ SFE_WAV_WVPK_DATA,
+
+ 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_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_FMT,
+ SFE_W64_NO_DATA,
+ SFE_W64_FMT_SHORT,
+ SFE_W64_FMT_TOO_BIG,
+ SFE_W64_ADPCM_NOT4BIT,
+ SFE_W64_ADPCM_CHANNELS,
+ SFE_W64_GSM610_FORMAT,
+
+ SFE_MAT4_BAD_NAME,
+ SFE_MAT4_NO_SAMPLERATE,
+ SFE_MAT4_ZERO_CHANNELS,
+
+ SFE_MAT5_BAD_ENDIAN,
+ SFE_MAT5_NO_BLOCK,
+ SFE_MAT5_SAMPLE_RATE,
+ SFE_MAT5_ZERO_CHANNELS,
+
+ SFE_PVF_NO_PVF1,
+ SFE_PVF_BAD_HEADER,
+ SFE_PVF_BAD_BITWIDTH,
+
+ SFE_DWVW_BAD_BITWIDTH,
+ SFE_G72X_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_UNKOWN_ERROR,
+
+ SFE_WVE_NOT_WVE,
+ SFE_WVE_NO_PIPE,
+
+ SFE_MAX_ERROR /* This must be last in list. */
+} ;
+
+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 (unsigned char *cptr) ;
+float float32_le_read (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 (unsigned char *cptr) ;
+double double64_le_read (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) ;
+
+void psf_hexdump (const void *ptr, int len) ;
+
+/* 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) ;
+
+/* 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, const char *pathname, int flags) ;
+int psf_set_stdio (SF_PRIVATE *psf, int mode) ;
+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) ;
+
+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 mode) ;
+int psf_close_rsrc (SF_PRIVATE *psf) ;
+
+/*
+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) ;
+
+/* In progress. Do not currently work. */
+
+int mpeg_open (SF_PRIVATE *psf) ;
+int ogg_open (SF_PRIVATE *psf) ;
+int rx2_open (SF_PRIVATE *psf) ;
+int txw_open (SF_PRIVATE *psf) ;
+int wve_open (SF_PRIVATE *psf) ;
+int dwd_open (SF_PRIVATE *psf) ;
+
+int macbinary3_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 vox_adpcm_init (SF_PRIVATE *psf) ;
+int flac_init (SF_PRIVATE *psf) ;
+int g72x_init (SF_PRIVATE * psf) ;
+
+int dither_init (SF_PRIVATE *psf, int mode) ;
+
+int wav_w64_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock) ;
+int wav_w64_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) ;
+
+/*------------------------------------------------------------------------------------
+** Other helper functions.
+*/
+
+void *psf_memset (void *s, int c, sf_count_t n) ;
+
+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* broadcast_info_alloc (void) ;
+int broadcast_info_copy (SF_BROADCAST_INFO* dst, SF_BROADCAST_INFO* src) ;
+int broadcast_add_coding_history (SF_BROADCAST_INFO* bext, unsigned int channels, unsigned int samplerate) ;
+
+typedef struct
+{ int channels ;
+ int endianness ;
+} AUDIO_DETECT ;
+
+int audio_detect (SF_PRIVATE * psf, AUDIO_DETECT *ad, const unsigned char * data, int datalen) ;
+
+
+/*------------------------------------------------------------------------------------
+** Here's how we fix systems which don't snprintf / vsnprintf.
+** Systems without these functions should use the
+*/
+
+#if USE_WINDOWS_API
+#define LSF_SNPRINTF _snprintf
+#elif (HAVE_SNPRINTF && ! FORCE_MISSING_SNPRINTF)
+#define LSF_SNPRINTF snprintf
+#else
+int missing_snprintf (char *str, size_t n, char const *fmt, ...) ;
+#define LSF_SNPRINTF missing_snprintf
+#endif
+
+#if USE_WINDOWS_API
+#define LSF_VSNPRINTF _vsnprintf
+#elif (HAVE_VSNPRINTF && ! FORCE_MISSING_SNPRINTF)
+#define LSF_VSNPRINTF vsnprintf
+#else
+int missing_vsnprintf (char *str, size_t n, const char *fmt, ...) ;
+#define LSF_VSNPRINTF missing_vsnprintf
+#endif
+
+/*------------------------------------------------------------------------------------
+** 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
+
+#endif /* SNDFILE_COMMON_H */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 7b45c0ee-5835-4a18-a4ef-994e4cd95b67
+*/
diff --git a/src/create_symbols_file.py b/src/create_symbols_file.py
new file mode 100755
index 0000000..8d60df8
--- /dev/null
+++ b/src/create_symbols_file.py
@@ -0,0 +1,153 @@
+#!/usr/bin/python
+
+# Copyright (C) 2003-2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+#
+# 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_get_info", 68 ),
+ ( "sf_open_fd", 70 ),
+ ( "sf_open_virtual", 80 ),
+ ( "sf_write_sync", 90 )
+ )
+
+#-------------------------------------------------------------------------------
+
+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:
+ print " %s ;" % name
+ print " local:"
+ print " * ;"
+ print "} ;"
+ print
+ return
+
+def darwin_symbols (progname, version):
+ print "# Auto-generated by %s\n" %progname
+ for name, ordinal in ALL_SYMBOLS:
+ print "_%s" % name
+ print
+ return
+
+def win32_symbols (progname, version, name):
+ print "; Auto-generated by %s\n" %progname
+ print "LIBRARY %s-%s.dll" % (name, re.sub ("\..*", "", version))
+ print "EXPORTS\n"
+ for name, ordinal in ALL_SYMBOLS:
+ print "%-20s @%s" % (name, ordinal)
+ print
+ return
+
+def no_symbols (os_name):
+ print
+ print "No known way of restricting exported symbols on '%s'." % os_name
+ print "If you know a way, please contact the author."
+ print
+ return
+
+#-------------------------------------------------------------------------------
+
+progname = re.sub (".*[\\/]", "", sys.argv [0])
+
+if len (sys.argv) != 3:
+ print
+ print "Usage : %s <target OS name> <libsndfile version>." % progname
+ print
+ print " Currently supported values for target OS are:"
+ print " linux"
+ print " darwin (ie MacOSX)"
+ print " win32 (ie wintendo)"
+ print " cygwin (Cygwin on wintendo)"
+ print
+ sys.exit (1)
+
+os_name = sys.argv [1]
+version = re.sub ("\.[a-z0-9]+$", "", sys.argv [2])
+
+if os_name == "linux":
+ 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")
+else:
+ no_symbols (os_name)
+
+sys.exit (0)
+
+# Do not edit or modify anything in this comment block.
+# The arch-tag line is a file identity tag for the GNU Arch
+# revision control system.
+#
+# arch-tag: 5814f35c-318f-4023-a0c3-d9cf7c9e5f6c
+
diff --git a/src/dither.c b/src/dither.c
new file mode 100644
index 0000000..50b5ba2
--- /dev/null
+++ b/src/dither.c
@@ -0,0 +1,533 @@
+/*
+** Copyright (C) 2003,2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdlib.h>
+
+#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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { case SF_FORMAT_DOUBLE :
+ case SF_FORMAT_FLOAT :
+ pdither->read_int = psf->read_int ;
+ psf->read_int = dither_read_int ;
+
+ 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 ;
+
+ 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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { case SF_FORMAT_DOUBLE :
+ case SF_FORMAT_FLOAT :
+ pdither->write_int = psf->write_int ;
+ psf->write_int = dither_write_int ;
+
+ 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 :
+
+ 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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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 = 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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { case SF_FORMAT_PCM_S8 :
+ case SF_FORMAT_PCM_U8 :
+ case SF_FORMAT_PCM_16 :
+ case SF_FORMAT_PCM_24 :
+
+ 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 = 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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { case SF_FORMAT_PCM_S8 :
+ case SF_FORMAT_PCM_U8 :
+ case SF_FORMAT_PCM_16 :
+ case SF_FORMAT_PCM_24 :
+
+ 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 : (float) len ;
+ writecount /= psf->sf.channels ;
+ writecount *= psf->sf.channels ;
+
+ dither_float (ptr, (float*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ;
+
+ thiswrite = 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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { case SF_FORMAT_PCM_S8 :
+ case SF_FORMAT_PCM_U8 :
+ case SF_FORMAT_PCM_16 :
+ case SF_FORMAT_PCM_24 :
+
+ 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 : (double) len ;
+ writecount /= psf->sf.channels ;
+ writecount *= psf->sf.channels ;
+
+ dither_double (ptr, (double*) pdither->buffer, writecount / psf->sf.channels, psf->sf.channels) ;
+
+ thiswrite = 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
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 673fad58-5314-421c-9144-9d54bfdf104c
+*/
diff --git a/src/double64.c b/src/double64.c
new file mode 100644
index 0000000..5bcaf5c
--- /dev/null
+++ b/src/double64.c
@@ -0,0 +1,1042 @@
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+#include "float_cast.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 ;
+
+ double64_caps = double64_get_capability (psf) ;
+
+ psf->blockwidth = sizeof (double) * psf->sf.channels ;
+
+ if (psf->mode == SFM_READ || psf->mode == SFM_RDWR)
+ { switch (psf->endian + double64_caps)
+ { case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) :
+ psf->float_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->float_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->float_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->float_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->float_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->float_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->float_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->float_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->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { switch (psf->endian + double64_caps)
+ { case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) :
+ psf->float_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->float_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->float_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->float_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->float_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->float_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->float_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->float_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 (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 *= (1 << exponent) ;
+ else if (exponent < 0)
+ dvalue /= (1 << abs (exponent)) ;
+
+ return dvalue ;
+} /* double64_be_read */
+
+double
+double64_le_read (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 *= (1 << exponent) ;
+ else if (exponent < 0)
+ dvalue /= (1 << 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 = 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 = 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 = 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 = 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)
+{ while (--count >= 0)
+ { dest [count] = lrint (scale * src [count]) ;
+ } ;
+} /* d2s_array */
+
+static void
+d2s_clip_array (const double *src, int count, short *dest, double scale)
+{ while (--count >= 0)
+ { double tmp = scale * src [count] ;
+
+ if (CPU_CLIPS_POSITIVE == 0 && tmp > 32767.0)
+ dest [count] = SHRT_MAX ;
+ else if (CPU_CLIPS_NEGATIVE == 0 && tmp < -32768.0)
+ dest [count] = SHRT_MIN ;
+ else
+ dest [count] = lrint (tmp) ;
+ } ;
+} /* d2s_clip_array */
+
+static void
+d2i_array (const double *src, int count, int *dest, double scale)
+{ while (--count >= 0)
+ { dest [count] = lrint (scale * src [count]) ;
+ } ;
+} /* d2i_array */
+
+static void
+d2i_clip_array (const double *src, int count, int *dest, double scale)
+{ while (--count >= 0)
+ { float tmp = scale * src [count] ;
+
+ if (CPU_CLIPS_POSITIVE == 0 && tmp > (1.0 * INT_MAX))
+ dest [count] = INT_MAX ;
+ else if (CPU_CLIPS_NEGATIVE == 0 && tmp < (-1.0 * INT_MAX))
+ dest [count] = INT_MIN ;
+ else
+ dest [count] = lrint (tmp) ;
+ } ;
+} /* d2i_clip_array */
+
+static inline void
+d2f_array (const double *src, int count, float *dest)
+{ while (--count >= 0)
+ { dest [count] = src [count] ;
+ } ;
+} /* d2f_array */
+
+static inline void
+s2d_array (const short *src, double *dest, int count)
+{ while (--count >= 0)
+ { dest [count] = src [count] ;
+ } ;
+} /* s2d_array */
+
+static inline void
+i2d_array (const int *src, double *dest, int count)
+{ while (--count >= 0)
+ { dest [count] = src [count] ;
+ } ;
+} /* i2d_array */
+
+static inline void
+f2d_array (const float *src, double *dest, int count)
+{ while (--count >= 0)
+ { dest [count] = src [count] ;
+ } ;
+} /* f2d_array */
+
+/*----------------------------------------------------------------------------------------------
+*/
+
+static sf_count_t
+host_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
+{ 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 (psf->u.dbuf) ;
+ scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, readcount) ;
+
+ convert (psf->u.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)
+{ 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 (psf->u.dbuf) ;
+ scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ convert (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ d2f_array (psf->u.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->float_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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+
+ s2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ f2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ if (psf->peak_info)
+ double64_peak_update (psf, ptr, len, 0) ;
+
+ if (psf->float_endswap != SF_TRUE)
+ return psf_fwrite (ptr, sizeof (double), len, psf) ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+
+ endswap_double_copy (psf->u.dbuf, ptr + total, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+ double scale ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+ scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ d2bd_read (psf->u.dbuf, bufferlen) ;
+
+ d2s_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+ double scale ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+ scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ d2bd_read (psf->u.dbuf, bufferlen) ;
+
+ d2i_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ d2bd_read (psf->u.dbuf, bufferlen) ;
+
+ memcpy (ptr + total, psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ /* FIXME : This is probably nowhere near optimal. */
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, readcount) ;
+
+ d2bd_read (psf->u.dbuf, readcount) ;
+
+ memcpy (ptr + total, psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ;
+
+ bd2d_write (psf->u.dbuf, bufferlen) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ;
+
+ bd2d_write (psf->u.dbuf, bufferlen) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ f2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
+
+ bd2d_write (psf->u.dbuf, bufferlen) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ 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 (psf->u.dbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+
+ memcpy (psf->u.dbuf, ptr + total, bufferlen * sizeof (double)) ;
+
+ bd2d_write (psf->u.dbuf, bufferlen) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_double_array (psf->u.dbuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ while (--count >= 0)
+ { buffer [count] = DOUBLE64_READ ((unsigned char *) (buffer + count)) ;
+ } ;
+} /* d2bd_read */
+
+static void
+bd2d_write (double *buffer, int count)
+{ while (--count >= 0)
+ { DOUBLE64_WRITE (buffer [count], (unsigned char*) (buffer + count)) ;
+ } ;
+} /* bd2d_write */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 4ee243b7-8c7a-469b-869c-e9aa0ee3b77f
+*/
diff --git a/src/dwd.c b/src/dwd.c
new file mode 100644
index 0000000..5db7fbb
--- /dev/null
+++ b/src/dwd.c
@@ -0,0 +1,208 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#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 subformat, error = 0 ;
+
+ if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = dwd_read_header (psf)))
+ return error ;
+ } ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_DWD)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ {
+ /*-psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+ 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
+{ unsigned char major, minor, compression, channels, bitwidth ;
+ unsigned short srate, maxval ;
+ unsigned int id, datalen, frames, offset ;
+} DWD_HEADER ;
+
+static int
+dwd_read_header (SF_PRIVATE *psf)
+{ DWD_HEADER dwdh ;
+
+ memset (psf->u.cbuf, 0, sizeof (psf->u.cbuf)) ;
+ /* Set position to start of file to begin reading header. */
+ psf_binheader_readf (psf, "pb", 0, psf->u.cbuf, DWD_IDENTIFIER_LEN) ;
+
+ if (memcmp (psf->u.cbuf, DWD_IDENTIFIER, DWD_IDENTIFIER_LEN) != 0)
+ return SFE_DWD_NO_DWD ;
+
+ psf_log_printf (psf, "Read only : DiamondWare Digitized (.dwd)\n", psf->u.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 = (unsigned int) (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
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: a5e1d2a6-a840-4039-a0e7-e1a43eb05a4f
+*/
diff --git a/src/dwvw.c b/src/dwvw.c
new file mode 100644
index 0000000..6076276
--- /dev/null
+++ b/src/dwvw.c
@@ -0,0 +1,669 @@
+/*
+** Copyright (C) 2002-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "float_cast.h"
+#include "common.h"
+
+typedef struct
+{ int dwm_maxsize, bit_width, 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_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->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 ;
+ pdwvw->dwm_maxsize = bitwidth / 2 ;
+ pdwvw->max_delta = 1 << (bitwidth - 1) ;
+ pdwvw->span = 1 << bitwidth ;
+
+ dwvw_read_reset (pdwvw) ;
+
+ if (psf->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->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 ;
+
+ /* FIXME : This is bogus. */
+ psf->sf.frames = SF_COUNT_MAX ;
+ psf->datalength = psf->sf.frames ;
+ /* EMXIF : This is bogus. */
+
+ 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->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 sf_count_t
+dwvw_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
+{ DWVW_PRIVATE *pdwvw ;
+ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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 ;
+ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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 ;
+ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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)
+ 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] = 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 = 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 = (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)
+{ pdwvw->samplecount = 0 ;
+ pdwvw->b.index = 0 ;
+ pdwvw->b.end = 0 ;
+ pdwvw->bit_count = 0 ;
+ pdwvw->bits = 0 ;
+ pdwvw->last_delta_width = 0 ;
+ pdwvw->last_sample = 0 ;
+} /* 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 = (pdwvw->bits << new_bits) | (data & ((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 ;
+ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ iptr [k] = 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 ;
+ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ iptr [k] = 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 ;
+ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ iptr [k] = 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 1ca09552-b01f-4d7f-9bcf-612f834fe41d
+*/
diff --git a/src/file_io.c b/src/file_io.c
new file mode 100644
index 0000000..123cf93
--- /dev/null
+++ b/src/file_io.c
@@ -0,0 +1,1537 @@
+/*
+** Copyright (C) 2002-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+** Copyright (C) 2003 Ross Bencina <rbencina@iprimus.com.au>
+**
+** 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"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if (HAVE_DECL_S_IRGRP == 0)
+#include <sf_unistd.h>
+#endif
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "sndfile.h"
+#include "common.h"
+
+#define SENSIBLE_SIZE (0x40000000)
+
+static void psf_log_syserr (SF_PRIVATE *psf, int error) ;
+
+#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 (const char * path, int mode) ;
+static sf_count_t psf_get_filelen_fd (int fd) ;
+
+int
+psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode)
+{
+ psf->error = 0 ;
+ psf->filedes = psf_open_fd (pathname, open_mode) ;
+
+ if (psf->filedes == - SFE_BAD_OPEN_MODE)
+ { psf->error = SFE_BAD_OPEN_MODE ;
+ psf->filedes = -1 ;
+ return psf->error ;
+ } ;
+
+ if (psf->filedes == -1)
+ psf_log_syserr (psf, errno) ;
+
+ psf->mode = open_mode ;
+
+ return psf->error ;
+} /* psf_fopen */
+
+int
+psf_fclose (SF_PRIVATE *psf)
+{ int retval ;
+
+ if (psf->virtual_io)
+ return 0 ;
+
+ if (psf->do_not_close_descriptor)
+ { psf->filedes = -1 ;
+ return 0 ;
+ } ;
+
+ if ((retval = psf_close_fd (psf->filedes)) == -1)
+ psf_log_syserr (psf, errno) ;
+
+ psf->filedes = -1 ;
+
+ return retval ;
+} /* psf_fclose */
+
+int
+psf_open_rsrc (SF_PRIVATE *psf, int open_mode)
+{
+ if (psf->rsrcdes > 0)
+ return 0 ;
+
+ /* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
+ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s/rsrc", psf->filepath) ;
+ psf->error = SFE_NO_ERROR ;
+ if ((psf->rsrcdes = psf_open_fd (psf->rsrcpath, open_mode)) >= 0)
+ { psf->rsrclength = psf_get_filelen_fd (psf->rsrcdes) ;
+ if (psf->rsrclength > 0 || (open_mode & SFM_WRITE))
+ return SFE_NO_ERROR ;
+ psf_close_fd (psf->rsrcdes) ;
+ psf->rsrcdes = -1 ;
+ } ;
+
+ if (psf->rsrcdes == - 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.
+ */
+ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s._%s", psf->directory, psf->filename) ;
+ psf->error = SFE_NO_ERROR ;
+ if ((psf->rsrcdes = psf_open_fd (psf->rsrcpath, open_mode)) >= 0)
+ { psf->rsrclength = psf_get_filelen_fd (psf->rsrcdes) ;
+ return SFE_NO_ERROR ;
+ } ;
+
+ /*
+ ** Now try for a resource fork stored in a separate file in the
+ ** .AppleDouble/ directory.
+ */
+ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s.AppleDouble/%s", psf->directory, psf->filename) ;
+ psf->error = SFE_NO_ERROR ;
+ if ((psf->rsrcdes = psf_open_fd (psf->rsrcpath, open_mode)) >= 0)
+ { psf->rsrclength = psf_get_filelen_fd (psf->rsrcdes) ;
+ return SFE_NO_ERROR ;
+ } ;
+
+ /* No resource file found. */
+ if (psf->rsrcdes == -1)
+ psf_log_syserr (psf, errno) ;
+
+ psf->rsrcdes = -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->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->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)
+{
+ if (psf->rsrcdes >= 0)
+ psf_close_fd (psf->rsrcdes) ;
+ psf->rsrcdes = -1 ;
+ return 0 ;
+} /* psf_close_rsrc */
+
+int
+psf_set_stdio (SF_PRIVATE *psf, int mode)
+{ int error = 0 ;
+
+ switch (mode)
+ { case SFM_RDWR :
+ error = SFE_OPEN_PIPE_RDWR ;
+ break ;
+
+ case SFM_READ :
+ psf->filedes = 0 ;
+ break ;
+
+ case SFM_WRITE :
+ psf->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->filedes = fd ;
+} /* psf_set_file */
+
+int
+psf_file_valid (SF_PRIVATE *psf)
+{ return (psf->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 new_position ;
+
+ if (psf->virtual_io)
+ return psf->vio.seek (offset, whence, psf->vio_user_data) ;
+
+ switch (whence)
+ { case SEEK_SET :
+ offset += psf->fileoffset ;
+ break ;
+
+ case SEEK_END :
+ if (psf->mode == SFM_WRITE)
+ { new_position = lseek (psf->filedes, offset, whence) ;
+
+ if (new_position < 0)
+ psf_log_syserr (psf, errno) ;
+
+ return new_position - psf->fileoffset ;
+ } ;
+
+ /* Transform SEEK_END into a SEEK_SET, ie find the file
+ ** length add the requested offset (should be <= 0) to
+ ** get the offset wrt the start of file.
+ */
+ whence = SEEK_SET ;
+ offset = lseek (psf->filedes, 0, SEEK_END) + offset ;
+ break ;
+
+ default :
+ /* No need to do anything about SEEK_CUR. */
+ break ;
+ } ;
+
+ new_position = lseek (psf->filedes, offset, whence) ;
+
+ if (new_position < 0)
+ psf_log_syserr (psf, errno) ;
+
+ new_position -= psf->fileoffset ;
+
+ return new_position ;
+} /* 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->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 (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->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->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 ;
+
+ 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->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->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)
+{ struct stat statbuf ;
+
+ /*
+ ** Sanity check.
+ ** If everything is OK, this will be optimised out.
+ */
+ if (sizeof (statbuf.st_size) == 4 && sizeof (sf_count_t) == 8)
+ return (sf_count_t) -SFE_BAD_STAT_SIZE ;
+
+ if (fstat (fd, &statbuf) == -1)
+ return (sf_count_t) -1 ;
+
+ return statbuf.st_size ;
+} /* 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->filedes, len) ;
+
+ if (retval == -1)
+ psf_log_syserr (psf, errno) ;
+
+ return retval ;
+} /* psf_ftruncate */
+
+void
+psf_init_files (SF_PRIVATE *psf)
+{ psf->filedes = -1 ;
+ psf->rsrcdes = -1 ;
+ psf->savedes = -1 ;
+} /* psf_init_files */
+
+void
+psf_use_rsrc (SF_PRIVATE *psf, int on_off)
+{
+ if (on_off)
+ { if (psf->filedes != psf->rsrcdes)
+ { psf->savedes = psf->filedes ;
+ psf->filedes = psf->rsrcdes ;
+ } ;
+ }
+ else if (psf->filedes == psf->rsrcdes)
+ psf->filedes = psf->savedes ;
+
+ return ;
+} /* psf_use_rsrc */
+
+static int
+psf_open_fd (const char * pathname, int open_mode)
+{ 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 <stdio.h>.
+ */
+ if (sizeof (off_t) != sizeof (sf_count_t))
+ { puts ("\n\n*** Fatal error : sizeof (off_t) != sizeof (sf_count_t)") ;
+ puts ("*** This means that libsndfile was not configured correctly.\n") ;
+ exit (1) ;
+ } ;
+
+ switch (open_mode)
+ { case SFM_READ :
+ oflag = O_RDONLY ;
+ mode = 0 ;
+ break ;
+
+ case SFM_WRITE :
+ oflag = O_WRONLY | O_CREAT | O_TRUNC ;
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ;
+ break ;
+
+ case SFM_RDWR :
+ oflag = O_RDWR | O_CREAT ;
+ mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH ;
+ break ;
+
+ default :
+ return - SFE_BAD_OPEN_MODE ;
+ break ;
+ } ;
+
+#if OS_IS_WIN32
+ /* For Cygwin. */
+ oflag |= O_BINARY ;
+#endif
+
+ if (mode == 0)
+ fd = open (pathname, oflag) ;
+ else
+ fd = open (pathname, 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 ;
+ LSF_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->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ fsync (psf->filedes) ;
+#else
+ psf = NULL ;
+#endif
+} /* psf_fsync */
+
+#elif USE_WINDOWS_API
+
+/* Win32 file i/o functions implemented using native Win32 API */
+
+#include <windows.h>
+#include <io.h>
+
+#ifndef HAVE_SSIZE_T
+typedef long ssize_t ;
+#endif
+
+static int psf_close_handle (HANDLE handle) ;
+static HANDLE psf_open_handle (const char * path, int mode) ;
+static sf_count_t psf_get_filelen_handle (HANDLE handle) ;
+
+/* USE_WINDOWS_API */ int
+psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode)
+{
+ psf->error = 0 ;
+ psf->hfile = psf_open_handle (pathname, open_mode) ;
+
+ if (psf->hfile == NULL)
+ psf_log_syserr (psf, GetLastError ()) ;
+
+ psf->mode = open_mode ;
+
+ return psf->error ;
+} /* psf_fopen */
+
+/* USE_WINDOWS_API */ int
+psf_fclose (SF_PRIVATE *psf)
+{ int retval ;
+
+ if (psf->virtual_io)
+ return 0 ;
+
+ if (psf->do_not_close_descriptor)
+ { psf->hfile = NULL ;
+ return 0 ;
+ } ;
+
+ if ((retval = psf_close_handle (psf->hfile)) == -1)
+ psf_log_syserr (psf, GetLastError ()) ;
+
+ psf->hfile = NULL ;
+
+ return retval ;
+} /* psf_fclose */
+
+/* USE_WINDOWS_API */ int
+psf_open_rsrc (SF_PRIVATE *psf, int open_mode)
+{
+ if (psf->hrsrc != NULL)
+ return 0 ;
+
+ /* Test for MacOSX style resource fork on HPFS or HPFS+ filesystems. */
+ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s/rsrc", psf->filepath) ;
+ psf->error = SFE_NO_ERROR ;
+ if ((psf->hrsrc = psf_open_handle (psf->rsrcpath, open_mode)) != NULL)
+ { psf->rsrclength = psf_get_filelen_handle (psf->hrsrc) ;
+ 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.
+ */
+ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s._%s", psf->directory, psf->filename) ;
+ psf->error = SFE_NO_ERROR ;
+ if ((psf->hrsrc = psf_open_handle (psf->rsrcpath, open_mode)) != NULL)
+ { psf->rsrclength = psf_get_filelen_handle (psf->hrsrc) ;
+ return SFE_NO_ERROR ;
+ } ;
+
+ /*
+ ** Now try for a resource fork stored in a separate file in the
+ ** .AppleDouble/ directory.
+ */
+ LSF_SNPRINTF (psf->rsrcpath, sizeof (psf->rsrcpath), "%s.AppleDouble/%s", psf->directory, psf->filename) ;
+ psf->error = SFE_NO_ERROR ;
+ if ((psf->hrsrc = psf_open_handle (psf->rsrcpath, open_mode)) != NULL)
+ { psf->rsrclength = psf_get_filelen_handle (psf->hrsrc) ;
+ return SFE_NO_ERROR ;
+ } ;
+
+ /* No resource file found. */
+ if (psf->hrsrc == NULL)
+ psf_log_syserr (psf, GetLastError ()) ;
+
+ psf->hrsrc = NULL ;
+
+ 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->hfile) ;
+
+ 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->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->hfile = NULL ;
+ psf->hrsrc = NULL ;
+ psf->hsaved = NULL ;
+} /* psf_init_files */
+
+/* USE_WINDOWS_API */ void
+psf_use_rsrc (SF_PRIVATE *psf, int on_off)
+{
+ if (on_off)
+ { if (psf->hfile != psf->hrsrc)
+ { psf->hsaved = psf->hfile ;
+ psf->hfile = psf->hrsrc ;
+ } ;
+ }
+ else if (psf->hfile == psf->hrsrc)
+ psf->hfile = psf->hsaved ;
+
+ return ;
+} /* psf_use_rsrc */
+
+/* USE_WINDOWS_API */ static HANDLE
+psf_open_handle (const char * pathname, int open_mode)
+{ DWORD dwDesiredAccess ;
+ DWORD dwShareMode ;
+ DWORD dwCreationDistribution ;
+ HANDLE handle ;
+
+ switch (open_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 NULL ;
+ } ;
+
+ handle = CreateFile (
+ pathname, /* 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 */
+ ) ;
+
+ if (handle == INVALID_HANDLE_VALUE)
+ return NULL ;
+
+ 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
+ ) ;
+
+ LSF_SNPRINTF (psf->syserr, sizeof (psf->syserr), "System error : %s", lpMsgBuf) ;
+ LocalFree (lpMsgBuf) ;
+ } ;
+
+ return ;
+} /* psf_log_syserr */
+
+
+/* USE_WINDOWS_API */ int
+psf_close_rsrc (SF_PRIVATE *psf)
+{
+ if (psf->hrsrc != NULL)
+ psf_close_handle (psf->hrsrc) ;
+ psf->hrsrc = NULL ;
+ return 0 ;
+} /* psf_close_rsrc */
+
+
+/* USE_WINDOWS_API */ int
+psf_set_stdio (SF_PRIVATE *psf, int mode)
+{ HANDLE handle = NULL ;
+ int error = 0 ;
+
+ switch (mode)
+ { case SFM_RDWR :
+ error = SFE_OPEN_PIPE_RDWR ;
+ break ;
+
+ case SFM_READ :
+ handle = GetStdHandle (STD_INPUT_HANDLE) ;
+ psf->do_not_close_descriptor = 1 ;
+ break ;
+
+ case SFM_WRITE :
+ handle = GetStdHandle (STD_OUTPUT_HANDLE) ;
+ psf->do_not_close_descriptor = 1 ;
+ break ;
+
+ default :
+ error = SFE_BAD_OPEN_MODE ;
+ break ;
+ } ;
+
+ psf->hfile = handle ;
+ psf->filelength = 0 ;
+
+ return error ;
+} /* psf_set_stdio */
+
+/* USE_WINDOWS_API */ void
+psf_set_file (SF_PRIVATE *psf, int fd)
+{ HANDLE handle ;
+ long osfhandle ;
+
+ osfhandle = _get_osfhandle (fd) ;
+ handle = (HANDLE) osfhandle ;
+
+ psf->hfile = handle ;
+} /* psf_set_file */
+
+/* USE_WINDOWS_API */ int
+psf_file_valid (SF_PRIVATE *psf)
+{ if (psf->hfile == NULL)
+ return SF_FALSE ;
+ if (psf->hfile == 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 ;
+ LONG lDistanceToMove, lDistanceToMoveHigh ;
+ DWORD dwMoveMethod ;
+ DWORD dwResult, 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 ;
+ } ;
+
+ lDistanceToMove = (DWORD) (offset & 0xFFFFFFFF) ;
+ lDistanceToMoveHigh = (DWORD) ((offset >> 32) & 0xFFFFFFFF) ;
+
+ dwResult = SetFilePointer (psf->hfile, lDistanceToMove, &lDistanceToMoveHigh, dwMoveMethod) ;
+
+ if (dwResult == 0xFFFFFFFF)
+ dwError = GetLastError () ;
+ else
+ dwError = NO_ERROR ;
+
+ if (dwError != NO_ERROR)
+ { psf_log_syserr (psf, dwError) ;
+ return -1 ;
+ } ;
+
+ new_position = (dwResult + ((__int64) lDistanceToMoveHigh << 32)) - 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->hfile, ((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->hfile, ((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 ;
+ LONG lDistanceToMoveLow, lDistanceToMoveHigh ;
+ DWORD dwResult, dwError ;
+
+ if (psf->virtual_io)
+ return psf->vio.tell (psf->vio_user_data) ;
+
+ if (psf->is_pipe)
+ return psf->pipeoffset ;
+
+ lDistanceToMoveLow = 0 ;
+ lDistanceToMoveHigh = 0 ;
+
+ dwResult = SetFilePointer (psf->hfile, lDistanceToMoveLow, &lDistanceToMoveHigh, FILE_CURRENT) ;
+
+ if (dwResult == 0xFFFFFFFF)
+ dwError = GetLastError () ;
+ else
+ dwError = NO_ERROR ;
+
+ if (dwError != NO_ERROR)
+ { psf_log_syserr (psf, dwError) ;
+ return -1 ;
+ } ;
+
+ pos = (dwResult + ((__int64) lDistanceToMoveHigh << 32)) ;
+
+ return pos - psf->fileoffset ;
+} /* psf_ftell */
+
+/* USE_WINDOWS_API */ static int
+psf_close_handle (HANDLE handle)
+{ 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->hfile, &(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->hfile) == 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 ;
+ DWORD dwFileSizeLow, dwFileSizeHigh, dwError = NO_ERROR ;
+
+ dwFileSizeLow = GetFileSize (handle, &dwFileSizeHigh) ;
+
+ if (dwFileSizeLow == 0xFFFFFFFF)
+ dwError = GetLastError () ;
+
+ if (dwError != NO_ERROR)
+ return (sf_count_t) -1 ;
+
+ filelen = dwFileSizeLow + ((__int64) dwFileSizeHigh << 32) ;
+
+ return filelen ;
+} /* psf_get_filelen_handle */
+
+/* USE_WINDOWS_API */ void
+psf_fsync (SF_PRIVATE *psf)
+{ FlushFileBuffers (psf->hfile) ;
+} /* psf_fsync */
+
+
+/* USE_WINDOWS_API */ int
+psf_ftruncate (SF_PRIVATE *psf, sf_count_t len)
+{ int retval = 0 ;
+ LONG lDistanceToMoveLow, lDistanceToMoveHigh ;
+ DWORD dwResult, 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 ;
+
+ lDistanceToMoveLow = (DWORD) (len & 0xFFFFFFFF) ;
+ lDistanceToMoveHigh = (DWORD) ((len >> 32) & 0xFFFFFFFF) ;
+
+ dwResult = SetFilePointer (psf->hfile, lDistanceToMoveLow, &lDistanceToMoveHigh, FILE_BEGIN) ;
+
+ if (dwResult == 0xFFFFFFFF)
+ 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->hfile) == 0)
+ { retval = -1 ;
+ psf_log_syserr (psf, GetLastError ()) ;
+ } ;
+ } ;
+
+ return retval ;
+} /* psf_ftruncate */
+
+
+#else
+/* Win32 file i/o functions implemented using Unix-style file i/o API */
+
+/* Win32 has a 64 file offset seek function:
+**
+** __int64 _lseeki64 (int handle, __int64 offset, int origin) ;
+**
+** It also has a 64 bit fstat function:
+**
+** int fstati64 (int, struct _stati64) ;
+**
+** but the fscking thing doesn't work!!!!! The file size parameter returned
+** by this function is only valid up until more data is written at the end of
+** the file. That makes this function completely 100% useless.
+*/
+
+#include <io.h>
+#include <direct.h>
+
+#ifndef HAVE_SSIZE_T
+typedef long ssize_t ;
+#endif
+
+/* Win32 */ int
+psf_fopen (SF_PRIVATE *psf, const char *pathname, int open_mode)
+{ int oflag, mode ;
+
+ switch (open_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 ;
+ break ;
+
+ case SFM_RDWR :
+ oflag = O_RDWR | O_CREAT | O_BINARY ;
+ mode = S_IRUSR | S_IWUSR | S_IRGRP ;
+ break ;
+
+ default :
+ psf->error = SFE_BAD_OPEN_MODE ;
+ return -1 ;
+ break ;
+ } ;
+
+ if (mode == 0)
+ psf->filedes = open (pathname, oflag) ;
+ else
+ psf->filedes = open (pathname, oflag, mode) ;
+
+ if (psf->filedes == -1)
+ psf_log_syserr (psf, errno) ;
+
+ return psf->filedes ;
+} /* psf_fopen */
+
+/* Win32 */ sf_count_t
+psf_fseek (SF_PRIVATE *psf, sf_count_t offset, int whence)
+{ sf_count_t new_position ;
+
+ if (psf->virtual_io)
+ return psf->vio.seek (offset, whence, psf->vio_user_data) ;
+
+ switch (whence)
+ { case SEEK_SET :
+ offset += psf->fileoffset ;
+ break ;
+
+ case SEEK_END :
+ if (psf->mode == SFM_WRITE)
+ { new_position = _lseeki64 (psf->filedes, offset, whence) ;
+
+ if (new_position < 0)
+ psf_log_syserr (psf, errno) ;
+
+ return new_position - psf->fileoffset ;
+ } ;
+
+ /* Transform SEEK_END into a SEEK_SET, ie find the file
+ ** length add the requested offset (should be <= 0) to
+ ** get the offset wrt the start of file.
+ */
+ whence = SEEK_SET ;
+ offset = _lseeki64 (psf->filedes, 0, SEEK_END) + offset ;
+ break ;
+
+ default :
+ /* No need to do anything about SEEK_CUR. */
+ break ;
+ } ;
+
+ /*
+ ** Bypass weird Win32-ism if necessary.
+ ** _lseeki64() returns an "invalid parameter" error if called with the
+ ** offset == 0 and whence == SEEK_CUR.
+ *** Use the _telli64() function instead.
+ */
+ if (offset == 0 && whence == SEEK_CUR)
+ new_position = _telli64 (psf->filedes) ;
+ else
+ new_position = _lseeki64 (psf->filedes, offset, whence) ;
+
+ if (new_position < 0)
+ psf_log_syserr (psf, errno) ;
+
+ new_position -= psf->fileoffset ;
+
+ return new_position ;
+} /* psf_fseek */
+
+/* Win32 */ 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 writes down to a sensible size. */
+ count = (items > SENSIBLE_SIZE) ? SENSIBLE_SIZE : (ssize_t) items ;
+
+ count = read (psf->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 ;
+ } ;
+
+ return total / bytes ;
+} /* psf_fread */
+
+/* Win32 */ 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 (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->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 ;
+ } ;
+
+ return total / bytes ;
+} /* psf_fwrite */
+
+/* Win32 */ sf_count_t
+psf_ftell (SF_PRIVATE *psf)
+{ sf_count_t pos ;
+
+ if (psf->virtual_io)
+ return psf->vio.tell (psf->vio_user_data) ;
+
+ pos = _telli64 (psf->filedes) ;
+
+ if (pos == ((sf_count_t) -1))
+ { psf_log_syserr (psf, errno) ;
+ return -1 ;
+ } ;
+
+ return pos - psf->fileoffset ;
+} /* psf_ftell */
+
+/* Win32 */ int
+psf_fclose (SF_PRIVATE *psf)
+{ int retval ;
+
+ while ((retval = close (psf->filedes)) == -1 && errno == EINTR)
+ /* Do nothing. */ ;
+
+ if (retval == -1)
+ psf_log_syserr (psf, errno) ;
+
+ psf->filedes = -1 ;
+
+ return retval ;
+} /* psf_fclose */
+
+/* Win32 */ 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->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 */
+
+/* Win32 */ int
+psf_is_pipe (SF_PRIVATE *psf)
+{ struct stat statbuf ;
+
+ if (psf->virtual_io)
+ return SF_FALSE ;
+
+ /* Not sure if this works. */
+ if (fstat (psf->filedes, &statbuf) == -1)
+ { psf_log_syserr (psf, errno) ;
+ /* Default to maximum safety. */
+ return SF_TRUE ;
+ } ;
+
+ /* These macros are defined in Win32/unistd.h. */
+ if (S_ISFIFO (statbuf.st_mode) || S_ISSOCK (statbuf.st_mode))
+ return SF_TRUE ;
+
+ return SF_FALSE ;
+} /* psf_checkpipe */
+
+/* Win32 */ sf_count_t
+psf_get_filelen (SF_PRIVATE *psf)
+{
+#if 0
+ /*
+ ** Windoze is SOOOOO FUCKED!!!!!!!
+ ** This code should work but doesn't. Why?
+ ** Code below does work.
+ */
+ struct _stati64 statbuf ;
+
+ if (_fstati64 (psf->filedes, &statbuf))
+ { psf_log_syserr (psf, errno) ;
+ return (sf_count_t) -1 ;
+ } ;
+
+ return statbuf.st_size ;
+#else
+ sf_count_t current, filelen ;
+
+ if (psf->virtual_io)
+ return psf->vio.get_filelen (psf->vio_user_data) ;
+
+ if ((current = _telli64 (psf->filedes)) < 0)
+ { psf_log_syserr (psf, errno) ;
+ return (sf_count_t) -1 ;
+ } ;
+
+ /*
+ ** Lets face it, windoze if FUBAR!!!
+ **
+ ** For some reason, I have to call _lseeki64() TWICE to get to the
+ ** end of the file.
+ **
+ ** This might have been avoided if windows had implemented the POSIX
+ ** standard function fsync() but NO, that would have been too easy.
+ **
+ ** I am VERY close to saying that windoze will no longer be supported
+ ** by libsndfile and changing the license to GPL at the same time.
+ */
+
+ _lseeki64 (psf->filedes, 0, SEEK_END) ;
+
+ if ((filelen = _lseeki64 (psf->filedes, 0, SEEK_END)) < 0)
+ { psf_log_syserr (psf, errno) ;
+ return (sf_count_t) -1 ;
+ } ;
+
+ if (filelen > current)
+ _lseeki64 (psf->filedes, current, SEEK_SET) ;
+
+ switch (psf->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 :
+ filelen = 0 ;
+ } ;
+
+ return filelen ;
+#endif
+} /* psf_get_filelen */
+
+/* Win32 */ 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 ;
+
+ /* The global village idiots at micorsoft decided to implement
+ ** nearly all the required 64 bit file offset functions except
+ ** for one, truncate. The fscking morons!
+ **
+ ** This is not 64 bit file offset clean. Somone needs to clean
+ ** this up.
+ */
+ if (len > 0x7FFFFFFF)
+ return -1 ;
+
+ retval = chsize (psf->filedes, len) ;
+
+ if (retval == -1)
+ psf_log_syserr (psf, errno) ;
+
+ return retval ;
+} /* psf_ftruncate */
+
+
+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 ;
+ LSF_SNPRINTF (psf->syserr, sizeof (psf->syserr), "System error : %s", strerror (error)) ;
+ } ;
+
+ return ;
+} /* psf_log_syserr */
+
+#endif
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 749740d7-ecc7-47bd-8cf7-600f31d32e6d
+*/
diff --git a/src/flac.c b/src/flac.c
new file mode 100644
index 0000000..e596b63
--- /dev/null
+++ b/src/flac.c
@@ -0,0 +1,1112 @@
+/*
+** Copyright (C) 2004, 2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+** Copyright (C) 2004 Tobias Gehrig <tgehrig@ira.uka.de>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sndfile.h"
+#include "common.h"
+
+
+#include "FLAC/include/FLAC/stream_decoder.h"
+#include "FLAC/include/FLAC/stream_encoder.h"
+
+#include "sfendian.h"
+#include "float_cast.h"
+
+/*------------------------------------------------------------------------------
+** Private static functions.
+*/
+
+#define ENC_BUFFER_SIZE 4096
+
+typedef enum
+{ PFLAC_PCM_SHORT = 0,
+ PFLAC_PCM_INT = 1,
+ PFLAC_PCM_FLOAT = 2,
+ PFLAC_PCM_DOUBLE = 3
+} PFLAC_PCM ;
+
+typedef struct
+{
+ FLAC__StreamDecoder *fsd ;
+ FLAC__StreamEncoder *fse ;
+
+ PFLAC_PCM pcmtype ;
+ void* ptr ;
+ unsigned pos, len, remain ;
+
+ const FLAC__int32 * const * wbuffer ;
+ FLAC__int32 * rbuffer [FLAC__MAX_CHANNELS] ;
+
+ FLAC__int32* encbuffer ;
+ unsigned bufferpos ;
+
+ const FLAC__Frame *frame ;
+ FLAC__bool bufferbackup ;
+} FLAC_PRIVATE ;
+
+static sf_count_t flac_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
+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, FLAC__int32 *dest, int count, int normalize) ;
+static void f2flac16_array (const float *src, FLAC__int32 *dest, int count, int normalize) ;
+static void f2flac24_array (const float *src, FLAC__int32 *dest, int count, int normalize) ;
+static void f2flac8_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize) ;
+static void f2flac16_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize) ;
+static void f2flac24_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize) ;
+static void d2flac8_array (const double *src, FLAC__int32 *dest, int count, int normalize) ;
+static void d2flac16_array (const double *src, FLAC__int32 *dest, int count, int normalize) ;
+static void d2flac24_array (const double *src, FLAC__int32 *dest, int count, int normalize) ;
+static void d2flac8_clip_array (const double *src, FLAC__int32 *dest, int count, int normalize) ;
+static void d2flac16_clip_array (const double *src, FLAC__int32 *dest, int count, int normalize) ;
+static void d2flac24_clip_array (const double *src, FLAC__int32 *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 FLAC__int32 * 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 const int legal_sample_rates [] =
+{ 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000
+} ;
+
+static void
+s2flac8_array (const short *src, FLAC__int32 *dest, int count)
+{ while (--count >= 0)
+ dest [count] = src [count] >> 8 ;
+} /* s2flac8_array */
+
+static void
+s2flac16_array (const short *src, FLAC__int32 *dest, int count)
+{ while (--count >= 0)
+ dest [count] = src [count] ;
+} /* s2flac16_array */
+
+static void
+s2flac24_array (const short *src, FLAC__int32 *dest, int count)
+{ while (--count >= 0)
+ dest [count] = src [count] << 8 ;
+} /* s2flac24_array */
+
+static void
+i2flac8_array (const int *src, FLAC__int32 *dest, int count)
+{ while (--count >= 0)
+ dest [count] = src [count] >> 24 ;
+} /* i2flac8_array */
+
+static void
+i2flac16_array (const int *src, FLAC__int32 *dest, int count)
+{
+ while (--count >= 0)
+ dest [count] = src [count] >> 16 ;
+} /* i2flac16_array */
+
+static void
+i2flac24_array (const int *src, FLAC__int32 *dest, int count)
+{ while (--count >= 0)
+ dest [count] = src [count] >> 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 FLAC__int32* const *buffer = pflac->wbuffer ;
+ unsigned i = 0, j, offset ;
+
+ if (pflac->ptr == NULL)
+ { /*
+ ** Not sure why this code is here and not elsewhere.
+ ** Removing it causes valgrind errors.
+ */
+ pflac->bufferbackup = SF_TRUE ;
+ for (i = 0 ; i < frame->header.channels ; i++)
+ { if (pflac->rbuffer [i] == NULL)
+ pflac->rbuffer [i] = calloc (frame->header.blocksize, sizeof (FLAC__int32)) ;
+ memcpy (pflac->rbuffer [i], buffer [i], frame->header.blocksize * sizeof (FLAC__int32)) ;
+ } ;
+ pflac->wbuffer = (const FLAC__int32* const*) pflac->rbuffer ;
+
+ 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 < frame->header.blocksize && pflac->remain > 0 ; i++)
+ { offset = pflac->pos + i * frame->header.channels ;
+ for (j = 0 ; j < frame->header.channels ; j++)
+ retpcm [offset + j] = buffer [j][pflac->bufferpos] >> shift ;
+ pflac->remain -= frame->header.channels ;
+ pflac->bufferpos++ ;
+ }
+ }
+ else
+ { for (i = 0 ; i < frame->header.blocksize && pflac->remain > 0 ; i++)
+ { offset = pflac->pos + i * frame->header.channels ;
+
+ if (pflac->bufferpos >= frame->header.blocksize)
+ break ;
+
+ for (j = 0 ; j < frame->header.channels ; j++)
+ retpcm [offset + j] = (buffer [j][pflac->bufferpos]) << shift ;
+
+ pflac->remain -= frame->header.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 < frame->header.blocksize && pflac->remain > 0 ; i++)
+ { offset = pflac->pos + i * frame->header.channels ;
+
+ if (pflac->bufferpos >= frame->header.blocksize)
+ break ;
+
+ for (j = 0 ; j < frame->header.channels ; j++)
+ retpcm [offset + j] = buffer [j][pflac->bufferpos] << shift ;
+ pflac->remain -= frame->header.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 < frame->header.blocksize && pflac->remain > 0 ; i++)
+ { offset = pflac->pos + i * frame->header.channels ;
+
+ if (pflac->bufferpos >= frame->header.blocksize)
+ break ;
+
+ for (j = 0 ; j < frame->header.channels ; j++)
+ retpcm [offset + j] = buffer [j][pflac->bufferpos] * norm ;
+ pflac->remain -= frame->header.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 < frame->header.blocksize && pflac->remain > 0 ; i++)
+ { offset = pflac->pos + i * frame->header.channels ;
+
+ if (pflac->bufferpos >= frame->header.blocksize)
+ break ;
+
+ for (j = 0 ; j < frame->header.channels ; j++)
+ retpcm [offset + j] = buffer [j][pflac->bufferpos] * norm ;
+ pflac->remain -= frame->header.channels ;
+ pflac->bufferpos++ ;
+ } ;
+ } ;
+ break ;
+
+ default :
+ return 0 ;
+ } ;
+
+ offset = i * frame->header.channels ;
+ pflac->pos += i * frame->header.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 FLAC__int32 * 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->bufferbackup = SF_FALSE ;
+ pflac->wbuffer = buffer ;
+
+ flac_buffer_copy (psf) ;
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE ;
+} /* sf_flac_write_callback */
+
+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 ;
+
+ switch (metadata->type)
+ { case FLAC__METADATA_TYPE_STREAMINFO :
+ 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 ;
+
+ switch (metadata->data.stream_info.bits_per_sample)
+ { case 8 :
+ psf->sf.format |= SF_FORMAT_PCM_S8 ;
+ break ;
+ case 16 :
+ psf->sf.format |= SF_FORMAT_PCM_16 ;
+ break ;
+ case 24 :
+ psf->sf.format |= SF_FORMAT_PCM_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 ;
+ } ;
+ 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 */
+
+/*------------------------------------------------------------------------------
+** 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 ;
+
+ if (psf->mode == SFM_RDWR)
+ return SFE_BAD_RDWR_FORMAT ;
+
+ if (psf->mode == SFM_READ)
+ { if ((error = flac_read_header (psf)))
+ return error ;
+ } ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE)
+ { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_FLAC)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ psf->endian = SF_ENDIAN_BIG ;
+ psf->sf.seekable = 0 ;
+
+ if ((error = flac_enc_init (psf)))
+ return error ;
+ } ;
+
+ psf->datalength = psf->filelength ;
+ psf->dataoffset = 0 ;
+ psf->blockwidth = 0 ;
+ psf->bytewidth = 1 ;
+
+ psf->container_close = flac_close ;
+ psf->seek = flac_seek ;
+ psf->command = flac_command ;
+
+ psf->blockwidth = psf->bytewidth * psf->sf.channels ;
+
+ 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 (psf->mode == SFM_WRITE)
+ { FLAC__stream_encoder_finish (pflac->fse) ;
+ FLAC__stream_encoder_delete (pflac->fse) ;
+
+ if (pflac->encbuffer)
+ free (pflac->encbuffer) ;
+ } ;
+
+ if (psf->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 ;
+ int k, found ;
+
+ found = 0 ;
+ for (k = 0 ; k < ARRAY_LEN (legal_sample_rates) ; k++)
+ if (psf->sf.samplerate == legal_sample_rates [k])
+ { found = 1 ;
+ break ;
+ } ;
+
+ if (found == 0)
+ return SFE_FLAC_BAD_SAMPLE_RATE ;
+
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ switch (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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_new ()) == NULL)
+ return SFE_FLAC_NEW_DECODER ;
+ FLAC__stream_encoder_set_channels (pflac->fse, psf->sf.channels) ;
+ FLAC__stream_encoder_set_sample_rate (pflac->fse, psf->sf.samplerate) ;
+ FLAC__stream_encoder_set_bits_per_sample (pflac->fse, bps) ;
+
+ if ((bps = 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 [bps]) ;
+ return SFE_FLAC_INIT_DECODER ;
+ } ;
+
+ if (psf->error == 0)
+ psf->dataoffset = psf_ftell (psf) ;
+ pflac->encbuffer = calloc (ENC_BUFFER_SIZE, sizeof (FLAC__int32)) ;
+
+ return psf->error ;
+} /* 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_new ()) == NULL)
+ return SFE_FLAC_NEW_DECODER ;
+
+ 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) ;
+
+ if (psf->error == 0)
+ { 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 * UNUSED (psf), int UNUSED (command), void * UNUSED (data), int UNUSED (datasize))
+{
+ return 0 ;
+} /* flac_command */
+
+int
+flac_init (SF_PRIVATE *psf)
+{
+ if (psf->mode == SFM_RDWR)
+ return SFE_BAD_MODE_RW ;
+
+ if (psf->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->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 ;
+ } ;
+
+ 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 ;
+
+ return 0 ;
+} /* flac_init */
+
+static unsigned
+flac_read_loop (SF_PRIVATE *psf, unsigned len)
+{ FLAC_PRIVATE* pflac = (FLAC_PRIVATE*) psf->codec_data ;
+
+ pflac->pos = 0 ;
+ pflac->len = len ;
+ pflac->remain = len ;
+ if (pflac->frame != NULL && pflac->bufferpos < pflac->frame->header.blocksize)
+ flac_buffer_copy (psf) ;
+
+ while (pflac->pos < pflac->len)
+ { if (FLAC__stream_decoder_process_single (pflac->fsd) == 0)
+ break ;
+ if (FLAC__stream_decoder_get_state (pflac->fsd) >= FLAC__STREAM_DECODER_END_OF_STREAM)
+ 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 > 0x1000000) ? 0x1000000 : (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 > 0x1000000) ? 0x1000000 : (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 > 0x1000000) ? 0x1000000 : (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 > 0x1000000) ? 0x1000000 : (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 *, FLAC__int32 *, int) ;
+ int bufferlen, writecount, thiswrite ;
+ sf_count_t total = 0 ;
+ FLAC__int32* buffer = pflac->encbuffer ;
+
+ switch (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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 (FLAC__int32) * 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 *, FLAC__int32 *, int) ;
+ int bufferlen, writecount, thiswrite ;
+ sf_count_t total = 0 ;
+ FLAC__int32* buffer = pflac->encbuffer ;
+
+ switch (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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 (FLAC__int32) * 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 *, FLAC__int32 *, int, int) ;
+ int bufferlen, writecount, thiswrite ;
+ sf_count_t total = 0 ;
+ FLAC__int32* buffer = pflac->encbuffer ;
+
+ switch (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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 (FLAC__int32) * 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, FLAC__int32 *dest, int count, int normalize)
+{ float normfact, scaled_value ;
+
+ normfact = normalize ? (8.0 * 0x10) : 1.0 ;
+
+ while (--count >= 0)
+ { scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7F))
+ { dest [count] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10))
+ { dest [count] = 0x80 ;
+ continue ;
+ } ;
+ dest [count] = lrintf (scaled_value) ;
+ } ;
+
+ return ;
+} /* f2flac8_clip_array */
+
+static void
+f2flac16_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize)
+{
+ float normfact, scaled_value ;
+
+ normfact = normalize ? (8.0 * 0x1000) : 1.0 ;
+
+ while (--count >= 0) {
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFF)) {
+ dest [count] = 0x7FFF ;
+ continue ;
+ }
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x1000)) {
+ dest [count] = 0x8000 ;
+ continue ;
+ }
+ dest [count] = lrintf (scaled_value) ;
+ }
+} /* f2flac16_clip_array */
+
+static void
+f2flac24_clip_array (const float *src, FLAC__int32 *dest, int count, int normalize)
+{ float normfact, scaled_value ;
+
+ normfact = normalize ? (8.0 * 0x100000) : 1.0 ;
+
+ while (--count >= 0)
+ { scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFF))
+ { dest [count] = 0x7FFFFF ;
+ continue ;
+ } ;
+
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x100000))
+ { dest [count] = 0x800000 ;
+ continue ;
+ }
+ dest [count] = lrintf (scaled_value) ;
+ } ;
+
+ return ;
+} /* f2flac24_clip_array */
+
+static void
+f2flac8_array (const float *src, FLAC__int32 *dest, int count, int normalize)
+{ float normfact = normalize ? (1.0 * 0x7F) : 1.0 ;
+
+ while (--count >= 0)
+ dest [count] = lrintf (src [count] * normfact) ;
+} /* f2flac8_array */
+
+static void
+f2flac16_array (const float *src, FLAC__int32 *dest, int count, int normalize)
+{ float normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ;
+
+ while (--count >= 0)
+ dest [count] = lrintf (src [count] * normfact) ;
+} /* f2flac16_array */
+
+static void
+f2flac24_array (const float *src, FLAC__int32 *dest, int count, int normalize)
+{ float normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ;
+
+ while (--count >= 0)
+ dest [count] = lrintf (src [count] * 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 *, FLAC__int32 *, int, int) ;
+ int bufferlen, writecount, thiswrite ;
+ sf_count_t total = 0 ;
+ FLAC__int32* buffer = pflac->encbuffer ;
+
+ switch (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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 (FLAC__int32) * 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, FLAC__int32 *dest, int count, int normalize)
+{ double normfact, scaled_value ;
+
+ normfact = normalize ? (8.0 * 0x10) : 1.0 ;
+
+ while (--count >= 0)
+ { scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7F))
+ { dest [count] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10))
+ { dest [count] = 0x80 ;
+ continue ;
+ } ;
+ dest [count] = lrint (scaled_value) ;
+ } ;
+
+ return ;
+} /* d2flac8_clip_array */
+
+static void
+d2flac16_clip_array (const double *src, FLAC__int32 *dest, int count, int normalize)
+{ double normfact, scaled_value ;
+
+ normfact = normalize ? (8.0 * 0x1000) : 1.0 ;
+
+ while (--count >= 0)
+ { scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFF))
+ { dest [count] = 0x7FFF ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x1000))
+ { dest [count] = 0x8000 ;
+ continue ;
+ } ;
+ dest [count] = lrint (scaled_value) ;
+ } ;
+
+ return ;
+} /* d2flac16_clip_array */
+
+static void
+d2flac24_clip_array (const double *src, FLAC__int32 *dest, int count, int normalize)
+{ double normfact, scaled_value ;
+
+ normfact = normalize ? (8.0 * 0x100000) : 1.0 ;
+
+ while (--count >= 0)
+ { scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFF))
+ { dest [count] = 0x7FFFFF ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x100000))
+ { dest [count] = 0x800000 ;
+ continue ;
+ } ;
+ dest [count] = lrint (scaled_value) ;
+ } ;
+
+ return ;
+} /* d2flac24_clip_array */
+
+static void
+d2flac8_array (const double *src, FLAC__int32 *dest, int count, int normalize)
+{ double normfact = normalize ? (1.0 * 0x7F) : 1.0 ;
+
+ while (--count >= 0)
+ dest [count] = lrint (src [count] * normfact) ;
+} /* d2flac8_array */
+
+static void
+d2flac16_array (const double *src, FLAC__int32 *dest, int count, int normalize)
+{ double normfact = normalize ? (1.0 * 0x7FFF) : 1.0 ;
+
+ while (--count >= 0)
+ dest [count] = lrint (src [count] * normfact) ;
+} /* d2flac16_array */
+
+static void
+d2flac24_array (const double *src, FLAC__int32 *dest, int count, int normalize)
+{ double normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ;
+
+ while (--count >= 0)
+ dest [count] = lrint (src [count] * 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->mode == SFM_READ)
+ { FLAC__uint64 position ;
+ if (FLAC__stream_decoder_seek_absolute (pflac->fsd, offset))
+ { FLAC__stream_decoder_get_decode_position (pflac->fsd, &position) ;
+ return offset ;
+ } ;
+
+ return ((sf_count_t) -1) ;
+ } ;
+
+ /* Seeking in write mode not yet supported. */
+ psf->error = SFE_BAD_SEEK ;
+
+ return ((sf_count_t) -1) ;
+} /* flac_seek */
+
diff --git a/src/float32.c b/src/float32.c
new file mode 100644
index 0000000..b3e8725
--- /dev/null
+++ b/src/float32.c
@@ -0,0 +1,995 @@
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+#include "float_cast.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 ;
+
+ float_caps = float32_get_capability (psf) ;
+
+ psf->blockwidth = sizeof (float) * psf->sf.channels ;
+
+ if (psf->mode == SFM_READ || psf->mode == SFM_RDWR)
+ { switch (psf->endian + float_caps)
+ { case (SF_ENDIAN_BIG + FLOAT_CAN_RW_BE) :
+ psf->float_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->float_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->float_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->float_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->float_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->float_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->float_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->float_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->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { switch (psf->endian + float_caps)
+ { case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_LE) :
+ psf->float_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->float_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->float_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->float_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->float_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->float_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->float_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->float_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->datalength / psf->blockwidth ;
+
+ return 0 ;
+} /* float32_init */
+
+float
+float32_be_read (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 *= (1 << exponent) ;
+ else if (exponent < 0)
+ fvalue /= (1 << abs (exponent)) ;
+
+ return fvalue ;
+} /* float32_be_read */
+
+float
+float32_le_read (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 *= (1 << exponent) ;
+ else if (exponent < 0)
+ fvalue /= (1 << 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)
+{
+ while (--count >= 0)
+ { dest [count] = lrintf (scale * src [count]) ;
+ } ;
+} /* f2s_array */
+
+static void
+f2s_clip_array (const float *src, int count, short *dest, float scale)
+{ while (--count >= 0)
+ { float tmp = scale * src [count] ;
+
+ if (CPU_CLIPS_POSITIVE == 0 && tmp > 32767.0)
+ dest [count] = SHRT_MAX ;
+ else if (CPU_CLIPS_NEGATIVE == 0 && tmp < 32768.0)
+ dest [count] = SHRT_MIN ;
+ else
+ dest [count] = lrintf (tmp) ;
+ } ;
+} /* f2s_clip_array */
+
+static inline void
+f2i_array (const float *src, int count, int *dest, float scale)
+{ while (--count >= 0)
+ { dest [count] = lrintf (scale * src [count]) ;
+ } ;
+} /* f2i_array */
+
+static inline void
+f2i_clip_array (const float *src, int count, int *dest, float scale)
+{ while (--count >= 0)
+ { float tmp = scale * src [count] ;
+
+ if (CPU_CLIPS_POSITIVE == 0 && tmp > (1.0 * INT_MAX))
+ dest [count] = INT_MAX ;
+ else if (CPU_CLIPS_NEGATIVE == 0 && tmp < (-1.0 * INT_MAX))
+ dest [count] = INT_MIN ;
+ else
+ dest [count] = lrintf (tmp) ;
+ } ;
+} /* f2i_clip_array */
+
+static inline void
+f2d_array (const float *src, int count, double *dest)
+{ while (--count >= 0)
+ { dest [count] = src [count] ;
+ } ;
+} /* f2d_array */
+
+static inline void
+s2f_array (const short *src, float *dest, int count)
+{ while (--count >= 0)
+ { dest [count] = src [count] ;
+ } ;
+
+} /* s2f_array */
+
+static inline void
+i2f_array (const int *src, float *dest, int count)
+{ while (--count >= 0)
+ { dest [count] = src [count] ;
+ } ;
+} /* i2f_array */
+
+static inline void
+d2f_array (const double *src, float *dest, int count)
+{ while (--count >= 0)
+ { dest [count] = src [count] ;
+ } ;
+} /* d2f_array */
+
+/*----------------------------------------------------------------------------------------------
+*/
+
+static sf_count_t
+host_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
+{ 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 (psf->u.fbuf) ;
+ scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
+
+/* Fix me : Need lef2s_array */
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ f2s_array (psf->u.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)
+{ 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 (psf->u.fbuf) ;
+ scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ convert (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ if (psf->float_endswap != SF_TRUE)
+ return psf_fread (ptr, sizeof (float), len, psf) ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
+
+ endswap_int_copy ((int*) (ptr + total), psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+/* Fix me : Need lef2d_array */
+ f2d_array (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2f_array (ptr + total, psf->u.fbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2f_array (ptr + total, psf->u.fbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ if (psf->peak_info)
+ float32_peak_update (psf, ptr, len, 0) ;
+
+ if (psf->float_endswap != SF_TRUE)
+ return psf_fwrite (ptr, sizeof (float), len, psf) ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+
+ endswap_int_copy (psf->u.ibuf, (const int*) (ptr + total), bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+
+ d2f_array (ptr + total, psf->u.fbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+ float scale ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+ scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ bf2f_array (psf->u.fbuf, bufferlen) ;
+
+ f2s_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+ float scale ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+ scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ bf2f_array (psf->u.fbuf, bufferlen) ;
+
+ f2i_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ /* FIX THIS */
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ bf2f_array (psf->u.fbuf, bufferlen) ;
+
+ memcpy (ptr + total, psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.fbuf, sizeof (float), bufferlen, psf) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ bf2f_array (psf->u.fbuf, bufferlen) ;
+
+ f2d_array (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2f_array (ptr + total, psf->u.fbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
+
+ f2bf_array (psf->u.fbuf, bufferlen) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2f_array (ptr + total, psf->u.fbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
+
+ f2bf_array (psf->u.fbuf, bufferlen) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ /* FIX THIS */
+ if (psf->peak_info)
+ float32_peak_update (psf, ptr, len, 0) ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+
+ memcpy (psf->u.fbuf, ptr + total, bufferlen * sizeof (float)) ;
+
+ f2bf_array (psf->u.fbuf, bufferlen) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.fbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ d2f_array (ptr + total, psf->u.fbuf, bufferlen) ;
+
+ if (psf->peak_info)
+ float32_peak_update (psf, psf->u.fbuf, bufferlen, total / psf->sf.channels) ;
+
+ f2bf_array (psf->u.fbuf, bufferlen) ;
+
+ if (psf->float_endswap == SF_TRUE)
+ endswap_int_array (psf->u.ibuf, bufferlen) ;
+
+ writecount = psf_fwrite (psf->u.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)
+{ while (--count >= 0)
+ { buffer [count] = FLOAT32_READ ((unsigned char *) (buffer + count)) ;
+ } ;
+} /* bf2f_array */
+
+static void
+f2bf_array (float *buffer, int count)
+{ while (--count >= 0)
+ { FLOAT32_WRITE (buffer [count], (unsigned char*) (buffer + count)) ;
+ } ;
+} /* f2bf_array */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: b6c34917-488c-4145-9648-f4371fc4c889
+*/
diff --git a/src/float_cast.h b/src/float_cast.h
new file mode 100644
index 0000000..099670a
--- /dev/null
+++ b/src/float_cast.h
@@ -0,0 +1,262 @@
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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.
+*/
+
+/* Version 1.4 */
+
+#ifndef FLOAT_CAST_HEADER
+#define FLOAT_CAST_HEADER
+
+/*============================================================================
+** On Intel Pentium processors (especially PIII and probably P4), converting
+** from float to int is very slow. To meet the C specs, the code produced by
+** most C compilers targeting Pentium needs to change the FPU rounding mode
+** before the float to int conversion is performed.
+**
+** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
+** is this flushing of the pipeline which is so slow.
+**
+** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
+** llrint and llrintf which fix this problem as a side effect.
+**
+** On Unix-like systems, the configure process should have detected the
+** presence of these functions. If they weren't found we have to replace them
+** here with a standard C cast.
+*/
+
+/*
+** The C99 prototypes for lrint and lrintf are as follows:
+**
+** long int lrintf (float x) ;
+** long int lrint (double x) ;
+*/
+
+#include "sfconfig.h"
+
+/*
+** The presence of the required functions are detected during the configure
+** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
+** the sfconfig.h file.
+*/
+
+#define HAVE_LRINT_REPLACEMENT 0
+
+#if (HAVE_LRINT && HAVE_LRINTF)
+
+ /*
+ ** These defines enable functionality introduced with the 1999 ISO C
+ ** standard. They must be defined before the inclusion of math.h to
+ ** engage them. If optimisation is enabled, these functions will be
+ ** inlined. With optimisation switched off, you have to link in the
+ ** maths library using -lm.
+ */
+
+ #define _ISOC9X_SOURCE 1
+ #define _ISOC99_SOURCE 1
+
+ #define __USE_ISOC9X 1
+ #define __USE_ISOC99 1
+
+ #include <math.h>
+
+#elif (defined (__CYGWIN__))
+
+ #include <math.h>
+
+ #undef HAVE_LRINT_REPLACEMENT
+ #define HAVE_LRINT_REPLACEMENT 1
+
+ #undef lrint
+ #undef lrintf
+
+ #define lrint double2int
+ #define lrintf float2int
+
+ /*
+ ** The native CYGWIN lrint and lrintf functions are buggy:
+ ** http://sourceware.org/ml/cygwin/2005-06/msg00153.html
+ ** http://sourceware.org/ml/cygwin/2005-09/msg00047.html
+ ** and slow.
+ ** These functions (pulled from the Public Domain MinGW math.h header)
+ ** replace the native versions.
+ */
+
+ static inline long double2int (double in)
+ { long retval ;
+
+ __asm__ __volatile__
+ ( "fistpl %0"
+ : "=m" (retval)
+ : "t" (in)
+ : "st"
+ ) ;
+
+ return retval ;
+ } /* double2int */
+
+ static inline long float2int (float in)
+ { long retval ;
+
+ __asm__ __volatile__
+ ( "fistpl %0"
+ : "=m" (retval)
+ : "t" (in)
+ : "st"
+ ) ;
+
+ return retval ;
+ } /* float2int */
+
+#elif (defined (WIN32) || defined (_WIN32))
+
+ #undef HAVE_LRINT_REPLACEMENT
+ #define HAVE_LRINT_REPLACEMENT 1
+
+ #include <math.h>
+
+ /*
+ ** Win32 doesn't seem to have these functions.
+ ** Therefore implement inline versions of these functions here.
+ */
+
+ __inline long int
+ lrint (double flt)
+ { int intgr ;
+
+ _asm
+ { fld flt
+ fistp intgr
+ } ;
+
+ return intgr ;
+ }
+
+ __inline long int
+ lrintf (float flt)
+ { int intgr ;
+
+ _asm
+ { fld flt
+ fistp intgr
+ } ;
+
+ return intgr ;
+ }
+
+#elif (defined (__MWERKS__) && defined (macintosh))
+
+ /* This MacOS 9 solution was provided by Stephane Letz */
+
+ #undef HAVE_LRINT_REPLACEMENT
+ #define HAVE_LRINT_REPLACEMENT 1
+ #include <math.h>
+
+ #undef lrint
+ #undef lrintf
+
+ #define lrint double2int
+ #define lrintf float2int
+
+ inline int
+ float2int (register float in)
+ { long res [2] ;
+
+ asm
+ { fctiw in, in
+ stfd in, res
+ }
+ return res [1] ;
+ } /* float2int */
+
+ inline int
+ double2int (register double in)
+ { long res [2] ;
+
+ asm
+ { fctiw in, in
+ stfd in, res
+ }
+ return res [1] ;
+ } /* double2int */
+
+#elif (defined (__MACH__) && defined (__APPLE__))
+
+ /* For Apple MacOSX. */
+
+ #undef HAVE_LRINT_REPLACEMENT
+ #define HAVE_LRINT_REPLACEMENT 1
+ #include <math.h>
+
+ #undef lrint
+ #undef lrintf
+
+ #define lrint double2int
+ #define lrintf float2int
+
+ inline static long
+ float2int (register float in)
+ { int res [2] ;
+
+ __asm__ __volatile__
+ ( "fctiw %1, %1\n\t"
+ "stfd %1, %0"
+ : "=m" (res) /* Output */
+ : "f" (in) /* Input */
+ : "memory"
+ ) ;
+
+ return res [1] ;
+ } /* lrintf */
+
+ inline static long
+ double2int (register double in)
+ { int res [2] ;
+
+ __asm__ __volatile__
+ ( "fctiw %1, %1\n\t"
+ "stfd %1, %0"
+ : "=m" (res) /* Output */
+ : "f" (in) /* Input */
+ : "memory"
+ ) ;
+
+ return res [1] ;
+ } /* lrint */
+
+#else
+ #ifndef __sgi
+ #warning "Don't have the functions lrint() and lrintf()."
+ #warning "Replacing these functions with a standard C cast."
+ #endif
+
+ #include <math.h>
+
+ #define lrint(dbl) ((long) (dbl))
+ #define lrintf(flt) ((long) (flt))
+
+#endif
+
+
+#endif /* FLOAT_CAST_HEADER */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 42db1693-ff61-4051-bac1-e4d24c4e30b7
+*/
diff --git a/src/g72x.c b/src/g72x.c
new file mode 100644
index 0000000..a33a926
--- /dev/null
+++ b/src/g72x.c
@@ -0,0 +1,611 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "float_cast.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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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->blockwidth = psf->bytewidth = 1 ;
+
+ 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->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 = pg72x->blocks_total * pg72x->samplesperblock ;
+
+ psf_g72x_decode_block (psf, pg72x) ;
+ }
+ else if (psf->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)
+{ 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 = psf->u.sbuf ;
+ bufferlen = SF_BUFFER_LEN / sizeof (short) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : len ;
+ count = g72x_read_block (psf, pg72x, sptr, readcount) ;
+
+ for (k = 0 ; k < readcount ; k++)
+ ptr [total + k] = 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)
+{ 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 = psf->u.sbuf ;
+ bufferlen = SF_BUFFER_LEN / sizeof (short) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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)
+{ 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 = psf->u.sbuf ;
+ bufferlen = SF_BUFFER_LEN / sizeof (short) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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->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)
+{ 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 = psf->u.sbuf ;
+ bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : 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)
+{ 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 = psf->u.sbuf ;
+ bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = 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)
+{ 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 = psf->u.sbuf ;
+ bufferlen = ((SF_BUFFER_LEN / psf->blockwidth) * psf->blockwidth) / sizeof (short) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = 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->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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 3cc5439e-7247-486b-b2e6-11a4affa5744
+*/
diff --git a/src/gsm610.c b/src/gsm610.c
new file mode 100644
index 0000000..748f2d4
--- /dev/null
+++ b/src/gsm610.c
@@ -0,0 +1,626 @@
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "float_cast.h"
+#include "common.h"
+#include "wav_w64.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 [WAV_W64_GSM610_SAMPLES] ;
+ unsigned char block [WAV_W64_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->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 (psf->sf.format & SF_FORMAT_TYPEMASK)
+ { 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 = WAV_W64_GSM610_SAMPLES ;
+ pgsm610->blocksize = WAV_W64_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->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 = pgsm610->samplesperblock * pgsm610->blocks ;
+
+ 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->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, WAV_W64_GSM610_SAMPLES * sizeof (short)) ;
+ return 1 ;
+ } ;
+
+ if ((k = psf_fread (pgsm610->block, 1, WAV_W64_GSM610_BLOCKSIZE, psf)) != WAV_W64_GSM610_BLOCKSIZE)
+ psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, WAV_W64_GSM610_BLOCKSIZE) ;
+
+ if (gsm_decode (pgsm610->gsm_data, pgsm610->block, pgsm610->samples) < 0)
+ { psf_log_printf (psf, "Error from gsm_decode() on frame : %d\n", pgsm610->blockcount) ;
+ return 0 ;
+ } ;
+
+ if (gsm_decode (pgsm610->gsm_data, pgsm610->block + (WAV_W64_GSM610_BLOCKSIZE + 1) / 2, pgsm610->samples + WAV_W64_GSM610_SAMPLES / 2) < 0)
+ { psf_log_printf (psf, "Error from 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, GSM610_SAMPLES * sizeof (short)) ;
+ return 1 ;
+ } ;
+
+ if ((k = 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 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : len ;
+ count = gsm610_read_block (psf, pgsm610, sptr, readcount) ;
+ for (k = 0 ; k < readcount ; k++)
+ ptr [total + k] = 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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 ((psf->sf.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAV ||
+ (psf->sf.format & SF_FORMAT_TYPEMASK) == 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->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 = 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, WAV_W64_GSM610_SAMPLES * sizeof (short)) ;
+
+ 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+WAV_W64_GSM610_SAMPLES/2, pgsm610->block+WAV_W64_GSM610_BLOCKSIZE/2) ;
+
+ /* Write the block to disk. */
+ if ((k = psf_fwrite (pgsm610->block, 1, WAV_W64_GSM610_BLOCKSIZE, psf)) != WAV_W64_GSM610_BLOCKSIZE)
+ psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", k, WAV_W64_GSM610_BLOCKSIZE) ;
+
+ pgsm610->samplecount = 0 ;
+ pgsm610->blockcount ++ ;
+
+ /* Set samples to zero for next block. */
+ memset (pgsm610->samples, 0, WAV_W64_GSM610_SAMPLES * sizeof (short)) ;
+
+ 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = lrintf (normfact * ptr [total + k]) ;
+ count = gsm610_write_block (psf, pgsm610, sptr, writecount) ;
+
+ total += count ;
+ len -= writecount ;
+ } ;
+ 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = 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->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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 8575187d-af4f-4acf-b9dd-6ff705628345
+*/
diff --git a/src/htk.c b/src/htk.c
new file mode 100644
index 0000000..716868b
--- /dev/null
+++ b/src/htk.c
@@ -0,0 +1,225 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = htk_read_header (psf)))
+ return error ;
+ } ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != 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->mode == SFM_WRITE || psf->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 [0] = 0 ;
+ psf->headindex = 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", sample_count, sample_period, 0x20000) ;
+
+ /* Header construction complete so write it out. */
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ 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 ;
+ 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) ;
+
+ 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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: c350e972-082e-4c20-8934-03391a723560
+*/
diff --git a/src/ima_adpcm.c b/src/ima_adpcm.c
new file mode 100644
index 0000000..49ffabe
--- /dev/null
+++ b/src/ima_adpcm.c
@@ -0,0 +1,976 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "float_cast.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 ;
+#if HAVE_FLEXIBLE_ARRAY
+ short data [] ; /* ISO C99 struct flexible array. */
+#else
+ short data [0] ; /* This is a hack and might not work. */
+#endif
+} 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 ima_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) ;
+
+static int ima_close (SF_PRIVATE *psf) ;
+
+static int wav_w64_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima) ;
+static int wav_w64_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) ;
+
+
+/*============================================================================================
+** IMA ADPCM Reader initialisation function.
+*/
+
+int
+wav_w64_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->mode == SFM_RDWR)
+ return SFE_BAD_MODE_RW ;
+
+ if (psf->mode == SFM_READ)
+ if ((error = ima_reader_init (psf, blockalign, samplesperblock)))
+ return error ;
+
+ if (psf->mode == SFM_WRITE)
+ if ((error = ima_writer_init (psf, blockalign)))
+ return error ;
+
+ psf->codec_close = ima_close ;
+ psf->seek = ima_seek ;
+
+ return 0 ;
+} /* wav_w64_ima_init */
+
+int
+aiff_ima_init (SF_PRIVATE *psf, int blockalign, int samplesperblock)
+{ int error ;
+
+ if (psf->mode == SFM_RDWR)
+ return SFE_BAD_MODE_RW ;
+
+ if (psf->mode == SFM_READ)
+ if ((error = ima_reader_init (psf, blockalign, samplesperblock)))
+ return error ;
+
+ if (psf->mode == SFM_WRITE)
+ if ((error = ima_writer_init (psf, blockalign)))
+ return error ;
+
+ psf->codec_close = ima_close ;
+
+ 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->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->mode != SFM_READ)
+ return SFE_BAD_MODE_RW ;
+
+ pimasize = sizeof (IMA_ADPCM_PRIVATE) + blockalign * psf->sf.channels + 3 * psf->sf.channels * samplesperblock ;
+
+ if (! (pima = malloc (pimasize)))
+ return SFE_MALLOC_FAILED ;
+
+ psf->codec_data = (void*) pima ;
+
+ memset (pima, 0, pimasize) ;
+
+ 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 (psf->datalength % pima->blocksize)
+ pima->blocks = psf->datalength / pima->blocksize + 1 ;
+ else
+ pima->blocks = psf->datalength / pima->blocksize ;
+
+ switch (psf->sf.format & SF_FORMAT_TYPEMASK)
+ { 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, "*** Warning : samplesperblock should be %d.\n", count) ;
+
+ pima->decode_block = wav_w64_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 ;
+ break ;
+ } ;
+
+ 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 ;
+ short step, stepindx, predictor, *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 = 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 ;
+
+ predictor = (blockdata [0] << 8) | (blockdata [1] & 0x80) ;
+ stepindx = blockdata [1] & 0x7F ;
+
+{
+if (count < 5)
+printf ("\nchan: %d predictor: %d stepindx: %d (%d)\n",
+ chan, predictor, stepindx, ima_step_size [stepindx]) ;
+}
+ /* FIXME : Do this a better way. */
+ if (stepindx < 0) stepindx = 0 ;
+ else if (stepindx > 88) stepindx = 88 ;
+
+ /*
+ ** 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] ;
+
+ if (stepindx < 0) stepindx = 0 ;
+ else if (stepindx > 88) stepindx = 88 ;
+
+ 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 ;
+
+ pima->samples [pima->channels * k + chan] = predictor ;
+ } ;
+ } ;
+
+if (count < 5)
+{
+ for (k = 0 ; k < 10 ; k++)
+ printf ("% 7d,", pima->samples [k]) ;
+ puts ("") ;
+}
+
+ 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 ;
+
+static int count = 0 ;
+if (0 && count == 0)
+{ pima->samples [0] = 0 ;
+ printf ("blocksize : %d\n", pima->blocksize) ;
+ printf ("pima->stepindx [0] : %d\n", pima->stepindx [0]) ;
+ }
+count ++ ;
+
+ /* Encode the block header. */
+ for (chan = 0 ; chan < pima->channels ; chan ++)
+ { blockindx = chan * pima->blocksize ;
+
+ pima->block [blockindx] = (pima->samples [chan] >> 8) & 0xFF ;
+ pima->block [blockindx + 1] = (pima->samples [chan] & 0x80) + (pima->stepindx [chan] & 0x7F) ;
+
+ pima->previous [chan] = pima->samples [chan] ;
+ } ;
+
+ /* Encode second and later samples for every block as a 4 bit value. */
+ 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] ;
+ if (pima->stepindx [chan] < 0)
+ pima->stepindx [chan] = 0 ;
+ else if (pima->stepindx [chan] > 88)
+ pima->stepindx [chan] = 88 ;
+
+ pima->samples [k] = bytecode ;
+ } ;
+
+ /* Pack the 4 bit encoded samples. */
+
+ for (chan = 0 ; chan < pima->channels ; chan ++)
+ { for (indx = pima->channels ; indx < pima->channels * pima->samplesperblock ; indx += 2 * pima->channels)
+ { blockindx = chan * pima->blocksize + 2 + indx / 2 ;
+
+if (0 && count ++ < 5)
+ printf ("chan: %d blockindx: %3d indx: %3d\n", chan, blockindx, indx) ;
+
+ pima->block [blockindx] = pima->samples [indx] & 0x0F ;
+ pima->block [blockindx] |= (pima->samples [indx + pima->channels] << 4) & 0xF0 ;
+ } ;
+ } ;
+
+ /* Write the block to disk. */
+
+ if ((k = 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->samples, 0, pima->channels * pima->samplesperblock * sizeof (short)) ;
+ pima->samplecount = 0 ;
+ pima->blockcount ++ ;
+
+ return 1 ;
+} /* aiff_ima_encode_block */
+
+static int
+wav_w64_ima_decode_block (SF_PRIVATE *psf, IMA_ADPCM_PRIVATE *pima)
+{ int chan, k, current, blockindx, indx, indxstart, diff ;
+ short step, bytecode, stepindx [2] ;
+
+ pima->blockcount ++ ;
+ pima->samplecount = 0 ;
+
+ if (pima->blockcount > pima->blocks)
+ { memset (pima->samples, 0, pima->samplesperblock * pima->channels * sizeof (short)) ;
+ return 1 ;
+ } ;
+
+ if ((k = 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++)
+ { current = pima->block [chan*4] | (pima->block [chan*4+1] << 8) ;
+ if (current & 0x8000)
+ current -= 0x10000 ;
+
+ stepindx [chan] = pima->block [chan*4+2] ;
+ if (stepindx [chan] < 0)
+ stepindx [chan] = 0 ;
+ else if (stepindx [chan] > 88)
+ stepindx [chan] = 88 ;
+
+ if (pima->block [chan*4+3] != 0)
+ psf_log_printf (psf, "IMA ADPCM synchronisation error.\n") ;
+
+ pima->samples [chan] = current ;
+ } ;
+
+ /*
+ ** 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]] ;
+ current = 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 ;
+
+ current += diff ;
+
+ if (current > 32767)
+ current = 32767 ;
+ else if (current < -32768)
+ current = -32768 ;
+
+ stepindx [chan] += ima_indx_adjust [bytecode] ;
+
+ if (stepindx [chan] < 0)
+ stepindx [chan] = 0 ;
+ else if (stepindx [chan] > 88)
+ stepindx [chan] = 88 ;
+
+ pima->samples [k] = current ;
+ } ;
+
+ return 1 ;
+} /* wav_w64_ima_decode_block */
+
+static int
+wav_w64_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] ;
+ if (pima->stepindx [chan] < 0)
+ pima->stepindx [chan] = 0 ;
+ else if (pima->stepindx [chan] > 88)
+ pima->stepindx [chan] = 88 ;
+
+ 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 = 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 ;
+} /* wav_w64_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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.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] = ((int) 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.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
+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 ;
+ 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 ;
+} /* 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->mode != SFM_WRITE)
+ return SFE_BAD_MODE_RW ;
+
+ samplesperblock = 2 * (blockalign - 4 * psf->sf.channels) / psf->sf.channels + 1 ;
+
+ 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 (psf->sf.format & SF_FORMAT_TYPEMASK)
+ { case SF_FORMAT_WAV :
+ case SF_FORMAT_W64 :
+ pima->encode_block = wav_w64_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 ;
+ break ;
+ } ;
+
+ 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : (int) len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : (int) len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = 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 */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 75a54b82-ad18-4758-9933-64e00a7f24e0
+*/
diff --git a/src/interleave.c b/src/interleave.c
new file mode 100644
index 0000000..7c18bd4
--- /dev/null
+++ b/src/interleave.c
@@ -0,0 +1,306 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdlib.h>
+
+#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->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 *psf, int mode, sf_count_t samples_from_start)
+{ psf = psf ; mode = mode ;
+
+ /*
+ ** Do nothing here. This is a place holder to prevent the default
+ ** seek function from being called.
+ */
+
+ return samples_from_start ;
+} /* interleave_seek */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 82314e13-0225-4408-a2f2-e6dab3f38904
+*/
diff --git a/src/ircam.c b/src/ircam.c
new file mode 100644
index 0000000..7df3848
--- /dev/null
+++ b/src/ircam.c
@@ -0,0 +1,329 @@
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = ircam_read_header (psf)))
+ return error ;
+ } ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_IRCAM)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+ 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 > 256)
+ { psf_binheader_readf (psf, "Epmf44", 0, &marker, &samplerate, &(psf->sf.channels), &encoding) ;
+
+ /* Sanity checking for endian-ness detection. */
+ if (psf->sf.channels > 256)
+ { 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 (psf->sf.format & SF_FORMAT_SUBMASK) ;
+
+ if (encoding == 0)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ /* Reset the current header length to zero. */
+ psf->header [0] = 0 ;
+ psf->headindex = 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", IRCAM_02B_MARKER, samplerate) ;
+ psf_binheader_writef (psf, "E44", psf->sf.channels, encoding) ;
+ break ;
+
+ case SF_ENDIAN_LITTLE :
+ psf_binheader_writef (psf, "emf", IRCAM_03L_MARKER, samplerate) ;
+ psf_binheader_writef (psf, "e44", psf->sf.channels, encoding) ;
+ break ;
+
+ default : return SFE_BAD_OPEN_FORMAT ;
+ } ;
+
+ psf_binheader_writef (psf, "z", (size_t) (IRCAM_DATA_OFFSET - psf->headindex)) ;
+
+ /* Header construction complete so write it out. */
+ psf_fwrite (psf->header, psf->headindex, 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: f2714ab8-f286-4c94-9740-edaf673a1c71
+*/
diff --git a/src/macbinary3.c b/src/macbinary3.c
new file mode 100644
index 0000000..66fe64d
--- /dev/null
+++ b/src/macbinary3.c
@@ -0,0 +1,52 @@
+/*
+** Copyright (C) 2003-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdlib.h>
+#include <string.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+
+#if (OS_IS_MACOSX == 1)
+
+int
+macbinary3_open (SF_PRIVATE * UNUSED (psf))
+{
+ return 0 ;
+} /* macbinary3_open */
+
+#else
+
+int
+macbinary3_open (SF_PRIVATE * UNUSED (psf))
+{
+ return 0 ;
+} /* macbinary3_open */
+
+#endif /* OS_IS_MACOSX */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: c397a7d7-1a31-4349-9684-bd29ef06211e
+*/
diff --git a/src/macos.c b/src/macos.c
new file mode 100644
index 0000000..c2ca593
--- /dev/null
+++ b/src/macos.c
@@ -0,0 +1,58 @@
+/*
+** Copyright (C) 2003-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 5fbf66d7-9547-442a-9c73-92fd164f3a95
+*/
diff --git a/src/mat4.c b/src/mat4.c
new file mode 100644
index 0000000..3ead032
--- /dev/null
+++ b/src/mat4.c
@@ -0,0 +1,395 @@
+/*
+** Copyright (C) 2002-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+#include "float_cast.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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = mat4_read_header (psf)))
+ return error ;
+ } ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_MAT4)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if (psf->is_pipe)
+ return SFE_NO_PIPE_WRITE ;
+
+ psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+ 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 ;
+ } ;
+
+ if (error)
+ return error ;
+
+ return error ;
+} /* mat4_open */
+
+/*------------------------------------------------------------------------------
+*/
+
+static int
+mat4_close (SF_PRIVATE *psf)
+{
+ if (psf->mode == SFM_WRITE || psf->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 (psf->sf.format & SF_FORMAT_SUBMASK, psf->endian) ;
+
+ if (encoding == -1)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ /* Reset the current header length to zero. */
+ psf->header [0] = 0 ;
+ psf->headindex = 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", MAT4_BE_DOUBLE, 1, 1, 0) ;
+ psf_binheader_writef (psf, "E4bd", 11, "samplerate", make_size_t (11), samplerate) ;
+ psf_binheader_writef (psf, "tEm484", encoding, psf->sf.channels, psf->sf.frames, 0) ;
+ psf_binheader_writef (psf, "E4b", 9, "wavedata", make_size_t (9)) ;
+ }
+ else if (psf->endian == SF_ENDIAN_LITTLE)
+ { psf_binheader_writef (psf, "em444", MAT4_LE_DOUBLE, 1, 1, 0) ;
+ psf_binheader_writef (psf, "e4bd", 11, "samplerate", make_size_t (11), samplerate) ;
+ psf_binheader_writef (psf, "tem484", encoding, psf->sf.channels, psf->sf.frames, 0) ;
+ psf_binheader_writef (psf, "e4b", 9, "wavedata", make_size_t (9)) ;
+ }
+ else
+ return SFE_BAD_OPEN_FORMAT ;
+
+ /* Header construction complete so write it out. */
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ if (current > 0)
+ psf_fseek (psf, current, SEEK_SET) ;
+
+ return psf->error ;
+} /* mat4_write_header */
+
+static int
+mat4_read_header (SF_PRIVATE *psf)
+{ int marker, rows, cols, imag ;
+ unsigned namesize ;
+ 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) ;
+
+ LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), " Value : %f\n", value) ;
+ psf_log_printf (psf, psf->u.cbuf) ;
+
+ if ((rows != 1) || (cols != 1))
+ return SFE_MAT4_NO_SAMPLERATE ;
+
+ psf->sf.samplerate = 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 && cols == 0)
+ { psf_log_printf (psf, "*** Error : zero channel count.\n") ;
+ return SFE_MAT4_ZERO_CHANNELS ;
+ } ;
+
+ 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 ;
+ LSF_SNPRINTF (str, sizeof (str) - 1, "%08X", marker) ;
+ return str ;
+} /* mat4_marker_to_str */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: f7e5f5d6-fc39-452e-bc4a-59627116ff59
+*/
diff --git a/src/mat5.c b/src/mat5.c
new file mode 100644
index 0000000..ecd0039
--- /dev/null
+++ b/src/mat5.c
@@ -0,0 +1,507 @@
+/*
+** Copyright (C) 2002-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+#include "float_cast.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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = mat5_read_header (psf)))
+ return error ;
+ } ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_MAT5)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if (psf->is_pipe)
+ return SFE_NO_PIPE_WRITE ;
+
+ psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+ 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->mode == SFM_WRITE || psf->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 "-" 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" ;
+ 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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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 [0] = 0 ;
+ psf->headindex = 0 ;
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ psf_get_date_str (psf->u.cbuf, sizeof (psf->u.scbuf)) ;
+ psf_binheader_writef (psf, "bb", filename, strlen (filename), psf->u.cbuf, strlen (psf->u.cbuf) + 1) ;
+
+ memset (psf->u.scbuf, ' ', 124 - psf->headindex) ;
+ psf_binheader_writef (psf, "b", psf->u.scbuf, make_size_t (124 - psf->headindex)) ;
+
+ psf->rwf_endian = psf->endian ;
+
+ if (psf->rwf_endian == SF_ENDIAN_BIG)
+ psf_binheader_writef (psf, "2b", 0x0100, "MI", make_size_t (2)) ;
+ else
+ psf_binheader_writef (psf, "2b", 0x0100, "IM", make_size_t (2)) ;
+
+ psf_binheader_writef (psf, "444444", MAT5_TYPE_ARRAY, 64, MAT5_TYPE_UINT32, 8, 6, 0) ;
+ psf_binheader_writef (psf, "4444", MAT5_TYPE_INT32, 8, 1, 1) ;
+ psf_binheader_writef (psf, "44b", MAT5_TYPE_SCHAR, strlen (sr_name), sr_name, make_size_t (16)) ;
+
+ if (psf->sf.samplerate > 0xFFFF)
+ psf_binheader_writef (psf, "44", MAT5_TYPE_COMP_UINT, psf->sf.samplerate) ;
+ else
+ { unsigned short samplerate = psf->sf.samplerate ;
+
+ psf_binheader_writef (psf, "422", MAT5_TYPE_COMP_USHORT, samplerate, 0) ;
+ } ;
+
+ datasize = psf->sf.frames * psf->sf.channels * psf->bytewidth ;
+
+ psf_binheader_writef (psf, "t484444", MAT5_TYPE_ARRAY, datasize + 64, MAT5_TYPE_UINT32, 8, 6, 0) ;
+ psf_binheader_writef (psf, "t4448", MAT5_TYPE_INT32, 8, psf->sf.channels, psf->sf.frames) ;
+ psf_binheader_writef (psf, "44b", MAT5_TYPE_SCHAR, strlen (wd_name), wd_name, strlen (wd_name)) ;
+
+ datasize = psf->sf.frames * psf->sf.channels * psf->bytewidth ;
+ if (datasize > 0x7FFFFFFF)
+ datasize = 0x7FFFFFFF ;
+
+ psf_binheader_writef (psf, "t48", encoding, datasize) ;
+
+ /* Header construction complete so write it out. */
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ if (current > 0)
+ psf_fseek (psf, current, SEEK_SET) ;
+
+ return psf->error ;
+} /* mat5_write_header */
+
+static int
+mat5_read_header (SF_PRIVATE *psf)
+{ char name [32] ;
+ short version, endian ;
+ int type, size, flags1, flags2, rows, cols ;
+
+ psf_binheader_readf (psf, "pb", 0, psf->u.cbuf, 124) ;
+
+ psf->u.scbuf [125] = 0 ;
+
+ if (strlen (psf->u.cbuf) >= 124)
+ return SFE_UNIMPLEMENTED ;
+
+ if (strstr (psf->u.cbuf, "MATLAB 5.0 MAT-file") == psf->u.cbuf)
+ psf_log_printf (psf, "%s\n", psf->u.scbuf) ;
+
+
+ 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_SHORT (version) ;
+ }
+ else if (endian == IM_MARKER)
+ { psf->endian = psf->rwf_endian = SF_ENDIAN_LITTLE ;
+ if (CPU_IS_BIG_ENDIAN) version = ENDSWAP_SHORT (version) ;
+ }
+ else
+ return SFE_MAT5_BAD_ENDIAN ;
+
+ if ((CPU_IS_LITTLE_ENDIAN && endian == IM_MARKER) ||
+ (CPU_IS_BIG_ENDIAN && endian == MI_MARKER))
+ version = ENDSWAP_SHORT (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 : %X Cols : %d\n", rows, cols) ;
+
+ if (rows != 1 || cols != 1)
+ return SFE_MAT5_SAMPLE_RATE ;
+
+ 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) ;
+
+ switch (type)
+ { case MAT5_TYPE_DOUBLE :
+ { double samplerate ;
+
+ psf_binheader_readf (psf, "d", &samplerate) ;
+ LSF_SNPRINTF (name, sizeof (name), "%f\n", samplerate) ;
+ psf_log_printf (psf, " Val : %s\n", name) ;
+
+ psf->sf.samplerate = 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) ;
+
+ /*++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+ if (rows == 0 && cols == 0)
+ { psf_log_printf (psf, "*** Error : zero channel count.\n") ;
+ return SFE_MAT5_ZERO_CHANNELS ;
+ } ;
+
+ 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: dfdb6742-b2be-4be8-b390-d0c674e8bc8e
+*/
diff --git a/src/ms_adpcm.c b/src/ms_adpcm.c
new file mode 100644
index 0000000..0fc3403
--- /dev/null
+++ b/src/ms_adpcm.c
@@ -0,0 +1,834 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "float_cast.h"
+#include "common.h"
+#include "wav_w64.h"
+
+/* These required here because we write the header in this file. */
+
+#define RIFF_MARKER (MAKE_MARKER ('R', 'I', 'F', 'F'))
+#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 data_MARKER (MAKE_MARKER ('d', 'a', 't', 'a'))
+
+#define WAVE_FORMAT_MS_ADPCM 0x0002
+
+typedef struct
+{ int channels, blocksize, samplesperblock, blocks, dataremaining ;
+ int blockcount ;
+ sf_count_t samplecount ;
+ short *samples ;
+ unsigned char *block ;
+#if HAVE_FLEXIBLE_ARRAY
+ short dummydata [] ; /* ISO C99 struct flexible array. */
+#else
+ short dummydata [0] ; /* This is a hack an might not work. */
+#endif
+} 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 [MSADPCM_ADAPT_COEFF_COUNT] =
+{ 256, 512, 0, 192, 240, 460, 392
+} ;
+
+static int AdaptCoeff2 [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
+wav_w64_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->mode == SFM_WRITE)
+ samplesperblock = 2 + 2 * (blockalign - 7 * psf->sf.channels) / psf->sf.channels ;
+
+ pmssize = sizeof (MSADPCM_PRIVATE) + blockalign + 3 * psf->sf.channels * samplesperblock ;
+
+ if (! (psf->codec_data = malloc (pmssize)))
+ return SFE_MALLOC_FAILED ;
+ pms = (MSADPCM_PRIVATE*) psf->codec_data ;
+ memset (pms, 0, pmssize) ;
+
+ 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 (psf->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, "*** Warning : samplesperblock shoud be %d.\n", count) ;
+
+ psf->sf.frames = (psf->datalength / pms->blocksize) * pms->samplesperblock ;
+
+ psf_log_printf (psf, " bpred idelta\n") ;
+
+ 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->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 ;
+} /* wav_w64_msadpcm_init */
+
+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 = psf_fread (pms->block, 1, pms->blocksize, psf)) != pms->blocksize)
+ psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pms->blocksize) ;
+
+ /* Read and check the block header. */
+
+ if (pms->channels == 1)
+ { bpred [0] = pms->block [0] ;
+
+ if (bpred [0] >= 7)
+ psf_log_printf (psf, "MS ADPCM synchronisation error (%d).\n", bpred [0]) ;
+
+ chan_idelta [0] = pms->block [1] | (pms->block [2] << 8) ;
+ chan_idelta [1] = 0 ;
+
+ psf_log_printf (psf, "(%d) (%d)\n", bpred [0], chan_idelta [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] = pms->block [0] ;
+ bpred [1] = pms->block [1] ;
+
+ if (bpred [0] >= 7 || bpred [1] >= 7)
+ psf_log_printf (psf, "MS ADPCM synchronisation error (%d %d).\n", bpred [0], bpred [1]) ;
+
+ chan_idelta [0] = pms->block [2] | (pms->block [3] << 8) ;
+ chan_idelta [1] = pms->block [4] | (pms->block [5] << 8) ;
+
+ psf_log_printf (psf, "(%d, %d) (%d, %d)\n", bpred [0], bpred [1], chan_idelta [0], chan_idelta [1]) ;
+
+ 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 1 ;
+} /* 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)
+ msadpcm_decode_block (psf, pms) ;
+
+ 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 ;
+
+ count = msadpcm_read_block (psf, pms, ptr, readcount) ;
+
+ 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : len ;
+ count = msadpcm_read_block (psf, pms, sptr, readcount) ;
+ for (k = 0 ; k < readcount ; k++)
+ ptr [total + k] = 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : len ;
+ count = msadpcm_read_block (psf, pms, 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 ;
+} /* msadpcm_read_f */
+
+static sf_count_t
+msadpcm_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len)
+{ MSADPCM_PRIVATE *pms ;
+ 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)
+ return 0 ;
+ pms = (MSADPCM_PRIVATE*) psf->codec_data ;
+
+ sptr = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : len ;
+ count = msadpcm_read_block (psf, pms, 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 ;
+} /* 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
+msadpcm_write_adapt_coeffs (SF_PRIVATE *psf)
+{ int k ;
+
+ for (k = 0 ; k < MSADPCM_ADAPT_COEFF_COUNT ; k++)
+ psf_binheader_writef (psf, "22", AdaptCoeff1 [k], AdaptCoeff2 [k]) ;
+} /* 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], idelta [2], 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 = 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 = 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = ptr [total + k] >> 16 ;
+ count = 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = lrintf (normfact * ptr [total + k]) ;
+ count = 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 ;
+ 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 = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = lrint (normfact * ptr [total + k]) ;
+ count = 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->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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: a98908a3-5305-4935-872b-77d6a86c330f
+*/
diff --git a/src/new.c b/src/new.c
new file mode 100644
index 0000000..475e92b
--- /dev/null
+++ b/src/new.c
@@ -0,0 +1,123 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#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->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ return SFE_UNIMPLEMENTED ;
+
+ if ((error = new_read_header (psf)))
+ return error ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_WVE)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ 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
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 98c77ff6-81a6-440d-bad1-4597f51df956
+*/
diff --git a/src/nist.c b/src/nist.c
new file mode 100644
index 0000000..2ab20db
--- /dev/null
+++ b/src/nist.c
@@ -0,0 +1,367 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = nist_read_header (psf)))
+ return error ;
+ } ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if (psf->is_pipe)
+ return SFE_NO_PIPE_WRITE ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_NIST)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+ 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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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 ;
+ int bitwidth = 0, bytes = 0, count, encoding ;
+ char str [64], *cptr ;
+ long samples ;
+
+ psf->sf.format = SF_FORMAT_NIST ;
+
+ psf_header = psf->u.cbuf ;
+
+ if (sizeof (psf->header) <= NIST_HEADER_LENGTH)
+ return SFE_INTERNAL ;
+
+ /* 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)
+ 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 ")))
+ sscanf (cptr, "channel_count -i %d", &(psf->sf.channels)) ;
+
+ if ((cptr = strstr (psf_header, "sample_rate -i ")))
+ sscanf (cptr, "sample_rate -i %d", &(psf->sf.samplerate)) ;
+
+ if ((cptr = strstr (psf_header, "sample_count -i ")))
+ { sscanf (psf_header, "sample_count -i %ld", &samples) ;
+ psf->sf.frames = samples ;
+ } ;
+
+ if ((cptr = strstr (psf_header, "sample_n_bytes -i ")))
+ 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%d %8s", &bytes, str) ;
+ if (bytes > 1)
+ { if (psf->bytewidth == 0)
+ psf->bytewidth = bytes ;
+ else if (psf->bytewidth != bytes)
+ { psf_log_printf (psf, "psf->bytewidth (%d) != bytes (%d)\n", psf->bytewidth, bytes) ;
+ return SFE_NIST_BAD_ENCODING ;
+ } ;
+
+ if (strstr (str, "01") == str)
+ psf->endian = SF_ENDIAN_LITTLE ;
+ else if (strstr (str, "10"))
+ 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 ;
+
+ return 0 ;
+} /* nist_read_header */
+
+static int
+nist_close (SF_PRIVATE *psf)
+{
+ if (psf->mode == SFM_WRITE || psf->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, 0, sizeof (psf->header)) ;
+ psf->headindex = 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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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", (size_t) (NIST_HEADER_LENGTH - psf->headindex)) ;
+
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ if (current > 0)
+ psf_fseek (psf, current, SEEK_SET) ;
+
+ return psf->error ;
+} /* nist_write_header */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: b45ed85d-9e22-4ad9-b78c-4b58b67152a8
+*/
diff --git a/src/ogg.c b/src/ogg.c
new file mode 100644
index 0000000..4bcc595
--- /dev/null
+++ b/src/ogg.c
@@ -0,0 +1,44 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+
+int
+ogg_open (SF_PRIVATE *psf)
+{ if (psf)
+ return SFE_UNIMPLEMENTED ;
+ return 0 ;
+} /* ogg_open */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 9ff1fe9c-629e-4e9c-9ef5-3d0eb1e427a0
+*/
diff --git a/src/paf.c b/src/paf.c
new file mode 100644
index 0000000..8d52e1c
--- /dev/null
+++ b/src/paf.c
@@ -0,0 +1,838 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "float_cast.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, samplesperblock, blocksize ;
+ int read_block, write_block, read_count, write_count ;
+ sf_count_t sample_count ;
+ int *samples ;
+ unsigned char *block ;
+#if HAVE_FLEXIBLE_ARRAY
+ int data [] ; /* ISO C99 struct flexible array. */
+#else
+ int data [1] ; /* This is a hack and may not work. */
+#endif
+} 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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = paf_read_header (psf)))
+ return error ;
+ } ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_PAF)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+
+ /* 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 ;
+
+ 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 (psf->filelength < PAF_HEADER_LENGTH)
+ return SFE_PAF_SHORT_HEADER ;
+
+ 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 (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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 [0] = 0 ;
+ psf->headindex = 0 ;
+
+ if (psf->endian == SF_ENDIAN_BIG)
+ { /* Marker, version, endianness, samplerate */
+ psf_binheader_writef (psf, "Em444", PAF_MARKER, 0, 0, psf->sf.samplerate) ;
+ /* format, channels, source */
+ psf_binheader_writef (psf, "E444", paf_format, psf->sf.channels, 0) ;
+ }
+ else if (psf->endian == SF_ENDIAN_LITTLE)
+ { /* Marker, version, endianness, samplerate */
+ psf_binheader_writef (psf, "em444", FAP_MARKER, 0, 1, psf->sf.samplerate) ;
+ /* format, channels, source */
+ psf_binheader_writef (psf, "e444", paf_format, psf->sf.channels, 0) ;
+ } ;
+
+ /* Zero fill to dataoffset. */
+ psf_binheader_writef (psf, "z", (size_t) (psf->dataoffset - psf->headindex)) ;
+
+ psf_fwrite (psf->header, psf->headindex, 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 = malloc (paf24size)))
+ return SFE_MALLOC_FAILED ;
+
+ ppaf24 = (PAF24_PRIVATE*) psf->codec_data ;
+ memset (ppaf24, 0, paf24size) ;
+
+ ppaf24->channels = psf->sf.channels ;
+ ppaf24->samples = ppaf24->data ;
+ ppaf24->block = (unsigned char*) (ppaf24->data + PAF24_SAMPLES_PER_BLOCK * ppaf24->channels) ;
+
+ ppaf24->blocksize = PAF24_BLOCK_SIZE * ppaf24->channels ;
+ ppaf24->samplesperblock = PAF24_SAMPLES_PER_BLOCK ;
+
+ if (psf->mode == SFM_READ || psf->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->mode == SFM_WRITE || psf->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->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->mode == SFM_RDWR)
+ ppaf24->write_block = ppaf24->max_blocks ;
+ else
+ ppaf24->write_block = 0 ;
+
+ psf->sf.frames = ppaf24->samplesperblock * 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 / ppaf24->samplesperblock ;
+ newsample = offset % ppaf24->samplesperblock ;
+
+ 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 * ppaf24->samplesperblock + 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->mode == SFM_WRITE || psf->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 * ppaf24->samplesperblock > ppaf24->sample_count)
+ { memset (ppaf24->samples, 0, ppaf24->samplesperblock * ppaf24->channels) ;
+ return 1 ;
+ } ;
+
+ /* Read the block. */
+ if ((k = psf_fread (ppaf24->block, 1, ppaf24->blocksize, psf)) != ppaf24->blocksize)
+ psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, ppaf24->blocksize) ;
+
+
+ if (CPU_IS_LITTLE_ENDIAN)
+ { /* Do endian swapping if necessary. */
+ if (psf->endian == SF_ENDIAN_BIG)
+ endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ;
+
+ /* Unpack block. */
+ for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++)
+ { channel = k % ppaf24->channels ;
+ cptr = ppaf24->block + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ;
+ ppaf24->samples [k] = (cptr [0] << 8) | (cptr [1] << 16) | (cptr [2] << 24) ;
+ } ;
+ }
+ else
+ { /* Do endian swapping if necessary. */
+ if (psf->endian == SF_ENDIAN_BIG)
+ endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ;
+
+ /* Unpack block. */
+ for (k = 0 ; k < PAF24_SAMPLES_PER_BLOCK * ppaf24->channels ; k++)
+ { channel = k % ppaf24->channels ;
+ cptr = ppaf24->block + PAF24_BLOCK_SIZE * channel + 3 * (k / ppaf24->channels) ;
+ ppaf24->samples [k] = (cptr [0] << 8) | (cptr [1] << 16) | (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 * ppaf24->samplesperblock >= ppaf24->sample_count)
+ { memset (&(ptr [total]), 0, (len - total) * sizeof (int)) ;
+ return total ;
+ } ;
+
+ if (ppaf24->read_count >= ppaf24->samplesperblock)
+ paf24_read_block (psf, ppaf24) ;
+
+ count = (ppaf24->samplesperblock - 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)
+{ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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)
+{ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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)
+{ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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 = 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->data, 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 = 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_BIG)
+ endswap_int_array (ppaf24->data, 8 * ppaf24->channels) ;
+ } ;
+
+ /* Write block to disk. */
+ if ((k = 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 * ppaf24->samplesperblock + ppaf24->write_count)
+ ppaf24->sample_count = ppaf24->write_block * ppaf24->samplesperblock + ppaf24->write_count ;
+
+ if (ppaf24->write_count == ppaf24->samplesperblock)
+ { 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 = (ppaf24->samplesperblock - 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 >= ppaf24->samplesperblock)
+ 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)
+{ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : 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)
+{ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ iptr [k] = 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)
+{ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ iptr [k] = 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 */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 477a5308-451e-4bbd-bab4-fab6caa4e884
+*/
diff --git a/src/pcm.c b/src/pcm.c
new file mode 100644
index 0000000..e3dd5a5
--- /dev/null
+++ b/src/pcm.c
@@ -0,0 +1,2901 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 "sfendian.h"
+#include "float_cast.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 void 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 ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_S8)
+ chars = SF_CHARS_SIGNED ;
+ else if ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_PCM_U8)
+ chars = SF_CHARS_UNSIGNED ;
+
+ if (psf->mode == SFM_READ || psf->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\n") ;
+ return SFE_UNIMPLEMENTED ;
+ } ;
+ } ;
+
+ if (psf->mode == SFM_WRITE || psf->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\n") ;
+ 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->datalength / psf->blockwidth ;
+
+ return 0 ;
+} /* pcm_init */
+
+/*==============================================================================
+*/
+
+static inline void
+sc2s_array (signed char *src, int count, short *dest)
+{ while (--count >= 0)
+ { dest [count] = src [count] << 8 ;
+ } ;
+} /* sc2s_array */
+
+static inline void
+uc2s_array (unsigned char *src, int count, short *dest)
+{ while (--count >= 0)
+ { dest [count] = (((short) src [count]) - 0x80) << 8 ;
+ } ;
+} /* uc2s_array */
+
+static inline void
+let2s_array (tribyte *src, int count, short *dest)
+{ unsigned char *ucptr ;
+
+ ucptr = ((unsigned char*) src) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ dest [count] = LET2H_SHORT_PTR (ucptr) ;
+ } ;
+} /* let2s_array */
+
+static inline void
+bet2s_array (tribyte *src, int count, short *dest)
+{ unsigned char *ucptr ;
+
+ ucptr = ((unsigned char*) src) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ dest [count] = BET2H_SHORT_PTR (ucptr) ;
+ } ;
+} /* bet2s_array */
+
+static inline void
+lei2s_array (int *src, int count, short *dest)
+{ int value ;
+
+ while (--count >= 0)
+ { value = LEI2H_INT (src [count]) ;
+ dest [count] = value >> 16 ;
+ } ;
+} /* lei2s_array */
+
+static inline void
+bei2s_array (int *src, int count, short *dest)
+{ int value ;
+
+ while (--count >= 0)
+ { value = BEI2H_INT (src [count]) ;
+ dest [count] = value >> 16 ;
+ } ;
+} /* bei2s_array */
+
+/*--------------------------------------------------------------------------
+*/
+
+static inline void
+sc2i_array (signed char *src, int count, int *dest)
+{ while (--count >= 0)
+ { dest [count] = ((int) src [count]) << 24 ;
+ } ;
+} /* sc2i_array */
+
+static inline void
+uc2i_array (unsigned char *src, int count, int *dest)
+{ while (--count >= 0)
+ { dest [count] = (((int) src [count]) - 128) << 24 ;
+ } ;
+} /* uc2i_array */
+
+static inline void
+bes2i_array (short *src, int count, int *dest)
+{ short value ;
+
+ while (--count >= 0)
+ { value = BES2H_SHORT (src [count]) ;
+ dest [count] = value << 16 ;
+ } ;
+} /* bes2i_array */
+
+static inline void
+les2i_array (short *src, int count, int *dest)
+{ short value ;
+
+ while (--count >= 0)
+ { value = LES2H_SHORT (src [count]) ;
+ dest [count] = value << 16 ;
+ } ;
+} /* les2i_array */
+
+static inline void
+bet2i_array (tribyte *src, int count, int *dest)
+{ unsigned char *ucptr ;
+
+ ucptr = ((unsigned char*) src) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ dest [count] = BET2H_INT_PTR (ucptr) ;
+ } ;
+} /* bet2i_array */
+
+static inline void
+let2i_array (tribyte *src, int count, int *dest)
+{ unsigned char *ucptr ;
+
+ ucptr = ((unsigned char*) src) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ dest [count] = LET2H_INT_PTR (ucptr) ;
+ } ;
+} /* let2i_array */
+
+/*--------------------------------------------------------------------------
+*/
+
+static inline void
+sc2f_array (signed char *src, int count, float *dest, float normfact)
+{ while (--count >= 0)
+ dest [count] = ((float) src [count]) * normfact ;
+} /* sc2f_array */
+
+static inline void
+uc2f_array (unsigned char *src, int count, float *dest, float normfact)
+{ while (--count >= 0)
+ dest [count] = (((int) src [count]) - 128) * normfact ;
+} /* uc2f_array */
+
+static inline void
+les2f_array (short *src, int count, float *dest, float normfact)
+{ short value ;
+
+ while (--count >= 0)
+ { value = src [count] ;
+ value = LES2H_SHORT (value) ;
+ dest [count] = ((float) value) * normfact ;
+ } ;
+} /* les2f_array */
+
+static inline void
+bes2f_array (short *src, int count, float *dest, float normfact)
+{ short value ;
+
+ while (--count >= 0)
+ { value = src [count] ;
+ value = BES2H_SHORT (value) ;
+ dest [count] = ((float) value) * normfact ;
+ } ;
+} /* bes2f_array */
+
+static inline void
+let2f_array (tribyte *src, int count, float *dest, float normfact)
+{ unsigned char *ucptr ;
+ int value ;
+
+ ucptr = ((unsigned char*) src) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ value = LET2H_INT_PTR (ucptr) ;
+ dest [count] = ((float) value) * normfact ;
+ } ;
+} /* let2f_array */
+
+static inline void
+bet2f_array (tribyte *src, int count, float *dest, float normfact)
+{ unsigned char *ucptr ;
+ int value ;
+
+ ucptr = ((unsigned char*) src) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ value = BET2H_INT_PTR (ucptr) ;
+ dest [count] = ((float) value) * normfact ;
+ } ;
+} /* bet2f_array */
+
+static inline void
+lei2f_array (int *src, int count, float *dest, float normfact)
+{ int value ;
+
+ while (--count >= 0)
+ { value = src [count] ;
+ value = LEI2H_INT (value) ;
+ dest [count] = ((float) value) * normfact ;
+ } ;
+} /* lei2f_array */
+
+static inline void
+bei2f_array (int *src, int count, float *dest, float normfact)
+{ int value ;
+
+ while (--count >= 0)
+ { value = src [count] ;
+ value = BEI2H_INT (value) ;
+ dest [count] = ((float) value) * normfact ;
+ } ;
+} /* bei2f_array */
+
+/*--------------------------------------------------------------------------
+*/
+
+static inline void
+sc2d_array (signed char *src, int count, double *dest, double normfact)
+{ while (--count >= 0)
+ dest [count] = ((double) src [count]) * normfact ;
+} /* sc2d_array */
+
+static inline void
+uc2d_array (unsigned char *src, int count, double *dest, double normfact)
+{ while (--count >= 0)
+ dest [count] = (((int) src [count]) - 128) * normfact ;
+} /* uc2d_array */
+
+static inline void
+les2d_array (short *src, int count, double *dest, double normfact)
+{ short value ;
+
+ while (--count >= 0)
+ { value = src [count] ;
+ value = LES2H_SHORT (value) ;
+ dest [count] = ((double) value) * normfact ;
+ } ;
+} /* les2d_array */
+
+static inline void
+bes2d_array (short *src, int count, double *dest, double normfact)
+{ short value ;
+
+ while (--count >= 0)
+ { value = src [count] ;
+ value = BES2H_SHORT (value) ;
+ dest [count] = ((double) value) * normfact ;
+ } ;
+} /* bes2d_array */
+
+static inline void
+let2d_array (tribyte *src, int count, double *dest, double normfact)
+{ unsigned char *ucptr ;
+ int value ;
+
+ ucptr = ((unsigned char*) src) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ value = LET2H_INT_PTR (ucptr) ;
+ dest [count] = ((double) value) * normfact ;
+ } ;
+} /* let2d_array */
+
+static inline void
+bet2d_array (tribyte *src, int count, double *dest, double normfact)
+{ unsigned char *ucptr ;
+ int value ;
+
+ ucptr = ((unsigned char*) src) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ value = (ucptr [0] << 24) | (ucptr [1] << 16) | (ucptr [2] << 8) ;
+ dest [count] = ((double) value) * normfact ;
+ } ;
+} /* bet2d_array */
+
+static inline void
+lei2d_array (int *src, int count, double *dest, double normfact)
+{ int value ;
+
+ while (--count >= 0)
+ { value = src [count] ;
+ value = LEI2H_INT (value) ;
+ dest [count] = ((double) value) * normfact ;
+ } ;
+} /* lei2d_array */
+
+static inline void
+bei2d_array (int *src, int count, double *dest, double normfact)
+{ int value ;
+
+ while (--count >= 0)
+ { value = src [count] ;
+ value = BEI2H_INT (value) ;
+ dest [count] = ((double) value) * normfact ;
+ } ;
+} /* bei2d_array */
+
+/*--------------------------------------------------------------------------
+*/
+
+static inline void
+s2sc_array (const short *src, signed char *dest, int count)
+{ while (--count >= 0)
+ dest [count] = src [count] >> 8 ;
+} /* s2sc_array */
+
+static inline void
+s2uc_array (const short *src, unsigned char *dest, int count)
+{ while (--count >= 0)
+ dest [count] = (src [count] >> 8) + 0x80 ;
+} /* s2uc_array */
+
+static inline void
+s2let_array (const short *src, tribyte *dest, int count)
+{ unsigned char *ucptr ;
+
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ ucptr [0] = 0 ;
+ ucptr [1] = src [count] ;
+ ucptr [2] = src [count] >> 8 ;
+ } ;
+} /* s2let_array */
+
+static inline void
+s2bet_array (const short *src, tribyte *dest, int count)
+{ unsigned char *ucptr ;
+
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ ucptr [2] = 0 ;
+ ucptr [1] = src [count] ;
+ ucptr [0] = src [count] >> 8 ;
+ } ;
+} /* s2bet_array */
+
+static inline void
+s2lei_array (const short *src, int *dest, int count)
+{ unsigned char *ucptr ;
+
+ ucptr = ((unsigned char*) dest) + 4 * count ;
+ while (--count >= 0)
+ { ucptr -= 4 ;
+ ucptr [0] = 0 ;
+ ucptr [1] = 0 ;
+ ucptr [2] = src [count] ;
+ ucptr [3] = src [count] >> 8 ;
+ } ;
+} /* s2lei_array */
+
+static inline void
+s2bei_array (const short *src, int *dest, int count)
+{ unsigned char *ucptr ;
+
+ ucptr = ((unsigned char*) dest) + 4 * count ;
+ while (--count >= 0)
+ { ucptr -= 4 ;
+ ucptr [0] = src [count] >> 8 ;
+ ucptr [1] = src [count] ;
+ ucptr [2] = 0 ;
+ ucptr [3] = 0 ;
+ } ;
+} /* s2bei_array */
+
+/*--------------------------------------------------------------------------
+*/
+
+static inline void
+i2sc_array (const int *src, signed char *dest, int count)
+{ while (--count >= 0)
+ dest [count] = (src [count] >> 24) ;
+} /* i2sc_array */
+
+static inline void
+i2uc_array (const int *src, unsigned char *dest, int count)
+{ while (--count >= 0)
+ dest [count] = ((src [count] >> 24) + 128) ;
+} /* i2uc_array */
+
+static inline void
+i2bes_array (const int *src, short *dest, int count)
+{ unsigned char *ucptr ;
+
+ ucptr = ((unsigned char*) dest) + 2 * count ;
+ while (--count >= 0)
+ { ucptr -= 2 ;
+ ucptr [0] = src [count] >> 24 ;
+ ucptr [1] = src [count] >> 16 ;
+ } ;
+} /* i2bes_array */
+
+static inline void
+i2les_array (const int *src, short *dest, int count)
+{ unsigned char *ucptr ;
+
+ ucptr = ((unsigned char*) dest) + 2 * count ;
+ while (--count >= 0)
+ { ucptr -= 2 ;
+ ucptr [0] = src [count] >> 16 ;
+ ucptr [1] = src [count] >> 24 ;
+ } ;
+} /* i2les_array */
+
+static inline void
+i2let_array (const int *src, tribyte *dest, int count)
+{ unsigned char *ucptr ;
+ int value ;
+
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ value = src [count] >> 8 ;
+ ucptr [0] = value ;
+ ucptr [1] = value >> 8 ;
+ ucptr [2] = value >> 16 ;
+ } ;
+} /* i2let_array */
+
+static inline void
+i2bet_array (const int *src, tribyte *dest, int count)
+{ unsigned char *ucptr ;
+ int value ;
+
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ value = src [count] >> 8 ;
+ ucptr [2] = value ;
+ ucptr [1] = value >> 8 ;
+ ucptr [0] = value >> 16 ;
+ } ;
+} /* i2bet_array */
+
+/*===============================================================================================
+*/
+
+static sf_count_t
+pcm_read_sc2s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.scbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ;
+ sc2s_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ;
+ uc2s_array (psf->u.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 = psf_fread (ptr, sizeof (short), len, psf) ;
+ if (CPU_IS_LITTLE_ENDIAN)
+ endswap_short_array (ptr, len) ;
+
+ 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) ;
+
+ return total ;
+} /* pcm_read_les2s */
+
+static sf_count_t
+pcm_read_bet2s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ;
+ bet2s_array ((tribyte*) (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ;
+ let2s_array ((tribyte*) (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ;
+ bei2s_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ;
+ lei2s_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.scbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ;
+ sc2i_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ;
+ uc2i_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ bes2i_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ les2i_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ;
+ bet2i_array ((tribyte*) (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ;
+ let2i_array ((tribyte*) (psf->u.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) ;
+
+ 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) ;
+
+ return total ;
+} /* pcm_read_lei2i */
+
+/*-----------------------------------------------------------------------------------------------
+*/
+
+static sf_count_t
+pcm_read_sc2f (SF_PRIVATE *psf, float *ptr, sf_count_t len)
+{ 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 (psf->u.scbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ;
+ sc2f_array (psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ;
+ uc2f_array (psf->u.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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ bes2f_array (psf->u.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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ les2f_array (psf->u.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)
+{ 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 (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ;
+ bet2f_array ((tribyte*) (psf->u.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)
+{ 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 (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ;
+ let2f_array ((tribyte*) (psf->u.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)
+{ 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 (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ;
+ bei2f_array (psf->u.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)
+{ 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 (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ;
+ lei2f_array (psf->u.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)
+{ 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 (psf->u.scbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ;
+ sc2d_array (psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, sizeof (unsigned char), bufferlen, psf) ;
+ uc2d_array (psf->u.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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ bes2d_array (psf->u.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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ les2d_array (psf->u.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)
+{ 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 (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ;
+ bet2d_array ((tribyte*) (psf->u.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)
+{ 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 (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, SIZEOF_TRIBYTE, bufferlen, psf) ;
+ let2d_array ((tribyte*) (psf->u.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)
+{ 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 (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ;
+ bei2d_array (psf->u.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)
+{ 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 (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ibuf, sizeof (int), bufferlen, psf) ;
+ lei2d_array (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.scbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2sc_array (ptr + total, psf->u.scbuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2uc_array (ptr + total, psf->u.ucbuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ if (CPU_IS_BIG_ENDIAN)
+ return psf_fwrite (ptr, sizeof (short), len, psf) ;
+ else
+
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ endswap_short_copy (psf->u.sbuf, ptr + total, bufferlen) ;
+ writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ total += writecount ;
+ if (writecount < bufferlen)
+ break ;
+ len -= writecount ;
+ } ;
+
+ return total ;
+} /* pcm_write_s2bes */
+
+static sf_count_t
+pcm_write_s2les (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ if (CPU_IS_LITTLE_ENDIAN)
+ return psf_fwrite (ptr, sizeof (short), len, psf) ;
+
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ endswap_short_copy (psf->u.sbuf, ptr + total, bufferlen) ;
+ writecount = psf_fwrite (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ total += writecount ;
+ if (writecount < bufferlen)
+ break ;
+ len -= writecount ;
+ } ;
+
+ return total ;
+} /* pcm_write_s2les */
+
+static sf_count_t
+pcm_write_s2bet (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2bet_array (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2let_array (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2bei_array (ptr + total, psf->u.ibuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2lei_array (ptr + total, psf->u.ibuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.scbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2sc_array (ptr + total, psf->u.scbuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2uc_array (ptr + total, psf->u.ucbuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2bes_array (ptr + total, psf->u.sbuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2les_array (ptr + total, psf->u.sbuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2bet_array (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = sizeof (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2let_array (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ if (CPU_IS_BIG_ENDIAN)
+ return psf_fwrite (ptr, sizeof (int), len, psf) ;
+
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ endswap_int_copy (psf->u.ibuf, ptr + total, bufferlen) ;
+ writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ;
+ total += writecount ;
+ if (writecount < bufferlen)
+ break ;
+ len -= writecount ;
+ } ;
+
+ return total ;
+} /* pcm_write_i2bei */
+
+static sf_count_t
+pcm_write_i2lei (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ if (CPU_IS_LITTLE_ENDIAN)
+ return psf_fwrite (ptr, sizeof (int), len, psf) ;
+
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ endswap_int_copy (psf->u.ibuf, ptr + total, bufferlen) ;
+ writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ;
+ total += writecount ;
+ if (writecount < bufferlen)
+ break ;
+ len -= writecount ;
+ } ;
+
+ return total ;
+} /* 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 ;
+
+ while (--count >= 0)
+ { dest [count] = lrintf (src [count] * 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) ;
+
+ while (--count >= 0)
+ { scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { dest [count] = 127 ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { dest [count] = -128 ;
+ continue ;
+ } ;
+
+ dest [count] = lrintf (scaled_value) >> 24 ;
+ } ;
+} /* f2sc_clip_array */
+
+static sf_count_t
+pcm_write_f2sc (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
+{ 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 (psf->u.scbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.scbuf, bufferlen, psf->norm_float) ;
+ writecount = psf_fwrite (psf->u.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 ;
+
+ while (--count >= 0)
+ { dest [count] = lrintf (src [count] * 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) ;
+
+ while (--count >= 0)
+ { scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { dest [count] = 0xFF ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { dest [count] = 0 ;
+ continue ;
+ } ;
+
+ dest [count] = (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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.ucbuf, bufferlen, psf->norm_float) ;
+ writecount = psf_fwrite (psf->u.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 ;
+ ucptr = ((unsigned char*) dest) + 2 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 2 ;
+ value = lrintf (src [count] * 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) ;
+ ucptr = ((unsigned char*) dest) + 2 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 2 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [1] = 0xFF ;
+ ucptr [0] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [1] = 0x00 ;
+ ucptr [0] = 0x80 ;
+ continue ;
+ } ;
+
+ value = 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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.sbuf, bufferlen, psf->norm_float) ;
+ writecount = psf_fwrite (psf->u.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 ;
+ ucptr = ((unsigned char*) dest) + 2 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 2 ;
+ value = lrintf (src [count] * 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) ;
+ ucptr = ((unsigned char*) dest) + 2 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 2 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [0] = 0xFF ;
+ ucptr [1] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [0] = 0x00 ;
+ ucptr [1] = 0x80 ;
+ continue ;
+ } ;
+
+ value = 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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.sbuf, bufferlen, psf->norm_float) ;
+ writecount = psf_fwrite (psf->u.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)
+{ unsigned char *ucptr ;
+ float normfact ;
+ int value ;
+
+ normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ;
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ value = lrintf (src [count] * normfact) ;
+ ucptr [0] = value ;
+ ucptr [1] = value >> 8 ;
+ ucptr [2] = value >> 16 ;
+ } ;
+} /* f2let_array */
+
+static void
+f2let_clip_array (const float *src, tribyte *dest, int count, int normalize)
+{ unsigned char *ucptr ;
+ float normfact, scaled_value ;
+ int value ;
+
+ normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ;
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [0] = 0xFF ;
+ ucptr [1] = 0xFF ;
+ ucptr [2] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [0] = 0x00 ;
+ ucptr [1] = 0x00 ;
+ ucptr [2] = 0x80 ;
+ continue ;
+ } ;
+
+ value = lrintf (scaled_value) ;
+ ucptr [0] = value >> 8 ;
+ ucptr [1] = value >> 16 ;
+ ucptr [2] = value >> 24 ;
+ } ;
+} /* f2let_clip_array */
+
+static sf_count_t
+pcm_write_f2let (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
+{ 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 (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen, psf->norm_float) ;
+ writecount = psf_fwrite (psf->u.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)
+{ unsigned char *ucptr ;
+ float normfact ;
+ int value ;
+
+ normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ;
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ value = lrintf (src [count] * normfact) ;
+ ucptr [0] = value >> 16 ;
+ ucptr [1] = value >> 8 ;
+ ucptr [2] = value ;
+ } ;
+} /* f2bet_array */
+
+static void
+f2bet_clip_array (const float *src, tribyte *dest, int count, int normalize)
+{ unsigned char *ucptr ;
+ float normfact, scaled_value ;
+ int value ;
+
+ normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ;
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [0] = 0x7F ;
+ ucptr [1] = 0xFF ;
+ ucptr [2] = 0xFF ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [0] = 0x80 ;
+ ucptr [1] = 0x00 ;
+ ucptr [2] = 0x00 ;
+ continue ;
+ } ;
+
+ value = lrint (scaled_value) ;
+ ucptr [0] = value >> 24 ;
+ ucptr [1] = value >> 16 ;
+ ucptr [2] = value >> 8 ;
+ } ;
+} /* f2bet_clip_array */
+
+static sf_count_t
+pcm_write_f2bet (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
+{ 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 (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen, psf->norm_float) ;
+ writecount = psf_fwrite (psf->u.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 ;
+ ucptr = ((unsigned char*) dest) + 4 * count ;
+ while (--count >= 0)
+ { ucptr -= 4 ;
+ value = lrintf (src [count] * 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 ;
+ ucptr = ((unsigned char*) dest) + 4 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 4 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= 1.0 * 0x7FFFFFFF)
+ { ucptr [0] = 0x7F ;
+ ucptr [1] = 0xFF ;
+ ucptr [2] = 0xFF ;
+ ucptr [3] = 0xFF ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [0] = 0x80 ;
+ ucptr [1] = 0x00 ;
+ ucptr [2] = 0x00 ;
+ ucptr [3] = 0x00 ;
+ continue ;
+ } ;
+
+ value = 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)
+{ 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 (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.ibuf, bufferlen, psf->norm_float) ;
+ writecount = psf_fwrite (psf->u.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 ;
+ ucptr = ((unsigned char*) dest) + 4 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 4 ;
+ value = lrintf (src [count] * 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 ;
+ ucptr = ((unsigned char*) dest) + 4 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 4 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [0] = 0xFF ;
+ ucptr [1] = 0xFF ;
+ ucptr [2] = 0xFF ;
+ ucptr [3] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [0] = 0x00 ;
+ ucptr [1] = 0x00 ;
+ ucptr [2] = 0x00 ;
+ ucptr [3] = 0x80 ;
+ continue ;
+ } ;
+
+ value = 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)
+{ 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 (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.ibuf, bufferlen, psf->norm_float) ;
+ writecount = psf_fwrite (psf->u.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 ;
+
+ while (--count >= 0)
+ { dest [count] = lrint (src [count] * 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) ;
+
+ while (--count >= 0)
+ { scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { dest [count] = 127 ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { dest [count] = -128 ;
+ continue ;
+ } ;
+
+ dest [count] = lrintf (scaled_value) >> 24 ;
+ } ;
+} /* d2sc_clip_array */
+
+static sf_count_t
+pcm_write_d2sc (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
+{ 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 (psf->u.scbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.scbuf, bufferlen, psf->norm_double) ;
+ writecount = psf_fwrite (psf->u.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 ;
+
+ while (--count >= 0)
+ { dest [count] = lrint (src [count] * 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) ;
+
+ while (--count >= 0)
+ { scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { dest [count] = 255 ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { dest [count] = 0 ;
+ continue ;
+ } ;
+
+ dest [count] = (lrint (src [count] * normfact) >> 24) + 128 ;
+ } ;
+} /* d2uc_clip_array */
+
+static sf_count_t
+pcm_write_d2uc (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.ucbuf, bufferlen, psf->norm_double) ;
+ writecount = psf_fwrite (psf->u.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 ;
+ ucptr = ((unsigned char*) dest) + 2 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 2 ;
+ value = lrint (src [count] * 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) ;
+ ucptr = ((unsigned char*) dest) + 2 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 2 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [1] = 0xFF ;
+ ucptr [0] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [1] = 0x00 ;
+ ucptr [0] = 0x80 ;
+ continue ;
+ } ;
+
+ value = 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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.sbuf, bufferlen, psf->norm_double) ;
+ writecount = psf_fwrite (psf->u.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 ;
+ ucptr = ((unsigned char*) dest) + 2 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 2 ;
+ value = lrint (src [count] * 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) ;
+ ucptr = ((unsigned char*) dest) + 2 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 2 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [0] = 0xFF ;
+ ucptr [1] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [0] = 0x00 ;
+ ucptr [1] = 0x80 ;
+ continue ;
+ } ;
+
+ value = 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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.sbuf, bufferlen, psf->norm_double) ;
+ writecount = psf_fwrite (psf->u.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)
+{ unsigned char *ucptr ;
+ int value ;
+ double normfact ;
+
+ normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ;
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ value = lrint (src [count] * normfact) ;
+ ucptr [0] = value ;
+ ucptr [1] = value >> 8 ;
+ ucptr [2] = value >> 16 ;
+ } ;
+} /* d2let_array */
+
+static void
+d2let_clip_array (const double *src, tribyte *dest, int count, int normalize)
+{ unsigned char *ucptr ;
+ int value ;
+ double normfact, scaled_value ;
+
+ normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ;
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [0] = 0xFF ;
+ ucptr [1] = 0xFF ;
+ ucptr [2] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [0] = 0x00 ;
+ ucptr [1] = 0x00 ;
+ ucptr [2] = 0x80 ;
+ continue ;
+ } ;
+
+ value = lrint (scaled_value) ;
+ ucptr [0] = value >> 8 ;
+ ucptr [1] = value >> 16 ;
+ ucptr [2] = value >> 24 ;
+ } ;
+} /* d2let_clip_array */
+
+static sf_count_t
+pcm_write_d2let (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
+{ 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 (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen, psf->norm_double) ;
+ writecount = psf_fwrite (psf->u.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)
+{ unsigned char *ucptr ;
+ int value ;
+ double normfact ;
+
+ normfact = normalize ? (1.0 * 0x7FFFFF) : 1.0 ;
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ value = lrint (src [count] * normfact) ;
+ ucptr [2] = value ;
+ ucptr [1] = value >> 8 ;
+ ucptr [0] = value >> 16 ;
+ } ;
+} /* d2bet_array */
+
+static void
+d2bet_clip_array (const double *src, tribyte *dest, int count, int normalize)
+{ unsigned char *ucptr ;
+ int value ;
+ double normfact, scaled_value ;
+
+ normfact = normalize ? (8.0 * 0x10000000) : (1.0 * 0x100) ;
+ ucptr = ((unsigned char*) dest) + 3 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 3 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [2] = 0xFF ;
+ ucptr [1] = 0xFF ;
+ ucptr [0] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [2] = 0x00 ;
+ ucptr [1] = 0x00 ;
+ ucptr [0] = 0x80 ;
+ continue ;
+ } ;
+
+ value = lrint (scaled_value) ;
+ ucptr [2] = value >> 8 ;
+ ucptr [1] = value >> 16 ;
+ ucptr [0] = value >> 24 ;
+ } ;
+} /* d2bet_clip_array */
+
+static sf_count_t
+pcm_write_d2bet (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
+{ 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 (psf->u.ucbuf) / SIZEOF_TRIBYTE ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, (tribyte*) (psf->u.ucbuf), bufferlen, psf->norm_double) ;
+ writecount = psf_fwrite (psf->u.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 ;
+ ucptr = ((unsigned char*) dest) + 4 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 4 ;
+ value = lrint (src [count] * 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 ;
+ ucptr = ((unsigned char*) dest) + 4 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 4 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [3] = 0xFF ;
+ ucptr [2] = 0xFF ;
+ ucptr [1] = 0xFF ;
+ ucptr [0] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [3] = 0x00 ;
+ ucptr [2] = 0x00 ;
+ ucptr [1] = 0x00 ;
+ ucptr [0] = 0x80 ;
+ continue ;
+ } ;
+
+ value = 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)
+{ 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 (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.ibuf, bufferlen, psf->norm_double) ;
+ writecount = psf_fwrite (psf->u.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 ;
+ ucptr = ((unsigned char*) dest) + 4 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 4 ;
+ value = lrint (src [count] * 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 ;
+ ucptr = ((unsigned char*) dest) + 4 * count ;
+
+ while (--count >= 0)
+ { ucptr -= 4 ;
+ scaled_value = src [count] * normfact ;
+ if (CPU_CLIPS_POSITIVE == 0 && scaled_value >= (1.0 * 0x7FFFFFFF))
+ { ucptr [0] = 0xFF ;
+ ucptr [1] = 0xFF ;
+ ucptr [2] = 0xFF ;
+ ucptr [3] = 0x7F ;
+ continue ;
+ } ;
+ if (CPU_CLIPS_NEGATIVE == 0 && scaled_value <= (-8.0 * 0x10000000))
+ { ucptr [0] = 0x00 ;
+ ucptr [1] = 0x00 ;
+ ucptr [2] = 0x00 ;
+ ucptr [3] = 0x80 ;
+ continue ;
+ } ;
+
+ value = 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)
+{ 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 (psf->u.ibuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ convert (ptr + total, psf->u.ibuf, bufferlen, psf->norm_double) ;
+ writecount = psf_fwrite (psf->u.ibuf, sizeof (int), bufferlen, psf) ;
+ total += writecount ;
+ if (writecount < bufferlen)
+ break ;
+ len -= writecount ;
+ } ;
+
+ return total ;
+} /* pcm_write_d2lei */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: d8bc7c0e-1e2f-4ff3-a28f-10ce1fbade3b
+*/
diff --git a/src/pvf.c b/src/pvf.c
new file mode 100644
index 0000000..b759dbb
--- /dev/null
+++ b/src/pvf.c
@@ -0,0 +1,195 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = pvf_read_header (psf)))
+ return error ;
+ } ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != 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 [0] = 0 ;
+ psf->headindex = 0 ;
+
+ if (psf->is_pipe == SF_FALSE)
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ LSF_SNPRINTF ((char*) psf->header, sizeof (psf->header), "PVF1\n%d %d %d\n",
+ psf->sf.channels, psf->sf.samplerate, psf->bytewidth * 8) ;
+
+ psf->headindex = strlen ((char*) psf->header) ;
+
+ /* Header construction complete so write it out. */
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ 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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 20a26761-8bc1-41d7-b1f3-9793bf3d9864
+*/
diff --git a/src/raw.c b/src/raw.c
new file mode 100644
index 0000000..65be491
--- /dev/null
+++ b/src/raw.c
@@ -0,0 +1,111 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+
+#include "sndfile.h"
+#include "common.h"
+
+/*------------------------------------------------------------------------------
+** Public function.
+*/
+
+int
+raw_open (SF_PRIVATE *psf)
+{ int subformat, error = SFE_NO_ERROR ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+
+ 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_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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: f0066de7-d6ce-4f36-a1e0-e475c07d4e1a
+*/
diff --git a/src/rx2.c b/src/rx2.c
new file mode 100644
index 0000000..b3a3090
--- /dev/null
+++ b/src/rx2.c
@@ -0,0 +1,326 @@
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#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"
+ } ;
+
+ 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 (psf->u.cbuf))
+ { psf_log_printf (psf, " Text : %d *** Error : Too sf_count_t!\n") ;
+ return -1001 ;
+ }
+
+ memset (psf->u.cbuf, 0, sizeof (psf->u.cbuf)) ;
+ psf_binheader_readf (psf, "b", psf->u.cbuf, length) ;
+ psf_log_printf (psf, " Text : \"%s\"\n", psf->u.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->logbuffer) ;
+ 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->logbuffer [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->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
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 7366e813-9fee-4d1f-881e-e4a691469370
+*/
diff --git a/src/sd2.c b/src/sd2.c
new file mode 100644
index 0000000..675807b
--- /dev/null
+++ b/src/sd2.c
@@ -0,0 +1,624 @@
+/*
+** Copyright (C) 2001-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#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 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->mode == SFM_READ || (psf->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->rsrcdes < 0\n") ;
+ return SFE_SD2_BAD_RSRC ;
+ } ;
+
+ error = sd2_parse_rsrc_fork (psf) ;
+
+ if (error)
+ goto error_cleanup ;
+ } ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_SD2)
+ { error = SFE_BAD_OPEN_FORMAT ;
+ goto error_cleanup ;
+ } ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+ psf->dataoffset = 0 ;
+
+ /* Only open and write the resource in RDWR mode is its current length is zero. */
+ if (psf->mode == SFM_WRITE || (psf->mode == SFM_RDWR && psf->rsrclength == 0))
+ { psf_open_rsrc (psf, psf->mode) ;
+
+ 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 */
+ 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->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 inline void
+write_char (unsigned char * data, int offset, char value)
+{ data [offset] = value ;
+} /* write_char */
+
+static inline void
+write_short (unsigned char * data, int offset, short value)
+{ data [offset] = value >> 8 ;
+ data [offset + 1] = value ;
+} /* write_char */
+
+static inline void
+write_int (unsigned char * data, int offset, int value)
+{ data [offset] = value >> 24 ;
+ data [offset + 1] = value >> 16 ;
+ data [offset + 2] = value >> 8 ;
+ data [offset + 3] = value ;
+} /* write_int */
+
+static inline void
+write_marker (unsigned char * data, int offset, int value)
+{
+ if (CPU_IS_BIG_ENDIAN)
+ { data [offset] = value >> 24 ;
+ data [offset + 1] = value >> 16 ;
+ data [offset + 2] = value >> 8 ;
+ data [offset + 3] = value ;
+ }
+ else
+ { data [offset] = value ;
+ data [offset + 1] = value >> 8 ;
+ data [offset + 2] = value >> 16 ;
+ data [offset + 3] = value >> 24 ;
+ } ;
+} /* write_marker */
+
+static void
+write_str (unsigned char * data, int offset, char * buffer, int buffer_len)
+{ memcpy (data + offset, buffer, buffer_len) ;
+} /* write_str */
+
+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 ;
+ rsrc.rsrc_len = sizeof (psf->header) ;
+ memset (rsrc.rsrc_data, 0xea, rsrc.rsrc_len) ;
+
+ LSF_SNPRINTF (str_rsrc [0].value, sizeof (str_rsrc [0].value), "_%d", rsrc.sample_size) ;
+ LSF_SNPRINTF (str_rsrc [1].value, sizeof (str_rsrc [1].value), "_%d.000000", rsrc.sample_rate) ;
+ LSF_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. */
+ write_int (rsrc.rsrc_data, 0, rsrc.data_offset) ;
+ write_int (rsrc.rsrc_data, 4, rsrc.map_offset) ;
+ write_int (rsrc.rsrc_data, 8, rsrc.data_length) ;
+
+ write_char (rsrc.rsrc_data, 0x30, strlen (psf->filename)) ;
+ write_str (rsrc.rsrc_data, 0x31, psf->filename, strlen (psf->filename)) ;
+
+ write_short (rsrc.rsrc_data, 0x50, 0) ;
+ write_marker (rsrc.rsrc_data, 0x52, Sd2f_MARKER) ;
+ write_marker (rsrc.rsrc_data, 0x56, lsf1_MARKER) ;
+
+ /* Very start of resource map. */
+ write_int (rsrc.rsrc_data, rsrc.map_offset + 0, rsrc.data_offset) ;
+ write_int (rsrc.rsrc_data, rsrc.map_offset + 4, rsrc.map_offset) ;
+ write_int (rsrc.rsrc_data, rsrc.map_offset + 8, rsrc.data_length) ;
+
+ /* These I don't currently understand. */
+ if (1)
+ { write_char (rsrc.rsrc_data, rsrc.map_offset+ 16, 1) ;
+ /* Next resource map. */
+ write_int (rsrc.rsrc_data, rsrc.map_offset + 17, 0x12345678) ;
+ /* File ref number. */
+ write_short (rsrc.rsrc_data, rsrc.map_offset + 21, 0xabcd) ;
+ /* Fork attributes. */
+ write_short (rsrc.rsrc_data, rsrc.map_offset + 23, 0) ;
+ } ;
+
+ /* Resource type offset. */
+ rsrc.type_offset = rsrc.map_offset + 30 ;
+ write_short (rsrc.rsrc_data, rsrc.map_offset + 24, rsrc.type_offset - rsrc.map_offset - 2) ;
+
+ /* Type index max. */
+ rsrc.type_count = 2 ;
+ write_short (rsrc.rsrc_data, rsrc.map_offset + 28, 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 ;
+ write_short (rsrc.rsrc_data, rsrc.map_offset + 26, rsrc.string_offset) ;
+
+ /* Write 'STR ' resource type. */
+ rsrc.str_count = 3 ;
+ write_marker (rsrc.rsrc_data, rsrc.type_offset, STR_MARKER) ;
+ write_short (rsrc.rsrc_data, rsrc.type_offset + 4, rsrc.str_count - 1) ;
+ write_short (rsrc.rsrc_data, rsrc.type_offset + 6, 0x12) ;
+
+ /* Write 'sdML' resource type. */
+ write_marker (rsrc.rsrc_data, rsrc.type_offset + 8, sdML_MARKER) ;
+ write_short (rsrc.rsrc_data, rsrc.type_offset + 12, 0) ;
+ write_short (rsrc.rsrc_data, rsrc.type_offset + 14, 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++)
+ { write_str (rsrc.rsrc_data, str_offset, str_rsrc [k].name, strlen (str_rsrc [k].name)) ;
+
+ write_short (rsrc.rsrc_data, rsrc.item_offset + k * 12, str_rsrc [k].id) ;
+ write_short (rsrc.rsrc_data, rsrc.item_offset + k * 12 + 2, next_str) ;
+
+ str_offset += strlen (str_rsrc [k].name) ;
+ next_str += strlen (str_rsrc [k].name) ;
+
+ write_int (rsrc.rsrc_data, rsrc.item_offset + k * 12 + 4, data_offset - rsrc.data_offset) ;
+
+ write_int (rsrc.rsrc_data, data_offset, str_rsrc [k].value_len) ;
+ write_str (rsrc.rsrc_data, data_offset + 4, str_rsrc [k].value, 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 ;
+ write_int (rsrc.rsrc_data, 12, rsrc.map_length) ;
+ write_int (rsrc.rsrc_data, rsrc.map_offset + 12, rsrc.map_length) ;
+
+ rsrc.rsrc_len = rsrc.map_offset + rsrc.map_length ;
+
+ psf_fwrite (rsrc.rsrc_data, rsrc.rsrc_len, 1, psf) ;
+
+ psf_use_rsrc (psf, SF_FALSE) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ return 0 ;
+} /* sd2_write_rsrc_fork */
+
+/*------------------------------------------------------------------------------
+*/
+
+static inline int
+read_char (const unsigned char * data, int offset)
+{ return data [offset] ;
+} /* read_char */
+
+static inline int
+read_short (const unsigned char * data, int offset)
+{ return (data [offset] << 8) + data [offset + 1] ;
+} /* read_short */
+
+static inline int
+read_int (const unsigned char * data, int offset)
+{ return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ;
+} /* read_int */
+
+static inline int
+read_marker (const unsigned char * data, int offset)
+{
+ if (CPU_IS_BIG_ENDIAN)
+ return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ;
+ else if (CPU_IS_LITTLE_ENDIAN)
+ return data [offset] + (data [offset + 1] << 8) + (data [offset + 2] << 16) + (data [offset + 3] << 24) ;
+ else
+ return 0x666 ;
+} /* read_marker */
+
+static void
+read_str (const unsigned char * data, int offset, char * buffer, int buffer_len)
+{ int k ;
+
+ memset (buffer, 0, buffer_len) ;
+
+ for (k = 0 ; k < buffer_len - 1 ; k++)
+ { if (isprint (data [offset + k]) == 0)
+ return ;
+ buffer [k] = data [offset + k] ;
+ } ;
+ return ;
+} /* read_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 > SIGNED_SIZEOF (psf->header))
+ rsrc.rsrc_data = calloc (1, rsrc.rsrc_len) ;
+ else
+ rsrc.rsrc_data = psf->header ;
+
+ /* 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->headindex = psf->headend = rsrc.rsrc_len ;
+
+ rsrc.data_offset = read_int (rsrc.rsrc_data, 0) ;
+ rsrc.map_offset = read_int (rsrc.rsrc_data, 4) ;
+ rsrc.data_length = read_int (rsrc.rsrc_data, 8) ;
+ rsrc.map_length = read_int (rsrc.rsrc_data, 12) ;
+
+ if (rsrc.data_offset == 0x51607 && rsrc.map_offset == 0x20000)
+ { psf_log_printf (psf, "Trying offset of 0x52 bytes.\n") ;
+ rsrc.data_offset = read_int (rsrc.rsrc_data, 0x52 + 0) + 0x52 ;
+ rsrc.map_offset = read_int (rsrc.rsrc_data, 0x52 + 4) + 0x52 ;
+ rsrc.data_length = read_int (rsrc.rsrc_data, 0x52 + 8) ;
+ rsrc.map_length = read_int (rsrc.rsrc_data, 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 ;
+ } ;
+
+ rsrc.string_offset = rsrc.map_offset + read_short (rsrc.rsrc_data, 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 ;
+
+ rsrc.type_count = read_short (rsrc.rsrc_data, 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 ++)
+ { marker = read_marker (rsrc.rsrc_data, rsrc.type_offset + k * 8) ;
+
+ if (marker == STR_MARKER)
+ { rsrc.str_index = k ;
+ rsrc.str_count = read_short (rsrc.rsrc_data, 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 ((void *) rsrc.rsrc_data < (void *) psf || (void *) rsrc.rsrc_data > (void *) (psf + 1))
+ 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, data_offset, data_len, rsrc_id ;
+
+ psf_log_printf (psf, "Finding parameters :\n") ;
+
+ str_offset = rsrc->string_offset ;
+ psf_log_printf (psf, " Name Offset RsrcId dlen slen Value\n") ;
+
+ for (k = 0 ; k < rsrc->str_count ; k++)
+ { int slen ;
+
+ slen = read_char (rsrc->rsrc_data, str_offset) ;
+ read_str (rsrc->rsrc_data, str_offset + 1, name, SF_MIN (SIGNED_SIZEOF (name), slen + 1)) ;
+ str_offset += slen + 1 ;
+
+ rsrc_id = read_short (rsrc->rsrc_data, rsrc->item_offset + k * 12) ;
+
+ data_offset = rsrc->data_offset + read_int (rsrc->rsrc_data, rsrc->item_offset + k * 12 + 4) ;
+ if (data_offset < 0 || data_offset > rsrc->rsrc_len)
+ { psf_log_printf (psf, "Bad data offset (%d)\n", data_offset) ;
+ return SFE_SD2_BAD_DATA_OFFSET ;
+ } ;
+
+ data_len = read_int (rsrc->rsrc_data, data_offset) ;
+ if (data_len < 0 || data_len > rsrc->rsrc_len)
+ { psf_log_printf (psf, "Bad data length (%d).\n", data_len) ;
+ return SFE_SD2_BAD_RSRC ;
+ } ;
+
+ slen = read_char (rsrc->rsrc_data, data_offset + 4) ;
+ read_str (rsrc->rsrc_data, data_offset + 5, value, SF_MIN (SIGNED_SIZEOF (value), slen + 1)) ;
+
+ psf_log_printf (psf, " %-12s 0x%04x %4d %2d %2d '%s'\n", name, data_offset, rsrc_id, data_len, slen, value) ;
+
+ if (strcmp (name, "sample-size") == 0 && rsrc->sample_size == 0)
+ rsrc->sample_size = strtol (value, NULL, 10) ;
+ else if (strcmp (name, "sample-rate") == 0 && rsrc->sample_rate == 0)
+ rsrc->sample_rate = strtol (value, NULL, 10) ;
+ else if (strcmp (name, "channels") == 0 && rsrc->channels == 0)
+ rsrc->channels = strtol (value, NULL, 10) ;
+ } ;
+
+ 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 ;
+
+ 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 1ee183e5-6b9f-4c2c-bd0a-24f35595cefc
+*/
diff --git a/src/sds.c b/src/sds.c
new file mode 100644
index 0000000..710d211
--- /dev/null
+++ b/src/sds.c
@@ -0,0 +1,993 @@
+/*
+** Copyright (C) 2002-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+#include "float_cast.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 ;
+ 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_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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = sds_read_header (psf, psds)))
+ return error ;
+ } ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_SDS)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ if (psf->mode == SFM_WRITE || psf->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->seek = sds_seek ;
+ psf->container_close = sds_close ;
+
+ psf->blockwidth = 0 ;
+
+ return error ;
+} /* sds_open */
+
+/*------------------------------------------------------------------------------
+*/
+
+static int
+sds_close (SF_PRIVATE *psf)
+{
+ if (psf->mode == SFM_WRITE || psf->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->mode == SFM_READ || psf->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->mode == SFM_WRITE || psf->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 ;
+
+ psf_log_printf (psf, "Midi Sample Dump Standard (.sds)\nF07E\n Midi Channel : %d\n", channel) ;
+
+ bytesread += psf_binheader_readf (psf, "e213", &sample_no, &bitwidth, &samp_period) ;
+
+ sample_no = SDS_3BYTE_TO_INT_DECODE (sample_no) ;
+ samp_period = SDS_3BYTE_TO_INT_DECODE (samp_period) ;
+
+ psds->bitwidth = bitwidth ;
+
+ psf->sf.samplerate = 1000000000 / samp_period ;
+
+ psf_log_printf (psf, " Sample Number : %d\n"
+ " Bit Width : %d\n"
+ " Sample Rate : %d\n",
+ sample_no, psds->bitwidth, 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) ;
+
+ 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 ;
+
+ if (data_length != psf->filelength - psf->dataoffset)
+ { psf_log_printf (psf, " Datalength : %d (truncated data??? %d)\n", data_length, psf->filelength - psf->dataoffset) ;
+ data_length = psf->filelength - psf->dataoffset ;
+ }
+ else
+ psf_log_printf (psf, " Datalength : %d\n", data_length) ;
+
+ 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 += 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) ;
+
+ psf->sf.frames = blockcount * psds->samplesperblock ;
+ psds->frames = 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_blocks * psds->samplesperblock + psds->write_count ;
+
+ 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 [0] = 0 ;
+ psf->headindex = 0 ;
+
+ if (psf->is_pipe == SF_FALSE)
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ psf_binheader_writef (psf, "E211", 0xF07E, 0, 1) ;
+
+ switch (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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", 0, psds->bitwidth, samp_period) ;
+
+ data_length = SDS_INT_TO_3BYTE_ENCODE (psds->total_blocks * SDS_BLOCK_SIZE) ;
+ sustain_loop_start = SDS_INT_TO_3BYTE_ENCODE (0) ;
+ sustain_loop_end = SDS_INT_TO_3BYTE_ENCODE (psf->sf.frames) ;
+
+ psf_binheader_writef (psf, "e33311", data_length, sustain_loop_start, sustain_loop_end, loop_type, 0xF7) ;
+
+ /* Header construction complete so write it out. */
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+ 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 = 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 = (ucptr [k] << 25) + (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 = 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 = (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 ;
+ 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 = 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 = (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)
+{ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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)
+{ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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)
+{ 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 = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : 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_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] = 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 = 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] = 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 = 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] = 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 = 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)
+{ 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 ;
+
+ iptr = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : len ;
+ for (k = 0 ; k < writecount ; k++)
+ iptr [k] = 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 ;
+
+ 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)
+{ 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 ;
+
+ if (psf->norm_float == SF_TRUE)
+ normfact = 1.0 * 0x80000000 ;
+ else
+ normfact = 1.0 * (1 << psds->bitwidth) ;
+
+ iptr = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : 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)
+{ 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 ;
+
+ if (psf->norm_double == SF_TRUE)
+ normfact = 1.0 * 0x80000000 ;
+ else
+ normfact = 1.0 * (1 << psds->bitwidth) ;
+
+ iptr = psf->u.ibuf ;
+ bufferlen = ARRAY_LEN (psf->u.ibuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: d5d26aa3-368c-4ca6-bb85-377e5a2578cc
+*/
diff --git a/src/sf_unistd.h b/src/sf_unistd.h
new file mode 100644
index 0000000..f24ae67
--- /dev/null
+++ b/src/sf_unistd.h
@@ -0,0 +1,67 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 defines that microsoft 'forgot' to implement. */
+
+#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
+
+#define S_IRWXG 0000070 /* rwx, group */
+#define S_IRGRP 0000040 /* read permission, group */
+#define S_IWGRP 0000020 /* write permission, grougroup */
+#define S_IXGRP 0000010 /* execute/search permission, group */
+
+#define S_IRWXO 0000007 /* rwx, other */
+#define S_IROTH 0000004 /* read permission, other */
+#define S_IWOTH 0000002 /* write permission, other */
+#define S_IXOTH 0000001 /* execute/search permission, other */
+
+#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
+*/
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 253aea6d-6299-46fd-8d06-bc5f6224c8fe
+*/
diff --git a/src/sfconfig.h b/src/sfconfig.h
new file mode 100644
index 0000000..f12df6d
--- /dev/null
+++ b/src/sfconfig.h
@@ -0,0 +1,108 @@
+/*
+** Copyright (C) 2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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_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_PREAD
+#define HAVE_PREAD 0
+#endif
+
+#ifndef HAVE_PWRITE
+#define HAVE_PWRITE 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_UNISTD_H
+#define HAVE_UNISTD_H 0
+#endif
+
+#endif
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 2df2316e-8f9d-4860-bba7-f3c16c63eed3
+*/
diff --git a/src/sfendian.h b/src/sfendian.h
new file mode 100644
index 0000000..651616b
--- /dev/null
+++ b/src/sfendian.h
@@ -0,0 +1,261 @@
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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"
+
+#if HAVE_STDINT_H
+#include <stdint.h>
+#elif HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#if (defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8))
+/* Good, we have int64_t. */
+#elif (defined (SIZEOF_LONG_LONG) && (SIZEOF_LONG_LONG == 8))
+typedef long long int64_t ;
+#elif (defined (SIZEOF_LONG) && (SIZEOF_LONG == 8))
+typedef long int64_t ;
+#elif (defined (WIN32) || defined (_WIN32))
+typedef __int64 int64_t ;
+#else
+#error "No 64 bit integer type."
+#endif
+
+#if HAVE_BYTESWAP_H
+
+#include <byteswap.h>
+
+#define ENDSWAP_SHORT(x) ((short) bswap_16 (x))
+#define ENDSWAP_INT(x) ((int) bswap_32 (x))
+
+#else
+
+#define ENDSWAP_SHORT(x) ((((x) >> 8) & 0xFF) + (((x) & 0xFF) << 8))
+#define ENDSWAP_INT(x) ((((x) >> 24) & 0xFF) + (((x) >> 8) & 0xFF00) + (((x) & 0xFF00) << 8) + (((x) & 0xFF) << 24))
+
+#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) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
+#elif (CPU_IS_BIG_ENDIAN == 1)
+ #define MAKE_MARKER(a,b,c,d) (((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 LES2H_SHORT(x) (x)
+ #define LEI2H_INT(x) (x)
+
+ #define BES2H_SHORT(x) ENDSWAP_SHORT (x)
+ #define BEI2H_INT(x) ENDSWAP_INT (x)
+
+ #define H2BE_SHORT(x) ENDSWAP_SHORT (x)
+ #define H2BE_INT(x) ENDSWAP_INT (x)
+
+#elif (CPU_IS_BIG_ENDIAN == 1)
+ #define LES2H_SHORT(x) ENDSWAP_SHORT (x)
+ #define LEI2H_INT(x) ENDSWAP_INT (x)
+
+ #define BES2H_SHORT(x) (x)
+ #define BEI2H_INT(x) (x)
+
+ #define H2LE_SHORT(x) ENDSWAP_SHORT (x)
+ #define H2LE_INT(x) ENDSWAP_INT (x)
+
+#else
+ #error "Target CPU endian-ness unknown. May need to hand edit src/sfconfig.h"
+#endif
+
+#define LET2H_SHORT_PTR(x) ((x) [1] + ((x) [2] << 8))
+#define LET2H_INT_PTR(x) (((x) [0] << 8) + ((x) [1] << 16) + ((x) [2] << 24))
+
+#define BET2H_SHORT_PTR(x) (((x) [0] << 8) + (x) [1])
+#define BET2H_INT_PTR(x) (((x) [0] << 24) + ((x) [1] << 16) + ((x) [2] << 8))
+
+/*-----------------------------------------------------------------------------------------------
+** Generic functions for performing endian swapping on integer arrays.
+*/
+
+static inline void
+endswap_short_array (short *ptr, int len)
+{ short temp ;
+
+ while (--len >= 0)
+ { temp = ptr [len] ;
+ ptr [len] = ENDSWAP_SHORT (temp) ;
+ } ;
+} /* endswap_short_array */
+
+static inline void
+endswap_short_copy (short *dest, const short *src, int len)
+{
+ while (--len >= 0)
+ { dest [len] = ENDSWAP_SHORT (src [len]) ;
+ } ;
+} /* endswap_short_copy */
+
+static inline void
+endswap_int_array (int *ptr, int len)
+{ int temp ;
+
+ while (--len >= 0)
+ { temp = ptr [len] ;
+ ptr [len] = ENDSWAP_INT (temp) ;
+ } ;
+} /* endswap_int_array */
+
+static inline void
+endswap_int_copy (int *dest, const int *src, int len)
+{
+ while (--len >= 0)
+ { dest [len] = ENDSWAP_INT (src [len]) ;
+ } ;
+} /* endswap_int_copy */
+
+/*========================================================================================
+*/
+
+#if (HAVE_BYTESWAP_H && defined (SIZEOF_INT64_T) && (SIZEOF_INT64_T == 8))
+
+static inline void
+endswap_int64_t_array (int64_t *ptr, int len)
+{ int64_t value ;
+
+ while (--len >= 0)
+ { value = ptr [len] ;
+ ptr [len] = bswap_64 (value) ;
+ } ;
+} /* endswap_int64_t_array */
+
+static inline void
+endswap_int64_t_copy (int64_t *dest, const int64_t *src, int len)
+{ int64_t value ;
+
+ while (--len >= 0)
+ { value = src [len] ;
+ dest [len] = bswap_64 (value) ;
+ } ;
+} /* endswap_int64_t_copy */
+
+#else
+
+static inline void
+endswap_int64_t_array (int64_t *ptr, int len)
+{ unsigned char *ucptr, temp ;
+
+ ucptr = (unsigned char *) ptr ;
+ ucptr += 8 * len ;
+ while (--len >= 0)
+ { ucptr -= 8 ;
+
+ temp = ucptr [0] ;
+ ucptr [0] = ucptr [7] ;
+ ucptr [7] = temp ;
+
+ temp = ucptr [1] ;
+ ucptr [1] = ucptr [6] ;
+ ucptr [6] = temp ;
+
+ temp = ucptr [2] ;
+ ucptr [2] = ucptr [5] ;
+ ucptr [5] = temp ;
+
+ temp = ucptr [3] ;
+ ucptr [3] = ucptr [4] ;
+ ucptr [4] = temp ;
+ } ;
+} /* endswap_int64_t_array */
+
+static inline void
+endswap_int64_t_copy (int64_t *dest, const int64_t *src, int len)
+{ const unsigned char *psrc ;
+ unsigned char *pdest ;
+
+ if (dest == src)
+ { endswap_int64_t_array (dest, len) ;
+ return ;
+ } ;
+
+ psrc = ((const unsigned char *) src) + 8 * len ;
+ pdest = ((unsigned char *) dest) + 8 * len ;
+ while (--len >= 0)
+ { psrc -= 8 ;
+ pdest -= 8 ;
+
+ pdest [0] = psrc [7] ;
+ pdest [2] = psrc [5] ;
+ pdest [4] = psrc [3] ;
+ pdest [6] = psrc [1] ;
+ pdest [7] = psrc [0] ;
+ pdest [1] = psrc [6] ;
+ pdest [3] = psrc [4] ;
+ pdest [5] = psrc [2] ;
+ } ;
+} /* endswap_int64_t_copy */
+
+#endif
+
+/* A couple of wrapper functions. */
+
+static inline void
+endswap_float_array (float *ptr, int len)
+{ endswap_int_array ((void *) ptr, len) ;
+} /* endswap_float_array */
+
+static inline void
+endswap_double_array (double *ptr, int len)
+{ endswap_int64_t_array ((void *) 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: f0c5cd54-42d3-4237-90ec-11fe24995de7
+*/
diff --git a/src/sndfile.c b/src/sndfile.c
new file mode 100644
index 0000000..4ae5bd0
--- /dev/null
+++ b/src/sndfile.c
@@ -0,0 +1,2756 @@
+/*
+** Copyright (C) 1999-2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+
+#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://www.mega-nerd.com/libsndfile/FAQ.html#Q018"
+ #endif
+ #endif
+
+ #ifdef __LITTLE_ENDIAN__
+ #if (CPU_IS_BIG_ENDIAN == 1)
+ #error "Universal binary compile detected. See http://www.mega-nerd.com/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 , "File opened for read. 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_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_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_UNKNOWN_FORMAT , "File contains data in an unknown format." },
+ { 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 , "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_RDWR_FORMAT , "Error : File format cannot be opened for RDWR." },
+ { SFE_BAD_VIRTUAL_IO , "Error : bad pointer on SF_VIRTUAL_IO 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_CONTROL_CMD , "Bad command passed to function sf_command()." },
+ { SFE_BAD_ENDIAN , "Bad endian-ness. Try default endian-ness" },
+ { SFE_CHANNEL_COUNT , "Too many channels specified." },
+
+ { 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 toopen 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_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 file. No 'fmt ' chunk marker." },
+ { SFE_WAV_FMT_SHORT , "Error in WAV 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_GSM610_FORMAT , "Error in GSM610 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 openning 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_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, unknow 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_FMT , "Error in W64 file. No 'fmt ' chunk marker." },
+ { SFE_W64_NO_DATA , "Error in W64 file. No 'data' chunk marker." },
+
+ { SFE_W64_FMT_SHORT , "Error in W64 file. Short 'fmt ' chunk." },
+ { SFE_W64_FMT_TOO_BIG , "Error in W64 file. 'fmt ' chunk too large." },
+
+ { 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_MAT4_ZERO_CHANNELS , "Error in MAT4 file. Channel count is zero." },
+
+ { 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_MAT5_ZERO_CHANNELS , "Error in MAT5 file. Channel count is zero." },
+
+ { 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 while 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_UNKOWN_ERROR , "Error : unkown 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_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 void copy_filename (SF_PRIVATE *psf, const char *path) ;
+static int psf_close (SF_PRIVATE *psf) ;
+static SNDFILE * psf_open_file (SF_PRIVATE *psf, int mode, SF_INFO *sfinfo) ;
+
+static int try_resource_fork (SF_PRIVATE * psf, int mode) ;
+
+/*------------------------------------------------------------------------------
+** Private (static) variables.
+*/
+
+static int sf_errno = 0 ;
+static char sf_logbuffer [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 ;
+
+ if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL)
+ { sf_errno = SFE_MALLOC_FAILED ;
+ return NULL ;
+ } ;
+
+ memset (psf, 0, sizeof (SF_PRIVATE)) ;
+ psf_init_files (psf) ;
+
+ psf_log_printf (psf, "File : %s\n", path) ;
+
+ copy_filename (psf, path) ;
+
+ if (strcmp (path, "-") == 0)
+ psf_set_stdio (psf, mode) ;
+ else
+ psf_fopen (psf, path, mode) ;
+
+ return psf_open_file (psf, mode, sfinfo) ;
+} /* sf_open */
+
+SNDFILE*
+sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc)
+{ SF_PRIVATE *psf ;
+
+ if ((sfinfo->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_SD2)
+ { sf_errno = SFE_SD2_FD_DISALLOWED ;
+ return NULL ;
+ } ;
+
+ if ((psf = calloc (1, sizeof (SF_PRIVATE))) == NULL)
+ { sf_errno = SFE_MALLOC_FAILED ;
+ return NULL ;
+ } ;
+
+ psf_init_files (psf) ;
+
+ psf_set_file (psf, fd) ;
+ psf->is_pipe = psf_is_pipe (psf) ;
+ psf->fileoffset = psf_ftell (psf) ;
+
+ if (! close_desc)
+ psf->do_not_close_descriptor = SF_TRUE ;
+
+ return psf_open_file (psf, mode, 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 || sfvirtual->seek == NULL || sfvirtual->tell == NULL)
+ { sf_errno = SFE_BAD_VIRTUAL_IO ;
+ LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "Bad vio_get_filelen / 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 ;
+ LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "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 ;
+ LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "Bad vio_write in SF_VIRTUAL_IO struct.\n") ;
+ return NULL ;
+ } ;
+
+ if ((psf = calloc (1, sizeof (SF_PRIVATE))) == 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->mode = mode ;
+
+ return psf_open_file (psf, mode, 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)
+ { if (sf_errno != 0)
+ return sf_errno ;
+ return 0 ;
+ } ;
+
+ 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 ;
+ } ;
+
+ LSF_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 = info->format & SF_FORMAT_SUBMASK ;
+ endian = info->format & SF_FORMAT_ENDMASK ;
+
+ /* This is the place where each file format can check if the suppiled
+ ** SF_INFO struct is valid.
+ ** Return 0 on failure, 1 ons success.
+ */
+
+ if (info->channels < 1 || info->channels > 256)
+ return 0 ;
+
+ if (info->samplerate < 0)
+ return 0 ;
+
+ switch (info->format & SF_FORMAT_TYPEMASK)
+ { case SF_FORMAT_WAV :
+ case SF_FORMAT_WAVEX :
+ /* 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 ;
+ 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 ;
+ /* Other encodings. Check for endian-ness. */
+ if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU)
+ 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_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 ;
+ break ;
+
+ case SF_FORMAT_PAF :
+ 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 ;
+ break ;
+
+ case SF_FORMAT_SVX :
+ /* SVX currently does not support more than one channel for write.
+ ** Read will allow more than one channel but only allow one here.
+ */
+ 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) && info->channels == 1)
+ 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 (subformat == SF_FORMAT_PCM_16 || subformat == SF_FORMAT_PCM_24 || 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 :
+ /* 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 :
+ /* HTK is strictly big endian. */
+ if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU)
+ return 0 ;
+ if (info->channels != 1)
+ return 0 ;
+ if (subformat == SF_FORMAT_PCM_16)
+ return 1 ;
+ break ;
+
+ case SF_FORMAT_SDS :
+ /* SDS is strictly big endian. */
+ if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU)
+ return 0 ;
+ if (info->channels != 1)
+ 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 :
+ /* SDS is strictly big endian. */
+ if (endian == SF_ENDIAN_LITTLE || endian == SF_ENDIAN_CPU)
+ return 0 ;
+ if (info->channels > 2)
+ 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 (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)
+ return 1 ;
+ break ;
+
+ case SF_FORMAT_WVE :
+ /* WVE is strictly big endian. */
+ if (endian == SF_ENDIAN_BIG || endian == SF_ENDIAN_CPU)
+ return 0 ;
+ if (info->channels > 1)
+ return 0 ;
+ if (subformat == SF_FORMAT_ALAW)
+ return 1 ;
+ break ;
+
+ default : break ;
+ } ;
+
+ return 0 ;
+} /* sf_format_check */
+
+/*------------------------------------------------------------------------------
+*/
+
+int
+sf_command (SNDFILE *sndfile, int command, void *data, int datasize)
+{ SF_PRIVATE *psf = NULL ;
+ int old_value ;
+
+ /* This set of commands do not need the sndfile parameter. */
+ switch (command)
+ { case SFC_GET_LIB_VERSION :
+ if (data == NULL)
+ return (psf->error = SFE_BAD_CONTROL_CMD) ;
+ if (ENABLE_EXPERIMENTAL_CODE)
+ LSF_SNPRINTF (data, datasize, "%s-%s-exp", PACKAGE_NAME, PACKAGE_VERSION) ;
+ else
+ LSF_SNPRINTF (data, datasize, "%s-%s", PACKAGE_NAME, PACKAGE_VERSION) ;
+ return strlen (data) ;
+
+ case SFC_GET_SIMPLE_FORMAT_COUNT :
+ if (data == NULL || datasize != SIGNED_SIZEOF (int))
+ return (sf_errno = SFE_BAD_CONTROL_CMD) ;
+ *((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_CONTROL_CMD) ;
+ return psf_get_format_simple (data) ;
+
+ case SFC_GET_FORMAT_MAJOR_COUNT :
+ if (data == NULL || datasize != SIGNED_SIZEOF (int))
+ return (sf_errno = SFE_BAD_CONTROL_CMD) ;
+ *((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_CONTROL_CMD) ;
+ return psf_get_format_major (data) ;
+
+ case SFC_GET_FORMAT_SUBTYPE_COUNT :
+ if (data == NULL || datasize != SIGNED_SIZEOF (int))
+ return (sf_errno = SFE_BAD_CONTROL_CMD) ;
+ *((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_CONTROL_CMD) ;
+ 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_CONTROL_CMD) ;
+ return psf_get_format_info (data) ;
+ } ;
+
+ if (sndfile == NULL && command == SFC_GET_LOG_INFO)
+ { if (data == NULL)
+ return (psf->error = SFE_BAD_CONTROL_CMD) ;
+ LSF_SNPRINTF (data, datasize, "%s", sf_logbuffer) ;
+ 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_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)
+ psf->float_max = psf_calc_signal_max (psf, SF_FALSE) ;
+ return old_value ;
+
+ case SFC_SET_ADD_PEAK_CHUNK :
+ { int format = psf->sf.format & SF_FORMAT_TYPEMASK ;
+
+ /* Only WAV and AIFF support the PEAK chunk. */
+ if (format != SF_FORMAT_WAV && format != SF_FORMAT_WAVEX && format != SF_FORMAT_AIFF)
+ return SF_FALSE ;
+
+ format = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ /* 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->mode != SFM_WRITE)
+ return SF_FALSE ;
+ /* If data has already been written this must fail. */
+ if (psf->have_written)
+ 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_GET_LOG_INFO :
+ if (data == NULL)
+ return SFE_BAD_CONTROL_CMD ;
+ LSF_SNPRINTF (data, datasize, "%s", psf->logbuffer) ;
+ break ;
+
+ case SFC_CALC_SIGNAL_MAX :
+ if (data == NULL || datasize != sizeof (double))
+ return (psf->error = SFE_BAD_CONTROL_CMD) ;
+ *((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_CONTROL_CMD) ;
+ *((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_CONTROL_CMD) ;
+ 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_CONTROL_CMD) ;
+ 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_CONTROL_CMD ;
+ 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_CONTROL_CMD ;
+ 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_CONTROL_CMD) ;
+ memcpy (&psf->write_dither, data, sizeof (psf->write_dither)) ;
+ if (psf->mode == SFM_WRITE || psf->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_CONTROL_CMD) ;
+ memcpy (&psf->read_dither, data, sizeof (psf->read_dither)) ;
+ if (psf->mode == SFM_READ || psf->mode == SFM_RDWR)
+ dither_init (psf, SFM_READ) ;
+ break ;
+
+ case SFC_FILE_TRUNCATE :
+ if (psf->mode != SFM_WRITE && psf->mode != SFM_RDWR)
+ return SF_TRUE ;
+ if (datasize != sizeof (sf_count_t))
+ return SF_TRUE ;
+ { 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_CONTROL_CMD) ;
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW)
+ return (psf->error = SFE_BAD_CONTROL_CMD) ;
+
+ 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_CONTROL_CMD) ;
+
+ ((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 ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT)
+ float32_init (psf) ;
+ else if ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_DOUBLE)
+ double64_init (psf) ;
+ else
+ return (psf->error = SFE_BAD_CONTROL_CMD) ;
+ 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)
+ 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 = psf->sf.format & SF_FORMAT_TYPEMASK ;
+
+ /* Only WAV supports the BEXT (Broadcast) chunk. */
+ if (format != SF_FORMAT_WAV && format != SF_FORMAT_WAVEX)
+ return SF_FALSE ;
+ } ;
+
+ /* Only makes sense in SFM_WRITE or SFM_RDWR mode. */
+ if ((psf->mode != SFM_WRITE) && (psf->mode != SFM_RDWR))
+ return SF_FALSE ;
+ /* If data has already been written this must fail. */
+ if (psf->have_written)
+ return SF_FALSE ;
+
+ if (psf->broadcast_info == NULL)
+ psf->broadcast_info = broadcast_info_alloc () ;
+
+ broadcast_info_copy (psf->broadcast_info, data) ;
+ broadcast_add_coding_history (psf->broadcast_info, psf->sf.channels, psf->sf.samplerate) ;
+
+ if (psf->write_header)
+ psf->write_header (psf, SF_TRUE) ;
+ return SF_TRUE ;
+
+ case SFC_GET_BROADCAST_INFO :
+ if (datasize != sizeof (SF_BROADCAST_INFO) || data == NULL)
+ return SF_FALSE ;
+ if (psf->broadcast_info == NULL)
+ return SF_FALSE ;
+ return broadcast_info_copy (data, psf->broadcast_info) ;
+
+ case SFC_GET_INSTRUMENT :
+ if (datasize != sizeof (SF_INSTRUMENT) || data == NULL)
+ 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)
+ return SF_FALSE ;
+ if (datasize != sizeof (SF_INSTRUMENT) || data == NULL)
+ 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 ;
+
+ 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_CONTROL_CMD) ;
+ } ;
+
+ 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->mode == SFM_READ) ||
+ ((whence & SFM_MASK) == SFM_READ && psf->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->mode == SFM_READ)
+ return psf->read_current ;
+ if (psf->mode == SFM_WRITE)
+ return psf->write_current ;
+ } ;
+ if (psf->mode == SFM_READ)
+ seek_from_start = psf->read_current + offset ;
+ else if (psf->mode == SFM_WRITE || psf->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 (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->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 */
+
+/*------------------------------------------------------------------------------
+*/
+
+int
+sf_get_info (SNDFILE * sndfile, SF_INFO * info)
+{ SF_PRIVATE *psf ;
+
+ if (info == NULL)
+ return SF_FALSE ;
+ if ((psf = (SF_PRIVATE*) sndfile) == NULL)
+ return SF_FALSE ;
+ if (psf->Magick != SNDFILE_MAGICK)
+ return SF_FALSE ;
+
+ /* Need to correct psf->sf.frames ???? */
+ memcpy (info, &psf->sf, sizeof (SF_INFO)) ;
+
+ return SF_TRUE ;
+} /* sf_get_info */
+
+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 */
+
+/*==============================================================================
+*/
+
+sf_count_t
+sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes)
+{ SF_PRIVATE *psf ;
+ sf_count_t count ;
+ int bytewidth, blockwidth ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ bytewidth = (psf->bytewidth > 0) ? psf->bytewidth : 1 ;
+ blockwidth = (psf->blockwidth > 0) ? psf->blockwidth : 1 ;
+
+ if (psf->mode == SFM_WRITE)
+ { psf->error = SFE_NOT_READMODE ;
+ return 0 ;
+ } ;
+
+ if (bytes < 0 || psf->read_current >= psf->datalength)
+ { psf_memset (ptr, 0, bytes) ;
+ return 0 ;
+ } ;
+
+ if (bytes % (psf->sf.channels * bytewidth))
+ { psf->error = SFE_BAD_READ_ALIGN ;
+ return 0 ;
+ } ;
+
+ count = psf_fread (ptr, 1, bytes, psf) ;
+
+ if (count < bytes)
+ psf_memset (((char*) ptr) + count, 0, bytes - count) ;
+
+ psf->read_current += count / blockwidth ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->mode == SFM_WRITE)
+ { psf->error = SFE_NOT_READMODE ;
+ return 0 ;
+ } ;
+
+ if (len % psf->sf.channels)
+ { psf->error = SFE_BAD_READ_ALIGN ;
+ return 0 ;
+ } ;
+
+ if (len <= 0 || 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)
+ { 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->read_current += count / psf->sf.channels ;
+
+ psf->last_op = SFM_READ ;
+
+ if (psf->read_current > psf->sf.frames)
+ { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ;
+ psf->read_current = psf->sf.frames ;
+ } ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->mode == SFM_WRITE)
+ { psf->error = SFE_NOT_READMODE ;
+ return 0 ;
+ } ;
+
+ if (frames <= 0 || 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)
+ { 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->read_current += count / psf->sf.channels ;
+
+ psf->last_op = SFM_READ ;
+
+ if (psf->read_current > psf->sf.frames)
+ { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ;
+ psf->read_current = psf->sf.frames ;
+ } ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->mode == SFM_WRITE)
+ { psf->error = SFE_NOT_READMODE ;
+ return 0 ;
+ } ;
+
+ if (len % psf->sf.channels)
+ { psf->error = SFE_BAD_READ_ALIGN ;
+ return 0 ;
+ } ;
+
+ if (len <= 0 || 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)
+ { 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->read_current += count / psf->sf.channels ;
+
+ psf->last_op = SFM_READ ;
+
+ if (psf->read_current > psf->sf.frames)
+ { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ;
+ psf->read_current = psf->sf.frames ;
+ } ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->mode == SFM_WRITE)
+ { psf->error = SFE_NOT_READMODE ;
+ return 0 ;
+ } ;
+
+ if (frames <= 0 || 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)
+ { 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->read_current += count / psf->sf.channels ;
+
+ psf->last_op = SFM_READ ;
+
+ if (psf->read_current > psf->sf.frames)
+ { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ;
+ psf->read_current = psf->sf.frames ;
+ } ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->mode == SFM_WRITE)
+ { psf->error = SFE_NOT_READMODE ;
+ return 0 ;
+ } ;
+
+ if (len % psf->sf.channels)
+ { psf->error = SFE_BAD_READ_ALIGN ;
+ return 0 ;
+ } ;
+
+ if (len <= 0 || 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)
+ { 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->read_current += count / psf->sf.channels ;
+
+ psf->last_op = SFM_READ ;
+
+ if (psf->read_current > psf->sf.frames)
+ { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ;
+ psf->read_current = psf->sf.frames ;
+ } ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->mode == SFM_WRITE)
+ { psf->error = SFE_NOT_READMODE ;
+ return 0 ;
+ } ;
+
+ if (frames <= 0 || 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)
+ { 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->read_current += count / psf->sf.channels ;
+
+ psf->last_op = SFM_READ ;
+
+ if (psf->read_current > psf->sf.frames)
+ { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ;
+ psf->read_current = psf->sf.frames ;
+ } ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->mode == SFM_WRITE)
+ { psf->error = SFE_NOT_READMODE ;
+ return 0 ;
+ } ;
+
+ if (len % psf->sf.channels)
+ { psf->error = SFE_BAD_READ_ALIGN ;
+ return 0 ;
+ } ;
+
+ if (len <= 0 || 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)
+ { 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->read_current += count / psf->sf.channels ;
+
+ psf->last_op = SFM_READ ;
+
+ if (psf->read_current > psf->sf.frames)
+ { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ;
+ psf->read_current = psf->sf.frames ;
+ } ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->mode == SFM_WRITE)
+ { psf->error = SFE_NOT_READMODE ;
+ return 0 ;
+ } ;
+
+ if (frames <= 0 || 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)
+ { 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->read_current += count / psf->sf.channels ;
+
+ psf->last_op = SFM_READ ;
+
+ if (psf->read_current > psf->sf.frames)
+ { count = psf->sf.channels * (psf->read_current - psf->sf.frames) ;
+ psf->read_current = psf->sf.frames ;
+ } ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ bytewidth = (psf->bytewidth > 0) ? psf->bytewidth : 1 ;
+ blockwidth = (psf->blockwidth > 0) ? psf->blockwidth : 1 ;
+
+ if (psf->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->have_written == SF_FALSE && psf->write_header != NULL)
+ psf->write_header (psf, SF_FALSE) ;
+ psf->have_written = SF_TRUE ;
+
+ count = psf_fwrite (ptr, 1, len, psf) ;
+
+ psf->write_current += count / blockwidth ;
+
+ if (psf->write_current > psf->sf.frames)
+ psf->sf.frames = psf->write_current ;
+
+ psf->last_op = SFM_WRITE ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->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)
+ psf->write_header (psf, SF_FALSE) ;
+ 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->auto_header && psf->write_header != NULL)
+ psf->write_header (psf, SF_TRUE) ;
+
+ if (psf->write_current > psf->sf.frames)
+ psf->sf.frames = psf->write_current ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->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)
+ psf->write_header (psf, SF_FALSE) ;
+ 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->auto_header && psf->write_header != NULL)
+ psf->write_header (psf, SF_TRUE) ;
+
+ if (psf->write_current > psf->sf.frames)
+ psf->sf.frames = psf->write_current ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->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)
+ psf->write_header (psf, SF_FALSE) ;
+ 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->auto_header && psf->write_header != NULL)
+ psf->write_header (psf, SF_TRUE) ;
+
+ if (psf->write_current > psf->sf.frames)
+ psf->sf.frames = psf->write_current ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->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)
+ psf->write_header (psf, SF_FALSE) ;
+ 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->auto_header && psf->write_header != NULL)
+ psf->write_header (psf, SF_TRUE) ;
+
+ if (psf->write_current > psf->sf.frames)
+ psf->sf.frames = psf->write_current ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->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)
+ psf->write_header (psf, SF_FALSE) ;
+ 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->auto_header && psf->write_header != NULL)
+ psf->write_header (psf, SF_TRUE) ;
+
+ if (psf->write_current > psf->sf.frames)
+ psf->sf.frames = psf->write_current ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->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)
+ psf->write_header (psf, SF_FALSE) ;
+ 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->auto_header && psf->write_header != NULL)
+ psf->write_header (psf, SF_TRUE) ;
+
+ if (psf->write_current > psf->sf.frames)
+ psf->sf.frames = psf->write_current ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->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)
+ psf->write_header (psf, SF_FALSE) ;
+ 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->auto_header && psf->write_header != NULL)
+ psf->write_header (psf, SF_TRUE) ;
+
+ if (psf->write_current > psf->sf.frames)
+ psf->sf.frames = psf->write_current ;
+
+ 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 ;
+
+ VALIDATE_SNDFILE_AND_ASSIGN_PSF (sndfile, psf, 1) ;
+
+ if (psf->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)
+ psf->write_header (psf, SF_FALSE) ;
+ 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->auto_header && psf->write_header != NULL)
+ psf->write_header (psf, SF_TRUE) ;
+
+ if (psf->write_current > psf->sf.frames)
+ psf->sf.frames = psf->write_current ;
+
+ return count / psf->sf.channels ;
+} /* sf_writef_double */
+
+/*=========================================================================
+** Private functions.
+*/
+
+static int
+try_resource_fork (SF_PRIVATE * psf, int mode)
+{
+ if (psf_open_rsrc (psf, mode) != 0)
+ return 0 ;
+
+ /* More checking here. */
+ psf_log_printf (psf, "Resource fork : %s\n", psf->rsrcpath) ;
+
+ return SF_FORMAT_SD2 ;
+} /* try_resource_fork */
+
+static int
+format_from_extension (SF_PRIVATE *psf)
+{ char *cptr ;
+ char buffer [16] ;
+ int format = 0 ;
+
+ if (psf->filename == NULL)
+ return 0 ;
+
+ if ((cptr = strrchr (psf->filename, '.')) == NULL)
+ return 0 ;
+
+ cptr ++ ;
+ if (strlen (cptr) > sizeof (buffer) - 1)
+ return 0 ;
+
+ strncpy (buffer, cptr, sizeof (buffer)) ;
+ 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)
+ { psf->sf.channels = 1 ;
+ psf->sf.samplerate = 8000 ;
+ 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 ;
+ }
+
+ /* For RAW files, make sure the dataoffset if set correctly. */
+ if ((format & SF_FORMAT_TYPEMASK) == SF_FORMAT_RAW)
+ psf->dataoffset = 0 ;
+
+ return format ;
+} /* format_from_extension */
+
+static int
+guess_file_type (SF_PRIVATE *psf)
+{ int buffer [3], format ;
+
+ 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 (ENABLE_EXPERIMENTAL_CODE && 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 ('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 (2 * BEI2H_INT (buffer [0]) + 12 == psf->filelength && buffer [2] == MAKE_MARKER (0, 2, 0, 0))
+ return SF_FORMAT_HTK ;
+
+ if (buffer [0] == MAKE_MARKER ('f', 'L', 'a', 'C'))
+ return SF_FORMAT_FLAC ;
+
+ /* Turtle Beach SMP 16-bit */
+ if (buffer [0] == MAKE_MARKER ('S', 'O', 'U', 'N') && buffer [1] == MAKE_MARKER ('D', ' ', 'S', 'A'))
+ return 0 ;
+
+ 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-*/ ;
+
+ if (buffer [0] == MAKE_MARKER ('2', 'B', 'I', 'T'))
+ return SF_FORMAT_AVR ;
+
+ /* This must be the second last one. */
+ if (psf->filelength > 0 && (format = try_resource_fork (psf, SFM_READ)) != 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)
+ return 0 ;
+ if ((sfinfo->format & SF_FORMAT_TYPEMASK) == 0)
+ return 0 ;
+ if ((sfinfo->format & SF_FORMAT_SUBMASK) == 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)
+{ LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "%s", psf->logbuffer) ;
+} /* save_header_info */
+
+static void
+copy_filename (SF_PRIVATE *psf, const char *path)
+{ const char *ccptr ;
+ char *cptr ;
+
+ LSF_SNPRINTF (psf->filepath, sizeof (psf->filepath), "%s", path) ;
+ if ((ccptr = strrchr (path, '/')) || (ccptr = strrchr (path, '\\')))
+ ccptr ++ ;
+ else
+ ccptr = path ;
+
+ LSF_SNPRINTF (psf->filename, sizeof (psf->filename), "%s", ccptr) ;
+
+ /* Now grab the directory. */
+ LSF_SNPRINTF (psf->directory, sizeof (psf->directory), "%s", path) ;
+ if ((cptr = strrchr (psf->directory, '/')) || (cptr = strrchr (psf->directory, '\\')))
+ cptr [1] = 0 ;
+ else
+ psf->directory [0] = 0 ;
+
+ return ;
+} /* copy_filename */
+
+/*==============================================================================
+*/
+
+static int
+psf_close (SF_PRIVATE *psf)
+{ int error ;
+
+ if (psf->codec_close)
+ error = psf->codec_close (psf) ;
+ if (psf->container_close)
+ error = psf->container_close (psf) ;
+
+ psf_fclose (psf) ;
+ psf_close_rsrc (psf) ;
+
+ if (psf->container_data)
+ free (psf->container_data) ;
+
+ if (psf->codec_data)
+ free (psf->codec_data) ;
+
+ if (psf->interleave)
+ free (psf->interleave) ;
+
+ if (psf->dither)
+ free (psf->dither) ;
+
+ if (psf->peak_info)
+ free (psf->peak_info) ;
+
+ if (psf->broadcast_info)
+ free (psf->broadcast_info) ;
+
+ if (psf->loop_info)
+ free (psf->loop_info) ;
+
+ if (psf->instrument)
+ free (psf->instrument) ;
+
+ if (psf->channel_map)
+ free (psf->channel_map) ;
+
+ if (psf->format_desc)
+ { memset (psf->format_desc, 0, strlen (psf->format_desc)) ;
+ free (psf->format_desc) ;
+ } ;
+
+ memset (psf, 0, sizeof (SF_PRIVATE)) ;
+ free (psf) ;
+
+ return 0 ;
+} /* psf_close */
+
+static SNDFILE *
+psf_open_file (SF_PRIVATE *psf, int mode, SF_INFO *sfinfo)
+{ int error, format ;
+
+ sf_errno = error = 0 ;
+ sf_logbuffer [0] = 0 ;
+
+ if (psf->error)
+ { error = psf->error ;
+ goto error_exit ;
+ } ;
+
+ if (mode != SFM_READ && mode != SFM_WRITE && mode != SFM_RDWR)
+ { error = SFE_BAD_OPEN_MODE ;
+ goto error_exit ;
+ } ;
+
+ if (sfinfo == NULL)
+ { error = SFE_BAD_SF_INFO_PTR ;
+ goto error_exit ;
+ } ;
+
+ /* Zero out these fields. */
+ sfinfo->frames = 0 ;
+ sfinfo->sections = 0 ;
+ sfinfo->seekable = 0 ;
+
+ if (mode == SFM_READ)
+ { if ((sfinfo->format & SF_FORMAT_TYPEMASK) == 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->mode = mode ;
+ 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 ;
+
+ /*
+ ** File formats that support ambisonic should override this default
+ ** and set it to SF_AMBISONIC_NONE.
+ */
+ psf->wavex_ambisonic = 0 ;
+ 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->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 (mode == SFM_WRITE || (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_format_check (&(psf->sf)) == 0)
+ { error = SFE_BAD_OPEN_FORMAT ;
+ goto error_exit ;
+ } ;
+ }
+ else if ((psf->sf.format & SF_FORMAT_TYPEMASK) != 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->mode ;
+
+ /* Set bytewidth if known. */
+ switch (psf->sf.format & SF_FORMAT_SUBMASK)
+ { 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 (psf->sf.format & SF_FORMAT_TYPEMASK)
+ { 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 ;
+
+ /* 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 ;
+
+ /* Lite remove end */
+
+ default :
+ error = SFE_UNKNOWN_FORMAT ;
+ } ;
+
+ if (error)
+ goto error_exit ;
+
+ /* For now, check whether embedding is supported. */
+ format = psf->sf.format & SF_FORMAT_TYPEMASK ;
+ if (psf->fileoffset > 0 &&
+ (format != SF_FORMAT_WAV) && (format != SF_FORMAT_WAVEX) &&
+ (format != SF_FORMAT_AIFF) && (format != SF_FORMAT_AU)
+ )
+ { error = SFE_NO_EMBED_SUPPORT ;
+ goto error_exit ;
+ } ;
+
+ if (psf->fileoffset > 0)
+ psf_log_printf (psf, "Embedded file length : %D\n", psf->filelength) ;
+
+ if (mode == SFM_RDWR && sf_format_check (&(psf->sf)) == 0)
+ { error = SFE_BAD_RDWR_FORMAT ;
+ 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 = (psf->mode == SFM_RDWR) ? psf->sf.frames : 0 ;
+
+ memcpy (sfinfo, &(psf->sf), sizeof (SF_INFO)) ;
+
+ memcpy (sfinfo, &(psf->sf), sizeof (SF_INFO)) ;
+
+ return (SNDFILE *) psf ;
+
+error_exit :
+ sf_errno = error ;
+
+ if (error == SFE_SYSTEM)
+ LSF_SNPRINTF (sf_syserr, sizeof (sf_syserr), "%s", psf->syserr) ;
+ LSF_SNPRINTF (sf_logbuffer, sizeof (sf_logbuffer), "%s", psf->logbuffer) ;
+
+ switch (error)
+ { case SF_ERR_SYSTEM :
+ case SF_ERR_UNSUPPORTED_ENCODING :
+ case SFE_UNIMPLEMENTED :
+ break ;
+
+ case SFE_RAW_BAD_FORMAT :
+ break ;
+
+ default :
+ if (psf->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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: cd4f9e91-a8ec-4154-9bf6-fe4b8c69a615
+*/
diff --git a/src/sndfile.h.in b/src/sndfile.h.in
new file mode 100644
index 0000000..2f55e87
--- /dev/null
+++ b/src/sndfile.h.in
@@ -0,0 +1,602 @@
+/*
+** Copyright (C) 1999-2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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.
+*/
+
+/*
+** sndfile.h -- system-wide definitions
+**
+** API documentation is in the doc/ directory of the source code tarball
+** and at http://www.mega-nerd.com/libsndfile/api.html.
+*/
+
+#ifndef SNDFILE_H
+#define SNDFILE_H
+
+/* This is the version 1.0.X header file. */
+#define SNDFILE_1
+
+#include <stdio.h>
+
+/* For the Metrowerks CodeWarrior Pro Compiler (mainly MacOS) */
+
+#if (defined (__MWERKS__))
+#include <unix.h>
+#else
+#include <sys/types.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* The following file types can be read and written.
+** A file type would consist of a major type (ie SF_FORMAT_WAV) bitwise
+** ORed with a minor type (ie SF_FORMAT_PCM). SF_FORMAT_TYPEMASK and
+** SF_FORMAT_SUBMASK can be used to separate the major and minor file
+** types.
+*/
+
+enum
+{ /* Major formats. */
+ SF_FORMAT_WAV = 0x010000, /* Microsoft WAV format (little endian default). */
+ 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 */
+
+ /* 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
+} ;
+
+/*
+** The following are the valid command numbers for the sf_command()
+** interface. The use of these commands is documented in the file
+** command.html in the doc directory of the source code distribution.
+*/
+
+enum
+{ SFC_GET_LIB_VERSION = 0x1000,
+ SFC_GET_LOG_INFO = 0x1001,
+
+ SFC_GET_NORM_DOUBLE = 0x1010,
+ SFC_GET_NORM_FLOAT = 0x1011,
+ SFC_SET_NORM_DOUBLE = 0x1012,
+ SFC_SET_NORM_FLOAT = 0x1013,
+ SFC_SET_SCALE_FLOAT_INT_READ = 0x1014,
+
+ SFC_GET_SIMPLE_FORMAT_COUNT = 0x1020,
+ SFC_GET_SIMPLE_FORMAT = 0x1021,
+
+ SFC_GET_FORMAT_INFO = 0x1028,
+
+ SFC_GET_FORMAT_MAJOR_COUNT = 0x1030,
+ SFC_GET_FORMAT_MAJOR = 0x1031,
+ SFC_GET_FORMAT_SUBTYPE_COUNT = 0x1032,
+ SFC_GET_FORMAT_SUBTYPE = 0x1033,
+
+ SFC_CALC_SIGNAL_MAX = 0x1040,
+ SFC_CALC_NORM_SIGNAL_MAX = 0x1041,
+ SFC_CALC_MAX_ALL_CHANNELS = 0x1042,
+ SFC_CALC_NORM_MAX_ALL_CHANNELS = 0x1043,
+ SFC_GET_SIGNAL_MAX = 0x1044,
+ SFC_GET_MAX_ALL_CHANNELS = 0x1045,
+
+ SFC_SET_ADD_PEAK_CHUNK = 0x1050,
+
+ SFC_UPDATE_HEADER_NOW = 0x1060,
+ SFC_SET_UPDATE_HEADER_AUTO = 0x1061,
+
+ SFC_FILE_TRUNCATE = 0x1080,
+
+ SFC_SET_RAW_START_OFFSET = 0x1090,
+
+ SFC_SET_DITHER_ON_WRITE = 0x10A0,
+ SFC_SET_DITHER_ON_READ = 0x10A1,
+
+ SFC_GET_DITHER_INFO_COUNT = 0x10A2,
+ SFC_GET_DITHER_INFO = 0x10A3,
+
+ SFC_GET_EMBED_FILE_INFO = 0x10B0,
+
+ SFC_SET_CLIPPING = 0x10C0,
+ SFC_GET_CLIPPING = 0x10C1,
+
+ SFC_GET_INSTRUMENT = 0x10D0,
+ SFC_SET_INSTRUMENT = 0x10D1,
+
+ SFC_GET_LOOP_INFO = 0x10E0,
+
+ SFC_GET_BROADCAST_INFO = 0x10F0,
+ SFC_SET_BROADCAST_INFO = 0x10F1,
+
+ SFC_GET_CHANNEL_MAP_INFO = 0x1100,
+ SFC_SET_CHANNEL_MAP_INFO = 0x1101,
+
+ /* Support for Wavex Ambisonics Format */
+ SFC_WAVEX_SET_AMBISONIC = 0x1200,
+ SFC_WAVEX_GET_AMBISONIC = 0x1201,
+
+ /* Following commands for testing only. */
+ SFC_TEST_IEEE_FLOAT_REPLACE = 0x6001,
+
+ /*
+ ** SFC_SET_ADD_* values are deprecated and will disappear at some
+ ** time in the future. They are guaranteed to be here up to and
+ ** including version 1.0.8 to avoid breakage of existng software.
+ ** They currently do nothing and will continue to do nothing.
+ */
+ SFC_SET_ADD_DITHER_ON_WRITE = 0x1070,
+ SFC_SET_ADD_DITHER_ON_READ = 0x1071
+} ;
+
+
+/*
+** String types that can be set and read from files. Not all file types
+** support this and even the file types which support one, may not support
+** all string types.
+*/
+
+enum
+{ SF_STR_TITLE = 0x01,
+ SF_STR_COPYRIGHT = 0x02,
+ SF_STR_SOFTWARE = 0x03,
+ SF_STR_ARTIST = 0x04,
+ SF_STR_COMMENT = 0x05,
+ SF_STR_DATE = 0x06
+} ;
+
+/*
+** Use the following as the start and end index when doing metadata
+** transcoding.
+*/
+
+#define SF_STR_FIRST SF_STR_TITLE
+#define SF_STR_LAST SF_STR_DATE
+
+enum
+{ /* True and false */
+ SF_FALSE = 0,
+ SF_TRUE = 1,
+
+ /* Modes for opening files. */
+ SFM_READ = 0x10,
+ SFM_WRITE = 0x20,
+ SFM_RDWR = 0x30,
+
+ SF_AMBISONIC_NONE = 0x40,
+ SF_AMBISONIC_B_FORMAT = 0x41
+} ;
+
+/* Public error values. These are guaranteed to remain unchanged for the duration
+** of the library major version number.
+** There are also a large number of private error numbers which are internal to
+** the library which can change at any time.
+*/
+
+enum
+{ SF_ERR_NO_ERROR = 0,
+ SF_ERR_UNRECOGNISED_FORMAT = 1,
+ SF_ERR_SYSTEM = 2,
+ SF_ERR_MALFORMED_FILE = 3,
+ SF_ERR_UNSUPPORTED_ENCODING = 4
+} ;
+
+
+/* Channel map values (used with SFC_SET/GET_CHANNEL_MAP).
+*/
+
+enum
+{ SF_CHANNEL_MAP_INVALID = 0,
+ SF_CHANNEL_MAP_MONO = 1,
+ SF_CHANNEL_MAP_LEFT,
+ SF_CHANNEL_MAP_RIGHT,
+ SF_CHANNEL_MAP_CENTER,
+ SF_CHANNEL_MAP_FRONT_LEFT,
+ SF_CHANNEL_MAP_FRONT_RIGHT,
+ SF_CHANNEL_MAP_FRONT_CENTER,
+ SF_CHANNEL_MAP_REAR_CENTER,
+ SF_CHANNEL_MAP_REAR_LEFT,
+ SF_CHANNEL_MAP_REAR_RIGHT,
+ SF_CHANNEL_MAP_LFE,
+ SF_CHANNEL_MAP_FRONT_LEFT_OF_CENTER,
+ SF_CHANNEL_MAP_FRONT_RIGHT_OF_CENTER,
+ SF_CHANNEL_MAP_SIDE_LEFT,
+ SF_CHANNEL_MAP_SIDE_RIGHT,
+ SF_CHANNEL_MAP_TOP_CENTER,
+ SF_CHANNEL_MAP_TOP_FRONT_LEFT,
+ SF_CHANNEL_MAP_TOP_FRONT_RIGHT,
+ SF_CHANNEL_MAP_TOP_FRONT_CENTER,
+ SF_CHANNEL_MAP_TOP_REAR_LEFT,
+ SF_CHANNEL_MAP_TOP_REAR_RIGHT,
+ SF_CHANNEL_MAP_TOP_REAR_CENTER
+} ;
+
+
+/* A SNDFILE* pointer can be passed around much like stdio.h's FILE* pointer. */
+
+typedef struct SNDFILE_tag SNDFILE ;
+
+/* The following typedef is system specific and is defined when libsndfile is.
+** compiled. sf_count_t can be one of loff_t (Linux), off_t (*BSD),
+** off64_t (Solaris), __int64_t (Win32) etc.
+*/
+
+typedef @TYPEOF_SF_COUNT_T@ sf_count_t ;
+
+#define SF_COUNT_MAX @SF_COUNT_MAX@
+
+/* A pointer to a SF_INFO structure is passed to sf_open_read () and filled in.
+** On write, the SF_INFO structure is filled in by the user and passed into
+** sf_open_write ().
+*/
+
+struct SF_INFO
+{ sf_count_t frames ; /* Used to be called samples. Changed to avoid confusion. */
+ int samplerate ;
+ int channels ;
+ int format ;
+ int sections ;
+ int seekable ;
+} ;
+
+typedef struct SF_INFO SF_INFO ;
+
+/* The SF_FORMAT_INFO struct is used to retrieve information about the sound
+** file formats libsndfile supports using the sf_command () interface.
+**
+** Using this interface will allow applications to support new file formats
+** and encoding types when libsndfile is upgraded, without requiring
+** re-compilation of the application.
+**
+** Please consult the libsndfile documentation (particularly the information
+** on the sf_command () interface) for examples of its use.
+*/
+
+typedef struct
+{ int format ;
+ const char *name ;
+ const char *extension ;
+} SF_FORMAT_INFO ;
+
+/*
+** Enums and typedefs for adding dither on read and write.
+** See the html documentation for sf_command(), SFC_SET_DITHER_ON_WRITE
+** and SFC_SET_DITHER_ON_READ.
+*/
+
+enum
+{ SFD_DEFAULT_LEVEL = 0,
+ SFD_CUSTOM_LEVEL = 0x40000000,
+
+ SFD_NO_DITHER = 500,
+ SFD_WHITE = 501,
+ SFD_TRIANGULAR_PDF = 502
+} ;
+
+typedef struct
+{ int type ;
+ double level ;
+ const char *name ;
+} SF_DITHER_INFO ;
+
+/* Struct used to retrieve information about a file embedded within a
+** larger file. See SFC_GET_EMBED_FILE_INFO.
+*/
+
+typedef struct
+{ sf_count_t offset ;
+ sf_count_t length ;
+} SF_EMBED_FILE_INFO ;
+
+/*
+** Structs used to retrieve music sample information from a file.
+*/
+
+enum
+{ /*
+ ** The loop mode field in SF_INSTRUMENT will be one of the following.
+ */
+ SF_LOOP_NONE = 800,
+ SF_LOOP_FORWARD,
+ SF_LOOP_BACKWARD,
+ SF_LOOP_ALTERNATING
+} ;
+
+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 ;
+
+
+
+/* Struct used to retrieve loop information from a file.*/
+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 lenght, 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 ;
+
+
+/* Struct used to retrieve broadcast (EBU) information from a file.
+** Strongly (!) based on EBU "bext" chunk format used in Broadcast WAVE.
+*/
+typedef struct
+{ char description [256] ;
+ char originator [32] ;
+ char originator_reference [32] ;
+ char origination_date [10] ;
+ char origination_time [8] ;
+ int time_reference_low ;
+ int time_reference_high ;
+ short version ;
+ char umid [64] ;
+ char reserved [190] ;
+ unsigned int coding_history_size ;
+ char coding_history [256] ;
+} SF_BROADCAST_INFO ;
+
+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) ;
+
+struct SF_VIRTUAL_IO
+{ sf_vio_get_filelen get_filelen ;
+ sf_vio_seek seek ;
+ sf_vio_read read ;
+ sf_vio_write write ;
+ sf_vio_tell tell ;
+} ;
+
+typedef struct SF_VIRTUAL_IO SF_VIRTUAL_IO ;
+
+/* Open the specified file for read, write or both. On error, this will
+** return a NULL pointer. To find the error number, pass a NULL SNDFILE
+** to sf_perror () or sf_error_str ().
+** All calls to sf_open() should be matched with a call to sf_close().
+*/
+
+SNDFILE* sf_open (const char *path, int mode, SF_INFO *sfinfo) ;
+
+/* Use the existing file descriptor to create a SNDFILE object. If close_desc
+** is TRUE, the file descriptor will be closed when sf_close() is called. If
+** it is FALSE, the descritor will not be closed.
+** When passed a descriptor like this, the library will assume that the start
+** of file header is at the current file offset. This allows sound files within
+** larger container files to be read and/or written.
+** On error, this will return a NULL pointer. To find the error number, pass a
+** NULL SNDFILE to sf_perror () or sf_error_str ().
+** All calls to sf_open_fd() should be matched with a call to sf_close().
+
+*/
+
+SNDFILE* sf_open_fd (int fd, int mode, SF_INFO *sfinfo, int close_desc) ;
+
+SNDFILE* sf_open_virtual (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data) ;
+
+/* sf_error () returns a error number which can be translated to a text
+** string using sf_error_number().
+*/
+
+int sf_error (SNDFILE *sndfile) ;
+
+/* sf_strerror () returns to the caller a pointer to the current error message for
+** the given SNDFILE.
+*/
+
+const char* sf_strerror (SNDFILE *sndfile) ;
+
+/* sf_error_number () allows the retrieval of the error string for each internal
+** error number.
+**
+*/
+
+const char* sf_error_number (int errnum) ;
+
+/* The following three error functions are deprecated but they will remain in the
+** library for the forseeable future. The function sf_strerror() should be used
+** in their place.
+*/
+
+int sf_perror (SNDFILE *sndfile) ;
+int sf_error_str (SNDFILE *sndfile, char* str, size_t len) ;
+
+
+/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */
+
+int sf_command (SNDFILE *sndfile, int command, void *data, int datasize) ;
+
+/* Return TRUE if fields of the SF_INFO struct are a valid combination of values. */
+
+int sf_format_check (const SF_INFO *info) ;
+
+/* Seek within the waveform data chunk of the SNDFILE. sf_seek () uses
+** the same values for whence (SEEK_SET, SEEK_CUR and SEEK_END) as
+** stdio.h function fseek ().
+** An offset of zero with whence set to SEEK_SET will position the
+** read / write pointer to the first data sample.
+** On success sf_seek returns the current position in (multi-channel)
+** samples from the start of the file.
+** Please see the libsndfile documentation for moving the read pointer
+** separately from the write pointer on files open in mode SFM_RDWR.
+** On error all of these functions return -1.
+*/
+
+sf_count_t sf_seek (SNDFILE *sndfile, sf_count_t frames, int whence) ;
+
+/* Retrieve the SF_INFO struct for the given SNDFILE. Returns SF_FALSE on
+** failure, SF_TRUE otherwise.
+*/
+
+int sf_get_info (SNDFILE * sndfile, SF_INFO * info) ;
+
+/* Functions for retrieving and setting string data within sound files.
+** Not all file types support this features; AIFF and WAV do. For both
+** functions, the str_type parameter must be one of the SF_STR_* values
+** defined above.
+** On error, sf_set_string() returns non-zero while sf_get_string()
+** returns NULL.
+*/
+
+int sf_set_string (SNDFILE *sndfile, int str_type, const char* str) ;
+
+const char* sf_get_string (SNDFILE *sndfile, int str_type) ;
+
+/* Functions for reading/writing the waveform data of a sound file.
+*/
+
+sf_count_t sf_read_raw (SNDFILE *sndfile, void *ptr, sf_count_t bytes) ;
+sf_count_t sf_write_raw (SNDFILE *sndfile, const void *ptr, sf_count_t bytes) ;
+
+/* Functions for reading and writing the data chunk in terms of frames.
+** The number of items actually read/written = frames * number of channels.
+** sf_xxxx_raw read/writes the raw data bytes from/to the file
+** sf_xxxx_short passes data in the native short format
+** sf_xxxx_int passes data in the native int format
+** sf_xxxx_float passes data in the native float format
+** sf_xxxx_double passes data in the native double format
+** All of these read/write function return number of frames read/written.
+*/
+
+sf_count_t sf_readf_short (SNDFILE *sndfile, short *ptr, sf_count_t frames) ;
+sf_count_t sf_writef_short (SNDFILE *sndfile, const short *ptr, sf_count_t frames) ;
+
+sf_count_t sf_readf_int (SNDFILE *sndfile, int *ptr, sf_count_t frames) ;
+sf_count_t sf_writef_int (SNDFILE *sndfile, const int *ptr, sf_count_t frames) ;
+
+sf_count_t sf_readf_float (SNDFILE *sndfile, float *ptr, sf_count_t frames) ;
+sf_count_t sf_writef_float (SNDFILE *sndfile, const float *ptr, sf_count_t frames) ;
+
+sf_count_t sf_readf_double (SNDFILE *sndfile, double *ptr, sf_count_t frames) ;
+sf_count_t sf_writef_double (SNDFILE *sndfile, const double *ptr, sf_count_t frames) ;
+
+/* Functions for reading and writing the data chunk in terms of items.
+** Otherwise similar to above.
+** All of these read/write function return number of items read/written.
+*/
+
+sf_count_t sf_read_short (SNDFILE *sndfile, short *ptr, sf_count_t items) ;
+sf_count_t sf_write_short (SNDFILE *sndfile, const short *ptr, sf_count_t items) ;
+
+sf_count_t sf_read_int (SNDFILE *sndfile, int *ptr, sf_count_t items) ;
+sf_count_t sf_write_int (SNDFILE *sndfile, const int *ptr, sf_count_t items) ;
+
+sf_count_t sf_read_float (SNDFILE *sndfile, float *ptr, sf_count_t items) ;
+sf_count_t sf_write_float (SNDFILE *sndfile, const float *ptr, sf_count_t items) ;
+
+sf_count_t sf_read_double (SNDFILE *sndfile, double *ptr, sf_count_t items) ;
+sf_count_t sf_write_double (SNDFILE *sndfile, const double *ptr, sf_count_t items) ;
+
+/* Close the SNDFILE and clean up all memory allocations associated with this
+** file.
+** Returns 0 on success, or an error number.
+*/
+
+int sf_close (SNDFILE *sndfile) ;
+
+/* If the file is opened SFM_WRITE or SFM_RDWR, call fsync() on the file
+** to force the writing of data to disk. If the file is opened SFM_READ
+** no action is taken.
+*/
+
+void sf_write_sync (SNDFILE *sndfile) ;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* SNDFILE_H */
diff --git a/src/sndfile.hh b/src/sndfile.hh
new file mode 100644
index 0000000..dcf2773
--- /dev/null
+++ b/src/sndfile.hh
@@ -0,0 +1,351 @@
+/*
+** Copyright (C) 2005,2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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://www.mega-nerd.com/libsndfile/api.html.
+*/
+
+#ifndef SNDFILE_HH
+#define SNDFILE_HH
+
+#include <sndfile.h>
+
+#include <string>
+#include <new> // for std::nothrow
+
+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 (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 (void) ;
+
+ SndfileHandle (const SndfileHandle &orig) ;
+ SndfileHandle & operator = (const SndfileHandle &rhs) ;
+
+ /* Mainly for debugging/testing. */
+ int refCount (void) const { return (p == NULL) ? 0 : p->ref ; }
+
+ operator bool () const { return (p != 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) ;
+
+} ;
+
+/*==============================================================================
+** Nothing but implementation below.
+*/
+
+inline
+SndfileHandle::SNDFILE_ref::SNDFILE_ref (void)
+: ref (1)
+{}
+
+inline
+SndfileHandle::SNDFILE_ref::~SNDFILE_ref (void)
+{ if (sf != NULL) sf_close (sf) ; }
+
+inline
+SndfileHandle::SndfileHandle (const char *path, int mode, int fmt, int chans, int srate)
+: p (NULL)
+{
+ p = new (std::nothrow) SNDFILE_ref () ;
+
+ if (p != 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 ;
+
+ if ((p->sf = sf_open (path, mode, &p->sfinfo)) == NULL)
+ { delete p ;
+ p = NULL ;
+ } ;
+ } ;
+} /* SndfileHandle const char * constructor */
+
+inline
+SndfileHandle::SndfileHandle (std::string const & path, int mode, int fmt, int chans, int srate)
+: p (NULL)
+{
+ p = new (std::nothrow) SNDFILE_ref () ;
+
+ if (p != 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 ;
+
+ if ((p->sf = sf_open (path.c_str (), mode, &p->sfinfo)) == NULL)
+ { delete p ;
+ p = NULL ;
+ } ;
+ } ;
+} /* SndfileHandle std::string constructor */
+
+inline
+SndfileHandle::~SndfileHandle (void)
+{ if (p != NULL && --p->ref == 0)
+ delete p ;
+} /* SndfileHandle destructor */
+
+
+inline
+SndfileHandle::SndfileHandle (const SndfileHandle &orig)
+: p (orig.p)
+{ if (p != NULL)
+ ++p->ref ;
+} /* SndfileHandle copy constructor */
+
+inline SndfileHandle &
+SndfileHandle::operator = (const SndfileHandle &rhs)
+{
+ if (&rhs == this)
+ return *this ;
+ if (p != NULL && --p->ref == 0)
+ delete p ;
+
+ p = rhs.p ;
+ if (p != NULL)
+ ++p->ref ;
+
+ return *this ;
+} /* SndfileHandle assignment operator */
+
+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) ; }
+
+
+#endif /* SNDFILE_HH */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The following line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: a0e9d996-73d7-47c4-a78d-79a3232a9eef
+*/
diff --git a/src/strings.c b/src/strings.c
new file mode 100644
index 0000000..2433f9b
--- /dev/null
+++ b/src/strings.c
@@ -0,0 +1,204 @@
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#include "sndfile.h"
+#include "common.h"
+
+#define STRINGS_DEBUG 0
+#if STRINGS_DEBUG
+static void hexdump (void *data, int len) ;
+#endif
+
+int
+psf_store_string (SF_PRIVATE *psf, int str_type, const char *str)
+{ static char lsf_name [] = PACKAGE "-" VERSION ;
+ static char bracket_name [] = " (" PACKAGE "-" VERSION ")" ;
+ int k, str_len, len_remaining, str_flags ;
+
+ if (str == NULL)
+ return SFE_STR_BAD_STRING ;
+
+ str_len = strlen (str) ;
+
+ /* A few extra checks for write mode. */
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if ((psf->str_flags & SF_STR_ALLOW_START) == 0)
+ return SFE_STR_NO_SUPPORT ;
+ if ((psf->str_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 ;
+ } ;
+
+ /* Determine flags */
+ str_flags = SF_STR_LOCATE_START ;
+ if (psf->have_written)
+ { if ((psf->str_flags & SF_STR_ALLOW_END) == 0)
+ return SFE_STR_NO_ADD_END ;
+ str_flags = SF_STR_LOCATE_END ;
+ } ;
+
+ /* Find next free slot in table. */
+ for (k = 0 ; k < SF_MAX_STRINGS ; k++)
+ if (psf->strings [k].type == 0)
+ break ;
+
+ /* More sanity checking. */
+ if (k >= SF_MAX_STRINGS)
+ return SFE_STR_MAX_COUNT ;
+
+ if (k == 0 && psf->str_end != NULL)
+ { psf_log_printf (psf, "SFE_STR_WEIRD : k == 0 && psf->str_end != NULL\n") ;
+ return SFE_STR_WEIRD ;
+ } ;
+
+ if (k != 0 && psf->str_end == NULL)
+ { psf_log_printf (psf, "SFE_STR_WEIRD : k != 0 && psf->str_end == NULL\n") ;
+ return SFE_STR_WEIRD ;
+ } ;
+
+ /* Special case for the first string. */
+ if (k == 0)
+ psf->str_end = psf->str_storage ;
+
+
+#if STRINGS_DEBUG
+ psf_log_printf (psf, "str_storage : %X\n", (int) psf->str_storage) ;
+ psf_log_printf (psf, "str_end : %X\n", (int) psf->str_end) ;
+ psf_log_printf (psf, "sizeof (str_storage) : %d\n", SIGNED_SIZEOF (psf->str_storage)) ;
+#endif
+
+ len_remaining = SIGNED_SIZEOF (psf->str_storage) - (psf->str_end - psf->str_storage) ;
+
+ if (len_remaining < str_len + 2)
+ return SFE_STR_MAX_DATA ;
+
+ switch (str_type)
+ { case SF_STR_SOFTWARE :
+ /* In write mode, want to append libsndfile-version to string. */
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { psf->strings [k].type = str_type ;
+ psf->strings [k].str = psf->str_end ;
+ psf->strings [k].flags = str_flags ;
+
+ memcpy (psf->str_end, str, str_len + 1) ;
+ psf->str_end += str_len ;
+
+ /*
+ ** If the supplied string does not already contain a
+ ** libsndfile-X.Y.Z component, then add it.
+ */
+ if (strstr (str, PACKAGE) == NULL && len_remaining > (int) (strlen (bracket_name) + str_len + 2))
+ { if (strlen (str) == 0)
+ strncat (psf->str_end, lsf_name, len_remaining) ;
+ else
+ strncat (psf->str_end, bracket_name, len_remaining) ;
+ psf->str_end += strlen (psf->str_end) ;
+ } ;
+
+ /* Plus one to catch string terminator. */
+ psf->str_end += 1 ;
+ break ;
+ } ;
+
+ /* Fall though if not write mode. */
+
+ case SF_STR_TITLE :
+ case SF_STR_COPYRIGHT :
+ case SF_STR_ARTIST :
+ case SF_STR_COMMENT :
+ case SF_STR_DATE :
+ psf->strings [k].type = str_type ;
+ psf->strings [k].str = psf->str_end ;
+ psf->strings [k].flags = str_flags ;
+
+ /* Plus one to catch string terminator. */
+ memcpy (psf->str_end, str, str_len + 1) ;
+ psf->str_end += str_len + 1 ;
+ break ;
+
+ default :
+ return SFE_STR_BAD_TYPE ;
+ } ;
+
+ psf->str_flags |= (psf->have_written) ? SF_STR_LOCATE_END : SF_STR_LOCATE_START ;
+
+#if STRINGS_DEBUG
+ hexdump (psf->str_storage, 300) ;
+#endif
+
+ return 0 ;
+} /* psf_store_string */
+
+int
+psf_set_string (SF_PRIVATE *psf, int str_type, const char *str)
+{ if (psf->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 [k].type)
+ return psf->strings [k].str ;
+
+ return NULL ;
+} /* psf_get_string */
+
+#if STRINGS_DEBUG
+
+#include <ctype.h>
+static void
+hexdump (void *data, int len)
+{ unsigned char *ptr ;
+ int k ;
+
+ ptr = data ;
+
+ puts ("---------------------------------------------------------") ;
+ while (len >= 16)
+ { for (k = 0 ; k < 16 ; k++)
+ printf ("%02X ", ptr [k] & 0xFF) ;
+ printf (" ") ;
+ for (k = 0 ; k < 16 ; k++)
+ printf ("%c", isprint (ptr [k]) ? ptr [k] : '.') ;
+ puts ("") ;
+ ptr += 16 ;
+ len -= 16 ;
+ } ;
+} /* hexdump */
+
+#endif
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 04393aa1-9389-46fe-baf2-58a7bd544fd6
+*/
diff --git a/src/svx.c b/src/svx.c
new file mode 100644
index 0000000..bc44fe5
--- /dev/null
+++ b/src/svx.c
@@ -0,0 +1,413 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#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->mode == SFM_READ || (psf->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->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if (psf->is_pipe)
+ return SFE_NO_PIPE_WRITE ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_SVX)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ psf->endian = psf->sf.format & SF_FORMAT_ENDMASK ;
+
+ 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 ;
+ unsigned int FORMsize, vhdrsize, dword, marker ;
+ int filetype = 0, parsestage = 0, done = 0 ;
+ int bytecount = 0, channels ;
+
+ if (psf->filelength > SF_PLATFORM_S64 (0xffffffff))
+ 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. Currently can't handle stereo SVX files. */
+ psf->sf.channels = 1 ;
+
+ psf->sf.format = SF_FORMAT_SVX ;
+
+ while (! done)
+ { psf_binheader_readf (psf, "m", &marker) ;
+ switch (marker)
+ { case FORM_MARKER :
+ if (parsestage)
+ return SFE_SVX_NO_FORM ;
+
+ psf_binheader_readf (psf, "E4", &FORMsize) ;
+
+ if (FORMsize != psf->filelength - 2 * sizeof (dword))
+ { dword = psf->filelength - 2 * sizeof (dword) ;
+ psf_log_printf (psf, "FORM : %d (should be %d)\n", FORMsize, dword) ;
+ FORMsize = dword ;
+ }
+ else
+ psf_log_printf (psf, "FORM : %d\n", FORMsize) ;
+ parsestage |= HAVE_FORM ;
+ break ;
+
+ case SVX8_MARKER :
+ case SV16_MARKER :
+ if (! (parsestage & HAVE_FORM))
+ return SFE_SVX_NO_FORM ;
+ 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_binheader_readf (psf, "E4", &vhdrsize) ;
+
+ psf_log_printf (psf, " VHDR : %d\n", vhdrsize) ;
+
+ 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_binheader_readf (psf, "E4", &dword) ;
+ psf->datalength = dword ;
+
+ psf->dataoffset = psf_ftell (psf) ;
+
+ 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_binheader_readf (psf, "E4", &dword) ;
+
+ psf_log_printf (psf, " %M : %d\n", marker, dword) ;
+
+ if (strlen (psf->filename) != dword)
+ { if (dword > sizeof (psf->filename) - 1)
+ return SFE_SVX_BAD_NAME_LENGTH ;
+
+ psf_binheader_readf (psf, "b", psf->filename, dword) ;
+ psf->filename [dword] = 0 ;
+ }
+ else
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+
+ case ANNO_MARKER :
+ if (! (parsestage & HAVE_SVX))
+ return SFE_SVX_NO_FORM ;
+
+ psf_binheader_readf (psf, "E4", &dword) ;
+
+ psf_log_printf (psf, " %M : %d\n", marker, dword) ;
+
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+
+ case CHAN_MARKER :
+ if (! (parsestage & HAVE_SVX))
+ return SFE_SVX_NO_FORM ;
+
+ psf_binheader_readf (psf, "E4", &dword) ;
+
+ psf_log_printf (psf, " %M : %d\n", marker, dword) ;
+
+ bytecount += psf_binheader_readf (psf, "E4", &channels) ;
+ psf->sf.channels = channels ;
+
+ psf_log_printf (psf, " Channels : %d\n", channels) ;
+
+ psf_binheader_readf (psf, "j", dword - bytecount) ;
+ break ;
+
+
+ case AUTH_MARKER :
+ case c_MARKER :
+ if (! (parsestage & HAVE_SVX))
+ return SFE_SVX_NO_FORM ;
+
+ psf_binheader_readf (psf, "E4", &dword) ;
+
+ psf_log_printf (psf, " %M : %d\n", marker, dword) ;
+
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+
+ default :
+ if (isprint ((marker >> 24) & 0xFF) && isprint ((marker >> 16) & 0xFF)
+ && isprint ((marker >> 8) & 0xFF) && isprint (marker & 0xFF))
+ { psf_binheader_readf (psf, "E4", &dword) ;
+
+ psf_log_printf (psf, "%M : %d (unknown marker)\n", marker, dword) ;
+
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+ } ;
+ if ((dword = psf_ftell (psf)) & 0x03)
+ { psf_log_printf (psf, " Unknown chunk marker at position %d. Resynching.\n", dword - 4) ;
+
+ psf_binheader_readf (psf, "j", -3) ;
+ break ;
+ } ;
+ psf_log_printf (psf, "*** Unknown chunk marker : %X. Exiting parser.\n", marker) ;
+ done = 1 ;
+ } ; /* switch (marker) */
+
+ if (! psf->sf.seekable && (parsestage & HAVE_BODY))
+ break ;
+
+ if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (dword))
+ 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->mode == SFM_WRITE || psf->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 [0] = 0 ;
+ psf->headindex = 0 ;
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ /* FORM marker and FORM size. */
+ psf_binheader_writef (psf, "Etm8", FORM_MARKER, (psf->filelength < 8) ?
+ psf->filelength * 0 : psf->filelength - 8) ;
+
+ psf_binheader_writef (psf, "m", (psf->bytewidth == 1) ? SVX8_MARKER : SV16_MARKER) ;
+
+ /* VHDR chunk. */
+ psf_binheader_writef (psf, "Em4", VHDR_MARKER, sizeof (VHDR_CHUNK)) ;
+ /* VHDR : oneShotHiSamples, repeatHiSamples, samplesPerHiCycle */
+ psf_binheader_writef (psf, "E444", psf->sf.frames, 0, 0) ;
+ /* VHDR : samplesPerSec, octave, compression */
+ psf_binheader_writef (psf, "E211", psf->sf.samplerate, 1, 0) ;
+ /* VHDR : volume */
+ psf_binheader_writef (psf, "E4", (psf->bytewidth == 1) ? 0xFF : 0xFFFF) ;
+
+ /* Filename and annotation strings. */
+ psf_binheader_writef (psf, "Emsms", NAME_MARKER, psf->filename, ANNO_MARKER, annotation) ;
+
+ /* BODY marker and size. */
+ psf_binheader_writef (psf, "Etm8", BODY_MARKER, (psf->datalength < 0) ?
+ psf->datalength * 0 : psf->datalength) ;
+
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ if (current > 0)
+ psf_fseek (psf, current, SEEK_SET) ;
+
+ return psf->error ;
+} /* svx_write_header */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: a80ab6fb-7d75-4d32-a6b0-0061a3f05d95
+*/
diff --git a/src/test_audio_detect.c b/src/test_audio_detect.c
new file mode 100644
index 0000000..c4f15cf
--- /dev/null
+++ b/src/test_audio_detect.c
@@ -0,0 +1,126 @@
+/*
+** Copyright (C) 2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include "common.h"
+#include "sfendian.h"
+
+
+static void test_audio_detect (void) ;
+
+int
+main (void)
+{
+ test_audio_detect () ;
+
+ return 0 ;
+} /* main */
+
+/*==============================================================================
+** Test data.
+*/
+
+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,
+} ;
+
+
+static void
+test_audio_detect (void)
+{
+ SF_PRIVATE psf ;
+ AUDIO_DETECT ad ;
+ int errors = 0 ;
+
+ printf (" test_audio_detect : ") ;
+ fflush (stdout) ;
+
+ 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)
+ { if (errors == 0) puts ("\nFailed tests :\n") ;
+ 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/src/test_conversions.c b/src/test_conversions.c
new file mode 100644
index 0000000..e49edd8
--- /dev/null
+++ b/src/test_conversions.c
@@ -0,0 +1,101 @@
+/*
+** Copyright (C) 2006,2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "common.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) ;
+
+int
+main (void)
+{
+ conversion_test ('E') ;
+ conversion_test ('e') ;
+ return 0 ;
+} /* main */
+
+static void
+conversion_test (char endian)
+{
+ SF_PRIVATE sf_private, *psf ;
+ const char * filename = "conversion.bin" ;
+ long long i64 = SF_PLATFORM_S64 (0x0123456789abcdef), t64 = 0 ;
+ char format_str [16] ;
+ 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) ;
+
+ printf (" conversion_test_%-8s : ", endian == 'e' ? "le" : "be") ;
+ fflush (stdout) ;
+
+ psf = &sf_private ;
+ memset (psf, 0, sizeof (sf_private)) ;
+
+ if (psf_fopen (psf, filename, SFM_WRITE) != 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, 1, psf->headindex, psf) ;
+ psf_fclose (psf) ;
+
+ memset (psf, 0, sizeof (sf_private)) ;
+ if (psf_fopen (psf, filename, SFM_READ) != 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) ;
+ 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%llx -> 0x%llx.\n\n") ;
+
+ remove (filename) ;
+ puts ("ok") ;
+} /* conversion_test */
diff --git a/src/test_endswap.def b/src/test_endswap.def
new file mode 100644
index 0000000..5fbc49b
--- /dev/null
+++ b/src/test_endswap.def
@@ -0,0 +1,28 @@
+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 ;
+ } ;
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 098c07e0-2d3f-4f62-ad93-f3f4b91c5211
+*/
+
diff --git a/src/test_endswap.tpl b/src/test_endswap.tpl
new file mode 100644
index 0000000..e3265b3
--- /dev/null
+++ b/src/test_endswap.tpl
@@ -0,0 +1,135 @@
+[+ AutoGen5 template c +]
+/*
+** Copyright (C) 2002-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include "common.h"
+#include "sfendian.h"
+
+#define FMT_SHORT "0x%04x\n"
+#define FMT_INT "0x%08x\n"
+
+#if SIZEOF_INT64_T == SIZEOF_LONG
+#define FMT_INT64 "0x%016lx\n"
+#else
+#define FMT_INT64 "0x%016llx\n"
+#endif
+
+[+ FOR int_type
++]static void test_endswap_[+ (get "name") +] (void) ;
+[+ ENDFOR int_type
++]
+
+int
+main (void)
+{
+[+ FOR int_type
++] test_endswap_[+ (get "name") +] () ;
+[+ ENDFOR int_type
++]
+ return 0 ;
+} /* main */
+
+/*==============================================================================
+** Actual 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] ;
+ int k ;
+
+ printf (" %-24s : ", "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
++]
+
+
+[+ COMMENT
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: fd8887e8-8202-4f30-a419-0cf01a0e799b
+*/
++]
diff --git a/src/test_file_io.c b/src/test_file_io.c
new file mode 100644
index 0000000..1d7f591
--- /dev/null
+++ b/src/test_file_io.c
@@ -0,0 +1,448 @@
+/*
+** Copyright (C) 2002-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include "common.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) ;
+
+
+
+int
+main (void)
+{ const char *filename = "file_io.dat" ;
+
+ file_open_test (filename) ;
+ file_read_write_test (filename) ;
+ file_truncate_test (filename) ;
+
+ unlink (filename) ;
+
+ return 0 ;
+} /* main */
+
+/*==============================================================================
+** Actual test functions.
+*/
+
+static void
+file_open_test (const char *filename)
+{ SF_PRIVATE sf_data, *psf ;
+ int error ;
+
+ printf (" %-24s : ", "file_open_test") ;
+ fflush (stdout) ;
+
+ 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) ;
+ } ;
+
+ strncpy (psf->filename, filename, sizeof (psf->filename)) ;
+
+ /* Test that open for read fails if the file doesn't exist. */
+ error = psf_fopen (psf, psf->filename, SFM_READ) ;
+ 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->mode = SFM_WRITE ;
+ test_open_or_die (psf, __LINE__) ;
+
+ test_close_or_die (psf, __LINE__) ;
+
+ unlink (psf->filename) ;
+
+ /* Test file open in read/write mode for a non-existant file. */
+ psf->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->mode = SFM_RDWR ;
+ test_open_or_die (psf, __LINE__) ;
+
+ test_close_or_die (psf, __LINE__) ;
+
+ unlink (psf->filename) ;
+ 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.
+ */
+
+ printf (" %-24s : ", "file_write_test") ;
+ fflush (stdout) ;
+
+ memset (&sf_data, 0, sizeof (sf_data)) ;
+ psf = &sf_data ;
+ strncpy (psf->filename, filename, sizeof (psf->filename)) ;
+
+ /* Test file open in write mode. */
+ psf->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 (%ld should be %d).\n\n", __LINE__, (long) retval, (int) 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. (%ld should be %d)\n\n", __LINE__, (long) retval, 2 * ((int) 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.
+ */
+
+ printf (" %-24s : ", "file_read_test") ;
+ fflush (stdout) ;
+
+ /* Test file open in write mode. */
+ psf->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.
+ */
+
+ printf (" %-24s : ", "file_seek_test") ;
+ fflush (stdout) ;
+
+ /* Test file open in read/write mode. */
+ psf->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.
+ */
+
+ printf (" %-24s : ", "file_offset_test") ;
+ fflush (stdout) ;
+
+ /* Test file open in read/write mode. */
+ psf->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. (%ld should be %d)\n\n", __LINE__, (long) retval, 3 * ((int) 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->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. (%ld should be %d)\n\n", __LINE__, (long) retval, 3 * ((int) 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.
+ */
+
+ printf (" %-24s : ", "file_truncate_test") ;
+ fflush (stdout) ;
+
+ memset (&sf_data, 0, sizeof (sf_data)) ;
+ memset (buffer, 0xEE, sizeof (buffer)) ;
+
+ psf = &sf_data ;
+ strncpy (psf->filename, filename, sizeof (psf->filename)) ;
+
+ /*
+ ** Open the file write mode, write 0xEE data and then extend the file
+ ** using truncate (the extended data should be 0x00).
+ */
+ psf->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->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] = %d (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] = %d (should be 0)\n\n", __LINE__, k, buffer [k]) ;
+ exit (1) ;
+ } ;
+
+ /* Open the file in read/write and shorten the file using truncate. */
+ psf->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->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 */
+
+/*==============================================================================
+** 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, psf->filename, psf->mode) ;
+ 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->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 %ld (should be %ld)\n\n", linenum, (long) retval, (long) items) ;
+ exit (1) ;
+ } ;
+
+ if ((retval = psf_ftell (psf)) != new_position)
+ { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %ld)\n\n", linenum, (long) retval, (long) 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 %ld (should be %ld)\n\n", linenum, (long) retval, (long) items) ;
+ exit (1) ;
+ } ;
+
+ if ((retval = psf_ftell (psf)) != new_position)
+ { printf ("\n\nLine %d: file length after write is not correct. (%ld should be %ld)\n\n", linenum, (long) retval, (long) 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 %ld (should be %ld).\n\n",
+ linenum, (long) retval, (long) new_position) ;
+ exit (1) ;
+ } ;
+
+} /* test_seek_or_die */
+
+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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 0a21fb93-78dd-4f72-8338-4bca9e77b8c8
+*/
diff --git a/src/test_log_printf.c b/src/test_log_printf.c
new file mode 100644
index 0000000..0221b6f
--- /dev/null
+++ b/src/test_log_printf.c
@@ -0,0 +1,133 @@
+/*
+** Copyright (C) 2003-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "common.h"
+
+#define CMP_0_ARGS(line,err,fmt) \
+ { psf->logindex = 0 ; \
+ LSF_SNPRINTF (buffer, sizeof (buffer), (fmt)) ; \
+ psf_log_printf (psf, (fmt)) ; \
+ err += compare_strings_or_die (line, fmt, buffer, psf->logbuffer) ; \
+ }
+
+#define CMP_2_ARGS(line,err,fmt,a) \
+ { psf->logindex = 0 ; \
+ LSF_SNPRINTF (buffer, sizeof (buffer), (fmt), (a), (a)) ; \
+ psf_log_printf (psf, (fmt), (a), (a)) ; \
+ err += compare_strings_or_die (line, fmt, buffer, psf->logbuffer) ; \
+ }
+
+#define CMP_4_ARGS(line,err,fmt,a) \
+ { psf->logindex = 0 ; \
+ LSF_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->logbuffer) ; \
+ }
+
+#define CMP_5_ARGS(line,err,fmt,a) \
+ { psf->logindex = 0 ; \
+ LSF_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->logbuffer) ; \
+ }
+
+#define CMP_6_ARGS(line,err,fmt,a) \
+ { psf->logindex = 0 ; \
+ LSF_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->logbuffer) ; \
+ }
+
+static int compare_strings_or_die (int linenum, const char *fmt, const char* s1, const char* s3) ;
+
+int
+main (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 } ;
+
+ printf (" %-24s : ", "psf_log_printf_test") ;
+ fflush (stdout) ;
+
+ 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") ;
+
+ if (errors)
+ { puts ("\nExiting due to errors.\n") ;
+ exit (1) ;
+ } ;
+
+ puts ("ok") ;
+
+ return 0 ;
+} /* main */
+
+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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 45147310-868b-400a-97e8-cc0a572a6270
+*/
diff --git a/src/txw.c b/src/txw.c
new file mode 100644
index 0000000..336b462
--- /dev/null
+++ b/src/txw.c
@@ -0,0 +1,379 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#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->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)
+{ TXW_HEADER txwh ;
+ char *strptr ;
+
+ memset (&txwh, 0, sizeof (txwh)) ;
+ memset (psf->u.cbuf, 0, sizeof (psf->u.cbuf)) ;
+ psf_binheader_readf (psf, "pb", 0, psf->u.cbuf, 16) ;
+
+ if (memcmp (psf->u.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)
+{ unsigned char *ucptr ;
+ short sample ;
+ int k, bufferlen, readcount, count ;
+ sf_count_t total = 0 ;
+
+ bufferlen = sizeof (psf->u.cbuf) / 3 ;
+ bufferlen -= (bufferlen & 1) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : len ;
+ count = psf_fread (psf->u.cbuf, 3, readcount, psf) ;
+
+ ucptr = psf->u.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)
+{ unsigned char *ucptr ;
+ short sample ;
+ int k, bufferlen, readcount, count ;
+ sf_count_t total = 0 ;
+
+ bufferlen = sizeof (psf->u.cbuf) / 3 ;
+ bufferlen -= (bufferlen & 1) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : len ;
+ count = psf_fread (psf->u.cbuf, 3, readcount, psf) ;
+
+ ucptr = psf->u.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)
+{ 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 (psf->u.cbuf) / 3 ;
+ bufferlen -= (bufferlen & 1) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : len ;
+ count = psf_fread (psf->u.cbuf, 3, readcount, psf) ;
+
+ ucptr = psf->u.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)
+{ 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 (psf->u.cbuf) / 3 ;
+ bufferlen -= (bufferlen & 1) ;
+ while (len > 0)
+ { readcount = (len >= bufferlen) ? bufferlen : len ;
+ count = psf_fread (psf->u.cbuf, 3, readcount, psf) ;
+
+ ucptr = psf->u.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
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 4d0ba7af-b1c5-46b4-a900-7c6f59fd9a89
+*/
diff --git a/src/ulaw.c b/src/ulaw.c
new file mode 100644
index 0000000..e476c0a
--- /dev/null
+++ b/src/ulaw.c
@@ -0,0 +1,1047 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 "sndfile.h"
+#include "float_cast.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->mode == SFM_READ || psf->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->mode == SFM_WRITE || psf->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->datalength / psf->blockwidth ;
+
+ 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, 0x00
+} ;
+
+static inline void
+ulaw2s_array (unsigned char *buffer, int count, short *ptr)
+{ while (--count >= 0)
+ ptr [count] = ulaw_decode [(int) buffer [count]] ;
+} /* ulaw2s_array */
+
+static inline void
+ulaw2i_array (unsigned char *buffer, int count, int *ptr)
+{ while (--count >= 0)
+ ptr [count] = ulaw_decode [buffer [count]] << 16 ;
+} /* ulaw2i_array */
+
+static inline void
+ulaw2f_array (unsigned char *buffer, int count, float *ptr, float normfact)
+{ while (--count >= 0)
+ ptr [count] = normfact * ulaw_decode [(int) buffer [count]] ;
+} /* ulaw2f_array */
+
+static inline void
+ulaw2d_array (const unsigned char *buffer, int count, double *ptr, double normfact)
+{ while (--count >= 0)
+ ptr [count] = normfact * ulaw_decode [(int) buffer [count]] ;
+} /* ulaw2d_array */
+
+static inline void
+s2ulaw_array (const short *ptr, int count, unsigned char *buffer)
+{ while (--count >= 0)
+ { if (ptr [count] >= 0)
+ buffer [count] = ulaw_encode [ptr [count] / 4] ;
+ else
+ buffer [count] = 0x7F & ulaw_encode [ptr [count] / -4] ;
+ } ;
+} /* s2ulaw_array */
+
+static inline void
+i2ulaw_array (const int *ptr, int count, unsigned char *buffer)
+{ while (--count >= 0)
+ { if (ptr [count] >= 0)
+ buffer [count] = ulaw_encode [ptr [count] >> (16 + 2)] ;
+ else
+ buffer [count] = 0x7F & ulaw_encode [-ptr [count] >> (16 + 2)] ;
+ } ;
+} /* i2ulaw_array */
+
+static inline void
+f2ulaw_array (const float *ptr, int count, unsigned char *buffer, float normfact)
+{ while (--count >= 0)
+ { if (ptr [count] >= 0)
+ buffer [count] = ulaw_encode [lrintf (normfact * ptr [count])] ;
+ else
+ buffer [count] = 0x7F & ulaw_encode [- lrintf (normfact * ptr [count])] ;
+ } ;
+} /* f2ulaw_array */
+
+static inline void
+d2ulaw_array (const double *ptr, int count, unsigned char *buffer, double normfact)
+{ while (--count >= 0)
+ { if (ptr [count] >= 0)
+ buffer [count] = ulaw_encode [lrint (normfact * ptr [count])] ;
+ else
+ buffer [count] = 0x7F & ulaw_encode [- lrint (normfact * ptr [count])] ;
+ } ;
+} /* d2ulaw_array */
+
+/*==============================================================================
+*/
+
+static sf_count_t
+ulaw_read_ulaw2s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
+ ulaw2s_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
+ ulaw2i_array (psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
+ ulaw2f_array (psf->u.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)
+{ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+ double normfact ;
+
+ normfact = (psf->norm_double) ? 1.0 / ((double) 0x8000) : 1.0 ;
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.ucbuf, 1, bufferlen, psf) ;
+ ulaw2d_array (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2ulaw_array (ptr + total, bufferlen, psf->u.ucbuf) ;
+ writecount = psf_fwrite (psf->u.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)
+{ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2ulaw_array (ptr + total, bufferlen, psf->u.ucbuf) ;
+ writecount = psf_fwrite (psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ f2ulaw_array (ptr + total, bufferlen, psf->u.ucbuf, normfact) ;
+ writecount = psf_fwrite (psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ d2ulaw_array (ptr + total, bufferlen, psf->u.ucbuf, normfact) ;
+ writecount = psf_fwrite (psf->u.ucbuf, 1, bufferlen, psf) ;
+ total += writecount ;
+ if (writecount < bufferlen)
+ break ;
+ len -= writecount ;
+ } ;
+
+ return total ;
+} /* ulaw_write_d2ulaw */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 655cc790-f058-45e8-89c9-86967cccc37e
+*/
diff --git a/src/voc.c b/src/voc.c
new file mode 100644
index 0000000..de7abf2
--- /dev/null
+++ b/src/voc.c
@@ -0,0 +1,878 @@
+/*
+** Copyright (C) 2001-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = voc_read_header (psf)))
+ return error ;
+ } ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != 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)
+ { offset += psf_binheader_readf (psf, "1", &block_type) ;
+
+ switch (block_type)
+ { case VOC_ASCII :
+ { int size ;
+
+ offset += psf_binheader_readf (psf, "e3", &size) ;
+
+ psf_log_printf (psf, " ASCII : %d\n", size) ;
+
+ offset += psf_binheader_readf (psf, "b", psf->header, size) ;
+ psf->header [size] = 0 ;
+ psf_log_printf (psf, " text : %s\n", psf->header) ;
+ } ;
+ 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 (offset + size - 1 < psf->filelength)
+ { 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_UNKNOWN_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 = psf->sf.format & SF_FORMAT_SUBMASK ;
+ /* Reset the current header length to zero. */
+ psf->header [0] = 0 ;
+ psf->headindex = 0 ;
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ /* VOC marker and 0x1A byte. */
+ psf_binheader_writef (psf, "eb1", "Creative Voice File", make_size_t (19), 0x1A) ;
+
+ /* Data offset, version and other. */
+ psf_binheader_writef (psf, "e222", 26, 0x0114, 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", VOC_SOUND_DATA, (int) (psf->datalength + 1), rate_const, 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", VOC_EXTENDED, 4, rate_const, 0, 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", VOC_SOUND_DATA, (int) (psf->datalength + 1), rate_const, 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", VOC_EXTENDED_II, length, psf->sf.samplerate, 16, psf->sf.channels, 4, 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", VOC_EXTENDED_II, length, psf->sf.samplerate, 16, psf->sf.channels, 4, 0) ;
+ break ;
+
+ case SF_FORMAT_ALAW :
+ psf->bytewidth = 1 ;
+ length = psf->sf.frames * psf->sf.channels * psf->bytewidth + 12 ;
+ psf_binheader_writef (psf, "e1341124", VOC_EXTENDED_II, length, psf->sf.samplerate, 8, psf->sf.channels, 6, 0) ;
+ break ;
+
+ case SF_FORMAT_ULAW :
+ psf->bytewidth = 1 ;
+ length = psf->sf.frames * psf->sf.channels * psf->bytewidth + 12 ;
+ psf_binheader_writef (psf, "e1341124", VOC_EXTENDED_II, length, psf->sf.samplerate, 8, psf->sf.channels, 7, 0) ;
+ break ;
+
+ default : return SFE_UNIMPLEMENTED ;
+ } ;
+ } ;
+
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ if (current > 0)
+ psf_fseek (psf, current, SEEK_SET) ;
+
+ return psf->error ;
+} /* voc_write_header */
+
+static int
+voc_close (SF_PRIVATE *psf)
+{
+ if (psf->mode == SFM_WRITE || psf->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 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 <guido@cwi.nl>.
+--------------------------------------------------------------------------
+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
+
+------------------------------------------------------------------------*/
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 40a50167-a81c-463a-9e1d-3282ff84e09d
+*/
diff --git a/src/vox_adpcm.c b/src/vox_adpcm.c
new file mode 100644
index 0000000..11f333f
--- /dev/null
+++ b/src/vox_adpcm.c
@@ -0,0 +1,537 @@
+/*
+** Copyright (C) 2002-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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.
+**
+** Implemented from the description found here:
+**
+** http://www.comptek.ru:8100/telephony/tnotes/tt1-13.html
+**
+** and compared against the encoder/decoder found here:
+**
+** http://ibiblio.org/pub/linux/apps/sound/convert/vox.tar.gz
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "float_cast.h"
+#include "common.h"
+
+#define VOX_DATA_LEN 2048
+#define PCM_DATA_LEN (VOX_DATA_LEN *2)
+
+typedef struct
+{ short last ;
+ short step_index ;
+
+ int vox_bytes, pcm_samples ;
+
+ unsigned char vox_data [VOX_DATA_LEN] ;
+ short pcm_data [PCM_DATA_LEN] ;
+} VOX_ADPCM_PRIVATE ;
+
+static int vox_adpcm_encode_block (VOX_ADPCM_PRIVATE *pvox) ;
+static int vox_adpcm_decode_block (VOX_ADPCM_PRIVATE *pvox) ;
+
+static short vox_adpcm_decode (char code, VOX_ADPCM_PRIVATE *pvox) ;
+static char vox_adpcm_encode (short samp, VOX_ADPCM_PRIVATE *pvox) ;
+
+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, VOX_ADPCM_PRIVATE *pvox, short *ptr, int len) ;
+
+/*============================================================================================
+** Predefined OKI ADPCM encoder/decoder tables.
+*/
+
+static short step_size_table [49] =
+{ 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, 1408, 1552
+} ; /* step_size_table */
+
+static short step_adjust_table [8] =
+{ -1, -1, -1, -1, 2, 4, 6, 8
+} ; /* step_adjust_table */
+
+/*------------------------------------------------------------------------------
+*/
+
+int
+vox_adpcm_init (SF_PRIVATE *psf)
+{ VOX_ADPCM_PRIVATE *pvox = NULL ;
+
+ if (psf->mode == SFM_RDWR)
+ return SFE_BAD_MODE_RW ;
+
+ if (psf->mode == SFM_WRITE && psf->sf.channels != 1)
+ return SFE_CHANNEL_COUNT ;
+
+ if ((pvox = malloc (sizeof (VOX_ADPCM_PRIVATE))) == NULL)
+ return SFE_MALLOC_FAILED ;
+
+ psf->codec_data = (void*) pvox ;
+ memset (pvox, 0, sizeof (VOX_ADPCM_PRIVATE)) ;
+
+ if (psf->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 ;
+
+ /* Seek back to start of data. */
+ if (psf_fseek (psf, 0 , SEEK_SET) == -1)
+ return SFE_BAD_SEEK ;
+
+ return 0 ;
+} /* vox_adpcm_init */
+
+/*------------------------------------------------------------------------------
+*/
+
+static char
+vox_adpcm_encode (short samp, VOX_ADPCM_PRIVATE *pvox)
+{ short code ;
+ short diff, error, stepsize ;
+
+ stepsize = step_size_table [pvox->step_index] ;
+ code = 0 ;
+
+ diff = samp - pvox->last ;
+ if (diff < 0)
+ { code = 0x08 ;
+ error = -diff ;
+ }
+ else
+ error = diff ;
+
+ if (error >= stepsize)
+ { code = code | 0x04 ;
+ error -= stepsize ;
+ } ;
+
+ if (error >= stepsize / 2)
+ { code = code | 0x02 ;
+ error -= stepsize / 2 ;
+ } ;
+
+ if (error >= stepsize / 4)
+ code = code | 0x01 ;
+
+ /*
+ ** To close the feedback loop, the deocder is used to set the
+ ** estimate of last sample and in doing so, also set the step_index.
+ */
+ pvox->last = vox_adpcm_decode (code, pvox) ;
+
+ return code ;
+} /* vox_adpcm_encode */
+
+static short
+vox_adpcm_decode (char code, VOX_ADPCM_PRIVATE *pvox)
+{ short diff, error, stepsize, samp ;
+
+ stepsize = step_size_table [pvox->step_index] ;
+
+ error = stepsize / 8 ;
+
+ if (code & 0x01)
+ error += stepsize / 4 ;
+
+ if (code & 0x02)
+ error += stepsize / 2 ;
+
+ if (code & 0x04)
+ error += stepsize ;
+
+ diff = (code & 0x08) ? -error : error ;
+ samp = pvox->last + diff ;
+
+ /*
+ ** Apply clipping.
+ */
+ if (samp > 2048)
+ samp = 2048 ;
+ if (samp < -2048)
+ samp = -2048 ;
+
+ pvox->last = samp ;
+ pvox->step_index += step_adjust_table [code & 0x7] ;
+
+ if (pvox->step_index < 0)
+ pvox->step_index = 0 ;
+ if (pvox->step_index > 48)
+ pvox->step_index = 48 ;
+
+ return samp ;
+} /* vox_adpcm_decode */
+
+static int
+vox_adpcm_encode_block (VOX_ADPCM_PRIVATE *pvox)
+{ unsigned char code ;
+ int j, k ;
+
+ /* If data_count is odd, add an extra zero valued sample. */
+ if (pvox->pcm_samples & 1)
+ pvox->pcm_data [pvox->pcm_samples++] = 0 ;
+
+ for (j = k = 0 ; k < pvox->pcm_samples ; j++)
+ { code = vox_adpcm_encode (pvox->pcm_data [k++] / 16, pvox) << 4 ;
+ code |= vox_adpcm_encode (pvox->pcm_data [k++] / 16, pvox) ;
+ pvox->vox_data [j] = code ;
+ } ;
+
+ pvox->vox_bytes = j ;
+
+ return 0 ;
+} /* vox_adpcm_encode_block */
+
+static int
+vox_adpcm_decode_block (VOX_ADPCM_PRIVATE *pvox)
+{ unsigned char code ;
+ int j, k ;
+
+ for (j = k = 0 ; j < pvox->vox_bytes ; j++)
+ { code = pvox->vox_data [j] ;
+ pvox->pcm_data [k++] = 16 * vox_adpcm_decode ((code >> 4) & 0x0f, pvox) ;
+ pvox->pcm_data [k++] = 16 * vox_adpcm_decode (code & 0x0f, pvox) ;
+ } ;
+
+ pvox->pcm_samples = k ;
+
+ return 0 ;
+} /* vox_adpcm_decode_block */
+
+/*==============================================================================
+*/
+
+static int
+vox_read_block (SF_PRIVATE *psf, VOX_ADPCM_PRIVATE *pvox, short *ptr, int len)
+{ int indx = 0, k ;
+
+ while (indx < len)
+ { pvox->vox_bytes = (len - indx > PCM_DATA_LEN) ? VOX_DATA_LEN : (len - indx + 1) / 2 ;
+
+ if ((k = psf_fread (pvox->vox_data, 1, pvox->vox_bytes, psf)) != pvox->vox_bytes)
+ { if (psf_ftell (psf) + k != psf->filelength)
+ psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pvox->vox_bytes) ;
+ if (k == 0)
+ break ;
+ } ;
+
+ pvox->vox_bytes = k ;
+
+ vox_adpcm_decode_block (pvox) ;
+
+ memcpy (&(ptr [indx]), pvox->pcm_data, pvox->pcm_samples * sizeof (short)) ;
+ indx += pvox->pcm_samples ;
+ } ;
+
+ return indx ;
+} /* vox_read_block */
+
+
+static sf_count_t
+vox_read_s (SF_PRIVATE *psf, short *ptr, sf_count_t len)
+{ VOX_ADPCM_PRIVATE *pvox ;
+ int readcount, count ;
+ sf_count_t total = 0 ;
+
+ if (! psf->codec_data)
+ return 0 ;
+ pvox = (VOX_ADPCM_PRIVATE*) 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)
+{ VOX_ADPCM_PRIVATE *pvox ;
+ short *sptr ;
+ int k, bufferlen, readcount, count ;
+ sf_count_t total = 0 ;
+
+ if (! psf->codec_data)
+ return 0 ;
+ pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ;
+
+ sptr = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.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] = ((int) 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)
+{ VOX_ADPCM_PRIVATE *pvox ;
+ short *sptr ;
+ int k, bufferlen, readcount, count ;
+ sf_count_t total = 0 ;
+ float normfact ;
+
+ if (! psf->codec_data)
+ return 0 ;
+ pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ;
+
+ normfact = (psf->norm_float == SF_TRUE) ? 1.0 / ((float) 0x8000) : 1.0 ;
+
+ sptr = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.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)
+{ VOX_ADPCM_PRIVATE *pvox ;
+ short *sptr ;
+ int k, bufferlen, readcount, count ;
+ sf_count_t total = 0 ;
+ double normfact ;
+
+ if (! psf->codec_data)
+ return 0 ;
+ pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ;
+
+ normfact = (psf->norm_double == SF_TRUE) ? 1.0 / ((double) 0x8000) : 1.0 ;
+
+ sptr = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.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, VOX_ADPCM_PRIVATE *pvox, const short *ptr, int len)
+{ int indx = 0, k ;
+
+ while (indx < len)
+ { pvox->pcm_samples = (len - indx > PCM_DATA_LEN) ? PCM_DATA_LEN : len - indx ;
+
+ memcpy (pvox->pcm_data, &(ptr [indx]), pvox->pcm_samples * sizeof (short)) ;
+
+ vox_adpcm_encode_block (pvox) ;
+
+ if ((k = psf_fwrite (pvox->vox_data, 1, pvox->vox_bytes, psf)) != pvox->vox_bytes)
+ psf_log_printf (psf, "*** Warning : short read (%d != %d).\n", k, pvox->vox_bytes) ;
+
+ indx += pvox->pcm_samples ;
+ } ;
+
+ return indx ;
+} /* vox_write_block */
+
+static sf_count_t
+vox_write_s (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
+{ VOX_ADPCM_PRIVATE *pvox ;
+ int writecount, count ;
+ sf_count_t total = 0 ;
+
+ if (! psf->codec_data)
+ return 0 ;
+ pvox = (VOX_ADPCM_PRIVATE*) 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)
+{ VOX_ADPCM_PRIVATE *pvox ;
+ short *sptr ;
+ int k, bufferlen, writecount, count ;
+ sf_count_t total = 0 ;
+
+ if (! psf->codec_data)
+ return 0 ;
+ pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ;
+
+ sptr = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.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)
+{ VOX_ADPCM_PRIVATE *pvox ;
+ short *sptr ;
+ int k, bufferlen, writecount, count ;
+ sf_count_t total = 0 ;
+ float normfact ;
+
+ if (! psf->codec_data)
+ return 0 ;
+ pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ;
+
+ normfact = (psf->norm_float == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
+
+ sptr = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : (int) len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = 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)
+{ VOX_ADPCM_PRIVATE *pvox ;
+ short *sptr ;
+ int k, bufferlen, writecount, count ;
+ sf_count_t total = 0 ;
+ double normfact ;
+
+ if (! psf->codec_data)
+ return 0 ;
+ pvox = (VOX_ADPCM_PRIVATE*) psf->codec_data ;
+
+ normfact = (psf->norm_double == SF_TRUE) ? (1.0 * 0x7FFF) : 1.0 ;
+
+ sptr = psf->u.sbuf ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (len > 0)
+ { writecount = (len >= bufferlen) ? bufferlen : (int) len ;
+ for (k = 0 ; k < writecount ; k++)
+ sptr [k] = 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 */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: e15e97fe-ff9d-4b46-a489-7059fb2d0b1e
+*/
diff --git a/src/w64.c b/src/w64.c
new file mode 100644
index 0000000..1fd7dde
--- /dev/null
+++ b/src/w64.c
@@ -0,0 +1,587 @@
+/*
+** Copyright (C) 1999-2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+#include "wav_w64.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)
+
+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)
+{ WAV_PRIVATE * wpriv ;
+ int subformat, error, blockalign = 0, framesperblock = 0 ;
+
+ if ((wpriv = calloc (1, sizeof (WAV_PRIVATE))) == NULL)
+ return SFE_MALLOC_FAILED ;
+ psf->container_data = wpriv ;
+
+ if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR &&psf->filelength > 0))
+ { if ((error = w64_read_header (psf, &blockalign, &framesperblock)))
+ return error ;
+ } ;
+
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_W64)
+ return SFE_BAD_OPEN_FORMAT ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->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 = wav_w64_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ;
+ framesperblock = -1 ;
+
+ /* FIXME : This block must go */
+ psf->filelength = SF_COUNT_MAX ;
+ psf->datalength = psf->filelength ;
+ if (psf->sf.frames <= 0)
+ psf->sf.frames = (psf->blockwidth) ? psf->filelength / psf->blockwidth : psf->filelength ;
+ /* EMXIF : This block must go */
+ } ;
+
+ 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 = wav_w64_ima_init (psf, blockalign, framesperblock) ;
+ break ;
+
+ case SF_FORMAT_MS_ADPCM :
+ error = wav_w64_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)
+{ WAV_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)
+ { /* Read the 4 byte marker and jump 12 bytes. */
+ bytesread += psf_binheader_readf (psf, "h", &marker) ;
+ chunk_size = 0 ;
+
+ switch (marker)
+ { case riff_HASH16 :
+ if (parsestage)
+ return SFE_W64_NO_RIFF ;
+
+ bytesread += psf_binheader_readf (psf, "e8", &chunk_size) ;
+
+ 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 ;
+ break ;
+
+ case ACID_HASH16:
+ psf_log_printf (psf, "Looks like an ACID file. Exiting.\n") ;
+ return SFE_UNIMPLEMENTED ;
+
+ case wave_HASH16 :
+ if ((parsestage & HAVE_riff) != HAVE_riff)
+ return SFE_W64_NO_WAVE ;
+ psf_log_printf (psf, "wave\n") ;
+ parsestage |= HAVE_wave ;
+ break ;
+
+ case fmt_HASH16 :
+ if ((parsestage & (HAVE_riff | HAVE_wave)) != (HAVE_riff | HAVE_wave))
+ return SFE_W64_NO_FMT ;
+
+ bytesread += psf_binheader_readf (psf, "e8", &chunk_size) ;
+ 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 = wav_w64_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 ;
+ break ;
+
+ case fact_HASH16:
+ { sf_count_t frames ;
+
+ psf_binheader_readf (psf, "e88", &chunk_size, &frames) ;
+ psf_log_printf (psf, " fact : %D\n frames : %D\n",
+ chunk_size, frames) ;
+ } ;
+ break ;
+
+
+ case data_HASH16 :
+ if ((parsestage & (HAVE_riff | HAVE_wave | HAVE_fmt)) != (HAVE_riff | HAVE_wave | HAVE_fmt))
+ return SFE_W64_NO_DATA ;
+
+ psf_binheader_readf (psf, "e8", &chunk_size) ;
+
+ psf->dataoffset = psf_ftell (psf) ;
+
+ psf->datalength = chunk_size - 24 ;
+
+ 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) ;
+ break ;
+
+ default :
+ if (psf_ftell (psf) & 0x0F)
+ { psf_log_printf (psf, " Unknown chunk marker at position %d. Resynching.\n", dword - 4) ;
+ psf_binheader_readf (psf, "j", -3) ;
+ break ;
+ } ;
+ psf_log_printf (psf, "*** Unknown chunk marker : %X. Exiting parser.\n", marker) ;
+ done = SF_TRUE ;
+ break ;
+ } ; /* switch (dword) */
+
+ if (psf->sf.seekable == 0 && (parsestage & HAVE_data))
+ break ;
+
+ if (psf_ftell (psf) >= (psf->filelength - (2 * SIGNED_SIZEOF (dword))))
+ break ;
+ } ; /* while (1) */
+
+ if (! psf->dataoffset)
+ return SFE_W64_NO_DATA ;
+
+ psf->endian = SF_ENDIAN_LITTLE ; /* All WAV 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 [0] = 0 ;
+ psf->headindex = 0 ;
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ /* riff marker, length, wave and 'fmt ' markers. */
+ psf_binheader_writef (psf, "eh8hh", riff_MARKER16, psf->filelength - 8, wave_MARKER16, fmt_MARKER16) ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ 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) (8 - (fmt_size & 0x7)) ;
+ fmt_size += fmt_pad ;
+
+ /* fmt : format, channels, samplerate */
+ psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_PCM, psf->sf.channels, psf->sf.samplerate) ;
+ /* fmt : bytespersec */
+ psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
+ /* fmt : blockalign, bitwidth */
+ psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, 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) (8 - (fmt_size & 0x7)) ;
+ fmt_size += fmt_pad ;
+
+ /* fmt : format, channels, samplerate */
+ psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_IEEE_FLOAT, psf->sf.channels, psf->sf.samplerate) ;
+ /* fmt : bytespersec */
+ psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
+ /* fmt : blockalign, bitwidth */
+ psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, 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) (8 - (fmt_size & 0x7)) ;
+ fmt_size += fmt_pad ;
+
+ /* fmt : format, channels, samplerate */
+ psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_MULAW, psf->sf.channels, psf->sf.samplerate) ;
+ /* fmt : bytespersec */
+ psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
+ /* fmt : blockalign, bitwidth */
+ psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, 8) ;
+
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ case SF_FORMAT_ALAW :
+ fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
+ fmt_pad = (size_t) (8 - (fmt_size & 0x7)) ;
+ fmt_size += fmt_pad ;
+
+ /* fmt : format, channels, samplerate */
+ psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_ALAW, psf->sf.channels, psf->sf.samplerate) ;
+ /* fmt : bytespersec */
+ psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
+ /* fmt : blockalign, bitwidth */
+ psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, 8) ;
+
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ /* Lite remove start */
+ case SF_FORMAT_IMA_ADPCM :
+ { int blockalign, framesperblock, bytespersec ;
+
+ blockalign = wav_w64_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) (8 - (fmt_size & 0x7)) ;
+ fmt_size += fmt_pad ;
+
+ /* fmt : size, WAV format type, channels. */
+ psf_binheader_writef (psf, "e822", fmt_size, WAVE_FORMAT_IMA_ADPCM, psf->sf.channels) ;
+
+ /* fmt : samplerate, bytespersec. */
+ psf_binheader_writef (psf, "e44", psf->sf.samplerate, bytespersec) ;
+
+ /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
+ psf_binheader_writef (psf, "e2222", blockalign, 4, 2, framesperblock) ;
+ } ;
+
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ case SF_FORMAT_MS_ADPCM :
+ { int blockalign, framesperblock, bytespersec, extrabytes ;
+
+ blockalign = wav_w64_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 + MSADPCM_ADAPT_COEFF_COUNT * (2 + 2) ;
+ fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + extrabytes ;
+ fmt_pad = (size_t) (8 - (fmt_size & 0x7)) ;
+ fmt_size += fmt_pad ;
+
+ /* fmt : size, W64 format type, channels. */
+ psf_binheader_writef (psf, "e822", fmt_size, WAVE_FORMAT_MS_ADPCM, psf->sf.channels) ;
+
+ /* fmt : samplerate, bytespersec. */
+ psf_binheader_writef (psf, "e44", psf->sf.samplerate, bytespersec) ;
+
+ /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
+ psf_binheader_writef (psf, "e22222", blockalign, 4, extrabytes, framesperblock, 7) ;
+
+ msadpcm_write_adapt_coeffs (psf) ;
+ } ;
+
+ add_fact_chunk = SF_TRUE ;
+ break ;
+ /* Lite remove end */
+
+ case SF_FORMAT_GSM610 :
+ { int bytespersec ;
+
+ bytespersec = (psf->sf.samplerate * WAV_W64_GSM610_BLOCKSIZE) / WAV_W64_GSM610_SAMPLES ;
+
+ /* fmt chunk. */
+ fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ;
+ fmt_pad = (size_t) (8 - (fmt_size & 0x7)) ;
+ fmt_size += fmt_pad ;
+
+ /* fmt : size, WAV format type, channels. */
+ psf_binheader_writef (psf, "e822", fmt_size, WAVE_FORMAT_GSM610, psf->sf.channels) ;
+
+ /* fmt : samplerate, bytespersec. */
+ psf_binheader_writef (psf, "e44", psf->sf.samplerate, bytespersec) ;
+
+ /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
+ psf_binheader_writef (psf, "e2222", WAV_W64_GSM610_BLOCKSIZE, 0, 2, WAV_W64_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", fmt_pad) ;
+
+ if (add_fact_chunk)
+ psf_binheader_writef (psf, "eh88", fact_MARKER16, (sf_count_t) (16 + 8 + 8), psf->sf.frames) ;
+
+ psf_binheader_writef (psf, "eh8", data_MARKER16, psf->datalength + 24) ;
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ if (current > 0)
+ psf_fseek (psf, current, SEEK_SET) ;
+
+ return psf->error ;
+} /* w64_write_header */
+
+static int
+w64_close (SF_PRIVATE *psf)
+{
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ w64_write_header (psf, SF_TRUE) ;
+
+ return 0 ;
+} /* w64_close */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 9aa4e141-538a-4dd9-99c9-b3f0f2dd4f4a
+*/
diff --git a/src/wav.c b/src/wav.c
new file mode 100644
index 0000000..09d4ce0
--- /dev/null
+++ b/src/wav.c
@@ -0,0 +1,1673 @@
+/*
+** Copyright (C) 1999-2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+** Copyright (C) 2004-2005 David Viens <davidv@plogue.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+#include "wav_w64.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 data_MARKER (MAKE_MARKER ('d', 'a', 't', 'a'))
+#define fact_MARKER (MAKE_MARKER ('f', 'a', 'c', 't'))
+#define PEAK_MARKER (MAKE_MARKER ('P', 'E', 'A', 'K'))
+
+#define cue_MARKER (MAKE_MARKER ('c', 'u', 'e', ' '))
+#define LIST_MARKER (MAKE_MARKER ('L', 'I', 'S', 'T'))
+#define slnt_MARKER (MAKE_MARKER ('s', 'l', 'n', 't'))
+#define wavl_MARKER (MAKE_MARKER ('w', 'a', 'v', 'l'))
+#define INFO_MARKER (MAKE_MARKER ('I', 'N', 'F', 'O'))
+#define plst_MARKER (MAKE_MARKER ('p', 'l', 's', 't'))
+#define adtl_MARKER (MAKE_MARKER ('a', 'd', 't', 'l'))
+#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 smpl_MARKER (MAKE_MARKER ('s', 'm', 'p', 'l'))
+#define bext_MARKER (MAKE_MARKER ('b', 'e', 'x', 't'))
+#define levl_MARKER (MAKE_MARKER ('l', 'e', 'v', 'l'))
+#define MEXT_MARKER (MAKE_MARKER ('M', 'E', 'X', 'T'))
+#define DISP_MARKER (MAKE_MARKER ('D', 'I', 'S', 'P'))
+#define acid_MARKER (MAKE_MARKER ('a', 'c', 'i', 'd'))
+#define strc_MARKER (MAKE_MARKER ('s', 't', 'r', 'c'))
+#define PAD_MARKER (MAKE_MARKER ('P', 'A', 'D', ' '))
+#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 cart_MARKER (MAKE_MARKER ('c', 'a', 'r', 't'))
+
+#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 IART_MARKER (MAKE_MARKER ('I', 'A', 'R', 'T'))
+#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'))
+
+/* 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'))
+
+#define WAV_PEAK_CHUNK_SIZE(ch) (2 * sizeof (int) + ch * (sizeof (float) + sizeof (int)))
+#define WAV_BEXT_CHUNK_SIZE 602
+
+enum
+{ HAVE_RIFF = 0x01,
+ HAVE_WAVE = 0x02,
+ HAVE_fmt = 0x04,
+ HAVE_fact = 0x08,
+ HAVE_PEAK = 0x10,
+ HAVE_data = 0x20,
+ HAVE_other = 0x80000000
+} ;
+
+
+
+/* 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
+
+/*------------------------------------------------------------------------------
+** 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 wavex_write_header (SF_PRIVATE *psf, int calc_length) ;
+
+static int wav_write_tailer (SF_PRIVATE *psf) ;
+static void wav_write_strings (SF_PRIVATE *psf, int location) ;
+static int wav_command (SF_PRIVATE *psf, int command, void *data, int datasize) ;
+static int wav_close (SF_PRIVATE *psf) ;
+
+static int wav_subchunk_parse (SF_PRIVATE *psf, int chunk) ;
+static int wav_read_smpl_chunk (SF_PRIVATE *psf, unsigned int chunklen) ;
+static int wav_read_acid_chunk (SF_PRIVATE *psf, unsigned int chunklen) ;
+static int wav_read_bext_chunk (SF_PRIVATE *psf, unsigned int chunklen) ;
+static int wav_write_bext_chunk (SF_PRIVATE *psf) ;
+
+/*------------------------------------------------------------------------------
+** Public function.
+*/
+
+int
+wav_open (SF_PRIVATE *psf)
+{ WAV_PRIVATE * wpriv ;
+ int format, subformat, error, blockalign = 0, framesperblock = 0 ;
+
+ if ((wpriv = calloc (1, sizeof (WAV_PRIVATE))) == NULL)
+ return SFE_MALLOC_FAILED ;
+ psf->container_data = wpriv ;
+
+ if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = wav_read_header (psf, &blockalign, &framesperblock)))
+ return error ;
+ } ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if (psf->is_pipe)
+ return SFE_NO_PIPE_WRITE ;
+
+ psf->wavex_ambisonic = SF_AMBISONIC_NONE ;
+
+ format = psf->sf.format & SF_FORMAT_TYPEMASK ;
+ 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 = psf->sf.format & SF_FORMAT_ENDMASK ;
+ 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->mode != SFM_RDWR || psf->filelength < 44)
+ { psf->filelength = 0 ;
+ psf->datalength = 0 ;
+ psf->dataoffset = 0 ;
+ psf->sf.frames = 0 ;
+ } ;
+
+ if (subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM)
+ { blockalign = wav_w64_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ;
+ framesperblock = -1 ; /* Corrected later. */
+ } ;
+
+ psf->str_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->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 = (format == SF_FORMAT_WAV) ? wav_write_header : wavex_write_header ;
+ } ;
+
+ 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 = wav_w64_ima_init (psf, blockalign, framesperblock) ;
+ break ;
+
+ case SF_FORMAT_MS_ADPCM :
+ error = wav_w64_msadpcm_init (psf, blockalign, framesperblock) ;
+ break ;
+
+ case SF_FORMAT_G721_32 :
+ error = g72x_init (psf) ;
+ break ;
+ /* Lite remove end */
+
+ case SF_FORMAT_GSM610 :
+ error = gsm610_init (psf) ;
+ break ;
+
+ default : return SFE_UNIMPLEMENTED ;
+ } ;
+
+ if (psf->mode == SFM_WRITE || (psf->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)
+{ WAV_PRIVATE *wpriv ;
+ WAV_FMT *wav_fmt ;
+ FACT_CHUNK fact_chunk ;
+ unsigned dword = 0, marker, RIFFsize, done = 0 ;
+ int parsestage = 0, error, format = 0 ;
+ char *cptr ;
+
+ if (psf->filelength > SF_PLATFORM_S64 (0xffffffff))
+ 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, "p", 0) ;
+
+ while (! done)
+ { psf_binheader_readf (psf, "m", &marker) ;
+
+ switch (marker)
+ { case RIFF_MARKER :
+ case RIFX_MARKER :
+ if (parsestage)
+ return SFE_WAV_NO_RIFF ;
+
+ parsestage |= HAVE_RIFF ;
+
+ /* 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
+ */
+ if (marker == RIFF_MARKER)
+ psf->rwf_endian = SF_ENDIAN_LITTLE ;
+ else
+ psf->rwf_endian = SF_ENDIAN_BIG ;
+
+ psf_binheader_readf (psf, "4", &RIFFsize) ;
+
+ 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 (dword))
+ { if (marker == RIFF_MARKER)
+ psf_log_printf (psf, "RIFF : %u (should be %D)\n", RIFFsize, psf->filelength - 2 * SIGNED_SIZEOF (dword)) ;
+ else
+ psf_log_printf (psf, "RIFX : %u (should be %D)\n", RIFFsize, psf->filelength - 2 * SIGNED_SIZEOF (dword)) ;
+
+ RIFFsize = dword ;
+ }
+ else
+ { if (marker == RIFF_MARKER)
+ psf_log_printf (psf, "RIFF : %u\n", RIFFsize) ;
+ else
+ psf_log_printf (psf, "RIFX : %u\n", RIFFsize) ;
+ } ;
+ break ;
+
+ case WAVE_MARKER :
+ if ((parsestage & HAVE_RIFF) != HAVE_RIFF)
+ return SFE_WAV_NO_WAVE ;
+ parsestage |= HAVE_WAVE ;
+
+ psf_log_printf (psf, "WAVE\n") ;
+ 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_binheader_readf (psf, "4", &dword) ;
+ psf_log_printf (psf, "fmt : %d\n", dword) ;
+
+ if ((error = wav_w64_read_fmt_chunk (psf, dword)))
+ 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->mode == SFM_RDWR && (parsestage & HAVE_other) != 0)
+ return SFE_RDWR_BAD_HEADER ;
+
+ parsestage |= HAVE_data ;
+
+ psf_binheader_readf (psf, "4", &dword) ;
+
+ psf->datalength = dword ;
+ psf->dataoffset = psf_ftell (psf) ;
+
+ if (dword == 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 ;
+
+ if (format == WAVE_FORMAT_MS_ADPCM && psf->datalength % 2)
+ { psf->datalength ++ ;
+ psf_log_printf (psf, "*** Data length odd. Increasing it by 1.\n") ;
+ } ;
+
+ if (! psf->sf.seekable)
+ 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", dword, psf->dataoffset + psf->datalength) ;
+ 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, "44", &dword, & (fact_chunk.frames)) ;
+
+ if (dword > SIGNED_SIZEOF (fact_chunk))
+ psf_binheader_readf (psf, "j", (int) (dword - SIGNED_SIZEOF (fact_chunk))) ;
+
+ if (dword)
+ psf_log_printf (psf, "%M : %d\n", marker, dword) ;
+ else
+ psf_log_printf (psf, "%M : %d (should not be zero)\n", marker, dword) ;
+
+ 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_binheader_readf (psf, "4", &dword) ;
+
+ psf_log_printf (psf, "%M : %d\n", marker, dword) ;
+ if (dword != WAV_PEAK_CHUNK_SIZE (psf->sf.channels))
+ { psf_binheader_readf (psf, "j", dword) ;
+ 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 = 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") ;
+
+ cptr = psf->u.cbuf ;
+ for (dword = 0 ; dword < (unsigned) psf->sf.channels ; dword++)
+ { float value ;
+ unsigned int position ;
+ psf_binheader_readf (psf, "f4", &value, &position) ;
+ psf->peak_info->peaks [dword].value = value ;
+ psf->peak_info->peaks [dword].position = position ;
+
+ LSF_SNPRINTF (cptr, sizeof (psf->u.cbuf), " %2d %-12ld %g\n",
+ dword, (long) psf->peak_info->peaks [dword].position, psf->peak_info->peaks [dword].value) ;
+ cptr [sizeof (psf->u.cbuf) - 1] = 0 ;
+ psf_log_printf (psf, cptr) ;
+ } ;
+
+ psf->peak_info->peak_loc = ((parsestage & HAVE_data) == 0) ? SF_PEAK_START : SF_PEAK_END ;
+ break ;
+
+ case cue_MARKER :
+ parsestage |= HAVE_other ;
+
+ { unsigned bytesread, cue_count ;
+ int id, position, chunk_id, chunk_start, block_start, offset ;
+
+ bytesread = psf_binheader_readf (psf, "44", &dword, &cue_count) ;
+ bytesread -= 4 ; /* Remove bytes for first dword. */
+ psf_log_printf (psf, "%M : %u\n", marker, dword) ;
+
+ if (cue_count > 10)
+ { psf_log_printf (psf, " Count : %d (skipping)\n", cue_count) ;
+ psf_binheader_readf (psf, "j", cue_count * 24) ;
+ break ;
+ } ;
+
+ psf_log_printf (psf, " Count : %d\n", cue_count) ;
+
+ while (cue_count)
+ { bytesread += psf_binheader_readf (psf, "444444", &id, &position,
+ &chunk_id, &chunk_start, &block_start, &offset) ;
+ 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) ;
+ cue_count -- ;
+ } ;
+
+ if (bytesread != dword)
+ { psf_log_printf (psf, "**** Chunk size weirdness (%d != %d)\n", dword, bytesread) ;
+ psf_binheader_readf (psf, "j", dword - bytesread) ;
+ } ;
+ } ;
+ break ;
+
+ case smpl_MARKER :
+ parsestage |= HAVE_other ;
+
+ psf_binheader_readf (psf, "4", &dword) ;
+ psf_log_printf (psf, "smpl : %u\n", dword) ;
+
+ if ((error = wav_read_smpl_chunk (psf, dword)))
+ return error ;
+ break ;
+
+ case acid_MARKER :
+ parsestage |= HAVE_other ;
+
+ psf_binheader_readf (psf, "4", &dword) ;
+ psf_log_printf (psf, "acid : %u\n", dword) ;
+
+ if ((error = wav_read_acid_chunk (psf, dword)))
+ return error ;
+ break ;
+
+ case INFO_MARKER :
+ case LIST_MARKER :
+ parsestage |= HAVE_other ;
+
+ if ((error = wav_subchunk_parse (psf, marker)) != 0)
+ return error ;
+ break ;
+
+ case bext_MARKER :
+ parsestage |= HAVE_other ;
+
+ psf_binheader_readf (psf, "4", &dword) ;
+ if (dword < WAV_BEXT_CHUNK_SIZE)
+ psf_log_printf (psf, "bext : %u (should be >= %d)\n", dword, WAV_BEXT_CHUNK_SIZE) ;
+ else
+ psf_log_printf (psf, "bext : %u\n", dword) ;
+
+ if ((error = wav_read_bext_chunk (psf, dword)))
+ return error ;
+ break ;
+
+ case strc_MARKER : /* Multiple of 32 bytes. */
+
+ case afsp_MARKER :
+ case clm_MARKER :
+ case elmo_MARKER :
+ case cart_MARKER :
+ case levl_MARKER :
+ case plst_MARKER :
+ case DISP_MARKER :
+ case MEXT_MARKER :
+ case PAD_MARKER :
+ parsestage |= HAVE_other ;
+
+ psf_binheader_readf (psf, "4", &dword) ;
+ psf_log_printf (psf, "%M : %u\n", marker, dword) ;
+ dword += (dword & 1) ;
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+
+ default :
+ parsestage |= HAVE_other ;
+ if (isprint ((marker >> 24) & 0xFF) && isprint ((marker >> 16) & 0xFF)
+ && isprint ((marker >> 8) & 0xFF) && isprint (marker & 0xFF))
+ { psf_binheader_readf (psf, "4", &dword) ;
+ psf_log_printf (psf, "*** %M : %d (unknown marker)\n", marker, dword) ;
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+ } ;
+ if (psf_ftell (psf) & 0x03)
+ { psf_log_printf (psf, " Unknown chunk marker at position %d. Resynching.\n", dword - 4) ;
+ 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) - 4) ;
+ done = SF_TRUE ;
+ break ;
+ } ; /* switch (dword) */
+
+ if (! psf->sf.seekable && (parsestage & HAVE_data))
+ break ;
+
+ if (psf_ftell (psf) >= psf->filelength - SIGNED_SIZEOF (dword))
+ { psf_log_printf (psf, "End\n") ;
+ break ;
+ } ;
+ } ; /* while (1) */
+
+ if (! psf->dataoffset)
+ return SFE_WAV_NO_DATA ;
+
+ /* 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_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 ;
+
+ default : return SFE_UNIMPLEMENTED ;
+ } ;
+
+ if (wpriv->fmt_is_broken)
+ wav_w64_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_header (SF_PRIVATE *psf, int calc_length)
+{ sf_count_t current ;
+ int fmt_size, k, 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 > 0)
+ psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
+ } ;
+
+ /* Reset the current header length to zero. */
+ psf->header [0] = 0 ;
+ psf->headindex = 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", RIFF_MARKER, (psf->filelength < 8) ? 8 : psf->filelength - 8) ;
+ else
+ psf_binheader_writef (psf, "Etm8", RIFX_MARKER, (psf->filelength < 8) ? 8 : psf->filelength - 8) ;
+
+ /* WAVE and 'fmt ' markers. */
+ psf_binheader_writef (psf, "mm", WAVE_MARKER, fmt_MARKER) ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ 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", fmt_size, WAVE_FORMAT_PCM, psf->sf.channels, psf->sf.samplerate) ;
+ /* fmt : bytespersec */
+ psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
+ /* fmt : blockalign, bitwidth */
+ psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, 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", fmt_size, WAVE_FORMAT_IEEE_FLOAT, psf->sf.channels, psf->sf.samplerate) ;
+ /* fmt : bytespersec */
+ psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
+ /* fmt : blockalign, bitwidth */
+ psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, psf->bytewidth * 8) ;
+
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ case SF_FORMAT_ULAW :
+ fmt_size = 2 + 2 + 4 + 4 + 2 + 2 ;
+
+ /* fmt : format, channels, samplerate */
+ psf_binheader_writef (psf, "4224", fmt_size, WAVE_FORMAT_MULAW, psf->sf.channels, psf->sf.samplerate) ;
+ /* fmt : bytespersec */
+ psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
+ /* fmt : blockalign, bitwidth */
+ psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, 8) ;
+
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ case SF_FORMAT_ALAW :
+ fmt_size = 2 + 2 + 4 + 4 + 2 + 2 ;
+
+ /* fmt : format, channels, samplerate */
+ psf_binheader_writef (psf, "4224", fmt_size, WAVE_FORMAT_ALAW, psf->sf.channels, psf->sf.samplerate) ;
+ /* fmt : bytespersec */
+ psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
+ /* fmt : blockalign, bitwidth */
+ psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, 8) ;
+
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ /* Lite remove start */
+ case SF_FORMAT_IMA_ADPCM :
+ { int blockalign, framesperblock, bytespersec ;
+
+ blockalign = wav_w64_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", fmt_size, WAVE_FORMAT_IMA_ADPCM,
+ psf->sf.channels, psf->sf.samplerate, bytespersec) ;
+
+ /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
+ psf_binheader_writef (psf, "2222", blockalign, 4, 2, framesperblock) ;
+ } ;
+
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ case SF_FORMAT_MS_ADPCM :
+ { int blockalign, framesperblock, bytespersec, extrabytes ;
+
+ blockalign = wav_w64_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 + 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", fmt_size, WAVE_FORMAT_MS_ADPCM, psf->sf.channels) ;
+
+ /* fmt : samplerate, bytespersec. */
+ psf_binheader_writef (psf, "44", psf->sf.samplerate, bytespersec) ;
+
+ /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
+ psf_binheader_writef (psf, "22222", blockalign, 4, extrabytes, framesperblock, 7) ;
+
+ 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", fmt_size, WAVE_FORMAT_G721_ADPCM,
+ psf->sf.channels, psf->sf.samplerate, psf->sf.samplerate * psf->sf.channels / 2) ;
+
+ /* fmt : blockalign, bitwidth, extrabytes, auxblocksize. */
+ psf_binheader_writef (psf, "2222", 64, 4, 2, 0) ;
+
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ /* Lite remove end */
+
+ case SF_FORMAT_GSM610 :
+ { int blockalign, framesperblock, bytespersec ;
+
+ blockalign = WAV_W64_GSM610_BLOCKSIZE ;
+ framesperblock = WAV_W64_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", fmt_size, WAVE_FORMAT_GSM610, psf->sf.channels) ;
+
+ /* fmt : samplerate, bytespersec. */
+ psf_binheader_writef (psf, "44", psf->sf.samplerate, bytespersec) ;
+
+ /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
+ psf_binheader_writef (psf, "2222", blockalign, 0, 2, framesperblock) ;
+ } ;
+
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ default : return SFE_UNIMPLEMENTED ;
+ } ;
+
+ if (add_fact_chunk)
+ psf_binheader_writef (psf, "tm48", fact_MARKER, 4, psf->sf.frames) ;
+
+ if (psf->str_flags & SF_STR_LOCATE_START)
+ wav_write_strings (psf, SF_STR_LOCATE_START) ;
+
+ if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_START)
+ { psf_binheader_writef (psf, "m4", PEAK_MARKER, WAV_PEAK_CHUNK_SIZE (psf->sf.channels)) ;
+ psf_binheader_writef (psf, "44", 1, time (NULL)) ;
+ for (k = 0 ; k < psf->sf.channels ; k++)
+ psf_binheader_writef (psf, "ft8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ;
+ } ;
+
+ if (psf->broadcast_info != NULL)
+ wav_write_bext_chunk (psf) ;
+
+ if (psf->instrument != NULL)
+ { int tmp ;
+ double dtune = (double) (0x40000000) / 25.0 ;
+
+ psf_binheader_writef (psf, "m4", smpl_MARKER, 9 * 4 + psf->instrument->loop_count * 6 * 4) ;
+ psf_binheader_writef (psf, "44", 0, 0) ; /* Manufacturer zero is everyone */
+ tmp = (int) (1.0e9 / psf->sf.samplerate) ; /* Sample period in nano seconds */
+ psf_binheader_writef (psf, "44", tmp, psf->instrument->basenote) ;
+ tmp = (unsigned int) (psf->instrument->detune * dtune + 0.5) ;
+ psf_binheader_writef (psf, "4", tmp) ;
+ psf_binheader_writef (psf, "44", 0, 0) ; /* SMTPE format */
+ psf_binheader_writef (psf, "44", psf->instrument->loop_count, 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", tmp, type) ;
+ psf_binheader_writef (psf, "44", psf->instrument->loops [tmp].start, psf->instrument->loops [tmp].end) ;
+ psf_binheader_writef (psf, "44", 0, psf->instrument->loops [tmp].count) ;
+ } ;
+ } ;
+
+ psf_binheader_writef (psf, "tm8", data_MARKER, psf->datalength) ;
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ if (current < psf->dataoffset)
+ 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
+wavex_write_header (SF_PRIVATE *psf, int calc_length)
+{ sf_count_t current ;
+ int fmt_size, k, 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 > 0)
+ psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
+ } ;
+
+
+ /* Reset the current header length to zero. */
+ psf->header [0] = 0 ;
+ psf->headindex = 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 ops
+ */
+
+ /* RIFF marker, length, WAVE and 'fmt ' markers. */
+
+ if (psf->endian == SF_ENDIAN_LITTLE)
+ { if (psf->filelength < 8)
+ psf_binheader_writef (psf, "tm8", RIFF_MARKER, 8) ;
+ else
+ psf_binheader_writef (psf, "tm8", RIFF_MARKER, psf->filelength - 8) ;
+ }
+ else
+ { if (psf->filelength < 8)
+ psf_binheader_writef (psf, "Etm8", RIFX_MARKER, 8) ;
+ else
+ psf_binheader_writef (psf, "Etm8", RIFX_MARKER, psf->filelength - 8) ;
+ } ;
+
+ /* WAVE and 'fmt ' markers. */
+ psf_binheader_writef (psf, "mm", WAVE_MARKER, fmt_MARKER) ;
+
+ 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", fmt_size, WAVE_FORMAT_EXTENSIBLE, psf->sf.channels, psf->sf.samplerate) ;
+ /* fmt : bytespersec */
+ psf_binheader_writef (psf, "4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
+ /* fmt : blockalign, bitwidth */
+ psf_binheader_writef (psf, "22", psf->bytewidth * psf->sf.channels, psf->bytewidth * 8) ;
+
+ /* cbSize 22 is sizeof (WAVEFORMATEXTENSIBLE) - sizeof (WAVEFORMATEX) */
+ psf_binheader_writef (psf, "2", 22) ;
+
+ /* wValidBitsPerSample, for our use same as bitwidth as we use it fully */
+ psf_binheader_writef (psf, "2", psf->bytewidth * 8) ;
+
+ /* For an Ambisonic file set the channel mask to zero.
+ ** Otherwise use a default based on the channel count.
+ */
+ if (psf->wavex_ambisonic)
+ psf_binheader_writef (psf, "4", 0) ;
+ 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", 0x4) ;
+ break ;
+
+ case 2 : /* front left and right */
+ psf_binheader_writef (psf, "4", 0x1 | 0x2) ;
+ break ;
+
+ case 4 : /* Quad */
+ psf_binheader_writef (psf, "4", 0x1 | 0x2 | 0x10 | 0x20) ;
+ break ;
+
+ case 6 : /* 5.1 */
+ psf_binheader_writef (psf, "4", 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20) ;
+ break ;
+
+ case 8 : /* 7.1 */
+ psf_binheader_writef (psf, "4", 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", 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 :
+ wavex_write_guid (psf, psf->wavex_ambisonic ? &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM
+ : &MSGUID_SUBTYPE_PCM) ;
+ break ;
+
+ case SF_FORMAT_FLOAT :
+ case SF_FORMAT_DOUBLE :
+ wavex_write_guid (psf, psf->wavex_ambisonic ? &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT
+ : &MSGUID_SUBTYPE_IEEE_FLOAT) ;
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ case SF_FORMAT_ULAW :
+ wavex_write_guid (psf, &MSGUID_SUBTYPE_MULAW) ;
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ case SF_FORMAT_ALAW :
+ wavex_write_guid (psf, &MSGUID_SUBTYPE_ALAW) ;
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ case SF_FORMAT_MS_ADPCM : /* todo, GUID exists */
+ return SFE_UNIMPLEMENTED ;
+ wavex_write_guid (psf, &MSGUID_SUBTYPE_MS_ADPCM) ;
+ add_fact_chunk = SF_TRUE ;
+ break ;
+
+ default : return SFE_UNIMPLEMENTED ;
+ } ;
+
+ if (add_fact_chunk)
+ psf_binheader_writef (psf, "tm48", fact_MARKER, 4, psf->sf.frames) ;
+
+ if (psf->str_flags & SF_STR_LOCATE_START)
+ wav_write_strings (psf, SF_STR_LOCATE_START) ;
+
+ if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_START)
+ { psf_binheader_writef (psf, "m4", PEAK_MARKER, WAV_PEAK_CHUNK_SIZE (psf->sf.channels)) ;
+ psf_binheader_writef (psf, "44", 1, time (NULL)) ;
+ for (k = 0 ; k < psf->sf.channels ; k++)
+ psf_binheader_writef (psf, "ft8", (float) psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ;
+ } ;
+
+ psf_binheader_writef (psf, "tm8", data_MARKER, psf->datalength) ;
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ if (current < psf->dataoffset)
+ psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
+ else if (current > 0)
+ psf_fseek (psf, current, SEEK_SET) ;
+
+ return psf->error ;
+} /* wavex_write_header */
+
+
+
+static int
+wav_write_tailer (SF_PRIVATE *psf)
+{ int k ;
+
+ /* Reset the current header buffer length to zero. */
+ psf->header [0] = 0 ;
+ psf->headindex = 0 ;
+
+ psf->dataend = psf_fseek (psf, 0, SEEK_END) ;
+
+ /* Add a PEAK chunk if requested. */
+ if (psf->peak_info != NULL && psf->peak_info->peak_loc == SF_PEAK_END)
+ { psf_binheader_writef (psf, "m4", PEAK_MARKER, WAV_PEAK_CHUNK_SIZE (psf->sf.channels)) ;
+ psf_binheader_writef (psf, "44", 1, time (NULL)) ;
+ for (k = 0 ; k < psf->sf.channels ; k++)
+ psf_binheader_writef (psf, "f4", psf->peak_info->peaks [k].value, psf->peak_info->peaks [k].position) ;
+ } ;
+
+ if (psf->str_flags & SF_STR_LOCATE_END)
+ wav_write_strings (psf, SF_STR_LOCATE_END) ;
+
+ /* Write the tailer. */
+ if (psf->headindex > 0)
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ return 0 ;
+} /* wav_write_tailer */
+
+static void
+wav_write_strings (SF_PRIVATE *psf, int location)
+{ int k, prev_head_index, saved_head_index ;
+
+ prev_head_index = psf->headindex + 4 ;
+
+ psf_binheader_writef (psf, "m4m", LIST_MARKER, 0xBADBAD, INFO_MARKER) ;
+
+ for (k = 0 ; k < SF_MAX_STRINGS ; k++)
+ { if (psf->strings [k].type == 0)
+ break ;
+ if (psf->strings [k].flags != location)
+ continue ;
+
+ switch (psf->strings [k].type)
+ { case SF_STR_SOFTWARE :
+ psf_binheader_writef (psf, "ms", ISFT_MARKER, psf->strings [k].str) ;
+ break ;
+
+ case SF_STR_TITLE :
+ psf_binheader_writef (psf, "ms", INAM_MARKER, psf->strings [k].str) ;
+ break ;
+
+ case SF_STR_COPYRIGHT :
+ psf_binheader_writef (psf, "ms", ICOP_MARKER, psf->strings [k].str) ;
+ break ;
+
+ case SF_STR_ARTIST :
+ psf_binheader_writef (psf, "ms", IART_MARKER, psf->strings [k].str) ;
+ break ;
+
+ case SF_STR_COMMENT :
+ psf_binheader_writef (psf, "ms", ICMT_MARKER, psf->strings [k].str) ;
+ break ;
+
+ case SF_STR_DATE :
+ psf_binheader_writef (psf, "ms", ICRD_MARKER, psf->strings [k].str) ;
+ break ;
+ } ;
+ } ;
+
+ saved_head_index = psf->headindex ;
+ psf->headindex = prev_head_index ;
+ psf_binheader_writef (psf, "4", saved_head_index - prev_head_index - 4) ;
+ psf->headindex = saved_head_index ;
+
+} /* wav_write_strings */
+
+static int
+wav_close (SF_PRIVATE *psf)
+{
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { wav_write_tailer (psf) ;
+
+ psf->write_header (psf, SF_TRUE) ;
+ } ;
+
+ return 0 ;
+} /* wav_close */
+
+static int
+wav_command (SF_PRIVATE *psf, int command, void * UNUSED (data), int datasize)
+{
+ switch (command)
+ { case SFC_WAVEX_SET_AMBISONIC :
+ if ((psf->sf.format & SF_FORMAT_TYPEMASK) == SF_FORMAT_WAVEX)
+ { if (datasize == SF_AMBISONIC_NONE)
+ psf->wavex_ambisonic = SF_AMBISONIC_NONE ;
+ else if (datasize == SF_AMBISONIC_B_FORMAT)
+ psf->wavex_ambisonic = SF_AMBISONIC_B_FORMAT ;
+ else
+ return 0 ;
+ } ;
+ return psf->wavex_ambisonic ;
+
+ case SFC_WAVEX_GET_AMBISONIC :
+ return psf->wavex_ambisonic ;
+
+ default :
+ break ;
+ } ;
+
+ return 0 ;
+} /* wav_command */
+
+static int
+wav_subchunk_parse (SF_PRIVATE *psf, int chunk)
+{ sf_count_t current_pos ;
+ char *cptr ;
+ int dword, bytesread, length ;
+
+ current_pos = psf_fseek (psf, 0, SEEK_CUR) ;
+
+ bytesread = psf_binheader_readf (psf, "4", &length) ;
+
+ if (length <= 8)
+ { /* This case is for broken files generated by PEAK. */
+ psf_log_printf (psf, "%M : %d (weird length)\n", chunk, length) ;
+ psf_binheader_readf (psf, "mj", &chunk, length - 4) ;
+ psf_log_printf (psf, " %M\n", chunk) ;
+ return 0 ;
+ } ;
+
+ if (psf->headindex + length > SIGNED_SIZEOF (psf->header))
+ { psf_log_printf (psf, "%M : %d (too long)\n", chunk, length) ;
+ psf_binheader_readf (psf, "j", length) ;
+ return 0 ;
+ } ;
+
+ if (current_pos + length > psf->filelength)
+ { psf_log_printf (psf, "%M : %d (should be %d)\n", chunk, length, (int) (psf->filelength - current_pos)) ;
+ length = psf->filelength - current_pos ;
+ }
+ else
+ psf_log_printf (psf, "%M : %d\n", chunk, length) ;
+
+ while (bytesread < length)
+ { bytesread += psf_binheader_readf (psf, "m", &chunk) ;
+
+ switch (chunk)
+ { case adtl_MARKER :
+ case INFO_MARKER :
+ /* These markers don't contain anything. */
+ psf_log_printf (psf, " %M\n", chunk) ;
+ break ;
+
+ 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 ISFT_MARKER :
+ case ICOP_MARKER :
+ case IARL_MARKER :
+ case IART_MARKER :
+ case ICMT_MARKER :
+ case ICRD_MARKER :
+ case IENG_MARKER :
+
+ case INAM_MARKER :
+ case IPRD_MARKER :
+ case ISBJ_MARKER :
+ case ISRC_MARKER :
+ bytesread += psf_binheader_readf (psf, "4", &dword) ;
+ dword += (dword & 1) ;
+ if (dword < 0 || dword > SIGNED_SIZEOF (psf->u.cbuf))
+ { psf_log_printf (psf, " *** %M : %d (too big)\n", chunk, dword) ;
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+ } ;
+
+ cptr = psf->u.cbuf ;
+ psf_binheader_readf (psf, "b", cptr, dword) ;
+ bytesread += dword ;
+ cptr [dword - 1] = 0 ;
+ psf_log_printf (psf, " %M : %s\n", chunk, cptr) ;
+ break ;
+
+ case labl_MARKER :
+ { int mark_id ;
+
+ bytesread += psf_binheader_readf (psf, "44", &dword, &mark_id) ;
+ dword -= 4 ;
+ dword += (dword & 1) ;
+ if (dword < 1 || dword > SIGNED_SIZEOF (psf->u.cbuf))
+ { psf_log_printf (psf, " *** %M : %d (too big)\n", chunk, dword) ;
+ psf_binheader_readf (psf, "j", dword) ;
+ break ;
+ } ;
+
+ cptr = psf->u.cbuf ;
+ psf_binheader_readf (psf, "b", cptr, dword) ;
+ bytesread += dword ;
+ cptr [dword - 1] = 0 ;
+ psf_log_printf (psf, " %M : %d : %s\n", chunk, mark_id, cptr) ;
+ } ;
+ break ;
+
+
+ case DISP_MARKER :
+ case ltxt_MARKER :
+ case note_MARKER :
+ bytesread += psf_binheader_readf (psf, "4", &dword) ;
+ dword += (dword & 1) ;
+ psf_binheader_readf (psf, "j", dword) ;
+ bytesread += dword ;
+ psf_log_printf (psf, " %M : %d\n", chunk, dword) ;
+ break ;
+
+ default :
+ psf_binheader_readf (psf, "4", &dword) ;
+ bytesread += sizeof (dword) ;
+ dword += (dword & 1) ;
+ psf_binheader_readf (psf, "j", dword) ;
+ bytesread += dword ;
+ psf_log_printf (psf, " *** %M : %d\n", chunk, dword) ;
+ if (dword > length)
+ return 0 ;
+ break ;
+ } ;
+
+ switch (chunk)
+ { case ISFT_MARKER :
+ psf_store_string (psf, SF_STR_SOFTWARE, psf->u.cbuf) ;
+ break ;
+ case ICOP_MARKER :
+ psf_store_string (psf, SF_STR_COPYRIGHT, psf->u.cbuf) ;
+ break ;
+ case INAM_MARKER :
+ psf_store_string (psf, SF_STR_TITLE, psf->u.cbuf) ;
+ break ;
+ case IART_MARKER :
+ psf_store_string (psf, SF_STR_ARTIST, psf->u.cbuf) ;
+ break ;
+ case ICMT_MARKER :
+ psf_store_string (psf, SF_STR_COMMENT, psf->u.cbuf) ;
+ break ;
+ case ICRD_MARKER :
+ psf_store_string (psf, SF_STR_DATE, psf->u.cbuf) ;
+ break ;
+ } ;
+ } ;
+
+ current_pos = psf_fseek (psf, 0, SEEK_CUR) - current_pos ;
+
+ if (current_pos - 4 != length)
+ psf_log_printf (psf, "**** Bad chunk length %d sbould be %D\n", length, current_pos - 4) ;
+
+ return 0 ;
+} /* wav_subchunk_parse */
+
+static int
+wav_read_smpl_chunk (SF_PRIVATE *psf, unsigned int chunklen)
+{ unsigned int bytesread = 0, dword, sampler_data, loop_count ;
+ unsigned int note, 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", &note) ;
+ psf_log_printf (psf, " Midi Note : %u\n", note) ;
+
+ bytesread += psf_binheader_readf (psf, "4", &dword) ;
+ if (dword != 0)
+ { LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%f",
+ (1.0 * 0x80000000) / ((unsigned int) dword)) ;
+ psf_log_printf (psf, " Pitch Fract. : %s\n", psf->u.cbuf) ;
+ }
+ 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) ;
+ LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%02d:%02d:%02d %02d",
+ (dword >> 24) & 0x7F, (dword >> 16) & 0x7F, (dword >> 8) & 0x7F, dword & 0x7F) ;
+ psf_log_printf (psf, " SMPTE Offset : %s\n", psf->u.cbuf) ;
+
+ bytesread += psf_binheader_readf (psf, "4", &loop_count) ;
+ psf_log_printf (psf, " Loop Count : %u\n", loop_count) ;
+
+ /* 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_instrument_alloc ()) == NULL)
+ return SFE_MALLOC_FAILED ;
+
+ psf->instrument->loop_count = loop_count ;
+
+ for (j = 0 ; loop_count > 0 && chunklen - bytesread >= 24 ; j ++)
+ { bytesread += psf_binheader_readf (psf, "4", &dword) ;
+ 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 ;
+ 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 ;
+ } ;
+ } ;
+
+ 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 ") ;
+
+ bytesread += psf_binheader_readf (psf, "1", &ch) ;
+ psf_log_printf (psf, "%02X ", ch & 0xFF) ;
+ } ;
+
+ psf_log_printf (psf, "\n") ;
+ } ;
+
+ psf->instrument->basenote = note ;
+ 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, unsigned int chunklen)
+{ unsigned int 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) ;
+
+ LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%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, psf->u.cbuf) ;
+
+ bytesread += psf_binheader_readf (psf, "422f", &beats, &meter_denom, &meter_numer, &tempo) ;
+ LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), "%f", tempo) ;
+ psf_log_printf (psf, " Beats : %d\n Meter : %d/%d\n Tempo : %s\n",
+ beats, meter_numer, meter_denom, psf->u.cbuf) ;
+
+ psf_binheader_readf (psf, "j", chunklen - bytesread) ;
+
+ 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 */
+
+int
+wav_read_bext_chunk (SF_PRIVATE *psf, unsigned int chunksize)
+{
+ SF_BROADCAST_INFO* b ;
+ unsigned int bytes = 0 ;
+
+ if ((psf->broadcast_info = calloc (1, sizeof (SF_BROADCAST_INFO))) == NULL)
+ { psf->error = SFE_MALLOC_FAILED ;
+ return psf->error ;
+ } ;
+
+ b = psf->broadcast_info ;
+
+ 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, "bj", &b->umid, sizeof (b->umid), 190) ;
+
+ if (chunksize > WAV_BEXT_CHUNK_SIZE)
+ { /* File has coding history data. */
+
+ b->coding_history_size = chunksize - WAV_BEXT_CHUNK_SIZE ;
+
+ if (b->coding_history_size > SIGNED_SIZEOF (b->coding_history))
+ b->coding_history_size = SIGNED_SIZEOF (b->coding_history) ;
+
+ /* We do not parse the coding history */
+ bytes += psf_binheader_readf (psf, "b", b->coding_history, b->coding_history_size) ;
+ b->coding_history [sizeof (b->coding_history) - 1] = 0 ;
+ } ;
+
+ if (bytes < chunksize)
+ psf_binheader_readf (psf, "j", chunksize - bytes) ;
+
+ return 0 ;
+} /* wav_read_bext_chunk */
+
+static int
+wav_write_bext_chunk (SF_PRIVATE *psf)
+{ SF_BROADCAST_INFO *b ;
+
+ if ((b = psf->broadcast_info) == NULL)
+ return -1 ;
+
+ psf_binheader_writef (psf, "m4", bext_MARKER, WAV_BEXT_CHUNK_SIZE + b->coding_history_size) ;
+
+ /*
+ ** Note that it is very important the the field widths of the SF_BROADCAST_INFO
+ ** struct match those for the bext chunk fields.
+ */
+
+ psf_binheader_writef (psf, "b", b->description, sizeof (b->description)) ;
+ psf_binheader_writef (psf, "b", b->originator, sizeof (b->originator)) ;
+ psf_binheader_writef (psf, "b", b->originator_reference, sizeof (b->originator_reference)) ;
+ psf_binheader_writef (psf, "b", b->origination_date, sizeof (b->origination_date)) ;
+ psf_binheader_writef (psf, "b", b->origination_time, sizeof (b->origination_time)) ;
+ psf_binheader_writef (psf, "442", b->time_reference_low, b->time_reference_high, b->version) ;
+ psf_binheader_writef (psf, "b", b->umid, sizeof (b->umid)) ;
+ psf_binheader_writef (psf, "z", make_size_t (190)) ;
+
+ if (b->coding_history_size > 0)
+ psf_binheader_writef (psf, "b", b->coding_history, make_size_t (b->coding_history_size)) ;
+
+ return 0 ;
+} /* wav_write_bext_chunk */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 9c551689-a1d8-4905-9f56-26a204374f18
+*/
diff --git a/src/wav_w64.c b/src/wav_w64.c
new file mode 100644
index 0000000..cec6a9b
--- /dev/null
+++ b/src/wav_w64.c
@@ -0,0 +1,578 @@
+/*
+** Copyright (C) 1999-2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+** Copyright (C) 2004-2005 David Viens <davidv@plogue.com>
+**
+** 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 <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+#include "wav_w64.h"
+
+/* 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
+
+/*------------------------------------------------------------------------------
+ * Private static functions.
+ */
+
+static int
+wavex_write_guid_equal (const EXT_SUBFORMAT * first, const EXT_SUBFORMAT * second)
+{ return !memcmp (first, second, sizeof (EXT_SUBFORMAT)) ;
+} /* wavex_write_guid_equal */
+
+
+
+int
+wav_w64_read_fmt_chunk (SF_PRIVATE *psf, int fmtsize)
+{ WAV_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, wav_w64_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) ;
+ 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 :
+ 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 :
+ 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.blockalign != wav_fmt->min.samplerate)
+ 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)) ;
+
+ 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) ;
+
+ psf->bytewidth = 2 ;
+ psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->ima.extrabytes) ;
+ psf_log_printf (psf, " Samples/Block : %d\n", wav_fmt->ima.samplesperblock) ;
+ 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)) ;
+
+ 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) ;
+
+
+ psf->bytewidth = 2 ;
+ psf_log_printf (psf, " Extra Bytes : %d\n", wav_fmt->msadpcm.extrabytes) ;
+ psf_log_printf (psf, " Samples/Block : %d\n", wav_fmt->msadpcm.samplesperblock) ;
+ if (wav_fmt->msadpcm.numcoeffs > SIGNED_SIZEOF (MS_ADPCM_WAV_FMT) / SIGNED_SIZEOF (int))
+ { psf_log_printf (psf, " No. of Coeffs : %d ****\n", wav_fmt->msadpcm.numcoeffs) ;
+ wav_fmt->msadpcm.numcoeffs = SIGNED_SIZEOF (MS_ADPCM_WAV_FMT) / SIGNED_SIZEOF (int) ;
+ }
+ 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++)
+ { bytesread +=
+ psf_binheader_readf (psf, "22", &(wav_fmt->msadpcm.coeffs [k].coeff1), &(wav_fmt->msadpcm.coeffs [k].coeff2)) ;
+ LSF_SNPRINTF (psf->u.cbuf, sizeof (psf->u.cbuf), " %2d %7d %7d\n", k, wav_fmt->msadpcm.coeffs [k].coeff1, wav_fmt->msadpcm.coeffs [k].coeff2) ;
+ psf_log_printf (psf, psf->u.cbuf) ;
+ } ;
+ 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->bytewidth = 2 ;
+ 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_EXTENSIBLE :
+ if (wav_fmt->ext.bytespersec / wav_fmt->ext.blockalign != wav_fmt->ext.samplerate)
+ 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) ;
+ psf_log_printf (psf, " Channel Mask : 0x%X\n", wav_fmt->ext.channelmask) ;
+
+ 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_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_PCM)
+ || wavex_write_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\n") ;
+ }
+ else if (wavex_write_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_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_IEEE_FLOAT)
+ || wavex_write_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\n") ;
+ }
+ else if (wavex_write_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_write_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
+ return SFE_UNIMPLEMENTED ;
+
+ psf->wavex_ambisonic = wavex_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_PCM)
+ || wavex_write_guid_equal (&wav_fmt->ext.esf, &MSGUID_SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT) ;
+ 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 ;
+
+ default :
+ psf_log_printf (psf, "*** No 'fmt ' chunk dumper for this format!\n") ;
+ break ;
+ } ;
+
+ if (bytesread > fmtsize)
+ { psf_log_printf (psf, "*** wav_w64_read_fmt_chunk (bytesread > fmtsize)\n") ;
+ return SFE_W64_FMT_SHORT ;
+ }
+ else
+ psf_binheader_readf (psf, "j", fmtsize - bytesread) ;
+
+ psf->blockwidth = wav_fmt->min.channels * psf->bytewidth ;
+
+ return 0 ;
+} /* wav_w64_read_fmt_chunk */
+
+void
+wavex_write_guid (SF_PRIVATE *psf, const EXT_SUBFORMAT * subformat)
+{
+ psf_binheader_writef (psf, "422b", subformat->esf_field1,
+ subformat->esf_field2, subformat->esf_field3,
+ subformat->esf_field4, make_size_t (8)) ;
+} /* wavex_write_guid */
+
+void
+wav_w64_analyze (SF_PRIVATE *psf)
+{ 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 (psf->u.ucbuf, 1, 4096, psf) == 4096)
+ { format = audio_detect (psf, &ad, psf->u.ucbuf, 4096) ;
+ if (format != 0)
+ break ;
+ } ;
+
+ /* Seek to start of DATA section. */
+ psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
+
+ if (format == 0)
+ { psf_log_printf (psf, "wav_w64_analyze : detection failed.\n") ;
+ return ;
+ } ;
+
+ switch (format)
+ { case SF_FORMAT_PCM_32 :
+ case SF_FORMAT_FLOAT :
+ psf_log_printf (psf, "wav_w64_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, "wav_w64_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, "wav_w64_analyze : unhandled format : 0x%X\n", format) ;
+ break ;
+ } ;
+
+ return ;
+} /* wav_w64_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*
+wav_w64_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" ;
+} /* wav_w64_format_str */
+
+int
+wav_w64_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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 43c1b1dd-8abd-43da-a8cd-44da914b64a5
+*/
diff --git a/src/wav_w64.h b/src/wav_w64.h
new file mode 100644
index 0000000..bb738fd
--- /dev/null
+++ b/src/wav_w64.h
@@ -0,0 +1,293 @@
+/*
+** Copyright (C) 1999-2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 WAV_W64_H_INCLUDED
+#define WAV_W64_H_INCLUDED
+
+/*------------------------------------------------------------------------------
+** List of known WAV format tags
+*/
+
+enum
+{
+ /* keep sorted for wav_w64_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 int esf_field1 ;
+ unsigned short esf_field2 ;
+ unsigned short esf_field3 ;
+ 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 ;
+ WAV_FMT_SIZE20 size20 ;
+ char padding [512] ;
+} WAV_FMT ;
+
+typedef struct
+{ int frames ;
+} FACT_CHUNK ;
+
+typedef struct
+{ /* Set to true when 'fmt ' chunk is ambiguous.*/
+ int fmt_is_broken ;
+ WAV_FMT wav_fmt ;
+} WAV_PRIVATE ;
+
+#define WAV_W64_GSM610_BLOCKSIZE 65
+#define WAV_W64_GSM610_SAMPLES 320
+
+/*------------------------------------------------------------------------------------
+** Functions defined in wav_ms_adpcm.c
+*/
+
+#define MSADPCM_ADAPT_COEFF_COUNT 7
+
+void msadpcm_write_adapt_coeffs (SF_PRIVATE *psf) ;
+
+/*------------------------------------------------------------------------------------
+** Functions defined in wav_w64.c
+*/
+
+int wav_w64_srate2blocksize (int srate_chan_product) ;
+char const* wav_w64_format_str (int k) ;
+int wav_w64_read_fmt_chunk (SF_PRIVATE *psf, int fmtsize) ;
+void wavex_write_guid (SF_PRIVATE *psf, const EXT_SUBFORMAT * subformat) ;
+void wav_w64_analyze (SF_PRIVATE *psf) ;
+
+#endif
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 877fde12-9be3-4a31-8a5a-fdae39958613
+*/
diff --git a/src/wve.c b/src/wve.c
new file mode 100644
index 0000000..b4bde60
--- /dev/null
+++ b/src/wve.c
@@ -0,0 +1,209 @@
+/*
+** Copyright (C) 2002-2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+** 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 <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = wve_read_header (psf)))
+ return error ;
+ } ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != 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 [0] = 0 ;
+ psf->headindex = 0 ;
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ /* Write header. */
+ datalen = psf->datalength ;
+ psf_binheader_writef (psf, "Emmmm", ALAW_MARKER, SOUN_MARKER, DFIL_MARKER, ESSN_MARKER) ;
+ psf_binheader_writef (psf, "E2422222", PSION_VERSION, datalen, 0, 0, 0, 0, 0) ;
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->sf.channels != 1)
+ return SFE_CHANNEL_COUNT ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ if (current > 0)
+ psf_fseek (psf, current, SEEK_SET) ;
+
+ return psf->error ;
+} /* wve_write_header */
+
+/*------------------------------------------------------------------------------
+*/
+
+static int
+wve_close (SF_PRIVATE *psf)
+{
+ if (psf->mode == SFM_WRITE || psf->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/src/xi.c b/src/xi.c
new file mode 100644
index 0000000..a4b2715
--- /dev/null
+++ b/src/xi.c
@@ -0,0 +1,1200 @@
+/*
+** Copyright (C) 2003-2006 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sndfile.h"
+#include "sfendian.h"
+#include "common.h"
+#include "float_cast.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->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0))
+ { if ((error = xi_read_header (psf)))
+ return error ;
+ } ;
+
+ subformat = psf->sf.format & SF_FORMAT_SUBMASK ;
+
+ if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
+ { if ((psf->sf.format & SF_FORMAT_TYPEMASK) != 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 "-" VERSION " ", sizeof (pxi->software)) ;
+
+ memset (pxi->sample_name, 0, sizeof (pxi->sample_name)) ;
+ LSF_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->mode == SFM_READ || psf->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->mode == SFM_WRITE || psf->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)
+{ 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 ((psf->sf.format & SF_FORMAT_SUBMASK) == SF_FORMAT_DPCM_16)
+ { total = offset ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (total > 0)
+ { len = (total > bufferlen) ? bufferlen : total ;
+ total -= dpcm_read_dles2s (psf, psf->u.sbuf, len) ;
+ } ;
+ }
+ else
+ { total = offset ;
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+ while (total > 0)
+ { len = (total > bufferlen) ? bufferlen : total ;
+ total -= dpcm_read_dsc2s (psf, psf->u.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 [0] = 0 ;
+ psf->headindex = 0 ;
+ psf_fseek (psf, 0, SEEK_SET) ;
+
+ string = "Extended Instrument: " ;
+ psf_binheader_writef (psf, "b", string, strlen (string)) ;
+ psf_binheader_writef (psf, "b1", pxi->filename, sizeof (pxi->filename), 0x1A) ;
+
+ /* Write software version and two byte XI version. */
+ psf_binheader_writef (psf, "eb2", pxi->software, sizeof (pxi->software), (1 << 8) + 2) ;
+
+ /*
+ ** Jump note numbers (96), volume envelope (48), pan envelope (48),
+ ** volume points (1), pan points (1)
+ */
+ psf_binheader_writef (psf, "z", (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", (size_t) (4 * 3), 0x1234, make_size_t (22), 1) ;
+
+ pxi->loop_begin = 0 ;
+ pxi->loop_end = 0 ;
+
+ psf_binheader_writef (psf, "et844", psf->sf.frames, pxi->loop_begin, pxi->loop_end) ;
+
+ /* volume, fine tune, flags, pan, note, namelen */
+ psf_binheader_writef (psf, "111111", 128, 0, pxi->sample_flags, 128, 0, strlen (pxi->sample_name)) ;
+
+ psf_binheader_writef (psf, "b", pxi->sample_name, sizeof (pxi->sample_name)) ;
+
+
+
+
+
+ /* Header construction complete so write it out. */
+ psf_fwrite (psf->header, psf->headindex, 1, psf) ;
+
+ if (psf->error)
+ return psf->error ;
+
+ psf->dataoffset = psf->headindex ;
+
+ 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 ;
+ psf_log_printf (psf, "Extended Instrument : %s\n", buffer) ;
+
+ psf_binheader_readf (psf, "be2", buffer, 20, &version) ;
+ buffer [19] = 0 ;
+ psf_log_printf (psf, "Software : %s\nVersion : %d.%02d\n", buffer, version / 256, version % 256) ;
+
+ /* 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 ;
+
+ /* 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]) ;
+
+ 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->dataoffset = psf_fseek (psf, 0, SEEK_CUR) ;
+ psf_log_printf (psf, "Data Offset : %D\n", psf->dataoffset) ;
+
+ psf->datalength = sample_sizes [0] ;
+
+ 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->basenote = 0 ;
+ 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)
+{ XI_PRIVATE *pxi ;
+ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ if ((pxi = psf->codec_data) == NULL)
+ return 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ;
+ dsc2s_array (pxi, psf->u.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)
+{ XI_PRIVATE *pxi ;
+ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ if ((pxi = psf->codec_data) == NULL)
+ return 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ;
+ dsc2i_array (pxi, psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ;
+ dsc2f_array (pxi, psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.scbuf, sizeof (signed char), bufferlen, psf) ;
+ dsc2d_array (pxi, psf->u.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)
+{ XI_PRIVATE *pxi ;
+ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ if ((pxi = psf->codec_data) == NULL)
+ return 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ dles2s_array (pxi, psf->u.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)
+{ XI_PRIVATE *pxi ;
+ int bufferlen, readcount ;
+ sf_count_t total = 0 ;
+
+ if ((pxi = psf->codec_data) == NULL)
+ return 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ dles2i_array (pxi, psf->u.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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ dles2f_array (pxi, psf->u.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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ readcount = psf_fread (psf->u.sbuf, sizeof (short), bufferlen, psf) ;
+ dles2d_array (pxi, psf->u.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)
+{ XI_PRIVATE *pxi ;
+ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ if ((pxi = psf->codec_data) == NULL)
+ return 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2dsc_array (pxi, ptr + total, psf->u.scbuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ XI_PRIVATE *pxi ;
+ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ if ((pxi = psf->codec_data) == NULL)
+ return 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2dsc_array (pxi, ptr + total, psf->u.scbuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ f2dsc_array (pxi, ptr + total, psf->u.scbuf, bufferlen, normfact) ;
+ writecount = psf_fwrite (psf->u.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)
+{ 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 (psf->u.ucbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ d2dsc_array (pxi, ptr + total, psf->u.scbuf, bufferlen, normfact) ;
+ writecount = psf_fwrite (psf->u.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)
+{ XI_PRIVATE *pxi ;
+ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ if ((pxi = psf->codec_data) == NULL)
+ return 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ s2dles_array (pxi, ptr + total, psf->u.sbuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ XI_PRIVATE *pxi ;
+ int bufferlen, writecount ;
+ sf_count_t total = 0 ;
+
+ if ((pxi = psf->codec_data) == NULL)
+ return 0 ;
+
+ bufferlen = ARRAY_LEN (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ i2dles_array (pxi, ptr + total, psf->u.sbuf, bufferlen) ;
+ writecount = psf_fwrite (psf->u.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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ f2dles_array (pxi, ptr + total, psf->u.sbuf, bufferlen, normfact) ;
+ writecount = psf_fwrite (psf->u.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)
+{ 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 (psf->u.sbuf) ;
+
+ while (len > 0)
+ { if (len < bufferlen)
+ bufferlen = (int) len ;
+ d2dles_array (pxi, ptr + total, psf->u.sbuf, bufferlen, normfact) ;
+ writecount = psf_fwrite (psf->u.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] = last_val << 8 ;
+ } ;
+
+ pxi->last_16 = 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] = last_val << 24 ;
+ } ;
+
+ pxi->last_16 = 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 = 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 = 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 = 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 = 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 = lrintf (src [k] * normfact) ;
+ dest [k] = current - last_val ;
+ last_val = current ;
+ } ;
+
+ pxi->last_16 = 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 = lrint (src [k] * normfact) ;
+ dest [k] = current - last_val ;
+ last_val = current ;
+ } ;
+
+ pxi->last_16 = 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 += LES2H_SHORT (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 += LES2H_SHORT (src [k]) ;
+ dest [k] = 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 += LES2H_SHORT (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 += LES2H_SHORT (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] = LES2H_SHORT (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] = LES2H_SHORT (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 = lrintf (src [k] * normfact) ;
+ diff = current - last_val ;
+ dest [k] = LES2H_SHORT (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 = lrint (src [k] * normfact) ;
+ diff = current - last_val ;
+ dest [k] = LES2H_SHORT (diff) ;
+ last_val = current ;
+ } ;
+
+ pxi->last_16 = last_val ;
+} /* d2dles_array */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 1ab2dbe0-29af-4d80-9c6f-cb21b67521bc
+*/
diff --git a/tests/Makefile.am b/tests/Makefile.am
new file mode 100644
index 0000000..4be379f
--- /dev/null
+++ b/tests/Makefile.am
@@ -0,0 +1,412 @@
+## Process this file with automake to produce Makefile.in
+
+if ENABLE_TEST_COVERAGE
+CPP_TEST =
+else
+CPP_TEST = cpp_test
+endif
+
+noinst_PROGRAMS = sfversion floating_point_test write_read_test \
+ lossy_comp_test error_test ulaw_test alaw_test dwvw_test \
+ peak_chunk_test command_test stdin_test stdout_test stdio_test \
+ pcm_test headerless_test pipe_test benchmark header_test misc_test \
+ raw_test string_test open_fail_test multi_file_test dither_test \
+ scale_clip_test win32_test fix_this aiff_rw_test virtual_io_test \
+ locale_test largefile_test win32_ordinal_test $(CPP_TEST)
+
+SNDFILEDIR = ../src
+INCLUDES = -I$(srcdir)/$(SNDFILEDIR)
+noinst_HEADERS = dft_cmp.h utils.h
+
+autogen_sources = write_read_test.tpl write_read_test.def \
+ pcm_test.tpl pcm_test.def \
+ header_test.tpl header_test.def \
+ utils.tpl utils.def \
+ scale_clip_test.tpl scale_clip_test.def \
+ pipe_test.tpl pipe_test.def \
+ floating_point_test.tpl floating_point_test.def \
+ benchmark.tpl benchmark.def
+
+EXTRA_DIST = $(autogen_sources)
+
+#===============================================================================
+
+sfversion_SOURCES = sfversion.c
+sfversion_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+write_read_test_SOURCES = utils.c write_read_test.c
+write_read_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+lossy_comp_test_SOURCES = utils.c lossy_comp_test.c
+lossy_comp_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+fix_this_SOURCES = utils.c fix_this.c
+fix_this_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+error_test_SOURCES = error_test.c utils.c
+error_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+ulaw_test_SOURCES = utils.c ulaw_test.c
+ulaw_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+alaw_test_SOURCES = utils.c alaw_test.c
+alaw_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+aiff_rw_test_SOURCES = utils.c aiff_rw_test.c
+aiff_rw_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+command_test_SOURCES = command_test.c utils.c
+command_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+locale_test_SOURCES = locale_test.c utils.c
+locale_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+largefile_test_SOURCES = largefile_test.c utils.c
+largefile_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+pcm_test_SOURCES = pcm_test.c utils.c
+pcm_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+headerless_test_SOURCES = utils.c headerless_test.c
+headerless_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+stdin_test_SOURCES = stdin_test.c utils.c
+stdin_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+stdout_test_SOURCES = stdout_test.c
+stdout_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+stdio_test_SOURCES = stdio_test.c utils.c
+stdio_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+pipe_test_SOURCES = pipe_test.c utils.c
+pipe_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+benchmark_SOURCES = benchmark.c
+benchmark_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+header_test_SOURCES = header_test.c utils.c
+header_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+misc_test_SOURCES = misc_test.c utils.c
+misc_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+raw_test_SOURCES = raw_test.c utils.c
+raw_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+string_test_SOURCES = string_test.c utils.c
+string_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+dither_test_SOURCES = dither_test.c utils.c
+dither_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+open_fail_test_SOURCES = open_fail_test.c utils.c
+open_fail_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+multi_file_test_SOURCES = multi_file_test.c utils.c
+multi_file_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+virtual_io_test_SOURCES = virtual_io_test.c utils.c
+virtual_io_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+win32_test_SOURCES = win32_test.c
+win32_test_LDADD =
+
+win32_ordinal_test_SOURCES = win32_ordinal_test.c utils.c
+win32_ordinal_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+cpp_test_SOURCES = cpp_test.cc utils.c
+cpp_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+# Lite remove start
+dwvw_test_SOURCES = utils.c dwvw_test.c
+dwvw_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+floating_point_test_SOURCES = utils.c dft_cmp.c floating_point_test.c
+floating_point_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+peak_chunk_test_SOURCES = peak_chunk_test.c utils.c
+peak_chunk_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+
+scale_clip_test_SOURCES = scale_clip_test.c utils.c
+scale_clip_test_LDADD = $(SNDFILEDIR)/libsndfile.la
+# Lite remove end
+
+#===============================================================================
+
+write_read_test.c: write_read_test.def write_read_test.tpl
+ autogen --writable write_read_test.def
+
+pcm_test.c: pcm_test.def pcm_test.tpl
+ autogen --writable pcm_test.def
+
+header_test.c: header_test.def header_test.tpl
+ autogen --writable header_test.def
+
+utils.c: utils.def utils.tpl
+ autogen --writable utils.def
+
+scale_clip_test.c: scale_clip_test.def scale_clip_test.tpl
+ autogen --writable scale_clip_test.def
+
+pipe_test.c: pipe_test.def pipe_test.tpl
+ autogen --writable pipe_test.def
+
+floating_point_test.c: floating_point_test.def floating_point_test.tpl
+ autogen --writable floating_point_test.def
+
+benchmark.c: benchmark.def benchmark.tpl
+ autogen --writable benchmark.def
+
+genfiles : write_read_test.c pcm_test.c header_test.c utils.c \
+ scale_clip_test.c pipe_test.c floating_point_test.c benchmark.c
+
+#===============================================================================
+
+check: generic-tests wav-tests aiff-tests au-tests caf-tests raw-tests \
+ paf-tests svx-tests nist-tests ircam-tests voc-tests w64-tests mat4-tests \
+ mat5-tests pvf-tests xi-tests htk-tests avr-tests sds-tests sd2-tests \
+ flac-tests caf-tests wve-tests io-tests
+
+generic-tests : error_test ulaw_test alaw_test command_test floating_point_test \
+ pcm_test win32_ordinal_test $(CPP_TEST)
+ uname -a
+ ./error_test
+ ./pcm_test
+ ./ulaw_test
+ ./alaw_test
+ ./dwvw_test
+ ./command_test ver
+ ./command_test norm
+ ./command_test format
+ ./command_test peak
+ ./command_test trunc
+ ./command_test inst
+ ./command_test bext
+ ./floating_point_test
+ ./scale_clip_test
+ ./headerless_test
+ ./locale_test
+ ./win32_ordinal_test
+if ENABLE_TEST_COVERAGE
+ @echo "cpp_test not under test coverage"
+else
+ ./cpp_test
+endif
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed common tests."
+ @echo "----------------------------------------------------------------------"
+
+wav-tests: write_read_test lossy_comp_test peak_chunk_test header_test misc_test multi_file_test
+ ./write_read_test wav
+ ./lossy_comp_test wav_ima
+ ./lossy_comp_test wav_msadpcm
+ ./lossy_comp_test wav_ulaw
+ ./lossy_comp_test wav_alaw
+ ./lossy_comp_test wav_gsm610
+ ./lossy_comp_test wav_g721
+ ./peak_chunk_test wav
+ ./header_test wav
+ ./misc_test wav
+ ./string_test wav
+ ./multi_file_test wav
+ ./open_fail_test wav
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on WAV files."
+ @echo "----------------------------------------------------------------------"
+
+aiff-tests: write_read_test lossy_comp_test peak_chunk_test header_test misc_test aiff_rw_test
+ ./write_read_test aiff
+ ./lossy_comp_test aiff_ulaw
+ ./lossy_comp_test aiff_alaw
+ ./lossy_comp_test aiff_gsm610
+ @echo "=========================="
+ @echo "./lossy_comp_test aiff_ima"
+ @echo "=========================="
+ ./peak_chunk_test aiff
+ ./header_test aiff
+ ./misc_test aiff
+ ./string_test aiff
+ ./multi_file_test aiff
+ ./aiff_rw_test
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on AIFF files."
+ @echo "----------------------------------------------------------------------"
+
+caf-tests: write_read_test lossy_comp_test header_test misc_test
+ ./write_read_test caf
+ ./lossy_comp_test caf_ulaw
+ ./lossy_comp_test caf_alaw
+ ./header_test caf
+ ./misc_test caf
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on CAF files."
+ @echo "----------------------------------------------------------------------"
+
+au-tests: write_read_test lossy_comp_test header_test misc_test
+ ./write_read_test au
+ ./lossy_comp_test au_ulaw
+ ./lossy_comp_test au_alaw
+ ./lossy_comp_test au_g721
+ ./lossy_comp_test au_g723
+ ./header_test au
+ ./misc_test au
+ ./multi_file_test wav
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on AU files."
+ @echo "----------------------------------------------------------------------"
+
+raw-tests: write_read_test lossy_comp_test raw_test
+ ./write_read_test raw
+ ./lossy_comp_test raw_ulaw
+ ./lossy_comp_test raw_alaw
+ ./lossy_comp_test raw_gsm610
+ ./lossy_comp_test vox_adpcm
+ ./raw_test
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on RAW (header-less) files."
+ @echo "----------------------------------------------------------------------"
+
+w64-tests: write_read_test lossy_comp_test misc_test
+ ./write_read_test w64
+ ./lossy_comp_test w64_ima
+ ./lossy_comp_test w64_msadpcm
+ ./lossy_comp_test w64_ulaw
+ ./lossy_comp_test w64_alaw
+ ./lossy_comp_test w64_gsm610
+ ./header_test w64
+ ./misc_test w64
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on W64 files."
+ @echo "----------------------------------------------------------------------"
+
+wve-tests: lossy_comp_test
+ ./lossy_comp_test wve
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on WVE files."
+ @echo "----------------------------------------------------------------------"
+
+# Lite remove start
+paf-tests: write_read_test misc_test
+ ./write_read_test paf
+ ./header_test paf
+ ./misc_test paf
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on PAF files."
+ @echo "----------------------------------------------------------------------"
+
+svx-tests: write_read_test misc_test
+ ./write_read_test svx
+ ./header_test svx
+ ./misc_test svx
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on SVX files."
+ @echo "----------------------------------------------------------------------"
+
+nist-tests: write_read_test lossy_comp_test misc_test
+ ./write_read_test nist
+ ./lossy_comp_test nist_ulaw
+ ./lossy_comp_test nist_alaw
+ ./header_test nist
+ ./misc_test nist
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on NIST files."
+ @echo "----------------------------------------------------------------------"
+
+ircam-tests: write_read_test lossy_comp_test misc_test
+ ./write_read_test ircam
+ ./lossy_comp_test ircam_ulaw
+ ./lossy_comp_test ircam_alaw
+ ./header_test ircam
+ ./misc_test ircam
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on IRCAM files."
+ @echo "----------------------------------------------------------------------"
+
+voc-tests: write_read_test lossy_comp_test misc_test
+ ./write_read_test voc
+ ./lossy_comp_test voc_ulaw
+ ./lossy_comp_test voc_alaw
+ ./header_test voc
+ ./misc_test voc
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on VOC files."
+ @echo "----------------------------------------------------------------------"
+
+mat4-tests: write_read_test misc_test
+ ./write_read_test mat4
+ ./header_test mat4
+ ./misc_test mat4
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on MAT4 files."
+ @echo "----------------------------------------------------------------------"
+
+mat5-tests: write_read_test misc_test
+ ./write_read_test mat5
+ ./header_test mat5
+ ./misc_test mat5
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on MAT5 files."
+ @echo "----------------------------------------------------------------------"
+
+pvf-tests: write_read_test misc_test
+ ./write_read_test pvf
+ ./header_test pvf
+ ./misc_test pvf
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on PVF files."
+ @echo "----------------------------------------------------------------------"
+
+xi-tests: lossy_comp_test
+ ./lossy_comp_test xi_dpcm
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on XI files."
+ @echo "----------------------------------------------------------------------"
+
+htk-tests: write_read_test misc_test
+ ./write_read_test htk
+ ./header_test htk
+ ./misc_test htk
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on HTK files."
+ @echo "----------------------------------------------------------------------"
+
+avr-tests: write_read_test misc_test
+ ./write_read_test avr
+ ./header_test avr
+ ./misc_test avr
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on AVR files."
+ @echo "----------------------------------------------------------------------"
+
+sds-tests: write_read_test misc_test
+ ./write_read_test sds
+ ./header_test sds
+ ./misc_test sds
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on SDS files."
+ @echo "----------------------------------------------------------------------"
+
+sd2-tests: write_read_test
+ ./write_read_test sd2
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on SD2 files."
+ @echo "----------------------------------------------------------------------"
+
+flac-tests: write_read_test
+ ./write_read_test flac
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed tests on FLAC files."
+ @echo "----------------------------------------------------------------------"
+
+# Lite remove end
+
+io-tests: stdio_test stdin_test stdout_test pipe_test
+ ./stdio_test
+ ./pipe_test
+ ./virtual_io_test
+ @echo "----------------------------------------------------------------------"
+ @echo " `./sfversion` passed stdio/pipe/vio tests."
+ @echo "----------------------------------------------------------------------"
+
+
diff --git a/tests/aiff_rw_test.c b/tests/aiff_rw_test.c
new file mode 100644
index 0000000..b15707d
--- /dev/null
+++ b/tests/aiff_rw_test.c
@@ -0,0 +1,169 @@
+/*
+** Copyright (C) 2003,2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <sndfile.h>
+
+#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 : channel count 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 (%ld != %ld).\n\n", __LINE__,
+ SF_COUNT_TO_LONG (sfinfo_rd.frames), SF_COUNT_TO_LONG (sfinfo_rw.frames)) ;
+ exit (1) ;
+ } ;
+
+ return ;
+} /* rw_test */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 12561248-1ad1-4ba6-941c-029f1333c080
+*/
diff --git a/tests/alaw_test.c b/tests/alaw_test.c
new file mode 100644
index 0000000..2c0788b
--- /dev/null
+++ b/tests/alaw_test.c
@@ -0,0 +1,250 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#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 ;
+
+ filename = "test.raw" ;
+
+ sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_ALAW ;
+ sfinfo.samplerate = 44100 ;
+ sfinfo.frames = 123456789 ; /* Wrong length. Library should correct this on sf_close. */
+ sfinfo.channels = 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) ;
+
+ printf (" alaw_test : encoder ... ok\n") ;
+
+ /* 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) ;
+
+ printf (" alaw_test : decoder ... ok\n") ;
+
+ 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 */
+
+
+
+
+
+
+
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: d3fb5eae-b3a4-4c5b-90ab-e3daa64c4a57
+*/
diff --git a/tests/benchmark-0.0.28 b/tests/benchmark-0.0.28
new file mode 100644
index 0000000..2d2b06f
--- /dev/null
+++ b/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/tests/benchmark-1.0.0 b/tests/benchmark-1.0.0
new file mode 100644
index 0000000..2922836
--- /dev/null
+++ b/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/tests/benchmark-1.0.0rc2 b/tests/benchmark-1.0.0rc2
new file mode 100644
index 0000000..7702246
--- /dev/null
+++ b/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/tests/benchmark-1.0.6pre10-coltrane b/tests/benchmark-1.0.6pre10-coltrane
new file mode 100644
index 0000000..12f71a8
--- /dev/null
+++ b/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/tests/benchmark-1.0.6pre10-miles b/tests/benchmark-1.0.6pre10-miles
new file mode 100644
index 0000000..fffdb84
--- /dev/null
+++ b/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/tests/benchmark-latest-coltrane b/tests/benchmark-latest-coltrane
new file mode 100644
index 0000000..97ce29a
--- /dev/null
+++ b/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/tests/benchmark.def b/tests/benchmark.def
new file mode 100644
index 0000000..5702d6b
--- /dev/null
+++ b/tests/benchmark.def
@@ -0,0 +1,25 @@
+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" ;
+ };
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 5cadd2d0-dd74-4067-9d75-781a36d6bf15
+*/
+
diff --git a/tests/benchmark.tpl b/tests/benchmark.tpl
new file mode 100644
index 0000000..d5961c9
--- /dev/null
+++ b/tests/benchmark.tpl
@@ -0,0 +1,361 @@
+[+ AutoGen5 template c +]
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if (HAVE_DECL_S_IRGRP == 0)
+#include <sf_unistd.h>
+#endif
+
+#include <string.h>
+#include <math.h>
+#include <time.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <sndfile.h>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846264338
+#endif
+
+#if (defined (WIN32) || defined (_WIN32))
+ #define WRITE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC | O_BINARY)
+ #define READ_FLAGS (O_RDONLY | O_BINARY)
+ #define WRITE_PERMS 0777
+#else
+ #define WRITE_FLAGS (O_WRONLY | O_CREAT | O_TRUNC)
+ #define READ_FLAGS (O_RDONLY)
+ #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 */
+
+[+ COMMENT
+
+ Do not edit or modify anything in this comment block.
+ The following line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 64ccb3fb-c61d-42d7-b14f-0ec3ba303f88
+
++]
diff --git a/tests/command_test.c b/tests/command_test.c
new file mode 100644
index 0000000..357a713
--- /dev/null
+++ b/tests/command_test.c
@@ -0,0 +1,880 @@
+/*
+** Copyright (C) 2001-2006 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <math.h>
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+#define BUFFER_LEN (1<<10)
+#define LOG_BUFFER_SIZE 1024
+
+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) ;
+static void truncate_test (const char *filename, int filetype) ;
+static void instrument_test (const char *filename, int filetype) ;
+static void channel_map_test (const char *filename, int filetype) ;
+static void broadcast_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 <test>\n", argv [0]) ;
+ printf (" Where <test> 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 (" chanmap - test set/get of channel map data..\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] ;
+ 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) ;
+ } ;
+ 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 ("float.wav") ;
+ double_norm_test ("double.wav") ;
+ test_count++ ;
+ } ;
+
+ if (do_all || strcmp (argv [1], "peak") == 0)
+ { calc_peak_test (SF_ENDIAN_BIG | SF_FORMAT_RAW, "be-peak.raw") ;
+ calc_peak_test (SF_ENDIAN_LITTLE | SF_FORMAT_RAW, "le-peak.raw") ;
+ 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], "chanmap") == 0)
+ { channel_map_test ("chanmap.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;
+ channel_map_test ("chanmap.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], "bext") == 0)
+ { broadcast_test ("broadcast.wav", SF_FORMAT_WAV | 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
+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.0 * BUFFER_LEN) ;
+ for (k = BUFFER_LEN / 2 ; k < BUFFER_LEN ; k++)
+ float_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) ;
+ } ;
+
+ /* Normalisation is on by default so no need to do anything here. */
+
+ if ((k = 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 = 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 => %ld)\n", __LINE__, BUFFER_LEN, SF_COUNT_TO_LONG (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 = 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 = 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 = 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 = 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 = 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 => %ld)\n", __LINE__, BUFFER_LEN, SF_COUNT_TO_LONG (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 = 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 = 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 = 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 > 30)
+ { 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)
+{ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ int k, format ;
+ double peak ;
+
+ print_test_name ("calc_peak_test", filename) ;
+
+ format = (filetype | SF_FORMAT_PCM_16) ;
+
+ sfinfo.samplerate = 44100 ;
+ sfinfo.format = format ;
+ sfinfo.channels = 1 ;
+ sfinfo.frames = BUFFER_LEN ;
+
+ /* 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_write_double_or_die (file, 0, double_data, BUFFER_LEN, __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 != BUFFER_LEN)
+ { printf ("\n\nLine %d: Incorrect number of.frames in file. (%d => %ld)\n", __LINE__, BUFFER_LEN, SF_COUNT_TO_LONG (sfinfo.frames)) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.channels != 1)
+ { 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 = 1 ;
+ sfinfo.frames = BUFFER_LEN ;
+
+ /* 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_write_double_or_die (file, 0, double_data, BUFFER_LEN, __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 != BUFFER_LEN)
+ { printf ("\n\nLine %d: Incorrect number of.frames in file. (%d => %ld)\n", __LINE__, BUFFER_LEN, SF_COUNT_TO_LONG (sfinfo.frames)) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.channels != 1)
+ { 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
+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.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 ((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) ;
+ } ;
+
+ unlink (filename) ;
+ puts ("ok") ;
+} /* instrument_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) ;
+
+ 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_SET_BROADCAST_INFO) failed.\n\n", __LINE__) ;
+ exit (1) ;
+ return ;
+ } ;
+ check_log_buffer_or_die (file, __LINE__) ;
+ sf_close (file) ;
+
+ if (bc_read.version != 1)
+ { 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
+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_FRONT_LEFT, SF_CHANNEL_MAP_FRONT_CENTER,
+ SF_CHANNEL_MAP_REAR_LEFT, SF_CHANNEL_MAP_REAR_RIGHT
+ } ;
+
+ 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) ;
+
+ /* 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 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_FALSE,
+ "\n\nLine %d : sf_command (SFC_GET_CHANNEL_MAP_INFO) should have failed.\n\n", __LINE__
+ ) ;
+ check_log_buffer_or_die (file, __LINE__) ;
+ sf_close (file) ;
+
+ /* Write file with a 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__) ;
+ 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__
+ ) ;
+ 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 */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The following line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 59e5d452-8dae-45aa-99aa-b78dc0deba1c
+*/
diff --git a/tests/cpp_crack_test.cc b/tests/cpp_crack_test.cc
new file mode 100644
index 0000000..0115ebb
--- /dev/null
+++ b/tests/cpp_crack_test.cc
@@ -0,0 +1,144 @@
+/*
+** Copyright (C) 2006 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+
+#include <sndfile.hh>
+
+#include "utils.h"
+
+static short sbuffer [100] ;
+static int ibuffer [100] ;
+static float fbuffer [100] ;
+static double dbuffer [100] ;
+
+static void
+create_file (const std::string& filename, int format)
+{ Sndfile::Handle file (filename, SFM_WRITE, format, 2, 48000) ;
+
+ setString (file, SF_STR_TITLE, filename) ;
+
+ /* Item write. */
+ write (file, sbuffer, ARRAY_LEN (sbuffer)) ;
+ write (file, ibuffer, ARRAY_LEN (ibuffer)) ;
+ write (file, fbuffer, ARRAY_LEN (fbuffer)) ;
+ write (file, dbuffer, ARRAY_LEN (dbuffer)) ;
+
+ /* Frame write. */
+ writef (file, sbuffer, ARRAY_LEN (sbuffer) / channels (file)) ;
+ writef (file, ibuffer, ARRAY_LEN (ibuffer) / channels (file)) ;
+ writef (file, fbuffer, ARRAY_LEN (fbuffer) / channels (file)) ;
+ writef (file, dbuffer, ARRAY_LEN (dbuffer) / channels (file)) ;
+
+ /*
+ ** An explicit close() call is not necessary as the
+ ** Sndfile::Handle destructor closes the file anyway.
+ */
+} /* create_file */
+
+static void
+read_file (const std::string& filename, int frmt)
+{ Sndfile::Handle file ;
+ std::string title ;
+ sf_count_t count ;
+
+ file = Sndfile::open (filename) ;
+
+ if (format (file) != frmt)
+ { printf ("\n\n%s %d : Error : format 0x%08x should be 0x%08x.\n\n", __func__, __LINE__, format (file), frmt) ;
+ exit (1) ;
+ } ;
+
+ if (channels (file) != 2)
+ { printf ("\n\n%s %d : Error : channels %d should be 2.\n\n", __func__, __LINE__, channels (file)) ;
+ exit (1) ;
+ } ;
+
+ if (frames (file) != ARRAY_LEN (sbuffer) * 4)
+ { printf ("\n\n%s %d : Error : frames %ld should be %d.\n\n", __func__, __LINE__,
+ SF_COUNT_TO_LONG (frames (file)), ARRAY_LEN (sbuffer) * 4 / 2) ;
+ exit (1) ;
+ } ;
+
+ title = getString (file, SF_STR_TITLE) ;
+
+ if (title == "")
+ { printf ("\n\n%s %d : Error : No title.\n\n", __func__, __LINE__) ;
+ exit (1) ;
+ } ;
+
+ if (filename != title)
+ { printf ("\n\n%s %d : Error : title '%s' should be '%s'\n\n", __func__, __LINE__, title.c_str(), filename.c_str()) ;
+ exit (1) ;
+ } ;
+
+ /* Item read. */
+ read (file, sbuffer, ARRAY_LEN (sbuffer)) ;
+ read (file, ibuffer, ARRAY_LEN (ibuffer)) ;
+ read (file, fbuffer, ARRAY_LEN (fbuffer)) ;
+ read (file, dbuffer, ARRAY_LEN (dbuffer)) ;
+
+ /* Frame read. */
+ readf (file, sbuffer, ARRAY_LEN (sbuffer) / channels (file)) ;
+ readf (file, ibuffer, ARRAY_LEN (ibuffer) / channels (file)) ;
+ readf (file, fbuffer, ARRAY_LEN (fbuffer) / channels (file)) ;
+ readf (file, dbuffer, ARRAY_LEN (dbuffer) / channels (file)) ;
+
+ count = seek (file, frames (file) - 10, SEEK_SET) ;
+ if (count != frames (file) - 10)
+ { printf ("\n\n%s %d : Error : offset (%ld) should be %ld\n\n", __func__, __LINE__,
+ SF_COUNT_TO_LONG (count), SF_COUNT_TO_LONG (frames (file) - 10)) ;
+ exit (1) ;
+ } ;
+
+ count = read (file, sbuffer, ARRAY_LEN (sbuffer)) ;
+ if (count != 10 * channels (file))
+ { printf ("\n\n%s %d : Error : count (%ld) should be %ld\n\n", __func__, __LINE__,
+ SF_COUNT_TO_LONG (count), SF_COUNT_TO_LONG (10 * channels (file))) ;
+ exit (1) ;
+ } ;
+
+ /*
+ ** An explicit close() call is not necessary as the
+ ** Sndfile::Handle destructor closes the file anyway.
+ */
+} /* create_file */
+
+int
+main (void)
+{ const char * filename = "cpp_test.wav" ;
+
+ print_test_name ("CeePlusPlus test", filename) ;
+
+ create_file (filename, SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;
+ read_file (filename, SF_FORMAT_WAV | SF_FORMAT_PCM_16) ;
+
+ remove (filename) ;
+ puts ("ok") ;
+ return 0 ;
+} /* main */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The following line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 9600906c-fd77-4fdd-a25e-c21a1776ef1f
+*/
diff --git a/tests/cpp_test.cc b/tests/cpp_test.cc
new file mode 100644
index 0000000..9108aa1
--- /dev/null
+++ b/tests/cpp_test.cc
@@ -0,0 +1,197 @@
+/*
+** Copyright (C) 2006 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include <sndfile.hh>
+
+#include "utils.h"
+
+static short sbuffer [100] ;
+static int ibuffer [100] ;
+static float fbuffer [100] ;
+static double dbuffer [100] ;
+
+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.\n\n", __func__, __LINE__) ;
+ 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__,
+ SF_COUNT_TO_LONG (file.frames ()), (long unsigned int) 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__,
+ SF_COUNT_TO_LONG (count), SF_COUNT_TO_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__,
+ SF_COUNT_TO_LONG (count), SF_COUNT_TO_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 */
+
+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) ;
+
+ return 0 ;
+} /* main */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The following line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 06e48ee6-b19d-4453-9999-a5cf2d7bf0b6
+*/
diff --git a/tests/dft_cmp.c b/tests/dft_cmp.c
new file mode 100644
index 0000000..cf80338
--- /dev/null
+++ b/tests/dft_cmp.c
@@ -0,0 +1,137 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#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 (double *spec1, double *spec2) ;
+
+/*--------------------------------------------------------------------------------
+** Public functions.
+*/
+
+double
+dft_cmp (int linenum, double *orig, 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 : Bad input arrays.\n", linenum) ;
+ return 1 ;
+ } ;
+
+ if (len != DFT_DATA_LENGTH)
+ { printf ("Error (line % d) : dft_cmp : 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 */
+
+/*--------------------------------------------------------------------------------
+** 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 [k] = 0.0 ;
+
+ spectrum [0] = spectrum [1] = spectrum [2] = spectrum [3] = spectrum [4] = 0.0 ;
+
+ return ;
+} /* dft_magnitude */
+
+static double
+calc_max_spectral_difference (double *orig, 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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: cba7ffe2-bafe-44bd-b57a-15def3408410
+*/
diff --git a/tests/dft_cmp.h b/tests/dft_cmp.h
new file mode 100644
index 0000000..1fb63c5
--- /dev/null
+++ b/tests/dft_cmp.h
@@ -0,0 +1,30 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+
+#define DFT_DATA_LENGTH (2048)
+
+double dft_cmp (int linenum, double *orig, double *test, int len, double tolerance, int allow_exit) ;
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 10eac7b2-04ef-4d86-b7c0-8f1de57b12a0
+*/
diff --git a/tests/dither_test.c b/tests/dither_test.c
new file mode 100644
index 0000000..5aae372
--- /dev/null
+++ b/tests/dither_test.c
@@ -0,0 +1,192 @@
+/*
+** Copyright (C) 2003,2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <math.h>
+
+#include <sndfile.h>
+
+#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 <test>\n", argv [0]) ;
+ printf (" Where <test> 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 ;
+ int frames ;
+
+ filetype = filetype ;
+
+ print_test_name ("dither_test", filename) ;
+
+ sfinfo.samplerate = 44100 ;
+ sfinfo.format = filetype ;
+ sfinfo.channels = 1 ;
+ sfinfo.frames = 0 ;
+
+ frames = BUFFER_LEN / sfinfo.channels ;
+
+ 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: ad688dd9-5211-48ef-b82d-089eafb1e7ad
+*/
diff --git a/tests/dwvw_test.c b/tests/dwvw_test.c
new file mode 100644
index 0000000..a4d9d15
--- /dev/null
+++ b/tests/dwvw_test.c
@@ -0,0 +1,119 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <float_cast.h>
+
+#include <sndfile.h>
+
+#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 = (-1 << (32 - bit_width)) ;
+
+ print_test_name ("dwvw_test", filename) ;
+
+ sfinfo.format = format ;
+ sfinfo.samplerate = 44100 ;
+ sfinfo.frames = -1 ; /* Unknown! */
+ sfinfo.channels = 1 ;
+
+ file = test_open_file_or_die (filename, SFM_WRITE, &sfinfo, SF_TRUE, __LINE__) ;
+
+ /* Generate random.frames. */
+ k = 0 ;
+ 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 & ((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 = 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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 9e7731c3-43cd-4de5-b539-1ce6fa11d937
+*/
diff --git a/tests/error_test.c b/tests/error_test.c
new file mode 100644
index 0000000..a2c696a
--- /dev/null
+++ b/tests/error_test.c
@@ -0,0 +1,113 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+#define BUFFER_SIZE (1<<15)
+#define SHORT_BUFFER (256)
+
+static void error_number_test (void) ;
+static void error_value_test (void) ;
+
+int
+main (void)
+{ error_number_test () ;
+ error_value_test () ;
+
+ return 0 ;
+} /* main */
+
+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."))
+ 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)) ;
+
+ 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 799eba74-b505-49d9-89a6-22a7f51a31b4
+*/
diff --git a/tests/fix_this.c b/tests/fix_this.c
new file mode 100644
index 0000000..c0575a5
--- /dev/null
+++ b/tests/fix_this.c
@@ -0,0 +1,331 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+#define BUFFER_SIZE (1<<14) /* Should be (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, sum_abs ;
+ long datalen, seekpos ;
+ 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 (%ld => %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. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (sfinfo.frames)) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.frames > (datalen + datalen / 2))
+ { printf ("Too many.frames in file. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (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 %ld).\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 (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 (%ld should be %d).\n", __LINE__, SF_COUNT_TO_LONG (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++)
+ { 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 (m = 0 ; m < 1 ; m++)
+ printf ("%d ", data [m]) ;
+ 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 + %ld 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 %ld)\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, %ld).\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, %ld).\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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 368e2777-2848-4e16-a77f-4db841377c73
+*/
diff --git a/tests/floating_point_test.def b/tests/floating_point_test.def
new file mode 100644
index 0000000..9104643
--- /dev/null
+++ b/tests/floating_point_test.def
@@ -0,0 +1,40 @@
+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 ;
+ } ;
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 053997cb-74d9-424e-aabf-3ad7622e3eee
+*/
+
diff --git a/tests/floating_point_test.tpl b/tests/floating_point_test.tpl
new file mode 100644
index 0000000..c6ad2b1
--- /dev/null
+++ b/tests/floating_point_test.tpl
@@ -0,0 +1,347 @@
+[+ AutoGen5 template c +]
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#include "dft_cmp.h"
+#include "utils.h"
+
+#include "float_cast.h"
+
+#define SAMPLE_RATE 16000
+
+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) ;
+[+ ENDFOR endian_type +][+ ENDFOR int_type +][+ ENDFOR float_type
++]
+
+static double double_data [DFT_DATA_LENGTH] ;
+static double test_data [DFT_DATA_LENGTH] ;
+
+static float float_data [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) && (HAVE_LRINT_REPLACEMENT == 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, -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, -34.0) ;
+ float_scaled_test ("g723_24.au", allow_exit, SF_FALSE, SF_FORMAT_AU | SF_FORMAT_G723_24, -34.0) ;
+ 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, -90.0) ;
+ float_scaled_test ("pcm_16.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_16, -140.0) ;
+ float_scaled_test ("pcm_24.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_24, -170.0) ;
+
+ 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 ("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, -300.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, -34.0) ;
+ double_scaled_test ("g723_24.au", allow_exit, SF_FALSE, SF_FORMAT_AU | SF_FORMAT_G723_24, -34.0) ;
+ 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 , -42.0) ;
+
+ double_scaled_test ("pcm_s8.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_S8, -90.0) ;
+ double_scaled_test ("pcm_16.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_16, -140.0) ;
+ double_scaled_test ("pcm_24.sds", allow_exit, SF_FALSE, SF_FORMAT_SDS | SF_FORMAT_PCM_24, -180.0) ;
+
+ 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 ("replace_double.raw", allow_exit, SF_TRUE, SF_FORMAT_RAW | SF_FORMAT_DOUBLE, -300.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") ;
+[+ 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)
+{ static float float_orig [DFT_DATA_LENGTH] ;
+ static float float_test [DFT_DATA_LENGTH] ;
+
+ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ int k ;
+ double snr ;
+
+ print_test_name ("float_scaled_test", filename) ;
+
+ gen_windowed_sine_double (double_data, DFT_DATA_LENGTH, 1.0) ;
+
+ for (k = 0 ; k < DFT_DATA_LENGTH ; k++)
+ float_orig [k] = double_data [k] ;
+
+ 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_orig, 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). (%ld should be %d)\n", __LINE__, SF_COUNT_TO_LONG (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__) ;
+
+ sf_close (file) ;
+
+ for (k = 0 ; k < DFT_DATA_LENGTH ; k++)
+ test_data [k] = float_test [k] ;
+
+ snr = dft_cmp (__LINE__, double_data, test_data, 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 ;
+
+ print_test_name ("double_scaled_test", filename) ;
+
+ gen_windowed_sine_double (double_data, DFT_DATA_LENGTH, 0.95) ;
+
+ 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 (test_data, 0, sizeof (test_data)) ;
+
+ 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). (%ld should be %d)\n", __LINE__, SF_COUNT_TO_LONG (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, test_data, DFT_DATA_LENGTH, __LINE__) ;
+
+ sf_close (file) ;
+
+ snr = dft_cmp (__LINE__, double_data, test_data, 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)
+{ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ unsigned k, max ;
+
+ 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.98) ;
+
+ 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__) ;
+ 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__) ;
+
+ if (sfinfo.frames != ARRAY_LEN ([+ (get "float_name") +]_data))
+ { printf ("\n\nLine %d: Incorrect number of frames in file (too short). (%ld should be %d)\n", __LINE__, SF_COUNT_TO_LONG (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 +]
+
+[+ COMMENT
+
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: c1043a35-f0aa-44af-9f7f-f193c67f140d
+
++]
diff --git a/tests/header_test.def b/tests/header_test.def
new file mode 100644
index 0000000..4a3fd8f
--- /dev/null
+++ b/tests/header_test.def
@@ -0,0 +1,30 @@
+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" ;
+ } ;
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 436e1f37-a274-4377-b8fa-b2e2fc29f85b
+*/
+
diff --git a/tests/header_test.tpl b/tests/header_test.tpl
new file mode 100644
index 0000000..38f7a37
--- /dev/null
+++ b/tests/header_test.tpl
@@ -0,0 +1,498 @@
+[+ AutoGen5 template c +]
+/*
+** Copyright (C) 2001-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#include <math.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if (HAVE_DECL_S_IRGRP == 0)
+#include <sf_unistd.h>
+#endif
+
+#if (defined (WIN32) || defined (_WIN32))
+#include <io.h>
+#include <direct.h>
+#endif
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+#define BUFFER_LEN (1<<10)
+#define LOG_BUFFER_SIZE 1024
+
+static void update_header_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) ;
+
+/* 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 <test>\n", argv [0]) ;
+ printf (" Where <test> 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) ;
+ extra_header_test ("extra.wav", SF_FORMAT_WAV) ;
+ 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) ;
+ 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], "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 (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, frames ;
+
+ sfinfo.samplerate = 44100 ;
+ sfinfo.format = (typemajor | SF_FORMAT_PCM_16) ;
+ sfinfo.channels = 1 ;
+ sfinfo.frames = 0 ;
+
+ frames = BUFFER_LEN / sfinfo.channels ;
+
+ 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 (%ld should be %d)\n", __LINE__, SF_COUNT_TO_LONG (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 (%ld should be %d)\n", __LINE__, SF_COUNT_TO_LONG (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) ;
+
+#if 0 /*-(OS_IS_WIN32 == 0)-*/
+ if (typemajor == SF_FORMAT_PAF)
+ { /*
+ ** I think this is a bug in the win32 file I/O code in src/file_io.c.
+ ** I didn't write that code and I don't have the time to debug and
+ ** fix it. Patches will gladly be accepted. Erik
+ */
+ puts ("doesn't work on win32") ;
+ return ;
+ } ;
+#endif
+
+ update_header_sub (filename, typemajor, SFM_WRITE) ;
+ update_header_sub (filename, typemajor, SFM_RDWR) ;
+
+ unlink (filename) ;
+ puts ("ok") ;
+} /* update_header_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. */
+ 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 (%ld should be %ld)\n", __LINE__, SF_COUNT_TO_LONG (sfinfo.frames), SF_COUNT_TO_LONG (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
+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) ;
+
+ 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 <erikd@mega-nerd.com> 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 (%ld should be %ld)\n", [+ (tpl-file-line "%2$d") +], SF_COUNT_TO_LONG (sfinfo.frames), SF_COUNT_TO_LONG (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 */
+
+[+ COMMENT
+
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: ba02b7d6-8a89-45f3-aad2-a50390f52af5
+
++]
diff --git a/tests/headerless_test.c b/tests/headerless_test.c
new file mode 100644
index 0000000..5595730
--- /dev/null
+++ b/tests/headerless_test.c
@@ -0,0 +1,187 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#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 ("raw.vox", SF_FORMAT_VOX_ADPCM, SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM) ;
+ headerless_test ("raw.gsm", SF_FORMAT_GSM610, SF_FORMAT_RAW | SF_FORMAT_GSM610) ;
+
+ headerless_test ("raw.snd", SF_FORMAT_ULAW, SF_FORMAT_RAW | SF_FORMAT_ULAW) ;
+ headerless_test ("raw.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 = 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 => %ld)\n", __LINE__, BUFFER_SIZE, SF_COUNT_TO_LONG (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__) ;
+
+ 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 = 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 => %ld)\n", __LINE__, BUFFER_SIZE, SF_COUNT_TO_LONG (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 = 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) ;
+ } ;
+
+ printf ("ok\n") ;
+ unlink (filename) ;
+} /* old_test */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 0820bc1a-c396-4e66-9997-096999b0bc40
+*/
diff --git a/tests/largefile_test.c b/tests/largefile_test.c
new file mode 100644
index 0000000..8fb005a
--- /dev/null
+++ b/tests/largefile_test.c
@@ -0,0 +1,90 @@
+/*
+** Copyright (C) 2006 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 4ef10b9a-3356-4b92-8b7b-c60c0c4123fe
+*/
diff --git a/tests/locale_test.c b/tests/locale_test.c
new file mode 100644
index 0000000..4c76f56
--- /dev/null
+++ b/tests/locale_test.c
@@ -0,0 +1,114 @@
+/*
+** Copyright (C) 2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+#include "sndfile.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#include "utils.h"
+
+typedef struct
+{ const char *locale ;
+ const char *filename ;
+ int width ;
+} LOCALE_DATA ;
+
+static void locale_test (const char * locname, const char * filename, int width) ;
+
+int
+main (void)
+{ LOCALE_DATA ldata [] =
+ { { "de_DE", "F\303\274\303\237e.au", 7 },
+ { "en_AU", "kangaroo.au", 11 },
+ { "POSIX", "posix.au", 8 },
+ { "pt_PT", "concei\303\247\303\243o.au", 12 },
+ { "ja_JP", "\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 },
+ { "vi_VN", "qu\341\273\221c ng\341\273\257.au", 11 },
+
+ { NULL, NULL, 0 }
+ } ;
+ int k ;
+
+ for (k = 0 ; ldata [k].locale != NULL ; k++)
+ locale_test (ldata [k].locale, ldata [k].filename, ldata [k].width) ;
+
+ return 0 ;
+} /* main */
+
+static void
+locale_test (const char * locname, const char * filename, int width)
+{
+#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 ;
+ SNDFILE *file ;
+ SF_INFO sfinfo ;
+
+ /* Grab the old locale. */
+ old_locale = setlocale (LC_ALL, NULL) ;
+
+ if (setlocale (LC_ALL, locname) == NULL)
+ return ;
+
+ printf (" locale_test : %-6s %s%*c : ", locname, filename, 28 - width, ' ') ;
+ fflush (stdout) ;
+
+ sfinfo.format = SF_FORMAT_AU | SF_FORMAT_PCM_16 ;
+ sfinfo.channels = 1 ;
+ sfinfo.samplerate = 44100 ;
+
+ file = test_open_file_or_die (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 (filename, SFM_READ, &sfinfo, 0, __LINE__) ;
+ test_read_short_or_die (file, 0, rdata, ARRAY_LEN (rdata), __LINE__) ;
+ sf_close (file) ;
+
+ /* Restore old locale. */
+ setlocale (LC_ALL, old_locale) ;
+
+ unlink (filename) ;
+ puts ("ok") ;
+#endif
+} /* locale_test */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 087b25a3-03a2-4195-acd2-23fbbc489021
+*/
diff --git a/tests/lossy_comp_test.c b/tests/lossy_comp_test.c
new file mode 100644
index 0000000..fdd6d03
--- /dev/null
+++ b/tests/lossy_comp_test.c
@@ -0,0 +1,2194 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+#define BUFFER_SIZE (1<<14) /* Should be (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 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 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) ;
+
+/*
+** 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 <test>\n", argv [0]) ;
+ printf (" Where <test> 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 (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, 0.00001) ;
+ lcomp_test_int ("pcm.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16, 2, 0.00001) ;
+ lcomp_test_short ("pcm.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_PCM_16, 2, 0.00001) ;
+ lcomp_test_int ("pcm.rifx", SF_ENDIAN_BIG | SF_FORMAT_WAV | SF_FORMAT_PCM_16, 2, 0.00001) ;
+ /* Lite remove start */
+ lcomp_test_float ("pcm.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16, 2, 0.005) ;
+ lcomp_test_double ("pcm.wav", SF_FORMAT_WAV | SF_FORMAT_PCM_16, 2, 0.005) ;
+ /* Lite remove end */
+ 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.18) ;
+ 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 */
+ 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 */
+ 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++ ;
+ } ;
+
+ 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 */
+ 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 */
+ 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 */
+ 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 */
+ 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], "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 */
+ 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 */
+ 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 ;
+ long datalen ;
+ short *orig, *data ;
+
+ 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, 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. (%ld should be a little more than %ld)\n", SF_COUNT_TO_LONG (sfinfo.frames), datalen) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.frames > (datalen + datalen / 20))
+ { printf ("Too many frames in file. (%ld should be a little more than %ld)\n", SF_COUNT_TO_LONG (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, 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 = sf_readf_short (file, data, datalen)) != sfinfo.frames - datalen)
+ { printf ("\n\nLine %d: Incorrect read length (%ld should be %d).\n", __LINE__,
+ SF_COUNT_TO_LONG (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 = 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 ((double) data [k], (double) 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 = 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 ((double) data [0], (double) 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 = 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 = sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ;
+ k = sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ;
+ test_readf_short_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) 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, datalen) ;
+ exit (1) ;
+ } ;
+
+ seekpos = sf_seek (file, 0, SEEK_CUR) - 20 ;
+ /* Check seek backward from current position. */
+ k = sf_seek (file, -20, SEEK_CUR) ;
+ test_readf_short_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (backwards, SEEK_CUR) followed by sf_readf_short failed (%d, %d) (%d, %d).\n", data [0], orig [seekpos * channels], k, seekpos) ;
+ exit (1) ;
+ } ;
+
+ /* Check that read past end of file returns number of items. */
+ sf_seek (file, (short) sfinfo.frames, SEEK_SET) ;
+
+ if ((k = 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 = sf_seek (file, 5 - (short) sfinfo.frames, SEEK_END)) != 5)
+ { printf ("sf_seek (SEEK_END) returned %d instead of %d.\n", k, 5) ;
+ exit (1) ;
+ } ;
+
+ test_readf_short_or_die (file, 0, data, channels, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [5], margin))
+ { printf ("\n\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_short */
+
+/*--------------------------------------------------------------------------------------------
+*/
+
+static void
+lcomp_test_int (const char *filename, int filetype, int channels, double margin)
+{ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ int k, m, *orig, *data, half_max_abs ;
+ long datalen, seekpos ;
+ double scale ;
+
+ print_test_name ("lcomp_test_int", filename) ;
+
+ datalen = BUFFER_SIZE / channels ;
+
+ scale = 1.0 * 0x10000 ;
+
+ data = data_buffer.i ;
+ orig = orig_buffer.i ;
+
+ gen_signal_double (orig_buffer.d, 32000.0 * scale, channels, 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__) ;
+ 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. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (sfinfo.frames)) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.frames > (datalen + datalen / 20))
+ { printf ("Too many.frames in file. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (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 ("\n\nLine %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) ;
+ } ;
+ 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 = sf_readf_int (file, data, datalen)) != sfinfo.frames - datalen)
+ { printf ("\n\nLine %d: Incorrect read length (%ld should be %d).\n", __LINE__,
+ SF_COUNT_TO_LONG (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 = 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 ("\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 = sf_seek (file, seekpos, SEEK_SET)) != seekpos)
+ { printf ("Seek to start of file + %ld failed (%d).\n", seekpos, k) ;
+ exit (1) ;
+ } ;
+
+ test_readf_int_or_die (file, 0, data, 1, __LINE__) ;
+
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin))
+ { printf ("\n\nLine %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 ("\n\nLine %d: sf_seek (SEEK_CUR) with 0 offset failed (%d should be %ld)\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) ;
+ test_readf_int_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("\n\nLine %d: sf_seek (forwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %ld).\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 = sf_seek (file, -20, SEEK_CUR) ;
+ test_readf_int_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (backwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %ld).\n", data [0], orig [seekpos * channels], 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 ("\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 = 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) ;
+ } ;
+
+ test_readf_int_or_die (file, 0, data, channels, __LINE__) ;
+ if (error_function (data [0] / scale, orig [5] / scale, margin))
+ { printf ("\n\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 ;
+ long datalen ;
+ float *orig, *data ;
+ double half_max_abs ;
+
+ 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, 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. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (sfinfo.frames)) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.frames > (datalen + datalen / 20))
+ { printf ("Too many.frames in file. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (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 ((double) data [k], (double) orig [k], margin))
+ { printf ("\n\nLine %d: Incorrect sample A (#%d : %f should be %f).\n", __LINE__, k, data [k], orig [k]) ;
+ oct_save_float (orig, data, 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 = sf_readf_float (file, data, datalen)) != sfinfo.frames - datalen)
+ { printf ("\n\nLine %d: Incorrect read length (%ld should be %d).\n", __LINE__,
+ SF_COUNT_TO_LONG (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 = 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 ((double) data [k], (double) orig [k + channels * m * 11], margin))
+ { printf ("\n\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 = 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 ((double) data [0], (double) orig [seekpos * channels], margin))
+ { printf ("\n\nLine %d: sf_seek (SEEK_SET) followed by sf_readf_float failed (%f, %f).\n", __LINE__, orig [1], data [0]) ;
+ exit (1) ;
+ } ;
+
+ if ((k = 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 = sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ;
+ k = sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ;
+ test_readf_float_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("\n\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 = sf_seek (file, 0, SEEK_CUR) - 20 ;
+ /* Check seek backward from current position. */
+ k = sf_seek (file, -20, SEEK_CUR) ;
+ test_readf_float_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (backwards, SEEK_CUR) followed by sf_readf_float failed (%f, %f) (%d, %d).\n", data [0], orig [seekpos * channels], k, seekpos) ;
+ exit (1) ;
+ } ;
+
+ /* Check that read past end of file returns number of items. */
+ sf_seek (file, (float) sfinfo.frames, SEEK_SET) ;
+
+ if ((k = 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 = sf_seek (file, 5 - (float) sfinfo.frames, SEEK_END)) != 5)
+ { printf ("sf_seek (SEEK_END) returned %d instead of %d.\n", k, 5) ;
+ exit (1) ;
+ } ;
+
+ test_readf_float_or_die (file, 0, data, channels, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [5], margin))
+ { printf ("\n\nLine %d: sf_seek (SEEK_END) followed by sf_readf_short failed (%f should be %f).\n", __LINE__, data [0], orig [5]) ;
+ 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 ;
+ long datalen ;
+ double *orig, *data ;
+ double half_max_abs ;
+
+ 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, datalen) ;
+ for (k = 0 ; k < channels * datalen ; k++)
+ orig [k] = (double) (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. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (sfinfo.frames)) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.frames > (datalen + datalen / 20))
+ { printf ("Too many.frames in file. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (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 ((double) data [k], (double) orig [k], margin))
+ { printf ("\n\nLine %d: Incorrect sample A (#%d : %f should be %f).\n", __LINE__, k, data [k], orig [k]) ;
+ oct_save_double (orig, data, 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 = sf_readf_double (file, data, datalen)) != sfinfo.frames - datalen)
+ { printf ("\n\nLine %d: Incorrect read length (%ld should be %d).\n", __LINE__,
+ SF_COUNT_TO_LONG (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 = 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 ((double) data [k], (double) orig [k + channels * m * 11], margin))
+ { printf ("\n\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 = 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 ((double) data [0], (double) orig [seekpos * channels], margin))
+ { printf ("\n\nLine %d: sf_seek (SEEK_SET) followed by sf_readf_double failed (%f, %f).\n", __LINE__, orig [1], data [0]) ;
+ exit (1) ;
+ } ;
+
+ if ((k = 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 = sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ;
+ k = sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ;
+ test_readf_double_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("\n\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 = sf_seek (file, 0, SEEK_CUR) - 20 ;
+ /* Check seek backward from current position. */
+ k = sf_seek (file, -20, SEEK_CUR) ;
+ test_readf_double_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (backwards, SEEK_CUR) followed by sf_readf_double failed (%f, %f) (%d, %d).\n", data [0], orig [seekpos * channels], k, seekpos) ;
+ exit (1) ;
+ } ;
+
+ /* Check that read past end of file returns number of items. */
+ sf_seek (file, (double) sfinfo.frames, SEEK_SET) ;
+
+ if ((k = 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 = sf_seek (file, 5 - (double) sfinfo.frames, SEEK_END)) != 5)
+ { printf ("sf_seek (SEEK_END) returned %d instead of %d.\n", k, 5) ;
+ exit (1) ;
+ } ;
+
+ test_readf_double_or_die (file, 0, data, channels, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [5], margin))
+ { printf ("\n\nLine %d: sf_seek (SEEK_END) followed by sf_readf_short failed (%f should be %f).\n", __LINE__, data [0], orig [5]) ;
+ 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 ;
+ long datalen ;
+ short *orig, *data, *smooth ;
+
+channels = 1 ;
+ 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, datalen) ;
+ for (k = 0 ; k < 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_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. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (sfinfo.frames)) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.frames > (datalen + 400))
+ { printf ("Too many.frames in file. (%ld should be a little more than %ld)\n", SF_COUNT_TO_LONG (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, datalen) ;
+ smoothed_diff_short (smooth, datalen) ;
+
+ half_max_abs = 0.0 ;
+ for (k = 0 ; k < datalen ; k++)
+ { if (error_function ((double) data [k], (double) smooth [k], margin))
+ { printf ("\n\nLine %d: Incorrect sample (#%d : %d should be %d).\n", __LINE__, k, data [k], smooth [k]) ;
+ oct_save_short (orig, smooth, datalen) ;
+ exit (1) ;
+ } ;
+ half_max_abs = 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 = sf_read_short (file, data, datalen)) != sfinfo.frames - datalen)
+ { printf ("\n\nLine %d: Incorrect read length (%d should be %ld).\n", __LINE__, k, SF_COUNT_TO_LONG (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 (#%ld : 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 = 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, datalen / 7) ;
+ memcpy (smooth, orig + m * datalen / 7, datalen / 7 * sizeof (short)) ;
+ smoothed_diff_short (smooth, datalen / 7) ;
+
+ for (k = 0 ; k < datalen / 7 ; k++)
+ if (error_function ((double) data [k], (double) smooth [k], margin))
+ { printf ("Incorrect sample C (#%d (%ld) : %d => %d).\n", 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 = 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 ((double) data [0], (double) orig [seekpos * channels], margin))
+ { printf ("sf_seek (SEEK_SET) followed by sf_read_short failed (%d, %d).\n", orig [1], data [0]) ;
+ exit (1) ;
+ } ;
+
+ if ((k = sf_seek (file, 0, SEEK_CUR)) != seekpos + 1)
+ { printf ("sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", k, seekpos + 1) ;
+ exit (1) ;
+ } ;
+
+ seekpos = sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ;
+ k = sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ;
+ test_readf_short_or_die (file, 0, data, channels, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (forwards, SEEK_CUR) followed by sf_read_short failed (%d, %d) (%d, %d).\n", 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 = sf_seek (file, -20, SEEK_CUR) ;
+ test_readf_short_or_die (file, 0, data, channels, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (backwards, SEEK_CUR) followed by sf_read_short failed (%d, %d) (%d, %d).\n", data [0], orig [seekpos * channels], 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_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 = 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) ;
+ } ;
+
+ test_read_short_or_die (file, 0, data, channels, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [5], margin))
+ { printf ("sf_seek (SEEK_END) followed by sf_read_short failed (%d should be %d).\n", data [0], orig [5]) ;
+ 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 ;
+ long datalen ;
+ int *orig, *data, *smooth ;
+ double scale ;
+
+channels = 1 ;
+
+ 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, datalen) ;
+ for (k = 0 ; k < datalen ; k++)
+ orig [k] = (int) (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 != 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. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (sfinfo.frames)) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.frames > (datalen + 400))
+ { printf ("Too many.frames in file. (%ld should be a little more than %ld)\n", SF_COUNT_TO_LONG (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, datalen) ;
+ smoothed_diff_int (smooth, 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 ("\n\nLine %d: Incorrect sample (#%d : %d should be %d).\n", __LINE__, k, data [k], smooth [k]) ;
+ oct_save_int (orig, smooth, 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 = sf_readf_int (file, data, datalen)) != sfinfo.frames - datalen)
+ { printf ("\n\nLine %d: Incorrect read length (%d should be %ld).\n", __LINE__, k, SF_COUNT_TO_LONG (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)
+ for (k = 0 ; k < sfinfo.frames - datalen ; k++)
+ if (abs (data [k]) > decay_response (k))
+ { printf ("\n\nLine %d: Incorrect sample (#%ld : 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 = 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, datalen / 7) ;
+ memcpy (smooth, orig + m * datalen / 7, datalen / 7 * sizeof (int)) ;
+ smoothed_diff_int (smooth, datalen / 7) ;
+
+ for (k = 0 ; k < datalen / 7 ; k++)
+ if (error_function (data [k] / scale, smooth [k] / scale, margin))
+ { printf ("\n\nLine %d: Incorrect sample (#%d (%ld) : %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 = 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 ((double) data [0], (double) orig [seekpos * channels], margin))
+ { printf ("sf_seek (SEEK_SET) followed by sf_readf_int failed (%d, %d).\n", orig [1], data [0]) ;
+ exit (1) ;
+ } ;
+
+ if ((k = sf_seek (file, 0, SEEK_CUR)) != seekpos + 1)
+ { printf ("sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", k, seekpos + 1) ;
+ exit (1) ;
+ } ;
+
+ seekpos = sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ;
+ k = sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ;
+ test_readf_int_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (forwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %d).\n", 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 = sf_seek (file, -20, SEEK_CUR) ;
+ test_readf_int_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (backwards, SEEK_CUR) followed by sf_readf_int failed (%d, %d) (%d, %d).\n", data [0], orig [seekpos * channels], 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 ("\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 = 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) ;
+ } ;
+
+ test_readf_int_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function (data [0] / scale, orig [5] / scale, margin))
+ { printf ("\n\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 ;
+ long datalen ;
+ float *orig, *data, *smooth ;
+ double half_max_abs ;
+
+channels = 1 ;
+
+ print_test_name ("sdlcomp_test_float", filename) ;
+
+printf ("** fix this ** ") ;
+
+ datalen = BUFFER_SIZE ;
+
+ orig = orig_buffer.f ;
+ data = data_buffer.f ;
+ smooth = smooth_buffer.f ;
+
+ gen_signal_double (orig_buffer.d, 32000.0, channels, datalen) ;
+ for (k = 0 ; k < datalen ; k++)
+ orig [k] = (int) (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_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. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (sfinfo.frames)) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.frames > (datalen + 400))
+ { printf ("Too many.frames in file. (%ld should be a little more than %ld)\n", SF_COUNT_TO_LONG (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, datalen) ;
+ smoothed_diff_float (smooth, datalen) ;
+
+ half_max_abs = fabs (data [0]) ;
+ for (k = 1 ; k < datalen ; k++)
+ { if (error_function (data [k], smooth [k], margin))
+ { printf ("\n\nLine %d: Incorrect sample (#%d : %d should be %d).\n", __LINE__, k, (int) data [k], (int) smooth [k]) ;
+ oct_save_float (orig, smooth, datalen) ;
+ exit (1) ;
+ } ;
+ half_max_abs = LCT_MAX (half_max_abs, abs (0.5 * data [k])) ;
+ } ;
+
+ 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 = sf_read_float (file, data, datalen)) != sfinfo.frames - datalen)
+ { printf ("\n\nLine %d: Incorrect read length (%d should be %ld).\n", __LINE__, k, SF_COUNT_TO_LONG (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 (#%ld : 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 = 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, datalen / 7) ;
+ memcpy (smooth, orig + m * datalen / 7, datalen / 7 * sizeof (float)) ;
+ smoothed_diff_float (smooth, datalen / 7) ;
+
+ for (k = 0 ; k < datalen / 7 ; k++)
+ if (error_function ((float) data [k], (float) smooth [k], margin))
+ { printf ("Incorrect sample C (#%d (%ld) : %d => %d).\n", k, k + m * (datalen / 7), (int) smooth [k], (int) data [k]) ;
+ 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 = 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, 1, __LINE__) ;
+
+ if (error_function ((float) data [0], (float) orig [seekpos * channels], margin))
+ { printf ("sf_seek (SEEK_SET) followed by sf_read_float failed (%d, %d).\n", (int) orig [1], (int) data [0]) ;
+ exit (1) ;
+ } ;
+
+ if ((k = sf_seek (file, 0, SEEK_CUR)) != seekpos + 1)
+ { printf ("sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", k, seekpos + 1) ;
+ exit (1) ;
+ } ;
+
+ seekpos = sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ;
+ k = sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ;
+ test_read_float_or_die (file, 0, data, channels, __LINE__) ;
+ if (error_function ((float) data [0], (float) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (forwards, SEEK_CUR) followed by sf_read_float failed (%d, %d) (%d, %d).\n", (int) data [0], (int) orig [seekpos * channels], 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) ;
+ test_read_float_or_die (file, 0, data, channels, __LINE__) ;
+ if (error_function ((float) data [0], (float) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (backwards, SEEK_CUR) followed by sf_read_float failed (%d, %d) (%d, %d).\n", (int) data [0], (int) orig [seekpos * channels], 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_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 = 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) ;
+ } ;
+
+ test_read_float_or_die (file, 0, data, channels, __LINE__) ;
+ if (error_function ((float) data [0], (float) orig [5], margin))
+ { printf ("sf_seek (SEEK_END) followed by sf_read_float failed (%d should be %d).\n", (int) data [0], (int) orig [5]) ;
+ 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 ;
+ long datalen ;
+ double *orig, *data, *smooth, half_max_abs ;
+
+channels = 1 ;
+ print_test_name ("sdlcomp_test_double", filename) ;
+
+ datalen = BUFFER_SIZE ;
+
+ orig = orig_buffer.d ;
+ data = data_buffer.d ;
+ smooth = smooth_buffer.d ;
+
+ gen_signal_double (orig_buffer.d, 32000.0, channels, datalen) ;
+
+ 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_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. (%ld should be a little more than %ld)\n", datalen, SF_COUNT_TO_LONG (sfinfo.frames)) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.frames > (datalen + 400))
+ { printf ("Too many.frames in file. (%ld should be a little more than %ld)\n", SF_COUNT_TO_LONG (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, datalen) ;
+ smoothed_diff_double (smooth, datalen) ;
+
+ half_max_abs = 0.0 ;
+ for (k = 0 ; k < datalen ; k++)
+ { if (error_function (data [k], smooth [k], margin))
+ { printf ("\n\nLine %d: Incorrect sample (#%d : %d should be %d).\n", __LINE__, k, (int) data [k], (int) smooth [k]) ;
+ oct_save_double (orig, smooth, datalen) ;
+ exit (1) ;
+ } ;
+ half_max_abs = LCT_MAX (half_max_abs, 0.5 * fabs (data [k])) ;
+ } ;
+
+ if (half_max_abs < 1.0)
+ { printf ("\n\nLine %d: Signal is all zeros.\n", __LINE__) ;
+ exit (1) ;
+ } ;
+
+ if ((k = sf_read_double (file, data, datalen)) != sfinfo.frames - datalen)
+ { printf ("\n\nLine %d: Incorrect read length (%d should be %ld).\n", __LINE__, k, SF_COUNT_TO_LONG (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 (#%ld : 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 = 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, datalen / 7) ;
+ memcpy (smooth, orig + m * datalen / 7, datalen / 7 * sizeof (double)) ;
+ smoothed_diff_double (smooth, datalen / 7) ;
+
+ for (k = 0 ; k < datalen / 7 ; k++)
+ if (error_function ((double) data [k], (double) smooth [k], margin))
+ { printf ("Incorrect sample C (#%d (%ld) : %d => %d).\n", k, k + m * (datalen / 7), (int) smooth [k], (int) data [k]) ;
+ 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 = 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, 1, __LINE__) ;
+
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin))
+ { printf ("sf_seek (SEEK_SET) followed by sf_read_double failed (%d, %d).\n", (int) orig [1], (int) data [0]) ;
+ exit (1) ;
+ } ;
+
+ if ((k = sf_seek (file, 0, SEEK_CUR)) != seekpos + 1)
+ { printf ("sf_seek (SEEK_CUR) with 0 offset failed (%d should be %d)\n", k, seekpos + 1) ;
+ exit (1) ;
+ } ;
+
+ seekpos = sf_seek (file, 0, SEEK_CUR) + BUFFER_SIZE / 5 ;
+ k = sf_seek (file, BUFFER_SIZE / 5, SEEK_CUR) ;
+ test_read_double_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (forwards, SEEK_CUR) followed by sf_read_double failed (%d, %d) (%d, %d).\n", (int) data [0], (int) orig [seekpos * channels], 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) ;
+ test_read_double_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [seekpos * channels], margin) || k != seekpos)
+ { printf ("sf_seek (backwards, SEEK_CUR) followed by sf_read_double failed (%d, %d) (%d, %d).\n", (int) data [0], (int) orig [seekpos * channels], 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_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 = 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) ;
+ } ;
+
+ test_read_double_or_die (file, 0, data, 1, __LINE__) ;
+ if (error_function ((double) data [0], (double) orig [5], margin))
+ { printf ("sf_seek (SEEK_END) followed by sf_read_double failed (%d should be %d).\n", (int) data [0], (int) orig [5]) ;
+ exit (1) ;
+ } ;
+ } /* if (sfinfo.seekable) */
+
+ sf_close (file) ;
+
+ unlink (filename) ;
+ printf ("ok\n") ;
+} /* sdlcomp_test_double */
+
+/*========================================================================================
+** 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\n*******************\nError : %f\n", 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 = 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 5eb86888-3311-48b8-920e-c2a0393b7ad2
+*/
diff --git a/tests/misc_test.c b/tests/misc_test.c
new file mode 100644
index 0000000..71aa186
--- /dev/null
+++ b/tests/misc_test.c
@@ -0,0 +1,365 @@
+/*
+** Copyright (C) 2001-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <math.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if (HAVE_DECL_S_IRGRP == 0)
+#include <sf_unistd.h>
+#endif
+
+#if (defined (WIN32) || defined (_WIN32))
+#include <io.h>
+#include <direct.h>
+#endif
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+#define BUFFER_LEN (1<<10)
+#define LOG_BUFFER_SIZE 1024
+
+static void zero_data_test (const char *filename, int typemajor) ;
+static void filesystem_full_test (int typemajor) ;
+static void permission_test (const char *filename, int typemajor) ;
+
+int
+main (int argc, char *argv [])
+{ int do_all = 0 ;
+ int test_count = 0 ;
+
+ if (argc != 2)
+ { printf ("Usage : %s <test>\n", argv [0]) ;
+ printf (" Where <test> 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) ;
+ filesystem_full_test (SF_FORMAT_WAV) ;
+ permission_test ("readonly.wav", SF_FORMAT_WAV) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "aiff"))
+ { zero_data_test ("zerolen.aiff", SF_FORMAT_AIFF) ;
+ filesystem_full_test (SF_FORMAT_AIFF) ;
+ permission_test ("readonly.aiff", SF_FORMAT_AIFF) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "au"))
+ { zero_data_test ("zerolen.au", SF_FORMAT_AU) ;
+ filesystem_full_test (SF_FORMAT_AU) ;
+ permission_test ("readonly.au", SF_FORMAT_AU) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "caf"))
+ { zero_data_test ("zerolen.caf", SF_FORMAT_CAF) ;
+ filesystem_full_test (SF_FORMAT_CAF) ;
+ permission_test ("readonly.caf", SF_FORMAT_CAF) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "svx"))
+ { zero_data_test ("zerolen.svx", SF_FORMAT_SVX) ;
+ filesystem_full_test (SF_FORMAT_SVX) ;
+ permission_test ("readonly.svx", SF_FORMAT_SVX) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "nist"))
+ { zero_data_test ("zerolen.nist", SF_FORMAT_NIST) ;
+ filesystem_full_test (SF_FORMAT_NIST) ;
+ permission_test ("readonly.nist", SF_FORMAT_NIST) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "paf"))
+ { zero_data_test ("zerolen.paf", SF_FORMAT_PAF) ;
+ filesystem_full_test (SF_FORMAT_PAF) ;
+ permission_test ("readonly.paf", SF_FORMAT_PAF) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "ircam"))
+ { zero_data_test ("zerolen.ircam", SF_FORMAT_IRCAM) ;
+ filesystem_full_test (SF_FORMAT_IRCAM) ;
+ permission_test ("readonly.ircam", SF_FORMAT_IRCAM) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "voc"))
+ { zero_data_test ("zerolen.voc", SF_FORMAT_VOC) ;
+ filesystem_full_test (SF_FORMAT_VOC) ;
+ permission_test ("readonly.voc", SF_FORMAT_VOC) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "w64"))
+ { zero_data_test ("zerolen.w64", SF_FORMAT_W64) ;
+ filesystem_full_test (SF_FORMAT_W64) ;
+ permission_test ("readonly.w64", SF_FORMAT_W64) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "mat4"))
+ { zero_data_test ("zerolen.mat4", SF_FORMAT_MAT4) ;
+ filesystem_full_test (SF_FORMAT_MAT4) ;
+ permission_test ("readonly.mat4", SF_FORMAT_MAT4) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "mat5"))
+ { zero_data_test ("zerolen.mat5", SF_FORMAT_MAT5) ;
+ filesystem_full_test (SF_FORMAT_MAT5) ;
+ permission_test ("readonly.mat5", SF_FORMAT_MAT5) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "pvf"))
+ { zero_data_test ("zerolen.pvf", SF_FORMAT_PVF) ;
+ filesystem_full_test (SF_FORMAT_PVF) ;
+ permission_test ("readonly.pvf", SF_FORMAT_PVF) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "htk"))
+ { zero_data_test ("zerolen.htk", SF_FORMAT_HTK) ;
+ filesystem_full_test (SF_FORMAT_HTK) ;
+ permission_test ("readonly.htk", SF_FORMAT_HTK) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "avr"))
+ { zero_data_test ("zerolen.avr", SF_FORMAT_AVR) ;
+ filesystem_full_test (SF_FORMAT_AVR) ;
+ permission_test ("readonly.avr", SF_FORMAT_AVR) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "sds"))
+ { zero_data_test ("zerolen.sds", SF_FORMAT_SDS) ;
+ filesystem_full_test (SF_FORMAT_SDS) ;
+ permission_test ("readonly.sds", SF_FORMAT_SDS) ;
+ 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 typemajor)
+{ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ int frames ;
+
+ print_test_name ("zero_data_test", filename) ;
+
+ sfinfo.samplerate = 44100 ;
+ sfinfo.format = (typemajor | SF_FORMAT_PCM_16) ;
+ sfinfo.channels = 1 ;
+ sfinfo.frames = 0 ;
+
+ frames = BUFFER_LEN / sfinfo.channels ;
+
+ 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 typemajor)
+{ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ struct stat buf ;
+
+ const char *filename = "/dev/full", *errorstr ;
+ int frames ;
+
+#if (defined (WIN32) || defined (_WIN32))
+ /* Can't run this test on Win32 so return. */
+ return ;
+#endif
+
+ /* 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 = (typemajor | SF_FORMAT_PCM_16) ;
+ sfinfo.channels = 1 ;
+ sfinfo.frames = 0 ;
+
+ frames = BUFFER_LEN / sfinfo.channels ;
+
+ 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") ;
+} /* filesystem_full_test */
+
+static void
+permission_test (const char *filename, int typemajor)
+{
+#if (OS_IS_WIN32)
+ /* Avoid compiler warnings. */
+ filename = filename ;
+ typemajor = typemajor ;
+
+ /* Can't run this test on Win32 so return. */
+ return ;
+#else
+
+ FILE *textfile ;
+ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ const char *errorstr ;
+ int frames ;
+
+ /* 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 ;
+
+ frames = BUFFER_LEN / sfinfo.channels ;
+
+ 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: efc6c227-8881-4a1d-8680-0d1255975267
+*/
diff --git a/tests/multi_file_test.c b/tests/multi_file_test.c
new file mode 100644
index 0000000..6662337
--- /dev/null
+++ b/tests/multi_file_test.c
@@ -0,0 +1,258 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if (HAVE_DECL_S_IRGRP == 0)
+#include <sf_unistd.h>
+#endif
+
+#include <fcntl.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+#define DATA_LENGTH (512)
+
+static off_t get_file_length (int fd) ;
+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 <test>\n", argv [0]) ;
+ printf (" Where <test> 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 ;
+ off_t file_length ;
+ 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 | S_IRGRP )) < 0)
+ { printf ("\n\nLine %d: open failed : %s\n", __LINE__, strerror (errno)) ;
+ exit (1) ;
+ } ;
+
+ write (fd, "1234", 4) ;
+
+ for (k = 0 ; k < format_count ; k++)
+ write_file_at_end (fd, formats [k], 2, k) ;
+
+ file_length = get_file_length (fd) ;
+
+ embed_info.offset = 4 ;
+ embed_info.length = 0 ;
+
+ file_count = 0 ;
+
+ while (embed_info.offset + embed_info.length < file_length)
+ {
+ file_count ++ ;
+
+ if (verbose)
+ { puts ("\n------------------------------------") ;
+ printf ("This offset : %ld\n", SF_COUNT_TO_LONG (embed_info.offset + embed_info.length)) ;
+ } ;
+
+ if (lseek (fd, 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 : %ld\n", file_count, SF_COUNT_TO_LONG (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 : %ld\nNext length : %ld\n", SF_COUNT_TO_LONG (embed_info.offset), SF_COUNT_TO_LONG (embed_info.length)) ;
+ } ;
+
+ 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 */
+
+static off_t
+get_file_length (int fd)
+{ struct stat statbuf ;
+
+ if (fstat (fd, &statbuf) == -1)
+ { printf ("\n\nError : fstat error : %s\n\n", strerror (errno)) ;
+ exit (1) ;
+ } ;
+
+ return statbuf.st_size ;
+} /* get_file_length */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: c1a09b0e-57c9-4306-b69e-a865d44eecb3
+*/
diff --git a/tests/open_fail_test.c b/tests/open_fail_test.c
new file mode 100644
index 0000000..620f3ba
--- /dev/null
+++ b/tests/open_fail_test.c
@@ -0,0 +1,81 @@
+/*
+** Copyright (C) 2003,2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+int
+main (void)
+{ SNDFILE *sndfile ;
+ SF_INFO sfinfo ;
+
+ FILE *bad_file ;
+ const char *bad_wav = "bad_wav.wav" ;
+ const char bad_data [] = "RIFF WAVEfmt " ;
+
+ print_test_name ("open_fail_test", bad_wav) ;
+
+ memset (&sfinfo, 0, sizeof (sfinfo)) ;
+
+ sndfile = sf_open ("let's hope this file doesn't exist", SFM_READ, &sfinfo) ;
+
+ if (sndfile)
+ { printf ("Line %d: should not have received a valid SNDFILE* pointer.\n", __LINE__) ;
+ exit (1) ;
+ } ;
+
+ if ((bad_file = fopen (bad_wav, "w")) == NULL)
+ { printf ("Line %d: fopen returned NULL.\n", __LINE__) ;
+ exit (1) ;
+ } ;
+
+ fwrite (bad_data, sizeof (bad_data), 1, bad_file) ;
+ fclose (bad_file) ;
+
+ sndfile = sf_open (bad_wav, SFM_READ, &sfinfo) ;
+
+ if (sndfile)
+ { printf ("Line %d: should not have received a valid SNDFILE* pointer.\n", __LINE__) ;
+ exit (1) ;
+ } ;
+
+ unlink (bad_wav) ;
+ puts ("ok") ;
+
+ return 0 ;
+} /* main */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 24440323-00b1-4e4b-87c5-0e3b7e9605e9
+*/
diff --git a/tests/pcm_test.def b/tests/pcm_test.def
new file mode 100644
index 0000000..1deb99d
--- /dev/null
+++ b/tests/pcm_test.def
@@ -0,0 +1,42 @@
+autogen definitions pcm_test.tpl;
+
+data_type = {
+ name = "bits_8" ;
+ item_count = 127 ;
+ short_func = "((k * ((k % 2) ? 1 : -1)) << 8)" ;
+ int_func = "((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 = "((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 = "((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))" ;
+ } ;
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: a939b77e-4175-460b-a393-fb38012ded7c
+*/
+
diff --git a/tests/pcm_test.tpl b/tests/pcm_test.tpl
new file mode 100644
index 0000000..dfe7a51
--- /dev/null
+++ b/tests/pcm_test.tpl
@@ -0,0 +1,940 @@
+[+ AutoGen5 template c +]
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#include "float_cast.h"
+#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, int hash) ;
+[+ ENDFOR data_type
++]
+static void pcm_test_float (const char *filename, int filetype, int hash, int replace_float) ;
+static void pcm_test_double (const char *filename, int filetype, int 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, 0x9ae33814) ;
+ pcm_test_bits_8 ("pcm-u8.raw", SF_FORMAT_RAW | SF_FORMAT_PCM_U8, 0x651d4694) ;
+
+ pcm_test_bits_16 ("le-pcm16.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_16, 0x16866fa0) ;
+ pcm_test_bits_16 ("be-pcm16.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_16, 0xc571826c) ;
+
+ pcm_test_bits_24 ("le-pcm24.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_24, 0x658e4bb6) ;
+ pcm_test_bits_24 ("be-pcm24.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_24, 0xbf8cde4a) ;
+
+ pcm_test_bits_32 ("le-pcm32.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_PCM_32, 0x04c84a70) ;
+ pcm_test_bits_32 ("be-pcm32.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_PCM_32, 0x069c84f6) ;
+
+ /* Lite remove start */
+ pcm_test_float ("le-float.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_FLOAT, 0xbb836603, SF_FALSE) ;
+ pcm_test_float ("be-float.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_FLOAT, 0x903cd8fc, SF_FALSE) ;
+
+ pcm_test_double ("le-double.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_DOUBLE, 0xbf84448e, SF_FALSE) ;
+ pcm_test_double ("be-double.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_DOUBLE, 0xaf3d9fb5, SF_FALSE) ;
+
+ puts ("Test IEEE replacement code.") ;
+
+ pcm_test_float ("le-float.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_FLOAT, 0xbb836603, SF_TRUE) ;
+ pcm_test_float ("be-float.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_FLOAT, 0x903cd8fc, SF_TRUE) ;
+
+ pcm_test_double ("le-double.raw", SF_ENDIAN_LITTLE | SF_FORMAT_RAW | SF_FORMAT_DOUBLE, 0xbf84448e, SF_TRUE) ;
+ pcm_test_double ("be-double.raw", SF_ENDIAN_BIG | SF_FORMAT_RAW | SF_FORMAT_DOUBLE, 0xaf3d9fb5, 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, int 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 => %ld)\n", __LINE__, items, SF_COUNT_TO_LONG (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 => %ld)\n", __LINE__, items, SF_COUNT_TO_LONG (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 => %ld)\n", __LINE__, items, SF_COUNT_TO_LONG (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) ;
+ break ;
+ } ;
+
+ 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 => %ld)\n", __LINE__, items, SF_COUNT_TO_LONG (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, int hash, int replace_float)
+{ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ int k, items, frames ;
+ int sign ;
+ double *data, error ;
+
+ print_test_name ("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 => %ld)\n", __FILE__, __LINE__, items, SF_COUNT_TO_LONG (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__) ;
+ 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 => %ld)\n", __FILE__, __LINE__, frames, SF_COUNT_TO_LONG (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, int 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 ("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) ;
+
+#if (defined (WIN32) || defined (_WIN32))
+ /* File hashing on Win32 fails due to slighty different
+ ** calculated values of the sin() function.
+ */
+ hash = hash ; /* Avoid compiler warning. */
+#else
+ check_file_hash_or_die (filename, hash, __LINE__) ;
+#endif
+
+ 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 => %ld)\n", __FILE__, __LINE__, items, SF_COUNT_TO_LONG (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) ;
+
+#if (defined (WIN32) || defined (_WIN32))
+ /* File hashing on Win32 fails due to slighty different
+ ** calculated values.
+ */
+ hash = hash ; /* Avoid compiler warning. */
+#else
+ check_file_hash_or_die (filename, hash, __LINE__) ;
+#endif
+
+ 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 => %ld)\n", __FILE__, __LINE__, frames, SF_COUNT_TO_LONG (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 */
+
+/*==============================================================================
+*/
+
+[+ COMMENT
+
+ Do not edit or modify anything in this comment block.
+ The following line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: cad1443b-99d9-414e-883f-178817600d40
+
++]
diff --git a/tests/peak_chunk_test.c b/tests/peak_chunk_test.c
new file mode 100644
index 0000000..3782dbf
--- /dev/null
+++ b/tests/peak_chunk_test.c
@@ -0,0 +1,289 @@
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#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 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 <test>\n", argv [0]) ;
+ printf (" Where <test> 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"))
+ { 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) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "aiff"))
+ { test_float_peak ("peak_float.aiff", SF_FORMAT_AIFF | 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) ;
+
+ 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) ;
+ } ;
+
+ if (! (cptr = strstr (buffer, "Channels")) || sscanf (cptr, "Channels : %d", &channel_count) != 1)
+ { 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 (buffer) ;
+ exit (1) ;
+ } ;
+ if (chan != k || fabs ((position) * 0.01 - value) > 1e-6)
+ { printf ("\n\nLine %d: Error : peak value incorrect!\n", __LINE__) ;
+ printf (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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: f10ca506-5808-4393-9d58-e3ec201fb7ee
+*/
diff --git a/tests/pipe_test.def b/tests/pipe_test.def
new file mode 100644
index 0000000..e1487d9
--- /dev/null
+++ b/tests/pipe_test.def
@@ -0,0 +1,22 @@
+autogen definitions pipe_test.tpl;
+
+data_type = {
+ type_name = short ;
+ };
+
+data_type = {
+ type_name = float ;
+ };
+
+data_type = {
+ type_name = double ;
+ };
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 5bbde7f4-71e4-4f3e-bdae-a1cb27cdf338
+*/
+
diff --git a/tests/pipe_test.tpl b/tests/pipe_test.tpl
new file mode 100644
index 0000000..95680cb
--- /dev/null
+++ b/tests/pipe_test.tpl
@@ -0,0 +1,382 @@
+[+ AutoGen5 template c +]
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+/*==========================================================================
+** This is a test program which tests reading from and writing to pipes.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if (OS_IS_WIN32)
+
+int
+main (void)
+{
+ puts (" pipe_test : this test doesn't work on win32.") ;
+ return 0 ;
+} /* main */
+
+#else
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+typedef struct
+{ int format ;
+ const char *ext ;
+} FILETYPE ;
+
+static int file_exists (const char *filename) ;
+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 ;
+
+ if (file_exists ("libsndfile.spec.in"))
+ chdir ("tests") ;
+
+ 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) ;
+
+ 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 | ./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), "./stdout_test %s | ./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.
+ */
+ pipe (pipefd) ;
+
+ /*
+ ** 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 ;
+
+ 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 | ./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 */
+
+
+/*==============================================================================
+*/
+
+static int
+file_exists (const char *filename)
+{ struct stat buf ;
+
+ if (stat (filename, &buf))
+ return 0 ;
+
+ return 1 ;
+} /* file_exists */
+
+#endif
+
+[+ COMMENT
+
+ Do not edit or modify anything in this comment block.
+ The arch-tag line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 968ad8d5-e724-41fe-8209-fa1578569dfe
+
++]
diff --git a/tests/raw_test.c b/tests/raw_test.c
new file mode 100644
index 0000000..0741f79
--- /dev/null
+++ b/tests/raw_test.c
@@ -0,0 +1,195 @@
+/*
+** Copyright (C) 2002-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#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, frames ;
+
+ print_test_name ("raw_offset_test", filename) ;
+
+ sfinfo.samplerate = 44100 ;
+ sfinfo.format = SF_FORMAT_RAW | typeminor ;
+ sfinfo.channels = 1 ;
+ sfinfo.frames = 0 ;
+
+ frames = BUFFER_LEN / sfinfo.channels ;
+
+ 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 (%ld should be %d)\n", __LINE__, SF_COUNT_TO_LONG (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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 3dccee22-b0bc-4a1f-966c-8ae96f0921ae
+*/
diff --git a/tests/scale_clip_test.def b/tests/scale_clip_test.def
new file mode 100644
index 0000000..91e55e6
--- /dev/null
+++ b/tests/scale_clip_test.def
@@ -0,0 +1,62 @@
+autogen definitions scale_clip_test.tpl;
+
+float_type = {
+ float_type_name = "float" ;
+ float_short_name = "flt" ;
+ float_upper_name = "FLOAT" ;
+ } ;
+
+float_type = {
+ float_type_name = "double" ;
+ float_short_name = "dbl" ;
+ float_upper_name = "DOUBLE" ;
+ } ;
+
+
+
+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" ;
+ } ;
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 4938e5b6-6f4c-4c69-8b92-f6c6d7a6b0ec
+*/
+
diff --git a/tests/scale_clip_test.tpl b/tests/scale_clip_test.tpl
new file mode 100644
index 0000000..45e4cec
--- /dev/null
+++ b/tests/scale_clip_test.tpl
@@ -0,0 +1,339 @@
+[+ AutoGen5 template c +]
+/*
+** Copyright (C) 1999-2006 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <math.h>
+
+#include <sndfile.h>
+
+#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_type_name") +]_[+ (get "int_type_name") +]_clip_test (const char *filename, int filetype) ;
+[+ ENDFOR int_type
++][+ ENDFOR float_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) ;
+
+ float_int_clip_test ("flt_int.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_FLOAT) ;
+ float_short_clip_test ("flt_short.au" , SF_ENDIAN_BIG | SF_FORMAT_AU | SF_FORMAT_FLOAT) ;
+ double_int_clip_test ("dbl_int.au" , SF_ENDIAN_LITTLE | SF_FORMAT_AU | SF_FORMAT_DOUBLE) ;
+ double_short_clip_test ("dbl_short.au" , SF_ENDIAN_BIG | 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 => %ld).\n\n", __LINE__, BUFFER_SIZE, SF_COUNT_TO_LONG (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_type_name") +]_[+ (get "int_type_name") +]_clip_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_type_name") +]_[+ (get "int_type_name") +]_clip_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 => %ld).\n\n", __LINE__, BUFFER_SIZE, SF_COUNT_TO_LONG (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_type_name") +]_[+ (get "int_type_name") +]_clip_test */
+[+ ENDFOR int_type
++][+ ENDFOR float_type +]
+
+
+
+
+
+
+[+ COMMENT
+
+ Do not edit or modify anything in this comment block.
+ The following line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: dc1613fe-2985-462c-a0b4-62143a7570e8
+
++]
diff --git a/tests/sftest.c b/tests/sftest.c
new file mode 100644
index 0000000..ab68f13
--- /dev/null
+++ b/tests/sftest.c
@@ -0,0 +1,73 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#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 */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 43654fba-c130-4870-992b-9d4a390a6964
+*/
diff --git a/tests/sfversion.c b/tests/sfversion.c
new file mode 100644
index 0000000..80e9816
--- /dev/null
+++ b/tests/sfversion.c
@@ -0,0 +1,49 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#define BUFFER_SIZE (256)
+
+static char strbuffer [BUFFER_SIZE] ;
+
+int
+main (void)
+{ sf_command (NULL, SFC_GET_LIB_VERSION, strbuffer, sizeof (strbuffer)) ;
+
+ printf ("%s", strbuffer) ;
+
+ return 0 ;
+} /* main */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 53b0b14d-a52b-4094-b510-df91e4947574
+*/
diff --git a/tests/stdin_test.c b/tests/stdin_test.c
new file mode 100644
index 0000000..8f4db30
--- /dev/null
+++ b/tests/stdin_test.c
@@ -0,0 +1,204 @@
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#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") ;
+ fprintf (stderr, "* 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 ;
+
+ if (typemajor == SF_FORMAT_RAW)
+ { sfinfo.samplerate = 44100 ;
+ sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 ;
+ sfinfo.channels = 1 ;
+ sfinfo.frames = 0 ;
+ }
+ else
+ sfinfo.format = 0 ;
+
+ if (! (file = sf_open ("-", SFM_READ, &sfinfo)))
+ { fprintf (stderr, "sf_open_read failed with error : ") ;
+ puts (sf_strerror (NULL)) ;
+ dump_log_buffer (NULL) ;
+ 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 = 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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 5e470e3e-743e-4bbc-a588-ec883843c938
+*/
diff --git a/tests/stdio_test.c b/tests/stdio_test.c
new file mode 100644
index 0000000..1d177fc
--- /dev/null
+++ b/tests/stdio_test.c
@@ -0,0 +1,159 @@
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+/*==========================================================================
+** This is a test program which tests reading from stdin and writing to
+** stdout.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+#include "utils.h"
+
+#if (OS_IS_WIN32)
+
+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 int file_exists (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 ;
+
+ if (file_exists ("libsndfile.spec.in"))
+ chdir ("tests") ;
+
+ 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), "./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), "./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 */
+
+static int
+file_exists (const char *filename)
+{ struct stat buf ;
+
+ if (stat (filename, &buf))
+ return 0 ;
+
+ return 1 ;
+} /* file_exists */
+
+#endif
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: f46d84fd-d37b-4d08-b1ba-80f2f1e0cfb9
+*/
diff --git a/tests/stdout_test.c b/tests/stdout_test.c
new file mode 100644
index 0000000..65343dd
--- /dev/null
+++ b/tests/stdout_test.c
@@ -0,0 +1,167 @@
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#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") ;
+ fprintf (stderr, "* 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, "sf_open_write failed with error : ") ;
+ fprintf (stderr, "%s\n", sf_strerror (NULL)) ;
+ exit (1) ;
+ } ;
+
+ total = 0 ;
+
+ while (total < count)
+ { this_write = (count - total > 1024) ? 1024 : count - total ;
+ if ((k = 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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 660c3f79-a459-4c7c-899b-b360b7403403
+*/
diff --git a/tests/string_test.c b/tests/string_test.c
new file mode 100644
index 0000000..09d7e01
--- /dev/null
+++ b/tests/string_test.c
@@ -0,0 +1,227 @@
+/*
+** Copyright (C) 2003,2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+#define BUFFER_LEN (1 << 10)
+#define LOG_BUFFER_SIZE 1024
+
+static void string_test (const char *filename, int typemajor) ;
+
+static int libsndfile_str_count (const char * cptr) ;
+
+int
+main (int argc, char *argv [])
+{ int do_all = 0 ;
+ int test_count = 0 ;
+
+ if (argc != 2)
+ { printf ("Usage : %s <test>\n", argv [0]) ;
+ printf (" Where <test> 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 (" all - perform all tests\n") ;
+ exit (1) ;
+ } ;
+
+ do_all =! strcmp (argv [1], "all") ;
+
+ if (do_all || ! strcmp (argv [1], "wav"))
+ { string_test ("strings.wav", SF_FORMAT_WAV) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "aiff"))
+ { string_test ("strings.aiff", 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 const char
+ software [] = "software (libsndfile-X.Y.Z)",
+ artist [] = "The Artist",
+ copyright [] = "Copyright (c) 2001 The Artist",
+ comment [] = "Comment goes here!!!",
+ date [] = "2001/01/27" ;
+
+static short data_out [BUFFER_LEN] ;
+
+static void
+string_test (const char *filename, int typemajor)
+{ const char *cptr ;
+ SNDFILE *file ;
+ SF_INFO sfinfo ;
+ int frames, errors = 0 ;
+
+ typemajor = typemajor ;
+
+ print_test_name ("string_test", filename) ;
+
+ sfinfo.samplerate = 44100 ;
+ sfinfo.channels = 1 ;
+ sfinfo.frames = 0 ;
+
+ switch (typemajor)
+ { case SF_FORMAT_WAV :
+ sfinfo.format = (typemajor | SF_FORMAT_PCM_U8) ;
+ break ;
+
+ default :
+ sfinfo.format = (typemajor | SF_FORMAT_PCM_S8) ;
+ break ;
+ } ;
+
+ frames = BUFFER_LEN / sfinfo.channels ;
+
+ 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) ;
+
+ /* 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_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", 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", 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", cptr) ;
+ } ;
+
+ if (libsndfile_str_count (cptr) != 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", 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", 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", 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_test */
+
+static int
+libsndfile_str_count (const char * str)
+{ const char * cptr ;
+
+ if ((cptr = strstr (str, "libsndfile")) == NULL)
+ return 0 ;
+
+ if ((cptr = strstr (cptr + 1, "libsndfile")) == NULL)
+ return 1 ;
+
+ return 2 ;
+} /* libsndfile_str_count */
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 0260b3db-c250-4244-95a0-d288a913729a
+*/
diff --git a/tests/ulaw_test.c b/tests/ulaw_test.c
new file mode 100644
index 0000000..1b73a13
--- /dev/null
+++ b/tests/ulaw_test.c
@@ -0,0 +1,262 @@
+/*
+** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <sndfile.h>
+
+#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 ;
+
+ filename = "test.raw" ;
+
+ sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_ULAW ;
+ sfinfo.samplerate = 44100 ;
+ sfinfo.frames = 123456789 ;
+ sfinfo.channels = 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) ;
+
+ printf (" ulaw_test : encoder ... ok\n") ;
+
+ /* 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) ;
+
+ printf (" ulaw_test : decoder ... ok\n") ;
+
+ 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: e764cee1-5a9a-480b-a4ca-34d9b57dea6f
+*/
diff --git a/tests/utils.def b/tests/utils.def
new file mode 100644
index 0000000..ed2d120
--- /dev/null
+++ b/tests/utils.def
@@ -0,0 +1,59 @@
+autogen definitions utils.tpl;
+
+float_type = {
+ name = float ;
+ };
+
+float_type = {
+ name = double ;
+ };
+
+/*----------------------------------*/
+
+io_type = {
+ io_element = short ;
+ format_str = "\"% d\\n\"" ;
+ };
+
+io_type = {
+ io_element = int ;
+ format_str = "\"% d\\n\"" ;
+ };
+
+io_type = {
+ io_element = float ;
+ format_str = "\"% g\\n\"" ;
+ };
+
+io_type = {
+ io_element = double ;
+ format_str = "\"% g\\n\"" ;
+ };
+
+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 ;
+ };
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 735898a2-711e-42c2-aaf1-354b20c07ac7
+*/
+
diff --git a/tests/utils.tpl b/tests/utils.tpl
new file mode 100644
index 0000000..bc15423
--- /dev/null
+++ b/tests/utils.tpl
@@ -0,0 +1,704 @@
+[+ AutoGen5 template h c +]
+/*
+** Copyright (C) 2002-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+/*
+** 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 <stdarg.h>
+
+#define SF_COUNT_TO_LONG(x) ((long) (x))
+#define ARRAY_LEN(x) ((int) (sizeof (x)) / (sizeof ((x) [0])))
+#define SIGNED_SIZEOF(x) ((int64_t) (sizeof (x)))
+
+#define PIPE_INDEX(x) ((x) + 500)
+#define PIPE_TEST_LEN 12345
+
+#if (defined (WIN32) || defined (_WIN32))
+#define snprintf _snprintf
+#endif
+
+[+ FOR float_type
++]void gen_windowed_sine_[+ (get "name") +] ([+ (get "name") +] *data, int len, double maximum) ;
+[+ ENDFOR float_type
++]
+
+void check_file_hash_or_die (const char *filename, unsigned int target_hash, int line_num) ;
+
+void print_test_name (const char *test, const char *filename) ;
+
+void dump_data_to_file (const char *filename, void *data, unsigned int datalen) ;
+
+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 */
+
+/*
+** 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") +] ([+ (get "io_element") +] *a, [+ (get "io_element") +] *b, int len) ;
+[+ ENDFOR io_type
++]
+
+void delete_file (int format, const char *filename) ;
+
+void count_open_files (void) ;
+void increment_open_file_count (void) ;
+void check_open_file_count_or_die (int lineno) ;
+
+#ifdef SNDFILE_H
+
+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) ;
+
+
+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 +]
+
+[+ 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 +]
+
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+[+ == c +]
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if (HAVE_DECL_S_IRGRP == 0)
+#include <sf_unistd.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846264338
+#endif
+
+#define LOG_BUFFER_SIZE 2048
+
+[+ 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") +])) ;
+ /*
+ ** Choose a frequency of 1/32 so that it aligns perfectly with a DFT
+ ** bucket to minimise spreading of energy over more than one bucket.
+ ** Also do not want to make the frequency too high as some of the
+ ** codecs (ie gsm610) have a quite severe high frequency roll off.
+ */
+ len /= 2 ;
+
+ 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
+check_file_hash_or_die (const char *filename, unsigned int target_hash, int line_num)
+{ static unsigned char buffer [2048] ;
+ unsigned int hash1, hash2 ;
+ FILE *file ;
+ int k, read_count ;
+
+ memset (buffer, 0xEE, sizeof (buffer)) ;
+
+ /* The 'b' in the mode string means binary for Win32. */
+ if (! (file = fopen (filename, "rb")))
+ { printf ("\n\nLine %d: could not open file '%s'\n\n", line_num, filename) ;
+ exit (1) ;
+ } ;
+
+ hash1 = hash2 = 0 ;
+
+ while ((read_count = fread (buffer, 1, sizeof (buffer), file)))
+ { for (k = 0 ; k < read_count ; k++)
+ { hash1 = hash1 + buffer [k] ;
+ hash2 = hash2 ^ (buffer [k] << (k % 25)) ;
+ } ;
+ } ;
+
+ fclose (file) ;
+
+ hash1 += hash2 ;
+
+ if (target_hash == 0)
+ { printf (" 0x%08x ", hash1) ;
+ return ;
+ } ;
+
+ if (hash1 != target_hash)
+ { printf ("\n\nLine %d: incorrect hash value 0x%08x should be 0x%08x\n\n", line_num, hash1, 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 || filename == NULL)
+ { printf (__FILE__ ": bad test of filename parameter.\n") ;
+ exit (1) ;
+ } ;
+
+ printf (" %-25s : %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, 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") +] ([+ (get "io_element") +] *a, [+ (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") +], 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") +], 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, LOG_BUFFER_SIZE) ;
+
+ /* 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, LOG_BUFFER_SIZE) ;
+
+ /* 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 (%ld) too long.\n\n", SF_COUNT_TO_LONG (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, %ld, SEEK_SET) failed : %s\n\n", SF_COUNT_TO_LONG (offset), strerror (errno)) ;
+ exit (1) ;
+ } ;
+
+ puts ("\n\n") ;
+
+ for (k = 0 ; k < length ; k+= sizeof (buffer))
+ { readcount = fread (buffer, 1, sizeof (buffer), file) ;
+
+ printf ("%08lx : ", SF_COUNT_TO_LONG (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] ;
+ int count ;
+
+ memset (buffer, 0, LOG_BUFFER_SIZE) ;
+
+ /* Get the log buffer data. */
+ count = 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 */
+
+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 ;
+
+ /*
+ ** Need to test both sf_open() and sf_open_fd().
+ ** Do so alternately.
+ */
+ switch (mode)
+ { case SFM_READ :
+ modestr = "SFM_READ" ;
+ oflags = O_RDONLY ;
+ omode = 0 ;
+ break ;
+
+ case SFM_WRITE :
+ modestr = "SFM_WRITE" ;
+ oflags = O_WRONLY | O_CREAT | O_TRUNC ;
+ omode = S_IRUSR | S_IWUSR | S_IRGRP ;
+ break ;
+
+ case SFM_RDWR :
+ modestr = "SFM_RDWR" ;
+ oflags = O_RDWR | O_CREAT ;
+ omode = S_IRUSR | S_IWUSR | S_IRGRP ;
+ break ;
+ default :
+ printf ("\n\nLine %d: Bad mode.\n", line_num) ;
+ fflush (stdout) ;
+ exit (1) ;
+ } ;
+
+#if (defined (WIN32) || defined (_WIN32))
+ /* Stupid fscking windows. */
+ oflags |= O_BINARY ;
+#endif
+
+ if (allow_fd && ((++count) & 1) == 1)
+ { int fd ;
+
+ if (omode == 0)
+ fd = open (filename, oflags) ;
+ else
+ fd = open (filename, oflags, omode) ;
+
+ if (fd < 0)
+ { perror ("open") ;
+ 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) ;
+ } ;
+
+ 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 (%ld) should be %ld.\n", SF_COUNT_TO_LONG (pos), SF_COUNT_TO_LONG (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 (%ld) should be %ld.\n",
+ SF_COUNT_TO_LONG (pos), SF_COUNT_TO_LONG (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, %ld, %s) returned %ld (should be %ld).\n\n",
+ line_num, channel_name, SF_COUNT_TO_LONG (offset), whence_name,
+ SF_COUNT_TO_LONG (position), SF_COUNT_TO_LONG (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") +] (%ld => %ld).\n",
+ SF_COUNT_TO_LONG ([+ (get "count_name") +]), SF_COUNT_TO_LONG (count)) ;
+ fflush (stdout) ;
+ puts (sf_strerror (file)) ;
+ exit (1) ;
+ } ;
+
+ return ;
+} /* test_[+ (get "op_element") +]_[+ (get "io_element") +] */
+[+ ENDFOR io_type +][+ ENDFOR read_op +]
+
+[+ 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") +] (%ld => %ld).\n",
+ SF_COUNT_TO_LONG ([+ (get "count_name") +]), SF_COUNT_TO_LONG (count)) ;
+ fflush (stdout) ;
+ puts (sf_strerror (file)) ;
+ exit (1) ;
+ } ;
+
+ return ;
+} /* test_[+ (get "op_element") +]_[+ (get "io_element") +] */
+[+ ENDFOR io_type +][+ ENDFOR write_op +]
+
+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 */
+
+static int allowed_open_files = -1 ;
+
+void
+count_open_files (void)
+{
+#if (defined (WIN32) || defined (_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 (defined (WIN32) || defined (_WIN32))
+ lineno = 0 ;
+ 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 */
+
+[+ ESAC +]
+
+[+ COMMENT
+
+ Do not edit or modify anything in this comment block.
+ The following line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: b1183d5d-ebd4-4bc5-af50-60d774d6b1f5
+
++]
diff --git a/tests/virtual_io_test.c b/tests/virtual_io_test.c
new file mode 100644
index 0000000..90fb6db
--- /dev/null
+++ b/tests/virtual_io_test.c
@@ -0,0 +1,238 @@
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <fcntl.h>
+#include <math.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include <sndfile.h>
+
+#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) ;
+
+ 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 brack 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) ;
+ } ;
+
+ 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, 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 */
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 5569fa52-15dd-496f-ab47-1fd42d76195d
+*/
diff --git a/tests/win32_ordinal_test.c b/tests/win32_ordinal_test.c
new file mode 100644
index 0000000..9719dbf
--- /dev/null
+++ b/tests/win32_ordinal_test.c
@@ -0,0 +1,146 @@
+/*
+** Copyright (C) 2006, 2007 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+#include "sndfile.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if (HAVE_DECL_S_IRGRP == 0)
+#include <sf_unistd.h>
+#endif
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+
+#include "utils.h"
+
+#if (defined (WIN32) || defined (_WIN32) || defined (__CYGWIN__))
+#define TEST_WIN32 1
+#else
+#define TEST_WIN32 0
+#endif
+
+#if TEST_WIN32
+#include <windows.h>
+
+#ifdef __CYGWIN__
+#define DLL_NAME "cygsndfile"
+#else
+#define DLL_NAME "libsndfile"
+#endif
+
+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) ;
+
+ ord = GetProcAddress (hmod, (LPSTR) 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/%s.def", locations [k], DLL_NAME) ;
+ 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/%s-1.dll", locations [k], DLL_NAME) ;
+ if ((hmod = (HMODULE) LoadLibrary (buffer)) != NULL)
+ break ;
+ } ;
+
+ if (hmod == NULL)
+ { puts ("\n\nError : cannot load DLL.\n") ;
+ 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/tests/win32_test.c b/tests/win32_test.c
new file mode 100644
index 0000000..ba903f1
--- /dev/null
+++ b/tests/win32_test.c
@@ -0,0 +1,235 @@
+/*
+** Copyright (C) 2001-2004 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+#include "sndfile.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if (HAVE_DECL_S_IRGRP == 0)
+#include <sf_unistd.h>
+#endif
+
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define SIGNED_SIZEOF(x) ((int) sizeof (x))
+
+#if defined (__CYGWIN__)
+
+ #define LSEEK lseek
+ #define FSTAT fstat
+
+ typedef struct stat STATBUF ;
+ typedef off_t INT64 ;
+
+ static char dir_cmd [] = "ls -l" ;
+
+ #define COMPILE_FULL_TEST 1
+#elif (defined (WIN32) || defined (_WIN32))
+
+ #define LSEEK _lseeki64
+ #define FSTAT _fstati64
+
+ typedef struct _stati64 STATBUF ;
+ typedef __int64 INT64 ;
+
+ static char dir_cmd [] = "dir" ;
+
+ #define COMPILE_FULL_TEST 1
+#elif defined (linux)
+
+ #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" ;
+
+ #define COMPILE_FULL_TEST 1
+#else
+ #define COMPILE_FULL_TEST 0
+#endif
+
+#if COMPILE_FULL_TEST
+static void show_fstat_error (void) ;
+static void show_lseek_error (void) ;
+
+int
+main (void)
+{ puts ("\n\n\n\n"
+ "This program shows up some errors in the Win32 implementation of\n"
+ "a couple of POSIX API functions. It can also be compiled on Linux\n"
+ "(which works correctly) just to provide a sanity check.\n"
+ ) ;
+
+ show_fstat_error () ;
+ show_lseek_error () ;
+
+ 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 ;
+ } ;
+ write (fd, data, sizeof (data)) ;
+ 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) ;
+ write (fd, data, sizeof (data)) ;
+
+ printf ("2) Now use system (\"%s %s\") to show the file length.\n\n", dir_cmd, filename) ;
+ sprintf (data, "%s %s", dir_cmd, filename) ;
+ system (data) ;
+ 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 ;
+ } ;
+ write (fd, data, sizeof (data)) ;
+ 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) ;
+ write (fd, data, sizeof (data)) ;
+
+ printf ("2) Now use system (\"%s %s\") to show the file length.\n\n", dir_cmd, filename) ;
+ sprintf (data, "%s %s", dir_cmd, filename) ;
+ system (data) ;
+ 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 */
+
+#else
+
+int
+main (void)
+{ puts ("\n"
+ "This program shows up some errors in the Win32 implementation of\n"
+ "a couple of POSIX API functions. It can also be compiled on Linux\n"
+ "and under Cygwin32 (which both work correctly) just to provide a \n"
+ "sanity check.\n"
+ "Unfortunately, it does not compile on this platform."
+ ) ;
+
+ return 0 ;
+} /* main */
+
+#endif
+
+
+
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 228b9a18-0555-46d9-b9e6-2b37ce048702
+*/
diff --git a/tests/write_read_test.def b/tests/write_read_test.def
new file mode 100644
index 0000000..524e86a
--- /dev/null
+++ b/tests/write_read_test.def
@@ -0,0 +1,73 @@
+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 = "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 */
+/*
+** Do not edit or modify anything in this comment block.
+** The arch-tag line is a file identity tag for the GNU Arch
+** revision control system.
+**
+** arch-tag: 624d498a-9ea1-46b5-a386-c1c2261cfce3
+*/
+
diff --git a/tests/write_read_test.tpl b/tests/write_read_test.tpl
new file mode 100644
index 0000000..0100b3b
--- /dev/null
+++ b/tests/write_read_test.tpl
@@ -0,0 +1,1026 @@
+[+ AutoGen5 template c +]
+/*
+** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.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.
+*/
+
+#include "sfconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <math.h>
+
+#if (defined (WIN32) || defined (_WIN32))
+#include <fcntl.h>
+static int truncate (const char *filename, int ignored) ;
+#endif
+
+#include <sndfile.h>
+
+#include "utils.h"
+
+#define SAMPLE_RATE 11025
+#define DATA_LENGTH (1<<12)
+
+#define SILLY_WRITE_COUNT (234)
+
+[+ FOR data_type
++]static void pcm_test_[+ (get "type_name") +] (const char *str, int format, int long_file_okz) ;
+[+ 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 <test>\n", argv [0]) ;
+ printf (" Where <test> 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 (" 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) ;
+ /* 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], "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_TRUE) ;
+ pcm_test_short ("short.sds" , SF_FORMAT_SDS | SF_FORMAT_PCM_16, SF_TRUE) ;
+ pcm_test_24bit ("24bit.sds" , SF_FORMAT_SDS | SF_FORMAT_PCM_24, SF_TRUE) ;
+ 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) ;
+ test_count++ ;
+ } ;
+
+ if (do_all || ! strcmp (argv [1], "flac"))
+ { 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) ;
+ 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 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
+pcm_test_[+ (get "type_name") +] (const char *filename, int format, int long_file_ok)
+{ SF_INFO sfinfo ;
+ [+ (get "data_type") +] *orig, *test ;
+ int k, items, 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 ;
+
+ 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 ;
+
+ 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 ;
+
+ /* 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)
+ 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)
+ 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 ;
+
+ 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__) ;
+
+ 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). (%ld should be %d)\n", __LINE__, SF_COUNT_TO_LONG (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). (%ld should be %d)\n", __LINE__, SF_COUNT_TO_LONG (sfinfo.frames), items) ;
+ exit (1) ;
+ } ;
+
+ if (sfinfo.channels != 1)
+ { printf ("\n\nLine %d : Mono : Incorrect number of channels in file.\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]) ;
+ 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) ;
+ } ;
+
+ 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 (%ld should be %ld)\n", __LINE__, (long) count, (long) sfinfo.frames) ;
+ exit (1) ;
+ } ;
+
+ test_seek_or_die (file, 0, SEEK_CUR, sfinfo.frames, sfinfo.channels, __LINE__) ;
+
+ sf_close (file) ;
+
+} /* 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). (%ld should be %d)\n",
+ __LINE__, SF_COUNT_TO_LONG (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). (%ld should be %d)\n",
+ __LINE__, SF_COUNT_TO_LONG (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 ;
+
+ 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 (filename, 0) < 0)
+ { printf ("\n\nLine %d: truncate (%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): 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. (%ld < %d)\n", __LINE__, SF_COUNT_TO_LONG (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. (%ld should be %d)\n", __LINE__, SF_COUNT_TO_LONG (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): 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 (%ld shold be %d)\n\n", __LINE__, SF_COUNT_TO_LONG (sfinfo.frames), 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 ;
+
+ print_test_name ("empty_file_test", filename) ;
+
+ unlink (filename) ;
+
+ info.samplerate = 48000 ;
+ info.channels = 2 ;
+ info.format = format ;
+
+ 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 (SF_COUNT_TO_LONG (info.frames) != 0)
+ { printf ("\n\nError : frame count (%ld) should be zero.\n", SF_COUNT_TO_LONG (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 (SF_COUNT_TO_LONG (info.frames) != 0)
+ { printf ("\n\nError : frame count (%ld) should be zero.\n", SF_COUNT_TO_LONG (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 (SF_COUNT_TO_LONG (info.frames) != 0)
+ { printf ("\n\nError : frame count (%ld) should be zero.\n", SF_COUNT_TO_LONG (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 */
+
+#if (defined (WIN32) || defined (__WIN32))
+
+/* Win32 does not have truncate (nor does it have the POSIX function ftruncate).
+** Hack somethng up here to over come this. This function can only truncate to a
+** length of zero.
+*/
+
+static int
+truncate (const char *filename, int ignored)
+{ int fd ;
+
+ ignored = 0 ;
+
+ if ((fd = open (filename, O_RDWR | O_TRUNC | O_BINARY)) < 0)
+ return 0 ;
+
+ close (fd) ;
+
+ return 0 ;
+} /* truncate */
+
+#endif
+
+[+ COMMENT
+
+ Do not edit or modify anything in this comment block.
+ The following line is a file identity tag for the GNU Arch
+ revision control system.
+
+ arch-tag: 4187de93-d434-41a2-93a9-4f6e2995b5c1
+
++]