Dependencies: Update BASS and WavPack libraries
BASSMIDI: 2.4.15.3 BASSFLAC: 2.4.5.5 BASSOPUS: 2.4.3 BASSWV: 2.4.7.4 WavPack: 5.8.1 And updated the WavPack plugin to support threaded decoding, using up to four worker threads, as detected from the host machine's CPU count. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
parent
c4a5c8f45b
commit
a708851b63
54 changed files with 116 additions and 21020 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -53,3 +53,4 @@ Xcode-config/SENTRY_SETTINGS.xcconfig
|
|||
/ThirdParty/vorbis/lib/libvorbisfile.3.dylib
|
||||
/ThirdParty/vorbis/lib/libvorbis.0.dylib
|
||||
/ThirdParty/soxr/lib/libsoxr.0.dylib
|
||||
/ThirdParty/WavPack/lib/libwavpack.a
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
David Bryant <david@wavpack.com>
|
||||
Sebastian Dröge <slomo@circular-chaos.org>
|
||||
Joachim Henke <j-o@users.sourceforge.net>
|
||||
Joël R. Langlois <joel.r.langlois@gmail.com>
|
||||
Alexis Ballier <aballier@gentoo.org>
|
||||
Stephen <stephengroat@users.noreply.github.com>
|
||||
Phil Eichinger <phil@zankapfel.net>
|
||||
Sebastian Ramacher <sramacher@debian.org>
|
||||
luxagen <hello@luxagen.com>
|
||||
Martin Koegler <martin.koegler@chello.at>
|
||||
nu774 <honeycomb77@gmail.com>
|
|
@ -1,366 +0,0 @@
|
|||
2019-12-14 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/wvunpack.c
|
||||
-s option: add "5.1 surround side" and "7.1 surround" to reported channel configurations
|
||||
|
||||
2019-12-13 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/riff[_write].c, cli/wave64[_write].c, cli/caff[_write].c, cli/dsf[_write].c, cli/dsdiff[_write].c:
|
||||
split header readers & writers so that wvunpack doesn't link libwavpack encoder
|
||||
|
||||
2019-12-12 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/riff.c, cli/wave64.c, cli/caff.c:
|
||||
-i option: display warning when dropping PCM samples from end of file
|
||||
|
||||
2019-12-11 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/wavpack.c:
|
||||
fix a WAV header if user specified -i (to ignore length) and we can make it valid
|
||||
|
||||
2019-12-08 David Bryant <david@wavpack.com>
|
||||
|
||||
* fuzzing/fuzzer.cc, fuzzing/fuzzer_seed_corpus.zip, etc...:
|
||||
add fuzzing directory with corpus and other files for oss-fuzz
|
||||
|
||||
2019-12-08 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/open_utils.c:
|
||||
fix possible memory leak on opening corrupted files
|
||||
|
||||
2019-12-08 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/common_utils.c, src/pack_dsd.c, src/unpack_dsd.c, src/wavpack_local.h:
|
||||
- fix potential memory leak when seeking in DSD files
|
||||
- simplify DSD fast mode lookup buffer allocations
|
||||
|
||||
2019-12-08 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/unpack.c, src/unpack_dsd.c, src/unpack_seek.c:
|
||||
seeking fixes:
|
||||
- fix crash during seek to corrupted block
|
||||
- check header size before malloc()
|
||||
- fix overlapping memcpy()
|
||||
|
||||
2019-11-30 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/pack.c:
|
||||
- provide more configuration sanity checks to aid application debugging
|
||||
- force max_blocksize even so bitstream buffer overflow detection works
|
||||
|
||||
2019-04-09 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/import_id3.c:
|
||||
issue #69: add TPUB (Publisher) to accepted ID3v2 tag fields
|
||||
|
||||
2019-03-05 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/wave64.c:
|
||||
issue #68: clear WaveHeader at start to prevent uninitialized read
|
||||
|
||||
2019-03-05 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/dsdiff.c:
|
||||
issue #67: make sure sample rate is specified and non-zero in DFF files
|
||||
|
||||
2019-03-04 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/caff.c:
|
||||
issue #66: make sure CAF files have a "desc" chunk
|
||||
|
||||
2019-03-02 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/dsdiff.c:
|
||||
issue #65: makre sure DSDIFF files have a valid channel count
|
||||
|
||||
2018-12-23 evpobr <evpobr@gmail.com>
|
||||
|
||||
* include/wavpack.h src/wavpack_local.h:
|
||||
remove duplication so that wavpack_local.h can include wavpack.h
|
||||
|
||||
2018-12-16 evpobr <evpobr@gmail.com>
|
||||
|
||||
* Makefile.am, CMakeLists.txt
|
||||
add CMake project
|
||||
|
||||
2018-12-09 orbea <orbea@fredslev.dk>
|
||||
|
||||
* cli/Makefile.am:
|
||||
fix command-line builds with slibtool
|
||||
|
||||
2018-12-08 Ørjan Malde <foxyred333@gmail.com>
|
||||
|
||||
* src/extra[12].c, src/pack.c, src/pack_x64.S, src/unpack.c, src/unpack_x64.S, src/wavpack_local.h:
|
||||
x64 ASM support for midipix
|
||||
|
||||
2018-11-29 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/pack_utils.c:
|
||||
issue #53: error on zero sample rate
|
||||
- CVE-2018-19840
|
||||
|
||||
2018-11-29 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/open_utils.c:
|
||||
issue #54: fix potential out-of-bounds heap read
|
||||
- CVE-2018-19841
|
||||
|
||||
2018-11-29 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/open_filename.c:
|
||||
Windows only: use wvc file when verifying encode when source is stdin
|
||||
|
||||
2018-09-03 Mike Tzou <Chocobo1@users.noreply.github.com>
|
||||
|
||||
* cli/import_id3.c, cli/wvgain.c, cli/open_raw.c, cli/wvparser.c, cli/wvunpack.c, winamp/in_wv.c:
|
||||
printf() format specifiers
|
||||
memory leaks
|
||||
|
||||
2018-08-26 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/dsdiff.c, cli/dsf.c, cli/caff.c:
|
||||
issue #41 issue #42 issue #43: sanitize input files to prevent crashes
|
||||
|
||||
2018-06-02 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/unpack_armv7.S:
|
||||
fix thumb interworking on ARM by adding .type for assembly functions
|
||||
|
||||
2018-04-30 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/import_id3.c, cli/wavpack.c:
|
||||
allow ID3v2.3 tag import from any file type (not just DSF)
|
||||
|
||||
2018-04-29 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/import_id3.c:
|
||||
handle ID3v2.3 TXXX tags using description for APEv2 item name (w/ case formatting)
|
||||
|
||||
2018-04-24 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/riff.c, cli/wave64.c:
|
||||
issue #30 issue #31 issue #32: no multiple format chunks in WAV or W64
|
||||
- CVE-2018-10536
|
||||
- CVE-2018-10537
|
||||
|
||||
* cli/dsdiff.c, cli/riff.c, cli/wave64.c:
|
||||
issue #33, sanitize size of unknown chunks before malloc()
|
||||
- CVE-2018-10538
|
||||
- CVE-2018-10539
|
||||
- CVE-2018-10540
|
||||
|
||||
2018-04-17 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/import_id3.c:
|
||||
add a bunch more ID3v2.3 tag entries
|
||||
make ImportID3v2() more robust (e.g. always set bytes_used)
|
||||
|
||||
2018-04-08 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/common_utils.c:
|
||||
fix memory leaks
|
||||
|
||||
2018-02-11 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/caff.c:
|
||||
issue #26, fix buffer overflows and bad allocs on corrupt CAF files
|
||||
- CVE-2018-7254
|
||||
|
||||
2018-02-10 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/dsdiff.c:
|
||||
issue #28, do not overwrite heap on corrupt DSDIFF file
|
||||
- CVE-2018-7253
|
||||
|
||||
2018-02-04 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/riff.c:
|
||||
issue #27, do not overwrite stack on corrupt RF64 file
|
||||
- CVE-2018-6767
|
||||
|
||||
2017-10-29 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/read_words.c:
|
||||
issue #24, another C++ compiler fix, this time for _BitScanForward()
|
||||
|
||||
2017-10-28 David Bryant <david@wavpack.com>
|
||||
|
||||
* Makefile.am:
|
||||
add README.md to extra distribution files
|
||||
|
||||
2017-10-20 Joël R. Langlois <joel.r.langlois@gmail.com>
|
||||
|
||||
* README, README.md:
|
||||
Updated README to Markdown format.
|
||||
|
||||
2017-10-12 Joël R. Langlois <joel.r.langlois@gmail.com>
|
||||
|
||||
* src/decorr_utils.c, src/entropy_utils.c, src/open_legacy.c,
|
||||
src/open_utils.c, src/tag_utils.c, src/tags.c, src/unpack3.c,
|
||||
src/unpack3_open.c, src/unpack_dsd.c, src/unpack_seek.c,
|
||||
src/unpack_utils.c:
|
||||
Fixed errors when compiling using a C++ compiler.
|
||||
|
||||
2017-09-30 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/import_id3.c:
|
||||
experimental fix to handle ID3v2.3 tags that [incorrectly] use synchsafe for the frame size
|
||||
|
||||
2017-08-31 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/wavpack.c
|
||||
briefly describe other utilities in help displays for wavpack
|
||||
|
||||
2017-07-24 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/md5.h
|
||||
do not try to use libcrypto on OS X
|
||||
|
||||
2017-07-23 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/md5.c, cli/md5.h, cli/wavpack.c, cli/wvtest.c, cli/wvunpack.c, configure.ac:
|
||||
use Alexander Peslyak's MD5 implementation (or libcrypto if present) to fix
|
||||
unaligned access coredump on OpenBSD/sparc64 (reported on openbsd-ports)
|
||||
|
||||
2017-03-19 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/write_words.c:
|
||||
improve quality of scan_word() results on very short blocks (via multiple passes)
|
||||
|
||||
2017-03-01 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/wavpack.c, cli/wvgain.c, cli/wvtag.c, cli/wvunpack.c:
|
||||
add required parens to correct precedence error/warning
|
||||
|
||||
2017-02-26 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/wavpack.c, cli/wvgain.c, cli/wvtag.c, cli/wvunpack.c:
|
||||
refactor debug logging mode so that we can turn on a forced arg dump
|
||||
|
||||
* src/common_utils.c, src/wavpack_local.h:
|
||||
provide for a "close" callback to be installed for dumping accumulated statistics
|
||||
|
||||
* configure.ac, src/unpack_armv7.S:
|
||||
SSAT instruction required armv6, now we should work on all ARMs using a pair of shifts instead
|
||||
|
||||
2017-02-18 Alexis Ballier <aballier@gentoo.org>
|
||||
|
||||
* configure.ac:
|
||||
configure: Restrict arm assembly to armv7 only.
|
||||
ARM assembly in wavpack is armv7 only it seems.
|
||||
I have reports this causes build failures on armv5: https://bugs.gentoo.org/show_bug.cgi?id=609168
|
||||
|
||||
2017-02-16 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/import_id3.c, cli/wvtag.c:
|
||||
fix GitHub issue #19 (new dependency on wchar_t) by removing dependency
|
||||
|
||||
2017-01-22 David Bryant <david@wavpack.com>
|
||||
|
||||
* .travis.yml:
|
||||
do more exhaustive testing for Travis (but should be faster)
|
||||
|
||||
2017-01-22 Stephen <stephengroat@users.noreply.github.com>
|
||||
|
||||
* .travis.yml:
|
||||
enable travis ci build and testing (#17)
|
||||
Create .travis.yml
|
||||
fix for running tests
|
||||
limit to smaller test suite
|
||||
add quotes to get spaces in arg
|
||||
remove linux clang builds
|
||||
move to trusty for clang
|
||||
|
||||
2017-01-18 David Bryant <david@wavpack.com>
|
||||
|
||||
* ChangeLog:
|
||||
refine change log and add updated plugins
|
||||
|
||||
* audition/cool_wv4.c, audition/readme.odt, audition/readme.pdf:
|
||||
update Cool Edit / Audition filter to 3.1
|
||||
|
||||
* COPYING, license.txt, winamp/in_wv.c, winamp/installer/WavPackPlugin1.nsi:
|
||||
update winamp to 2.8.0.3 and license dates
|
||||
|
||||
2017-01-17 David Bryant <david@wavpack.com>
|
||||
|
||||
* ChangeLog:
|
||||
first pass at 5.1.0 changelog
|
||||
|
||||
* cli/Makefile.am, cli/import_id3.c, cli/wavpack.c:
|
||||
fix Darwin build (iconv) and ptr warnings
|
||||
improve --import-id3 console messaging
|
||||
|
||||
2017-01-16 David Bryant <david@wavpack.com>
|
||||
|
||||
* wavpackdll/wavpackdll.rc, wavpackexe/wavpack.vcproj, winamp/in_wv.c:
|
||||
bump DLL version and fix MSVC build
|
||||
|
||||
* cli/utils.h, cli/wavpack.c, cli/wvgain.c, cli/wvtag.c, cli/wvunpack.c,
|
||||
configure.ac, src/wavpack_version.h:
|
||||
update version to 5.1.0 and bump some copyright dates
|
||||
|
||||
* src/pack.c:
|
||||
do not write data in NEW_CONFIG_BLOCK for "do not care" bits in qmode
|
||||
|
||||
* src/unpack_dsd.c:
|
||||
shorter DSD decimation filter with less HF rolloff and lower CPU use
|
||||
|
||||
2017-01-15 David Bryant <david@wavpack.com>
|
||||
|
||||
* doc/wavpack_doc.html:
|
||||
update user manual for 5.1.0 and wvtag
|
||||
|
||||
2017-01-14 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/wvtag.c:
|
||||
allow multiple files on Windows, update "help"
|
||||
|
||||
* man/Makefile.am, man/wavpack.1, man/wavpack.xml, man/wvgain.1, man/wvgain.xml,
|
||||
man/wvtag.1, man/wvtag.xml, man/wvunpack.1, man/wvunpack.xml:
|
||||
add man page for wvtag and update the other man pages (--import-id3)
|
||||
|
||||
2017-01-13 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/Makefile.am, cli/wavpack.c:
|
||||
add --import-id3 option to wavpack executable
|
||||
(works with original DSF files and when transcoding)
|
||||
|
||||
* cli/import_id3.c, cli/wvtag.c:
|
||||
refactor ID3 import code to calculate the total number of bytes being imported
|
||||
- allow total size and item count to be returned even on dry runs
|
||||
- plug a memory leak in the dry run
|
||||
|
||||
2017-01-11 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/pack.c, src/unpack.c:
|
||||
fix issue where noise-shaping falsely triggers lossy muting
|
||||
- only in very rare cases (detected with pathological testing)
|
||||
- also fix (again) macro that disables lossy muting
|
||||
|
||||
2017-01-08 David Bryant <david@wavpack.com>
|
||||
|
||||
* src/pack_utils.c:
|
||||
fix regression causing non-byte-aligned audio (e.g., 12-bit)
|
||||
to lose the actual reduced bit-depth indication (although
|
||||
there was no effect on integrity or compression ratio)
|
||||
|
||||
2017-01-07 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/import_id3.c, cli/wvtag.c, wavpack.sln, wvtagexe/wvtag.vcproj:
|
||||
add wvtag to MSVC build and fix warnings (and one mistake)
|
||||
|
||||
* src/open_filename.c:
|
||||
fix MSVC build (broken by portability enhancements...sigh)
|
||||
|
||||
2017-01-06 David Bryant <david@wavpack.com>
|
||||
|
||||
* cli/Makefile.am, cli/import_id3.c, cli/wvtag.c:
|
||||
new cli tool "wvtag" to manipulate APEv2 tags on existing WavPack files
|
||||
(includes new facility to import ID3v2.3 tag items from Sony DSF files)
|
||||
|
||||
* cli/wavpack.c:
|
||||
add --pre-quantize-round to settings tag
|
||||
|
||||
* cli/wvgain.c, cli/wvunpack.c:
|
||||
copy TextToUTF8() BOM fix into other modules that use it for filename lists
|
|
@ -1,717 +0,0 @@
|
|||
---------------------------------
|
||||
Release 5.2.0 - December 15, 2019
|
||||
---------------------------------
|
||||
|
||||
WavPack Library Source Code - 5.2.0
|
||||
wavpack.exe (command-line encoder) - 5.2.0
|
||||
wvunpack.exe (command-line decoder) - 5.2.0
|
||||
wvgain.exe (command-line ReplayGain scanner) - 5.2.0
|
||||
wvtag.exe (command-line tagging utility) - 5.2.0
|
||||
----------------------------------------------------
|
||||
fixed: potential security issues including the following CVEs:
|
||||
CVE-2018-19840 CVE-2018-19841 CVE-2018-10536
|
||||
CVE-2018-10537 CVE-2018-10538 CVE-2018-10539
|
||||
CVE-2018-10540 CVE-2018-7254 CVE-2018-7253
|
||||
CVE-2018-6767
|
||||
added: support for CMake, Travis CI, and Google's OSS-fuzz
|
||||
fixed: use correction file for encode verify (pipe input, Windows)
|
||||
fixed: correct WAV header with actual length (pipe input, -i option)
|
||||
fixed: thumb interworking and not needing v6 architecture (ARM asm)
|
||||
added: handle more ID3v2.3 tag items and from all file types
|
||||
fixed: coredump on Sparc64 (changed MD5 implementation)
|
||||
fixed: handle invalid ID3v2.3 tags from sacd-ripper
|
||||
fixed: several corner-case memory leaks
|
||||
|
||||
|
||||
--------------------------------
|
||||
Release 5.1.0 - January 18, 2017
|
||||
--------------------------------
|
||||
|
||||
WavPack Library Source Code - 5.1.0
|
||||
wavpack.exe (command-line encoder) - 5.1.0
|
||||
wvunpack.exe (command-line decoder) - 5.1.0
|
||||
wvgain.exe (command-line ReplayGain scanner) - 5.1.0
|
||||
wvtag.exe (command-line tagging utility) - 5.1.0
|
||||
----------------------------------------------------
|
||||
added: all new command-line tagging utility (wvtag)
|
||||
added: option to import ID3v2.3 tags from Sony DSF files
|
||||
fixed: fuzz test failures from AFL reported on SourceForge
|
||||
improved: DSD decimation filter (less HF rolloff & CPU use)
|
||||
fixed: non-byte audio depths (12-bit, 20-bit) not showing
|
||||
fixed: rare case of noise-shaping triggering a lossy mute
|
||||
fixed: recognize UTF-8 BOM when reading text files
|
||||
fixed: a few portability issues
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.8.0.3
|
||||
CoreWavPack DirectShow Filters - 1.5.1.0
|
||||
AmioWavpack.amio (Adobe Audition Plugins) - 2.1
|
||||
cool_wv4.flt (Cool Edit / Audition filter) - 3.1
|
||||
------------------------------------------------
|
||||
updated: see 5.1.0 library changes
|
||||
|
||||
|
||||
--------------------------------
|
||||
Release 5.0.0 - December 6, 2016
|
||||
--------------------------------
|
||||
|
||||
WavPack Library Source Code - 5.0.0
|
||||
wavpack.exe (command-line encoder) - 5.0.0
|
||||
wvunpack.exe (command-line decoder) - 5.0.0
|
||||
wvgain.exe (command-line ReplayGain scanner) - 5.0.0
|
||||
----------------------------------------------------
|
||||
added: multiple input formats, including RF64, Wave64, and CAF
|
||||
added: lossless DSD audio in Philips DSDIFF and Sony DSF files
|
||||
fixed: seeking in > 2GB WavPack files (new stream reader)
|
||||
fixed: accept > 4GB source audio files (all formats)
|
||||
improved: increase maximum samples from 2^32 to 2^40
|
||||
added: block checksums for robustness to corruption
|
||||
added: support for non-standard channel identities
|
||||
removed: support for legacy WavPack files (< 4.0)
|
||||
added: block decoder for streaming applications
|
||||
fixed: many small fixes and improvements
|
||||
added: all new pdf documentation
|
||||
|
||||
AmioWavpack.amio (Adobe Audition Plugins) - 2.0
|
||||
-----------------------------------------------
|
||||
improved: all new dialog for WavPack settings
|
||||
fixed: handle unlimited audio file size
|
||||
fixed: save all Amio channel identities
|
||||
added: save/restore APEv2 tags
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.8.0.2
|
||||
CoreWavPack DirectShow Filters - 1.5.0.0
|
||||
cool_wv4.flt (Cool Edit / Audition filter) - 3.0
|
||||
------------------------------------------------
|
||||
updated: see 5.0.0 library changes
|
||||
|
||||
|
||||
-------------------------------
|
||||
Release 4.80.0 - March 28, 2016
|
||||
-------------------------------
|
||||
|
||||
WavPack Library Source Code - 4.80.0
|
||||
wavpack.exe (command-line encoder) - 4.80.0
|
||||
wvunpack.exe (command-line decoder) - 4.80.0
|
||||
wvgain.exe (command-line ReplayGain scanner) - 4.80.0
|
||||
-----------------------------------------------------
|
||||
added: full Unicode support on Windows platform
|
||||
added: new option --pre-quantize to truncate high-resolution files
|
||||
to a reasonable depth (e.g., 20-bit) for better compression
|
||||
fixed: Debian bug #793320 (executable stack)
|
||||
fixed: LargeAddressAware problem reported on HA
|
||||
fixed: several "fuzz test" failures reported on GitHub
|
||||
fixed: repack blocks after possible arithmetic overflows
|
||||
improved: faster assembly code for mono packing
|
||||
improved: portability for various platforms
|
||||
|
||||
wvtest.exe (command-line libwavpack test suite) - 4.80.0
|
||||
--------------------------------------------------------
|
||||
added: exhaustive test for WavpackSeekSample() API
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.8.0.1
|
||||
CoreWavPack DirectShow Filters - 1.3.0.0
|
||||
AmioWavpack.amio (Adobe Audition Plugins) - 1.5
|
||||
cool_wv4.flt (CoolEdit / Audition filter) - 2.14
|
||||
------------------------------------------------
|
||||
updated: see 4.80.0 library changes
|
||||
|
||||
|
||||
--------------------------------
|
||||
Release 4.75.2 - October 1, 2015
|
||||
--------------------------------
|
||||
|
||||
WavPack Library Source Code - 4.75.2
|
||||
------------------------------------
|
||||
fixed: corrupt mono or multichannel files created with assembly code (rare)
|
||||
fixed: building on Clang systems like Darwin and FreeBSD (req. Clang 3.5+)
|
||||
fixed: explicitly sign-extend audio data (< 4-byte) to avoid corrupt files
|
||||
fixed: rare decoding errors due to integer overflow (ARM assembly code)
|
||||
added: assembly optimizations for "extra" mode on mono or multichannel
|
||||
|
||||
wvtest.exe (command-line libwavpack test suite) - 4.75.2
|
||||
--------------------------------------------------------
|
||||
all new program to stress-test libwavpack (requires Pthreads)
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.75.2
|
||||
wvunpack.exe (command-line decoder) - 4.75.2
|
||||
wvgain.exe (command-line ReplayGain scanner) - 4.75.2
|
||||
-----------------------------------------------------
|
||||
fixed: corrupt mono or multichannel files created with assembly code (rare)
|
||||
added: assembly optimizations for "extra" mode on mono or multichannel
|
||||
improved: flush stderr after all writes
|
||||
|
||||
cool_wv4.flt (CoolEdit / Audition filter) - 2.13
|
||||
AmioWavpack.amio (Adobe Audition Plugins) - 1.4
|
||||
------------------------------------------------
|
||||
fixed: corrupt mono or multichannel files (rare)
|
||||
|
||||
|
||||
-----------------------------
|
||||
Release 4.75.0 - May 25, 2015
|
||||
-----------------------------
|
||||
|
||||
WavPack Library Source Code - 4.75.0
|
||||
------------------------------------
|
||||
improved: reorganization for modularity and to improve linking
|
||||
added: assembly optimizations for encode/decode on x86 and x64
|
||||
added: assembly optimizations for decoding on ARMv7 (Linux)
|
||||
improved: several minor speed optimizations using intrinsics
|
||||
fixed: wavpack.pc.in not working correctly on some Linux distros
|
||||
fixed: memcpy() issue causing abort() on OpenBSD
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.75.0
|
||||
wvunpack.exe (command-line decoder) - 4.75.0
|
||||
wvgain.exe (command-line ReplayGain scanner) - 4.75.0
|
||||
-----------------------------------------------------
|
||||
changed: writing to console title default is off (Linux only, -z1 to enable)
|
||||
fixed: wvgain crashes on bad file arguments (Debian bug #716478)
|
||||
|
||||
cool_wv4.flt (CoolEdit / Audition filter) - 2.12
|
||||
------------------------------------------------
|
||||
improved: performance (from assembly optimizations)
|
||||
|
||||
|
||||
-------------------------
|
||||
Update - December 7, 2013
|
||||
-------------------------
|
||||
|
||||
CoreWavPack DirectShow Filters - 1.2.0.2
|
||||
----------------------------------------
|
||||
imported: latest filter sources from Christophe Paris and CoreCodec
|
||||
updated: port to VS 2008 and add 64-bit build platform with installer
|
||||
added: decode streams with full headers (tested with LAV splitter)
|
||||
fixed: issues with 7.1 and non-standard channel configurations
|
||||
fixed: problems with 12-bit, 20-bit, and 32-bit integer audio
|
||||
fixed: crashing bug related to hybrid files with DNS
|
||||
fixed: custom sampling rates being ignored
|
||||
|
||||
|
||||
---------------------------------
|
||||
Release 4.70.0 - October 19, 2013
|
||||
---------------------------------
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.70.0
|
||||
-------------------------------------------
|
||||
added: transcoding from existing WavPack files (with tag copy)
|
||||
added: option to verify WavPack file integrity on creation (-v)
|
||||
added: use temporary files for safer overwriting
|
||||
added: detect UTF-16LE encoding for tag text files (mostly a Windows thing)
|
||||
added: --version command to write machine-parsable value
|
||||
added: option to allow up to 16 MB APEv2 tag data (--allow-huge-tags)
|
||||
added: allow channel-order specification on WAV files with zeroed channel mask
|
||||
added: several Windows features to Linux (clean ^C handling, console title)
|
||||
added: 4GB file support on 32-bit Linux targets
|
||||
|
||||
WavPack Library Source Code - 4.70.0
|
||||
------------------------------------
|
||||
fixed: seeking to last block failure (after finishing file)
|
||||
fixed: memcpy() not always used correctly (Linux targets)
|
||||
fixed: unsigned char issue (ARM targets)
|
||||
fixed: add binary tag functions to Windows DLL exports (forgot on 4.60)
|
||||
added: read-only access to APEv2 tags that come at the beginning of files
|
||||
improved: switched to Microsoft Visual Studio 2008 (win32 only)
|
||||
|
||||
wvunpack.exe (command-line decoder) - 4.70.0
|
||||
--------------------------------------------
|
||||
added: use temporary files for safer overwriting
|
||||
added: --version command to write machine-parsable value
|
||||
added: new command (-f) for getting machine-parsable WavPack file info
|
||||
added: option (-n) to suppress audio decoding (useful for extracting only tags)
|
||||
|
||||
wvgain.exe (command-line ReplayGain scanner) - 4.70.0
|
||||
-----------------------------------------------------
|
||||
fixed: the -q (quiet) option would cause the -c (clean) option to fail
|
||||
added: version command (-v) to write machine-parsable value
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.8
|
||||
-------------------------------
|
||||
fixed: settings could not be saved on newer Windows versions (7 & 8)
|
||||
fixed: installation issue caused by including manifest in build
|
||||
added: dialog to installer suggesting "Winamp Essentials Pack"
|
||||
|
||||
AmioWavpack.amio (Adobe Audition Plugin) - 1.0
|
||||
----------------------------------------------
|
||||
all new plugin for Audition 4.0 (CS5.5) and later (including Audition CC)
|
||||
|
||||
|
||||
--------------------------
|
||||
Update - December 23, 2009
|
||||
--------------------------
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.8a
|
||||
--------------------------------
|
||||
fixed: crashes in winamp 5.57 when playing tracks that have "genre" tag
|
||||
|
||||
|
||||
----------------------------------
|
||||
Release 4.60.1 - November 29, 2009
|
||||
----------------------------------
|
||||
|
||||
WavPack Library Source Code - 4.60.1
|
||||
------------------------------------
|
||||
fixed: filename specs in tag extractions failed in batch operations
|
||||
fixed: prevent creation of APEv2 tags > 1 MB (which we can't read)
|
||||
fixed: crash when decoding old WavPack files (pre version 4.0)
|
||||
added: man pages to build system and updated with newer options
|
||||
added: versioning info to Windows DLL
|
||||
improved: build compatibility (eliminated uchar, ushort types)
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.60.1
|
||||
-------------------------------------------
|
||||
fixed: don't allow user to attempt to place over 1 MB into APEv2 tags
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.7
|
||||
-------------------------------
|
||||
added: read-only support for displaying cover art (thanks Benski!)
|
||||
|
||||
wvunpack.exe (command-line decoder) - 4.60.1
|
||||
wvgain.exe (command-line ReplayGain scanner) - 4.60.1
|
||||
cool_wv4.flt (CoolEdit / Audition filter) - 2.11
|
||||
-----------------------------------------------------
|
||||
(see library changes)
|
||||
|
||||
|
||||
---------------------------------
|
||||
Release 4.60 - September 27, 2009
|
||||
---------------------------------
|
||||
|
||||
WavPack Library Source Code - 4.60
|
||||
----------------------------------
|
||||
added: API for reading & writing binary fields in APEv2 tags
|
||||
fixed: recognize APEv2 tags with footers but no headers
|
||||
fixed: playback of files with 8 streams (15-16 channels)
|
||||
fixed: playback and seeking failed on certain rare correction files
|
||||
fixed: handle case where library makes RIFF header but app adds RIFF trailer
|
||||
improved: channel count limit now virtually unlimited (tested to 256)
|
||||
improved: move all tag functions into new module (tags.c)
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.60
|
||||
-----------------------------------------
|
||||
added: --write-binary-tag command for embedded cover art
|
||||
added: --no-utf8-convert command to skip Unicode character conversions
|
||||
added: --raw-pcm command to specify raw PCM data (samplerate, bitdepth, num chans)
|
||||
added: --channel-order accepts "..." to specify unassigned channels
|
||||
added: --pair-unassigned-chans command to put unassigned channels into stereo pairs
|
||||
|
||||
wvunpack.exe (command-line decoder) - 4.60
|
||||
------------------------------------------
|
||||
added: -x (and -xx) commands for extracting arbitrary tag fields to stdout (and files)
|
||||
added: --no-utf8-convert command to skip Unicode character conversions
|
||||
changed: -ss command no longer dumps multiline tags (use -x instead)
|
||||
improved: formatting of -ss command, also shows information on binary tags
|
||||
|
||||
wvgain.exe (command-line ReplayGain scanner) - 4.60
|
||||
---------------------------------------------------
|
||||
added: -n option for processing new files only (those without ReplayGain info)
|
||||
improved: increase maximum gain value generated from +24 to +64 dB
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.6
|
||||
cool_wv4.flt (CoolEdit / Audition filter) - 2.10
|
||||
------------------------------------------------
|
||||
(see library changes)
|
||||
|
||||
|
||||
-------------------------
|
||||
Update - January 23, 2009
|
||||
-------------------------
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.6b
|
||||
--------------------------------
|
||||
added: "lossless" and "category" to metadata keywords that we handle in winamp plugin
|
||||
added: internationalization support to facilitate inclusion in Winamp Essentials Pack
|
||||
|
||||
|
||||
-----------------------------
|
||||
Release 4.50.1 - July 3, 2008
|
||||
-----------------------------
|
||||
|
||||
WavPack Library Source Code - 4.50.1
|
||||
------------------------------------
|
||||
fixed: alignment fault when manipulating APEv2 tags (non-x86 only)
|
||||
fixed: build on UNIX via elimination of non-standard strnlen()
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.50.1
|
||||
wvunpack.exe (command-line decoder) - 4.50.1
|
||||
--------------------------------------------
|
||||
fixed: checking return value of iconv_open() prevents core dump on Solaris
|
||||
|
||||
|
||||
----------------------------
|
||||
Release 4.50 - June 13, 2008
|
||||
----------------------------
|
||||
|
||||
WavPack Library Source Code - 4.50
|
||||
----------------------------------
|
||||
added: dynamic noise shaping for improved hybrid quality
|
||||
added: option to merge blocks of similar redundancy
|
||||
added: ability to store and retrieve extra mode level
|
||||
fixed: alignment fault on some big-endian machines
|
||||
fixed: compiling with enable-mmx on gcc 4.3.x (thanks Joachim)
|
||||
improved: allow bitrate to be calculated for files down to 1/10 second
|
||||
improved: decoding of corrupt files (prevents heap overrun crashes)
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.50
|
||||
-----------------------------------------
|
||||
added: dynamic noise shaping for improved hybrid quality
|
||||
added: --channel-order option to reorder nonconforming multichannel files
|
||||
added: --merge-blocks option to optimize storage of LossyWAV output files
|
||||
added: ignore -o on Windows for compatibility with Linux version
|
||||
fixed: alignment fault on some big-endian machines
|
||||
improved: reformatted and expanded --help display
|
||||
|
||||
wvunpack.exe (command-line decoder) - 4.50
|
||||
------------------------------------------
|
||||
fixed: don't ignore fractions of seconds in --skip option
|
||||
added: show extra level and dns status for newer files (-s command)
|
||||
added: ignore -o on Windows for compatibility with Linux version
|
||||
improved: decoding of corrupt files (prevents heap overrun crashes)
|
||||
improved: display bitrate for files down to 1/10 second
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.5
|
||||
-------------------------------
|
||||
added: transcoding API (allows CD burning, format conversion, ReplayGain calc, etc.)
|
||||
added: metadata writing API (for Auto-Tag, etc.)
|
||||
added: full Unicode support for info box (older Winamps) and media library
|
||||
added: standard Winamp metadata display & edit for newer Winamps
|
||||
added: option to pass multichannel audio
|
||||
added: option to pass all audio as 16-bit (for better compatibility)
|
||||
added: option to output 24-bit audio when ReplayGain is active
|
||||
added: genre display to info box (older Winamps)
|
||||
fixed: seek bar sometimes vacillates when moved
|
||||
fixed: crash when winamp is opened with files in playlist moved or deleted
|
||||
improved: hi-res audio now output as 24-bit (not 32-bit) for better compatibility (EQ, etc.)
|
||||
improved: performance of adding tracks to library, especially from network drives
|
||||
improved: decoding of corrupt files (prevents heap overrun crashes)
|
||||
|
||||
cool_wv4.flt (CoolEdit / Audition filter) - 2.9
|
||||
-----------------------------------------------
|
||||
added: about box
|
||||
added: dynamic noise shaping for improved hybrid quality
|
||||
improved: display bitrate for files as short as 1/10 second
|
||||
improved: decoding of corrupt files (prevents heap overrun crashes)
|
||||
improved: replace "extra processing" switch with a slider (0-6)
|
||||
|
||||
|
||||
--------------------------
|
||||
Release 4.41 - May 6, 2007
|
||||
--------------------------
|
||||
|
||||
WavPack Library Source Code - 4.41
|
||||
----------------------------------
|
||||
added: create wavpackdll.dll for Windows (not used yet)
|
||||
fixed: corrupt floating-point audio on big-endian machines
|
||||
fixed: put MSVC projects in their own subdir (fixed build problems)
|
||||
fixed: limit RIFF data buffering to 16 MB to prevent out-of-memory crash
|
||||
improved: attempt to mute errors when decoding corrupt legacy WavPack files
|
||||
improved: overall performance enhancements of 10% to 30% (depending on mode)
|
||||
added: MMX intrinsics for 24-bit (and higher) stereo encoding (thanks to
|
||||
Joachim Henke)
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.41
|
||||
-----------------------------------------
|
||||
fixed: corrupt floating-point audio on big-endian machines
|
||||
improved: refuse to encode WAV files over 4 GB or with over 16 MB RIFF data
|
||||
improved: overall performance enhancements of 10% to 30% (depending on mode)
|
||||
added: MMX intrinsics for 24-bit (and higher) stereo encoding (thanks to
|
||||
Joachim Henke)
|
||||
|
||||
wvunpack.exe (command-line decoder) - 4.41
|
||||
------------------------------------------
|
||||
fixed: corrupt floating-point audio on big-endian machines
|
||||
fixed: restore files mistakenly encoded with huge RIFF chunks
|
||||
improved: attempt to mute errors when decoding corrupt legacy WavPack files
|
||||
improved: overall performance enhancements of 10% to 30% (depending on mode)
|
||||
added: --skip and --until commands to unpack specified range of audio data
|
||||
added: MMX intrinsics for 24-bit (and higher) stereo encoding (thanks to
|
||||
Joachim Henke)
|
||||
|
||||
wvgain.exe (command-line ReplayGain scanner) - 4.41
|
||||
---------------------------------------------------
|
||||
improved: overall performance enhancements of 10% to 30% (depending on mode)
|
||||
added: MMX intrinsics for 24-bit (and higher) stereo encoding (thanks to
|
||||
Joachim Henke)
|
||||
|
||||
cool_wv4.flt (CoolEdit / Audition filter) - 2.8
|
||||
-----------------------------------------------
|
||||
fixed: read all RIFF metadata from files created in other applications
|
||||
improved: attempt to mute errors when decoding corrupt legacy WavPack files
|
||||
improved: overall performance enhancements of 10% to 30% (depending on mode)
|
||||
added: MMX intrinsics for 24-bit (and higher) stereo encoding (thanks to
|
||||
Joachim Henke)
|
||||
|
||||
|
||||
-------------------------------
|
||||
Release 4.40 - December 3, 2006
|
||||
-------------------------------
|
||||
|
||||
WavPack Library Source Code - 4.40
|
||||
----------------------------------
|
||||
added: new hardware-friendly "high" mode that compresses almost as well as
|
||||
old "high" mode but decodes significantly faster; old "high" mode
|
||||
now available as "very high"
|
||||
added: option added to improve compression of mono material in stereo files
|
||||
(requires at least version 4.3 decoder)
|
||||
added: function to obtain channel mapping information on decoding
|
||||
added: function to get trailing wrapper info (RIFF) without decoding file
|
||||
improved: "extra" mode levels 1-3 completely revamped, fast enough for use
|
||||
improved: reorganized to create a standard library that should more easily
|
||||
integrate into other applications; eliminated namespace issues
|
||||
improved: more robust handling of corrupt files
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.40
|
||||
-----------------------------------------
|
||||
added: accepts long option names including --help for full usage info
|
||||
added: new hardware-friendly "high" mode that compresses almost as well as
|
||||
old "high" mode but decodes significantly faster; old "high" mode
|
||||
now available as "very high" (-hh)
|
||||
added: --optimize-mono option added to improve compression of mono material
|
||||
in stereo files (requires at least version 4.3 decoder)
|
||||
improved: "extra" mode levels 1-3 completely revamped, fast enough for use
|
||||
improved: switched to Microsoft Visual Studio 2005 (win32 only)
|
||||
removed: support for Windows 95
|
||||
|
||||
wvunpack.exe (command-line decoder) - 4.40
|
||||
------------------------------------------
|
||||
added: cuesheet extraction (to .cue file or stdout)
|
||||
added: wav header generation on decode for files with missing RIFF
|
||||
information, or forced with -w option
|
||||
added: more summary info (wrapper info + channel assignments)
|
||||
improved: more robust handling of corrupt files
|
||||
improved: separate options for raw (-r) and blind stream decoding (-b)
|
||||
improved: switched to Microsoft Visual Studio 2005 (win32 only)
|
||||
removed: support for Windows 95
|
||||
|
||||
wvgain.exe (command-line ReplayGain scanner) - 4.40
|
||||
---------------------------------------------------
|
||||
improved: switched to Microsoft Visual Studio 2005 (win32 only)
|
||||
removed: support for Windows 95
|
||||
|
||||
wvselfx.exe (self-extraction stub) - 4.40
|
||||
------------------------------------------
|
||||
added: automatic cuesheet extraction (if present in APEv2 tag)
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.4
|
||||
-------------------------------
|
||||
fixed: quietly skips deleted files in playlist
|
||||
improved: more robust handling of corrupt files
|
||||
improved: APEv2 tags are read even if followed by ID3v1 tag
|
||||
|
||||
cool_wv4.flt (CoolEdit / Audition filter) - 2.7
|
||||
-----------------------------------------------
|
||||
added: new hardware-friendly "high" mode that compresses almost as well as
|
||||
old "high" mode but decodes significantly faster; old "high" mode
|
||||
now available as "v. high"
|
||||
improved: more robust handling of corrupt files
|
||||
|
||||
|
||||
----------------------
|
||||
Update - April 5, 2006
|
||||
----------------------
|
||||
|
||||
WavPack Library Source Code - 4.32
|
||||
wavpack.exe (command-line encoder) - 4.32
|
||||
-----------------------------------------
|
||||
fixed: generating RIFF headers on big-endian machines caused crash
|
||||
|
||||
|
||||
--------------------------
|
||||
Update - December 10, 2005
|
||||
--------------------------
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.31
|
||||
wvunpack.exe (command-line decoder) - 4.31
|
||||
------------------------------------------
|
||||
fixed: detect debug mode in all cases (win32 only)
|
||||
improved: use latest service pack and SDK for building (win32 only)
|
||||
improved: better directory choice for logging file (win32 only)
|
||||
improved: allow shell to expand wildcards (*nix only)
|
||||
added: option (-o) to specify output directory or path (*nix only)
|
||||
added: option (-t) to copy timestamp (*nix only)
|
||||
|
||||
wvgain.exe (command-line ReplayGain scanner) - 4.31
|
||||
---------------------------------------------------
|
||||
new
|
||||
|
||||
WavPack Library Source Code - 4.31
|
||||
----------------------------------
|
||||
fixed: failing seek with some files that had been played to the end
|
||||
fixed: small memory leak when opening hybrid lossless files
|
||||
improved: signed characters no longer must be default
|
||||
improved: APEv2 tags are read even if followed by ID3v1 tag
|
||||
improved: limited APEv2 tag editing capability
|
||||
|
||||
|
||||
------------------------------
|
||||
Release 4.3 - November 1, 2005
|
||||
------------------------------
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.3
|
||||
----------------------------------------
|
||||
fixed: bug causing termination error with very wide screen widths
|
||||
added: command-line option (-l) to use low priority for batch operation
|
||||
added: command-line option (-r) to generate a fresh RIFF header
|
||||
added: debug mode (rename to wavpack_debug.exe)
|
||||
added: automatically detect lower resolution data even without -x1
|
||||
added: src and dst dirs are searched also for tag source files (handy for EAC)
|
||||
added: wildcard accepted for tag source files (handy for EAC)
|
||||
added: handle non-standard sampling rates
|
||||
improved: returns error status for any error
|
||||
improved: use longer blocks in multichannel files (better "high" compression)
|
||||
|
||||
wvunpack.exe (command-line decoder) - 4.3
|
||||
-----------------------------------------
|
||||
fixed: very rare decoding bug causing overflow with hi-res files
|
||||
fixed: bug causing termination error with very wide screen widths
|
||||
fixed: formatting error in duration display
|
||||
added: command-line option (-ss) to include tags in summary dump
|
||||
added: command-line option (-l) to use low priority for batch operation
|
||||
added: debug mode (rename to wvunpack_debug.exe)
|
||||
improved: returns error status for any error
|
||||
improved: more robust decoding of damaged (or invalid) files
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.3
|
||||
nxWavPack.dll (Nero plugin) - 1.2
|
||||
WavPack_Apollo.dll (Apollo plugin) - 1.3
|
||||
cool_wv4.flt (CoolEdit / Audition filter) - 2.6
|
||||
-----------------------------------------------
|
||||
fixed: very rare decoding bug causing overflow with hi-res files
|
||||
improved: handle ID3v1.1 tags (now includes track number)
|
||||
improved: more robust decoding of damaged (or invalid) files
|
||||
added: handle non-standard sampling rates
|
||||
|
||||
foo_wavpack.dll (foobar plugin) - 2.3
|
||||
-----------------------------------------------
|
||||
fixed: any error during WavPack file open caused crash if wvc file present
|
||||
fixed: very rare decoding bug causing overflow with hi-res files
|
||||
improved: more robust decoding of damaged (or invalid) files
|
||||
added: handle non-standard sampling rates
|
||||
|
||||
WavPack Library Source Code - 4.3
|
||||
---------------------------------
|
||||
fixed: very rare decoding bug causing overflow with hi-res files
|
||||
added: automatic generation of RIFF wav header during encoding
|
||||
added: new functions to access tags by index (instead of item name)
|
||||
added: automatically detect lower resolution data during encoding
|
||||
added: handle non-standard sampling rates
|
||||
improved: more robust decoding of damaged (or invalid) files
|
||||
improved: use longer blocks in multichannel files (better "high" compression)
|
||||
improved: two structures renamed to avoid namespace conflict
|
||||
removed: legacy code for Borland compiler
|
||||
|
||||
|
||||
--------------------------
|
||||
Update - September 1, 2005
|
||||
--------------------------
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.22
|
||||
cool_wv4.flt (CoolEdit / Audition filter) - 2.5
|
||||
-----------------------------------------------
|
||||
fixed: possible corrupt files written (24 or 32-bit + "extra" mode)
|
||||
|
||||
|
||||
---------------------------
|
||||
Release 4.2 - April 2, 2005
|
||||
---------------------------
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.2
|
||||
----------------------------------------
|
||||
fixed: handling of wav files larger than 2 gig
|
||||
improved: stereo lossless encoding speed (including "extra" mode)
|
||||
added: -i option to ignore length specified in wav header
|
||||
added: -w option to write APEv2 tags directly from command line
|
||||
|
||||
wvunpack.exe (command-line decoder) - 4.2
|
||||
-----------------------------------------
|
||||
improved: decoding speed
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.2
|
||||
-------------------------------
|
||||
added: winamp media library support
|
||||
improved: decoding speed
|
||||
|
||||
foo_wavpack.dll (foobar plugin) - 2.2
|
||||
-------------------------------------
|
||||
improved: decoding speed
|
||||
|
||||
nxWavPack.dll (Nero plugin) - 1.1
|
||||
Cool_wv4.flt (CoolEdit / Audition filter) - 2.4
|
||||
-----------------------------------------------
|
||||
fixed: handling of wav files larger than 2 gig
|
||||
improved: encoding and decoding speed
|
||||
|
||||
WavPack Library Source Code - 4.2
|
||||
---------------------------------
|
||||
improved: encoding and decoding speed
|
||||
fixed: works correctly with 64-bit compilers
|
||||
added: mode bit to open files in "streaming" mode
|
||||
|
||||
|
||||
--------------------------
|
||||
Update - December 12, 2004
|
||||
--------------------------
|
||||
|
||||
WavPack_Apollo.dll (Apollo plugin) - 1.2
|
||||
----------------------------------------
|
||||
fixed: crash when Apollo opened and WavPack plugin can't find config file
|
||||
|
||||
|
||||
--------------------------------
|
||||
Release 4.1 - September 14, 2004
|
||||
--------------------------------
|
||||
|
||||
wavpack.exe (command-line encoder) - 4.1
|
||||
----------------------------------------
|
||||
fixed: hybrid mode + "extra" mode + very low bitrates making corrupt files
|
||||
fixed: mono or multichannel files causing crash (no corruption possible)
|
||||
added: third name specification for "correction" file (EAC specific)
|
||||
added: -t option to preserve timestamps
|
||||
added: error summary for batch mode
|
||||
|
||||
wvunpack.exe (command-line decoder) - 4.1
|
||||
-----------------------------------------
|
||||
fixed: hybrid mode decoding bugs (very obscure situations)
|
||||
added: -s option to dump file summary to stdout
|
||||
added: -t option to preserve timestamps
|
||||
added: error summary for batch mode
|
||||
|
||||
wvselfx.exe (self-extraction stub) - 4.1
|
||||
----------------------------------------
|
||||
fixed: hybrid mode decoding bugs (very obscure situations)
|
||||
|
||||
in_wv.dll (winamp plugin) - 2.1
|
||||
-------------------------------
|
||||
fixed: international characters in tags display properly (UTF-8 to Ansi)
|
||||
added: maximum tag data field width changed from 64 chars to 128 chars
|
||||
added: new infobox items including encoder version & modes, track #, md5
|
||||
|
||||
foo_wavpack.dll (foobar plugin) - 2.1
|
||||
-------------------------------------
|
||||
added: new database items including encoder version & modes and md5
|
||||
|
||||
WavPack_Apollo.dll (Apollo plugin) - 1.1
|
||||
----------------------------------------
|
||||
fixed: international characters in tags display properly (UTF-8 to Ansi)
|
||||
|
||||
Cool_wv4.flt (CoolEdit / Audition filter) - 2.2
|
||||
-----------------------------------------------
|
||||
fixed: hybrid mode + "extra" mode + very low bitrates making corrupt files
|
||||
fixed: saving mono file causing crash (no corruption possible)
|
||||
fixed: hybrid mode decoding bugs (very obscure situations)
|
||||
fixed: partial saves (with "Cancel") have incorrect RIFF header if unpacked
|
||||
|
||||
nxWavPack.dll (Nero plugin) - 1.0
|
||||
---------------------------------
|
||||
new
|
||||
|
||||
WavPack Library Source Code - 4.1
|
||||
---------------------------------
|
||||
fixed: hybrid mode + "extra" mode + very low bitrates making corrupt files
|
||||
fixed: mono or multichannel files causing crash (no corruption possible)
|
||||
fixed: hybrid mode decoding bugs (very obscure situations)
|
||||
added: mode bits for determining additional encode info (extra, sfx)
|
||||
added: function to return total compressed file length (including wvc)
|
||||
added: function to return encoder version (1, 2, 3, or 4)
|
||||
added: ability to obtain MD5 sum before decoding file (requires seek to end)
|
||||
added: mode bit for determining tag type (for proper character translation)
|
||||
added: ability to encode WavPack files without knowing length in advance
|
||||
added: option for small "information only" version of library
|
|
@ -1,136 +0,0 @@
|
|||
<img src="http://www.rarewares.org/wavpack/logos/wavpacklogo.png" width="250"></img>
|
||||
|
||||
Hybrid Lossless Wavefile Compressor
|
||||
|
||||
Copyright (c) 1998 - 2019 David Bryant.
|
||||
|
||||
All Rights Reserved.
|
||||
|
||||
Distributed under the [BSD Software License](https://github.com/dbry/WavPack/blob/master/license.txt).
|
||||
|
||||
---
|
||||
|
||||
This [repository](https://github.com/dbry/WavPack) contains all of the source code required to build the WavPack library (_libwavpack_), and any associated command-line programs.
|
||||
|
||||
Additional references:
|
||||
|
||||
* [Official website](http://wavpack.com/)
|
||||
* [Binaries](http://wavpack.com/downloads.html#binaries)
|
||||
* [Other sources](http://wavpack.com/downloads.html#sources)
|
||||
* [Documentation](http://wavpack.com/downloads.html#documentation)
|
||||
* [Test suite](http://www.rarewares.org/wavpack/test_suite.zip)
|
||||
* [Logos](http://wavpack.com/downloads.html#logos)
|
||||
|
||||
---
|
||||
|
||||
## Build Status
|
||||
|
||||
| Branch | Status |
|
||||
|----------------|-------------------------------------------------------------------------------------------------------------------|
|
||||
| `master` | [](https://travis-ci.org/dbry/WavPack) |
|
||||
|
||||
Branches [actively built](https://travis-ci.org/dbry/WavPack/branches) by TravisCI.
|
||||
|
||||
---
|
||||
|
||||
## Building
|
||||
|
||||
### Windows
|
||||
|
||||
There are solution and project files for Visual Studio 2008, and additional source code to build the [CoolEdit/Audition](https://github.com/dbry/WavPack/tree/master/audition) plugin and the [Winamp](https://github.com/dbry/WavPack/tree/master/winamp) plugin.
|
||||
|
||||
The CoolEdit/Audition plugin provides a good example for using the library to both read and write WavPack files, and the Winamp plugin makes extensive use of APEv2 tag reading and writing.
|
||||
|
||||
Both 32-bit and 64-bit platforms are provided.
|
||||
|
||||
Visual Studio 2008 does not support projects with x64 assembly very well. I have provided a copy of the edited `masm.rules` file that works for me, but I can't provide support if your build does not work. Please make a copy of your `masm.rules` file first.
|
||||
|
||||
On my system it lives here: `C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\VCProjectDefaults`
|
||||
|
||||
### Linux
|
||||
|
||||
To build everything on Linux, type:
|
||||
|
||||
1. `./configure`
|
||||
* `--disable-asm`
|
||||
* `--enable-man`
|
||||
* `--enable-rpath`
|
||||
* `--enable-tests`
|
||||
* `--disable-apps`
|
||||
* `--disable-dsd`
|
||||
* `--enable-legacy`
|
||||
2. `make`
|
||||
* Optionally, `make install`, to install into `/usr/local/bin`
|
||||
|
||||
If you are using the code directly from Git (rather than a distribution) then you will need to do a ./autogen.sh instead of the configure step. If assembly optimizations are available for your processor they will be automatically enabled, but if there is a problem with them then use the `--disable-asm` option to revert to pure C.
|
||||
|
||||
For Clang-based build systems (Darwin, FreeBSD, etc.), Clang version 3.5 or higher is required.
|
||||
|
||||
If you get a WARNING about unexpected _libwavpack_ version when you run the command-line programs, you might try using `--enable-rpath` to hardcode the library location in the executables, or simply force static linking with `--disable-shared`.
|
||||
|
||||
There is now a CLI program to do a full suite of stress tests for _libwavpack_, and this is particularly useful for packagers to make sure that the assembly language optimizations are working correctly on various platforms. It is built with the configure option `--enable-tests` and requires Pthreads (it worked out-of-the-box on all the platforms I tried it on). There are lots of options, but the default test suite (consisting of 192 tests) is executed with `wvtest --default`. There is also a seeking test. On Windows a third-party Pthreads library is required, so I am not including this in the build for now.
|
||||
|
||||
---
|
||||
|
||||
## Assembly
|
||||
|
||||
Assembly language optimizations are provided for x86 and x86-64 (AMD64) processors (encoding and decoding) and ARMv7 (decoding only).
|
||||
|
||||
The x86 assembly code includes a runtime check for MMX capability, so it will work on legacy i386 processors.
|
||||
|
||||
## Documentation
|
||||
|
||||
There are four documentation files contained in the distribution:
|
||||
|
||||
| File | Description |
|
||||
|------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| [doc/wavpack_doc.html](https://github.com/dbry/WavPack/blob/master/doc/wavpack_doc.html) | Contains user-targeted documentation for the command-line programs. |
|
||||
| [doc/WavPack5PortingGuide.pdf](https://github.com/dbry/WavPack/blob/master/doc/WavPack5PortingGuide.pdf) | This document is targeted at developers who are migrating to WavPack 5, and it provides a short description of the major improvements and how to utilize them. |
|
||||
| [doc/WavPack5LibraryDoc.pdf](https://github.com/dbry/WavPack/blob/master/doc/WavPack5LibraryDoc.pdf) | Contains a detailed description of the API provided by WavPack library appropriate for reading and writing WavPack files and manipulating APEv2 tags. |
|
||||
| [doc/WavPack5FileFormat.pdf](https://github.com/dbry/WavPack/blob/master/doc/WavPack5FileFormat.pdf) | Contains a description of the WavPack file format, including details needed for parsing WavPack, blocks, and interpreting the block header and flags. |
|
||||
|
||||
There is also a description of the WavPack algorithms in the forth edition of David Salomon's book "Data Compression: The Complete Reference". This section can be found here: www.wavpack.com/WavPack.pdf
|
||||
|
||||
## Portability
|
||||
|
||||
This code is designed to be easy to port to other platforms.
|
||||
|
||||
It is endian-agnostic and usually uses callbacks for I/O, although there's a convenience function for reading files that accepts filename strings and automatically handles correction files.
|
||||
|
||||
On Windows, there is now an option to select UTF-8 instead of ANSI.
|
||||
|
||||
To maintain compatibility on various platforms, the following conventions are used:
|
||||
* `char` must be 8-bits (`signed` or `unsigned`).
|
||||
* `short` must be 16-bits.
|
||||
* `int` and `long` must be at least 32-bits.
|
||||
|
||||
## Design
|
||||
|
||||
The code's modules are organized in such a way that if major chunks of the functionality are not referenced (for example, creating WavPack files) then link-time dependency resolution should provide optimum binary sizes.
|
||||
|
||||
However, some functionality could not be easily excluded in this way and so there are additional macros that may be used to further reduce the size of the binary. Note that these must be defined for all modules:
|
||||
|
||||
| Macros | Description |
|
||||
|-----------------|------------------------------------------------------------------------------------------------------------|
|
||||
| `NO_SEEKING` | To not allow seeking to a specific sample index (for applications that always read entire files). |
|
||||
| `NO_TAGS` | To not read specified fields from ID3v1 and APEv2 tags, and not create or edit APEv2 tags. |
|
||||
| `ENABLE_LEGACY` | Include support for Wavpack files from before version 4.0. This was eliminated by default with WavPack 5. |
|
||||
| `ENABLE_DSD` | Include support for DSD audio. New for WavPack 5 and the default, but obviously not universally required. |
|
||||
|
||||
Note that this has been tested on many platforms.
|
||||
|
||||
## Tiny Decoder
|
||||
|
||||
There are alternate versions of this library available specifically designed for resource limited CPUs, and hardware encoding and decoding.
|
||||
|
||||
There is the _Tiny Decoder_ library which works with less than 32k of code and less than 4k of data, and has assembly language optimizations for the ARM and Freescale ColdFire CPUs.
|
||||
|
||||
The _Tiny Decoder_ is also designed for embedded use and handles the pure lossless, lossy, and hybrid lossless modes.
|
||||
|
||||
Neither of these versions use any memory allocation functions, nor do they require floating-point arithmetic support.
|
||||
|
||||
---
|
||||
|
||||
Questions or comments should be directed to david@wavpack.com.
|
||||
|
||||
You may also find David on GitHub as [dbry](https://github.com/dbry).
|
|
@ -1,788 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// common_utils.c
|
||||
|
||||
// This module provides a lot of the trivial WavPack API functions and several
|
||||
// functions that are common to both reading and writing WavPack files (like
|
||||
// WavpackCloseFile()). Functions here are restricted to those that have few
|
||||
// external dependencies and this is done so that applications that statically
|
||||
// link to the WavPack library (like the command-line utilities on Windows)
|
||||
// do not need to include the entire library image if they only use a subset
|
||||
// of it. This module will be loaded for ANY WavPack application.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#ifndef LIBWAVPACK_VERSION_STRING
|
||||
#include "wavpack_version.h"
|
||||
#endif
|
||||
|
||||
///////////////////////////// local table storage ////////////////////////////
|
||||
|
||||
const uint32_t sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050,
|
||||
24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 };
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// This function obtains general information about an open input file and
|
||||
// returns a mask with the following bit values:
|
||||
|
||||
// MODE_WVC: a .wvc file has been found and will be used for lossless
|
||||
// MODE_LOSSLESS: file is lossless (either pure or hybrid)
|
||||
// MODE_HYBRID: file is hybrid mode (either lossy or lossless)
|
||||
// MODE_FLOAT: audio data is 32-bit ieee floating point
|
||||
// MODE_VALID_TAG: file contains a valid ID3v1 or APEv2 tag
|
||||
// MODE_HIGH: file was created in "high" mode (information only)
|
||||
// MODE_FAST: file was created in "fast" mode (information only)
|
||||
// MODE_EXTRA: file was created using "extra" mode (information only)
|
||||
// MODE_APETAG: file contains a valid APEv2 tag
|
||||
// MODE_SFX: file was created as a "self-extracting" executable
|
||||
// MODE_VERY_HIGH: file was created in the "very high" mode (or in
|
||||
// the "high" mode prior to 4.4)
|
||||
// MODE_MD5: file contains an MD5 checksum
|
||||
// MODE_XMODE: level used for extra mode (1-6, 0=unknown)
|
||||
// MODE_DNS: dynamic noise shaping
|
||||
|
||||
int WavpackGetMode (WavpackContext *wpc)
|
||||
{
|
||||
int mode = 0;
|
||||
|
||||
if (wpc) {
|
||||
if (wpc->config.flags & CONFIG_HYBRID_FLAG)
|
||||
mode |= MODE_HYBRID;
|
||||
else if (!(wpc->config.flags & CONFIG_LOSSY_MODE))
|
||||
mode |= MODE_LOSSLESS;
|
||||
|
||||
if (wpc->wvc_flag)
|
||||
mode |= (MODE_LOSSLESS | MODE_WVC);
|
||||
|
||||
if (wpc->lossy_blocks)
|
||||
mode &= ~MODE_LOSSLESS;
|
||||
|
||||
if (wpc->config.flags & CONFIG_FLOAT_DATA)
|
||||
mode |= MODE_FLOAT;
|
||||
|
||||
if (wpc->config.flags & (CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG)) {
|
||||
mode |= MODE_HIGH;
|
||||
|
||||
if ((wpc->config.flags & CONFIG_VERY_HIGH_FLAG) ||
|
||||
(wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.version < 0x405))
|
||||
mode |= MODE_VERY_HIGH;
|
||||
}
|
||||
|
||||
if (wpc->config.flags & CONFIG_FAST_FLAG)
|
||||
mode |= MODE_FAST;
|
||||
|
||||
if (wpc->config.flags & CONFIG_EXTRA_MODE)
|
||||
mode |= (MODE_EXTRA | (wpc->config.xmode << 12));
|
||||
|
||||
if (wpc->config.flags & CONFIG_CREATE_EXE)
|
||||
mode |= MODE_SFX;
|
||||
|
||||
if (wpc->config.flags & CONFIG_MD5_CHECKSUM)
|
||||
mode |= MODE_MD5;
|
||||
|
||||
if ((wpc->config.flags & CONFIG_HYBRID_FLAG) && (wpc->config.flags & CONFIG_DYNAMIC_SHAPING) &&
|
||||
wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.version >= 0x407)
|
||||
mode |= MODE_DNS;
|
||||
|
||||
#ifndef NO_TAGS
|
||||
if (valid_tag (&wpc->m_tag)) {
|
||||
mode |= MODE_VALID_TAG;
|
||||
|
||||
if (valid_tag (&wpc->m_tag) == 'A')
|
||||
mode |= MODE_APETAG;
|
||||
}
|
||||
#endif
|
||||
|
||||
mode |= (wpc->config.qmode << 16) & 0xFF0000;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
// This function obtains information about specific file features that were
|
||||
// added for version 5.0, specifically qualifications added to support CAF
|
||||
// and DSD files. Except for indicating the presence of DSD data, these
|
||||
// bits are meant to simply indicate the format of the data in the original
|
||||
// source file and do NOT indicate how the library will return the data to
|
||||
// the appication (which is always the same). This means that in general an
|
||||
// application that simply wants to play or process the audio data need not
|
||||
// be concerned about these. If the file is DSD audio, then either of the
|
||||
// QMDOE_DSD_LSB_FIRST or QMODE_DSD_MSB_FIRST bits will be set (but the
|
||||
// DSD audio is always returned to the caller MSB first).
|
||||
|
||||
// QMODE_BIG_ENDIAN 0x1 // big-endian data format (opposite of WAV format)
|
||||
// QMODE_SIGNED_BYTES 0x2 // 8-bit audio data is signed (opposite of WAV format)
|
||||
// QMODE_UNSIGNED_WORDS 0x4 // audio data (other than 8-bit) is unsigned (opposite of WAV format)
|
||||
// QMODE_REORDERED_CHANS 0x8 // source channels were not Microsoft order, so they were reordered
|
||||
// QMODE_DSD_LSB_FIRST 0x10 // DSD bytes, LSB first (most Sony .dsf files)
|
||||
// QMODE_DSD_MSB_FIRST 0x20 // DSD bytes, MSB first (Philips .dff files)
|
||||
// QMODE_DSD_IN_BLOCKS 0x40 // DSD data is blocked by channels (Sony .dsf only)
|
||||
|
||||
int WavpackGetQualifyMode (WavpackContext *wpc)
|
||||
{
|
||||
return wpc->config.qmode & 0xFF;
|
||||
}
|
||||
|
||||
// This function returns a pointer to a string describing the last error
|
||||
// generated by WavPack.
|
||||
|
||||
char *WavpackGetErrorMessage (WavpackContext *wpc)
|
||||
{
|
||||
return wpc->error_message;
|
||||
}
|
||||
|
||||
// Get total number of samples contained in the WavPack file, or -1 if unknown
|
||||
|
||||
uint32_t WavpackGetNumSamples (WavpackContext *wpc)
|
||||
{
|
||||
return (uint32_t) WavpackGetNumSamples64 (wpc);
|
||||
}
|
||||
|
||||
int64_t WavpackGetNumSamples64 (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->total_samples : -1;
|
||||
}
|
||||
|
||||
// Get the current sample index position, or -1 if unknown
|
||||
|
||||
uint32_t WavpackGetSampleIndex (WavpackContext *wpc)
|
||||
{
|
||||
return (uint32_t) WavpackGetSampleIndex64 (wpc);
|
||||
}
|
||||
|
||||
int64_t WavpackGetSampleIndex64 (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc) {
|
||||
#ifdef ENABLE_LEGACY
|
||||
if (wpc->stream3)
|
||||
return get_sample_index3 (wpc);
|
||||
else if (wpc->streams && wpc->streams [0])
|
||||
return wpc->streams [0]->sample_index;
|
||||
#else
|
||||
if (wpc->streams && wpc->streams [0])
|
||||
return wpc->streams [0]->sample_index;
|
||||
#endif
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the number of errors encountered so far
|
||||
|
||||
int WavpackGetNumErrors (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->crc_errors : 0;
|
||||
}
|
||||
|
||||
// return TRUE if any uncorrected lossy blocks were actually written or read
|
||||
|
||||
int WavpackLossyBlocks (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->lossy_blocks : 0;
|
||||
}
|
||||
|
||||
// Calculate the progress through the file as a double from 0.0 (for begin)
|
||||
// to 1.0 (for done). A return value of -1.0 indicates that the progress is
|
||||
// unknown.
|
||||
|
||||
double WavpackGetProgress (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc && wpc->total_samples != -1 && wpc->total_samples != 0)
|
||||
return (double) WavpackGetSampleIndex64 (wpc) / wpc->total_samples;
|
||||
else
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
// Return the total size of the WavPack file(s) in bytes.
|
||||
|
||||
uint32_t WavpackGetFileSize (WavpackContext *wpc)
|
||||
{
|
||||
return (uint32_t) (wpc ? wpc->filelen + wpc->file2len : 0);
|
||||
}
|
||||
|
||||
int64_t WavpackGetFileSize64 (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->filelen + wpc->file2len : 0;
|
||||
}
|
||||
|
||||
// Calculate the ratio of the specified WavPack file size to the size of the
|
||||
// original audio data as a double greater than 0.0 and (usually) smaller than
|
||||
// 1.0. A value greater than 1.0 represents "negative" compression and a
|
||||
// return value of 0.0 indicates that the ratio cannot be determined.
|
||||
|
||||
double WavpackGetRatio (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc && wpc->total_samples != -1 && wpc->filelen) {
|
||||
double output_size = (double) wpc->total_samples * wpc->config.num_channels *
|
||||
wpc->config.bytes_per_sample;
|
||||
double input_size = (double) wpc->filelen + wpc->file2len;
|
||||
|
||||
if (output_size >= 1.0 && input_size >= 1.0)
|
||||
return input_size / output_size;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Calculate the average bitrate of the WavPack file in bits per second. A
|
||||
// return of 0.0 indicates that the bitrate cannot be determined. An option is
|
||||
// provided to use (or not use) any attendant .wvc file.
|
||||
|
||||
double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc)
|
||||
{
|
||||
if (wpc && wpc->total_samples != -1 && wpc->filelen) {
|
||||
double output_time = (double) wpc->total_samples / WavpackGetSampleRate (wpc);
|
||||
double input_size = (double) wpc->filelen + (count_wvc ? wpc->file2len : 0);
|
||||
|
||||
if (output_time >= 0.1 && input_size >= 1.0)
|
||||
return input_size * 8.0 / output_time;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Calculate the bitrate of the current WavPack file block in bits per second.
|
||||
// This can be used for an "instant" bit display and gets updated from about
|
||||
// 1 to 4 times per second. A return of 0.0 indicates that the bitrate cannot
|
||||
// be determined.
|
||||
|
||||
double WavpackGetInstantBitrate (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc && wpc->stream3)
|
||||
return WavpackGetAverageBitrate (wpc, TRUE);
|
||||
|
||||
if (wpc && wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.block_samples) {
|
||||
double output_time = (double) wpc->streams [0]->wphdr.block_samples / WavpackGetSampleRate (wpc);
|
||||
double input_size = 0;
|
||||
int si;
|
||||
|
||||
for (si = 0; si < wpc->num_streams; ++si) {
|
||||
if (wpc->streams [si]->blockbuff)
|
||||
input_size += ((WavpackHeader *) wpc->streams [si]->blockbuff)->ckSize;
|
||||
|
||||
if (wpc->streams [si]->block2buff)
|
||||
input_size += ((WavpackHeader *) wpc->streams [si]->block2buff)->ckSize;
|
||||
}
|
||||
|
||||
if (output_time > 0.0 && input_size >= 1.0)
|
||||
return input_size * 8.0 / output_time;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// This function allows retrieving the Core Audio File channel layout, many of which do not
|
||||
// conform to the Microsoft ordering standard that WavPack requires internally (at least for
|
||||
// those channels present in the "channel mask"). In addition to the layout tag, this function
|
||||
// returns the reordering string (if stored in the file) to allow the unpacker to reorder the
|
||||
// channels back to the specified layout (if it wants to restore the CAF order). The number of
|
||||
// channels in the layout is determined from the lower nybble of the layout word (and should
|
||||
// probably match the number of channels in the file), and if a reorder string is requested
|
||||
// then that much space must be allocated. Note that all the reordering is actually done
|
||||
// outside of this library, and that if reordering is done then the appropriate qmode bit
|
||||
// will be set.
|
||||
//
|
||||
// Note: Normally this function would not be used by an application unless it specifically
|
||||
// wanted to restore a non-standard channel order (to check an MD5, for example) or obtain
|
||||
// the Core Audio channel layout ID. For simple file decoding for playback, the channel_mask
|
||||
// should provide all the information required unless there are non-Microsoft channels
|
||||
// involved, in which case WavpackGetChannelIdentities() will provide the identities of
|
||||
// the other channels (if they are known).
|
||||
|
||||
uint32_t WavpackGetChannelLayout (WavpackContext *wpc, unsigned char *reorder)
|
||||
{
|
||||
if ((wpc->channel_layout & 0xff) && wpc->channel_reordering && reorder)
|
||||
memcpy (reorder, wpc->channel_reordering, wpc->channel_layout & 0xff);
|
||||
|
||||
return wpc->channel_layout;
|
||||
}
|
||||
|
||||
// This function provides the identities of ALL the channels in the file, including the
|
||||
// standard Microsoft channels (which come first, in order, and are numbered 1-18) and also
|
||||
// any non-Microsoft channels (which can be in any order and have values from 33-254). The
|
||||
// value 0x00 is invalid and 0xFF indicates an "unknown" or "unnassigned" channel. The
|
||||
// string is NULL terminated so the caller must supply enough space for the number
|
||||
// of channels indicated by WavpackGetNumChannels(), plus one.
|
||||
//
|
||||
// Note that this function returns the actual order of the channels in the Wavpack file
|
||||
// (i.e., the order returned by WavpackUnpackSamples()). If the file includes a "reordering"
|
||||
// string because the source file was not in Microsoft order that is NOT taken into account
|
||||
// here and really only needs to be considered if doing an MD5 verification or if it's
|
||||
// required to restore the original order/file (like wvunpack does).
|
||||
|
||||
void WavpackGetChannelIdentities (WavpackContext *wpc, unsigned char *identities)
|
||||
{
|
||||
int num_channels = wpc->config.num_channels, index = 1;
|
||||
uint32_t channel_mask = wpc->config.channel_mask;
|
||||
unsigned char *src = wpc->channel_identities;
|
||||
|
||||
while (num_channels--) {
|
||||
if (channel_mask) {
|
||||
while (!(channel_mask & 1)) {
|
||||
channel_mask >>= 1;
|
||||
index++;
|
||||
}
|
||||
|
||||
*identities++ = index++;
|
||||
channel_mask >>= 1;
|
||||
}
|
||||
else if (src && *src)
|
||||
*identities++ = *src++;
|
||||
else
|
||||
*identities++ = 0xff;
|
||||
}
|
||||
|
||||
*identities = 0;
|
||||
}
|
||||
|
||||
// For local use only. Install a callback to be executed when WavpackCloseFile() is called,
|
||||
// usually used to dump some statistics accumulated during encode or decode.
|
||||
|
||||
void install_close_callback (WavpackContext *wpc, void cb_func (void *wpc))
|
||||
{
|
||||
wpc->close_callback = cb_func;
|
||||
}
|
||||
|
||||
// Close the specified WavPack file and release all resources used by it.
|
||||
// Returns NULL.
|
||||
|
||||
WavpackContext *WavpackCloseFile (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc->close_callback)
|
||||
wpc->close_callback (wpc);
|
||||
|
||||
if (wpc->streams) {
|
||||
free_streams (wpc);
|
||||
|
||||
if (wpc->streams [0])
|
||||
free (wpc->streams [0]);
|
||||
|
||||
free (wpc->streams);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LEGACY
|
||||
if (wpc->stream3)
|
||||
free_stream3 (wpc);
|
||||
#endif
|
||||
|
||||
if (wpc->reader && wpc->reader->close && wpc->wv_in)
|
||||
wpc->reader->close (wpc->wv_in);
|
||||
|
||||
if (wpc->reader && wpc->reader->close && wpc->wvc_in)
|
||||
wpc->reader->close (wpc->wvc_in);
|
||||
|
||||
WavpackFreeWrapper (wpc);
|
||||
|
||||
if (wpc->metadata) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < wpc->metacount; ++i)
|
||||
if (wpc->metadata [i].data)
|
||||
free (wpc->metadata [i].data);
|
||||
|
||||
free (wpc->metadata);
|
||||
}
|
||||
|
||||
if (wpc->channel_identities)
|
||||
free (wpc->channel_identities);
|
||||
|
||||
if (wpc->channel_reordering)
|
||||
free (wpc->channel_reordering);
|
||||
|
||||
#ifndef NO_TAGS
|
||||
free_tag (&wpc->m_tag);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->decimation_context)
|
||||
decimate_dsd_destroy (wpc->decimation_context);
|
||||
#endif
|
||||
|
||||
free (wpc);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// These routines are used to access (and free) header and trailer data that
|
||||
// was retrieved from the Wavpack file. The header will be available before
|
||||
// the samples are decoded and the trailer will be available after all samples
|
||||
// have been read.
|
||||
|
||||
uint32_t WavpackGetWrapperBytes (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->wrapper_bytes : 0;
|
||||
}
|
||||
|
||||
unsigned char *WavpackGetWrapperData (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->wrapper_data : NULL;
|
||||
}
|
||||
|
||||
void WavpackFreeWrapper (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc && wpc->wrapper_data) {
|
||||
free (wpc->wrapper_data);
|
||||
wpc->wrapper_data = NULL;
|
||||
wpc->wrapper_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the sample rate of the specified WavPack file
|
||||
|
||||
uint32_t WavpackGetSampleRate (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? (wpc->dsd_multiplier ? wpc->config.sample_rate * wpc->dsd_multiplier : wpc->config.sample_rate) : 44100;
|
||||
}
|
||||
|
||||
// Returns the native sample rate of the specified WavPack file
|
||||
// (provides the native rate for DSD files rather than the "byte" rate that's used for
|
||||
// seeking, duration, etc. and would generally be used just for user facing reports)
|
||||
|
||||
uint32_t WavpackGetNativeSampleRate (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? (wpc->dsd_multiplier ? wpc->config.sample_rate * wpc->dsd_multiplier * 8 : wpc->config.sample_rate) : 44100;
|
||||
}
|
||||
|
||||
// Returns the number of channels of the specified WavPack file. Note that
|
||||
// this is the actual number of channels contained in the file even if the
|
||||
// OPEN_2CH_MAX flag was specified when the file was opened.
|
||||
|
||||
int WavpackGetNumChannels (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->config.num_channels : 2;
|
||||
}
|
||||
|
||||
// Returns the standard Microsoft channel mask for the specified WavPack
|
||||
// file. A value of zero indicates that there is no speaker assignment
|
||||
// information.
|
||||
|
||||
int WavpackGetChannelMask (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->config.channel_mask : 0;
|
||||
}
|
||||
|
||||
// Return the normalization value for floating point data (valid only
|
||||
// if floating point data is present). A value of 127 indicates that
|
||||
// the floating point range is +/- 1.0. Higher values indicate a
|
||||
// larger floating point range.
|
||||
|
||||
int WavpackGetFloatNormExp (WavpackContext *wpc)
|
||||
{
|
||||
return wpc->config.float_norm_exp;
|
||||
}
|
||||
|
||||
// Returns the actual number of valid bits per sample contained in the
|
||||
// original file, which may or may not be a multiple of 8. Floating data
|
||||
// always has 32 bits, integers may be from 1 to 32 bits each. When this
|
||||
// value is not a multiple of 8, then the "extra" bits are located in the
|
||||
// LSBs of the results. That is, values are right justified when unpacked
|
||||
// into ints, but are left justified in the number of bytes used by the
|
||||
// original data.
|
||||
|
||||
int WavpackGetBitsPerSample (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->config.bits_per_sample : 16;
|
||||
}
|
||||
|
||||
// Returns the number of bytes used for each sample (1 to 4) in the original
|
||||
// file. This is required information for the user of this module because the
|
||||
// audio data is returned in the LOWER bytes of the long buffer and must be
|
||||
// left-shifted 8, 16, or 24 bits if normalized longs are required.
|
||||
|
||||
int WavpackGetBytesPerSample (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->config.bytes_per_sample : 2;
|
||||
}
|
||||
|
||||
// If the OPEN_2CH_MAX flag is specified when opening the file, this function
|
||||
// will return the actual number of channels decoded from the file (which may
|
||||
// or may not be less than the actual number of channels, but will always be
|
||||
// 1 or 2). Normally, this will be the front left and right channels of a
|
||||
// multichannel file.
|
||||
|
||||
int WavpackGetReducedChannels (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc)
|
||||
return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Free all memory allocated for raw WavPack blocks (for all allocated streams)
|
||||
// and free all additional streams. This does not free the default stream ([0])
|
||||
// which is always kept around.
|
||||
|
||||
void free_streams (WavpackContext *wpc)
|
||||
{
|
||||
int si = wpc->num_streams;
|
||||
|
||||
while (si--) {
|
||||
if (wpc->streams [si]->blockbuff) {
|
||||
free (wpc->streams [si]->blockbuff);
|
||||
wpc->streams [si]->blockbuff = NULL;
|
||||
}
|
||||
|
||||
if (wpc->streams [si]->block2buff) {
|
||||
free (wpc->streams [si]->block2buff);
|
||||
wpc->streams [si]->block2buff = NULL;
|
||||
}
|
||||
|
||||
if (wpc->streams [si]->sample_buffer) {
|
||||
free (wpc->streams [si]->sample_buffer);
|
||||
wpc->streams [si]->sample_buffer = NULL;
|
||||
}
|
||||
|
||||
if (wpc->streams [si]->dc.shaping_data) {
|
||||
free (wpc->streams [si]->dc.shaping_data);
|
||||
wpc->streams [si]->dc.shaping_data = NULL;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
free_dsd_tables (wpc->streams [si]);
|
||||
#endif
|
||||
|
||||
if (si) {
|
||||
wpc->num_streams--;
|
||||
free (wpc->streams [si]);
|
||||
wpc->streams [si] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wpc->current_stream = 0;
|
||||
}
|
||||
|
||||
void free_dsd_tables (WavpackStream *wps)
|
||||
{
|
||||
if (wps->dsd.probabilities) {
|
||||
free (wps->dsd.probabilities);
|
||||
wps->dsd.probabilities = NULL;
|
||||
}
|
||||
|
||||
if (wps->dsd.summed_probabilities) {
|
||||
free (wps->dsd.summed_probabilities);
|
||||
wps->dsd.summed_probabilities = NULL;
|
||||
}
|
||||
|
||||
if (wps->dsd.lookup_buffer) {
|
||||
free (wps->dsd.lookup_buffer);
|
||||
wps->dsd.lookup_buffer = NULL;
|
||||
}
|
||||
|
||||
if (wps->dsd.value_lookup) {
|
||||
free (wps->dsd.value_lookup);
|
||||
wps->dsd.value_lookup = NULL;
|
||||
}
|
||||
|
||||
if (wps->dsd.ptable) {
|
||||
free (wps->dsd.ptable);
|
||||
wps->dsd.ptable = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp)
|
||||
{
|
||||
f32 *fvalues = (f32 *) values;
|
||||
int exp;
|
||||
|
||||
if (!delta_exp)
|
||||
return;
|
||||
|
||||
while (num_values--) {
|
||||
if ((exp = get_exponent (*fvalues)) == 0 || exp + delta_exp <= 0)
|
||||
*fvalues = 0;
|
||||
else if (exp == 255 || (exp += delta_exp) >= 255) {
|
||||
set_exponent (*fvalues, 255);
|
||||
set_mantissa (*fvalues, 0);
|
||||
}
|
||||
else
|
||||
set_exponent (*fvalues, exp);
|
||||
|
||||
fvalues++;
|
||||
}
|
||||
}
|
||||
|
||||
void WavpackLittleEndianToNative (void *data, char *format)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) data;
|
||||
int64_t temp;
|
||||
|
||||
while (*format) {
|
||||
switch (*format) {
|
||||
case 'D':
|
||||
temp = cp [0] + ((int64_t) cp [1] << 8) + ((int64_t) cp [2] << 16) + ((int64_t) cp [3] << 24) +
|
||||
((int64_t) cp [4] << 32) + ((int64_t) cp [5] << 40) + ((int64_t) cp [6] << 48) + ((int64_t) cp [7] << 56);
|
||||
* (int64_t *) cp = temp;
|
||||
cp += 8;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24);
|
||||
* (int32_t *) cp = (int32_t) temp;
|
||||
cp += 4;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
temp = cp [0] + (cp [1] << 8);
|
||||
* (int16_t *) cp = (int16_t) temp;
|
||||
cp += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit (*format))
|
||||
cp += *format - '0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
void WavpackNativeToLittleEndian (void *data, char *format)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) data;
|
||||
int64_t temp;
|
||||
|
||||
while (*format) {
|
||||
switch (*format) {
|
||||
case 'D':
|
||||
temp = * (int64_t *) cp;
|
||||
*cp++ = (unsigned char) temp;
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) (temp >> 16);
|
||||
*cp++ = (unsigned char) (temp >> 24);
|
||||
*cp++ = (unsigned char) (temp >> 32);
|
||||
*cp++ = (unsigned char) (temp >> 40);
|
||||
*cp++ = (unsigned char) (temp >> 48);
|
||||
*cp++ = (unsigned char) (temp >> 56);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
temp = * (int32_t *) cp;
|
||||
*cp++ = (unsigned char) temp;
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) (temp >> 16);
|
||||
*cp++ = (unsigned char) (temp >> 24);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
temp = * (int16_t *) cp;
|
||||
*cp++ = (unsigned char) temp;
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit (*format))
|
||||
cp += *format - '0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
void WavpackBigEndianToNative (void *data, char *format)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) data;
|
||||
int64_t temp;
|
||||
|
||||
while (*format) {
|
||||
switch (*format) {
|
||||
case 'D':
|
||||
temp = cp [7] + ((int64_t) cp [6] << 8) + ((int64_t) cp [5] << 16) + ((int64_t) cp [4] << 24) +
|
||||
((int64_t) cp [3] << 32) + ((int64_t) cp [2] << 40) + ((int64_t) cp [1] << 48) + ((int64_t) cp [0] << 56);
|
||||
* (int64_t *) cp = temp;
|
||||
cp += 8;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
temp = cp [3] + ((int32_t) cp [2] << 8) + ((int32_t) cp [1] << 16) + ((int32_t) cp [0] << 24);
|
||||
* (int32_t *) cp = (int32_t) temp;
|
||||
cp += 4;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
temp = cp [1] + (cp [0] << 8);
|
||||
* (int16_t *) cp = (int16_t) temp;
|
||||
cp += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit (*format))
|
||||
cp += *format - '0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
void WavpackNativeToBigEndian (void *data, char *format)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) data;
|
||||
int64_t temp;
|
||||
|
||||
while (*format) {
|
||||
switch (*format) {
|
||||
case 'D':
|
||||
temp = * (int64_t *) cp;
|
||||
*cp++ = (unsigned char) (temp >> 56);
|
||||
*cp++ = (unsigned char) (temp >> 48);
|
||||
*cp++ = (unsigned char) (temp >> 40);
|
||||
*cp++ = (unsigned char) (temp >> 32);
|
||||
*cp++ = (unsigned char) (temp >> 24);
|
||||
*cp++ = (unsigned char) (temp >> 16);
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) temp;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
temp = * (int32_t *) cp;
|
||||
*cp++ = (unsigned char) (temp >> 24);
|
||||
*cp++ = (unsigned char) (temp >> 16);
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) temp;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
temp = * (int16_t *) cp;
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) temp;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit (*format))
|
||||
cp += *format - '0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t WavpackGetLibraryVersion (void)
|
||||
{
|
||||
return (LIBWAVPACK_MAJOR<<16)
|
||||
|(LIBWAVPACK_MINOR<<8)
|
||||
|(LIBWAVPACK_MICRO<<0);
|
||||
}
|
||||
|
||||
const char *WavpackGetLibraryVersionString (void)
|
||||
{
|
||||
return LIBWAVPACK_VERSION_STRING;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -1,204 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// decorr_utils.c
|
||||
|
||||
// This module contains the functions that process metadata blocks that are
|
||||
// specific to the decorrelator. These would be called any time a WavPack
|
||||
// block was parsed. These are in a module separate from the actual unpack
|
||||
// decorrelation code (unpack.c) so that if an application just wants to get
|
||||
// information from WavPack files (rather than actually decoding audio) then
|
||||
// less code needs to be linked.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// Read decorrelation terms from specified metadata block into the
|
||||
// decorr_passes array. The terms range from -3 to 8, plus 17 & 18;
|
||||
// other values are reserved and generate errors for now. The delta
|
||||
// ranges from 0 to 7 with all values valid. Note that the terms are
|
||||
// stored in the opposite order in the decorr_passes array compared
|
||||
// to packing.
|
||||
|
||||
int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
int termcnt = wpmd->byte_length;
|
||||
unsigned char *byteptr = (unsigned char *)wpmd->data;
|
||||
struct decorr_pass *dpp;
|
||||
|
||||
if (termcnt > MAX_NTERMS)
|
||||
return FALSE;
|
||||
|
||||
wps->num_terms = termcnt;
|
||||
|
||||
for (dpp = wps->decorr_passes + termcnt - 1; termcnt--; dpp--) {
|
||||
dpp->term = (int)(*byteptr & 0x1f) - 5;
|
||||
dpp->delta = (*byteptr++ >> 5) & 0x7;
|
||||
|
||||
if (!dpp->term || dpp->term < -3 || (dpp->term > MAX_TERM && dpp->term < 17) || dpp->term > 18 ||
|
||||
((wps->wphdr.flags & MONO_DATA) && dpp->term < 0))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Read decorrelation weights from specified metadata block into the
|
||||
// decorr_passes array. The weights range +/-1024, but are rounded and
|
||||
// truncated to fit in signed chars for metadata storage. Weights are
|
||||
// separate for the two channels and are specified from the "last" term
|
||||
// (first during encode). Unspecified weights are set to zero.
|
||||
|
||||
int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
int termcnt = wpmd->byte_length, tcount;
|
||||
char *byteptr = (char *)wpmd->data;
|
||||
struct decorr_pass *dpp;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
termcnt /= 2;
|
||||
|
||||
if (termcnt > wps->num_terms)
|
||||
return FALSE;
|
||||
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
||||
dpp->weight_A = dpp->weight_B = 0;
|
||||
|
||||
while (--dpp >= wps->decorr_passes && termcnt--) {
|
||||
dpp->weight_A = restore_weight (*byteptr++);
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
dpp->weight_B = restore_weight (*byteptr++);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Read decorrelation samples from specified metadata block into the
|
||||
// decorr_passes array. The samples are signed 32-bit values, but are
|
||||
// converted to signed log2 values for storage in metadata. Values are
|
||||
// stored for both channels and are specified from the "last" term
|
||||
// (first during encode) with unspecified samples set to zero. The
|
||||
// number of samples stored varies with the actual term value, so
|
||||
// those must obviously come first in the metadata.
|
||||
|
||||
int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char *byteptr = (unsigned char *)wpmd->data;
|
||||
unsigned char *endptr = byteptr + wpmd->byte_length;
|
||||
struct decorr_pass *dpp;
|
||||
int tcount;
|
||||
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
|
||||
CLEAR (dpp->samples_A);
|
||||
CLEAR (dpp->samples_B);
|
||||
}
|
||||
|
||||
if (wps->wphdr.version == 0x402 && (wps->wphdr.flags & HYBRID_FLAG)) {
|
||||
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr)
|
||||
return FALSE;
|
||||
|
||||
wps->dc.error [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
byteptr += 2;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
wps->dc.error [1] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
byteptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
while (dpp-- > wps->decorr_passes && byteptr < endptr)
|
||||
if (dpp->term > MAX_TERM) {
|
||||
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 4 : 8) > endptr)
|
||||
return FALSE;
|
||||
|
||||
dpp->samples_A [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
dpp->samples_A [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
||||
byteptr += 4;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
dpp->samples_B [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
dpp->samples_B [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
||||
byteptr += 4;
|
||||
}
|
||||
}
|
||||
else if (dpp->term < 0) {
|
||||
if (byteptr + 4 > endptr)
|
||||
return FALSE;
|
||||
|
||||
dpp->samples_A [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
dpp->samples_B [0] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
||||
byteptr += 4;
|
||||
}
|
||||
else {
|
||||
int m = 0, cnt = dpp->term;
|
||||
|
||||
while (cnt--) {
|
||||
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr)
|
||||
return FALSE;
|
||||
|
||||
dpp->samples_A [m] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
byteptr += 2;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
dpp->samples_B [m] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
byteptr += 2;
|
||||
}
|
||||
|
||||
m++;
|
||||
}
|
||||
}
|
||||
|
||||
return byteptr == endptr;
|
||||
}
|
||||
|
||||
// Read the shaping weights from specified metadata block into the
|
||||
// WavpackStream structure. Note that there must be two values (even
|
||||
// for mono streams) and that the values are stored in the same
|
||||
// manner as decorrelation weights. These would normally be read from
|
||||
// the "correction" file and are used for lossless reconstruction of
|
||||
// hybrid data.
|
||||
|
||||
int read_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
if (wpmd->byte_length == 2) {
|
||||
char *byteptr = (char *)wpmd->data;
|
||||
|
||||
wps->dc.shaping_acc [0] = (int32_t) restore_weight (*byteptr++) << 16;
|
||||
wps->dc.shaping_acc [1] = (int32_t) restore_weight (*byteptr++) << 16;
|
||||
return TRUE;
|
||||
}
|
||||
else if (wpmd->byte_length >= (wps->wphdr.flags & MONO_DATA ? 4 : 8)) {
|
||||
unsigned char *byteptr = (unsigned char *)wpmd->data;
|
||||
|
||||
wps->dc.error [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
wps->dc.shaping_acc [0] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
||||
byteptr += 4;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
wps->dc.error [1] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
wps->dc.shaping_acc [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
||||
byteptr += 4;
|
||||
}
|
||||
|
||||
if (wpmd->byte_length == (wps->wphdr.flags & MONO_DATA ? 6 : 12)) {
|
||||
wps->dc.shaping_delta [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
wps->dc.shaping_delta [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
|
@ -1,378 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// entropy_utils.c
|
||||
|
||||
// This module contains the functions that process metadata blocks that are
|
||||
// specific to the entropy decoder; these would be called any time a WavPack
|
||||
// block was parsed. Additionally, it contains tables and functions that are
|
||||
// common to both entropy coding and decoding. These are in a module separate
|
||||
// from the actual entropy encoder (write_words.c) and decoder (read_words.c)
|
||||
// so that if applications that just do a subset of the full WavPack reading
|
||||
// and writing can link with a subset of the library.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// local table storage ////////////////////////////
|
||||
|
||||
const uint32_t bitset [] = {
|
||||
1L << 0, 1L << 1, 1L << 2, 1L << 3,
|
||||
1L << 4, 1L << 5, 1L << 6, 1L << 7,
|
||||
1L << 8, 1L << 9, 1L << 10, 1L << 11,
|
||||
1L << 12, 1L << 13, 1L << 14, 1L << 15,
|
||||
1L << 16, 1L << 17, 1L << 18, 1L << 19,
|
||||
1L << 20, 1L << 21, 1L << 22, 1L << 23,
|
||||
1L << 24, 1L << 25, 1L << 26, 1L << 27,
|
||||
1L << 28, 1L << 29, 1L << 30, 1L << 31
|
||||
};
|
||||
|
||||
const uint32_t bitmask [] = {
|
||||
(1L << 0) - 1, (1L << 1) - 1, (1L << 2) - 1, (1L << 3) - 1,
|
||||
(1L << 4) - 1, (1L << 5) - 1, (1L << 6) - 1, (1L << 7) - 1,
|
||||
(1L << 8) - 1, (1L << 9) - 1, (1L << 10) - 1, (1L << 11) - 1,
|
||||
(1L << 12) - 1, (1L << 13) - 1, (1L << 14) - 1, (1L << 15) - 1,
|
||||
(1L << 16) - 1, (1L << 17) - 1, (1L << 18) - 1, (1L << 19) - 1,
|
||||
(1L << 20) - 1, (1L << 21) - 1, (1L << 22) - 1, (1L << 23) - 1,
|
||||
(1L << 24) - 1, (1L << 25) - 1, (1L << 26) - 1, (1L << 27) - 1,
|
||||
(1L << 28) - 1, (1L << 29) - 1, (1L << 30) - 1, 0x7fffffff
|
||||
};
|
||||
|
||||
const char nbits_table [] = {
|
||||
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 15
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 16 - 31
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 32 - 47
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 48 - 63
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 64 - 79
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 80 - 95
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 96 - 111
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 112 - 127
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 128 - 143
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 144 - 159
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 160 - 175
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 176 - 191
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 192 - 207
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 208 - 223
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 224 - 239
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 // 240 - 255
|
||||
};
|
||||
|
||||
static const unsigned char log2_table [] = {
|
||||
0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15,
|
||||
0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a,
|
||||
0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e,
|
||||
0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
|
||||
0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
|
||||
0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75,
|
||||
0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85,
|
||||
0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
|
||||
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
|
||||
0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2,
|
||||
0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0,
|
||||
0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce,
|
||||
0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb,
|
||||
0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4,
|
||||
0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff
|
||||
};
|
||||
|
||||
static const unsigned char exp2_table [] = {
|
||||
0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16,
|
||||
0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23,
|
||||
0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d,
|
||||
0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
|
||||
0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
|
||||
0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
|
||||
0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
|
||||
0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a,
|
||||
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
|
||||
0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
|
||||
0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
|
||||
0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4,
|
||||
0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9,
|
||||
0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff
|
||||
};
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// Read the median log2 values from the specified metadata structure, convert
|
||||
// them back to 32-bit unsigned values and store them. If length is not
|
||||
// exactly correct then we flag and return an error.
|
||||
|
||||
int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char *byteptr = (unsigned char *)wpmd->data;
|
||||
|
||||
if (wpmd->byte_length != ((wps->wphdr.flags & MONO_DATA) ? 6 : 12))
|
||||
return FALSE;
|
||||
|
||||
wps->w.c [0].median [0] = wp_exp2s (byteptr [0] + (byteptr [1] << 8));
|
||||
wps->w.c [0].median [1] = wp_exp2s (byteptr [2] + (byteptr [3] << 8));
|
||||
wps->w.c [0].median [2] = wp_exp2s (byteptr [4] + (byteptr [5] << 8));
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
wps->w.c [1].median [0] = wp_exp2s (byteptr [6] + (byteptr [7] << 8));
|
||||
wps->w.c [1].median [1] = wp_exp2s (byteptr [8] + (byteptr [9] << 8));
|
||||
wps->w.c [1].median [2] = wp_exp2s (byteptr [10] + (byteptr [11] << 8));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Read the hybrid related values from the specified metadata structure, convert
|
||||
// them back to their internal formats and store them. The extended profile
|
||||
// stuff is not implemented yet, so return an error if we get more data than
|
||||
// we know what to do with.
|
||||
|
||||
int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char *byteptr = (unsigned char *)wpmd->data;
|
||||
unsigned char *endptr = byteptr + wpmd->byte_length;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr)
|
||||
return FALSE;
|
||||
|
||||
wps->w.c [0].slow_level = wp_exp2s (byteptr [0] + (byteptr [1] << 8));
|
||||
byteptr += 2;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
wps->w.c [1].slow_level = wp_exp2s (byteptr [0] + (byteptr [1] << 8));
|
||||
byteptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr)
|
||||
return FALSE;
|
||||
|
||||
wps->w.bitrate_acc [0] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16;
|
||||
byteptr += 2;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
wps->w.bitrate_acc [1] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16;
|
||||
byteptr += 2;
|
||||
}
|
||||
|
||||
if (byteptr < endptr) {
|
||||
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr)
|
||||
return FALSE;
|
||||
|
||||
wps->w.bitrate_delta [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
byteptr += 2;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
wps->w.bitrate_delta [1] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
byteptr += 2;
|
||||
}
|
||||
|
||||
if (byteptr < endptr)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
wps->w.bitrate_delta [0] = wps->w.bitrate_delta [1] = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// This function is called during both encoding and decoding of hybrid data to
|
||||
// update the "error_limit" variable which determines the maximum sample error
|
||||
// allowed in the main bitstream. In the HYBRID_BITRATE mode (which is the only
|
||||
// currently implemented) this is calculated from the slow_level values and the
|
||||
// bitrate accumulators. Note that the bitrate accumulators can be changing.
|
||||
|
||||
void update_error_limit (WavpackStream *wps)
|
||||
{
|
||||
int bitrate_0 = (wps->w.bitrate_acc [0] += wps->w.bitrate_delta [0]) >> 16;
|
||||
|
||||
if (wps->wphdr.flags & MONO_DATA) {
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
int slow_log_0 = (wps->w.c [0].slow_level + SLO) >> SLS;
|
||||
|
||||
if (slow_log_0 - bitrate_0 > -0x100)
|
||||
wps->w.c [0].error_limit = wp_exp2s (slow_log_0 - bitrate_0 + 0x100);
|
||||
else
|
||||
wps->w.c [0].error_limit = 0;
|
||||
}
|
||||
else
|
||||
wps->w.c [0].error_limit = wp_exp2s (bitrate_0);
|
||||
}
|
||||
else {
|
||||
int bitrate_1 = (wps->w.bitrate_acc [1] += wps->w.bitrate_delta [1]) >> 16;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
int slow_log_0 = (wps->w.c [0].slow_level + SLO) >> SLS;
|
||||
int slow_log_1 = (wps->w.c [1].slow_level + SLO) >> SLS;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BALANCE) {
|
||||
int balance = (slow_log_1 - slow_log_0 + bitrate_1 + 1) >> 1;
|
||||
|
||||
if (balance > bitrate_0) {
|
||||
bitrate_1 = bitrate_0 * 2;
|
||||
bitrate_0 = 0;
|
||||
}
|
||||
else if (-balance > bitrate_0) {
|
||||
bitrate_0 = bitrate_0 * 2;
|
||||
bitrate_1 = 0;
|
||||
}
|
||||
else {
|
||||
bitrate_1 = bitrate_0 + balance;
|
||||
bitrate_0 = bitrate_0 - balance;
|
||||
}
|
||||
}
|
||||
|
||||
if (slow_log_0 - bitrate_0 > -0x100)
|
||||
wps->w.c [0].error_limit = wp_exp2s (slow_log_0 - bitrate_0 + 0x100);
|
||||
else
|
||||
wps->w.c [0].error_limit = 0;
|
||||
|
||||
if (slow_log_1 - bitrate_1 > -0x100)
|
||||
wps->w.c [1].error_limit = wp_exp2s (slow_log_1 - bitrate_1 + 0x100);
|
||||
else
|
||||
wps->w.c [1].error_limit = 0;
|
||||
}
|
||||
else {
|
||||
wps->w.c [0].error_limit = wp_exp2s (bitrate_0);
|
||||
wps->w.c [1].error_limit = wp_exp2s (bitrate_1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The concept of a base 2 logarithm is used in many parts of WavPack. It is
|
||||
// a way of sufficiently accurately representing 32-bit signed and unsigned
|
||||
// values storing only 16 bits (actually fewer). It is also used in the hybrid
|
||||
// mode for quickly comparing the relative magnitude of large values (i.e.
|
||||
// division) and providing smooth exponentials using only addition.
|
||||
|
||||
// These are not strict logarithms in that they become linear around zero and
|
||||
// can therefore represent both zero and negative values. They have 8 bits
|
||||
// of precision and in "roundtrip" conversions the total error never exceeds 1
|
||||
// part in 225 except for the cases of +/-115 and +/-195 (which error by 1).
|
||||
|
||||
|
||||
// This function returns the log2 for the specified 32-bit unsigned value.
|
||||
// The maximum value allowed is about 0xff800000 and returns 8447.
|
||||
|
||||
int FASTCALL wp_log2 (uint32_t avalue)
|
||||
{
|
||||
int dbits;
|
||||
|
||||
if ((avalue += avalue >> 9) < (1 << 8)) {
|
||||
dbits = nbits_table [avalue];
|
||||
return (dbits << 8) + log2_table [(avalue << (9 - dbits)) & 0xff];
|
||||
}
|
||||
else {
|
||||
if (avalue < (1L << 16))
|
||||
dbits = nbits_table [avalue >> 8] + 8;
|
||||
else if (avalue < (1L << 24))
|
||||
dbits = nbits_table [avalue >> 16] + 16;
|
||||
else
|
||||
dbits = nbits_table [avalue >> 24] + 24;
|
||||
|
||||
return (dbits << 8) + log2_table [(avalue >> (dbits - 9)) & 0xff];
|
||||
}
|
||||
}
|
||||
|
||||
// This function scans a buffer of longs and accumulates the total log2 value
|
||||
// of all the samples. This is useful for determining maximum compression
|
||||
// because the bitstream storage required for entropy coding is proportional
|
||||
// to the base 2 log of the samples. On some platforms there is an assembly
|
||||
// version of this.
|
||||
|
||||
#if !defined(OPT_ASM_X86) && !defined(OPT_ASM_X64)
|
||||
|
||||
uint32_t log2buffer (int32_t *samples, uint32_t num_samples, int limit)
|
||||
{
|
||||
uint32_t result = 0, avalue;
|
||||
int dbits;
|
||||
|
||||
while (num_samples--) {
|
||||
avalue = abs (*samples++);
|
||||
|
||||
if ((avalue += avalue >> 9) < (1 << 8)) {
|
||||
dbits = nbits_table [avalue];
|
||||
result += (dbits << 8) + log2_table [(avalue << (9 - dbits)) & 0xff];
|
||||
}
|
||||
else {
|
||||
if (avalue < (1L << 16))
|
||||
dbits = nbits_table [avalue >> 8] + 8;
|
||||
else if (avalue < (1L << 24))
|
||||
dbits = nbits_table [avalue >> 16] + 16;
|
||||
else
|
||||
dbits = nbits_table [avalue >> 24] + 24;
|
||||
|
||||
result += dbits = (dbits << 8) + log2_table [(avalue >> (dbits - 9)) & 0xff];
|
||||
|
||||
if (limit && dbits >= limit)
|
||||
return (uint32_t) -1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// This function returns the log2 for the specified 32-bit signed value.
|
||||
// All input values are valid and the return values are in the range of
|
||||
// +/- 8192.
|
||||
|
||||
int wp_log2s (int32_t value)
|
||||
{
|
||||
return (value < 0) ? -wp_log2 (-value) : wp_log2 (value);
|
||||
}
|
||||
|
||||
// This function returns the original integer represented by the supplied
|
||||
// logarithm (at least within the provided accuracy). The log is signed,
|
||||
// but since a full 32-bit value is returned this can be used for unsigned
|
||||
// conversions as well (i.e. the input range is -8192 to +8447).
|
||||
|
||||
int32_t wp_exp2s (int log)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
if (log < 0)
|
||||
return -wp_exp2s (-log);
|
||||
|
||||
value = exp2_table [log & 0xff] | 0x100;
|
||||
|
||||
if ((log >>= 8) <= 9)
|
||||
return value >> (9 - log);
|
||||
else
|
||||
return value << (log - 9);
|
||||
}
|
||||
|
||||
// These two functions convert internal weights (which are normally +/-1024)
|
||||
// to and from an 8-bit signed character version for storage in metadata. The
|
||||
// weights are clipped here in the case that they are outside that range.
|
||||
|
||||
signed char store_weight (int weight)
|
||||
{
|
||||
if (weight > 1024)
|
||||
weight = 1024;
|
||||
else if (weight < -1024)
|
||||
weight = -1024;
|
||||
|
||||
if (weight > 0)
|
||||
weight -= (weight + 64) >> 7;
|
||||
|
||||
return (weight + 4) >> 3;
|
||||
}
|
||||
|
||||
int restore_weight (signed char weight)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result = (int) weight << 3) > 0)
|
||||
result += (result + 64) >> 7;
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,704 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// extra1.c
|
||||
|
||||
// This module handles the "extra" mode for mono files.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
// This flag causes this module to take into account the size of the header
|
||||
// (which grows with more decorrelation passes) when making decisions about
|
||||
// adding additional passes (as opposed to just considering the resulting
|
||||
// magnitude of the residuals). With really long blocks it seems to actually
|
||||
// hurt compression (for reasons I cannot explain), but with short blocks it
|
||||
// works okay, so we're enabling it for now.
|
||||
|
||||
#define USE_OVERHEAD
|
||||
|
||||
// If the log2 value of any sample in a buffer being scanned exceeds this value,
|
||||
// we abandon that configuration. This prevents us from going down paths that
|
||||
// are wildly unstable.
|
||||
|
||||
#define LOG_LIMIT 6912
|
||||
|
||||
//#define EXTRA_DUMP // dump generated filter data error_line()
|
||||
|
||||
#ifdef OPT_ASM_X86
|
||||
#define PACK_DECORR_MONO_PASS_CONT pack_decorr_mono_pass_cont_x86
|
||||
#elif defined(OPT_ASM_X64) && (defined (_WIN64) || defined(__CYGWIN__) || defined(__MINGW64__) || defined(__midipix__))
|
||||
#define PACK_DECORR_MONO_PASS_CONT pack_decorr_mono_pass_cont_x64win
|
||||
#elif defined(OPT_ASM_X64)
|
||||
#define PACK_DECORR_MONO_PASS_CONT pack_decorr_mono_pass_cont_x64
|
||||
#endif
|
||||
|
||||
#ifdef PACK_DECORR_MONO_PASS_CONT
|
||||
void PACK_DECORR_MONO_PASS_CONT (int32_t *out_buffer, int32_t *in_buffer, struct decorr_pass *dpp, int32_t sample_count);
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int32_t *sampleptrs [MAX_NTERMS+2];
|
||||
struct decorr_pass dps [MAX_NTERMS];
|
||||
int nterms, log_limit;
|
||||
uint32_t best_bits;
|
||||
} WavpackExtraInfo;
|
||||
|
||||
static void decorr_mono_pass (int32_t *in_samples, int32_t *out_samples, uint32_t num_samples, struct decorr_pass *dpp, int dir)
|
||||
{
|
||||
int32_t cont_samples = 0;
|
||||
int m = 0, i;
|
||||
|
||||
#ifdef PACK_DECORR_MONO_PASS_CONT
|
||||
if (num_samples > 16 && dir > 0) {
|
||||
int32_t pre_samples = (dpp->term > MAX_TERM) ? 2 : dpp->term;
|
||||
cont_samples = num_samples - pre_samples;
|
||||
num_samples = pre_samples;
|
||||
}
|
||||
#endif
|
||||
|
||||
dpp->sum_A = 0;
|
||||
|
||||
if (dir < 0) {
|
||||
out_samples += (num_samples + cont_samples - 1);
|
||||
in_samples += (num_samples + cont_samples - 1);
|
||||
dir = -1;
|
||||
}
|
||||
else
|
||||
dir = 1;
|
||||
|
||||
dpp->weight_A = restore_weight (store_weight (dpp->weight_A));
|
||||
|
||||
for (i = 0; i < 8; ++i)
|
||||
dpp->samples_A [i] = wp_exp2s (wp_log2s (dpp->samples_A [i]));
|
||||
|
||||
if (dpp->term > MAX_TERM) {
|
||||
while (num_samples--) {
|
||||
int32_t left, sam_A;
|
||||
|
||||
if (dpp->term & 1)
|
||||
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
else
|
||||
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
dpp->samples_A [0] = left = in_samples [0];
|
||||
|
||||
left -= apply_weight (dpp->weight_A, sam_A);
|
||||
update_weight (dpp->weight_A, dpp->delta, sam_A, left);
|
||||
dpp->sum_A += dpp->weight_A;
|
||||
out_samples [0] = left;
|
||||
in_samples += dir;
|
||||
out_samples += dir;
|
||||
}
|
||||
}
|
||||
else if (dpp->term > 0) {
|
||||
while (num_samples--) {
|
||||
int k = (m + dpp->term) & (MAX_TERM - 1);
|
||||
int32_t left, sam_A;
|
||||
|
||||
sam_A = dpp->samples_A [m];
|
||||
dpp->samples_A [k] = left = in_samples [0];
|
||||
m = (m + 1) & (MAX_TERM - 1);
|
||||
|
||||
left -= apply_weight (dpp->weight_A, sam_A);
|
||||
update_weight (dpp->weight_A, dpp->delta, sam_A, left);
|
||||
dpp->sum_A += dpp->weight_A;
|
||||
out_samples [0] = left;
|
||||
in_samples += dir;
|
||||
out_samples += dir;
|
||||
}
|
||||
}
|
||||
|
||||
if (m && dpp->term > 0 && dpp->term <= MAX_TERM) {
|
||||
int32_t temp_A [MAX_TERM];
|
||||
int k;
|
||||
|
||||
memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A));
|
||||
|
||||
for (k = 0; k < MAX_TERM; k++) {
|
||||
dpp->samples_A [k] = temp_A [m];
|
||||
m = (m + 1) & (MAX_TERM - 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PACK_DECORR_MONO_PASS_CONT
|
||||
if (cont_samples)
|
||||
PACK_DECORR_MONO_PASS_CONT (out_samples, in_samples, dpp, cont_samples);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void reverse_mono_decorr (struct decorr_pass *dpp)
|
||||
{
|
||||
if (dpp->term > MAX_TERM) {
|
||||
int32_t sam_A;
|
||||
|
||||
if (dpp->term & 1)
|
||||
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
else
|
||||
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
dpp->samples_A [0] = sam_A;
|
||||
|
||||
if (dpp->term & 1)
|
||||
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
else
|
||||
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||
|
||||
dpp->samples_A [1] = sam_A;
|
||||
}
|
||||
else if (dpp->term > 1) {
|
||||
int i = 0, j = dpp->term - 1, cnt = dpp->term / 2;
|
||||
|
||||
while (cnt--) {
|
||||
i &= (MAX_TERM - 1);
|
||||
j &= (MAX_TERM - 1);
|
||||
dpp->samples_A [i] ^= dpp->samples_A [j];
|
||||
dpp->samples_A [j] ^= dpp->samples_A [i];
|
||||
dpp->samples_A [i++] ^= dpp->samples_A [j--];
|
||||
}
|
||||
|
||||
// CLEAR (dpp->samples_A);
|
||||
}
|
||||
}
|
||||
|
||||
static void decorr_mono_buffer (int32_t *samples, int32_t *outsamples, uint32_t num_samples, struct decorr_pass *dpp, int tindex)
|
||||
{
|
||||
struct decorr_pass dp, *dppi = dpp + tindex;
|
||||
int delta = dppi->delta, pre_delta, term = dppi->term;
|
||||
|
||||
if (delta == 7)
|
||||
pre_delta = 7;
|
||||
else if (delta < 2)
|
||||
pre_delta = 3;
|
||||
else
|
||||
pre_delta = delta + 1;
|
||||
|
||||
CLEAR (dp);
|
||||
dp.term = term;
|
||||
dp.delta = pre_delta;
|
||||
decorr_mono_pass (samples, outsamples, num_samples > 2048 ? 2048 : num_samples, &dp, -1);
|
||||
dp.delta = delta;
|
||||
|
||||
if (tindex == 0)
|
||||
reverse_mono_decorr (&dp);
|
||||
else
|
||||
CLEAR (dp.samples_A);
|
||||
|
||||
memcpy (dppi->samples_A, dp.samples_A, sizeof (dp.samples_A));
|
||||
dppi->weight_A = dp.weight_A;
|
||||
|
||||
if (delta == 0) {
|
||||
dp.delta = 1;
|
||||
decorr_mono_pass (samples, outsamples, num_samples, &dp, 1);
|
||||
dp.delta = 0;
|
||||
memcpy (dp.samples_A, dppi->samples_A, sizeof (dp.samples_A));
|
||||
dppi->weight_A = dp.weight_A = dp.sum_A / num_samples;
|
||||
}
|
||||
|
||||
// if (memcmp (dppi, &dp, sizeof (dp)))
|
||||
// error_line ("decorr_passes don't match, delta = %d", delta);
|
||||
|
||||
decorr_mono_pass (samples, outsamples, num_samples, &dp, 1);
|
||||
}
|
||||
|
||||
static int log2overhead (int first_term, int num_terms)
|
||||
{
|
||||
#ifdef USE_OVERHEAD
|
||||
if (first_term > MAX_TERM)
|
||||
return (4 + num_terms * 2) << 11;
|
||||
else
|
||||
return (2 + num_terms * 2) << 11;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void recurse_mono (WavpackContext *wpc, WavpackExtraInfo *info, int depth, int delta, uint32_t input_bits)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int term, branches = ((wpc->config.extra_flags & EXTRA_BRANCHES) >> 6) - depth;
|
||||
int32_t *samples, *outsamples;
|
||||
uint32_t term_bits [22], bits;
|
||||
|
||||
if (branches < 1 || depth + 1 == info->nterms)
|
||||
branches = 1;
|
||||
|
||||
CLEAR (term_bits);
|
||||
samples = info->sampleptrs [depth];
|
||||
outsamples = info->sampleptrs [depth + 1];
|
||||
|
||||
for (term = 1; term <= 18; ++term) {
|
||||
if (term == 17 && branches == 1 && depth + 1 < info->nterms)
|
||||
continue;
|
||||
|
||||
if (term > 8 && term < 17)
|
||||
continue;
|
||||
|
||||
if ((wpc->config.flags & CONFIG_FAST_FLAG) && (term > 4 && term < 17))
|
||||
continue;
|
||||
|
||||
info->dps [depth].term = term;
|
||||
info->dps [depth].delta = delta;
|
||||
decorr_mono_buffer (samples, outsamples, wps->wphdr.block_samples, info->dps, depth);
|
||||
bits = LOG2BUFFER (outsamples, wps->wphdr.block_samples, info->log_limit);
|
||||
|
||||
if (bits != (uint32_t) -1)
|
||||
bits += log2overhead (info->dps [0].term, depth + 1);
|
||||
|
||||
if (bits < info->best_bits) {
|
||||
info->best_bits = bits;
|
||||
CLEAR (wps->decorr_passes);
|
||||
memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * (depth + 1));
|
||||
memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [depth + 1], wps->wphdr.block_samples * 4);
|
||||
}
|
||||
|
||||
term_bits [term + 3] = bits;
|
||||
}
|
||||
|
||||
while (depth + 1 < info->nterms && branches--) {
|
||||
uint32_t local_best_bits = input_bits;
|
||||
int best_term = 0, i;
|
||||
|
||||
for (i = 0; i < 22; ++i)
|
||||
if (term_bits [i] && term_bits [i] < local_best_bits) {
|
||||
local_best_bits = term_bits [i];
|
||||
// term_bits [i] = 0;
|
||||
best_term = i - 3;
|
||||
}
|
||||
|
||||
if (!best_term)
|
||||
break;
|
||||
|
||||
term_bits [best_term + 3] = 0;
|
||||
|
||||
info->dps [depth].term = best_term;
|
||||
info->dps [depth].delta = delta;
|
||||
decorr_mono_buffer (samples, outsamples, wps->wphdr.block_samples, info->dps, depth);
|
||||
|
||||
// if (log2buffer (outsamples, wps->wphdr.block_samples * 2, 0) != local_best_bits)
|
||||
// error_line ("data doesn't match!");
|
||||
|
||||
recurse_mono (wpc, info, depth + 1, delta, local_best_bits);
|
||||
}
|
||||
}
|
||||
|
||||
static void delta_mono (WavpackContext *wpc, WavpackExtraInfo *info)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int lower = FALSE, delta, d;
|
||||
uint32_t bits;
|
||||
|
||||
if (wps->decorr_passes [0].term)
|
||||
delta = wps->decorr_passes [0].delta;
|
||||
else
|
||||
return;
|
||||
|
||||
for (d = delta - 1; d >= 0; --d) {
|
||||
int i;
|
||||
|
||||
if (!d && (wps->wphdr.flags & HYBRID_FLAG))
|
||||
break;
|
||||
|
||||
for (i = 0; i < info->nterms && wps->decorr_passes [i].term; ++i) {
|
||||
info->dps [i].term = wps->decorr_passes [i].term;
|
||||
info->dps [i].delta = d;
|
||||
decorr_mono_buffer (info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, info->dps, i);
|
||||
}
|
||||
|
||||
bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples, info->log_limit);
|
||||
|
||||
if (bits != (uint32_t) -1)
|
||||
bits += log2overhead (wps->decorr_passes [0].term, i);
|
||||
|
||||
if (bits < info->best_bits) {
|
||||
lower = TRUE;
|
||||
info->best_bits = bits;
|
||||
CLEAR (wps->decorr_passes);
|
||||
memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i);
|
||||
memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 4);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
for (d = delta + 1; !lower && d <= 7; ++d) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < info->nterms && wps->decorr_passes [i].term; ++i) {
|
||||
info->dps [i].term = wps->decorr_passes [i].term;
|
||||
info->dps [i].delta = d;
|
||||
decorr_mono_buffer (info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, info->dps, i);
|
||||
}
|
||||
|
||||
bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples, info->log_limit);
|
||||
|
||||
if (bits != (uint32_t) -1)
|
||||
bits += log2overhead (wps->decorr_passes [0].term, i);
|
||||
|
||||
if (bits < info->best_bits) {
|
||||
info->best_bits = bits;
|
||||
CLEAR (wps->decorr_passes);
|
||||
memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i);
|
||||
memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 4);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sort_mono (WavpackContext *wpc, WavpackExtraInfo *info)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int reversed = TRUE;
|
||||
uint32_t bits;
|
||||
|
||||
while (reversed) {
|
||||
int ri, i;
|
||||
|
||||
memcpy (info->dps, wps->decorr_passes, sizeof (wps->decorr_passes));
|
||||
reversed = FALSE;
|
||||
|
||||
for (ri = 0; ri < info->nterms && wps->decorr_passes [ri].term; ++ri) {
|
||||
|
||||
if (ri + 1 >= info->nterms || !wps->decorr_passes [ri+1].term)
|
||||
break;
|
||||
|
||||
if (wps->decorr_passes [ri].term == wps->decorr_passes [ri+1].term) {
|
||||
decorr_mono_buffer (info->sampleptrs [ri], info->sampleptrs [ri+1], wps->wphdr.block_samples, info->dps, ri);
|
||||
continue;
|
||||
}
|
||||
|
||||
info->dps [ri] = wps->decorr_passes [ri+1];
|
||||
info->dps [ri+1] = wps->decorr_passes [ri];
|
||||
|
||||
for (i = ri; i < info->nterms && wps->decorr_passes [i].term; ++i)
|
||||
decorr_mono_buffer (info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, info->dps, i);
|
||||
|
||||
bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples, info->log_limit);
|
||||
|
||||
if (bits != (uint32_t) -1)
|
||||
bits += log2overhead (wps->decorr_passes [0].term, i);
|
||||
|
||||
if (bits < info->best_bits) {
|
||||
reversed = TRUE;
|
||||
info->best_bits = bits;
|
||||
CLEAR (wps->decorr_passes);
|
||||
memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i);
|
||||
memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 4);
|
||||
}
|
||||
else {
|
||||
info->dps [ri] = wps->decorr_passes [ri];
|
||||
info->dps [ri+1] = wps->decorr_passes [ri+1];
|
||||
decorr_mono_buffer (info->sampleptrs [ri], info->sampleptrs [ri+1], wps->wphdr.block_samples, info->dps, ri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32_t xtable [] = { 91, 123, 187, 251 };
|
||||
|
||||
static void analyze_mono (WavpackContext *wpc, int32_t *samples, int do_samples)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
WavpackExtraInfo info;
|
||||
int i;
|
||||
|
||||
#ifdef LOG_LIMIT
|
||||
info.log_limit = (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) + 4) * 256;
|
||||
|
||||
if (info.log_limit > LOG_LIMIT)
|
||||
info.log_limit = LOG_LIMIT;
|
||||
#else
|
||||
info.log_limit = 0;
|
||||
#endif
|
||||
|
||||
if (wpc->config.flags & (CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG))
|
||||
wpc->config.extra_flags = xtable [wpc->config.xmode - 4];
|
||||
else
|
||||
wpc->config.extra_flags = xtable [wpc->config.xmode - 3];
|
||||
|
||||
info.nterms = wps->num_terms;
|
||||
|
||||
for (i = 0; i < info.nterms + 2; ++i)
|
||||
info.sampleptrs [i] = malloc (wps->wphdr.block_samples * 4);
|
||||
|
||||
memcpy (info.dps, wps->decorr_passes, sizeof (info.dps));
|
||||
memcpy (info.sampleptrs [0], samples, wps->wphdr.block_samples * 4);
|
||||
|
||||
for (i = 0; i < info.nterms && info.dps [i].term; ++i)
|
||||
decorr_mono_pass (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps + i, 1);
|
||||
|
||||
info.best_bits = LOG2BUFFER (info.sampleptrs [info.nterms], wps->wphdr.block_samples, 0) * 1;
|
||||
info.best_bits += log2overhead (info.dps [0].term, i);
|
||||
memcpy (info.sampleptrs [info.nterms + 1], info.sampleptrs [i], wps->wphdr.block_samples * 4);
|
||||
|
||||
if (wpc->config.extra_flags & EXTRA_BRANCHES)
|
||||
recurse_mono (wpc, &info, 0, (int) floor (wps->delta_decay + 0.5),
|
||||
LOG2BUFFER (info.sampleptrs [0], wps->wphdr.block_samples, 0));
|
||||
|
||||
if (wpc->config.extra_flags & EXTRA_SORT_FIRST)
|
||||
sort_mono (wpc, &info);
|
||||
|
||||
if (wpc->config.extra_flags & EXTRA_TRY_DELTAS) {
|
||||
delta_mono (wpc, &info);
|
||||
|
||||
if ((wpc->config.extra_flags & EXTRA_ADJUST_DELTAS) && wps->decorr_passes [0].term)
|
||||
wps->delta_decay = (float)((wps->delta_decay * 2.0 + wps->decorr_passes [0].delta) / 3.0);
|
||||
else
|
||||
wps->delta_decay = 2.0;
|
||||
}
|
||||
|
||||
if (wpc->config.extra_flags & EXTRA_SORT_LAST)
|
||||
sort_mono (wpc, &info);
|
||||
|
||||
if (do_samples)
|
||||
memcpy (samples, info.sampleptrs [info.nterms + 1], wps->wphdr.block_samples * 4);
|
||||
|
||||
for (i = 0; i < info.nterms; ++i)
|
||||
if (!wps->decorr_passes [i].term)
|
||||
break;
|
||||
|
||||
wps->num_terms = i;
|
||||
|
||||
for (i = 0; i < info.nterms + 2; ++i)
|
||||
free (info.sampleptrs [i]);
|
||||
}
|
||||
|
||||
static void mono_add_noise (WavpackStream *wps, int32_t *lptr, int32_t *rptr)
|
||||
{
|
||||
int shaping_weight, new = wps->wphdr.flags & NEW_SHAPING;
|
||||
short *shaping_array = wps->dc.shaping_array;
|
||||
int32_t error = 0, temp, cnt;
|
||||
|
||||
scan_word (wps, rptr, wps->wphdr.block_samples, -1);
|
||||
cnt = wps->wphdr.block_samples;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_SHAPE) {
|
||||
while (cnt--) {
|
||||
if (shaping_array)
|
||||
shaping_weight = *shaping_array++;
|
||||
else
|
||||
shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16;
|
||||
|
||||
temp = -apply_weight (shaping_weight, error);
|
||||
|
||||
if (new && shaping_weight < 0 && temp) {
|
||||
if (temp == error)
|
||||
temp = (temp < 0) ? temp + 1 : temp - 1;
|
||||
|
||||
lptr [0] += (error = nosend_word (wps, rptr [0], 0) - rptr [0] + temp);
|
||||
}
|
||||
else
|
||||
lptr [0] += (error = nosend_word (wps, rptr [0], 0) - rptr [0]) + temp;
|
||||
|
||||
lptr++;
|
||||
rptr++;
|
||||
}
|
||||
|
||||
if (!shaping_array)
|
||||
wps->dc.shaping_acc [0] -= wps->dc.shaping_delta [0] * wps->wphdr.block_samples;
|
||||
}
|
||||
else
|
||||
while (cnt--) {
|
||||
lptr [0] += nosend_word (wps, rptr [0], 0) - rptr [0];
|
||||
lptr++;
|
||||
rptr++;
|
||||
}
|
||||
}
|
||||
|
||||
void execute_mono (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples)
|
||||
{
|
||||
int32_t *temp_buffer [2], *best_buffer, *noisy_buffer = NULL;
|
||||
struct decorr_pass temp_decorr_pass, save_decorr_passes [MAX_NTERMS];
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int32_t num_samples = wps->wphdr.block_samples;
|
||||
int32_t buf_size = sizeof (int32_t) * num_samples;
|
||||
uint32_t best_size = (uint32_t) -1, size;
|
||||
int log_limit, pi, i;
|
||||
|
||||
#ifdef SKIP_DECORRELATION
|
||||
CLEAR (wps->decorr_passes);
|
||||
wps->num_terms = 0;
|
||||
return;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < num_samples; ++i)
|
||||
if (samples [i])
|
||||
break;
|
||||
|
||||
if (i == num_samples) {
|
||||
CLEAR (wps->decorr_passes);
|
||||
wps->num_terms = 0;
|
||||
init_words (wps);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LOG_LIMIT
|
||||
log_limit = (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) + 4) * 256;
|
||||
|
||||
if (log_limit > LOG_LIMIT)
|
||||
log_limit = LOG_LIMIT;
|
||||
#else
|
||||
log_limit = 0;
|
||||
#endif
|
||||
|
||||
CLEAR (save_decorr_passes);
|
||||
temp_buffer [0] = malloc (buf_size);
|
||||
temp_buffer [1] = malloc (buf_size);
|
||||
best_buffer = malloc (buf_size);
|
||||
|
||||
if (wps->num_passes > 1 && (wps->wphdr.flags & HYBRID_FLAG)) {
|
||||
CLEAR (temp_decorr_pass);
|
||||
temp_decorr_pass.delta = 2;
|
||||
temp_decorr_pass.term = 18;
|
||||
|
||||
decorr_mono_pass (samples, temp_buffer [0],
|
||||
num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1);
|
||||
|
||||
reverse_mono_decorr (&temp_decorr_pass);
|
||||
decorr_mono_pass (samples, temp_buffer [0], num_samples, &temp_decorr_pass, 1);
|
||||
CLEAR (temp_decorr_pass);
|
||||
temp_decorr_pass.delta = 2;
|
||||
temp_decorr_pass.term = 17;
|
||||
|
||||
decorr_mono_pass (temp_buffer [0], temp_buffer [1],
|
||||
num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1);
|
||||
|
||||
decorr_mono_pass (temp_buffer [0], temp_buffer [1], num_samples, &temp_decorr_pass, 1);
|
||||
noisy_buffer = malloc (buf_size);
|
||||
memcpy (noisy_buffer, samples, buf_size);
|
||||
mono_add_noise (wps, noisy_buffer, temp_buffer [1]);
|
||||
no_history = 1;
|
||||
}
|
||||
|
||||
if (no_history || wps->num_passes >= 7)
|
||||
wps->best_decorr = wps->mask_decorr = 0;
|
||||
|
||||
for (pi = 0; pi < wps->num_passes;) {
|
||||
const WavpackDecorrSpec *wpds;
|
||||
int nterms, c, j;
|
||||
|
||||
if (!pi)
|
||||
c = wps->best_decorr;
|
||||
else {
|
||||
if (wps->mask_decorr == 0)
|
||||
c = 0;
|
||||
else
|
||||
c = (wps->best_decorr & (wps->mask_decorr - 1)) | wps->mask_decorr;
|
||||
|
||||
if (c == wps->best_decorr) {
|
||||
wps->mask_decorr = wps->mask_decorr ? ((wps->mask_decorr << 1) & (wps->num_decorrs - 1)) : 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
wpds = &wps->decorr_specs [c];
|
||||
nterms = (int) strlen ((char *) wpds->terms);
|
||||
|
||||
while (1) {
|
||||
memcpy (temp_buffer [0], noisy_buffer ? noisy_buffer : samples, buf_size);
|
||||
CLEAR (save_decorr_passes);
|
||||
|
||||
for (j = 0; j < nterms; ++j) {
|
||||
CLEAR (temp_decorr_pass);
|
||||
temp_decorr_pass.delta = wpds->delta;
|
||||
temp_decorr_pass.term = wpds->terms [j];
|
||||
|
||||
if (temp_decorr_pass.term < 0)
|
||||
temp_decorr_pass.term = 1;
|
||||
|
||||
decorr_mono_pass (temp_buffer [j&1], temp_buffer [~j&1],
|
||||
num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1);
|
||||
|
||||
if (j) {
|
||||
CLEAR (temp_decorr_pass.samples_A);
|
||||
}
|
||||
else
|
||||
reverse_mono_decorr (&temp_decorr_pass);
|
||||
|
||||
memcpy (save_decorr_passes + j, &temp_decorr_pass, sizeof (struct decorr_pass));
|
||||
decorr_mono_pass (temp_buffer [j&1], temp_buffer [~j&1], num_samples, &temp_decorr_pass, 1);
|
||||
}
|
||||
|
||||
size = LOG2BUFFER (temp_buffer [j&1], num_samples, log_limit);
|
||||
|
||||
if (size == (uint32_t) -1 && nterms)
|
||||
nterms >>= 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
size += log2overhead (wpds->terms [0], nterms);
|
||||
|
||||
if (size < best_size) {
|
||||
memcpy (best_buffer, temp_buffer [j&1], buf_size);
|
||||
memcpy (wps->decorr_passes, save_decorr_passes, sizeof (struct decorr_pass) * MAX_NTERMS);
|
||||
wps->num_terms = nterms;
|
||||
wps->best_decorr = c;
|
||||
best_size = size;
|
||||
}
|
||||
|
||||
if (pi++)
|
||||
wps->mask_decorr = wps->mask_decorr ? ((wps->mask_decorr << 1) & (wps->num_decorrs - 1)) : 1;
|
||||
}
|
||||
|
||||
if (wpc->config.xmode > 3) {
|
||||
if (noisy_buffer) {
|
||||
analyze_mono (wpc, noisy_buffer, do_samples);
|
||||
|
||||
if (do_samples)
|
||||
memcpy (samples, noisy_buffer, buf_size);
|
||||
}
|
||||
else
|
||||
analyze_mono (wpc, samples, do_samples);
|
||||
}
|
||||
else if (do_samples)
|
||||
memcpy (samples, best_buffer, buf_size);
|
||||
|
||||
if (no_history || wpc->config.xmode > 3)
|
||||
scan_word (wps, best_buffer, num_samples, -1);
|
||||
|
||||
if (noisy_buffer)
|
||||
free (noisy_buffer);
|
||||
|
||||
free (temp_buffer [1]);
|
||||
free (temp_buffer [0]);
|
||||
free (best_buffer);
|
||||
|
||||
#ifdef EXTRA_DUMP
|
||||
if (1) {
|
||||
char string [256], substring [20];
|
||||
int i;
|
||||
|
||||
sprintf (string, "M: terms =");
|
||||
|
||||
for (i = 0; i < wps->num_terms; ++i) {
|
||||
if (wps->decorr_passes [i].term) {
|
||||
if (i && wps->decorr_passes [i-1].delta == wps->decorr_passes [i].delta)
|
||||
sprintf (substring, " %d", wps->decorr_passes [i].term);
|
||||
else
|
||||
sprintf (substring, " %d->%d", wps->decorr_passes [i].term,
|
||||
wps->decorr_passes [i].delta);
|
||||
}
|
||||
else
|
||||
sprintf (substring, " *");
|
||||
|
||||
strcat (string, substring);
|
||||
}
|
||||
|
||||
error_line (string);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,929 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// MMX optimizations (c) 2006 Joachim Henke //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// extra2.c
|
||||
|
||||
// This module handles the "extra" mode for stereo files.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
// This flag causes this module to take into account the size of the header
|
||||
// (which grows with more decorrelation passes) when making decisions about
|
||||
// adding additional passes (as opposed to just considering the resulting
|
||||
// magnitude of the residuals). With really long blocks it seems to actually
|
||||
// hurt compression (for reasons I cannot explain), but with short blocks it
|
||||
// works okay, so we're enabling it for now.
|
||||
|
||||
#define USE_OVERHEAD
|
||||
|
||||
// If the log2 value of any sample in a buffer being scanned exceeds this value,
|
||||
// we abandon that configuration. This prevents us from going down paths that
|
||||
// are wildly unstable.
|
||||
|
||||
#define LOG_LIMIT 6912
|
||||
|
||||
//#define EXTRA_DUMP // dump generated filter data to error_line()
|
||||
|
||||
#ifdef OPT_ASM_X86
|
||||
#define PACK_DECORR_STEREO_PASS_CONT pack_decorr_stereo_pass_cont_x86
|
||||
#define PACK_DECORR_STEREO_PASS_CONT_REV pack_decorr_stereo_pass_cont_rev_x86
|
||||
#define PACK_DECORR_STEREO_PASS_CONT_AVAILABLE pack_cpu_has_feature_x86(CPU_FEATURE_MMX)
|
||||
#elif defined(OPT_ASM_X64) && (defined (_WIN64) || defined(__CYGWIN__) || defined(__MINGW64__) || defined(__midipix__))
|
||||
#define PACK_DECORR_STEREO_PASS_CONT pack_decorr_stereo_pass_cont_x64win
|
||||
#define PACK_DECORR_STEREO_PASS_CONT_REV pack_decorr_stereo_pass_cont_rev_x64win
|
||||
#define PACK_DECORR_STEREO_PASS_CONT_AVAILABLE 1
|
||||
#elif defined(OPT_ASM_X64)
|
||||
#define PACK_DECORR_STEREO_PASS_CONT pack_decorr_stereo_pass_cont_x64
|
||||
#define PACK_DECORR_STEREO_PASS_CONT_REV pack_decorr_stereo_pass_cont_rev_x64
|
||||
#define PACK_DECORR_STEREO_PASS_CONT_AVAILABLE 1
|
||||
#endif
|
||||
|
||||
#ifdef PACK_DECORR_STEREO_PASS_CONT
|
||||
void PACK_DECORR_STEREO_PASS_CONT (struct decorr_pass *dpp, int32_t *in_buffer, int32_t *out_buffer, int32_t sample_count);
|
||||
void PACK_DECORR_STEREO_PASS_CONT_REV (struct decorr_pass *dpp, int32_t *in_buffer, int32_t *out_buffer, int32_t sample_count);
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int32_t *sampleptrs [MAX_NTERMS+2];
|
||||
struct decorr_pass dps [MAX_NTERMS];
|
||||
int nterms, log_limit;
|
||||
uint32_t best_bits;
|
||||
} WavpackExtraInfo;
|
||||
|
||||
static void decorr_stereo_pass (int32_t *in_samples, int32_t *out_samples, int32_t num_samples, struct decorr_pass *dpp, int dir)
|
||||
{
|
||||
int32_t cont_samples = 0;
|
||||
int m = 0, i;
|
||||
|
||||
#ifdef PACK_DECORR_STEREO_PASS_CONT
|
||||
if (num_samples > 16 && PACK_DECORR_STEREO_PASS_CONT_AVAILABLE) {
|
||||
int32_t pre_samples = (dpp->term < 0 || dpp->term > MAX_TERM) ? 2 : dpp->term;
|
||||
cont_samples = num_samples - pre_samples;
|
||||
num_samples = pre_samples;
|
||||
}
|
||||
#endif
|
||||
|
||||
dpp->sum_A = dpp->sum_B = 0;
|
||||
|
||||
if (dir < 0) {
|
||||
out_samples += (num_samples + cont_samples - 1) * 2;
|
||||
in_samples += (num_samples + cont_samples - 1) * 2;
|
||||
dir = -2;
|
||||
}
|
||||
else
|
||||
dir = 2;
|
||||
|
||||
dpp->weight_A = restore_weight (store_weight (dpp->weight_A));
|
||||
dpp->weight_B = restore_weight (store_weight (dpp->weight_B));
|
||||
|
||||
for (i = 0; i < 8; ++i) {
|
||||
dpp->samples_A [i] = wp_exp2s (wp_log2s (dpp->samples_A [i]));
|
||||
dpp->samples_B [i] = wp_exp2s (wp_log2s (dpp->samples_B [i]));
|
||||
}
|
||||
|
||||
switch (dpp->term) {
|
||||
|
||||
case 2:
|
||||
while (num_samples--) {
|
||||
int32_t sam, tmp;
|
||||
|
||||
sam = dpp->samples_A [0];
|
||||
dpp->samples_A [0] = dpp->samples_A [1];
|
||||
out_samples [0] = tmp = (dpp->samples_A [1] = in_samples [0]) - apply_weight (dpp->weight_A, sam);
|
||||
update_weight (dpp->weight_A, dpp->delta, sam, tmp);
|
||||
dpp->sum_A += dpp->weight_A;
|
||||
|
||||
sam = dpp->samples_B [0];
|
||||
dpp->samples_B [0] = dpp->samples_B [1];
|
||||
out_samples [1] = tmp = (dpp->samples_B [1] = in_samples [1]) - apply_weight (dpp->weight_B, sam);
|
||||
update_weight (dpp->weight_B, dpp->delta, sam, tmp);
|
||||
dpp->sum_B += dpp->weight_B;
|
||||
|
||||
in_samples += dir;
|
||||
out_samples += dir;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 17:
|
||||
while (num_samples--) {
|
||||
int32_t sam, tmp;
|
||||
|
||||
sam = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
out_samples [0] = tmp = (dpp->samples_A [0] = in_samples [0]) - apply_weight (dpp->weight_A, sam);
|
||||
update_weight (dpp->weight_A, dpp->delta, sam, tmp);
|
||||
dpp->sum_A += dpp->weight_A;
|
||||
|
||||
sam = 2 * dpp->samples_B [0] - dpp->samples_B [1];
|
||||
dpp->samples_B [1] = dpp->samples_B [0];
|
||||
out_samples [1] = tmp = (dpp->samples_B [0] = in_samples [1]) - apply_weight (dpp->weight_B, sam);
|
||||
update_weight (dpp->weight_B, dpp->delta, sam, tmp);
|
||||
dpp->sum_B += dpp->weight_B;
|
||||
|
||||
in_samples += dir;
|
||||
out_samples += dir;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 18:
|
||||
while (num_samples--) {
|
||||
int32_t sam, tmp;
|
||||
|
||||
sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1);
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
out_samples [0] = tmp = (dpp->samples_A [0] = in_samples [0]) - apply_weight (dpp->weight_A, sam);
|
||||
update_weight (dpp->weight_A, dpp->delta, sam, tmp);
|
||||
dpp->sum_A += dpp->weight_A;
|
||||
|
||||
sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1);
|
||||
dpp->samples_B [1] = dpp->samples_B [0];
|
||||
out_samples [1] = tmp = (dpp->samples_B [0] = in_samples [1]) - apply_weight (dpp->weight_B, sam);
|
||||
update_weight (dpp->weight_B, dpp->delta, sam, tmp);
|
||||
dpp->sum_B += dpp->weight_B;
|
||||
|
||||
in_samples += dir;
|
||||
out_samples += dir;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default: {
|
||||
int k = dpp->term & (MAX_TERM - 1);
|
||||
|
||||
while (num_samples--) {
|
||||
int32_t sam, tmp;
|
||||
|
||||
sam = dpp->samples_A [m];
|
||||
out_samples [0] = tmp = (dpp->samples_A [k] = in_samples [0]) - apply_weight (dpp->weight_A, sam);
|
||||
update_weight (dpp->weight_A, dpp->delta, sam, tmp);
|
||||
dpp->sum_A += dpp->weight_A;
|
||||
|
||||
sam = dpp->samples_B [m];
|
||||
out_samples [1] = tmp = (dpp->samples_B [k] = in_samples [1]) - apply_weight (dpp->weight_B, sam);
|
||||
update_weight (dpp->weight_B, dpp->delta, sam, tmp);
|
||||
dpp->sum_B += dpp->weight_B;
|
||||
|
||||
in_samples += dir;
|
||||
out_samples += dir;
|
||||
m = (m + 1) & (MAX_TERM - 1);
|
||||
k = (k + 1) & (MAX_TERM - 1);
|
||||
}
|
||||
|
||||
if (m) {
|
||||
int32_t temp_A [MAX_TERM], temp_B [MAX_TERM];
|
||||
int k;
|
||||
|
||||
memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A));
|
||||
memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B));
|
||||
|
||||
for (k = 0; k < MAX_TERM; k++) {
|
||||
dpp->samples_A [k] = temp_A [m];
|
||||
dpp->samples_B [k] = temp_B [m];
|
||||
m = (m + 1) & (MAX_TERM - 1);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case -1:
|
||||
while (num_samples--) {
|
||||
int32_t sam_A, sam_B, tmp;
|
||||
|
||||
sam_A = dpp->samples_A [0];
|
||||
out_samples [0] = tmp = (sam_B = in_samples [0]) - apply_weight (dpp->weight_A, sam_A);
|
||||
update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp);
|
||||
dpp->sum_A += dpp->weight_A;
|
||||
|
||||
out_samples [1] = tmp = (dpp->samples_A [0] = in_samples [1]) - apply_weight (dpp->weight_B, sam_B);
|
||||
update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp);
|
||||
dpp->sum_B += dpp->weight_B;
|
||||
|
||||
in_samples += dir;
|
||||
out_samples += dir;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case -2:
|
||||
while (num_samples--) {
|
||||
int32_t sam_A, sam_B, tmp;
|
||||
|
||||
sam_B = dpp->samples_B [0];
|
||||
out_samples [1] = tmp = (sam_A = in_samples [1]) - apply_weight (dpp->weight_B, sam_B);
|
||||
update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp);
|
||||
dpp->sum_B += dpp->weight_B;
|
||||
|
||||
out_samples [0] = tmp = (dpp->samples_B [0] = in_samples [0]) - apply_weight (dpp->weight_A, sam_A);
|
||||
update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp);
|
||||
dpp->sum_A += dpp->weight_A;
|
||||
|
||||
in_samples += dir;
|
||||
out_samples += dir;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case -3:
|
||||
while (num_samples--) {
|
||||
int32_t sam_A, sam_B, tmp;
|
||||
|
||||
sam_A = dpp->samples_A [0];
|
||||
sam_B = dpp->samples_B [0];
|
||||
|
||||
dpp->samples_A [0] = tmp = in_samples [1];
|
||||
out_samples [1] = tmp -= apply_weight (dpp->weight_B, sam_B);
|
||||
update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp);
|
||||
dpp->sum_B += dpp->weight_B;
|
||||
|
||||
dpp->samples_B [0] = tmp = in_samples [0];
|
||||
out_samples [0] = tmp -= apply_weight (dpp->weight_A, sam_A);
|
||||
update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp);
|
||||
dpp->sum_A += dpp->weight_A;
|
||||
|
||||
in_samples += dir;
|
||||
out_samples += dir;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef PACK_DECORR_STEREO_PASS_CONT
|
||||
if (cont_samples) {
|
||||
if (dir < 0)
|
||||
PACK_DECORR_STEREO_PASS_CONT_REV (dpp, in_samples, out_samples, cont_samples);
|
||||
else
|
||||
PACK_DECORR_STEREO_PASS_CONT (dpp, in_samples, out_samples, cont_samples);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void reverse_decorr (struct decorr_pass *dpp)
|
||||
{
|
||||
if (dpp->term > MAX_TERM) {
|
||||
int32_t sam_A, sam_B;
|
||||
|
||||
if (dpp->term & 1) {
|
||||
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1];
|
||||
}
|
||||
else {
|
||||
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||
sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1;
|
||||
}
|
||||
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
dpp->samples_B [1] = dpp->samples_B [0];
|
||||
dpp->samples_A [0] = sam_A;
|
||||
dpp->samples_B [0] = sam_B;
|
||||
|
||||
if (dpp->term & 1) {
|
||||
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1];
|
||||
}
|
||||
else {
|
||||
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||
sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1;
|
||||
}
|
||||
|
||||
dpp->samples_A [1] = sam_A;
|
||||
dpp->samples_B [1] = sam_B;
|
||||
}
|
||||
else if (dpp->term > 1) {
|
||||
int i = 0, j = dpp->term - 1, cnt = dpp->term / 2;
|
||||
|
||||
while (cnt--) {
|
||||
i &= (MAX_TERM - 1);
|
||||
j &= (MAX_TERM - 1);
|
||||
dpp->samples_A [i] ^= dpp->samples_A [j];
|
||||
dpp->samples_A [j] ^= dpp->samples_A [i];
|
||||
dpp->samples_A [i] ^= dpp->samples_A [j];
|
||||
dpp->samples_B [i] ^= dpp->samples_B [j];
|
||||
dpp->samples_B [j] ^= dpp->samples_B [i];
|
||||
dpp->samples_B [i++] ^= dpp->samples_B [j--];
|
||||
}
|
||||
}
|
||||
else if (dpp->term == -1) {
|
||||
}
|
||||
else if (dpp->term == -2) {
|
||||
}
|
||||
else if (dpp->term == -3) {
|
||||
}
|
||||
}
|
||||
|
||||
static void decorr_stereo_buffer (WavpackExtraInfo *info, int32_t *samples, int32_t *outsamples, int32_t num_samples, int tindex)
|
||||
{
|
||||
struct decorr_pass dp, *dppi = info->dps + tindex;
|
||||
int delta = dppi->delta, pre_delta;
|
||||
int term = dppi->term;
|
||||
|
||||
if (delta == 7)
|
||||
pre_delta = 7;
|
||||
else if (delta < 2)
|
||||
pre_delta = 3;
|
||||
else
|
||||
pre_delta = delta + 1;
|
||||
|
||||
CLEAR (dp);
|
||||
dp.term = term;
|
||||
dp.delta = pre_delta;
|
||||
decorr_stereo_pass (samples, outsamples, num_samples > 2048 ? 2048 : num_samples, &dp, -1);
|
||||
dp.delta = delta;
|
||||
|
||||
if (tindex == 0)
|
||||
reverse_decorr (&dp);
|
||||
else {
|
||||
CLEAR (dp.samples_A);
|
||||
CLEAR (dp.samples_B);
|
||||
}
|
||||
|
||||
memcpy (dppi->samples_A, dp.samples_A, sizeof (dp.samples_A));
|
||||
memcpy (dppi->samples_B, dp.samples_B, sizeof (dp.samples_B));
|
||||
dppi->weight_A = dp.weight_A;
|
||||
dppi->weight_B = dp.weight_B;
|
||||
|
||||
if (delta == 0) {
|
||||
dp.delta = 1;
|
||||
decorr_stereo_pass (samples, outsamples, num_samples, &dp, 1);
|
||||
dp.delta = 0;
|
||||
memcpy (dp.samples_A, dppi->samples_A, sizeof (dp.samples_A));
|
||||
memcpy (dp.samples_B, dppi->samples_B, sizeof (dp.samples_B));
|
||||
dppi->weight_A = dp.weight_A = dp.sum_A / num_samples;
|
||||
dppi->weight_B = dp.weight_B = dp.sum_B / num_samples;
|
||||
}
|
||||
|
||||
// if (memcmp (dppi, &dp, sizeof (dp)))
|
||||
// error_line ("decorr_passes don't match, delta = %d", delta);
|
||||
|
||||
decorr_stereo_pass (samples, outsamples, num_samples, &dp, 1);
|
||||
}
|
||||
|
||||
static int log2overhead (int first_term, int num_terms)
|
||||
{
|
||||
#ifdef USE_OVERHEAD
|
||||
if (first_term > MAX_TERM)
|
||||
return (8 + num_terms * 3) << 11;
|
||||
else
|
||||
return (4 + num_terms * 3) << 11;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void recurse_stereo (WavpackContext *wpc, WavpackExtraInfo *info, int depth, int delta, uint32_t input_bits)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int term, branches = ((wpc->config.extra_flags & EXTRA_BRANCHES) >> 6) - depth;
|
||||
int32_t *samples, *outsamples;
|
||||
uint32_t term_bits [22], bits;
|
||||
|
||||
if (branches < 1 || depth + 1 == info->nterms)
|
||||
branches = 1;
|
||||
|
||||
CLEAR (term_bits);
|
||||
samples = info->sampleptrs [depth];
|
||||
outsamples = info->sampleptrs [depth + 1];
|
||||
|
||||
for (term = -3; term <= 18; ++term) {
|
||||
if (!term || (term > 8 && term < 17))
|
||||
continue;
|
||||
|
||||
if (term == 17 && branches == 1 && depth + 1 < info->nterms)
|
||||
continue;
|
||||
|
||||
if (term == -1 || term == -2)
|
||||
if (!(wps->wphdr.flags & CROSS_DECORR))
|
||||
continue;
|
||||
|
||||
if ((wpc->config.flags & CONFIG_FAST_FLAG) && (term > 4 && term < 17))
|
||||
continue;
|
||||
|
||||
info->dps [depth].term = term;
|
||||
info->dps [depth].delta = delta;
|
||||
decorr_stereo_buffer (info, samples, outsamples, wps->wphdr.block_samples, depth);
|
||||
bits = LOG2BUFFER (outsamples, wps->wphdr.block_samples * 2, info->log_limit);
|
||||
|
||||
if (bits != (uint32_t) -1)
|
||||
bits += log2overhead (info->dps [0].term, depth + 1);
|
||||
|
||||
if (bits < info->best_bits) {
|
||||
info->best_bits = bits;
|
||||
CLEAR (wps->decorr_passes);
|
||||
memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * (depth + 1));
|
||||
memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [depth + 1], wps->wphdr.block_samples * 8);
|
||||
}
|
||||
|
||||
term_bits [term + 3] = bits;
|
||||
}
|
||||
|
||||
while (depth + 1 < info->nterms && branches--) {
|
||||
uint32_t local_best_bits = input_bits;
|
||||
int best_term = 0, i;
|
||||
|
||||
for (i = 0; i < 22; ++i)
|
||||
if (term_bits [i] && term_bits [i] < local_best_bits) {
|
||||
local_best_bits = term_bits [i];
|
||||
// term_bits [i] = 0;
|
||||
best_term = i - 3;
|
||||
}
|
||||
|
||||
if (!best_term)
|
||||
break;
|
||||
|
||||
term_bits [best_term + 3] = 0;
|
||||
|
||||
info->dps [depth].term = best_term;
|
||||
info->dps [depth].delta = delta;
|
||||
decorr_stereo_buffer (info, samples, outsamples, wps->wphdr.block_samples, depth);
|
||||
|
||||
// if (log2buffer (outsamples, wps->wphdr.block_samples * 2, 0) != local_best_bits)
|
||||
// error_line ("data doesn't match!");
|
||||
|
||||
recurse_stereo (wpc, info, depth + 1, delta, local_best_bits);
|
||||
}
|
||||
}
|
||||
|
||||
static void delta_stereo (WavpackContext *wpc, WavpackExtraInfo *info)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int lower = FALSE;
|
||||
int delta, d;
|
||||
uint32_t bits;
|
||||
|
||||
if (wps->decorr_passes [0].term)
|
||||
delta = wps->decorr_passes [0].delta;
|
||||
else
|
||||
return;
|
||||
|
||||
for (d = delta - 1; d >= 0; --d) {
|
||||
int i;
|
||||
|
||||
if (!d && (wps->wphdr.flags & HYBRID_FLAG))
|
||||
break;
|
||||
|
||||
for (i = 0; i < info->nterms && wps->decorr_passes [i].term; ++i) {
|
||||
info->dps [i].term = wps->decorr_passes [i].term;
|
||||
info->dps [i].delta = d;
|
||||
decorr_stereo_buffer (info, info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, i);
|
||||
}
|
||||
|
||||
bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit);
|
||||
|
||||
if (bits != (uint32_t) -1)
|
||||
bits += log2overhead (wps->decorr_passes [0].term, i);
|
||||
|
||||
if (bits < info->best_bits) {
|
||||
lower = TRUE;
|
||||
info->best_bits = bits;
|
||||
CLEAR (wps->decorr_passes);
|
||||
memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i);
|
||||
memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 8);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
for (d = delta + 1; !lower && d <= 7; ++d) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < info->nterms && wps->decorr_passes [i].term; ++i) {
|
||||
info->dps [i].term = wps->decorr_passes [i].term;
|
||||
info->dps [i].delta = d;
|
||||
decorr_stereo_buffer (info, info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, i);
|
||||
}
|
||||
|
||||
bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit);
|
||||
|
||||
if (bits != (uint32_t) -1)
|
||||
bits += log2overhead (wps->decorr_passes [0].term, i);
|
||||
|
||||
if (bits < info->best_bits) {
|
||||
info->best_bits = bits;
|
||||
CLEAR (wps->decorr_passes);
|
||||
memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i);
|
||||
memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 8);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sort_stereo (WavpackContext *wpc, WavpackExtraInfo *info)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int reversed = TRUE;
|
||||
uint32_t bits;
|
||||
|
||||
while (reversed) {
|
||||
int ri, i;
|
||||
|
||||
memcpy (info->dps, wps->decorr_passes, sizeof (wps->decorr_passes));
|
||||
reversed = FALSE;
|
||||
|
||||
for (ri = 0; ri < info->nterms && wps->decorr_passes [ri].term; ++ri) {
|
||||
|
||||
if (ri + 1 >= info->nterms || !wps->decorr_passes [ri+1].term)
|
||||
break;
|
||||
|
||||
if (wps->decorr_passes [ri].term == wps->decorr_passes [ri+1].term) {
|
||||
decorr_stereo_buffer (info, info->sampleptrs [ri], info->sampleptrs [ri+1], wps->wphdr.block_samples, ri);
|
||||
continue;
|
||||
}
|
||||
|
||||
info->dps [ri] = wps->decorr_passes [ri+1];
|
||||
info->dps [ri+1] = wps->decorr_passes [ri];
|
||||
|
||||
for (i = ri; i < info->nterms && wps->decorr_passes [i].term; ++i)
|
||||
decorr_stereo_buffer (info, info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, i);
|
||||
|
||||
bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit);
|
||||
|
||||
if (bits != (uint32_t) -1)
|
||||
bits += log2overhead (wps->decorr_passes [0].term, i);
|
||||
|
||||
if (bits < info->best_bits) {
|
||||
reversed = TRUE;
|
||||
info->best_bits = bits;
|
||||
CLEAR (wps->decorr_passes);
|
||||
memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i);
|
||||
memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 8);
|
||||
}
|
||||
else {
|
||||
info->dps [ri] = wps->decorr_passes [ri];
|
||||
info->dps [ri+1] = wps->decorr_passes [ri+1];
|
||||
decorr_stereo_buffer (info, info->sampleptrs [ri], info->sampleptrs [ri+1], wps->wphdr.block_samples, ri);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32_t xtable [] = { 91, 123, 187, 251 };
|
||||
|
||||
static void analyze_stereo (WavpackContext *wpc, int32_t *samples, int do_samples)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
WavpackExtraInfo info;
|
||||
int i;
|
||||
|
||||
#ifdef LOG_LIMIT
|
||||
info.log_limit = (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) + 4) * 256;
|
||||
|
||||
if (info.log_limit > LOG_LIMIT)
|
||||
info.log_limit = LOG_LIMIT;
|
||||
#else
|
||||
info.log_limit = 0;
|
||||
#endif
|
||||
|
||||
if (wpc->config.flags & (CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG))
|
||||
wpc->config.extra_flags = xtable [wpc->config.xmode - 4];
|
||||
else
|
||||
wpc->config.extra_flags = xtable [wpc->config.xmode - 3];
|
||||
|
||||
info.nterms = wps->num_terms;
|
||||
|
||||
for (i = 0; i < info.nterms + 2; ++i)
|
||||
info.sampleptrs [i] = malloc (wps->wphdr.block_samples * 8);
|
||||
|
||||
memcpy (info.dps, wps->decorr_passes, sizeof (info.dps));
|
||||
memcpy (info.sampleptrs [0], samples, wps->wphdr.block_samples * 8);
|
||||
|
||||
for (i = 0; i < info.nterms && info.dps [i].term; ++i)
|
||||
decorr_stereo_pass (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps + i, 1);
|
||||
|
||||
info.best_bits = LOG2BUFFER (info.sampleptrs [info.nterms], wps->wphdr.block_samples * 2, 0) * 1;
|
||||
info.best_bits += log2overhead (info.dps [0].term, i);
|
||||
memcpy (info.sampleptrs [info.nterms + 1], info.sampleptrs [i], wps->wphdr.block_samples * 8);
|
||||
|
||||
if (wpc->config.extra_flags & EXTRA_BRANCHES)
|
||||
recurse_stereo (wpc, &info, 0, (int) floor (wps->delta_decay + 0.5),
|
||||
LOG2BUFFER (info.sampleptrs [0], wps->wphdr.block_samples * 2, 0));
|
||||
|
||||
if (wpc->config.extra_flags & EXTRA_SORT_FIRST)
|
||||
sort_stereo (wpc, &info);
|
||||
|
||||
if (wpc->config.extra_flags & EXTRA_TRY_DELTAS) {
|
||||
delta_stereo (wpc, &info);
|
||||
|
||||
if ((wpc->config.extra_flags & EXTRA_ADJUST_DELTAS) && wps->decorr_passes [0].term)
|
||||
wps->delta_decay = (float)((wps->delta_decay * 2.0 + wps->decorr_passes [0].delta) / 3.0);
|
||||
else
|
||||
wps->delta_decay = 2.0;
|
||||
}
|
||||
|
||||
if (wpc->config.extra_flags & EXTRA_SORT_LAST)
|
||||
sort_stereo (wpc, &info);
|
||||
|
||||
if (do_samples)
|
||||
memcpy (samples, info.sampleptrs [info.nterms + 1], wps->wphdr.block_samples * 8);
|
||||
|
||||
for (i = 0; i < info.nterms; ++i)
|
||||
if (!wps->decorr_passes [i].term)
|
||||
break;
|
||||
|
||||
wps->num_terms = i;
|
||||
|
||||
for (i = 0; i < info.nterms + 2; ++i)
|
||||
free (info.sampleptrs [i]);
|
||||
}
|
||||
|
||||
static void stereo_add_noise (WavpackStream *wps, int32_t *lptr, int32_t *rptr)
|
||||
{
|
||||
int shaping_weight, new = wps->wphdr.flags & NEW_SHAPING;
|
||||
short *shaping_array = wps->dc.shaping_array;
|
||||
int32_t error [2], temp, cnt;
|
||||
|
||||
scan_word (wps, rptr, wps->wphdr.block_samples, -1);
|
||||
cnt = wps->wphdr.block_samples;
|
||||
CLEAR (error);
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_SHAPE) {
|
||||
while (cnt--) {
|
||||
if (shaping_array)
|
||||
shaping_weight = *shaping_array++;
|
||||
else
|
||||
shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16;
|
||||
|
||||
temp = -apply_weight (shaping_weight, error [0]);
|
||||
|
||||
if (new && shaping_weight < 0 && temp) {
|
||||
if (temp == error [0])
|
||||
temp = (temp < 0) ? temp + 1 : temp - 1;
|
||||
|
||||
lptr [0] += (error [0] = nosend_word (wps, rptr [0], 0) - rptr [0] + temp);
|
||||
}
|
||||
else
|
||||
lptr [0] += (error [0] = nosend_word (wps, rptr [0], 0) - rptr [0]) + temp;
|
||||
|
||||
if (!shaping_array)
|
||||
shaping_weight = (wps->dc.shaping_acc [1] += wps->dc.shaping_delta [1]) >> 16;
|
||||
|
||||
temp = -apply_weight (shaping_weight, error [1]);
|
||||
|
||||
if (new && shaping_weight < 0 && temp) {
|
||||
if (temp == error [1])
|
||||
temp = (temp < 0) ? temp + 1 : temp - 1;
|
||||
|
||||
lptr [1] += (error [1] = nosend_word (wps, rptr [1], 1) - rptr [1] + temp);
|
||||
}
|
||||
else
|
||||
lptr [1] += (error [1] = nosend_word (wps, rptr [1], 1) - rptr [1]) + temp;
|
||||
|
||||
lptr += 2;
|
||||
rptr += 2;
|
||||
}
|
||||
|
||||
if (!shaping_array) {
|
||||
wps->dc.shaping_acc [0] -= wps->dc.shaping_delta [0] * wps->wphdr.block_samples;
|
||||
wps->dc.shaping_acc [1] -= wps->dc.shaping_delta [1] * wps->wphdr.block_samples;
|
||||
}
|
||||
}
|
||||
else
|
||||
while (cnt--) {
|
||||
lptr [0] += nosend_word (wps, rptr [0], 0) - rptr [0];
|
||||
lptr [1] += nosend_word (wps, rptr [1], 1) - rptr [1];
|
||||
lptr += 2;
|
||||
rptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void execute_stereo (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples)
|
||||
{
|
||||
int32_t *temp_buffer [2], *best_buffer, *noisy_buffer = NULL, *js_buffer = NULL;
|
||||
struct decorr_pass temp_decorr_pass, save_decorr_passes [MAX_NTERMS];
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int32_t num_samples = wps->wphdr.block_samples;
|
||||
int32_t buf_size = sizeof (int32_t) * num_samples * 2;
|
||||
uint32_t best_size = (uint32_t) -1, size;
|
||||
int log_limit, force_js = 0, force_ts = 0, pi, i;
|
||||
|
||||
#ifdef SKIP_DECORRELATION
|
||||
CLEAR (wps->decorr_passes);
|
||||
wps->num_terms = 0;
|
||||
return;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < num_samples * 2; ++i)
|
||||
if (samples [i])
|
||||
break;
|
||||
|
||||
if (i == num_samples * 2) {
|
||||
wps->wphdr.flags &= ~((uint32_t) JOINT_STEREO);
|
||||
CLEAR (wps->decorr_passes);
|
||||
wps->num_terms = 0;
|
||||
init_words (wps);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LOG_LIMIT
|
||||
log_limit = (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) + 4) * 256;
|
||||
|
||||
if (log_limit > LOG_LIMIT)
|
||||
log_limit = LOG_LIMIT;
|
||||
#else
|
||||
log_limit = 0;
|
||||
#endif
|
||||
|
||||
if (wpc->config.flags & CONFIG_JOINT_OVERRIDE) {
|
||||
if (wps->wphdr.flags & JOINT_STEREO)
|
||||
force_js = 1;
|
||||
else
|
||||
force_ts = 1;
|
||||
}
|
||||
|
||||
CLEAR (save_decorr_passes);
|
||||
temp_buffer [0] = malloc (buf_size);
|
||||
temp_buffer [1] = malloc (buf_size);
|
||||
best_buffer = malloc (buf_size);
|
||||
|
||||
if (wps->num_passes > 1 && (wps->wphdr.flags & HYBRID_FLAG)) {
|
||||
CLEAR (temp_decorr_pass);
|
||||
temp_decorr_pass.delta = 2;
|
||||
temp_decorr_pass.term = 18;
|
||||
|
||||
decorr_stereo_pass (samples, temp_buffer [0],
|
||||
num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1);
|
||||
|
||||
reverse_decorr (&temp_decorr_pass);
|
||||
decorr_stereo_pass (samples, temp_buffer [0], num_samples, &temp_decorr_pass, 1);
|
||||
CLEAR (temp_decorr_pass);
|
||||
temp_decorr_pass.delta = 2;
|
||||
temp_decorr_pass.term = 17;
|
||||
|
||||
decorr_stereo_pass (temp_buffer [0], temp_buffer [1],
|
||||
num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1);
|
||||
|
||||
decorr_stereo_pass (temp_buffer [0], temp_buffer [1], num_samples, &temp_decorr_pass, 1);
|
||||
noisy_buffer = malloc (buf_size);
|
||||
memcpy (noisy_buffer, samples, buf_size);
|
||||
stereo_add_noise (wps, noisy_buffer, temp_buffer [1]);
|
||||
no_history = 1;
|
||||
}
|
||||
|
||||
if (no_history || wps->num_passes >= 7)
|
||||
wps->best_decorr = wps->mask_decorr = 0;
|
||||
|
||||
for (pi = 0; pi < wps->num_passes;) {
|
||||
const WavpackDecorrSpec *wpds;
|
||||
int nterms, c, j;
|
||||
|
||||
if (!pi)
|
||||
c = wps->best_decorr;
|
||||
else {
|
||||
if (wps->mask_decorr == 0)
|
||||
c = 0;
|
||||
else
|
||||
c = (wps->best_decorr & (wps->mask_decorr - 1)) | wps->mask_decorr;
|
||||
|
||||
if (c == wps->best_decorr) {
|
||||
wps->mask_decorr = wps->mask_decorr ? ((wps->mask_decorr << 1) & (wps->num_decorrs - 1)) : 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
wpds = &wps->decorr_specs [c];
|
||||
nterms = (int) strlen ((char *) wpds->terms);
|
||||
|
||||
while (1) {
|
||||
if (force_js || (wpds->joint_stereo && !force_ts)) {
|
||||
if (!js_buffer) {
|
||||
int32_t *lptr, cnt = num_samples;
|
||||
|
||||
lptr = js_buffer = malloc (buf_size);
|
||||
memcpy (js_buffer, noisy_buffer ? noisy_buffer : samples, buf_size);
|
||||
|
||||
while (cnt--) {
|
||||
lptr [1] += ((lptr [0] -= lptr [1]) >> 1);
|
||||
lptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy (temp_buffer [0], js_buffer, buf_size);
|
||||
}
|
||||
else
|
||||
memcpy (temp_buffer [0], noisy_buffer ? noisy_buffer : samples, buf_size);
|
||||
|
||||
CLEAR (save_decorr_passes);
|
||||
|
||||
for (j = 0; j < nterms; ++j) {
|
||||
CLEAR (temp_decorr_pass);
|
||||
temp_decorr_pass.delta = wpds->delta;
|
||||
temp_decorr_pass.term = wpds->terms [j];
|
||||
|
||||
if (temp_decorr_pass.term < 0 && !(wps->wphdr.flags & CROSS_DECORR))
|
||||
temp_decorr_pass.term = -3;
|
||||
|
||||
decorr_stereo_pass (temp_buffer [j&1], temp_buffer [~j&1],
|
||||
num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1);
|
||||
|
||||
if (j) {
|
||||
CLEAR (temp_decorr_pass.samples_A);
|
||||
CLEAR (temp_decorr_pass.samples_B);
|
||||
}
|
||||
else
|
||||
reverse_decorr (&temp_decorr_pass);
|
||||
|
||||
memcpy (save_decorr_passes + j, &temp_decorr_pass, sizeof (struct decorr_pass));
|
||||
decorr_stereo_pass (temp_buffer [j&1], temp_buffer [~j&1], num_samples, &temp_decorr_pass, 1);
|
||||
}
|
||||
|
||||
size = LOG2BUFFER (temp_buffer [j&1], num_samples * 2, log_limit);
|
||||
|
||||
if (size == (uint32_t) -1 && nterms)
|
||||
nterms >>= 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
size += log2overhead (wpds->terms [0], nterms);
|
||||
|
||||
if (size < best_size) {
|
||||
memcpy (best_buffer, temp_buffer [j&1], buf_size);
|
||||
memcpy (wps->decorr_passes, save_decorr_passes, sizeof (struct decorr_pass) * MAX_NTERMS);
|
||||
wps->num_terms = nterms;
|
||||
wps->best_decorr = c;
|
||||
best_size = size;
|
||||
}
|
||||
|
||||
if (pi++)
|
||||
wps->mask_decorr = wps->mask_decorr ? ((wps->mask_decorr << 1) & (wps->num_decorrs - 1)) : 1;
|
||||
}
|
||||
|
||||
if (force_js || (wps->decorr_specs [wps->best_decorr].joint_stereo && !force_ts))
|
||||
wps->wphdr.flags |= JOINT_STEREO;
|
||||
else
|
||||
wps->wphdr.flags &= ~((uint32_t) JOINT_STEREO);
|
||||
|
||||
if (wpc->config.xmode > 3) {
|
||||
if (wps->wphdr.flags & JOINT_STEREO) {
|
||||
analyze_stereo (wpc, js_buffer, do_samples);
|
||||
|
||||
if (do_samples)
|
||||
memcpy (samples, js_buffer, buf_size);
|
||||
}
|
||||
else if (noisy_buffer) {
|
||||
analyze_stereo (wpc, noisy_buffer, do_samples);
|
||||
|
||||
if (do_samples)
|
||||
memcpy (samples, noisy_buffer, buf_size);
|
||||
}
|
||||
else
|
||||
analyze_stereo (wpc, samples, do_samples);
|
||||
}
|
||||
else if (do_samples)
|
||||
memcpy (samples, best_buffer, buf_size);
|
||||
|
||||
if (wpc->config.xmode > 3 || no_history || wps->joint_stereo != wps->decorr_specs [wps->best_decorr].joint_stereo) {
|
||||
wps->joint_stereo = wps->decorr_specs [wps->best_decorr].joint_stereo;
|
||||
scan_word (wps, best_buffer, num_samples, -1);
|
||||
}
|
||||
|
||||
if (noisy_buffer)
|
||||
free (noisy_buffer);
|
||||
|
||||
if (js_buffer)
|
||||
free (js_buffer);
|
||||
|
||||
free (temp_buffer [1]);
|
||||
free (temp_buffer [0]);
|
||||
free (best_buffer);
|
||||
|
||||
#ifdef EXTRA_DUMP
|
||||
if (1) {
|
||||
char string [256], substring [20];
|
||||
int i;
|
||||
|
||||
sprintf (string, "%s: terms =",
|
||||
(wps->wphdr.flags & JOINT_STEREO) ? "JS" : "TS");
|
||||
|
||||
for (i = 0; i < wps->num_terms; ++i) {
|
||||
if (wps->decorr_passes [i].term) {
|
||||
if (i && wps->decorr_passes [i-1].delta == wps->decorr_passes [i].delta)
|
||||
sprintf (substring, " %d", wps->decorr_passes [i].term);
|
||||
else
|
||||
sprintf (substring, " %d->%d", wps->decorr_passes [i].term,
|
||||
wps->decorr_passes [i].delta);
|
||||
}
|
||||
else
|
||||
sprintf (substring, " *");
|
||||
|
||||
strcat (string, substring);
|
||||
}
|
||||
|
||||
error_line (string);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -1,291 +0,0 @@
|
|||
/*
|
||||
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
|
||||
* MD5 Message-Digest Algorithm (RFC 1321).
|
||||
*
|
||||
* Homepage:
|
||||
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
|
||||
*
|
||||
* Author:
|
||||
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
|
||||
*
|
||||
* This software was written by Alexander Peslyak in 2001. No copyright is
|
||||
* claimed, and the software is hereby placed in the public domain.
|
||||
* In case this attempt to disclaim copyright and place the software in the
|
||||
* public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* (This is a heavily cut-down "BSD license".)
|
||||
*
|
||||
* This differs from Colin Plumb's older public domain implementation in that
|
||||
* no exactly 32-bit integer data type is required (any 32-bit or wider
|
||||
* unsigned integer data type will do), there's no compile-time endianness
|
||||
* configuration, and the function prototypes match OpenSSL's. No code from
|
||||
* Colin Plumb's implementation has been reused; this comment merely compares
|
||||
* the properties of the two independent implementations.
|
||||
*
|
||||
* The primary goals of this implementation are portability and ease of use.
|
||||
* It is meant to be fast, but not as fast as possible. Some known
|
||||
* optimizations are not included to reduce source code size and avoid
|
||||
* compile-time configuration.
|
||||
*/
|
||||
|
||||
#ifndef HAVE_LIBCRYPTO
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
/*
|
||||
* The basic MD5 functions.
|
||||
*
|
||||
* F and G are optimized compared to their RFC 1321 definitions for
|
||||
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
|
||||
* implementation.
|
||||
*/
|
||||
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
|
||||
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
|
||||
#define H(x, y, z) (((x) ^ (y)) ^ (z))
|
||||
#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
|
||||
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
|
||||
|
||||
/*
|
||||
* The MD5 transformation for all four rounds.
|
||||
*/
|
||||
#define STEP(f, a, b, c, d, x, t, s) \
|
||||
(a) += f((b), (c), (d)) + (x) + (t); \
|
||||
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
|
||||
(a) += (b);
|
||||
|
||||
/*
|
||||
* SET reads 4 input bytes in little-endian byte order and stores them in a
|
||||
* properly aligned word in host byte order.
|
||||
*
|
||||
* The check for little-endian architectures that tolerate unaligned memory
|
||||
* accesses is just an optimization. Nothing will break if it fails to detect
|
||||
* a suitable architecture.
|
||||
*
|
||||
* Unfortunately, this optimization may be a C strict aliasing rules violation
|
||||
* if the caller's data buffer has effective type that cannot be aliased by
|
||||
* MD5_u32plus. In practice, this problem may occur if these MD5 routines are
|
||||
* inlined into a calling function, or with future and dangerously advanced
|
||||
* link-time optimizations. For the time being, keeping these MD5 routines in
|
||||
* their own translation unit avoids the problem.
|
||||
*/
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
|
||||
#define SET(n) \
|
||||
(*(MD5_u32plus *)&ptr[(n) * 4])
|
||||
#define GET(n) \
|
||||
SET(n)
|
||||
#else
|
||||
#define SET(n) \
|
||||
(ctx->block[(n)] = \
|
||||
(MD5_u32plus)ptr[(n) * 4] | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
|
||||
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
|
||||
#define GET(n) \
|
||||
(ctx->block[(n)])
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This processes one or more 64-byte data blocks, but does NOT update the bit
|
||||
* counters. There are no alignment requirements.
|
||||
*/
|
||||
static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
|
||||
{
|
||||
const unsigned char *ptr;
|
||||
MD5_u32plus a, b, c, d;
|
||||
MD5_u32plus saved_a, saved_b, saved_c, saved_d;
|
||||
|
||||
ptr = (const unsigned char *)data;
|
||||
|
||||
a = ctx->a;
|
||||
b = ctx->b;
|
||||
c = ctx->c;
|
||||
d = ctx->d;
|
||||
|
||||
do {
|
||||
saved_a = a;
|
||||
saved_b = b;
|
||||
saved_c = c;
|
||||
saved_d = d;
|
||||
|
||||
/* Round 1 */
|
||||
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
|
||||
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
|
||||
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
|
||||
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
|
||||
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
|
||||
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
|
||||
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
|
||||
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
|
||||
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
|
||||
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
|
||||
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
|
||||
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
|
||||
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
|
||||
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
|
||||
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
|
||||
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
|
||||
|
||||
/* Round 2 */
|
||||
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
|
||||
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
|
||||
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
|
||||
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
|
||||
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
|
||||
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
|
||||
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
|
||||
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
|
||||
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
|
||||
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
|
||||
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
|
||||
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
|
||||
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
|
||||
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
|
||||
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
|
||||
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
|
||||
|
||||
/* Round 3 */
|
||||
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
|
||||
STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
|
||||
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
|
||||
STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
|
||||
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
|
||||
STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
|
||||
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
|
||||
STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
|
||||
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
|
||||
STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
|
||||
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
|
||||
STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
|
||||
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
|
||||
STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
|
||||
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
|
||||
STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
|
||||
|
||||
/* Round 4 */
|
||||
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
|
||||
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
|
||||
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
|
||||
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
|
||||
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
|
||||
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
|
||||
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
|
||||
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
|
||||
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
|
||||
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
|
||||
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
|
||||
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
|
||||
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
|
||||
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
|
||||
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
|
||||
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
|
||||
|
||||
a += saved_a;
|
||||
b += saved_b;
|
||||
c += saved_c;
|
||||
d += saved_d;
|
||||
|
||||
ptr += 64;
|
||||
} while (size -= 64);
|
||||
|
||||
ctx->a = a;
|
||||
ctx->b = b;
|
||||
ctx->c = c;
|
||||
ctx->d = d;
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void MD5_Init(MD5_CTX *ctx)
|
||||
{
|
||||
ctx->a = 0x67452301;
|
||||
ctx->b = 0xefcdab89;
|
||||
ctx->c = 0x98badcfe;
|
||||
ctx->d = 0x10325476;
|
||||
|
||||
ctx->lo = 0;
|
||||
ctx->hi = 0;
|
||||
}
|
||||
|
||||
void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
|
||||
{
|
||||
MD5_u32plus saved_lo;
|
||||
unsigned long used, available;
|
||||
|
||||
saved_lo = ctx->lo;
|
||||
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
|
||||
ctx->hi++;
|
||||
ctx->hi += size >> 29;
|
||||
|
||||
used = saved_lo & 0x3f;
|
||||
|
||||
if (used) {
|
||||
available = 64 - used;
|
||||
|
||||
if (size < available) {
|
||||
memcpy(&ctx->buffer[used], data, size);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(&ctx->buffer[used], data, available);
|
||||
data = (const unsigned char *)data + available;
|
||||
size -= available;
|
||||
body(ctx, ctx->buffer, 64);
|
||||
}
|
||||
|
||||
if (size >= 64) {
|
||||
data = body(ctx, data, size & ~(unsigned long)0x3f);
|
||||
size &= 0x3f;
|
||||
}
|
||||
|
||||
memcpy(ctx->buffer, data, size);
|
||||
}
|
||||
|
||||
#define OUT(dst, src) \
|
||||
(dst)[0] = (unsigned char)(src); \
|
||||
(dst)[1] = (unsigned char)((src) >> 8); \
|
||||
(dst)[2] = (unsigned char)((src) >> 16); \
|
||||
(dst)[3] = (unsigned char)((src) >> 24);
|
||||
|
||||
void MD5_Final(unsigned char *result, MD5_CTX *ctx)
|
||||
{
|
||||
unsigned long used, available;
|
||||
|
||||
used = ctx->lo & 0x3f;
|
||||
|
||||
ctx->buffer[used++] = 0x80;
|
||||
|
||||
available = 64 - used;
|
||||
|
||||
if (available < 8) {
|
||||
memset(&ctx->buffer[used], 0, available);
|
||||
body(ctx, ctx->buffer, 64);
|
||||
used = 0;
|
||||
available = 64;
|
||||
}
|
||||
|
||||
memset(&ctx->buffer[used], 0, available - 8);
|
||||
|
||||
ctx->lo <<= 3;
|
||||
OUT(&ctx->buffer[56], ctx->lo)
|
||||
OUT(&ctx->buffer[60], ctx->hi)
|
||||
|
||||
body(ctx, ctx->buffer, 64);
|
||||
|
||||
OUT(&result[0], ctx->a)
|
||||
OUT(&result[4], ctx->b)
|
||||
OUT(&result[8], ctx->c)
|
||||
OUT(&result[12], ctx->d)
|
||||
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
|
||||
* MD5 Message-Digest Algorithm (RFC 1321).
|
||||
*
|
||||
* Homepage:
|
||||
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
|
||||
*
|
||||
* Author:
|
||||
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
|
||||
*
|
||||
* This software was written by Alexander Peslyak in 2001. No copyright is
|
||||
* claimed, and the software is hereby placed in the public domain.
|
||||
* In case this attempt to disclaim copyright and place the software in the
|
||||
* public domain is deemed null and void, then the software is
|
||||
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
|
||||
* general public under the following terms:
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted.
|
||||
*
|
||||
* There's ABSOLUTELY NO WARRANTY, express or implied.
|
||||
*
|
||||
* See md5.c for more information.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_LIBCRYPTO
|
||||
#include <openssl/md5.h>
|
||||
#elif !defined(_MD5_H)
|
||||
#define _MD5_H
|
||||
|
||||
/* Any 32-bit or wider unsigned integer data type will do */
|
||||
typedef unsigned int MD5_u32plus;
|
||||
|
||||
typedef struct {
|
||||
MD5_u32plus lo, hi;
|
||||
MD5_u32plus a, b, c, d;
|
||||
unsigned char buffer[64];
|
||||
MD5_u32plus block[16];
|
||||
} MD5_CTX;
|
||||
|
||||
extern void MD5_Init(MD5_CTX *ctx);
|
||||
extern void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
|
||||
extern void MD5_Final(unsigned char *result, MD5_CTX *ctx);
|
||||
|
||||
#endif
|
|
@ -1,304 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// open_filename.c
|
||||
|
||||
// This module provides all the code required to open an existing WavPack
|
||||
// file, by filename, for reading. It does not contain the actual code to
|
||||
// unpack audio data and this was done so that programs that just want to
|
||||
// query WavPack files for information (like, for example, taggers) don't
|
||||
// need to link in a lot of unnecessary code.
|
||||
//
|
||||
// To allow opening files by filename, this code provides an interface
|
||||
// between the reader callback mechanism that WavPack uses internally and
|
||||
// the standard fstream C library. Note that in applications that do not
|
||||
// require opening files by filename, this module can be omitted (which
|
||||
// might make building easier).
|
||||
//
|
||||
// For Unicode support on Windows, a flag has been added (OPEN_FILE_UTF8)
|
||||
// that forces the filename string to be assumed UTF-8 and converted to
|
||||
// a widechar string suitable for _wfopen(). Without this flag we revert
|
||||
// to the previous behavior of simply calling fopen() and hoping that the
|
||||
// local character set works. This is ignored on non-Windows platforms
|
||||
// (which is okay because they are probably UTF-8 anyway).
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if (defined(__GNUC__) || defined(__sun)) && !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __OS2__
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define fileno _fileno
|
||||
static FILE *fopen_utf8 (const char *filename_utf8, const char *mode_utf8);
|
||||
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FSEEKO
|
||||
#define fseek fseeko
|
||||
#define ftell ftello
|
||||
#endif
|
||||
|
||||
static int32_t read_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
return (int32_t) fread (data, 1, bcount, (FILE*) id);
|
||||
}
|
||||
|
||||
static int64_t get_pos (void *id)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _ftelli64 ((FILE*) id);
|
||||
#else
|
||||
return ftell ((FILE*) id);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int set_pos_abs (void *id, int64_t pos)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _fseeki64 (id, pos, SEEK_SET);
|
||||
#else
|
||||
return fseek (id, pos, SEEK_SET);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int set_pos_rel (void *id, int64_t delta, int mode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _fseeki64 (id, delta, mode);
|
||||
#else
|
||||
return fseek (id, delta, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int push_back_byte (void *id, int c)
|
||||
{
|
||||
return ungetc (c, id);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static int64_t get_length (void *id)
|
||||
{
|
||||
LARGE_INTEGER Size;
|
||||
HANDLE fHandle;
|
||||
|
||||
if (id == NULL)
|
||||
return 0;
|
||||
|
||||
fHandle = (HANDLE)_get_osfhandle(_fileno((FILE*) id));
|
||||
if (fHandle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
Size.u.LowPart = GetFileSize(fHandle, &Size.u.HighPart);
|
||||
|
||||
if (Size.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
|
||||
return 0;
|
||||
|
||||
return (int64_t)Size.QuadPart;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int64_t get_length (void *id)
|
||||
{
|
||||
FILE *file = id;
|
||||
struct stat statbuf;
|
||||
|
||||
if (!file || fstat (fileno (file), &statbuf) || !S_ISREG(statbuf.st_mode))
|
||||
return 0;
|
||||
|
||||
return statbuf.st_size;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int can_seek (void *id)
|
||||
{
|
||||
FILE *file = id;
|
||||
struct stat statbuf;
|
||||
|
||||
return file && !fstat (fileno (file), &statbuf) && S_ISREG(statbuf.st_mode);
|
||||
}
|
||||
|
||||
static int32_t write_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
return (int32_t) fwrite (data, 1, bcount, (FILE*) id);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static int truncate_here (void *id)
|
||||
{
|
||||
FILE *file = id;
|
||||
int64_t curr_pos = _ftelli64 (file);
|
||||
|
||||
return _chsize_s (fileno (file), curr_pos);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int truncate_here (void *id)
|
||||
{
|
||||
FILE *file = id;
|
||||
off_t curr_pos = ftell (file);
|
||||
|
||||
return ftruncate (fileno (file), curr_pos);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int close_stream (void *id)
|
||||
{
|
||||
return fclose ((FILE*) id);
|
||||
}
|
||||
|
||||
// int32_t (*read_bytes)(void *id, void *data, int32_t bcount);
|
||||
// int32_t (*write_bytes)(void *id, void *data, int32_t bcount);
|
||||
// int64_t (*get_pos)(void *id); // new signature for large files
|
||||
// int (*set_pos_abs)(void *id, int64_t pos); // new signature for large files
|
||||
// int (*set_pos_rel)(void *id, int64_t delta, int mode); // new signature for large files
|
||||
// int (*push_back_byte)(void *id, int c);
|
||||
// int64_t (*get_length)(void *id); // new signature for large files
|
||||
// int (*can_seek)(void *id);
|
||||
// int (*truncate_here)(void *id); // new function to truncate file at current position
|
||||
// int (*close)(void *id); // new function to close file
|
||||
|
||||
static WavpackStreamReader64 freader = {
|
||||
read_bytes, write_bytes, get_pos, set_pos_abs, set_pos_rel,
|
||||
push_back_byte, get_length, can_seek, truncate_here, close_stream
|
||||
};
|
||||
|
||||
// This function attempts to open the specified WavPack file for reading. If
|
||||
// this fails for any reason then an appropriate message is copied to "error"
|
||||
// (which must accept 80 characters) and NULL is returned, otherwise a
|
||||
// pointer to a WavpackContext structure is returned (which is used to call
|
||||
// all other functions in this module). A filename beginning with "-" is
|
||||
// assumed to be stdin. The "flags" argument has the following bit mask
|
||||
// values to specify details of the open operation:
|
||||
|
||||
// OPEN_WVC: attempt to open/read "correction" file
|
||||
// OPEN_TAGS: attempt to read ID3v1 / APEv2 tags (requires seekable file)
|
||||
// OPEN_WRAPPER: make audio wrapper available (i.e. RIFF) to caller
|
||||
// OPEN_2CH_MAX: open only first stream of multichannel file (usually L/R)
|
||||
// OPEN_NORMALIZE: normalize floating point data to +/- 1.0 (w/ offset exp)
|
||||
// OPEN_STREAMING: blindly unpacks blocks w/o regard to header file position
|
||||
// OPEN_EDIT_TAGS: allow editing of tags (file must be writable)
|
||||
// OPEN_FILE_UTF8: assume infilename is UTF-8 encoded (Windows only)
|
||||
|
||||
// Version 4.2 of the WavPack library adds the OPEN_STREAMING flag. This is
|
||||
// essentially a "raw" mode where the library will simply decode any blocks
|
||||
// fed it through the reader callback, regardless of where those blocks came
|
||||
// from in a stream. The only requirement is that complete WavPack blocks are
|
||||
// fed to the decoder (and this may require multiple blocks in multichannel
|
||||
// mode) and that complete blocks are decoded (even if all samples are not
|
||||
// actually required). All the blocks must contain the same number of channels
|
||||
// and bit resolution, and the correction data must be either present or not.
|
||||
// All other parameters may change from block to block (like lossy/lossless).
|
||||
// Obviously, in this mode any seeking must be performed by the application
|
||||
// (and again, decoding must start at the beginning of the block containing
|
||||
// the seek sample).
|
||||
|
||||
WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset)
|
||||
{
|
||||
char *file_mode = (flags & OPEN_EDIT_TAGS) ? "r+b" : "rb";
|
||||
FILE *(*fopen_func)(const char *, const char *) = fopen;
|
||||
FILE *wv_id, *wvc_id;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (flags & OPEN_FILE_UTF8)
|
||||
fopen_func = fopen_utf8;
|
||||
#endif
|
||||
|
||||
if (*infilename == '-') {
|
||||
wv_id = stdin;
|
||||
#if defined(_WIN32)
|
||||
_setmode (fileno (stdin), O_BINARY);
|
||||
#endif
|
||||
#if defined(__OS2__)
|
||||
setmode (fileno (stdin), O_BINARY);
|
||||
#endif
|
||||
}
|
||||
else if ((wv_id = fopen_func (infilename, file_mode)) == NULL) {
|
||||
if (error) strcpy (error, (flags & OPEN_EDIT_TAGS) ? "can't open file for editing" : "can't open file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (*infilename != '-' && (flags & OPEN_WVC)) {
|
||||
char *in2filename = malloc (strlen (infilename) + 10);
|
||||
|
||||
strcpy (in2filename, infilename);
|
||||
strcat (in2filename, "c");
|
||||
wvc_id = fopen_func (in2filename, "rb");
|
||||
free (in2filename);
|
||||
}
|
||||
else
|
||||
wvc_id = NULL;
|
||||
|
||||
return WavpackOpenFileInputEx64 (&freader, wv_id, wvc_id, error, flags, norm_offset);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// The following code Copyright (c) 2004-2012 LoRd_MuldeR <mulder2@gmx.de>
|
||||
// (see cli/win32_unicode_support.c for full license)
|
||||
|
||||
static wchar_t *utf8_to_utf16(const char *input)
|
||||
{
|
||||
wchar_t *Buffer;
|
||||
int BuffSize = 0, Result = 0;
|
||||
|
||||
BuffSize = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
|
||||
Buffer = (wchar_t*) malloc(sizeof(wchar_t) * BuffSize);
|
||||
if(Buffer)
|
||||
{
|
||||
Result = MultiByteToWideChar(CP_UTF8, 0, input, -1, Buffer, BuffSize);
|
||||
}
|
||||
|
||||
return ((Result > 0) && (Result <= BuffSize)) ? Buffer : NULL;
|
||||
}
|
||||
|
||||
|
||||
static FILE *fopen_utf8(const char *filename_utf8, const char *mode_utf8)
|
||||
{
|
||||
FILE *ret = NULL;
|
||||
wchar_t *filename_utf16 = utf8_to_utf16(filename_utf8);
|
||||
wchar_t *mode_utf16 = utf8_to_utf16(mode_utf8);
|
||||
|
||||
if(filename_utf16 && mode_utf16)
|
||||
{
|
||||
ret = _wfopen(filename_utf16, mode_utf16);
|
||||
}
|
||||
|
||||
if(filename_utf16) free(filename_utf16);
|
||||
if(mode_utf16) free(mode_utf16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2019 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// open_legacy.c
|
||||
|
||||
// This code provides an interface between the new reader callback mechanism that
|
||||
// WavPack uses internally and the old reader callback functions that did not
|
||||
// provide large file support.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
typedef struct {
|
||||
WavpackStreamReader *reader;
|
||||
void *id;
|
||||
} WavpackReaderTranslator;
|
||||
|
||||
static int32_t trans_read_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->read_bytes (trans->id, data, bcount);
|
||||
}
|
||||
|
||||
static int32_t trans_write_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->write_bytes (trans->id, data, bcount);
|
||||
}
|
||||
|
||||
static int64_t trans_get_pos (void *id)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->get_pos (trans->id);
|
||||
}
|
||||
|
||||
static int trans_set_pos_abs (void *id, int64_t pos)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->set_pos_abs (trans->id, (uint32_t) pos);
|
||||
}
|
||||
|
||||
static int trans_set_pos_rel (void *id, int64_t delta, int mode)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->set_pos_rel (trans->id, (int32_t) delta, mode);
|
||||
}
|
||||
|
||||
static int trans_push_back_byte (void *id, int c)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->push_back_byte (trans->id, c);
|
||||
}
|
||||
|
||||
static int64_t trans_get_length (void *id)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->get_length (trans->id);
|
||||
}
|
||||
|
||||
static int trans_can_seek (void *id)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->can_seek (trans->id);
|
||||
}
|
||||
|
||||
static int trans_close_stream (void *id)
|
||||
{
|
||||
free (id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WavpackStreamReader64 trans_reader = {
|
||||
trans_read_bytes, trans_write_bytes, trans_get_pos, trans_set_pos_abs, trans_set_pos_rel,
|
||||
trans_push_back_byte, trans_get_length, trans_can_seek, NULL, trans_close_stream
|
||||
};
|
||||
|
||||
// This function is identical to WavpackOpenFileInput64() except that instead
|
||||
// of providing the new 64-bit reader callbacks, the old reader callbacks are
|
||||
// utilized and a translation layer is employed. It is provided as a compatibility
|
||||
// function for existing applications. To ensure that streaming applications using
|
||||
// this function continue to work, the OPEN_NO_CHECKSUM flag is forced on when
|
||||
// the OPEN_STREAMING flag is set.
|
||||
|
||||
WavpackContext *WavpackOpenFileInputEx (WavpackStreamReader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset)
|
||||
{
|
||||
WavpackReaderTranslator *trans_wv = NULL, *trans_wvc = NULL;
|
||||
|
||||
// this prevents existing streaming applications from failing if they try to pass
|
||||
// in blocks that have been modified from the original (e.g., Matroska blocks)
|
||||
|
||||
if (flags & OPEN_STREAMING)
|
||||
flags |= OPEN_NO_CHECKSUM;
|
||||
|
||||
if (wv_id) {
|
||||
trans_wv = (WavpackReaderTranslator *)malloc (sizeof (WavpackReaderTranslator));
|
||||
trans_wv->reader = reader;
|
||||
trans_wv->id = wv_id;
|
||||
}
|
||||
|
||||
if (wvc_id) {
|
||||
trans_wvc = (WavpackReaderTranslator *)malloc (sizeof (WavpackReaderTranslator));
|
||||
trans_wvc->reader = reader;
|
||||
trans_wvc->id = wvc_id;
|
||||
}
|
||||
|
||||
return WavpackOpenFileInputEx64 (&trans_reader, trans_wv, trans_wvc, error, flags, norm_offset);
|
||||
}
|
|
@ -1,315 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2019 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// open_raw.c
|
||||
|
||||
// This code provides the ability to decode WavPack frames directly from
|
||||
// memory for use in a streaming application. It can handle full blocks
|
||||
// or the headerless block data provided by Matroska and the DirectShow
|
||||
// WavPack splitter. For information about how Matroska stores WavPack,
|
||||
// see: https://www.matroska.org/technical/specs/codecid/wavpack.html
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned char *sptr, *dptr, *eptr, free_required;
|
||||
} RawSegment;
|
||||
|
||||
typedef struct {
|
||||
RawSegment *segments;
|
||||
int num_segments, curr_segment;
|
||||
unsigned char ungetc_char, ungetc_flag;
|
||||
} WavpackRawContext;
|
||||
|
||||
static int32_t raw_read_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
WavpackRawContext *rcxt = id;
|
||||
unsigned char *outptr = data;
|
||||
|
||||
while (bcount) {
|
||||
if (rcxt->ungetc_flag) {
|
||||
*outptr++ = rcxt->ungetc_char;
|
||||
rcxt->ungetc_flag = 0;
|
||||
bcount--;
|
||||
}
|
||||
else if (rcxt->curr_segment < rcxt->num_segments) {
|
||||
RawSegment *segptr = rcxt->segments + rcxt->curr_segment;
|
||||
int bytes_to_copy = (int)(segptr->eptr - segptr->dptr);
|
||||
|
||||
if (bytes_to_copy > bcount)
|
||||
bytes_to_copy = bcount;
|
||||
|
||||
memcpy (outptr, segptr->dptr, bytes_to_copy);
|
||||
outptr += bytes_to_copy;
|
||||
bcount -= bytes_to_copy;
|
||||
|
||||
if ((segptr->dptr += bytes_to_copy) == segptr->eptr)
|
||||
rcxt->curr_segment++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return (int32_t)(outptr - (unsigned char *) data);
|
||||
}
|
||||
|
||||
static int32_t raw_write_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int64_t raw_get_pos (void *id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_set_pos_abs (void *id, int64_t pos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_set_pos_rel (void *id, int64_t delta, int mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_push_back_byte (void *id, int c)
|
||||
{
|
||||
WavpackRawContext *rcxt = id;
|
||||
rcxt->ungetc_char = c;
|
||||
rcxt->ungetc_flag = 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
static int64_t raw_get_length (void *id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_can_seek (void *id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_close_stream (void *id)
|
||||
{
|
||||
WavpackRawContext *rcxt = id;
|
||||
int i;
|
||||
|
||||
if (rcxt) {
|
||||
for (i = 0; i < rcxt->num_segments; ++i)
|
||||
if (rcxt->segments [i].sptr && rcxt->segments [i].free_required)
|
||||
free (rcxt->segments [i].sptr);
|
||||
|
||||
if (rcxt->segments) free (rcxt->segments);
|
||||
free (rcxt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WavpackStreamReader64 raw_reader = {
|
||||
raw_read_bytes, raw_write_bytes, raw_get_pos, raw_set_pos_abs, raw_set_pos_rel,
|
||||
raw_push_back_byte, raw_get_length, raw_can_seek, NULL, raw_close_stream
|
||||
};
|
||||
|
||||
// This function is similar to WavpackOpenFileInput() except that instead of
|
||||
// providing a filename to open, the caller provides pointers to buffered
|
||||
// WavPack frames (both standard and, optionally, correction data). It
|
||||
// decodes only a single frame. Note that in this context, a "frame" is a
|
||||
// collection of WavPack blocks that represent all the channels present. In
|
||||
// the case of mono or [most] stereo streams, this is the same thing, but
|
||||
// for multichannel streams each frame consists of several WavPack blocks
|
||||
// (which can contain only 1 or 2 channels).
|
||||
|
||||
WavpackContext *WavpackOpenRawDecoder (
|
||||
void *main_data, int32_t main_size,
|
||||
void *corr_data, int32_t corr_size,
|
||||
int16_t version, char *error, int flags, int norm_offset)
|
||||
{
|
||||
WavpackRawContext *raw_wv = NULL, *raw_wvc = NULL;
|
||||
|
||||
// if the WavPack data does not contain headers we assume Matroska-style storage
|
||||
// and recreate the missing headers
|
||||
|
||||
if (strncmp (main_data, "wvpk", 4)) {
|
||||
uint32_t multiple_blocks = 0, block_size, block_samples = 0, wphdr_flags, crc;
|
||||
uint32_t main_bytes = main_size, corr_bytes = corr_size;
|
||||
unsigned char *mcp = main_data;
|
||||
unsigned char *ccp = corr_data;
|
||||
int msi = 0, csi = 0;
|
||||
|
||||
raw_wv = malloc (sizeof (WavpackRawContext));
|
||||
memset (raw_wv, 0, sizeof (WavpackRawContext));
|
||||
|
||||
if (corr_data && corr_size) {
|
||||
raw_wvc = malloc (sizeof (WavpackRawContext));
|
||||
memset (raw_wvc, 0, sizeof (WavpackRawContext));
|
||||
}
|
||||
|
||||
while (main_bytes >= 12) {
|
||||
if (!msi) {
|
||||
block_samples = *mcp++;
|
||||
block_samples += *mcp++ << 8;
|
||||
block_samples += *mcp++ << 16;
|
||||
block_samples += *mcp++ << 24;
|
||||
main_bytes -= 4;
|
||||
}
|
||||
|
||||
wphdr_flags = *mcp++;
|
||||
wphdr_flags += *mcp++ << 8;
|
||||
wphdr_flags += *mcp++ << 16;
|
||||
wphdr_flags += *mcp++ << 24;
|
||||
main_bytes -= 4;
|
||||
|
||||
// if the first block does not have the FINAL_BLOCK flag set,
|
||||
// then there are multiple blocks
|
||||
|
||||
if (!msi && !(wphdr_flags & FINAL_BLOCK))
|
||||
multiple_blocks = 1;
|
||||
|
||||
crc = *mcp++;
|
||||
crc += *mcp++ << 8;
|
||||
crc += *mcp++ << 16;
|
||||
crc += *mcp++ << 24;
|
||||
main_bytes -= 4;
|
||||
|
||||
if (multiple_blocks) {
|
||||
block_size = *mcp++;
|
||||
block_size += *mcp++ << 8;
|
||||
block_size += *mcp++ << 16;
|
||||
block_size += *mcp++ << 24;
|
||||
main_bytes -= 4;
|
||||
}
|
||||
else
|
||||
block_size = main_bytes;
|
||||
|
||||
if (block_size > main_bytes) {
|
||||
if (error) strcpy (error, "main block overran available data!");
|
||||
raw_close_stream (raw_wv);
|
||||
raw_close_stream (raw_wvc);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
WavpackHeader *wphdr = malloc (sizeof (WavpackHeader));
|
||||
memset (wphdr, 0, sizeof (WavpackHeader));
|
||||
memcpy (wphdr->ckID, "wvpk", 4);
|
||||
wphdr->ckSize = sizeof (WavpackHeader) - 8 + block_size;
|
||||
SET_TOTAL_SAMPLES (*wphdr, block_samples);
|
||||
wphdr->block_samples = block_samples;
|
||||
wphdr->version = version;
|
||||
wphdr->flags = wphdr_flags;
|
||||
wphdr->crc = crc;
|
||||
WavpackLittleEndianToNative (wphdr, WavpackHeaderFormat);
|
||||
|
||||
raw_wv->num_segments += 2;
|
||||
raw_wv->segments = realloc (raw_wv->segments, sizeof (RawSegment) * raw_wv->num_segments);
|
||||
raw_wv->segments [msi].dptr = raw_wv->segments [msi].sptr = (unsigned char *) wphdr;
|
||||
raw_wv->segments [msi].eptr = raw_wv->segments [msi].dptr + sizeof (WavpackHeader);
|
||||
raw_wv->segments [msi++].free_required = 1;
|
||||
raw_wv->segments [msi].dptr = raw_wv->segments [msi].sptr = mcp;
|
||||
raw_wv->segments [msi].eptr = raw_wv->segments [msi].dptr + block_size;
|
||||
raw_wv->segments [msi++].free_required = 0;
|
||||
main_bytes -= block_size;
|
||||
mcp += block_size;
|
||||
}
|
||||
|
||||
if (corr_data && corr_bytes >= 4) {
|
||||
crc = *ccp++;
|
||||
crc += *ccp++ << 8;
|
||||
crc += *ccp++ << 16;
|
||||
crc += *ccp++ << 24;
|
||||
corr_bytes -= 4;
|
||||
|
||||
if (multiple_blocks) {
|
||||
block_size = *ccp++;
|
||||
block_size += *ccp++ << 8;
|
||||
block_size += *ccp++ << 16;
|
||||
block_size += *ccp++ << 24;
|
||||
corr_bytes -= 4;
|
||||
}
|
||||
else
|
||||
block_size = corr_bytes;
|
||||
|
||||
if (block_size > corr_bytes) {
|
||||
if (error) strcpy (error, "correction block overran available data!");
|
||||
raw_close_stream (raw_wv);
|
||||
raw_close_stream (raw_wvc);
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
WavpackHeader *wphdr = malloc (sizeof (WavpackHeader));
|
||||
memset (wphdr, 0, sizeof (WavpackHeader));
|
||||
memcpy (wphdr->ckID, "wvpk", 4);
|
||||
wphdr->ckSize = sizeof (WavpackHeader) - 8 + block_size;
|
||||
SET_TOTAL_SAMPLES (*wphdr, block_samples);
|
||||
wphdr->block_samples = block_samples;
|
||||
wphdr->version = version;
|
||||
wphdr->flags = wphdr_flags;
|
||||
wphdr->crc = crc;
|
||||
WavpackLittleEndianToNative (wphdr, WavpackHeaderFormat);
|
||||
|
||||
raw_wvc->num_segments += 2;
|
||||
raw_wvc->segments = realloc (raw_wvc->segments, sizeof (RawSegment) * raw_wvc->num_segments);
|
||||
raw_wvc->segments [csi].dptr = raw_wvc->segments [csi].sptr = (unsigned char *) wphdr;
|
||||
raw_wvc->segments [csi].eptr = raw_wvc->segments [csi].dptr + sizeof (WavpackHeader);
|
||||
raw_wvc->segments [csi++].free_required = 1;
|
||||
raw_wvc->segments [csi].dptr = raw_wvc->segments [csi].sptr = ccp;
|
||||
raw_wvc->segments [csi].eptr = raw_wvc->segments [csi].dptr + block_size;
|
||||
raw_wvc->segments [csi++].free_required = 0;
|
||||
corr_bytes -= block_size;
|
||||
ccp += block_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (main_bytes || (corr_data && corr_bytes)) {
|
||||
if (error) strcpy (error, "leftover multiblock data!");
|
||||
raw_close_stream (raw_wv);
|
||||
raw_close_stream (raw_wvc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else { // the case of WavPack blocks with headers is much easier...
|
||||
if (main_data) {
|
||||
raw_wv = malloc (sizeof (WavpackRawContext));
|
||||
memset (raw_wv, 0, sizeof (WavpackRawContext));
|
||||
raw_wv->num_segments = 1;
|
||||
raw_wv->segments = malloc (sizeof (RawSegment) * raw_wv->num_segments);
|
||||
raw_wv->segments [0].dptr = raw_wv->segments [0].sptr = main_data;
|
||||
raw_wv->segments [0].eptr = raw_wv->segments [0].dptr + main_size;
|
||||
raw_wv->segments [0].free_required = 0;
|
||||
}
|
||||
|
||||
if (corr_data && corr_size) {
|
||||
raw_wvc = malloc (sizeof (WavpackRawContext));
|
||||
memset (raw_wvc, 0, sizeof (WavpackRawContext));
|
||||
raw_wvc->num_segments = 1;
|
||||
raw_wvc->segments = malloc (sizeof (RawSegment) * raw_wvc->num_segments);
|
||||
raw_wvc->segments [0].dptr = raw_wvc->segments [0].sptr = corr_data;
|
||||
raw_wvc->segments [0].eptr = raw_wvc->segments [0].dptr + corr_size;
|
||||
raw_wvc->segments [0].free_required = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return WavpackOpenFileInputEx64 (&raw_reader, raw_wv, raw_wvc, error, flags | OPEN_STREAMING | OPEN_NO_CHECKSUM, norm_offset);
|
||||
}
|
||||
|
||||
// Return the number of samples represented by the current (and in the raw case, only) frame.
|
||||
|
||||
uint32_t WavpackGetNumSamplesInFrame (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc && wpc->streams && wpc->streams [0])
|
||||
return wpc->streams [0]->wphdr.block_samples;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,191 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// pack_dns.c
|
||||
|
||||
// This module handles the implementation of "dynamic noise shaping" which is
|
||||
// designed to move the spectrum of the quantization noise introduced by lossy
|
||||
// compression up or down in frequency so that it is more likely to be masked
|
||||
// by the source material.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
static void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error);
|
||||
|
||||
void dynamic_noise_shaping (WavpackContext *wpc, int32_t *buffer, int shortening_allowed)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int32_t sample_count = wps->wphdr.block_samples;
|
||||
struct decorr_pass *ap = &wps->analysis_pass;
|
||||
uint32_t flags = wps->wphdr.flags;
|
||||
int32_t *bptr, temp, sam;
|
||||
short *swptr;
|
||||
int sc;
|
||||
|
||||
if (!wps->num_terms && sample_count > 8) {
|
||||
if (flags & MONO_DATA)
|
||||
for (bptr = buffer + sample_count - 3, sc = sample_count - 2; sc--;) {
|
||||
sam = (3 * bptr [1] - bptr [2]) >> 1;
|
||||
temp = *bptr-- - apply_weight (ap->weight_A, sam);
|
||||
update_weight (ap->weight_A, 2, sam, temp);
|
||||
}
|
||||
else
|
||||
for (bptr = buffer + (sample_count - 3) * 2 + 1, sc = sample_count - 2; sc--;) {
|
||||
sam = (3 * bptr [2] - bptr [4]) >> 1;
|
||||
temp = *bptr-- - apply_weight (ap->weight_B, sam);
|
||||
update_weight (ap->weight_B, 2, sam, temp);
|
||||
sam = (3 * bptr [2] - bptr [4]) >> 1;
|
||||
temp = *bptr-- - apply_weight (ap->weight_A, sam);
|
||||
update_weight (ap->weight_A, 2, sam, temp);
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_count > wps->dc.shaping_samples) {
|
||||
sc = sample_count - wps->dc.shaping_samples;
|
||||
swptr = wps->dc.shaping_data + wps->dc.shaping_samples;
|
||||
bptr = buffer + wps->dc.shaping_samples * ((flags & MONO_DATA) ? 1 : 2);
|
||||
|
||||
if (flags & MONO_DATA)
|
||||
while (sc--) {
|
||||
sam = (3 * ap->samples_A [0] - ap->samples_A [1]) >> 1;
|
||||
temp = *bptr - apply_weight (ap->weight_A, sam);
|
||||
update_weight (ap->weight_A, 2, sam, temp);
|
||||
ap->samples_A [1] = ap->samples_A [0];
|
||||
ap->samples_A [0] = *bptr++;
|
||||
*swptr++ = (ap->weight_A < 256) ? 1024 : 1536 - ap->weight_A * 2;
|
||||
}
|
||||
else
|
||||
while (sc--) {
|
||||
sam = (3 * ap->samples_A [0] - ap->samples_A [1]) >> 1;
|
||||
temp = *bptr - apply_weight (ap->weight_A, sam);
|
||||
update_weight (ap->weight_A, 2, sam, temp);
|
||||
ap->samples_A [1] = ap->samples_A [0];
|
||||
ap->samples_A [0] = *bptr++;
|
||||
|
||||
sam = (3 * ap->samples_B [0] - ap->samples_B [1]) >> 1;
|
||||
temp = *bptr - apply_weight (ap->weight_B, sam);
|
||||
update_weight (ap->weight_B, 2, sam, temp);
|
||||
ap->samples_B [1] = ap->samples_B [0];
|
||||
ap->samples_B [0] = *bptr++;
|
||||
|
||||
*swptr++ = (ap->weight_A + ap->weight_B < 512) ? 1024 : 1536 - ap->weight_A - ap->weight_B;
|
||||
}
|
||||
|
||||
wps->dc.shaping_samples = sample_count;
|
||||
}
|
||||
|
||||
if (wpc->wvc_flag) {
|
||||
int max_allowed_error = 1000000 / wpc->ave_block_samples;
|
||||
short max_error, trial_max_error;
|
||||
double initial_y, final_y;
|
||||
|
||||
if (max_allowed_error < 128)
|
||||
max_allowed_error = 128;
|
||||
|
||||
best_floating_line (wps->dc.shaping_data, sample_count, &initial_y, &final_y, &max_error);
|
||||
|
||||
if (shortening_allowed && max_error > max_allowed_error) {
|
||||
int min_samples = 0, max_samples = sample_count, trial_count;
|
||||
double trial_initial_y, trial_final_y;
|
||||
|
||||
while (1) {
|
||||
trial_count = (min_samples + max_samples) / 2;
|
||||
|
||||
best_floating_line (wps->dc.shaping_data, trial_count, &trial_initial_y,
|
||||
&trial_final_y, &trial_max_error);
|
||||
|
||||
if (trial_max_error < max_allowed_error) {
|
||||
max_error = trial_max_error;
|
||||
min_samples = trial_count;
|
||||
initial_y = trial_initial_y;
|
||||
final_y = trial_final_y;
|
||||
}
|
||||
else
|
||||
max_samples = trial_count;
|
||||
|
||||
if (min_samples > 10000 || max_samples - min_samples < 2)
|
||||
break;
|
||||
}
|
||||
|
||||
sample_count = min_samples;
|
||||
}
|
||||
|
||||
if (initial_y < -512) initial_y = -512;
|
||||
else if (initial_y > 1024) initial_y = 1024;
|
||||
|
||||
if (final_y < -512) final_y = -512;
|
||||
else if (final_y > 1024) final_y = 1024;
|
||||
#if 0
|
||||
error_line ("%.2f sec, sample count = %5d, max error = %3d, range = %5d, %5d, actual = %5d, %5d",
|
||||
(double) wps->sample_index / wpc->config.sample_rate, sample_count, max_error,
|
||||
(int) floor (initial_y), (int) floor (final_y),
|
||||
wps->dc.shaping_data [0], wps->dc.shaping_data [sample_count-1]);
|
||||
#endif
|
||||
if (sample_count != wps->wphdr.block_samples)
|
||||
wps->wphdr.block_samples = sample_count;
|
||||
|
||||
if (wpc->wvc_flag) {
|
||||
wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = (int32_t) floor (initial_y * 65536.0 + 0.5);
|
||||
|
||||
wps->dc.shaping_delta [0] = wps->dc.shaping_delta [1] =
|
||||
(int32_t) floor ((final_y - initial_y) / (sample_count - 1) * 65536.0 + 0.5);
|
||||
|
||||
wps->dc.shaping_array = NULL;
|
||||
}
|
||||
else
|
||||
wps->dc.shaping_array = wps->dc.shaping_data;
|
||||
}
|
||||
else
|
||||
wps->dc.shaping_array = wps->dc.shaping_data;
|
||||
}
|
||||
|
||||
// Given an array of integer data (in shorts), find the linear function that most closely
|
||||
// represents it (based on minimum sum of absolute errors). This is returned as the double
|
||||
// precision initial & final Y values of the best-fit line. The function can also optionally
|
||||
// compute and return a maximum error value (as a short). Note that the ends of the resulting
|
||||
// line may fall way outside the range of input values, so some sort of clipping may be
|
||||
// needed.
|
||||
|
||||
static void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error)
|
||||
{
|
||||
double left_sum = 0.0, right_sum = 0.0, center_x = (num_values - 1) / 2.0, center_y, m;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_values >> 1; ++i) {
|
||||
right_sum += values [num_values - i - 1];
|
||||
left_sum += values [i];
|
||||
}
|
||||
|
||||
if (num_values & 1) {
|
||||
right_sum += values [num_values >> 1] * 0.5;
|
||||
left_sum += values [num_values >> 1] * 0.5;
|
||||
}
|
||||
|
||||
center_y = (right_sum + left_sum) / num_values;
|
||||
m = (right_sum - left_sum) / ((double) num_values * num_values) * 4.0;
|
||||
|
||||
if (initial_y)
|
||||
*initial_y = center_y - m * center_x;
|
||||
|
||||
if (final_y)
|
||||
*final_y = center_y + m * center_x;
|
||||
|
||||
if (max_error) {
|
||||
double max = 0.0;
|
||||
|
||||
for (i = 0; i < num_values; ++i)
|
||||
if (fabs (values [i] - (center_y + (i - center_x) * m)) > max)
|
||||
max = fabs (values [i] - (center_y + (i - center_x) * m));
|
||||
|
||||
*max_error = (short) floor (max + 0.5);
|
||||
}
|
||||
}
|
|
@ -1,668 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** DSDPACK **** //
|
||||
// Lossless DSD (Direct Stream Digital) Audio Compressor //
|
||||
// Copyright (c) 2013 - 2016 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// pack_dsd.c
|
||||
|
||||
// This module actually handles the compression of the DSD audio data.
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// This function initializes everything required to pack WavPack DSD bitstreams
|
||||
// and must be called BEFORE any other function in this module.
|
||||
|
||||
void pack_dsd_init (WavpackContext *wpc)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
|
||||
wps->sample_index = 0;
|
||||
}
|
||||
|
||||
// Pack an entire block of samples (either mono or stereo) into a completed
|
||||
// WavPack block. This function is actually a shell for pack_samples() and
|
||||
// performs tasks like handling any shift required by the format, preprocessing
|
||||
// of floating point data or integer data over 24 bits wide, and implementing
|
||||
// the "extra" mode (via the extra?.c modules). It is assumed that there is
|
||||
// sufficient space for the completed block at "wps->blockbuff" and that
|
||||
// "wps->blockend" points to the end of the available space. A return value of
|
||||
// FALSE indicates an error.
|
||||
|
||||
// Pack an entire block of samples (either mono or stereo) into a completed
|
||||
// WavPack block. It is assumed that there is sufficient space for the
|
||||
// completed block at "wps->blockbuff" and that "wps->blockend" points to the
|
||||
// end of the available space. A return value of FALSE indicates an error.
|
||||
// Any unsent metadata is transmitted first, then required metadata for this
|
||||
// block is sent, and finally the compressed integer data is sent. If a "wpx"
|
||||
// stream is required for floating point data or large integer data, then this
|
||||
// must be handled outside this function. To find out how much data was written
|
||||
// the caller must look at the ckSize field of the written WavpackHeader, NOT
|
||||
// the one in the WavpackStream.
|
||||
|
||||
static int encode_buffer_high (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination);
|
||||
static int encode_buffer_fast (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination);
|
||||
|
||||
int pack_dsd_block (WavpackContext *wpc, int32_t *buffer)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
uint32_t flags = wps->wphdr.flags, mult = wpc->dsd_multiplier, data_count;
|
||||
uint32_t sample_count = wps->wphdr.block_samples;
|
||||
unsigned char *dsd_encoding, dsd_power = 0;
|
||||
int32_t res;
|
||||
|
||||
// This code scans stereo data to check whether it can be stored as mono data
|
||||
// (i.e., all L/R samples identical).
|
||||
|
||||
if (!(flags & MONO_FLAG)) {
|
||||
int32_t *sptr, *dptr, i;
|
||||
|
||||
for (sptr = buffer, i = 0; i < (int32_t) sample_count; sptr += 2, i++)
|
||||
if ((sptr [0] ^ sptr [1]) & 0xff)
|
||||
break;
|
||||
|
||||
if (i == sample_count) {
|
||||
wps->wphdr.flags = flags |= FALSE_STEREO;
|
||||
dptr = buffer;
|
||||
sptr = buffer;
|
||||
|
||||
for (i = sample_count; i--; sptr++)
|
||||
*dptr++ = *sptr++;
|
||||
}
|
||||
else
|
||||
wps->wphdr.flags = flags &= ~FALSE_STEREO;
|
||||
}
|
||||
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader));
|
||||
|
||||
if (wpc->metacount) {
|
||||
WavpackMetadata *wpmdp = wpc->metadata;
|
||||
|
||||
while (wpc->metacount) {
|
||||
copy_metadata (wpmdp, wps->blockbuff, wps->blockend);
|
||||
wpc->metabytes -= wpmdp->byte_length;
|
||||
free_metadata (wpmdp++);
|
||||
wpc->metacount--;
|
||||
}
|
||||
|
||||
free (wpc->metadata);
|
||||
wpc->metadata = NULL;
|
||||
}
|
||||
|
||||
if (!sample_count)
|
||||
return TRUE;
|
||||
|
||||
send_general_metadata (wpc);
|
||||
memcpy (&wps->wphdr, wps->blockbuff, sizeof (WavpackHeader));
|
||||
|
||||
dsd_encoding = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12;
|
||||
|
||||
while (mult >>= 1)
|
||||
dsd_power++;
|
||||
|
||||
*dsd_encoding++ = dsd_power;
|
||||
|
||||
if (wpc->config.flags & CONFIG_HIGH_FLAG) {
|
||||
int fast_res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding);
|
||||
|
||||
res = encode_buffer_high (wps, buffer, sample_count, dsd_encoding);
|
||||
|
||||
if ((fast_res != -1) && (res == -1 || res > fast_res))
|
||||
res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding);
|
||||
}
|
||||
else
|
||||
res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding);
|
||||
|
||||
if (res == -1) {
|
||||
int num_samples = sample_count * ((flags & MONO_DATA) ? 1 : 2);
|
||||
uint32_t crc = 0xffffffff;
|
||||
|
||||
*dsd_encoding++ = 0;
|
||||
|
||||
data_count = num_samples + 2;
|
||||
|
||||
while (num_samples--)
|
||||
crc += (crc << 1) + (*dsd_encoding++ = *buffer++);
|
||||
|
||||
((WavpackHeader *) wps->blockbuff)->crc = crc;
|
||||
}
|
||||
else
|
||||
data_count = res + 1;
|
||||
|
||||
if (data_count) {
|
||||
unsigned char *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8;
|
||||
|
||||
if (data_count & 1) {
|
||||
cptr [data_count + 4] = 0;
|
||||
*cptr++ = ID_DSD_BLOCK | ID_LARGE | ID_ODD_SIZE;
|
||||
data_count++;
|
||||
}
|
||||
else
|
||||
*cptr++ = ID_DSD_BLOCK | ID_LARGE;
|
||||
|
||||
*cptr++ = data_count >> 1;
|
||||
*cptr++ = data_count >> 9;
|
||||
*cptr++ = data_count >> 17;
|
||||
((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4;
|
||||
}
|
||||
|
||||
wps->sample_index += sample_count;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
// #define DSD_BYTE_READY(low,high) (((low) >> 24) == ((high) >> 24))
|
||||
// #define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) >> 24))
|
||||
#define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) & 0xff000000))
|
||||
|
||||
#define MAX_PROBABILITY 0xa0 // set to 0xff to disable RLE encoding for probabilities table
|
||||
|
||||
#if (MAX_PROBABILITY < 0xff)
|
||||
|
||||
static int rle_encode (unsigned char *src, int bcount, unsigned char *destination)
|
||||
{
|
||||
int max_rle_zeros = 0xff - MAX_PROBABILITY;
|
||||
unsigned char *dp = destination;
|
||||
int zcount = 0;
|
||||
|
||||
while (bcount--) {
|
||||
if (*src) {
|
||||
while (zcount) {
|
||||
*dp++ = MAX_PROBABILITY + (zcount > max_rle_zeros ? max_rle_zeros : zcount);
|
||||
zcount -= (zcount > max_rle_zeros ? max_rle_zeros : zcount);
|
||||
}
|
||||
|
||||
*dp++ = *src++;
|
||||
}
|
||||
else {
|
||||
zcount++;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
while (zcount) {
|
||||
*dp++ = MAX_PROBABILITY + (zcount > max_rle_zeros ? max_rle_zeros : zcount);
|
||||
zcount -= (zcount > max_rle_zeros ? max_rle_zeros : zcount);
|
||||
}
|
||||
|
||||
*dp++ = 0;
|
||||
|
||||
return (int)(dp - destination);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void calculate_probabilities (int hist [256], unsigned char probs [256], unsigned short prob_sums [256])
|
||||
{
|
||||
int divisor, min_value, max_value, sum_values;
|
||||
int min_hits = 0x7fffffff, max_hits = 0, i;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
if (hist [i] < min_hits) min_hits = hist [i];
|
||||
if (hist [i] > max_hits) max_hits = hist [i];
|
||||
}
|
||||
|
||||
if (max_hits == 0) {
|
||||
memset (probs, 0, sizeof (*probs) * 256);
|
||||
memset (prob_sums, 0, sizeof (*prob_sums) * 256);
|
||||
return;
|
||||
}
|
||||
|
||||
// fprintf (stderr, "process_histogram(): hits = %d to %d\n", min_hits, max_hits);
|
||||
|
||||
if (max_hits > MAX_PROBABILITY)
|
||||
divisor = ((max_hits << 8) + (MAX_PROBABILITY >> 1)) / MAX_PROBABILITY;
|
||||
else
|
||||
divisor = 0;
|
||||
|
||||
while (1) {
|
||||
min_value = 0x7fffffff; max_value = 0; sum_values = 0;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
int value;
|
||||
|
||||
if (hist [i]) {
|
||||
if (divisor) {
|
||||
if (!(value = ((hist [i] << 8) + (divisor >> 1)) / divisor))
|
||||
value = 1;
|
||||
}
|
||||
else
|
||||
value = hist [i];
|
||||
|
||||
if (value < min_value) min_value = value;
|
||||
if (value > max_value) max_value = value;
|
||||
}
|
||||
else
|
||||
value = 0;
|
||||
|
||||
prob_sums [i] = sum_values += value;
|
||||
probs [i] = value;
|
||||
}
|
||||
|
||||
if (max_value > MAX_PROBABILITY) {
|
||||
divisor++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 0 // this code reduces probability values when they are completely redundant (i.e., common divisor), but
|
||||
// this doesn't really happen often enough to make it worthwhile
|
||||
|
||||
if (min_value > 1) {
|
||||
for (i = 0; i < 256; ++i)
|
||||
if (probs [i] % min_value)
|
||||
break;
|
||||
|
||||
if (i == 256) {
|
||||
for (i = 0; i < 256; ++i) {
|
||||
prob_sums [i] /= min_value;
|
||||
probs [i] /= min_value;
|
||||
}
|
||||
|
||||
// fprintf (stderr, "fixed min_value = %d, divisor = %d, probs_sum = %d\n", min_value, divisor, prob_sums [255]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int encode_buffer_fast (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination)
|
||||
{
|
||||
uint32_t flags = wps->wphdr.flags, crc = 0xffffffff;
|
||||
unsigned int low = 0, high = 0xffffffff, mult;
|
||||
unsigned short (*summed_probabilities) [256];
|
||||
unsigned char (*probabilities) [256];
|
||||
unsigned char *dp = destination, *ep;
|
||||
int history_bins, bc, p0 = 0, p1 = 0;
|
||||
int total_summed_probabilities = 0;
|
||||
int (*histogram) [256];
|
||||
int32_t *bp = buffer;
|
||||
char history_bits;
|
||||
|
||||
if (!(flags & MONO_DATA))
|
||||
num_samples *= 2;
|
||||
|
||||
if (num_samples < 280)
|
||||
return -1;
|
||||
else if (num_samples < 560)
|
||||
history_bits = 0;
|
||||
else if (num_samples < 1725)
|
||||
history_bits = 1;
|
||||
else if (num_samples < 5000)
|
||||
history_bits = 2;
|
||||
else if (num_samples < 14000)
|
||||
history_bits = 3;
|
||||
else if (num_samples < 28000)
|
||||
history_bits = 4;
|
||||
else if (num_samples < 76000)
|
||||
history_bits = 5;
|
||||
else if (num_samples < 130000)
|
||||
history_bits = 6;
|
||||
else if (num_samples < 300000)
|
||||
history_bits = 7;
|
||||
else
|
||||
history_bits = 8;
|
||||
|
||||
if (history_bits > MAX_HISTORY_BITS)
|
||||
history_bits = MAX_HISTORY_BITS;
|
||||
|
||||
history_bins = 1 << history_bits;
|
||||
histogram = malloc (sizeof (*histogram) * history_bins);
|
||||
memset (histogram, 0, sizeof (*histogram) * history_bins);
|
||||
probabilities = malloc (sizeof (*probabilities) * history_bins);
|
||||
summed_probabilities = malloc (sizeof (*summed_probabilities) * history_bins);
|
||||
|
||||
bc = num_samples;
|
||||
|
||||
if (flags & MONO_DATA)
|
||||
while (bc--) {
|
||||
crc += (crc << 1) + (*bp & 0xff);
|
||||
histogram [p0] [*bp & 0xff]++;
|
||||
p0 = *bp++ & (history_bins-1);
|
||||
}
|
||||
else
|
||||
while (bc--) {
|
||||
crc += (crc << 1) + (*bp & 0xff);
|
||||
histogram [p0] [*bp & 0xff]++;
|
||||
p0 = p1;
|
||||
p1 = *bp++ & (history_bins-1);
|
||||
}
|
||||
|
||||
for (p0 = 0; p0 < history_bins; p0++) {
|
||||
calculate_probabilities (histogram [p0], probabilities [p0], summed_probabilities [p0]);
|
||||
total_summed_probabilities += summed_probabilities [p0] [255];
|
||||
}
|
||||
|
||||
((WavpackHeader *) wps->blockbuff)->crc = crc;
|
||||
|
||||
// This code detects the case where the required value lookup tables grow silly big and cuts them back down. This would
|
||||
// normally only happen with large blocks or poorly compressible data. The target is to guarantee that the total memory
|
||||
// required for all three decode tables will be 2K bytes per history bin.
|
||||
|
||||
while (total_summed_probabilities > history_bins * MAX_BYTES_PER_BIN) {
|
||||
int max_sum = 0, sum_values = 0, largest_bin = 0;
|
||||
|
||||
for (p0 = 0; p0 < history_bins; ++p0)
|
||||
if (summed_probabilities [p0] [255] > max_sum) {
|
||||
max_sum = summed_probabilities [p0] [255];
|
||||
largest_bin = p0;
|
||||
}
|
||||
|
||||
total_summed_probabilities -= max_sum;
|
||||
p0 = largest_bin;
|
||||
|
||||
for (p1 = 0; p1 < 256; ++p1)
|
||||
summed_probabilities [p0] [p1] = sum_values += probabilities [p0] [p1] = (probabilities [p0] [p1] + 1) >> 1;
|
||||
|
||||
total_summed_probabilities += summed_probabilities [p0] [255];
|
||||
// fprintf (stderr, "processed bin 0x%02x, bin: %d --> %d, new sum = %d\n",
|
||||
// p0, max_sum, summed_probabilities [p0] [255], total_summed_probabilities);
|
||||
}
|
||||
|
||||
free (histogram);
|
||||
bp = buffer;
|
||||
bc = num_samples;
|
||||
*dp++ = 1;
|
||||
*dp++ = history_bits;
|
||||
*dp++ = MAX_PROBABILITY;
|
||||
ep = destination + num_samples - 10;
|
||||
|
||||
#if (MAX_PROBABILITY < 0xff)
|
||||
dp += rle_encode ((unsigned char *) probabilities, sizeof (*probabilities) * history_bins, dp);
|
||||
#else
|
||||
memcpy (dp, probabilities, sizeof (*probabilities) * history_bins);
|
||||
dp += sizeof (*probabilities) * history_bins;
|
||||
#endif
|
||||
|
||||
p0 = p1 = 0;
|
||||
|
||||
while (dp < ep && bc--) {
|
||||
|
||||
mult = (high - low) / summed_probabilities [p0] [255];
|
||||
|
||||
if (!mult) {
|
||||
high = low;
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
mult = (high - low) / summed_probabilities [p0] [255];
|
||||
}
|
||||
|
||||
if (*bp & 0xff)
|
||||
low += summed_probabilities [p0] [(*bp & 0xff)-1] * mult;
|
||||
|
||||
high = low + probabilities [p0] [*bp & 0xff] * mult - 1;
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
if (flags & MONO_DATA)
|
||||
p0 = *bp++ & (history_bins-1);
|
||||
else {
|
||||
p0 = p1;
|
||||
p1 = *bp++ & (history_bins-1);
|
||||
}
|
||||
}
|
||||
|
||||
high = low;
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
free (summed_probabilities);
|
||||
free (probabilities);
|
||||
|
||||
if (dp < ep)
|
||||
return (int)(dp - destination);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#define PTABLE_BITS 8
|
||||
#define PTABLE_BINS (1<<PTABLE_BITS)
|
||||
#define PTABLE_MASK (PTABLE_BINS-1)
|
||||
|
||||
#define INITIAL_TERM (1536/PTABLE_BINS)
|
||||
|
||||
#define UP 0x010000fe
|
||||
#define DOWN 0x00010000
|
||||
#define DECAY 8
|
||||
|
||||
#define PRECISION 20
|
||||
#define VALUE_ONE (1 << PRECISION)
|
||||
#define PRECISION_USE 12
|
||||
|
||||
#define RATE_S 20
|
||||
|
||||
static void init_ptable (int *table, int rate_i, int rate_s)
|
||||
{
|
||||
int value = 0x808000, rate = rate_i << 8, c, i;
|
||||
|
||||
for (c = (rate + 128) >> 8; c--;)
|
||||
value += (DOWN - value) >> DECAY;
|
||||
|
||||
for (i = 0; i < PTABLE_BINS/2; ++i) {
|
||||
table [i] = value;
|
||||
table [PTABLE_BINS-1-i] = 0x100ffff - value;
|
||||
|
||||
if (value > 0x010000) {
|
||||
rate += (rate * rate_s + 128) >> 8;
|
||||
|
||||
for (c = (rate + 64) >> 7; c--;)
|
||||
value += (DOWN - value) >> DECAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int normalize_ptable (int *ptable)
|
||||
{
|
||||
int rate = 0, min_error, error_sum, i;
|
||||
int ntable [PTABLE_BINS];
|
||||
|
||||
init_ptable (ntable, rate, RATE_S);
|
||||
|
||||
for (min_error = i = 0; i < PTABLE_BINS; ++i)
|
||||
min_error += abs (ptable [i] - ntable [i]) >> 8;
|
||||
|
||||
while (1) {
|
||||
init_ptable (ntable, ++rate, RATE_S);
|
||||
|
||||
for (error_sum = i = 0; i < PTABLE_BINS; ++i)
|
||||
error_sum += abs (ptable [i] - ntable [i]) >> 8;
|
||||
|
||||
if (error_sum < min_error)
|
||||
min_error = error_sum;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return rate - 1;
|
||||
}
|
||||
|
||||
static int encode_buffer_high (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination)
|
||||
{
|
||||
int channel, stereo = (wps->wphdr.flags & MONO_DATA) ? 0 : 1;
|
||||
uint32_t crc = 0xffffffff, high = 0xffffffff, low = 0;
|
||||
unsigned char *dp = destination, *ep;
|
||||
DSDfilters *sp;
|
||||
|
||||
if (num_samples * (stereo + 1) < 280)
|
||||
return -1;
|
||||
|
||||
*dp++ = 3;
|
||||
ep = destination + num_samples * (stereo + 1) - 10;
|
||||
|
||||
if (!wps->sample_index) {
|
||||
if (!wps->dsd.ptable)
|
||||
wps->dsd.ptable = malloc (PTABLE_BINS * sizeof (*wps->dsd.ptable));
|
||||
|
||||
init_ptable (wps->dsd.ptable, INITIAL_TERM, RATE_S);
|
||||
|
||||
for (channel = 0; channel < 2; ++channel) {
|
||||
sp = wps->dsd.filters + channel;
|
||||
|
||||
sp->filter1 = sp->filter2 = sp->filter3 = sp->filter4 = sp->filter5 = VALUE_ONE / 2;
|
||||
sp->filter6 = sp->factor = 0;
|
||||
}
|
||||
|
||||
*dp++ = INITIAL_TERM;
|
||||
*dp++ = RATE_S;
|
||||
}
|
||||
else {
|
||||
int rate = normalize_ptable (wps->dsd.ptable);
|
||||
init_ptable (wps->dsd.ptable, rate, RATE_S);
|
||||
*dp++ = rate;
|
||||
*dp++ = RATE_S;
|
||||
}
|
||||
|
||||
for (channel = 0; channel <= stereo; ++channel) {
|
||||
sp = wps->dsd.filters + channel;
|
||||
|
||||
*dp = sp->filter1 >> (PRECISION - 8);
|
||||
sp->filter1 = *dp++ << (PRECISION - 8);
|
||||
|
||||
*dp = sp->filter2 >> (PRECISION - 8);
|
||||
sp->filter2 = *dp++ << (PRECISION - 8);
|
||||
|
||||
*dp = sp->filter3 >> (PRECISION - 8);
|
||||
sp->filter3 = *dp++ << (PRECISION - 8);
|
||||
|
||||
*dp = sp->filter4 >> (PRECISION - 8);
|
||||
sp->filter4 = *dp++ << (PRECISION - 8);
|
||||
|
||||
*dp = sp->filter5 >> (PRECISION - 8);
|
||||
sp->filter5 = *dp++ << (PRECISION - 8);
|
||||
|
||||
*dp++ = sp->factor;
|
||||
*dp++ = sp->factor >> 8;
|
||||
sp->filter6 = 0;
|
||||
sp->factor = (sp->factor << 16) >> 16;
|
||||
}
|
||||
|
||||
sp = wps->dsd.filters;
|
||||
|
||||
while (dp < ep && num_samples--) {
|
||||
int bitcount = 8;
|
||||
|
||||
crc += (crc << 1) + (sp->byte = *buffer++ & 0xff);
|
||||
sp [0].value = sp [0].filter1 - sp [0].filter5 + ((sp [0].filter6 * sp [0].factor) >> 2);
|
||||
|
||||
if (stereo) {
|
||||
crc += (crc << 1) + (sp [1].byte = *buffer++ & 0xff);
|
||||
sp [1].value = sp [1].filter1 - sp [1].filter5 + ((sp [1].filter6 * sp [1].factor) >> 2);
|
||||
}
|
||||
|
||||
while (bitcount--) {
|
||||
int32_t *pp = wps->dsd.ptable + ((sp [0].value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK);
|
||||
|
||||
if (sp [0].byte & 0x80) {
|
||||
high = low + ((high - low) >> 8) * (*pp >> 16);
|
||||
*pp += (UP - *pp) >> DECAY;
|
||||
sp [0].filter0 = -1;
|
||||
}
|
||||
else {
|
||||
low += 1 + ((high - low) >> 8) * (*pp >> 16);
|
||||
*pp += (DOWN - *pp) >> DECAY;
|
||||
sp [0].filter0 = 0;
|
||||
}
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
sp [0].value += sp [0].filter6 << 3;
|
||||
sp [0].factor += (((sp [0].value ^ sp [0].filter0) >> 31) | 1) & ((sp [0].value ^ (sp [0].value - (sp [0].filter6 << 4))) >> 31);
|
||||
sp [0].filter1 += ((sp [0].filter0 & VALUE_ONE) - sp [0].filter1) >> 6;
|
||||
sp [0].filter2 += ((sp [0].filter0 & VALUE_ONE) - sp [0].filter2) >> 4;
|
||||
sp [0].filter3 += (sp [0].filter2 - sp [0].filter3) >> 4;
|
||||
sp [0].filter4 += (sp [0].filter3 - sp [0].filter4) >> 4;
|
||||
sp [0].value = (sp [0].filter4 - sp [0].filter5) >> 4;
|
||||
sp [0].filter5 += sp [0].value;
|
||||
sp [0].filter6 += (sp [0].value - sp [0].filter6) >> 3;
|
||||
sp [0].value = sp [0].filter1 - sp [0].filter5 + ((sp [0].filter6 * sp [0].factor) >> 2);
|
||||
sp [0].byte <<= 1;
|
||||
|
||||
if (!stereo)
|
||||
continue;
|
||||
|
||||
pp = wps->dsd.ptable + ((sp [1].value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK);
|
||||
|
||||
if (sp [1].byte & 0x80) {
|
||||
high = low + ((high - low) >> 8) * (*pp >> 16);
|
||||
*pp += (UP - *pp) >> DECAY;
|
||||
sp [1].filter0 = -1;
|
||||
}
|
||||
else {
|
||||
low += 1 + ((high - low) >> 8) * (*pp >> 16);
|
||||
*pp += (DOWN - *pp) >> DECAY;
|
||||
sp [1].filter0 = 0;
|
||||
}
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
sp [1].value += sp [1].filter6 << 3;
|
||||
sp [1].factor += (((sp [1].value ^ sp [1].filter0) >> 31) | 1) & ((sp [1].value ^ (sp [1].value - (sp [1].filter6 << 4))) >> 31);
|
||||
sp [1].filter1 += ((sp [1].filter0 & VALUE_ONE) - sp [1].filter1) >> 6;
|
||||
sp [1].filter2 += ((sp [1].filter0 & VALUE_ONE) - sp [1].filter2) >> 4;
|
||||
sp [1].filter3 += (sp [1].filter2 - sp [1].filter3) >> 4;
|
||||
sp [1].filter4 += (sp [1].filter3 - sp [1].filter4) >> 4;
|
||||
sp [1].value = (sp [1].filter4 - sp [1].filter5) >> 4;
|
||||
sp [1].filter5 += sp [1].value;
|
||||
sp [1].filter6 += (sp [1].value - sp [1].filter6) >> 3;
|
||||
sp [1].value = sp [1].filter1 - sp [1].filter5 + ((sp [1].filter6 * sp [1].factor) >> 2);
|
||||
sp [1].byte <<= 1;
|
||||
}
|
||||
|
||||
sp [0].factor -= (sp->factor + 512) >> 10;
|
||||
|
||||
if (stereo)
|
||||
sp [1].factor -= (sp [1].factor + 512) >> 10;
|
||||
}
|
||||
|
||||
((WavpackHeader *) wps->blockbuff)->crc = crc;
|
||||
high = low;
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
if (dp < ep)
|
||||
return (int)(dp - destination);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // ENABLE_DSD
|
|
@ -1,270 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// pack_floats.c
|
||||
|
||||
// This module deals with the compression of floating-point data. Note that no
|
||||
// floating point math is involved here...the values are only processed with
|
||||
// the macros that directly access the mantissa, exponent, and sign fields.
|
||||
// That's why we use the f32 type instead of the built-in float type.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
//#define DISPLAY_DIAGNOSTICS
|
||||
|
||||
// Scan the provided buffer of floating-point values and (1) convert the
|
||||
// significant portion of the data to integers for compression using the
|
||||
// regular WavPack algorithms (which only operate on integers) and (2)
|
||||
// determine whether the data requires a second stream for lossless
|
||||
// storage (which will usually be the case except when the floating-point
|
||||
// data was originally integer data). The converted integers are returned
|
||||
// "in-place" and a return value of TRUE indicates that a second stream
|
||||
// is required.
|
||||
|
||||
int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values)
|
||||
{
|
||||
int32_t shifted_ones = 0, shifted_zeros = 0, shifted_both = 0;
|
||||
int32_t false_zeros = 0, neg_zeros = 0;
|
||||
#ifdef DISPLAY_DIAGNOSTICS
|
||||
int32_t true_zeros = 0, denormals = 0, exceptions = 0;
|
||||
#endif
|
||||
uint32_t ordata = 0, crc = 0xffffffff;
|
||||
int32_t count, value, shift_count;
|
||||
int max_mag = 0, max_exp = 0;
|
||||
f32 *dp;
|
||||
|
||||
wps->float_shift = wps->float_flags = 0;
|
||||
|
||||
// First loop goes through all the data and (1) calculates the CRC and (2) finds the
|
||||
// max magnitude that does not have an exponent of 255 (reserved for +/-inf and NaN).
|
||||
for (dp = values, count = num_values; count--; dp++) {
|
||||
crc = crc * 27 + get_mantissa (*dp) * 9 + get_exponent (*dp) * 3 + get_sign (*dp);
|
||||
|
||||
if (get_exponent (*dp) < 255 && get_magnitude (*dp) > max_mag)
|
||||
max_mag = get_magnitude (*dp);
|
||||
}
|
||||
|
||||
wps->crc_x = crc;
|
||||
|
||||
// round up the magnitude so that when we convert the floating-point values to integers,
|
||||
// they will be (at most) just over 24-bits signed precision
|
||||
if (get_exponent (max_mag))
|
||||
max_exp = get_exponent (max_mag + 0x7F0000);
|
||||
|
||||
for (dp = values, count = num_values; count--; dp++) {
|
||||
// Exponent of 255 is reserved for +/-inf (mantissa = 0) or NaN (mantissa != 0).
|
||||
// we use a value one greater than 24-bits unsigned for this.
|
||||
if (get_exponent (*dp) == 255) {
|
||||
#ifdef DISPLAY_DIAGNOSTICS
|
||||
exceptions++;
|
||||
#endif
|
||||
wps->float_flags |= FLOAT_EXCEPTIONS;
|
||||
value = 0x1000000;
|
||||
shift_count = 0;
|
||||
}
|
||||
// This is the regular case. We generate a 24-bit unsigned value with the implied
|
||||
// '1' MSB set and calculate a shift that will make it line up with the biggest
|
||||
// samples in this block (although that shift would obviously shift out real data).
|
||||
else if (get_exponent (*dp)) {
|
||||
shift_count = max_exp - get_exponent (*dp);
|
||||
value = 0x800000 + get_mantissa (*dp);
|
||||
}
|
||||
// Zero exponent means either +/- zero (mantissa = 0) or denormals (mantissa != 0).
|
||||
// shift_count is set so that denormals (without an implied '1') will line up with
|
||||
// regular values (with their implied '1' added at bit 23). Trust me. We don't care
|
||||
// about the shift with zero.
|
||||
else {
|
||||
shift_count = max_exp ? max_exp - 1 : 0;
|
||||
value = get_mantissa (*dp);
|
||||
|
||||
#ifdef DISPLAY_DIAGNOSTICS
|
||||
if (get_mantissa (*dp))
|
||||
denormals++;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (shift_count < 25)
|
||||
value >>= shift_count; // perform the shift if there could be anything left
|
||||
else
|
||||
value = 0; // else just zero the value
|
||||
|
||||
// If we are going to encode an integer zero, then this might be a "false zero" which
|
||||
// means that there are significant bits but they're completely shifted out, or a
|
||||
// "negative zero" which is simply a floating point value that we have to encode
|
||||
// (and converting it to a positive zero would be an error).
|
||||
if (!value) {
|
||||
if (get_exponent (*dp) || get_mantissa (*dp))
|
||||
++false_zeros;
|
||||
else if (get_sign (*dp))
|
||||
++neg_zeros;
|
||||
#ifdef DISPLAY_DIAGNOSTICS
|
||||
else
|
||||
++true_zeros;
|
||||
#endif
|
||||
}
|
||||
// If we are going to shift something (but not everything) out of our integer before
|
||||
// encoding, then we generate a mask corresponding to the bits that will be shifted
|
||||
// out and increment the counter for the 3 possible cases of (1) all zeros, (2) all
|
||||
// ones, and (3) a mix of ones and zeros.
|
||||
else if (shift_count) {
|
||||
int32_t mask = (1 << shift_count) - 1;
|
||||
|
||||
if (!(get_mantissa (*dp) & mask))
|
||||
shifted_zeros++;
|
||||
else if ((get_mantissa (*dp) & mask) == mask)
|
||||
shifted_ones++;
|
||||
else
|
||||
shifted_both++;
|
||||
}
|
||||
|
||||
// "or" all the integer values together, and store the final integer with applied sign
|
||||
|
||||
ordata |= value;
|
||||
* (int32_t *) dp = (get_sign (*dp)) ? -value : value;
|
||||
}
|
||||
|
||||
wps->float_max_exp = max_exp; // on decode, we use this to calculate actual exponent
|
||||
|
||||
// Now, based on our various counts, we determine the scheme required to encode the bits
|
||||
// shifted out. Usually these will simply have to be sent literally, but in some rare cases
|
||||
// we can get away with always assuming ones shifted out, or assuming all the bits shifted
|
||||
// out in each value are the same (which means we only have to send a single bit).
|
||||
if (shifted_both)
|
||||
wps->float_flags |= FLOAT_SHIFT_SENT;
|
||||
else if (shifted_ones && !shifted_zeros)
|
||||
wps->float_flags |= FLOAT_SHIFT_ONES;
|
||||
else if (shifted_ones && shifted_zeros)
|
||||
wps->float_flags |= FLOAT_SHIFT_SAME;
|
||||
// Another case is that we only shift out zeros (or maybe nothing), and in that case we
|
||||
// check to see if our data actually has less than 24 or 25 bits of resolution, which means
|
||||
// that we reduce can the magnitude of the integers we are encoding (which saves all those
|
||||
// bits). The number of bits of reduced resolution is stored in float_shift.
|
||||
else if (ordata && !(ordata & 1)) {
|
||||
while (!(ordata & 1)) {
|
||||
wps->float_shift++;
|
||||
ordata >>= 1;
|
||||
}
|
||||
|
||||
// here we shift out all those zeros in the integer data we will encode
|
||||
for (dp = values, count = num_values; count--; dp++)
|
||||
* (int32_t *) dp >>= wps->float_shift;
|
||||
}
|
||||
|
||||
// Here we calculate the actual magnitude used by our integer data, although this is just
|
||||
// used for informational purposes during encode/decode to possibly use faster math.
|
||||
|
||||
wps->wphdr.flags &= ~MAG_MASK;
|
||||
|
||||
while (ordata) {
|
||||
wps->wphdr.flags += 1 << MAG_LSB;
|
||||
ordata >>= 1;
|
||||
}
|
||||
|
||||
// Finally, we have to set some flags that guide how we encode various types of "zeros".
|
||||
// If none of these are set (which is the most common situation), then every integer
|
||||
// zero in the decoded data will simply become a floating-point zero.
|
||||
|
||||
if (false_zeros || neg_zeros)
|
||||
wps->float_flags |= FLOAT_ZEROS_SENT;
|
||||
|
||||
if (neg_zeros)
|
||||
wps->float_flags |= FLOAT_NEG_ZEROS;
|
||||
|
||||
#ifdef DISPLAY_DIAGNOSTICS
|
||||
{
|
||||
int32_t *ip, min = 0x7fffffff, max = 0x80000000;
|
||||
for (ip = (int32_t *) values, count = num_values; count--; ip++) {
|
||||
if (*ip < min) min = *ip;
|
||||
if (*ip > max) max = *ip;
|
||||
}
|
||||
|
||||
fprintf (stderr, "integer range = %d to %d\n", min, max);
|
||||
}
|
||||
|
||||
fprintf (stderr, "samples = %d, max exp = %d, pre-shift = %d, denormals = %d, exceptions = %d, max_mag = %x\n",
|
||||
num_values, max_exp, wps->float_shift, denormals, exceptions, max_mag);
|
||||
fprintf (stderr, "shifted ones/zeros/both = %d/%d/%d, true/neg/false zeros = %d/%d/%d\n",
|
||||
shifted_ones, shifted_zeros, shifted_both, true_zeros, neg_zeros, false_zeros);
|
||||
#endif
|
||||
|
||||
return wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME);
|
||||
}
|
||||
|
||||
// Given a buffer of float data, convert the data to integers (which is what the WavPack compression
|
||||
// algorithms require) and write the other data required for lossless compression (which includes
|
||||
// significant bits shifted out of the integers, plus information about +/- zeros and exceptions
|
||||
// like NaN and +/- infinities) into the wvxbits stream (which is assumed to be opened). Note that
|
||||
// for this work correctly, scan_float_data() must have been called on the original data to set
|
||||
// the appropriate flags in float_flags and max_exp.
|
||||
|
||||
void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values)
|
||||
{
|
||||
int max_exp = wps->float_max_exp;
|
||||
int32_t count, value, shift_count;
|
||||
f32 *dp;
|
||||
|
||||
for (dp = values, count = num_values; count--; dp++) {
|
||||
if (get_exponent (*dp) == 255) {
|
||||
if (get_mantissa (*dp)) {
|
||||
putbit_1 (&wps->wvxbits);
|
||||
putbits (get_mantissa (*dp), 23, &wps->wvxbits);
|
||||
}
|
||||
else {
|
||||
putbit_0 (&wps->wvxbits);
|
||||
}
|
||||
|
||||
value = 0x1000000;
|
||||
shift_count = 0;
|
||||
}
|
||||
else if (get_exponent (*dp)) {
|
||||
shift_count = max_exp - get_exponent (*dp);
|
||||
value = 0x800000 + get_mantissa (*dp);
|
||||
}
|
||||
else {
|
||||
shift_count = max_exp ? max_exp - 1 : 0;
|
||||
value = get_mantissa (*dp);
|
||||
}
|
||||
|
||||
if (shift_count < 25)
|
||||
value >>= shift_count;
|
||||
else
|
||||
value = 0;
|
||||
|
||||
if (!value) {
|
||||
if (wps->float_flags & FLOAT_ZEROS_SENT) {
|
||||
if (get_exponent (*dp) || get_mantissa (*dp)) {
|
||||
putbit_1 (&wps->wvxbits);
|
||||
putbits (get_mantissa (*dp), 23, &wps->wvxbits);
|
||||
|
||||
if (max_exp >= 25) {
|
||||
putbits (get_exponent (*dp), 8, &wps->wvxbits);
|
||||
}
|
||||
|
||||
putbit (get_sign (*dp), &wps->wvxbits);
|
||||
}
|
||||
else {
|
||||
putbit_0 (&wps->wvxbits);
|
||||
|
||||
if (wps->float_flags & FLOAT_NEG_ZEROS)
|
||||
putbit (get_sign (*dp), &wps->wvxbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (shift_count) {
|
||||
if (wps->float_flags & FLOAT_SHIFT_SENT) {
|
||||
int32_t data = get_mantissa (*dp) & ((1 << shift_count) - 1);
|
||||
putbits (data, shift_count, &wps->wvxbits);
|
||||
}
|
||||
else if (wps->float_flags & FLOAT_SHIFT_SAME) {
|
||||
putbit (get_mantissa (*dp) & 1, &wps->wvxbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,614 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// read_words.c
|
||||
|
||||
// This module provides entropy word decoding functions using
|
||||
// a variation on the Rice method. This was introduced in version 3.93
|
||||
// because it allows splitting the data into a "lossy" stream and a
|
||||
// "correction" stream in a very efficient manner and is therefore ideal
|
||||
// for the "hybrid" mode. For 4.0, the efficiency of this method was
|
||||
// significantly improved by moving away from the normal Rice restriction of
|
||||
// using powers of two for the modulus divisions and now the method can be
|
||||
// used for both hybrid and pure lossless encoding.
|
||||
|
||||
// Samples are divided by median probabilities at 5/7 (71.43%), 10/49 (20.41%),
|
||||
// and 20/343 (5.83%). Each zone has 3.5 times fewer samples than the
|
||||
// previous. Using standard Rice coding on this data would result in 1.4
|
||||
// bits per sample average (not counting sign bit). However, there is a
|
||||
// very simple encoding that is over 99% efficient with this data and
|
||||
// results in about 1.22 bits per sample.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#if defined (HAVE___BUILTIN_CTZ) || defined (_WIN64)
|
||||
#define USE_CTZ_OPTIMIZATION // use ctz intrinsic (or Windows equivalent) to count trailing ones
|
||||
#else
|
||||
#define USE_NEXT8_OPTIMIZATION // optimization using a table to count trailing ones
|
||||
#endif
|
||||
|
||||
#define USE_BITMASK_TABLES // use tables instead of shifting for certain masking operations
|
||||
|
||||
///////////////////////////// local table storage ////////////////////////////
|
||||
|
||||
#ifdef USE_NEXT8_OPTIMIZATION
|
||||
static const char ones_count_table [] = {
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8
|
||||
};
|
||||
#endif
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
static uint32_t __inline read_code (Bitstream *bs, uint32_t maxcode);
|
||||
|
||||
// Read the next word from the bitstream "wvbits" and return the value. This
|
||||
// function can be used for hybrid or lossless streams, but since an
|
||||
// optimized version is available for lossless this function would normally
|
||||
// be used for hybrid only. If a hybrid lossless stream is being read then
|
||||
// the "correction" offset is written at the specified pointer. A return value
|
||||
// of WORD_EOF indicates that the end of the bitstream was reached (all 1s) or
|
||||
// some other error occurred.
|
||||
|
||||
int32_t FASTCALL get_word (WavpackStream *wps, int chan, int32_t *correction)
|
||||
{
|
||||
struct entropy_data *c = wps->w.c + chan;
|
||||
uint32_t ones_count, low, mid, high;
|
||||
int32_t value;
|
||||
int sign;
|
||||
|
||||
if (!wps->wvbits.ptr)
|
||||
return WORD_EOF;
|
||||
|
||||
if (correction)
|
||||
*correction = 0;
|
||||
|
||||
if (!(wps->w.c [0].median [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.c [1].median [0] & ~1)) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
if (wps->w.zeros_acc) {
|
||||
if (--wps->w.zeros_acc) {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
return WORD_EOF;
|
||||
|
||||
if (cbits < 2)
|
||||
wps->w.zeros_acc = cbits;
|
||||
else {
|
||||
for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1)
|
||||
if (getbit (&wps->wvbits))
|
||||
wps->w.zeros_acc |= mask;
|
||||
|
||||
wps->w.zeros_acc |= mask;
|
||||
}
|
||||
|
||||
if (wps->w.zeros_acc) {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
CLEAR (wps->w.c [0].median);
|
||||
CLEAR (wps->w.c [1].median);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wps->w.holding_zero)
|
||||
ones_count = wps->w.holding_zero = 0;
|
||||
else {
|
||||
#ifdef USE_CTZ_OPTIMIZATION
|
||||
while (wps->wvbits.bc < LIMIT_ONES) {
|
||||
if (++(wps->wvbits.ptr) == wps->wvbits.end)
|
||||
wps->wvbits.wrap (&wps->wvbits);
|
||||
|
||||
wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc;
|
||||
wps->wvbits.bc += sizeof (*(wps->wvbits.ptr)) * 8;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
{ unsigned long res; _BitScanForward (&res, (unsigned long)~wps->wvbits.sr); ones_count = (uint32_t) res; }
|
||||
#else
|
||||
ones_count = __builtin_ctz (~wps->wvbits.sr);
|
||||
#endif
|
||||
|
||||
if (ones_count >= LIMIT_ONES) {
|
||||
wps->wvbits.bc -= ones_count;
|
||||
wps->wvbits.sr >>= ones_count;
|
||||
|
||||
for (; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count);
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
return WORD_EOF;
|
||||
|
||||
if (ones_count == LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
return WORD_EOF;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (&wps->wvbits))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
}
|
||||
else {
|
||||
wps->wvbits.bc -= ones_count + 1;
|
||||
wps->wvbits.sr >>= ones_count + 1;
|
||||
}
|
||||
#elif defined (USE_NEXT8_OPTIMIZATION)
|
||||
int next8;
|
||||
|
||||
if (wps->wvbits.bc < 8) {
|
||||
if (++(wps->wvbits.ptr) == wps->wvbits.end)
|
||||
wps->wvbits.wrap (&wps->wvbits);
|
||||
|
||||
next8 = (wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc) & 0xff;
|
||||
wps->wvbits.bc += sizeof (*(wps->wvbits.ptr)) * 8;
|
||||
}
|
||||
else
|
||||
next8 = wps->wvbits.sr & 0xff;
|
||||
|
||||
if (next8 == 0xff) {
|
||||
wps->wvbits.bc -= 8;
|
||||
wps->wvbits.sr >>= 8;
|
||||
|
||||
for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count);
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
return WORD_EOF;
|
||||
|
||||
if (ones_count == LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
return WORD_EOF;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (&wps->wvbits))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
}
|
||||
else {
|
||||
wps->wvbits.bc -= (ones_count = ones_count_table [next8]) + 1;
|
||||
wps->wvbits.sr >>= ones_count + 1;
|
||||
}
|
||||
#else
|
||||
for (ones_count = 0; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count);
|
||||
|
||||
if (ones_count >= LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
return WORD_EOF;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
return WORD_EOF;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (&wps->wvbits))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wps->w.holding_one) {
|
||||
wps->w.holding_one = ones_count & 1;
|
||||
ones_count = (ones_count >> 1) + 1;
|
||||
}
|
||||
else {
|
||||
wps->w.holding_one = ones_count & 1;
|
||||
ones_count >>= 1;
|
||||
}
|
||||
|
||||
wps->w.holding_zero = ~wps->w.holding_one & 1;
|
||||
}
|
||||
|
||||
if ((wps->wphdr.flags & HYBRID_FLAG) && !chan)
|
||||
update_error_limit (wps);
|
||||
|
||||
if (ones_count == 0) {
|
||||
low = 0;
|
||||
high = GET_MED (0) - 1;
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (ones_count == 1) {
|
||||
high = low + GET_MED (1) - 1;
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (ones_count == 2) {
|
||||
high = low + GET_MED (2) - 1;
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
low += (ones_count - 2) * GET_MED (2);
|
||||
high = low + GET_MED (2) - 1;
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
low &= 0x7fffffff;
|
||||
high &= 0x7fffffff;
|
||||
|
||||
if (low > high) // make sure high and low make sense
|
||||
high = low;
|
||||
|
||||
mid = (high + low + 1) >> 1;
|
||||
|
||||
if (!c->error_limit)
|
||||
mid = read_code (&wps->wvbits, high - low) + low;
|
||||
else while (high - low > c->error_limit) {
|
||||
if (getbit (&wps->wvbits))
|
||||
mid = (high + (low = mid) + 1) >> 1;
|
||||
else
|
||||
mid = ((high = mid - 1) + low + 1) >> 1;
|
||||
}
|
||||
|
||||
sign = getbit (&wps->wvbits);
|
||||
|
||||
if (bs_is_open (&wps->wvcbits) && c->error_limit) {
|
||||
value = read_code (&wps->wvcbits, high - low) + low;
|
||||
|
||||
if (correction)
|
||||
*correction = sign ? (mid - value) : (value - mid);
|
||||
}
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
c->slow_level += wp_log2 (mid);
|
||||
}
|
||||
|
||||
return sign ? ~mid : mid;
|
||||
}
|
||||
|
||||
// This is an optimized version of get_word() that is used for lossless only
|
||||
// (error_limit == 0). Also, rather than obtaining a single sample, it can be
|
||||
// used to obtain an entire buffer of either mono or stereo samples.
|
||||
|
||||
int32_t get_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples)
|
||||
{
|
||||
struct entropy_data *c = wps->w.c;
|
||||
uint32_t ones_count, low, high;
|
||||
Bitstream *bs = &wps->wvbits;
|
||||
int32_t csamples;
|
||||
#ifdef USE_NEXT8_OPTIMIZATION
|
||||
int32_t next8;
|
||||
#endif
|
||||
|
||||
if (nsamples && !bs->ptr) {
|
||||
memset (buffer, 0, (wps->wphdr.flags & MONO_DATA) ? nsamples * 4 : nsamples * 8);
|
||||
return nsamples;
|
||||
}
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
nsamples *= 2;
|
||||
|
||||
for (csamples = 0; csamples < nsamples; ++csamples) {
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
c = wps->w.c + (csamples & 1);
|
||||
|
||||
if (wps->w.holding_zero) {
|
||||
wps->w.holding_zero = 0;
|
||||
low = read_code (bs, GET_MED (0) - 1);
|
||||
DEC_MED0 ();
|
||||
buffer [csamples] = (getbit (bs)) ? ~low : low;
|
||||
|
||||
if (++csamples == nsamples)
|
||||
break;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
c = wps->w.c + (csamples & 1);
|
||||
}
|
||||
|
||||
if (wps->w.c [0].median [0] < 2 && !wps->w.holding_one && wps->w.c [1].median [0] < 2) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
if (wps->w.zeros_acc) {
|
||||
if (--wps->w.zeros_acc) {
|
||||
buffer [csamples] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (cbits = 0; cbits < 33 && getbit (bs); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
break;
|
||||
|
||||
if (cbits < 2)
|
||||
wps->w.zeros_acc = cbits;
|
||||
else {
|
||||
for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1)
|
||||
if (getbit (bs))
|
||||
wps->w.zeros_acc |= mask;
|
||||
|
||||
wps->w.zeros_acc |= mask;
|
||||
}
|
||||
|
||||
if (wps->w.zeros_acc) {
|
||||
CLEAR (wps->w.c [0].median);
|
||||
CLEAR (wps->w.c [1].median);
|
||||
buffer [csamples] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_CTZ_OPTIMIZATION
|
||||
while (bs->bc < LIMIT_ONES) {
|
||||
if (++(bs->ptr) == bs->end)
|
||||
bs->wrap (bs);
|
||||
|
||||
bs->sr |= *(bs->ptr) << bs->bc;
|
||||
bs->bc += sizeof (*(bs->ptr)) * 8;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
{ unsigned long res; _BitScanForward (&res, (unsigned long)~wps->wvbits.sr); ones_count = (uint32_t) res; }
|
||||
#else
|
||||
ones_count = __builtin_ctz (~wps->wvbits.sr);
|
||||
#endif
|
||||
|
||||
if (ones_count >= LIMIT_ONES) {
|
||||
bs->bc -= ones_count;
|
||||
bs->sr >>= ones_count;
|
||||
|
||||
for (; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count);
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
break;
|
||||
|
||||
if (ones_count == LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (bs); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
break;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (bs))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bs->bc -= ones_count + 1;
|
||||
bs->sr >>= ones_count + 1;
|
||||
}
|
||||
#elif defined (USE_NEXT8_OPTIMIZATION)
|
||||
if (bs->bc < 8) {
|
||||
if (++(bs->ptr) == bs->end)
|
||||
bs->wrap (bs);
|
||||
|
||||
next8 = (bs->sr |= *(bs->ptr) << bs->bc) & 0xff;
|
||||
bs->bc += sizeof (*(bs->ptr)) * 8;
|
||||
}
|
||||
else
|
||||
next8 = bs->sr & 0xff;
|
||||
|
||||
if (next8 == 0xff) {
|
||||
bs->bc -= 8;
|
||||
bs->sr >>= 8;
|
||||
|
||||
for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count);
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
break;
|
||||
|
||||
if (ones_count == LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (bs); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
break;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (bs))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bs->bc -= (ones_count = ones_count_table [next8]) + 1;
|
||||
bs->sr >>= ones_count + 1;
|
||||
}
|
||||
#else
|
||||
for (ones_count = 0; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count);
|
||||
|
||||
if (ones_count >= LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
break;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (bs); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
break;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (bs))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
#endif
|
||||
|
||||
low = wps->w.holding_one;
|
||||
wps->w.holding_one = ones_count & 1;
|
||||
wps->w.holding_zero = ~ones_count & 1;
|
||||
ones_count = (ones_count >> 1) + low;
|
||||
|
||||
if (ones_count == 0) {
|
||||
low = 0;
|
||||
high = GET_MED (0) - 1;
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (ones_count == 1) {
|
||||
high = low + GET_MED (1) - 1;
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (ones_count == 2) {
|
||||
high = low + GET_MED (2) - 1;
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
low += (ones_count - 2) * GET_MED (2);
|
||||
high = low + GET_MED (2) - 1;
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
low += read_code (bs, high - low);
|
||||
buffer [csamples] = (getbit (bs)) ? ~low : low;
|
||||
}
|
||||
|
||||
return (wps->wphdr.flags & MONO_DATA) ? csamples : (csamples / 2);
|
||||
}
|
||||
|
||||
// Read a single unsigned value from the specified bitstream with a value
|
||||
// from 0 to maxcode. If there are exactly a power of two number of possible
|
||||
// codes then this will read a fixed number of bits; otherwise it reads the
|
||||
// minimum number of bits and then determines whether another bit is needed
|
||||
// to define the code.
|
||||
|
||||
static uint32_t __inline read_code (Bitstream *bs, uint32_t maxcode)
|
||||
{
|
||||
unsigned long local_sr;
|
||||
uint32_t extras, code;
|
||||
int bitcount;
|
||||
|
||||
if (maxcode < 2)
|
||||
return maxcode ? getbit (bs) : 0;
|
||||
|
||||
bitcount = count_bits (maxcode);
|
||||
#ifdef USE_BITMASK_TABLES
|
||||
extras = bitset [bitcount] - maxcode - 1;
|
||||
#else
|
||||
extras = (1 << bitcount) - maxcode - 1;
|
||||
#endif
|
||||
|
||||
local_sr = bs->sr;
|
||||
|
||||
while (bs->bc < bitcount) {
|
||||
if (++(bs->ptr) == bs->end)
|
||||
bs->wrap (bs);
|
||||
|
||||
local_sr |= (long)*(bs->ptr) << bs->bc;
|
||||
bs->bc += sizeof (*(bs->ptr)) * 8;
|
||||
}
|
||||
|
||||
#ifdef USE_BITMASK_TABLES
|
||||
if ((code = local_sr & bitmask [bitcount - 1]) >= extras)
|
||||
#else
|
||||
if ((code = local_sr & ((1 << (bitcount - 1)) - 1)) >= extras)
|
||||
#endif
|
||||
code = (code << 1) - extras + ((local_sr >> (bitcount - 1)) & 1);
|
||||
else
|
||||
bitcount--;
|
||||
|
||||
if (sizeof (local_sr) < 8 && bs->bc > sizeof (local_sr) * 8) {
|
||||
bs->bc -= bitcount;
|
||||
bs->sr = *(bs->ptr) >> (sizeof (*(bs->ptr)) * 8 - bs->bc);
|
||||
}
|
||||
else {
|
||||
bs->bc -= bitcount;
|
||||
bs->sr = local_sr >> bitcount;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
|
@ -1,597 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// tag_utils.c
|
||||
|
||||
// This module provides the high-level API for creating, reading and editing
|
||||
// APEv2 tags on WavPack files. Read-only support is also provided for ID3v1
|
||||
// tags, but their use is not recommended.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define stricmp(x,y) _stricmp(x,y)
|
||||
#else
|
||||
#define stricmp strcasecmp
|
||||
#endif
|
||||
|
||||
static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size, int type);
|
||||
static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size);
|
||||
static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size, int type);
|
||||
static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size);
|
||||
static int append_ape_tag_item (WavpackContext *wpc, const char *item, const char *value, int vsize, int type);
|
||||
static int write_tag_blockout (WavpackContext *wpc);
|
||||
static int write_tag_reader (WavpackContext *wpc);
|
||||
static void tagcpy (char *dest, char *src, int tag_size);
|
||||
static int tagdata (char *src, int tag_size);
|
||||
|
||||
//////////////////// Global functions part of external API /////////////////////////
|
||||
|
||||
// Count and return the total number of tag items in the specified file.
|
||||
|
||||
int WavpackGetNumTagItems (WavpackContext *wpc)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (WavpackGetTagItemIndexed (wpc, i, NULL, 0))
|
||||
++i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// Count and return the total number of binary tag items in the specified file. This applies
|
||||
// only to APEv2 tags and was implemented as a separate function to avoid breaking the old API.
|
||||
|
||||
int WavpackGetNumBinaryTagItems (WavpackContext *wpc)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (WavpackGetBinaryTagItemIndexed (wpc, i, NULL, 0))
|
||||
++i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// Attempt to get the specified item from the specified file's ID3v1 or APEv2
|
||||
// tag. The "size" parameter specifies the amount of space available at "value",
|
||||
// if the desired item will not fit in this space then ellipses (...) will
|
||||
// be appended and the string terminated. Only text data are supported. The
|
||||
// actual length of the string is returned (or 0 if no matching value found).
|
||||
// Note that with APEv2 tags the length might not be the same as the number of
|
||||
// characters because UTF-8 encoding is used. Also, APEv2 tags can have multiple
|
||||
// (NULL separated) strings for a single value (this is why the length is
|
||||
// returned). If this function is called with a NULL "value" pointer (or a
|
||||
// zero "length") then only the actual length of the value data is returned
|
||||
// (not counting the terminating NULL). This can be used to determine the
|
||||
// actual memory to be allocated beforehand.
|
||||
|
||||
int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
if (value && size)
|
||||
*value = 0;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A')
|
||||
return get_ape_tag_item (m_tag, item, value, size, APE_TAG_TYPE_TEXT);
|
||||
else if (m_tag->id3_tag.tag_id [0] == 'T')
|
||||
return get_id3_tag_item (m_tag, item, value, size);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Attempt to get the specified binary item from the specified file's APEv2
|
||||
// tag. The "size" parameter specifies the amount of space available at "value".
|
||||
// If the desired item will not fit in this space then nothing will be copied
|
||||
// and 0 will be returned, otherwise the actual size will be returned. If this
|
||||
// function is called with a NULL "value" pointer (or a zero "length") then only
|
||||
// the actual length of the value data is returned and can be used to determine
|
||||
// the actual memory to be allocated beforehand.
|
||||
|
||||
int WavpackGetBinaryTagItem (WavpackContext *wpc, const char *item, char *value, int size)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
if (value && size)
|
||||
*value = 0;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A')
|
||||
return get_ape_tag_item (m_tag, item, value, size, APE_TAG_TYPE_BINARY);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This function looks up the tag item name by index and is used when the
|
||||
// application wants to access all the items in the file's ID3v1 or APEv2 tag.
|
||||
// Note that this function accesses only the item's name; WavpackGetTagItem()
|
||||
// still must be called to get the actual value. The "size" parameter specifies
|
||||
// the amount of space available at "item", if the desired item will not fit in
|
||||
// this space then ellipses (...) will be appended and the string terminated.
|
||||
// The actual length of the string is returned (or 0 if no item exists for
|
||||
// index). If this function is called with a NULL "value" pointer (or a
|
||||
// zero "length") then only the actual length of the item name is returned
|
||||
// (not counting the terminating NULL). This can be used to determine the
|
||||
// actual memory to be allocated beforehand. For binary tag values use the
|
||||
// otherwise identical WavpackGetBinaryTagItemIndexed ();
|
||||
|
||||
int WavpackGetTagItemIndexed (WavpackContext *wpc, int index, char *item, int size)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
if (item && size)
|
||||
*item = 0;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A')
|
||||
return get_ape_tag_item_indexed (m_tag, index, item, size, APE_TAG_TYPE_TEXT);
|
||||
else if (m_tag->id3_tag.tag_id [0] == 'T')
|
||||
return get_id3_tag_item_indexed (m_tag, index, item, size);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WavpackGetBinaryTagItemIndexed (WavpackContext *wpc, int index, char *item, int size)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
if (item && size)
|
||||
*item = 0;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A')
|
||||
return get_ape_tag_item_indexed (m_tag, index, item, size, APE_TAG_TYPE_BINARY);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// These two functions are used to append APEv2 tags to WavPack files; one is
|
||||
// for text values (UTF-8 encoded) and the other is for binary values. If no tag
|
||||
// has been started, then an empty one will be allocated first. When finished,
|
||||
// use WavpackWriteTag() to write the completed tag to the file. The purpose of
|
||||
// the passed size parameter is obvious for binary values, but might not be for
|
||||
// text values. Keep in mind that APEv2 text values can have multiple values
|
||||
// that are NULL separated, so the size is required to know the extent of the
|
||||
// value (although the final terminating NULL is not included in the passed
|
||||
// size). If the specified item already exists, it will be replaced with the
|
||||
// new value. ID3v1 tags are not supported.
|
||||
|
||||
int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize)
|
||||
{
|
||||
while (WavpackDeleteTagItem (wpc, item));
|
||||
return append_ape_tag_item (wpc, item, value, vsize, APE_TAG_TYPE_TEXT);
|
||||
}
|
||||
|
||||
int WavpackAppendBinaryTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize)
|
||||
{
|
||||
while (WavpackDeleteTagItem (wpc, item));
|
||||
return append_ape_tag_item (wpc, item, value, vsize, APE_TAG_TYPE_BINARY);
|
||||
}
|
||||
|
||||
// Delete the specified tag item from the APEv2 tag on the specified WavPack file
|
||||
// (fields cannot be deleted from ID3v1 tags). A return value of TRUE indicates
|
||||
// that the item was found and successfully deleted.
|
||||
|
||||
int WavpackDeleteTagItem (WavpackContext *wpc, const char *item)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A') {
|
||||
unsigned char *p = m_tag->ape_tag_data;
|
||||
unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m_tag->ape_tag_hdr.item_count; ++i) {
|
||||
int vsize, isize;
|
||||
|
||||
vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 8; // skip flags because we don't need them
|
||||
for (isize = 0; p[isize] && p + isize < q; ++isize);
|
||||
|
||||
if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q)
|
||||
break;
|
||||
|
||||
if (isize && vsize && !stricmp (item, (char *) p)) {
|
||||
unsigned char *d = p - 8;
|
||||
|
||||
p += isize + vsize + 1;
|
||||
|
||||
while (p < q)
|
||||
*d++ = *p++;
|
||||
|
||||
m_tag->ape_tag_hdr.length = (int32_t)(d - m_tag->ape_tag_data) + sizeof (APE_Tag_Hdr);
|
||||
m_tag->ape_tag_hdr.item_count--;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
p += isize + vsize + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Once a APEv2 tag has been created with WavpackAppendTag(), this function is
|
||||
// used to write the completed tag to the end of the WavPack file. Note that
|
||||
// this function uses the same "blockout" function that is used to write
|
||||
// regular WavPack blocks, although that's where the similarity ends. It is also
|
||||
// used to write tags that have been edited on existing files.
|
||||
|
||||
int WavpackWriteTag (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc->blockout) // this is the case for creating fresh WavPack files
|
||||
return write_tag_blockout (wpc);
|
||||
else // otherwise we are editing existing tags (OPEN_EDIT_TAGS)
|
||||
return write_tag_reader (wpc);
|
||||
}
|
||||
|
||||
////////////////////////// local static functions /////////////////////////////
|
||||
|
||||
static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size, int type)
|
||||
{
|
||||
unsigned char *p = m_tag->ape_tag_data;
|
||||
unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m_tag->ape_tag_hdr.item_count && q - p > 8; ++i) {
|
||||
int vsize, flags, isize;
|
||||
|
||||
vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
|
||||
flags = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
|
||||
for (isize = 0; p[isize] && p + isize < q; ++isize);
|
||||
|
||||
if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q)
|
||||
break;
|
||||
|
||||
if (isize && vsize && !stricmp (item, (char *) p) && ((flags & 6) >> 1) == type) {
|
||||
|
||||
if (!value || !size)
|
||||
return vsize;
|
||||
|
||||
if (type == APE_TAG_TYPE_BINARY) {
|
||||
if (vsize <= size) {
|
||||
memcpy (value, p + isize + 1, vsize);
|
||||
return vsize;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if (vsize < size) {
|
||||
memcpy (value, p + isize + 1, vsize);
|
||||
value [vsize] = 0;
|
||||
return vsize;
|
||||
}
|
||||
else if (size >= 4) {
|
||||
memcpy (value, p + isize + 1, size - 1);
|
||||
value [size - 4] = value [size - 3] = value [size - 2] = '.';
|
||||
value [size - 1] = 0;
|
||||
return size - 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
p += isize + vsize + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size)
|
||||
{
|
||||
char lvalue [64];
|
||||
int len;
|
||||
|
||||
lvalue [0] = 0;
|
||||
|
||||
if (!stricmp (item, "title"))
|
||||
tagcpy (lvalue, m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title));
|
||||
else if (!stricmp (item, "artist"))
|
||||
tagcpy (lvalue, m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist));
|
||||
else if (!stricmp (item, "album"))
|
||||
tagcpy (lvalue, m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album));
|
||||
else if (!stricmp (item, "year"))
|
||||
tagcpy (lvalue, m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year));
|
||||
else if (!stricmp (item, "comment"))
|
||||
tagcpy (lvalue, m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.comment));
|
||||
else if (!stricmp (item, "track") && m_tag->id3_tag.comment [29] && !m_tag->id3_tag.comment [28])
|
||||
sprintf (lvalue, "%d", m_tag->id3_tag.comment [29]);
|
||||
else
|
||||
return 0;
|
||||
|
||||
len = (int) strlen (lvalue);
|
||||
|
||||
if (!value || !size)
|
||||
return len;
|
||||
|
||||
if (len < size) {
|
||||
strcpy (value, lvalue);
|
||||
return len;
|
||||
}
|
||||
else if (size >= 4) {
|
||||
strncpy (value, lvalue, size - 1);
|
||||
value [size - 4] = value [size - 3] = value [size - 2] = '.';
|
||||
value [size - 1] = 0;
|
||||
return size - 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size, int type)
|
||||
{
|
||||
unsigned char *p = m_tag->ape_tag_data;
|
||||
unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m_tag->ape_tag_hdr.item_count && index >= 0 && q - p > 8; ++i) {
|
||||
int vsize, flags, isize;
|
||||
|
||||
vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
|
||||
flags = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
|
||||
for (isize = 0; p[isize] && p + isize < q; ++isize);
|
||||
|
||||
if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q)
|
||||
break;
|
||||
|
||||
if (isize && vsize && ((flags & 6) >> 1) == type && !index--) {
|
||||
|
||||
if (!item || !size)
|
||||
return isize;
|
||||
|
||||
if (isize < size) {
|
||||
memcpy (item, p, isize);
|
||||
item [isize] = 0;
|
||||
return isize;
|
||||
}
|
||||
else if (size >= 4) {
|
||||
memcpy (item, p, size - 1);
|
||||
item [size - 4] = item [size - 3] = item [size - 2] = '.';
|
||||
item [size - 1] = 0;
|
||||
return size - 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
p += isize + vsize + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size)
|
||||
{
|
||||
char lvalue [16];
|
||||
int len;
|
||||
|
||||
lvalue [0] = 0;
|
||||
|
||||
if (tagdata (m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title)) && !index--)
|
||||
strcpy (lvalue, "Title");
|
||||
else if (tagdata (m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist)) && !index--)
|
||||
strcpy (lvalue, "Artist");
|
||||
else if (tagdata (m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album)) && !index--)
|
||||
strcpy (lvalue, "Album");
|
||||
else if (tagdata (m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year)) && !index--)
|
||||
strcpy (lvalue, "Year");
|
||||
else if (tagdata (m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.comment)) && !index--)
|
||||
strcpy (lvalue, "Comment");
|
||||
else if (m_tag->id3_tag.comment [29] && !m_tag->id3_tag.comment [28] && !index--)
|
||||
strcpy (lvalue, "Track");
|
||||
else
|
||||
return 0;
|
||||
|
||||
len = (int) strlen (lvalue);
|
||||
|
||||
if (!item || !size)
|
||||
return len;
|
||||
|
||||
if (len < size) {
|
||||
strcpy (item, lvalue);
|
||||
return len;
|
||||
}
|
||||
else if (size >= 4) {
|
||||
strncpy (item, lvalue, size - 1);
|
||||
item [size - 4] = item [size - 3] = item [size - 2] = '.';
|
||||
item [size - 1] = 0;
|
||||
return size - 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_ape_tag_item (WavpackContext *wpc, const char *item, const char *value, int vsize, int type)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
int isize = (int) strlen (item);
|
||||
|
||||
if (!m_tag->ape_tag_hdr.ID [0]) {
|
||||
memcpy (m_tag->ape_tag_hdr.ID, "APETAGEX", sizeof (m_tag->ape_tag_hdr.ID));
|
||||
m_tag->ape_tag_hdr.version = 2000;
|
||||
m_tag->ape_tag_hdr.length = sizeof (m_tag->ape_tag_hdr);
|
||||
m_tag->ape_tag_hdr.item_count = 0;
|
||||
m_tag->ape_tag_hdr.flags = APE_TAG_CONTAINS_HEADER; // we will include header on tags we originate
|
||||
}
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A') {
|
||||
int new_item_len = vsize + isize + 9, flags = type << 1;
|
||||
unsigned char *p;
|
||||
|
||||
if (m_tag->ape_tag_hdr.length + new_item_len > APE_TAG_MAX_LENGTH) {
|
||||
strcpy (wpc->error_message, "APEv2 tag exceeds maximum allowed length!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_tag->ape_tag_hdr.item_count++;
|
||||
m_tag->ape_tag_hdr.length += new_item_len;
|
||||
p = m_tag->ape_tag_data = (unsigned char*)realloc (m_tag->ape_tag_data, m_tag->ape_tag_hdr.length);
|
||||
p += m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr) - new_item_len;
|
||||
|
||||
*p++ = (unsigned char) vsize;
|
||||
*p++ = (unsigned char) (vsize >> 8);
|
||||
*p++ = (unsigned char) (vsize >> 16);
|
||||
*p++ = (unsigned char) (vsize >> 24);
|
||||
|
||||
*p++ = (unsigned char) flags;
|
||||
*p++ = (unsigned char) (flags >> 8);
|
||||
*p++ = (unsigned char) (flags >> 16);
|
||||
*p++ = (unsigned char) (flags >> 24);
|
||||
|
||||
strcpy ((char *) p, item);
|
||||
p += isize + 1;
|
||||
memcpy (p, value, vsize);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Append the stored APEv2 tag to the file being created using the "blockout" function callback.
|
||||
|
||||
static int write_tag_blockout (WavpackContext *wpc)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
int result = TRUE;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A' && m_tag->ape_tag_hdr.item_count) {
|
||||
|
||||
// only write header if it's specified in the flags
|
||||
|
||||
if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER) {
|
||||
m_tag->ape_tag_hdr.flags |= APE_TAG_THIS_IS_HEADER;
|
||||
WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
result = wpc->blockout (wpc->wv_out, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr));
|
||||
WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
}
|
||||
|
||||
if (m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr))
|
||||
result = wpc->blockout (wpc->wv_out, m_tag->ape_tag_data, m_tag->ape_tag_hdr.length - sizeof (m_tag->ape_tag_hdr));
|
||||
|
||||
m_tag->ape_tag_hdr.flags &= ~APE_TAG_THIS_IS_HEADER; // this is NOT header
|
||||
WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
result = wpc->blockout (wpc->wv_out, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr));
|
||||
WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
strcpy (wpc->error_message, "can't write WavPack data, disk probably full!");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Write the [potentially] edited tag to the existing WavPack file using the reader callback functions.
|
||||
|
||||
static int write_tag_reader (WavpackContext *wpc)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
int32_t tag_size = 0;
|
||||
int result;
|
||||
|
||||
// before we write an edited (or new) tag into an existing file, make sure it's safe and possible
|
||||
|
||||
if (m_tag->tag_begins_file) {
|
||||
strcpy (wpc->error_message, "can't edit tags located at the beginning of files!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!wpc->reader->can_seek (wpc->wv_in)) {
|
||||
strcpy (wpc->error_message, "can't edit tags on pipes or unseekable files!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(wpc->open_flags & OPEN_EDIT_TAGS)) {
|
||||
strcpy (wpc->error_message, "can't edit tags without OPEN_EDIT_TAGS flag!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A' && m_tag->ape_tag_hdr.item_count &&
|
||||
m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr))
|
||||
tag_size = m_tag->ape_tag_hdr.length;
|
||||
|
||||
// only write header if it's specified in the flags
|
||||
|
||||
if (tag_size && (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER))
|
||||
tag_size += sizeof (m_tag->ape_tag_hdr);
|
||||
|
||||
result = !wpc->reader->set_pos_rel (wpc->wv_in, m_tag->tag_file_pos, SEEK_END);
|
||||
|
||||
if (result && tag_size < -m_tag->tag_file_pos && !wpc->reader->truncate_here) {
|
||||
int nullcnt = (int) (-m_tag->tag_file_pos - tag_size);
|
||||
char zero [1] = { 0 };
|
||||
|
||||
while (nullcnt--)
|
||||
wpc->reader->write_bytes (wpc->wv_in, &zero, 1);
|
||||
}
|
||||
|
||||
if (result && tag_size) {
|
||||
if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER) {
|
||||
m_tag->ape_tag_hdr.flags |= APE_TAG_THIS_IS_HEADER;
|
||||
WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
result = (wpc->reader->write_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr)) == sizeof (m_tag->ape_tag_hdr));
|
||||
WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
}
|
||||
|
||||
result = (wpc->reader->write_bytes (wpc->wv_in, m_tag->ape_tag_data, m_tag->ape_tag_hdr.length - sizeof (m_tag->ape_tag_hdr)) == sizeof (m_tag->ape_tag_hdr));
|
||||
m_tag->ape_tag_hdr.flags &= ~APE_TAG_THIS_IS_HEADER; // this is NOT header
|
||||
WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
result = (wpc->reader->write_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr)) == sizeof (m_tag->ape_tag_hdr));
|
||||
WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
}
|
||||
|
||||
if (result && tag_size < -m_tag->tag_file_pos && wpc->reader->truncate_here)
|
||||
result = !wpc->reader->truncate_here (wpc->wv_in);
|
||||
|
||||
if (!result)
|
||||
strcpy (wpc->error_message, "can't write WavPack data, disk probably full!");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Copy the specified ID3v1 tag value (with specified field size) from the
|
||||
// source pointer to the destination, eliminating leading spaces and trailing
|
||||
// spaces and nulls.
|
||||
|
||||
static void tagcpy (char *dest, char *src, int tag_size)
|
||||
{
|
||||
char *s1 = src, *s2 = src + tag_size - 1;
|
||||
|
||||
if (*s2 && !s2 [-1])
|
||||
s2--;
|
||||
|
||||
while (s1 <= s2)
|
||||
if (*s1 == ' ')
|
||||
++s1;
|
||||
else if (!*s2 || *s2 == ' ')
|
||||
--s2;
|
||||
else
|
||||
break;
|
||||
|
||||
while (*s1 && s1 <= s2)
|
||||
*dest++ = *s1++;
|
||||
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
static int tagdata (char *src, int tag_size)
|
||||
{
|
||||
char *s1 = src, *s2 = src + tag_size - 1;
|
||||
|
||||
if (*s2 && !s2 [-1])
|
||||
s2--;
|
||||
|
||||
while (s1 <= s2)
|
||||
if (*s1 == ' ')
|
||||
++s1;
|
||||
else if (!*s2 || *s2 == ' ')
|
||||
--s2;
|
||||
else
|
||||
break;
|
||||
|
||||
return (*s1 && s1 <= s2);
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// tags.c
|
||||
|
||||
// This module provides support for reading metadata tags (either ID3v1 or
|
||||
// APEv2) from WavPack files. No actual creation or manipulation of the tags
|
||||
// is done in this module; this is just internal code to load the tags into
|
||||
// memory. The high-level API functions are in the tag_utils.c module.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
// This function attempts to load an ID3v1 or APEv2 tag from the specified
|
||||
// file into the specified M_Tag structure. The ID3 tag fits in completely,
|
||||
// but an APEv2 tag is variable length and so space must be allocated here
|
||||
// to accommodate the data, and this will need to be freed later. A return
|
||||
// value of TRUE indicates a valid tag was found and loaded. Note that the
|
||||
// file pointer is undefined when this function exits.
|
||||
|
||||
int load_tag (WavpackContext *wpc)
|
||||
{
|
||||
int ape_tag_length, ape_tag_items;
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
CLEAR (*m_tag);
|
||||
|
||||
// This is a loop because we can try up to three times to look for an APEv2 tag. In order, we look:
|
||||
//
|
||||
// 1. At the end of the file for a APEv2 footer (this is the preferred location)
|
||||
// 2. If there's instead an ID3v1 tag at the end of the file, try looking for an APEv2 footer right before that
|
||||
// 3. If all else fails, look for an APEv2 header the the beginning of the file (use is strongly discouraged)
|
||||
|
||||
while (1) {
|
||||
|
||||
// seek based on specific location that we are looking for tag (see above list)
|
||||
|
||||
if (m_tag->tag_begins_file) // case #3
|
||||
wpc->reader->set_pos_abs (wpc->wv_in, 0);
|
||||
else if (m_tag->id3_tag.tag_id [0] == 'T') // case #2
|
||||
wpc->reader->set_pos_rel (wpc->wv_in, -(int32_t)(sizeof (APE_Tag_Hdr) + sizeof (ID3_Tag)), SEEK_END);
|
||||
else // case #1
|
||||
wpc->reader->set_pos_rel (wpc->wv_in, -(int32_t)sizeof (APE_Tag_Hdr), SEEK_END);
|
||||
|
||||
// read a possible APEv2 tag header/footer and see if there's one there...
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (APE_Tag_Hdr)) == sizeof (APE_Tag_Hdr) &&
|
||||
!strncmp (m_tag->ape_tag_hdr.ID, "APETAGEX", 8)) {
|
||||
|
||||
WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
|
||||
if (m_tag->ape_tag_hdr.version == 2000 && m_tag->ape_tag_hdr.item_count &&
|
||||
m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr) &&
|
||||
m_tag->ape_tag_hdr.length <= APE_TAG_MAX_LENGTH &&
|
||||
(m_tag->ape_tag_data = (unsigned char *)malloc (m_tag->ape_tag_hdr.length)) != NULL) {
|
||||
|
||||
ape_tag_items = m_tag->ape_tag_hdr.item_count;
|
||||
ape_tag_length = m_tag->ape_tag_hdr.length;
|
||||
|
||||
// If this is a APEv2 footer (which is normal if we are searching at the end of the file)...
|
||||
|
||||
if (!(m_tag->ape_tag_hdr.flags & APE_TAG_THIS_IS_HEADER)) {
|
||||
|
||||
if (m_tag->id3_tag.tag_id [0] == 'T')
|
||||
m_tag->tag_file_pos = -(int32_t)sizeof (ID3_Tag);
|
||||
else
|
||||
m_tag->tag_file_pos = 0;
|
||||
|
||||
m_tag->tag_file_pos -= ape_tag_length;
|
||||
|
||||
// if the footer claims there is a header present also, we will read that and use it
|
||||
// instead of the footer (after verifying it, of course) for enhanced robustness
|
||||
|
||||
if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER)
|
||||
m_tag->tag_file_pos -= sizeof (APE_Tag_Hdr);
|
||||
|
||||
wpc->reader->set_pos_rel (wpc->wv_in, m_tag->tag_file_pos, SEEK_END);
|
||||
|
||||
if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER) {
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (APE_Tag_Hdr)) !=
|
||||
sizeof (APE_Tag_Hdr) || strncmp (m_tag->ape_tag_hdr.ID, "APETAGEX", 8)) {
|
||||
free (m_tag->ape_tag_data);
|
||||
CLEAR (*m_tag);
|
||||
return FALSE; // something's wrong...
|
||||
}
|
||||
|
||||
WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
|
||||
if (m_tag->ape_tag_hdr.version != 2000 || m_tag->ape_tag_hdr.item_count != ape_tag_items ||
|
||||
m_tag->ape_tag_hdr.length != ape_tag_length) {
|
||||
free (m_tag->ape_tag_data);
|
||||
CLEAR (*m_tag);
|
||||
return FALSE; // something's wrong...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, m_tag->ape_tag_data,
|
||||
ape_tag_length - sizeof (APE_Tag_Hdr)) != ape_tag_length - sizeof (APE_Tag_Hdr)) {
|
||||
free (m_tag->ape_tag_data);
|
||||
CLEAR (*m_tag);
|
||||
return FALSE; // something's wrong...
|
||||
}
|
||||
else {
|
||||
CLEAR (m_tag->id3_tag); // ignore ID3v1 tag if we found APEv2 tag
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we come here if the search for the APEv2 tag failed (otherwise we would have returned with it)
|
||||
|
||||
if (m_tag->id3_tag.tag_id [0] == 'T') { // settle for the ID3v1 tag that we found
|
||||
CLEAR (m_tag->ape_tag_hdr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// if this was the search for the APEv2 tag at the beginning of the file (which is our
|
||||
// last resort) then we have nothing, so return failure
|
||||
|
||||
if (m_tag->tag_begins_file) {
|
||||
CLEAR (*m_tag);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// If we get here, then we have failed the first APEv2 tag search (at end of file) and so now we
|
||||
// look for an ID3v1 tag at the same position. If that succeeds, then we'll loop back and look for
|
||||
// an APEv2 tag immediately before the ID3v1 tag, otherwise our last resort is to look for an
|
||||
// APEv2 tag at the beginning of the file. These are strongly discouraged (and not editable) but
|
||||
// they have been seen in the wild so we attempt to handle them here (at least well enough to
|
||||
// allow a proper transcoding).
|
||||
|
||||
m_tag->tag_file_pos = -(int32_t)sizeof (ID3_Tag);
|
||||
wpc->reader->set_pos_rel (wpc->wv_in, m_tag->tag_file_pos, SEEK_END);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, &m_tag->id3_tag, sizeof (ID3_Tag)) != sizeof (ID3_Tag) ||
|
||||
strncmp (m_tag->id3_tag.tag_id, "TAG", 3)) {
|
||||
m_tag->tag_begins_file = 1; // failed ID3v1, so look for APEv2 at beginning of file
|
||||
CLEAR (m_tag->id3_tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return TRUE is a valid ID3v1 or APEv2 tag has been loaded.
|
||||
|
||||
int valid_tag (M_Tag *m_tag)
|
||||
{
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A')
|
||||
return 'A';
|
||||
else if (m_tag->id3_tag.tag_id [0] == 'T')
|
||||
return 'T';
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return FALSE if a valid APEv2 tag was only found at the beginning of the file (these are read-only
|
||||
// because they cannot be edited without possibly shifting the entire file)
|
||||
|
||||
int editable_tag (M_Tag *m_tag)
|
||||
{
|
||||
return !m_tag->tag_begins_file;
|
||||
}
|
||||
|
||||
// Free the data for any APEv2 tag that was allocated.
|
||||
|
||||
void free_tag (M_Tag *m_tag)
|
||||
{
|
||||
if (m_tag->ape_tag_data) {
|
||||
free (m_tag->ape_tag_data);
|
||||
m_tag->ape_tag_data = NULL;
|
||||
}
|
||||
}
|
|
@ -1,817 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack.c
|
||||
|
||||
// This module actually handles the decompression of the audio data, except for
|
||||
// the entropy decoding which is handled by the read_words.c module. For better
|
||||
// efficiency, the conversion is isolated to tight loops that handle an entire
|
||||
// buffer.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#ifdef OPT_ASM_X86
|
||||
#define DECORR_STEREO_PASS_CONT unpack_decorr_stereo_pass_cont_x86
|
||||
#define DECORR_STEREO_PASS_CONT_AVAILABLE unpack_cpu_has_feature_x86(CPU_FEATURE_MMX)
|
||||
#define DECORR_MONO_PASS_CONT unpack_decorr_mono_pass_cont_x86
|
||||
#elif defined(OPT_ASM_X64) && (defined (_WIN64) || defined(__CYGWIN__) || defined(__MINGW64__) || defined(__midipix__))
|
||||
#define DECORR_STEREO_PASS_CONT unpack_decorr_stereo_pass_cont_x64win
|
||||
#define DECORR_STEREO_PASS_CONT_AVAILABLE 1
|
||||
#define DECORR_MONO_PASS_CONT unpack_decorr_mono_pass_cont_x64win
|
||||
#elif defined(OPT_ASM_X64)
|
||||
#define DECORR_STEREO_PASS_CONT unpack_decorr_stereo_pass_cont_x64
|
||||
#define DECORR_STEREO_PASS_CONT_AVAILABLE 1
|
||||
#define DECORR_MONO_PASS_CONT unpack_decorr_mono_pass_cont_x64
|
||||
#elif defined(OPT_ASM_ARM)
|
||||
#define DECORR_STEREO_PASS_CONT unpack_decorr_stereo_pass_cont_armv7
|
||||
#define DECORR_STEREO_PASS_CONT_AVAILABLE 1
|
||||
#define DECORR_MONO_PASS_CONT unpack_decorr_mono_pass_cont_armv7
|
||||
#endif
|
||||
|
||||
#ifdef DECORR_STEREO_PASS_CONT
|
||||
extern void DECORR_STEREO_PASS_CONT (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count, int32_t long_math);
|
||||
extern void DECORR_MONO_PASS_CONT (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count, int32_t long_math);
|
||||
#endif
|
||||
|
||||
// This flag provides the functionality of terminating the decoding and muting
|
||||
// the output when a lossy sample appears to be corrupt. This is automatic
|
||||
// for lossless files because a corrupt sample is unambigious, but for lossy
|
||||
// data it might be possible for this to falsely trigger (although I have never
|
||||
// seen it).
|
||||
|
||||
#define LOSSY_MUTE
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// This monster actually unpacks the WavPack bitstream(s) into the specified
|
||||
// buffer as 32-bit integers or floats (depending on original data). Lossy
|
||||
// samples will be clipped to their original limits (i.e. 8-bit samples are
|
||||
// clipped to -128/+127) but are still returned in longs. It is up to the
|
||||
// caller to potentially reformat this for the final output including any
|
||||
// multichannel distribution, block alignment or endian compensation. The
|
||||
// function unpack_init() must have been called and the entire WavPack block
|
||||
// must still be visible (although wps->blockbuff will not be accessed again).
|
||||
// For maximum clarity, the function is broken up into segments that handle
|
||||
// various modes. This makes for a few extra infrequent flag checks, but
|
||||
// makes the code easier to follow because the nesting does not become so
|
||||
// deep. For maximum efficiency, the conversion is isolated to tight loops
|
||||
// that handle an entire buffer. The function returns the total number of
|
||||
// samples unpacked, which can be less than the number requested if an error
|
||||
// occurs or the end of the block is reached.
|
||||
|
||||
static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count);
|
||||
static void decorr_mono_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count);
|
||||
static void fixup_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count);
|
||||
|
||||
int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
uint32_t flags = wps->wphdr.flags, crc = wps->crc, i;
|
||||
int32_t mute_limit = (1L << ((flags & MAG_MASK) >> MAG_LSB)) + 2;
|
||||
int32_t correction [2], read_word, *bptr;
|
||||
struct decorr_pass *dpp;
|
||||
int tcount, m = 0;
|
||||
|
||||
// don't attempt to decode past the end of the block, but watch out for overflow!
|
||||
|
||||
if (wps->sample_index + sample_count > GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples &&
|
||||
(uint32_t) (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index) < sample_count)
|
||||
sample_count = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index);
|
||||
|
||||
if (GET_BLOCK_INDEX (wps->wphdr) > wps->sample_index || wps->wphdr.block_samples < sample_count)
|
||||
wps->mute_error = TRUE;
|
||||
|
||||
if (wps->mute_error) {
|
||||
if (wpc->reduced_channels == 1 || wpc->config.num_channels == 1 || (flags & MONO_FLAG))
|
||||
memset (buffer, 0, sample_count * 4);
|
||||
else
|
||||
memset (buffer, 0, sample_count * 8);
|
||||
|
||||
wps->sample_index += sample_count;
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
if ((flags & HYBRID_FLAG) && !wps->block2buff)
|
||||
mute_limit = (mute_limit * 2) + 128;
|
||||
|
||||
//////////////// handle lossless or hybrid lossy mono data /////////////////
|
||||
|
||||
if (!wps->block2buff && (flags & MONO_DATA)) {
|
||||
int32_t *eptr = buffer + sample_count;
|
||||
|
||||
if (flags & HYBRID_FLAG) {
|
||||
i = sample_count;
|
||||
|
||||
for (bptr = buffer; bptr < eptr;)
|
||||
if ((*bptr++ = get_word (wps, 0, NULL)) == WORD_EOF) {
|
||||
i = (uint32_t)(bptr - buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
i = get_words_lossless (wps, buffer, sample_count);
|
||||
|
||||
#ifdef DECORR_MONO_PASS_CONT
|
||||
if (sample_count < 16)
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
||||
decorr_mono_pass (dpp, buffer, sample_count);
|
||||
else
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
|
||||
int pre_samples = (dpp->term > MAX_TERM) ? 2 : dpp->term;
|
||||
|
||||
decorr_mono_pass (dpp, buffer, pre_samples);
|
||||
|
||||
DECORR_MONO_PASS_CONT (dpp, buffer + pre_samples, sample_count - pre_samples,
|
||||
((flags & MAG_MASK) >> MAG_LSB) > 15);
|
||||
}
|
||||
#else
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
||||
decorr_mono_pass (dpp, buffer, sample_count);
|
||||
#endif
|
||||
|
||||
#ifndef LOSSY_MUTE
|
||||
if (!(flags & HYBRID_FLAG))
|
||||
#endif
|
||||
for (bptr = buffer; bptr < eptr; ++bptr) {
|
||||
if (labs (bptr [0]) > mute_limit) {
|
||||
i = (uint32_t)(bptr - buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
crc = crc * 3 + bptr [0];
|
||||
}
|
||||
#ifndef LOSSY_MUTE
|
||||
else
|
||||
for (bptr = buffer; bptr < eptr; ++bptr)
|
||||
crc = crc * 3 + bptr [0];
|
||||
#endif
|
||||
}
|
||||
|
||||
/////////////// handle lossless or hybrid lossy stereo data ///////////////
|
||||
|
||||
else if (!wps->block2buff && !(flags & MONO_DATA)) {
|
||||
int32_t *eptr = buffer + (sample_count * 2);
|
||||
|
||||
if (flags & HYBRID_FLAG) {
|
||||
i = sample_count;
|
||||
|
||||
for (bptr = buffer; bptr < eptr; bptr += 2)
|
||||
if ((bptr [0] = get_word (wps, 0, NULL)) == WORD_EOF ||
|
||||
(bptr [1] = get_word (wps, 1, NULL)) == WORD_EOF) {
|
||||
i = (uint32_t)(bptr - buffer) / 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
i = get_words_lossless (wps, buffer, sample_count);
|
||||
|
||||
#ifdef DECORR_STEREO_PASS_CONT
|
||||
if (sample_count < 16 || !DECORR_STEREO_PASS_CONT_AVAILABLE) {
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
||||
decorr_stereo_pass (dpp, buffer, sample_count);
|
||||
|
||||
m = sample_count & (MAX_TERM - 1);
|
||||
}
|
||||
else
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
|
||||
int pre_samples = (dpp->term < 0 || dpp->term > MAX_TERM) ? 2 : dpp->term;
|
||||
|
||||
decorr_stereo_pass (dpp, buffer, pre_samples);
|
||||
|
||||
DECORR_STEREO_PASS_CONT (dpp, buffer + pre_samples * 2, sample_count - pre_samples,
|
||||
((flags & MAG_MASK) >> MAG_LSB) >= 16);
|
||||
}
|
||||
#else
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
||||
decorr_stereo_pass (dpp, buffer, sample_count);
|
||||
|
||||
m = sample_count & (MAX_TERM - 1);
|
||||
#endif
|
||||
|
||||
if (flags & JOINT_STEREO)
|
||||
for (bptr = buffer; bptr < eptr; bptr += 2) {
|
||||
bptr [0] += (bptr [1] -= (bptr [0] >> 1));
|
||||
crc += (crc << 3) + (bptr [0] << 1) + bptr [0] + bptr [1];
|
||||
}
|
||||
else
|
||||
for (bptr = buffer; bptr < eptr; bptr += 2)
|
||||
crc += (crc << 3) + (bptr [0] << 1) + bptr [0] + bptr [1];
|
||||
|
||||
#ifndef LOSSY_MUTE
|
||||
if (!(flags & HYBRID_FLAG))
|
||||
#endif
|
||||
for (bptr = buffer; bptr < eptr; bptr += 16)
|
||||
if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) {
|
||||
i = (uint32_t)(bptr - buffer) / 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////// handle hybrid lossless mono data ////////////////////
|
||||
|
||||
else if ((flags & HYBRID_FLAG) && (flags & MONO_DATA))
|
||||
for (bptr = buffer, i = 0; i < sample_count; ++i) {
|
||||
|
||||
if ((read_word = get_word (wps, 0, correction)) == WORD_EOF)
|
||||
break;
|
||||
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
|
||||
int32_t sam, temp;
|
||||
int k;
|
||||
|
||||
if (dpp->term > MAX_TERM) {
|
||||
if (dpp->term & 1)
|
||||
sam = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
else
|
||||
sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
k = 0;
|
||||
}
|
||||
else {
|
||||
sam = dpp->samples_A [m];
|
||||
k = (m + dpp->term) & (MAX_TERM - 1);
|
||||
}
|
||||
|
||||
temp = apply_weight (dpp->weight_A, sam) + read_word;
|
||||
update_weight (dpp->weight_A, dpp->delta, sam, read_word);
|
||||
dpp->samples_A [k] = read_word = temp;
|
||||
}
|
||||
|
||||
m = (m + 1) & (MAX_TERM - 1);
|
||||
|
||||
if (flags & HYBRID_SHAPE) {
|
||||
int shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16;
|
||||
int32_t temp = -apply_weight (shaping_weight, wps->dc.error [0]);
|
||||
|
||||
if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) {
|
||||
if (temp == wps->dc.error [0])
|
||||
temp = (temp < 0) ? temp + 1 : temp - 1;
|
||||
|
||||
wps->dc.error [0] = temp - correction [0];
|
||||
}
|
||||
else
|
||||
wps->dc.error [0] = -correction [0];
|
||||
|
||||
read_word += correction [0] - temp;
|
||||
}
|
||||
else
|
||||
read_word += correction [0];
|
||||
|
||||
crc += (crc << 1) + read_word;
|
||||
|
||||
if (labs (read_word) > mute_limit)
|
||||
break;
|
||||
|
||||
*bptr++ = read_word;
|
||||
}
|
||||
|
||||
//////////////////// handle hybrid lossless stereo data ///////////////////
|
||||
|
||||
else if (wps->block2buff && !(flags & MONO_DATA))
|
||||
for (bptr = buffer, i = 0; i < sample_count; ++i) {
|
||||
int32_t left, right, left2, right2;
|
||||
int32_t left_c = 0, right_c = 0;
|
||||
|
||||
if ((left = get_word (wps, 0, correction)) == WORD_EOF ||
|
||||
(right = get_word (wps, 1, correction + 1)) == WORD_EOF)
|
||||
break;
|
||||
|
||||
if (flags & CROSS_DECORR) {
|
||||
left_c = left + correction [0];
|
||||
right_c = right + correction [1];
|
||||
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
|
||||
int32_t sam_A, sam_B;
|
||||
|
||||
if (dpp->term > 0) {
|
||||
if (dpp->term > MAX_TERM) {
|
||||
if (dpp->term & 1) {
|
||||
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1];
|
||||
}
|
||||
else {
|
||||
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||
sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sam_A = dpp->samples_A [m];
|
||||
sam_B = dpp->samples_B [m];
|
||||
}
|
||||
|
||||
left_c += apply_weight (dpp->weight_A, sam_A);
|
||||
right_c += apply_weight (dpp->weight_B, sam_B);
|
||||
}
|
||||
else if (dpp->term == -1) {
|
||||
left_c += apply_weight (dpp->weight_A, dpp->samples_A [0]);
|
||||
right_c += apply_weight (dpp->weight_B, left_c);
|
||||
}
|
||||
else {
|
||||
right_c += apply_weight (dpp->weight_B, dpp->samples_B [0]);
|
||||
|
||||
if (dpp->term == -3)
|
||||
left_c += apply_weight (dpp->weight_A, dpp->samples_A [0]);
|
||||
else
|
||||
left_c += apply_weight (dpp->weight_A, right_c);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & JOINT_STEREO)
|
||||
left_c += (right_c -= (left_c >> 1));
|
||||
}
|
||||
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
|
||||
int32_t sam_A, sam_B;
|
||||
|
||||
if (dpp->term > 0) {
|
||||
int k;
|
||||
|
||||
if (dpp->term > MAX_TERM) {
|
||||
if (dpp->term & 1) {
|
||||
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1];
|
||||
}
|
||||
else {
|
||||
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||
sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1;
|
||||
}
|
||||
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
dpp->samples_B [1] = dpp->samples_B [0];
|
||||
k = 0;
|
||||
}
|
||||
else {
|
||||
sam_A = dpp->samples_A [m];
|
||||
sam_B = dpp->samples_B [m];
|
||||
k = (m + dpp->term) & (MAX_TERM - 1);
|
||||
}
|
||||
|
||||
left2 = apply_weight (dpp->weight_A, sam_A) + left;
|
||||
right2 = apply_weight (dpp->weight_B, sam_B) + right;
|
||||
|
||||
update_weight (dpp->weight_A, dpp->delta, sam_A, left);
|
||||
update_weight (dpp->weight_B, dpp->delta, sam_B, right);
|
||||
|
||||
dpp->samples_A [k] = left = left2;
|
||||
dpp->samples_B [k] = right = right2;
|
||||
}
|
||||
else if (dpp->term == -1) {
|
||||
left2 = left + apply_weight (dpp->weight_A, dpp->samples_A [0]);
|
||||
update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], left);
|
||||
left = left2;
|
||||
right2 = right + apply_weight (dpp->weight_B, left2);
|
||||
update_weight_clip (dpp->weight_B, dpp->delta, left2, right);
|
||||
dpp->samples_A [0] = right = right2;
|
||||
}
|
||||
else {
|
||||
right2 = right + apply_weight (dpp->weight_B, dpp->samples_B [0]);
|
||||
update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], right);
|
||||
right = right2;
|
||||
|
||||
if (dpp->term == -3) {
|
||||
right2 = dpp->samples_A [0];
|
||||
dpp->samples_A [0] = right;
|
||||
}
|
||||
|
||||
left2 = left + apply_weight (dpp->weight_A, right2);
|
||||
update_weight_clip (dpp->weight_A, dpp->delta, right2, left);
|
||||
dpp->samples_B [0] = left = left2;
|
||||
}
|
||||
}
|
||||
|
||||
m = (m + 1) & (MAX_TERM - 1);
|
||||
|
||||
if (!(flags & CROSS_DECORR)) {
|
||||
left_c = left + correction [0];
|
||||
right_c = right + correction [1];
|
||||
|
||||
if (flags & JOINT_STEREO)
|
||||
left_c += (right_c -= (left_c >> 1));
|
||||
}
|
||||
|
||||
if (flags & JOINT_STEREO)
|
||||
left += (right -= (left >> 1));
|
||||
|
||||
if (flags & HYBRID_SHAPE) {
|
||||
int shaping_weight;
|
||||
int32_t temp;
|
||||
|
||||
correction [0] = left_c - left;
|
||||
shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16;
|
||||
temp = -apply_weight (shaping_weight, wps->dc.error [0]);
|
||||
|
||||
if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) {
|
||||
if (temp == wps->dc.error [0])
|
||||
temp = (temp < 0) ? temp + 1 : temp - 1;
|
||||
|
||||
wps->dc.error [0] = temp - correction [0];
|
||||
}
|
||||
else
|
||||
wps->dc.error [0] = -correction [0];
|
||||
|
||||
left = left_c - temp;
|
||||
correction [1] = right_c - right;
|
||||
shaping_weight = (wps->dc.shaping_acc [1] += wps->dc.shaping_delta [1]) >> 16;
|
||||
temp = -apply_weight (shaping_weight, wps->dc.error [1]);
|
||||
|
||||
if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) {
|
||||
if (temp == wps->dc.error [1])
|
||||
temp = (temp < 0) ? temp + 1 : temp - 1;
|
||||
|
||||
wps->dc.error [1] = temp - correction [1];
|
||||
}
|
||||
else
|
||||
wps->dc.error [1] = -correction [1];
|
||||
|
||||
right = right_c - temp;
|
||||
}
|
||||
else {
|
||||
left = left_c;
|
||||
right = right_c;
|
||||
}
|
||||
|
||||
if (labs (left) > mute_limit || labs (right) > mute_limit)
|
||||
break;
|
||||
|
||||
crc += (crc << 3) + (left << 1) + left + right;
|
||||
*bptr++ = left;
|
||||
*bptr++ = right;
|
||||
}
|
||||
else
|
||||
i = 0; /* this line can't execute, but suppresses compiler warning */
|
||||
|
||||
if (i != sample_count) {
|
||||
memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8));
|
||||
wps->mute_error = TRUE;
|
||||
i = sample_count;
|
||||
|
||||
if (bs_is_open (&wps->wvxbits))
|
||||
bs_close_read (&wps->wvxbits);
|
||||
}
|
||||
|
||||
if (m)
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
||||
if (dpp->term > 0 && dpp->term <= MAX_TERM) {
|
||||
int32_t temp_A [MAX_TERM], temp_B [MAX_TERM];
|
||||
int k;
|
||||
|
||||
memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A));
|
||||
memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B));
|
||||
|
||||
for (k = 0; k < MAX_TERM; k++) {
|
||||
dpp->samples_A [k] = temp_A [m];
|
||||
dpp->samples_B [k] = temp_B [m];
|
||||
m = (m + 1) & (MAX_TERM - 1);
|
||||
}
|
||||
}
|
||||
|
||||
fixup_samples (wpc, buffer, i);
|
||||
|
||||
if ((flags & FLOAT_DATA) && (wpc->open_flags & OPEN_NORMALIZE))
|
||||
WavpackFloatNormalize (buffer, (flags & MONO_DATA) ? i : i * 2,
|
||||
127 - wps->float_norm_exp + wpc->norm_offset);
|
||||
|
||||
if (flags & FALSE_STEREO) {
|
||||
int32_t *dptr = buffer + i * 2;
|
||||
int32_t *sptr = buffer + i;
|
||||
int32_t c = i;
|
||||
|
||||
while (c--) {
|
||||
*--dptr = *--sptr;
|
||||
*--dptr = *sptr;
|
||||
}
|
||||
}
|
||||
|
||||
wps->sample_index += i;
|
||||
wps->crc = crc;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// General function to perform mono decorrelation pass on specified buffer
|
||||
// (although since this is the reverse function it might technically be called
|
||||
// "correlation" instead). This version handles all sample resolutions and
|
||||
// weight deltas. The dpp->samples_X[] data is returned normalized for term
|
||||
// values 1-8.
|
||||
|
||||
static void decorr_mono_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count)
|
||||
{
|
||||
int32_t delta = dpp->delta, weight_A = dpp->weight_A;
|
||||
int32_t *bptr, *eptr = buffer + sample_count, sam_A;
|
||||
int m, k;
|
||||
|
||||
switch (dpp->term) {
|
||||
|
||||
case 17:
|
||||
for (bptr = buffer; bptr < eptr; bptr++) {
|
||||
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0];
|
||||
update_weight (weight_A, delta, sam_A, bptr [0]);
|
||||
bptr [0] = dpp->samples_A [0];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 18:
|
||||
for (bptr = buffer; bptr < eptr; bptr++) {
|
||||
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0];
|
||||
update_weight (weight_A, delta, sam_A, bptr [0]);
|
||||
bptr [0] = dpp->samples_A [0];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr++) {
|
||||
sam_A = dpp->samples_A [m];
|
||||
dpp->samples_A [k] = apply_weight (weight_A, sam_A) + bptr [0];
|
||||
update_weight (weight_A, delta, sam_A, bptr [0]);
|
||||
bptr [0] = dpp->samples_A [k];
|
||||
m = (m + 1) & (MAX_TERM - 1);
|
||||
k = (k + 1) & (MAX_TERM - 1);
|
||||
}
|
||||
|
||||
if (m) {
|
||||
int32_t temp_samples [MAX_TERM];
|
||||
|
||||
memcpy (temp_samples, dpp->samples_A, sizeof (dpp->samples_A));
|
||||
|
||||
for (k = 0; k < MAX_TERM; k++, m++)
|
||||
dpp->samples_A [k] = temp_samples [m & (MAX_TERM - 1)];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
dpp->weight_A = weight_A;
|
||||
}
|
||||
|
||||
// General function to perform stereo decorrelation pass on specified buffer
|
||||
// (although since this is the reverse function it might technically be called
|
||||
// "correlation" instead). This version handles all sample resolutions and
|
||||
// weight deltas. The dpp->samples_X[] data is *not* returned normalized for
|
||||
// term values 1-8, so it should be normalized if it is going to be used to
|
||||
// call this function again.
|
||||
|
||||
static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count)
|
||||
{
|
||||
int32_t *bptr, *eptr = buffer + (sample_count * 2);
|
||||
int m, k;
|
||||
|
||||
switch (dpp->term) {
|
||||
case 17:
|
||||
for (bptr = buffer; bptr < eptr; bptr += 2) {
|
||||
int32_t sam, tmp;
|
||||
|
||||
sam = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
bptr [0] = dpp->samples_A [0] = apply_weight (dpp->weight_A, sam) + (tmp = bptr [0]);
|
||||
update_weight (dpp->weight_A, dpp->delta, sam, tmp);
|
||||
|
||||
sam = 2 * dpp->samples_B [0] - dpp->samples_B [1];
|
||||
dpp->samples_B [1] = dpp->samples_B [0];
|
||||
bptr [1] = dpp->samples_B [0] = apply_weight (dpp->weight_B, sam) + (tmp = bptr [1]);
|
||||
update_weight (dpp->weight_B, dpp->delta, sam, tmp);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 18:
|
||||
for (bptr = buffer; bptr < eptr; bptr += 2) {
|
||||
int32_t sam, tmp;
|
||||
|
||||
sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1);
|
||||
dpp->samples_A [1] = dpp->samples_A [0];
|
||||
bptr [0] = dpp->samples_A [0] = apply_weight (dpp->weight_A, sam) + (tmp = bptr [0]);
|
||||
update_weight (dpp->weight_A, dpp->delta, sam, tmp);
|
||||
|
||||
sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1);
|
||||
dpp->samples_B [1] = dpp->samples_B [0];
|
||||
bptr [1] = dpp->samples_B [0] = apply_weight (dpp->weight_B, sam) + (tmp = bptr [1]);
|
||||
update_weight (dpp->weight_B, dpp->delta, sam, tmp);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) {
|
||||
int32_t sam;
|
||||
|
||||
sam = dpp->samples_A [m];
|
||||
dpp->samples_A [k] = apply_weight (dpp->weight_A, sam) + bptr [0];
|
||||
update_weight (dpp->weight_A, dpp->delta, sam, bptr [0]);
|
||||
bptr [0] = dpp->samples_A [k];
|
||||
|
||||
sam = dpp->samples_B [m];
|
||||
dpp->samples_B [k] = apply_weight (dpp->weight_B, sam) + bptr [1];
|
||||
update_weight (dpp->weight_B, dpp->delta, sam, bptr [1]);
|
||||
bptr [1] = dpp->samples_B [k];
|
||||
|
||||
m = (m + 1) & (MAX_TERM - 1);
|
||||
k = (k + 1) & (MAX_TERM - 1);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case -1:
|
||||
for (bptr = buffer; bptr < eptr; bptr += 2) {
|
||||
int32_t sam;
|
||||
|
||||
sam = bptr [0] + apply_weight (dpp->weight_A, dpp->samples_A [0]);
|
||||
update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]);
|
||||
bptr [0] = sam;
|
||||
dpp->samples_A [0] = bptr [1] + apply_weight (dpp->weight_B, sam);
|
||||
update_weight_clip (dpp->weight_B, dpp->delta, sam, bptr [1]);
|
||||
bptr [1] = dpp->samples_A [0];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case -2:
|
||||
for (bptr = buffer; bptr < eptr; bptr += 2) {
|
||||
int32_t sam;
|
||||
|
||||
sam = bptr [1] + apply_weight (dpp->weight_B, dpp->samples_B [0]);
|
||||
update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]);
|
||||
bptr [1] = sam;
|
||||
dpp->samples_B [0] = bptr [0] + apply_weight (dpp->weight_A, sam);
|
||||
update_weight_clip (dpp->weight_A, dpp->delta, sam, bptr [0]);
|
||||
bptr [0] = dpp->samples_B [0];
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case -3:
|
||||
for (bptr = buffer; bptr < eptr; bptr += 2) {
|
||||
int32_t sam_A, sam_B;
|
||||
|
||||
sam_A = bptr [0] + apply_weight (dpp->weight_A, dpp->samples_A [0]);
|
||||
update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]);
|
||||
sam_B = bptr [1] + apply_weight (dpp->weight_B, dpp->samples_B [0]);
|
||||
update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]);
|
||||
bptr [0] = dpp->samples_B [0] = sam_A;
|
||||
bptr [1] = dpp->samples_A [0] = sam_B;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// This is a helper function for unpack_samples() that applies several final
|
||||
// operations. First, if the data is 32-bit float data, then that conversion
|
||||
// is done in the float.c module (whether lossy or lossless) and we return.
|
||||
// Otherwise, if the extended integer data applies, then that operation is
|
||||
// executed first. If the unpacked data is lossy (and not corrected) then
|
||||
// it is clipped and shifted in a single operation. Otherwise, if it's
|
||||
// lossless then the last step is to apply the final shift (if any).
|
||||
|
||||
static void fixup_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
uint32_t flags = wps->wphdr.flags;
|
||||
int lossy_flag = (flags & HYBRID_FLAG) && !wps->block2buff;
|
||||
int shift = (flags & SHIFT_MASK) >> SHIFT_LSB;
|
||||
|
||||
if (flags & FLOAT_DATA) {
|
||||
float_values (wps, buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & INT32_DATA) {
|
||||
uint32_t count = (flags & MONO_DATA) ? sample_count : sample_count * 2;
|
||||
int sent_bits = wps->int32_sent_bits, zeros = wps->int32_zeros;
|
||||
int ones = wps->int32_ones, dups = wps->int32_dups;
|
||||
uint32_t data, mask = (1 << sent_bits) - 1;
|
||||
int32_t *dptr = buffer;
|
||||
|
||||
if (bs_is_open (&wps->wvxbits)) {
|
||||
uint32_t crc = wps->crc_x;
|
||||
|
||||
while (count--) {
|
||||
// if (sent_bits) {
|
||||
getbits (&data, sent_bits, &wps->wvxbits);
|
||||
*dptr = (*dptr << sent_bits) | (data & mask);
|
||||
// }
|
||||
|
||||
if (zeros)
|
||||
*dptr <<= zeros;
|
||||
else if (ones)
|
||||
*dptr = ((*dptr + 1) << ones) - 1;
|
||||
else if (dups)
|
||||
*dptr = ((*dptr + (*dptr & 1)) << dups) - (*dptr & 1);
|
||||
|
||||
crc = crc * 9 + (*dptr & 0xffff) * 3 + ((*dptr >> 16) & 0xffff);
|
||||
dptr++;
|
||||
}
|
||||
|
||||
wps->crc_x = crc;
|
||||
}
|
||||
else if (!sent_bits && (zeros + ones + dups)) {
|
||||
while (lossy_flag && (flags & BYTES_STORED) == 3 && shift < 8) {
|
||||
if (zeros)
|
||||
zeros--;
|
||||
else if (ones)
|
||||
ones--;
|
||||
else if (dups)
|
||||
dups--;
|
||||
else
|
||||
break;
|
||||
|
||||
shift++;
|
||||
}
|
||||
|
||||
while (count--) {
|
||||
if (zeros)
|
||||
*dptr <<= zeros;
|
||||
else if (ones)
|
||||
*dptr = ((*dptr + 1) << ones) - 1;
|
||||
else if (dups)
|
||||
*dptr = ((*dptr + (*dptr & 1)) << dups) - (*dptr & 1);
|
||||
|
||||
dptr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
shift += zeros + sent_bits + ones + dups;
|
||||
}
|
||||
|
||||
if (lossy_flag) {
|
||||
int32_t min_value, max_value, min_shifted, max_shifted;
|
||||
|
||||
switch (flags & BYTES_STORED) {
|
||||
case 0:
|
||||
min_shifted = (min_value = -128 >> shift) << shift;
|
||||
max_shifted = (max_value = 127 >> shift) << shift;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
min_shifted = (min_value = -32768 >> shift) << shift;
|
||||
max_shifted = (max_value = 32767 >> shift) << shift;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
min_shifted = (min_value = -8388608 >> shift) << shift;
|
||||
max_shifted = (max_value = 8388607 >> shift) << shift;
|
||||
break;
|
||||
|
||||
case 3: default: /* "default" suppresses compiler warning */
|
||||
min_shifted = (min_value = (int32_t) 0x80000000 >> shift) << shift;
|
||||
max_shifted = (max_value = (int32_t) 0x7fffffff >> shift) << shift;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(flags & MONO_DATA))
|
||||
sample_count *= 2;
|
||||
|
||||
while (sample_count--) {
|
||||
if (*buffer < min_value)
|
||||
*buffer++ = min_shifted;
|
||||
else if (*buffer > max_value)
|
||||
*buffer++ = max_shifted;
|
||||
else
|
||||
*buffer++ <<= shift;
|
||||
}
|
||||
}
|
||||
else if (shift) {
|
||||
if (!(flags & MONO_DATA))
|
||||
sample_count *= 2;
|
||||
|
||||
while (sample_count--)
|
||||
*buffer++ <<= shift;
|
||||
}
|
||||
}
|
||||
|
||||
// This function checks the crc value(s) for an unpacked block, returning the
|
||||
// number of actual crc errors detected for the block. The block must be
|
||||
// completely unpacked before this test is valid. For losslessly unpacked
|
||||
// blocks of float or extended integer data the extended crc is also checked.
|
||||
// Note that WavPack's crc is not a CCITT approved polynomial algorithm, but
|
||||
// is a much simpler method that is virtually as robust for real world data.
|
||||
|
||||
int check_crc_error (WavpackContext *wpc)
|
||||
{
|
||||
int result = 0, stream;
|
||||
|
||||
for (stream = 0; stream < wpc->num_streams; stream++) {
|
||||
WavpackStream *wps = wpc->streams [stream];
|
||||
|
||||
if (wps->crc != wps->wphdr.crc)
|
||||
++result;
|
||||
else if (bs_is_open (&wps->wvxbits) && wps->crc_x != wps->crc_wvx)
|
||||
++result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,119 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2006 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// wavpack3.h
|
||||
|
||||
// This header file contains all the additional definitions required for
|
||||
// decoding old (versions 1, 2 & 3) WavPack files.
|
||||
|
||||
typedef struct {
|
||||
uint16_t FormatTag, NumChannels;
|
||||
uint32_t SampleRate, BytesPerSecond;
|
||||
uint16_t BlockAlign, BitsPerSample;
|
||||
} WaveHeader3;
|
||||
|
||||
#define WaveHeader3Format "SSLLSS"
|
||||
|
||||
typedef struct {
|
||||
char ckID [4];
|
||||
int32_t ckSize;
|
||||
int16_t version;
|
||||
int16_t bits; // added for version 2.00
|
||||
int16_t flags, shift; // added for version 3.00
|
||||
int32_t total_samples, crc, crc2;
|
||||
char extension [4], extra_bc, extras [3];
|
||||
} WavpackHeader3;
|
||||
|
||||
#define WavpackHeader3Format "4LSSSSLLL4L"
|
||||
|
||||
// these flags added for version 3
|
||||
|
||||
#undef MONO_FLAG // these definitions changed for WavPack 4.0
|
||||
#undef CROSS_DECORR
|
||||
#undef JOINT_STEREO
|
||||
|
||||
#define MONO_FLAG 1 // not stereo
|
||||
#define FAST_FLAG 2 // non-adaptive predictor and stereo mode
|
||||
#define RAW_FLAG 4 // raw mode (no .wav header)
|
||||
#define CALC_NOISE 8 // calc noise in lossy mode (no longer stored)
|
||||
#define HIGH_FLAG 0x10 // high quality mode (all modes)
|
||||
#define BYTES_3 0x20 // files have 3-byte samples
|
||||
#define OVER_20 0x40 // samples are over 20 bits
|
||||
#define WVC_FLAG 0x80 // create/use .wvc (no longer stored)
|
||||
#define LOSSY_SHAPE 0x100 // noise shape (lossy mode only)
|
||||
#define VERY_FAST_FLAG 0x200 // double fast (no longer stored)
|
||||
#define NEW_HIGH_FLAG 0x400 // new high quality mode (lossless only)
|
||||
#define CANCEL_EXTREME 0x800 // cancel EXTREME_DECORR
|
||||
#define CROSS_DECORR 0x1000 // decorrelate chans (with EXTREME_DECORR flag)
|
||||
#define NEW_DECORR_FLAG 0x2000 // new high-mode decorrelator
|
||||
#define JOINT_STEREO 0x4000 // joint stereo (lossy and high lossless)
|
||||
#define EXTREME_DECORR 0x8000 // extra decorrelation (+ enables other flags)
|
||||
|
||||
#define STORED_FLAGS 0xfd77 // these are only flags that affect unpacking
|
||||
#define NOT_STORED_FLAGS (~STORED_FLAGS & 0xffff)
|
||||
|
||||
// BitStream stuff (bits.c)
|
||||
|
||||
typedef struct bs3 {
|
||||
void (*wrap)(struct bs3 *bs);
|
||||
unsigned char *buf, *end, *ptr;
|
||||
uint32_t bufsiz, sr;
|
||||
int64_t fpos;
|
||||
WavpackStreamReader64 *reader;
|
||||
int error, bc;
|
||||
void *id;
|
||||
} Bitstream3;
|
||||
|
||||
#define K_DEPTH 3
|
||||
#define MAX_NTERMS3 18
|
||||
|
||||
typedef struct {
|
||||
WavpackHeader3 wphdr;
|
||||
Bitstream3 wvbits, wvcbits;
|
||||
uint32_t sample_index;
|
||||
int num_terms;
|
||||
|
||||
#ifndef NO_SEEKING
|
||||
struct index_point {
|
||||
char saved;
|
||||
uint32_t sample_index;
|
||||
} index_points [256];
|
||||
|
||||
unsigned char *unpack_data;
|
||||
uint32_t unpack_size;
|
||||
#endif
|
||||
|
||||
struct {
|
||||
int32_t sum_level, left_level, right_level, diff_level;
|
||||
int last_extra_bits, extra_bits_count, m;
|
||||
int32_t error [2], crc;
|
||||
int32_t sample [2] [2];
|
||||
int weight [2] [1];
|
||||
} dc;
|
||||
|
||||
struct decorr_pass decorr_passes [MAX_NTERMS3];
|
||||
|
||||
struct {
|
||||
unsigned int index [2], k_value [2], ave_k [2];
|
||||
uint32_t zeros_acc, ave_level [K_DEPTH] [2];
|
||||
} w1;
|
||||
|
||||
struct { int last_dbits [2], last_delta_sign [2], bit_limit; } w2;
|
||||
|
||||
struct { int ave_dbits [2], bit_limit; } w3;
|
||||
|
||||
struct {
|
||||
uint32_t fast_level [2], slow_level [2];
|
||||
int bits_acc [2], bitrate;
|
||||
} w4;
|
||||
} WavpackStream3;
|
||||
|
||||
#define SAVE(destin, item) { memcpy (destin, &item, sizeof (item)); destin = (char *) destin + sizeof (item); }
|
||||
#define RESTORE(item, source) { memcpy (&item, source, sizeof (item)); source = (char *) source + sizeof (item); }
|
||||
|
||||
void unpack_init3 (WavpackStream3 *wps);
|
|
@ -1,289 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack3_open.c
|
||||
|
||||
// This module provides an extension to the open_utils.c module for handling
|
||||
// WavPack files prior to version 4.0, not including "raw" files. As these
|
||||
// modes are all obsolete and are no longer written, this code will not be
|
||||
// fully documented other than the global functions. However, full documentation
|
||||
// is provided in the version 3.97 source code. Note that this module only
|
||||
// provides the functionality of opening the files and obtaining information
|
||||
// from them; the actual audio decoding is located in the unpack3.c module.
|
||||
|
||||
#ifdef ENABLE_LEGACY
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
#include "unpack3.h"
|
||||
|
||||
#define ATTEMPT_ERROR_MUTING
|
||||
|
||||
// This provides an extension to the WavpackOpenFileRead () function contained
|
||||
// in the wputils.c module. It is assumed that an 'R' had been read as the
|
||||
// first character of the file/stream (indicating a non-raw pre version 4.0
|
||||
// WavPack file) and had been pushed back onto the stream (or simply seeked
|
||||
// back to).
|
||||
|
||||
WavpackContext *open_file3 (WavpackContext *wpc, char *error)
|
||||
{
|
||||
RiffChunkHeader RiffChunkHeader;
|
||||
ChunkHeader ChunkHeader;
|
||||
WavpackHeader3 wphdr;
|
||||
WavpackStream3 *wps;
|
||||
WaveHeader3 wavhdr;
|
||||
|
||||
CLEAR (wavhdr);
|
||||
wpc->stream3 = wps = (WavpackStream3 *) malloc (sizeof (WavpackStream3));
|
||||
CLEAR (*wps);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, &RiffChunkHeader, sizeof (RiffChunkHeader)) !=
|
||||
sizeof (RiffChunkHeader)) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (!strncmp (RiffChunkHeader.ckID, "RIFF", 4) && !strncmp (RiffChunkHeader.formType, "WAVE", 4)) {
|
||||
|
||||
if (wpc->open_flags & OPEN_WRAPPER) {
|
||||
wpc->wrapper_data = (unsigned char *)malloc (wpc->wrapper_bytes = sizeof (RiffChunkHeader));
|
||||
memcpy (wpc->wrapper_data, &RiffChunkHeader, sizeof (RiffChunkHeader));
|
||||
}
|
||||
|
||||
// If the first chunk is a wave RIFF header, then read the various chunks
|
||||
// until we get to the "data" chunk (and WavPack header should follow). If
|
||||
// the first chunk is not a RIFF, then we assume a "raw" WavPack file and
|
||||
// the WavPack header must be first.
|
||||
|
||||
while (1) {
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, &ChunkHeader, sizeof (ChunkHeader)) !=
|
||||
sizeof (ChunkHeader)) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
else {
|
||||
if (wpc->open_flags & OPEN_WRAPPER) {
|
||||
wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (ChunkHeader));
|
||||
memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &ChunkHeader, sizeof (ChunkHeader));
|
||||
wpc->wrapper_bytes += sizeof (ChunkHeader);
|
||||
}
|
||||
|
||||
WavpackLittleEndianToNative (&ChunkHeader, ChunkHeaderFormat);
|
||||
|
||||
if (!strncmp (ChunkHeader.ckID, "fmt ", 4)) {
|
||||
|
||||
if (ChunkHeader.ckSize < sizeof (wavhdr) ||
|
||||
wpc->reader->read_bytes (wpc->wv_in, &wavhdr, sizeof (wavhdr)) != sizeof (wavhdr)) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
else if (wpc->open_flags & OPEN_WRAPPER) {
|
||||
wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (wavhdr));
|
||||
memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &wavhdr, sizeof (wavhdr));
|
||||
wpc->wrapper_bytes += sizeof (wavhdr);
|
||||
}
|
||||
|
||||
WavpackLittleEndianToNative (&wavhdr, WaveHeader3Format);
|
||||
|
||||
if (ChunkHeader.ckSize > sizeof (wavhdr)) {
|
||||
uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1 - sizeof (wavhdr)) & ~1L;
|
||||
|
||||
if (bytes_to_skip > 1024 * 1024) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (wpc->open_flags & OPEN_WRAPPER) {
|
||||
wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip);
|
||||
wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip);
|
||||
wpc->wrapper_bytes += bytes_to_skip;
|
||||
}
|
||||
else {
|
||||
unsigned char *temp = (unsigned char *)malloc (bytes_to_skip);
|
||||
wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip);
|
||||
free (temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strncmp (ChunkHeader.ckID, "data", 4))
|
||||
break;
|
||||
else if ((ChunkHeader.ckSize + 1) & ~1L) {
|
||||
uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1) & ~1L;
|
||||
|
||||
if (bytes_to_skip > 1024 * 1024) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (wpc->open_flags & OPEN_WRAPPER) {
|
||||
wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip);
|
||||
wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip);
|
||||
wpc->wrapper_bytes += bytes_to_skip;
|
||||
}
|
||||
else {
|
||||
unsigned char *temp = (unsigned char *)malloc (bytes_to_skip);
|
||||
wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip);
|
||||
free (temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (wavhdr.FormatTag != 1 || !wavhdr.NumChannels || wavhdr.NumChannels > 2 ||
|
||||
!wavhdr.SampleRate || wavhdr.BitsPerSample < 16 || wavhdr.BitsPerSample > 24 ||
|
||||
wavhdr.BlockAlign / wavhdr.NumChannels > 3 || wavhdr.BlockAlign % wavhdr.NumChannels ||
|
||||
wavhdr.BlockAlign / wavhdr.NumChannels < (wavhdr.BitsPerSample + 7) / 8) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
wpc->total_samples = ChunkHeader.ckSize / wavhdr.NumChannels /
|
||||
((wavhdr.BitsPerSample > 16) ? 3 : 2);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, &wphdr, 10) != 10) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (((char *) &wphdr) [8] == 2 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10, 2) != 2)) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
else if (((char *) &wphdr) [8] == 3 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10,
|
||||
sizeof (wphdr) - 10) != sizeof (wphdr) - 10)) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
WavpackLittleEndianToNative (&wphdr, WavpackHeader3Format);
|
||||
|
||||
// make sure this is a version we know about
|
||||
|
||||
if (strncmp (wphdr.ckID, "wvpk", 4) || wphdr.version < 1 || wphdr.version > 3) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
// Because I ran out of flag bits in the WavPack header, an amazingly ugly
|
||||
// kludge was forced upon me! This code takes care of preparing the flags
|
||||
// field for internal use and checking for unknown formats we can't decode
|
||||
|
||||
if (wphdr.version == 3) {
|
||||
|
||||
if (wphdr.flags & EXTREME_DECORR) {
|
||||
|
||||
if ((wphdr.flags & NOT_STORED_FLAGS) ||
|
||||
((wphdr.bits) &&
|
||||
(((wphdr.flags & NEW_HIGH_FLAG) &&
|
||||
(wphdr.flags & (FAST_FLAG | HIGH_FLAG))) ||
|
||||
(wphdr.flags & CROSS_DECORR)))) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (wphdr.flags & CANCEL_EXTREME)
|
||||
wphdr.flags &= ~(EXTREME_DECORR | CANCEL_EXTREME);
|
||||
}
|
||||
else
|
||||
wphdr.flags &= ~CROSS_DECORR;
|
||||
}
|
||||
|
||||
// check to see if we should look for a "correction" file, and if so try
|
||||
// to open it for reading, then set WVC_FLAG accordingly
|
||||
|
||||
if (wpc->wvc_in && wphdr.version == 3 && wphdr.bits && (wphdr.flags & NEW_HIGH_FLAG)) {
|
||||
wpc->file2len = wpc->reader->get_length (wpc->wvc_in);
|
||||
wphdr.flags |= WVC_FLAG;
|
||||
wpc->wvc_flag = TRUE;
|
||||
}
|
||||
else
|
||||
wphdr.flags &= ~WVC_FLAG;
|
||||
|
||||
// check WavPack version to handle special requirements of versions
|
||||
// before 3.0 that had smaller headers
|
||||
|
||||
if (wphdr.version < 3) {
|
||||
wphdr.total_samples = (int32_t) wpc->total_samples;
|
||||
wphdr.flags = wavhdr.NumChannels == 1 ? MONO_FLAG : 0;
|
||||
wphdr.shift = 16 - wavhdr.BitsPerSample;
|
||||
|
||||
if (wphdr.version == 1)
|
||||
wphdr.bits = 0;
|
||||
}
|
||||
|
||||
wpc->config.sample_rate = wavhdr.SampleRate;
|
||||
wpc->config.num_channels = wavhdr.NumChannels;
|
||||
wpc->config.channel_mask = 5 - wavhdr.NumChannels;
|
||||
|
||||
if (wphdr.flags & MONO_FLAG)
|
||||
wpc->config.flags |= CONFIG_MONO_FLAG;
|
||||
|
||||
if (wphdr.flags & EXTREME_DECORR)
|
||||
wpc->config.flags |= CONFIG_HIGH_FLAG;
|
||||
|
||||
if (wphdr.bits) {
|
||||
if (wphdr.flags & NEW_HIGH_FLAG)
|
||||
wpc->config.flags |= CONFIG_HYBRID_FLAG;
|
||||
else
|
||||
wpc->config.flags |= CONFIG_LOSSY_MODE;
|
||||
}
|
||||
else if (!(wphdr.flags & HIGH_FLAG))
|
||||
wpc->config.flags |= CONFIG_FAST_FLAG;
|
||||
|
||||
wpc->config.bytes_per_sample = (wphdr.flags & BYTES_3) ? 3 : 2;
|
||||
wpc->config.bits_per_sample = wavhdr.BitsPerSample;
|
||||
|
||||
memcpy (&wps->wphdr, &wphdr, sizeof (wphdr));
|
||||
wps->wvbits.bufsiz = wps->wvcbits.bufsiz = 1024 * 1024;
|
||||
return wpc;
|
||||
}
|
||||
|
||||
// return currently decoded sample index
|
||||
|
||||
uint32_t get_sample_index3 (WavpackContext *wpc)
|
||||
{
|
||||
WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
|
||||
|
||||
return (wps) ? wps->sample_index : (uint32_t) -1;
|
||||
}
|
||||
|
||||
int get_version3 (WavpackContext *wpc)
|
||||
{
|
||||
WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
|
||||
|
||||
return (wps) ? wps->wphdr.version : 0;
|
||||
}
|
||||
|
||||
void free_stream3 (WavpackContext *wpc)
|
||||
{
|
||||
WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
|
||||
|
||||
if (wps) {
|
||||
#ifndef NO_SEEKING
|
||||
if (wps->unpack_data)
|
||||
free (wps->unpack_data);
|
||||
#endif
|
||||
if ((wps->wphdr.flags & WVC_FLAG) && wps->wvcbits.buf)
|
||||
free (wps->wvcbits.buf);
|
||||
|
||||
if (wps->wvbits.buf)
|
||||
free (wps->wvbits.buf);
|
||||
|
||||
free (wps);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ENABLE_LEGACY
|
|
@ -1,212 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack3_seek.c
|
||||
|
||||
// This module provides seeking support for WavPack files prior to version 4.0.
|
||||
|
||||
#ifdef ENABLE_LEGACY
|
||||
#ifndef NO_SEEKING
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
#include "unpack3.h"
|
||||
|
||||
static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources);
|
||||
static void bs_restore3 (Bitstream3 *bs);
|
||||
|
||||
// This is an extension for WavpackSeekSample (). Note that because WavPack
|
||||
// files created prior to version 4.0 are not inherently seekable, this
|
||||
// function could take a long time if a forward seek is requested to an
|
||||
// area that has not been played (or seeked through) yet.
|
||||
|
||||
int seek_sample3 (WavpackContext *wpc, uint32_t desired_index)
|
||||
{
|
||||
int points_index = desired_index / (((uint32_t) wpc->total_samples >> 8) + 1);
|
||||
WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
|
||||
|
||||
if (desired_index >= wpc->total_samples)
|
||||
return FALSE;
|
||||
|
||||
while (points_index)
|
||||
if (wps->index_points [points_index].saved &&
|
||||
wps->index_points [points_index].sample_index <= desired_index)
|
||||
break;
|
||||
else
|
||||
points_index--;
|
||||
|
||||
if (wps->index_points [points_index].saved)
|
||||
if (wps->index_points [points_index].sample_index > wps->sample_index ||
|
||||
wps->sample_index > desired_index) {
|
||||
wps->sample_index = wps->index_points [points_index].sample_index;
|
||||
unpack_restore (wps, wps->unpack_data + points_index * wps->unpack_size, TRUE);
|
||||
}
|
||||
|
||||
if (desired_index > wps->sample_index) {
|
||||
int32_t *buffer = (int32_t *) malloc (1024 * (wps->wphdr.flags & MONO_FLAG ? 4 : 8));
|
||||
uint32_t samples_to_skip = desired_index - wps->sample_index;
|
||||
|
||||
while (1) {
|
||||
if (samples_to_skip > 1024) {
|
||||
if (unpack_samples3 (wpc, buffer, 1024) == 1024)
|
||||
samples_to_skip -= 1024;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else {
|
||||
samples_to_skip -= unpack_samples3 (wpc, buffer, samples_to_skip);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free (buffer);
|
||||
|
||||
if (samples_to_skip)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// This function restores the unpacking context from the specified pointer
|
||||
// and returns the updated pointer. After this call, unpack_samples() will
|
||||
// continue where it left off immediately before unpack_save() was called.
|
||||
// If the WavPack files and bitstreams might have been closed and reopened,
|
||||
// then the "keep_resources" flag should be set to avoid using the "old"
|
||||
// resources that were originally saved (and are probably now invalid).
|
||||
|
||||
static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources)
|
||||
{
|
||||
int flags = wps->wphdr.flags, tcount;
|
||||
struct decorr_pass *dpp;
|
||||
FILE *temp_file;
|
||||
unsigned char *temp_buf;
|
||||
|
||||
unpack_init3 (wps);
|
||||
temp_file = wps->wvbits.id;
|
||||
temp_buf = wps->wvbits.buf;
|
||||
RESTORE (wps->wvbits, source);
|
||||
|
||||
if (keep_resources) {
|
||||
wps->wvbits.id = temp_file;
|
||||
wps->wvbits.ptr += temp_buf - wps->wvbits.buf;
|
||||
wps->wvbits.end += temp_buf - wps->wvbits.buf;
|
||||
wps->wvbits.buf = temp_buf;
|
||||
}
|
||||
|
||||
bs_restore3 (&wps->wvbits);
|
||||
|
||||
if (flags & WVC_FLAG) {
|
||||
temp_file = wps->wvcbits.id;
|
||||
temp_buf = wps->wvcbits.buf;
|
||||
RESTORE (wps->wvcbits, source);
|
||||
|
||||
if (keep_resources) {
|
||||
wps->wvcbits.id = temp_file;
|
||||
wps->wvcbits.ptr += temp_buf - wps->wvcbits.buf;
|
||||
wps->wvcbits.end += temp_buf - wps->wvcbits.buf;
|
||||
wps->wvcbits.buf = temp_buf;
|
||||
}
|
||||
|
||||
bs_restore3 (&wps->wvcbits);
|
||||
}
|
||||
|
||||
if (wps->wphdr.version == 3) {
|
||||
if (wps->wphdr.bits) {
|
||||
RESTORE (wps->w4, source);
|
||||
}
|
||||
else {
|
||||
RESTORE (wps->w1, source);
|
||||
}
|
||||
|
||||
RESTORE (wps->w3, source);
|
||||
RESTORE (wps->dc.crc, source);
|
||||
}
|
||||
else
|
||||
RESTORE (wps->w2, source);
|
||||
|
||||
if (wps->wphdr.bits) {
|
||||
RESTORE (wps->dc.error, source);
|
||||
}
|
||||
else {
|
||||
RESTORE (wps->dc.sum_level, source);
|
||||
RESTORE (wps->dc.left_level, source);
|
||||
RESTORE (wps->dc.right_level, source);
|
||||
RESTORE (wps->dc.diff_level, source);
|
||||
}
|
||||
|
||||
if (flags & OVER_20) {
|
||||
RESTORE (wps->dc.last_extra_bits, source);
|
||||
RESTORE (wps->dc.extra_bits_count, source);
|
||||
}
|
||||
|
||||
if (!(flags & EXTREME_DECORR)) {
|
||||
RESTORE (wps->dc.sample, source);
|
||||
RESTORE (wps->dc.weight, source);
|
||||
}
|
||||
|
||||
if (flags & (HIGH_FLAG | NEW_HIGH_FLAG))
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
|
||||
if (dpp->term > 0) {
|
||||
int count = dpp->term;
|
||||
int index = wps->dc.m;
|
||||
|
||||
RESTORE (dpp->weight_A, source);
|
||||
|
||||
while (count--) {
|
||||
RESTORE (dpp->samples_A [index], source);
|
||||
index = (index + 1) & (MAX_TERM - 1);
|
||||
}
|
||||
|
||||
if (!(flags & MONO_FLAG)) {
|
||||
count = dpp->term;
|
||||
index = wps->dc.m;
|
||||
|
||||
RESTORE (dpp->weight_B, source);
|
||||
|
||||
while (count--) {
|
||||
RESTORE (dpp->samples_B [index], source);
|
||||
index = (index + 1) & (MAX_TERM - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
RESTORE (dpp->weight_A, source);
|
||||
RESTORE (dpp->weight_B, source);
|
||||
RESTORE (dpp->samples_A [0], source);
|
||||
RESTORE (dpp->samples_B [0], source);
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
// This function is called after a call to unpack_restore() has restored
|
||||
// the BitStream structure to a previous state and causes any required data
|
||||
// to be read from the file. This function is NOT supported for overlapped
|
||||
// operation.
|
||||
|
||||
static void bs_restore3 (Bitstream3 *bs)
|
||||
{
|
||||
uint32_t bytes_to_read = (uint32_t)(bs->end - bs->ptr - 1), bytes_read;
|
||||
|
||||
bs->reader->set_pos_abs (bs->id, bs->fpos - bytes_to_read);
|
||||
|
||||
if (bytes_to_read > 0) {
|
||||
|
||||
bytes_read = bs->reader->read_bytes (bs->id, bs->ptr + 1, bytes_to_read);
|
||||
|
||||
if (bytes_to_read != bytes_read)
|
||||
bs->end = bs->ptr + 1 + bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NO_SEEKING
|
||||
#endif // ENABLE_LEGACY
|
|
@ -1,620 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** DSDPACK **** //
|
||||
// Lossless DSD (Direct Stream Digital) Audio Compressor //
|
||||
// Copyright (c) 2013 - 2016 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack_dsd.c
|
||||
|
||||
// This module actually handles the uncompression of the DSD audio data.
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// This function initializes the main range-encoded data for DSD audio samples
|
||||
|
||||
static int init_dsd_block_fast (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
static int init_dsd_block_high (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
static int decode_fast (WavpackStream *wps, int32_t *output, int sample_count);
|
||||
static int decode_high (WavpackStream *wps, int32_t *output, int sample_count);
|
||||
|
||||
int init_dsd_block (WavpackContext *wpc, WavpackMetadata *wpmd)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
|
||||
if (wpmd->byte_length < 2)
|
||||
return FALSE;
|
||||
|
||||
wps->dsd.byteptr = (unsigned char *)wpmd->data;
|
||||
wps->dsd.endptr = wps->dsd.byteptr + wpmd->byte_length;
|
||||
wpc->dsd_multiplier = 1 << *wps->dsd.byteptr++;
|
||||
wps->dsd.mode = *wps->dsd.byteptr++;
|
||||
|
||||
if (!wps->dsd.mode) {
|
||||
if (wps->dsd.endptr - wps->dsd.byteptr != wps->wphdr.block_samples * (wps->wphdr.flags & MONO_DATA ? 1 : 2)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wps->dsd.ready = 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (wps->dsd.mode == 1)
|
||||
return init_dsd_block_fast (wps, wpmd);
|
||||
else if (wps->dsd.mode == 3)
|
||||
return init_dsd_block_high (wps, wpmd);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int32_t unpack_dsd_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
uint32_t flags = wps->wphdr.flags;
|
||||
|
||||
// don't attempt to decode past the end of the block, but watch out for overflow!
|
||||
|
||||
if (wps->sample_index + sample_count > GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples &&
|
||||
(uint32_t) (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index) < sample_count)
|
||||
sample_count = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index);
|
||||
|
||||
if (GET_BLOCK_INDEX (wps->wphdr) > wps->sample_index || wps->wphdr.block_samples < sample_count)
|
||||
wps->mute_error = TRUE;
|
||||
|
||||
if (!wps->mute_error) {
|
||||
if (!wps->dsd.mode) {
|
||||
int total_samples = sample_count * ((flags & MONO_DATA) ? 1 : 2);
|
||||
int32_t *bptr = buffer;
|
||||
|
||||
if (wps->dsd.endptr - wps->dsd.byteptr < total_samples)
|
||||
total_samples = (int)(wps->dsd.endptr - wps->dsd.byteptr);
|
||||
|
||||
while (total_samples--)
|
||||
wps->crc += (wps->crc << 1) + (*bptr++ = *wps->dsd.byteptr++);
|
||||
}
|
||||
else if (wps->dsd.mode == 1) {
|
||||
if (!decode_fast (wps, buffer, sample_count))
|
||||
wps->mute_error = TRUE;
|
||||
}
|
||||
else if (!decode_high (wps, buffer, sample_count))
|
||||
wps->mute_error = TRUE;
|
||||
}
|
||||
|
||||
if (wps->mute_error) {
|
||||
int samples_to_null;
|
||||
if (wpc->reduced_channels == 1 || wpc->config.num_channels == 1 || (flags & MONO_FLAG))
|
||||
samples_to_null = sample_count;
|
||||
else
|
||||
samples_to_null = sample_count * 2;
|
||||
|
||||
while (samples_to_null--)
|
||||
*buffer++ = 0x55;
|
||||
|
||||
wps->sample_index += sample_count;
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
if (flags & FALSE_STEREO) {
|
||||
int32_t *dptr = buffer + sample_count * 2;
|
||||
int32_t *sptr = buffer + sample_count;
|
||||
int32_t c = sample_count;
|
||||
|
||||
while (c--) {
|
||||
*--dptr = *--sptr;
|
||||
*--dptr = *sptr;
|
||||
}
|
||||
}
|
||||
|
||||
wps->sample_index += sample_count;
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
// #define DSD_BYTE_READY(low,high) (((low) >> 24) == ((high) >> 24))
|
||||
// #define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) >> 24))
|
||||
#define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) & 0xff000000))
|
||||
|
||||
static int init_dsd_block_fast (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char history_bits, max_probability, *lb_ptr;
|
||||
int total_summed_probabilities = 0, bi, i;
|
||||
|
||||
if (wps->dsd.byteptr == wps->dsd.endptr)
|
||||
return FALSE;
|
||||
|
||||
history_bits = *wps->dsd.byteptr++;
|
||||
|
||||
if (wps->dsd.byteptr == wps->dsd.endptr || history_bits > MAX_HISTORY_BITS)
|
||||
return FALSE;
|
||||
|
||||
wps->dsd.history_bins = 1 << history_bits;
|
||||
|
||||
free_dsd_tables (wps);
|
||||
lb_ptr = wps->dsd.lookup_buffer = (unsigned char *)malloc (wps->dsd.history_bins * MAX_BYTES_PER_BIN);
|
||||
wps->dsd.value_lookup = (unsigned char **)malloc (sizeof (*wps->dsd.value_lookup) * wps->dsd.history_bins);
|
||||
memset (wps->dsd.value_lookup, 0, sizeof (*wps->dsd.value_lookup) * wps->dsd.history_bins);
|
||||
wps->dsd.summed_probabilities = (int16_t (*)[256])malloc (sizeof (*wps->dsd.summed_probabilities) * wps->dsd.history_bins);
|
||||
wps->dsd.probabilities = (unsigned char (*)[256])malloc (sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins);
|
||||
|
||||
max_probability = *wps->dsd.byteptr++;
|
||||
|
||||
if (max_probability < 0xff) {
|
||||
unsigned char *outptr = (unsigned char *) wps->dsd.probabilities;
|
||||
unsigned char *outend = outptr + sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins;
|
||||
|
||||
while (outptr < outend && wps->dsd.byteptr < wps->dsd.endptr) {
|
||||
int code = *wps->dsd.byteptr++;
|
||||
|
||||
if (code > max_probability) {
|
||||
int zcount = code - max_probability;
|
||||
|
||||
while (outptr < outend && zcount--)
|
||||
*outptr++ = 0;
|
||||
}
|
||||
else if (code)
|
||||
*outptr++ = code;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (outptr < outend || (wps->dsd.byteptr < wps->dsd.endptr && *wps->dsd.byteptr++))
|
||||
return FALSE;
|
||||
}
|
||||
else if (wps->dsd.endptr - wps->dsd.byteptr > (int) sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins) {
|
||||
memcpy (wps->dsd.probabilities, wps->dsd.byteptr, sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins);
|
||||
wps->dsd.byteptr += sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
for (bi = 0; bi < wps->dsd.history_bins; ++bi) {
|
||||
int32_t sum_values;
|
||||
|
||||
for (sum_values = i = 0; i < 256; ++i)
|
||||
wps->dsd.summed_probabilities [bi] [i] = sum_values += wps->dsd.probabilities [bi] [i];
|
||||
|
||||
if (sum_values) {
|
||||
if ((total_summed_probabilities += sum_values) > wps->dsd.history_bins * MAX_BYTES_PER_BIN)
|
||||
return FALSE;
|
||||
|
||||
wps->dsd.value_lookup [bi] = lb_ptr;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
int c = wps->dsd.probabilities [bi] [i];
|
||||
|
||||
while (c--)
|
||||
*lb_ptr++ = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wps->dsd.endptr - wps->dsd.byteptr < 4 || total_summed_probabilities > wps->dsd.history_bins * MAX_BYTES_PER_BIN)
|
||||
return FALSE;
|
||||
|
||||
for (i = 4; i--;)
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
|
||||
wps->dsd.p0 = wps->dsd.p1 = 0;
|
||||
wps->dsd.low = 0; wps->dsd.high = 0xffffffff;
|
||||
wps->dsd.ready = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int decode_fast (WavpackStream *wps, int32_t *output, int sample_count)
|
||||
{
|
||||
int total_samples = sample_count;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
total_samples *= 2;
|
||||
|
||||
while (total_samples--) {
|
||||
int mult, index, code, i;
|
||||
|
||||
if (!wps->dsd.summed_probabilities [wps->dsd.p0] [255])
|
||||
return 0;
|
||||
|
||||
mult = (wps->dsd.high - wps->dsd.low) / wps->dsd.summed_probabilities [wps->dsd.p0] [255];
|
||||
|
||||
if (!mult) {
|
||||
if (wps->dsd.endptr - wps->dsd.byteptr >= 4)
|
||||
for (i = 4; i--;)
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
|
||||
wps->dsd.low = 0;
|
||||
wps->dsd.high = 0xffffffff;
|
||||
mult = wps->dsd.high / wps->dsd.summed_probabilities [wps->dsd.p0] [255];
|
||||
|
||||
if (!mult)
|
||||
return 0;
|
||||
}
|
||||
|
||||
index = (wps->dsd.value - wps->dsd.low) / mult;
|
||||
|
||||
if (index >= wps->dsd.summed_probabilities [wps->dsd.p0] [255])
|
||||
return 0;
|
||||
|
||||
if ((*output++ = code = wps->dsd.value_lookup [wps->dsd.p0] [index]))
|
||||
wps->dsd.low += wps->dsd.summed_probabilities [wps->dsd.p0] [code-1] * mult;
|
||||
|
||||
wps->dsd.high = wps->dsd.low + wps->dsd.probabilities [wps->dsd.p0] [code] * mult - 1;
|
||||
wps->crc += (wps->crc << 1) + code;
|
||||
|
||||
if (wps->wphdr.flags & MONO_DATA)
|
||||
wps->dsd.p0 = code & (wps->dsd.history_bins-1);
|
||||
else {
|
||||
wps->dsd.p0 = wps->dsd.p1;
|
||||
wps->dsd.p1 = code & (wps->dsd.history_bins-1);
|
||||
}
|
||||
|
||||
while (DSD_BYTE_READY (wps->dsd.high, wps->dsd.low) && wps->dsd.byteptr < wps->dsd.endptr) {
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
wps->dsd.high = (wps->dsd.high << 8) | 0xff;
|
||||
wps->dsd.low <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#define PTABLE_BITS 8
|
||||
#define PTABLE_BINS (1<<PTABLE_BITS)
|
||||
#define PTABLE_MASK (PTABLE_BINS-1)
|
||||
|
||||
#define UP 0x010000fe
|
||||
#define DOWN 0x00010000
|
||||
#define DECAY 8
|
||||
|
||||
#define PRECISION 20
|
||||
#define VALUE_ONE (1 << PRECISION)
|
||||
#define PRECISION_USE 12
|
||||
|
||||
#define RATE_S 20
|
||||
|
||||
static void init_ptable (int *table, int rate_i, int rate_s)
|
||||
{
|
||||
int value = 0x808000, rate = rate_i << 8, c, i;
|
||||
|
||||
for (c = (rate + 128) >> 8; c--;)
|
||||
value += (DOWN - value) >> DECAY;
|
||||
|
||||
for (i = 0; i < PTABLE_BINS/2; ++i) {
|
||||
table [i] = value;
|
||||
table [PTABLE_BINS-1-i] = 0x100ffff - value;
|
||||
|
||||
if (value > 0x010000) {
|
||||
rate += (rate * rate_s + 128) >> 8;
|
||||
|
||||
for (c = (rate + 64) >> 7; c--;)
|
||||
value += (DOWN - value) >> DECAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int init_dsd_block_high (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
uint32_t flags = wps->wphdr.flags;
|
||||
int channel, rate_i, rate_s, i;
|
||||
|
||||
if (wps->dsd.endptr - wps->dsd.byteptr < ((flags & MONO_DATA) ? 13 : 20))
|
||||
return FALSE;
|
||||
|
||||
rate_i = *wps->dsd.byteptr++;
|
||||
rate_s = *wps->dsd.byteptr++;
|
||||
|
||||
if (rate_s != RATE_S)
|
||||
return FALSE;
|
||||
|
||||
if (!wps->dsd.ptable)
|
||||
wps->dsd.ptable = (int32_t *)malloc (PTABLE_BINS * sizeof (*wps->dsd.ptable));
|
||||
|
||||
init_ptable (wps->dsd.ptable, rate_i, rate_s);
|
||||
|
||||
for (channel = 0; channel < ((flags & MONO_DATA) ? 1 : 2); ++channel) {
|
||||
DSDfilters *sp = wps->dsd.filters + channel;
|
||||
|
||||
sp->filter1 = *wps->dsd.byteptr++ << (PRECISION - 8);
|
||||
sp->filter2 = *wps->dsd.byteptr++ << (PRECISION - 8);
|
||||
sp->filter3 = *wps->dsd.byteptr++ << (PRECISION - 8);
|
||||
sp->filter4 = *wps->dsd.byteptr++ << (PRECISION - 8);
|
||||
sp->filter5 = *wps->dsd.byteptr++ << (PRECISION - 8);
|
||||
sp->filter6 = 0;
|
||||
sp->factor = *wps->dsd.byteptr++ & 0xff;
|
||||
sp->factor |= (*wps->dsd.byteptr++ << 8) & 0xff00;
|
||||
sp->factor = (sp->factor << 16) >> 16;
|
||||
}
|
||||
|
||||
wps->dsd.high = 0xffffffff;
|
||||
wps->dsd.low = 0x0;
|
||||
|
||||
for (i = 4; i--;)
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
|
||||
wps->dsd.ready = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int decode_high (WavpackStream *wps, int32_t *output, int sample_count)
|
||||
{
|
||||
int total_samples = sample_count, stereo = (wps->wphdr.flags & MONO_DATA) ? 0 : 1;
|
||||
DSDfilters *sp = wps->dsd.filters;
|
||||
|
||||
while (total_samples--) {
|
||||
int bitcount = 8;
|
||||
|
||||
sp [0].value = sp [0].filter1 - sp [0].filter5 + ((sp [0].filter6 * sp [0].factor) >> 2);
|
||||
|
||||
if (stereo)
|
||||
sp [1].value = sp [1].filter1 - sp [1].filter5 + ((sp [1].filter6 * sp [1].factor) >> 2);
|
||||
|
||||
while (bitcount--) {
|
||||
int32_t *pp = wps->dsd.ptable + ((sp [0].value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK);
|
||||
uint32_t split = wps->dsd.low + ((wps->dsd.high - wps->dsd.low) >> 8) * (*pp >> 16);
|
||||
|
||||
if (wps->dsd.value <= split) {
|
||||
wps->dsd.high = split;
|
||||
*pp += (UP - *pp) >> DECAY;
|
||||
sp [0].filter0 = -1;
|
||||
}
|
||||
else {
|
||||
wps->dsd.low = split + 1;
|
||||
*pp += (DOWN - *pp) >> DECAY;
|
||||
sp [0].filter0 = 0;
|
||||
}
|
||||
|
||||
while (DSD_BYTE_READY (wps->dsd.high, wps->dsd.low) && wps->dsd.byteptr < wps->dsd.endptr) {
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
wps->dsd.high = (wps->dsd.high << 8) | 0xff;
|
||||
wps->dsd.low <<= 8;
|
||||
}
|
||||
|
||||
sp [0].value += sp [0].filter6 << 3;
|
||||
sp [0].byte = (sp [0].byte << 1) | (sp [0].filter0 & 1);
|
||||
sp [0].factor += (((sp [0].value ^ sp [0].filter0) >> 31) | 1) & ((sp [0].value ^ (sp [0].value - (sp [0].filter6 << 4))) >> 31);
|
||||
sp [0].filter1 += ((sp [0].filter0 & VALUE_ONE) - sp [0].filter1) >> 6;
|
||||
sp [0].filter2 += ((sp [0].filter0 & VALUE_ONE) - sp [0].filter2) >> 4;
|
||||
sp [0].filter3 += (sp [0].filter2 - sp [0].filter3) >> 4;
|
||||
sp [0].filter4 += (sp [0].filter3 - sp [0].filter4) >> 4;
|
||||
sp [0].value = (sp [0].filter4 - sp [0].filter5) >> 4;
|
||||
sp [0].filter5 += sp [0].value;
|
||||
sp [0].filter6 += (sp [0].value - sp [0].filter6) >> 3;
|
||||
sp [0].value = sp [0].filter1 - sp [0].filter5 + ((sp [0].filter6 * sp [0].factor) >> 2);
|
||||
|
||||
if (!stereo)
|
||||
continue;
|
||||
|
||||
pp = wps->dsd.ptable + ((sp [1].value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK);
|
||||
split = wps->dsd.low + ((wps->dsd.high - wps->dsd.low) >> 8) * (*pp >> 16);
|
||||
|
||||
if (wps->dsd.value <= split) {
|
||||
wps->dsd.high = split;
|
||||
*pp += (UP - *pp) >> DECAY;
|
||||
sp [1].filter0 = -1;
|
||||
}
|
||||
else {
|
||||
wps->dsd.low = split + 1;
|
||||
*pp += (DOWN - *pp) >> DECAY;
|
||||
sp [1].filter0 = 0;
|
||||
}
|
||||
|
||||
while (DSD_BYTE_READY (wps->dsd.high, wps->dsd.low) && wps->dsd.byteptr < wps->dsd.endptr) {
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
wps->dsd.high = (wps->dsd.high << 8) | 0xff;
|
||||
wps->dsd.low <<= 8;
|
||||
}
|
||||
|
||||
sp [1].value += sp [1].filter6 << 3;
|
||||
sp [1].byte = (sp [1].byte << 1) | (sp [1].filter0 & 1);
|
||||
sp [1].factor += (((sp [1].value ^ sp [1].filter0) >> 31) | 1) & ((sp [1].value ^ (sp [1].value - (sp [1].filter6 << 4))) >> 31);
|
||||
sp [1].filter1 += ((sp [1].filter0 & VALUE_ONE) - sp [1].filter1) >> 6;
|
||||
sp [1].filter2 += ((sp [1].filter0 & VALUE_ONE) - sp [1].filter2) >> 4;
|
||||
sp [1].filter3 += (sp [1].filter2 - sp [1].filter3) >> 4;
|
||||
sp [1].filter4 += (sp [1].filter3 - sp [1].filter4) >> 4;
|
||||
sp [1].value = (sp [1].filter4 - sp [1].filter5) >> 4;
|
||||
sp [1].filter5 += sp [1].value;
|
||||
sp [1].filter6 += (sp [1].value - sp [1].filter6) >> 3;
|
||||
sp [1].value = sp [1].filter1 - sp [1].filter5 + ((sp [1].filter6 * sp [1].factor) >> 2);
|
||||
}
|
||||
|
||||
wps->crc += (wps->crc << 1) + (*output++ = sp [0].byte & 0xff);
|
||||
sp [0].factor -= (sp [0].factor + 512) >> 10;
|
||||
|
||||
if (stereo) {
|
||||
wps->crc += (wps->crc << 1) + (*output++ = wps->dsd.filters [1].byte & 0xff);
|
||||
wps->dsd.filters [1].factor -= (wps->dsd.filters [1].factor + 512) >> 10;
|
||||
}
|
||||
}
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#if 0
|
||||
|
||||
// 80 term DSD decimation filter
|
||||
// < 1 dB down at 20 kHz
|
||||
// > 108 dB stopband attenuation (fs/16)
|
||||
|
||||
static const int32_t decm_filter [] = {
|
||||
4, 17, 56, 147, 336, 693, 1320, 2359,
|
||||
4003, 6502, 10170, 15392, 22623, 32389, 45275, 61920,
|
||||
82994, 109174, 141119, 179431, 224621, 277068, 336983, 404373,
|
||||
479004, 560384, 647741, 740025, 835917, 933849, 1032042, 1128551,
|
||||
1221329, 1308290, 1387386, 1456680, 1514425, 1559128, 1589610, 1605059,
|
||||
1605059, 1589610, 1559128, 1514425, 1456680, 1387386, 1308290, 1221329,
|
||||
1128551, 1032042, 933849, 835917, 740025, 647741, 560384, 479004,
|
||||
404373, 336983, 277068, 224621, 179431, 141119, 109174, 82994,
|
||||
61920, 45275, 32389, 22623, 15392, 10170, 6502, 4003,
|
||||
2359, 1320, 693, 336, 147, 56, 17, 4,
|
||||
};
|
||||
|
||||
#define NUM_FILTER_TERMS 80
|
||||
|
||||
#else
|
||||
|
||||
// 56 term decimation filter
|
||||
// < 0.5 dB down at 20 kHz
|
||||
// > 100 dB stopband attenuation (fs/12)
|
||||
|
||||
static const int32_t decm_filter [] = {
|
||||
4, 17, 56, 147, 336, 692, 1315, 2337,
|
||||
3926, 6281, 9631, 14216, 20275, 28021, 37619, 49155,
|
||||
62616, 77870, 94649, 112551, 131049, 149507, 167220, 183448,
|
||||
197472, 208636, 216402, 220385, 220385, 216402, 208636, 197472,
|
||||
183448, 167220, 149507, 131049, 112551, 94649, 77870, 62616,
|
||||
49155, 37619, 28021, 20275, 14216, 9631, 6281, 3926,
|
||||
2337, 1315, 692, 336, 147, 56, 17, 4,
|
||||
};
|
||||
|
||||
#define NUM_FILTER_TERMS 56
|
||||
|
||||
#endif
|
||||
|
||||
#define HISTORY_BYTES ((NUM_FILTER_TERMS+7)/8)
|
||||
|
||||
typedef struct {
|
||||
unsigned char delay [HISTORY_BYTES];
|
||||
} DecimationChannel;
|
||||
|
||||
typedef struct {
|
||||
int32_t conv_tables [HISTORY_BYTES] [256];
|
||||
DecimationChannel *chans;
|
||||
int num_channels;
|
||||
} DecimationContext;
|
||||
|
||||
void *decimate_dsd_init (int num_channels)
|
||||
{
|
||||
DecimationContext *context = (DecimationContext *)malloc (sizeof (DecimationContext));
|
||||
double filter_sum = 0, filter_scale;
|
||||
int skipped_terms, i, j;
|
||||
|
||||
if (!context)
|
||||
return context;
|
||||
|
||||
memset (context, 0, sizeof (*context));
|
||||
context->num_channels = num_channels;
|
||||
context->chans = (DecimationChannel *)malloc (num_channels * sizeof (DecimationChannel));
|
||||
|
||||
if (!context->chans) {
|
||||
free (context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_FILTER_TERMS; ++i)
|
||||
filter_sum += decm_filter [i];
|
||||
|
||||
filter_scale = ((1 << 23) - 1) / filter_sum * 16.0;
|
||||
// fprintf (stderr, "convolution, %d terms, %f sum, %f scale\n", NUM_FILTER_TERMS, filter_sum, filter_scale);
|
||||
|
||||
for (skipped_terms = i = 0; i < NUM_FILTER_TERMS; ++i) {
|
||||
int scaled_term = (int) floor (decm_filter [i] * filter_scale + 0.5);
|
||||
|
||||
if (scaled_term) {
|
||||
for (j = 0; j < 256; ++j)
|
||||
if (j & (0x80 >> (i & 0x7)))
|
||||
context->conv_tables [i >> 3] [j] += scaled_term;
|
||||
else
|
||||
context->conv_tables [i >> 3] [j] -= scaled_term;
|
||||
}
|
||||
else
|
||||
skipped_terms++;
|
||||
}
|
||||
|
||||
// fprintf (stderr, "%d terms skipped\n", skipped_terms);
|
||||
|
||||
decimate_dsd_reset (context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void decimate_dsd_reset (void *decimate_context)
|
||||
{
|
||||
DecimationContext *context = (DecimationContext *) decimate_context;
|
||||
int chan = 0, i;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
for (chan = 0; chan < context->num_channels; ++chan)
|
||||
for (i = 0; i < HISTORY_BYTES; ++i)
|
||||
context->chans [chan].delay [i] = 0x55;
|
||||
}
|
||||
|
||||
void decimate_dsd_run (void *decimate_context, int32_t *samples, int num_samples)
|
||||
{
|
||||
DecimationContext *context = (DecimationContext *) decimate_context;
|
||||
int chan = 0;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
while (num_samples) {
|
||||
DecimationChannel *sp = context->chans + chan;
|
||||
int sum = 0;
|
||||
|
||||
#if (HISTORY_BYTES == 10)
|
||||
sum += context->conv_tables [0] [sp->delay [0] = sp->delay [1]];
|
||||
sum += context->conv_tables [1] [sp->delay [1] = sp->delay [2]];
|
||||
sum += context->conv_tables [2] [sp->delay [2] = sp->delay [3]];
|
||||
sum += context->conv_tables [3] [sp->delay [3] = sp->delay [4]];
|
||||
sum += context->conv_tables [4] [sp->delay [4] = sp->delay [5]];
|
||||
sum += context->conv_tables [5] [sp->delay [5] = sp->delay [6]];
|
||||
sum += context->conv_tables [6] [sp->delay [6] = sp->delay [7]];
|
||||
sum += context->conv_tables [7] [sp->delay [7] = sp->delay [8]];
|
||||
sum += context->conv_tables [8] [sp->delay [8] = sp->delay [9]];
|
||||
sum += context->conv_tables [9] [sp->delay [9] = *samples];
|
||||
#elif (HISTORY_BYTES == 7)
|
||||
sum += context->conv_tables [0] [sp->delay [0] = sp->delay [1]];
|
||||
sum += context->conv_tables [1] [sp->delay [1] = sp->delay [2]];
|
||||
sum += context->conv_tables [2] [sp->delay [2] = sp->delay [3]];
|
||||
sum += context->conv_tables [3] [sp->delay [3] = sp->delay [4]];
|
||||
sum += context->conv_tables [4] [sp->delay [4] = sp->delay [5]];
|
||||
sum += context->conv_tables [5] [sp->delay [5] = sp->delay [6]];
|
||||
sum += context->conv_tables [6] [sp->delay [6] = *samples];
|
||||
#else
|
||||
int i;
|
||||
|
||||
for (i = 0; i < HISTORY_BYTES-1; ++i)
|
||||
sum += context->conv_tables [i] [sp->delay [i] = sp->delay [i+1]];
|
||||
|
||||
sum += context->conv_tables [i] [sp->delay [i] = *samples];
|
||||
#endif
|
||||
|
||||
*samples++ = sum >> 4;
|
||||
|
||||
if (++chan == context->num_channels) {
|
||||
num_samples--;
|
||||
chan = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decimate_dsd_destroy (void *decimate_context)
|
||||
{
|
||||
DecimationContext *context = (DecimationContext *) decimate_context;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
if (context->chans)
|
||||
free (context->chans);
|
||||
|
||||
free (context);
|
||||
}
|
||||
|
||||
#endif // ENABLE_DSD
|
|
@ -1,134 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack_floats.c
|
||||
|
||||
// This module deals with the restoration of floating-point data. Note that no
|
||||
// floating point math is involved here...the values are only processed with
|
||||
// the macros that directly access the mantissa, exponent, and sign fields.
|
||||
// That's why we use the f32 type instead of the built-in float type.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values);
|
||||
|
||||
void float_values (WavpackStream *wps, int32_t *values, int32_t num_values)
|
||||
{
|
||||
uint32_t crc = wps->crc_x;
|
||||
|
||||
if (!bs_is_open (&wps->wvxbits)) {
|
||||
float_values_nowvx (wps, values, num_values);
|
||||
return;
|
||||
}
|
||||
|
||||
while (num_values--) {
|
||||
int shift_count = 0, exp = wps->float_max_exp;
|
||||
f32 outval = 0;
|
||||
uint32_t temp;
|
||||
|
||||
if (*values == 0) {
|
||||
if (wps->float_flags & FLOAT_ZEROS_SENT) {
|
||||
if (getbit (&wps->wvxbits)) {
|
||||
getbits (&temp, 23, &wps->wvxbits);
|
||||
set_mantissa (outval, temp);
|
||||
|
||||
if (exp >= 25) {
|
||||
getbits (&temp, 8, &wps->wvxbits);
|
||||
set_exponent (outval, temp);
|
||||
}
|
||||
|
||||
set_sign (outval, getbit (&wps->wvxbits));
|
||||
}
|
||||
else if (wps->float_flags & FLOAT_NEG_ZEROS)
|
||||
set_sign (outval, getbit (&wps->wvxbits));
|
||||
}
|
||||
}
|
||||
else {
|
||||
*values <<= wps->float_shift;
|
||||
|
||||
if (*values < 0) {
|
||||
*values = -*values;
|
||||
set_sign (outval, 1);
|
||||
}
|
||||
|
||||
if (*values == 0x1000000) {
|
||||
if (getbit (&wps->wvxbits)) {
|
||||
getbits (&temp, 23, &wps->wvxbits);
|
||||
set_mantissa (outval, temp);
|
||||
}
|
||||
|
||||
set_exponent (outval, 255);
|
||||
}
|
||||
else {
|
||||
if (exp)
|
||||
while (!(*values & 0x800000) && --exp) {
|
||||
shift_count++;
|
||||
*values <<= 1;
|
||||
}
|
||||
|
||||
if (shift_count) {
|
||||
if ((wps->float_flags & FLOAT_SHIFT_ONES) ||
|
||||
((wps->float_flags & FLOAT_SHIFT_SAME) && getbit (&wps->wvxbits)))
|
||||
*values |= ((1 << shift_count) - 1);
|
||||
else if (wps->float_flags & FLOAT_SHIFT_SENT) {
|
||||
getbits (&temp, shift_count, &wps->wvxbits);
|
||||
*values |= temp & ((1 << shift_count) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
set_mantissa (outval, *values);
|
||||
set_exponent (outval, exp);
|
||||
}
|
||||
}
|
||||
|
||||
crc = crc * 27 + get_mantissa (outval) * 9 + get_exponent (outval) * 3 + get_sign (outval);
|
||||
* (f32 *) values++ = outval;
|
||||
}
|
||||
|
||||
wps->crc_x = crc;
|
||||
}
|
||||
|
||||
static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values)
|
||||
{
|
||||
while (num_values--) {
|
||||
int shift_count = 0, exp = wps->float_max_exp;
|
||||
f32 outval = 0;
|
||||
|
||||
if (*values) {
|
||||
*values <<= wps->float_shift;
|
||||
|
||||
if (*values < 0) {
|
||||
*values = -*values;
|
||||
set_sign (outval, 1);
|
||||
}
|
||||
|
||||
if (*values >= 0x1000000) {
|
||||
while (*values & 0xf000000) {
|
||||
*values >>= 1;
|
||||
++exp;
|
||||
}
|
||||
}
|
||||
else if (exp) {
|
||||
while (!(*values & 0x800000) && --exp) {
|
||||
shift_count++;
|
||||
*values <<= 1;
|
||||
}
|
||||
|
||||
if (shift_count && (wps->float_flags & FLOAT_SHIFT_ONES))
|
||||
*values |= ((1 << shift_count) - 1);
|
||||
}
|
||||
|
||||
set_mantissa (outval, *values);
|
||||
set_exponent (outval, exp);
|
||||
}
|
||||
|
||||
* (f32 *) values++ = outval;
|
||||
}
|
||||
}
|
|
@ -1,387 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack_seek.c
|
||||
|
||||
// This module provides the high-level API for unpacking audio data from
|
||||
// a specific sample index (i.e., seeking).
|
||||
|
||||
#ifndef NO_SEEKING
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
static int64_t find_sample (WavpackContext *wpc, void *infile, int64_t header_pos, int64_t sample);
|
||||
|
||||
// Seek to the specified sample index, returning TRUE on success. Note that
|
||||
// files generated with version 4.0 or newer will seek almost immediately.
|
||||
// Older files can take quite long if required to seek through unplayed
|
||||
// portions of the file, but will create a seek map so that reverse seeks
|
||||
// (or forward seeks to already scanned areas) will be very fast. After a
|
||||
// FALSE return the file should not be accessed again (other than to close
|
||||
// it); this is a fatal error.
|
||||
|
||||
int WavpackSeekSample (WavpackContext *wpc, uint32_t sample)
|
||||
{
|
||||
return WavpackSeekSample64 (wpc, sample);
|
||||
}
|
||||
|
||||
int WavpackSeekSample64 (WavpackContext *wpc, int64_t sample)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams ? wpc->streams [wpc->current_stream = 0] : NULL;
|
||||
uint32_t bcount, samples_to_skip, samples_to_decode = 0;
|
||||
int32_t *buffer;
|
||||
|
||||
if (wpc->total_samples == -1 || sample >= wpc->total_samples ||
|
||||
!wpc->reader->can_seek (wpc->wv_in) || (wpc->open_flags & OPEN_STREAMING) ||
|
||||
(wpc->wvc_flag && !wpc->reader->can_seek (wpc->wvc_in)))
|
||||
return FALSE;
|
||||
|
||||
#ifdef ENABLE_LEGACY
|
||||
if (wpc->stream3)
|
||||
return seek_sample3 (wpc, (uint32_t) sample);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->decimation_context) { // the decimation code needs some context to be sample accurate
|
||||
if (sample < 16) {
|
||||
samples_to_decode = (uint32_t) sample;
|
||||
sample = 0;
|
||||
}
|
||||
else {
|
||||
samples_to_decode = 16;
|
||||
sample -= 16;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || sample < GET_BLOCK_INDEX (wps->wphdr) ||
|
||||
sample >= GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples) {
|
||||
|
||||
free_streams (wpc);
|
||||
wpc->filepos = find_sample (wpc, wpc->wv_in, wpc->filepos, sample);
|
||||
|
||||
if (wpc->filepos == -1)
|
||||
return FALSE;
|
||||
|
||||
if (wpc->wvc_flag) {
|
||||
wpc->file2pos = find_sample (wpc, wpc->wvc_in, 0, sample);
|
||||
|
||||
if (wpc->file2pos == -1)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wps->blockbuff) {
|
||||
wpc->reader->set_pos_abs (wpc->wv_in, wpc->filepos);
|
||||
wpc->reader->read_bytes (wpc->wv_in, &wps->wphdr, sizeof (WavpackHeader));
|
||||
WavpackLittleEndianToNative (&wps->wphdr, WavpackHeaderFormat);
|
||||
|
||||
if ((wps->wphdr.ckSize & 1) || wps->wphdr.ckSize < 24 || wps->wphdr.ckSize >= 1024 * 1024) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wps->blockbuff = (unsigned char *)malloc (wps->wphdr.ckSize + 8);
|
||||
memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader));
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + sizeof (WavpackHeader), wps->wphdr.ckSize - 24) !=
|
||||
wps->wphdr.ckSize - 24) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// render corrupt blocks harmless
|
||||
if (!WavpackVerifySingleBlock (wps->blockbuff, !(wpc->open_flags & OPEN_NO_CHECKSUM))) {
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
wps->wphdr.block_samples = 0;
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
}
|
||||
|
||||
SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index);
|
||||
memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader));
|
||||
wps->init_done = FALSE;
|
||||
|
||||
if (wpc->wvc_flag) {
|
||||
wpc->reader->set_pos_abs (wpc->wvc_in, wpc->file2pos);
|
||||
wpc->reader->read_bytes (wpc->wvc_in, &wps->wphdr, sizeof (WavpackHeader));
|
||||
WavpackLittleEndianToNative (&wps->wphdr, WavpackHeaderFormat);
|
||||
|
||||
if ((wps->wphdr.ckSize & 1) || wps->wphdr.ckSize < 24 || wps->wphdr.ckSize >= 1024 * 1024) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wps->block2buff = (unsigned char *)malloc (wps->wphdr.ckSize + 8);
|
||||
memcpy (wps->block2buff, &wps->wphdr, sizeof (WavpackHeader));
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + sizeof (WavpackHeader), wps->wphdr.ckSize - 24) !=
|
||||
wps->wphdr.ckSize - 24) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// render corrupt blocks harmless
|
||||
if (!WavpackVerifySingleBlock (wps->block2buff, !(wpc->open_flags & OPEN_NO_CHECKSUM))) {
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
wps->wphdr.block_samples = 0;
|
||||
memcpy (wps->block2buff, &wps->wphdr, 32);
|
||||
}
|
||||
|
||||
SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index);
|
||||
memcpy (wps->block2buff, &wps->wphdr, sizeof (WavpackHeader));
|
||||
}
|
||||
|
||||
if (!wps->init_done && !unpack_init (wpc)) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wps->init_done = TRUE;
|
||||
}
|
||||
|
||||
while (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) {
|
||||
if (++wpc->current_stream == wpc->num_streams) {
|
||||
|
||||
if (wpc->num_streams == wpc->max_streams) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wpc->streams = (WavpackStream **)realloc (wpc->streams, (wpc->num_streams + 1) * sizeof (wpc->streams [0]));
|
||||
wps = wpc->streams [wpc->num_streams++] = (WavpackStream *)malloc (sizeof (WavpackStream));
|
||||
CLEAR (*wps);
|
||||
bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr);
|
||||
|
||||
if (bcount == (uint32_t) -1) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wps->blockbuff = (unsigned char *)malloc (wps->wphdr.ckSize + 8);
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) !=
|
||||
wps->wphdr.ckSize - 24) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// render corrupt blocks harmless
|
||||
if (!WavpackVerifySingleBlock (wps->blockbuff, !(wpc->open_flags & OPEN_NO_CHECKSUM))) {
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
wps->wphdr.block_samples = 0;
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
}
|
||||
|
||||
wps->init_done = FALSE;
|
||||
|
||||
if (wpc->wvc_flag && !read_wvc_block (wpc)) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!wps->init_done && !unpack_init (wpc)) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wps->init_done = TRUE;
|
||||
}
|
||||
else
|
||||
wps = wpc->streams [wpc->current_stream];
|
||||
}
|
||||
|
||||
if (sample < wps->sample_index) {
|
||||
for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++)
|
||||
if (!unpack_init (wpc))
|
||||
return FALSE;
|
||||
else
|
||||
wpc->streams [wpc->current_stream]->init_done = TRUE;
|
||||
}
|
||||
|
||||
samples_to_skip = (uint32_t) (sample - wps->sample_index);
|
||||
|
||||
if (samples_to_skip > 131072) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (samples_to_skip) {
|
||||
buffer = (int32_t *)malloc (samples_to_skip * 8);
|
||||
|
||||
for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++)
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->streams [wpc->current_stream]->wphdr.flags & DSD_FLAG)
|
||||
unpack_dsd_samples (wpc, buffer, samples_to_skip);
|
||||
else
|
||||
#endif
|
||||
unpack_samples (wpc, buffer, samples_to_skip);
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
|
||||
wpc->current_stream = 0;
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->decimation_context)
|
||||
decimate_dsd_reset (wpc->decimation_context);
|
||||
|
||||
if (samples_to_decode) {
|
||||
buffer = (int32_t *)malloc (samples_to_decode * wpc->config.num_channels * 4);
|
||||
|
||||
if (buffer) {
|
||||
WavpackUnpackSamples (wpc, buffer, samples_to_decode);
|
||||
free (buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Find a valid WavPack header, searching either from the current file position
|
||||
// (or from the specified position if not -1) and store it (endian corrected)
|
||||
// at the specified pointer. The return value is the exact file position of the
|
||||
// header, although we may have actually read past it. Because this function
|
||||
// is used for seeking to a specific audio sample, it only considers blocks
|
||||
// that contain audio samples for the initial stream to be valid.
|
||||
|
||||
#define BUFSIZE 4096
|
||||
|
||||
static int64_t find_header (WavpackStreamReader64 *reader, void *id, int64_t filepos, WavpackHeader *wphdr)
|
||||
{
|
||||
unsigned char *buffer = (unsigned char *)malloc (BUFSIZE), *sp = buffer, *ep = buffer;
|
||||
|
||||
if (filepos != (uint32_t) -1 && reader->set_pos_abs (id, filepos)) {
|
||||
free (buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int bleft;
|
||||
|
||||
if (sp < ep) {
|
||||
bleft = (int)(ep - sp);
|
||||
memmove (buffer, sp, bleft);
|
||||
ep -= (sp - buffer);
|
||||
sp = buffer;
|
||||
}
|
||||
else {
|
||||
if (sp > ep)
|
||||
if (reader->set_pos_rel (id, (int32_t)(sp - ep), SEEK_CUR)) {
|
||||
free (buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sp = ep = buffer;
|
||||
bleft = 0;
|
||||
}
|
||||
|
||||
ep += reader->read_bytes (id, ep, BUFSIZE - bleft);
|
||||
|
||||
if (ep - sp < 32) {
|
||||
free (buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (sp + 32 <= ep)
|
||||
if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' &&
|
||||
!(*++sp & 1) && sp [2] < 16 && !sp [3] && (sp [2] || sp [1] || *sp >= 24) && sp [5] == 4 &&
|
||||
sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff) && sp [18] < 3 && !sp [19]) {
|
||||
memcpy (wphdr, sp - 4, sizeof (*wphdr));
|
||||
WavpackLittleEndianToNative (wphdr, WavpackHeaderFormat);
|
||||
|
||||
if (wphdr->block_samples && (wphdr->flags & INITIAL_BLOCK)) {
|
||||
free (buffer);
|
||||
return reader->get_pos (id) - (ep - sp + 4);
|
||||
}
|
||||
|
||||
if (wphdr->ckSize > 1024)
|
||||
sp += wphdr->ckSize - 1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the WavPack block that contains the specified sample. If "header_pos"
|
||||
// is zero, then no information is assumed except the total number of samples
|
||||
// in the file and its size in bytes. If "header_pos" is non-zero then we
|
||||
// assume that it is the file position of the valid header image contained in
|
||||
// the first stream and we can limit our search to either the portion above
|
||||
// or below that point. If a .wvc file is being used, then this must be called
|
||||
// for that file also.
|
||||
|
||||
static int64_t find_sample (WavpackContext *wpc, void *infile, int64_t header_pos, int64_t sample)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int64_t file_pos1 = 0, file_pos2 = wpc->reader->get_length (infile);
|
||||
int64_t sample_pos1 = 0, sample_pos2 = wpc->total_samples;
|
||||
double ratio = 0.96;
|
||||
int file_skip = 0;
|
||||
|
||||
if (sample >= wpc->total_samples)
|
||||
return -1;
|
||||
|
||||
if (header_pos && wps->wphdr.block_samples) {
|
||||
if (GET_BLOCK_INDEX (wps->wphdr) > sample) {
|
||||
sample_pos2 = GET_BLOCK_INDEX (wps->wphdr);
|
||||
file_pos2 = header_pos;
|
||||
}
|
||||
else if (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples <= sample) {
|
||||
sample_pos1 = GET_BLOCK_INDEX (wps->wphdr);
|
||||
file_pos1 = header_pos;
|
||||
}
|
||||
else
|
||||
return header_pos;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
double bytes_per_sample;
|
||||
int64_t seek_pos;
|
||||
|
||||
bytes_per_sample = (double) file_pos2 - file_pos1;
|
||||
bytes_per_sample /= sample_pos2 - sample_pos1;
|
||||
seek_pos = file_pos1 + (file_skip ? 32 : 0);
|
||||
seek_pos += (int64_t)(bytes_per_sample * (sample - sample_pos1) * ratio);
|
||||
seek_pos = find_header (wpc->reader, infile, seek_pos, &wps->wphdr);
|
||||
|
||||
if (seek_pos != (int64_t) -1)
|
||||
SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index);
|
||||
|
||||
if (seek_pos == (int64_t) -1 || seek_pos >= file_pos2) {
|
||||
if (ratio > 0.0) {
|
||||
if ((ratio -= 0.24) < 0.0)
|
||||
ratio = 0.0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else if (GET_BLOCK_INDEX (wps->wphdr) > sample) {
|
||||
sample_pos2 = GET_BLOCK_INDEX (wps->wphdr);
|
||||
file_pos2 = seek_pos;
|
||||
}
|
||||
else if (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples <= sample) {
|
||||
|
||||
if (seek_pos == file_pos1)
|
||||
file_skip = 1;
|
||||
else {
|
||||
sample_pos1 = GET_BLOCK_INDEX (wps->wphdr);
|
||||
file_pos1 = seek_pos;
|
||||
}
|
||||
}
|
||||
else
|
||||
return seek_pos;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,411 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack_utils.c
|
||||
|
||||
// This module provides the high-level API for unpacking audio data from
|
||||
// WavPack files. It manages the buffers used to interleave the data passed
|
||||
// back to the application from the individual streams. The actual audio
|
||||
// stream decompression is handled in the unpack.c module.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// Unpack the specified number of samples from the current file position.
|
||||
// Note that "samples" here refers to "complete" samples, which would be
|
||||
// 2 longs for stereo files or even more for multichannel files, so the
|
||||
// required memory at "buffer" is 4 * samples * num_channels bytes. The
|
||||
// audio data is returned right-justified in 32-bit longs in the endian
|
||||
// mode native to the executing processor. So, if the original data was
|
||||
// 16-bit, then the values returned would be +/-32k. Floating point data
|
||||
// can also be returned if the source was floating point data (and this
|
||||
// can be optionally normalized to +/-1.0 by using the appropriate flag
|
||||
// in the call to WavpackOpenFileInput ()). The actual number of samples
|
||||
// unpacked is returned, which should be equal to the number requested unless
|
||||
// the end of fle is encountered or an error occurs. After all samples have
|
||||
// been unpacked then 0 will be returned.
|
||||
|
||||
uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams ? wpc->streams [wpc->current_stream = 0] : NULL;
|
||||
int num_channels = wpc->config.num_channels, file_done = FALSE;
|
||||
uint32_t bcount, samples_unpacked = 0, samples_to_unpack;
|
||||
int32_t *bptr = buffer;
|
||||
|
||||
#ifdef ENABLE_LEGACY
|
||||
if (wpc->stream3)
|
||||
return unpack_samples3 (wpc, buffer, samples);
|
||||
#endif
|
||||
|
||||
while (samples) {
|
||||
|
||||
// if the current block has no audio, or it's not the first block of a multichannel
|
||||
// sequence, or the sample we're on is past the last sample in this block...we need
|
||||
// to free up the streams and read the next block
|
||||
|
||||
if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) ||
|
||||
wps->sample_index >= GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples) {
|
||||
|
||||
int64_t nexthdrpos;
|
||||
|
||||
if (wpc->wrapper_bytes >= MAX_WRAPPER_BYTES)
|
||||
break;
|
||||
|
||||
free_streams (wpc);
|
||||
nexthdrpos = wpc->reader->get_pos (wpc->wv_in);
|
||||
bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr);
|
||||
|
||||
if (bcount == (uint32_t) -1)
|
||||
break;
|
||||
|
||||
wpc->filepos = nexthdrpos + bcount;
|
||||
|
||||
// allocate the memory for the entire raw block and read it in
|
||||
|
||||
wps->blockbuff = (unsigned char *)malloc (wps->wphdr.ckSize + 8);
|
||||
|
||||
if (!wps->blockbuff)
|
||||
break;
|
||||
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) !=
|
||||
wps->wphdr.ckSize - 24) {
|
||||
strcpy (wpc->error_message, "can't read all of last block!");
|
||||
wps->wphdr.block_samples = 0;
|
||||
wps->wphdr.ckSize = 24;
|
||||
break;
|
||||
}
|
||||
|
||||
// render corrupt blocks harmless
|
||||
if (!WavpackVerifySingleBlock (wps->blockbuff, !(wpc->open_flags & OPEN_NO_CHECKSUM))) {
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
wps->wphdr.block_samples = 0;
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
}
|
||||
|
||||
// potentially adjusting block_index must be done AFTER verifying block
|
||||
|
||||
if (wpc->open_flags & OPEN_STREAMING)
|
||||
SET_BLOCK_INDEX (wps->wphdr, wps->sample_index = 0);
|
||||
else
|
||||
SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index);
|
||||
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
wps->init_done = FALSE; // we have not yet called unpack_init() for this block
|
||||
|
||||
// if this block has audio, but not the sample index we were expecting, flag an error
|
||||
|
||||
if (wps->wphdr.block_samples && wps->sample_index != GET_BLOCK_INDEX (wps->wphdr))
|
||||
wpc->crc_errors++;
|
||||
|
||||
// if this block has audio, and we're in hybrid lossless mode, read the matching wvc block
|
||||
|
||||
if (wps->wphdr.block_samples && wpc->wvc_flag)
|
||||
read_wvc_block (wpc);
|
||||
|
||||
// if the block does NOT have any audio, call unpack_init() to process non-audio stuff
|
||||
|
||||
if (!wps->wphdr.block_samples) {
|
||||
if (!wps->init_done && !unpack_init (wpc))
|
||||
wpc->crc_errors++;
|
||||
|
||||
wps->init_done = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// if the current block has no audio, or it's not the first block of a multichannel
|
||||
// sequence, or the sample we're on is past the last sample in this block...we need
|
||||
// to loop back and read the next block
|
||||
|
||||
if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) ||
|
||||
wps->sample_index >= GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples)
|
||||
continue;
|
||||
|
||||
// There seems to be some missing data, like a block was corrupted or something.
|
||||
// If it's not too much data, just fill in with silence here and loop back.
|
||||
|
||||
if (wps->sample_index < GET_BLOCK_INDEX (wps->wphdr)) {
|
||||
int32_t zvalue = (wps->wphdr.flags & DSD_FLAG) ? 0x55 : 0;
|
||||
|
||||
samples_to_unpack = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) - wps->sample_index);
|
||||
|
||||
if (!samples_to_unpack || samples_to_unpack > 262144) {
|
||||
strcpy (wpc->error_message, "discontinuity found, aborting file!");
|
||||
wps->wphdr.block_samples = 0;
|
||||
wps->wphdr.ckSize = 24;
|
||||
break;
|
||||
}
|
||||
|
||||
if (samples_to_unpack > samples)
|
||||
samples_to_unpack = samples;
|
||||
|
||||
wps->sample_index += samples_to_unpack;
|
||||
samples_unpacked += samples_to_unpack;
|
||||
samples -= samples_to_unpack;
|
||||
|
||||
samples_to_unpack *= (wpc->reduced_channels ? wpc->reduced_channels : num_channels);
|
||||
|
||||
while (samples_to_unpack--)
|
||||
*bptr++ = zvalue;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// calculate number of samples to process from this block, then initialize the decoder for
|
||||
// this block if we haven't already
|
||||
|
||||
samples_to_unpack = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index);
|
||||
|
||||
if (samples_to_unpack > samples)
|
||||
samples_to_unpack = samples;
|
||||
|
||||
if (!wps->init_done && !unpack_init (wpc))
|
||||
wpc->crc_errors++;
|
||||
|
||||
wps->init_done = TRUE;
|
||||
|
||||
// if this block is not the final block of a multichannel sequence (and we're not truncating
|
||||
// to stereo), then enter this conditional block...otherwise we just unpack the samples directly
|
||||
|
||||
if (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) {
|
||||
int32_t *temp_buffer = (int32_t *)malloc (samples_to_unpack * 8), *src, *dst;
|
||||
int offset = 0; // offset to next channel in sequence (0 to num_channels - 1)
|
||||
uint32_t samcnt;
|
||||
|
||||
// since we are getting samples from multiple bocks in a multichannel sequence, we must
|
||||
// allocate a temporary buffer to unpack to so that we can re-interleave the samples
|
||||
|
||||
if (!temp_buffer)
|
||||
break;
|
||||
|
||||
// loop through all the streams...
|
||||
|
||||
while (1) {
|
||||
|
||||
// if the stream has not been allocated and corresponding block read, do that here...
|
||||
|
||||
if (wpc->current_stream == wpc->num_streams) {
|
||||
wpc->streams = (WavpackStream **)realloc (wpc->streams, (wpc->num_streams + 1) * sizeof (wpc->streams [0]));
|
||||
|
||||
if (!wpc->streams)
|
||||
break;
|
||||
|
||||
wps = wpc->streams [wpc->num_streams++] = (WavpackStream *)malloc (sizeof (WavpackStream));
|
||||
|
||||
if (!wps)
|
||||
break;
|
||||
|
||||
CLEAR (*wps);
|
||||
bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr);
|
||||
|
||||
if (bcount == (uint32_t) -1) {
|
||||
wpc->streams [0]->wphdr.block_samples = 0;
|
||||
wpc->streams [0]->wphdr.ckSize = 24;
|
||||
file_done = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
wps->blockbuff = (unsigned char *)malloc (wps->wphdr.ckSize + 8);
|
||||
|
||||
if (!wps->blockbuff)
|
||||
break;
|
||||
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) !=
|
||||
wps->wphdr.ckSize - 24) {
|
||||
wpc->streams [0]->wphdr.block_samples = 0;
|
||||
wpc->streams [0]->wphdr.ckSize = 24;
|
||||
file_done = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
// render corrupt blocks harmless
|
||||
if (!WavpackVerifySingleBlock (wps->blockbuff, !(wpc->open_flags & OPEN_NO_CHECKSUM))) {
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
wps->wphdr.block_samples = 0;
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
}
|
||||
|
||||
// potentially adjusting block_index must be done AFTER verifying block
|
||||
|
||||
if (wpc->open_flags & OPEN_STREAMING)
|
||||
SET_BLOCK_INDEX (wps->wphdr, wps->sample_index = 0);
|
||||
else
|
||||
SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index);
|
||||
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
|
||||
// if this block has audio, and we're in hybrid lossless mode, read the matching wvc block
|
||||
|
||||
if (wpc->wvc_flag)
|
||||
read_wvc_block (wpc);
|
||||
|
||||
// initialize the unpacker for this block
|
||||
|
||||
if (!unpack_init (wpc))
|
||||
wpc->crc_errors++;
|
||||
|
||||
wps->init_done = TRUE;
|
||||
}
|
||||
else
|
||||
wps = wpc->streams [wpc->current_stream];
|
||||
|
||||
// unpack the correct number of samples (either mono or stereo) into the temp buffer
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wps->wphdr.flags & DSD_FLAG)
|
||||
unpack_dsd_samples (wpc, src = temp_buffer, samples_to_unpack);
|
||||
else
|
||||
#endif
|
||||
unpack_samples (wpc, src = temp_buffer, samples_to_unpack);
|
||||
|
||||
samcnt = samples_to_unpack;
|
||||
dst = bptr + offset;
|
||||
|
||||
// if the block is mono, copy the samples from the single channel into the destination
|
||||
// using num_channels as the stride
|
||||
|
||||
if (wps->wphdr.flags & MONO_FLAG) {
|
||||
while (samcnt--) {
|
||||
dst [0] = *src++;
|
||||
dst += num_channels;
|
||||
}
|
||||
|
||||
offset++;
|
||||
}
|
||||
|
||||
// if the block is stereo, and we don't have room for two more channels, just copy one
|
||||
// and flag an error
|
||||
|
||||
else if (offset == num_channels - 1) {
|
||||
while (samcnt--) {
|
||||
dst [0] = src [0];
|
||||
dst += num_channels;
|
||||
src += 2;
|
||||
}
|
||||
|
||||
wpc->crc_errors++;
|
||||
offset++;
|
||||
}
|
||||
|
||||
// otherwise copy the stereo samples into the destination
|
||||
|
||||
else {
|
||||
while (samcnt--) {
|
||||
dst [0] = *src++;
|
||||
dst [1] = *src++;
|
||||
dst += num_channels;
|
||||
}
|
||||
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
// check several clues that we're done with this set of blocks and exit if we are; else do next stream
|
||||
|
||||
if ((wps->wphdr.flags & FINAL_BLOCK) || wpc->current_stream == wpc->max_streams - 1 || offset == num_channels)
|
||||
break;
|
||||
else
|
||||
wpc->current_stream++;
|
||||
}
|
||||
|
||||
// if we didn't get all the channels we expected, mute the buffer and flag an error
|
||||
|
||||
if (offset != num_channels) {
|
||||
if (wps->wphdr.flags & DSD_FLAG) {
|
||||
int samples_to_zero = samples_to_unpack * num_channels;
|
||||
int32_t *zptr = bptr;
|
||||
|
||||
while (samples_to_zero--)
|
||||
*zptr++ = 0x55;
|
||||
}
|
||||
else
|
||||
memset (bptr, 0, samples_to_unpack * num_channels * 4);
|
||||
|
||||
wpc->crc_errors++;
|
||||
}
|
||||
|
||||
// go back to the first stream (we're going to leave them all loaded for now because they might have more samples)
|
||||
// and free the temp buffer
|
||||
|
||||
wps = wpc->streams [wpc->current_stream = 0];
|
||||
free (temp_buffer);
|
||||
}
|
||||
// catch the error situation where we have only one channel but run into a stereo block
|
||||
// (this avoids overwriting the caller's buffer)
|
||||
else if (!(wps->wphdr.flags & MONO_FLAG) && (num_channels == 1 || wpc->reduced_channels == 1)) {
|
||||
memset (bptr, 0, samples_to_unpack * sizeof (*bptr));
|
||||
wps->sample_index += samples_to_unpack;
|
||||
wpc->crc_errors++;
|
||||
}
|
||||
#ifdef ENABLE_DSD
|
||||
else if (wps->wphdr.flags & DSD_FLAG)
|
||||
unpack_dsd_samples (wpc, bptr, samples_to_unpack);
|
||||
#endif
|
||||
else
|
||||
unpack_samples (wpc, bptr, samples_to_unpack);
|
||||
|
||||
if (file_done) {
|
||||
strcpy (wpc->error_message, "can't read all of last block!");
|
||||
break;
|
||||
}
|
||||
|
||||
if (wpc->reduced_channels)
|
||||
bptr += samples_to_unpack * wpc->reduced_channels;
|
||||
else
|
||||
bptr += samples_to_unpack * num_channels;
|
||||
|
||||
samples_unpacked += samples_to_unpack;
|
||||
samples -= samples_to_unpack;
|
||||
|
||||
// if we just finished a block, check for a calculated crc error
|
||||
// (and back up the streams a little if possible in case we passed a header)
|
||||
|
||||
if (wps->sample_index == GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples) {
|
||||
if (check_crc_error (wpc)) {
|
||||
int32_t *zptr = bptr, zvalue = (wps->wphdr.flags & DSD_FLAG) ? 0x55 : 0;
|
||||
uint32_t samples_to_zero = wps->wphdr.block_samples;
|
||||
|
||||
if (samples_to_zero > samples_to_unpack)
|
||||
samples_to_zero = samples_to_unpack;
|
||||
|
||||
samples_to_zero *= (wpc->reduced_channels ? wpc->reduced_channels : num_channels);
|
||||
|
||||
while (samples_to_zero--)
|
||||
*--zptr = zvalue;
|
||||
|
||||
if (wps->blockbuff && wpc->reader->can_seek (wpc->wv_in)) {
|
||||
int32_t rseek = ((WavpackHeader *) wps->blockbuff)->ckSize / 3;
|
||||
wpc->reader->set_pos_rel (wpc->wv_in, (rseek > 16384) ? -16384 : -rseek, SEEK_CUR);
|
||||
}
|
||||
|
||||
if (wpc->wvc_flag && wps->block2buff && wpc->reader->can_seek (wpc->wvc_in)) {
|
||||
int32_t rseek = ((WavpackHeader *) wps->block2buff)->ckSize / 3;
|
||||
wpc->reader->set_pos_rel (wpc->wvc_in, (rseek > 16384) ? -16384 : -rseek, SEEK_CUR);
|
||||
}
|
||||
|
||||
wpc->crc_errors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (wpc->total_samples != -1 && wps->sample_index == wpc->total_samples)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->decimation_context)
|
||||
decimate_dsd_run (wpc->decimation_context, buffer, samples_unpacked);
|
||||
#endif
|
||||
|
||||
return samples_unpacked;
|
||||
}
|
|
@ -1,770 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2006 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// utils.c
|
||||
|
||||
// This module provides general purpose utilities for the WavPack command-line
|
||||
// utilities and the self-extraction module.
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <conio.h>
|
||||
#include <shlobj.h>
|
||||
#elif defined(__GNUC__) || defined(__sun)
|
||||
#include <glob.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "wavpack.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "win32_unicode_support.h"
|
||||
#define fprintf fprintf_utf8
|
||||
#define fputs fputs_utf8
|
||||
#define remove(f) unlink_utf8(f)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
int copy_timestamp (const char *src_filename, const char *dst_filename)
|
||||
{
|
||||
wchar_t *src_filename_utf16 = utf8_to_utf16(src_filename);
|
||||
wchar_t *dst_filename_utf16 = utf8_to_utf16(dst_filename);
|
||||
FILETIME last_modified;
|
||||
HANDLE src, dst;
|
||||
int res = TRUE;
|
||||
|
||||
if (*src_filename == '-' || *dst_filename == '-')
|
||||
return res;
|
||||
|
||||
if (!src_filename_utf16 || !dst_filename_utf16)
|
||||
return FALSE;
|
||||
|
||||
src = CreateFileW (src_filename_utf16, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
|
||||
dst = CreateFileW (dst_filename_utf16, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
|
||||
if (src == INVALID_HANDLE_VALUE || dst == INVALID_HANDLE_VALUE ||
|
||||
!GetFileTime (src, NULL, NULL, &last_modified) ||
|
||||
!SetFileTime (dst, NULL, NULL, &last_modified))
|
||||
res = FALSE;
|
||||
|
||||
if (src != INVALID_HANDLE_VALUE)
|
||||
CloseHandle (src);
|
||||
|
||||
if (dst != INVALID_HANDLE_VALUE)
|
||||
CloseHandle (dst);
|
||||
|
||||
free (src_filename_utf16);
|
||||
free (dst_filename_utf16);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
int copy_timestamp(const char *src_filename, const char *dst_filename)
|
||||
{
|
||||
struct stat fileinfo;
|
||||
struct timeval times[2];
|
||||
|
||||
if (strcmp(src_filename, "-") == 0 || strcmp(dst_filename, "-") == 0)
|
||||
return TRUE;
|
||||
|
||||
if (stat(src_filename, &fileinfo))
|
||||
return FALSE; /* stat failed */
|
||||
|
||||
times[0].tv_sec = fileinfo.st_atime;
|
||||
times[0].tv_usec = 0;
|
||||
|
||||
times[1].tv_sec = fileinfo.st_mtime;
|
||||
times[1].tv_usec = 0;
|
||||
|
||||
if (utimes(dst_filename, times))
|
||||
return FALSE; /* utimes failed */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// This function parses a filename (with or without full path) and returns //
|
||||
// a pointer to the extension (including the "."). If no extension is found //
|
||||
// then NULL is returned. Extensions with more than 4 letters don't count. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
char *filespec_ext (char *filespec)
|
||||
{
|
||||
char *cp = filespec + strlen (filespec);
|
||||
|
||||
while (--cp >= filespec) {
|
||||
|
||||
if (*cp == '\\' || *cp == ':')
|
||||
return NULL;
|
||||
|
||||
if (*cp == '.') {
|
||||
if (strlen (cp+1) && strlen (cp+1) <= 4)
|
||||
return cp;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
char *filespec_ext (char *filespec)
|
||||
{
|
||||
char *cp = filespec + strlen (filespec);
|
||||
|
||||
while (--cp >= filespec) {
|
||||
|
||||
if (*cp == '/')
|
||||
return NULL;
|
||||
|
||||
if (*cp == '.') {
|
||||
if (strlen (cp+1) && strlen (cp+1) <= 4)
|
||||
return cp;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// This function determines if the specified filespec is a valid pathname. //
|
||||
// If not, NULL is returned. If it is in the format of a pathname, then the //
|
||||
// original pointer is returned. If the format is ambiguous, then a lookup //
|
||||
// is performed to determine if it is in fact a valid path, and if so a "\" //
|
||||
// is appended so that the pathname can be used and the original pointer is //
|
||||
// returned. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if (defined(__GNUC__) || defined(__sun)) && !defined(_WIN32)
|
||||
|
||||
char *filespec_path (char *filespec)
|
||||
{
|
||||
char *cp = filespec + strlen (filespec);
|
||||
glob_t globs;
|
||||
struct stat fstats;
|
||||
|
||||
if (cp == filespec || filespec_wild (filespec))
|
||||
return NULL;
|
||||
|
||||
if (*--cp == '/')
|
||||
return filespec;
|
||||
|
||||
if (*cp == '.' && cp == filespec)
|
||||
return strcat (filespec, "/");
|
||||
|
||||
if (glob (filespec, GLOB_MARK|GLOB_NOSORT, NULL, &globs) == 0 &&
|
||||
globs.gl_pathc > 0)
|
||||
{
|
||||
/* test if the file is a directory */
|
||||
if (stat(globs.gl_pathv[0], &fstats) == 0 && (fstats.st_mode & S_IFDIR)) {
|
||||
filespec[0] = '\0';
|
||||
strcat (filespec, globs.gl_pathv[0]);
|
||||
globfree(&globs);
|
||||
return filespec;
|
||||
}
|
||||
}
|
||||
globfree(&globs);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
char *filespec_path (char *filespec)
|
||||
{
|
||||
char *cp = filespec + strlen (filespec);
|
||||
struct _wfinddata_t wfinddata;
|
||||
wchar_t *filespec_utf16;
|
||||
intptr_t file;
|
||||
|
||||
if (cp == filespec || filespec_wild (filespec))
|
||||
return NULL;
|
||||
|
||||
--cp;
|
||||
|
||||
if (*cp == '\\' || *cp == ':')
|
||||
return filespec;
|
||||
|
||||
if (*cp == '.' && cp == filespec)
|
||||
return strcat (filespec, "\\");
|
||||
|
||||
filespec_utf16 = utf8_to_utf16(filespec);
|
||||
|
||||
if (!filespec_utf16)
|
||||
return NULL;
|
||||
|
||||
if ((file = _wfindfirst (filespec_utf16, &wfinddata)) != (intptr_t) -1 &&
|
||||
(wfinddata.attrib & _A_SUBDIR)) {
|
||||
_findclose (file);
|
||||
free (filespec_utf16);
|
||||
return strcat (filespec, "\\");
|
||||
}
|
||||
|
||||
if (file != -1L)
|
||||
_findclose(file);
|
||||
|
||||
free (filespec_utf16);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// This function returns non-NULL if the specified filename spec has any //
|
||||
// wildcard characters. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
char *filespec_wild (char *filespec)
|
||||
{
|
||||
return strpbrk (filespec, "*?");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// This function parses a filename (with or without full path) and returns //
|
||||
// a pointer to the actual filename, or NULL if no filename can be found. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
char *filespec_name (char *filespec)
|
||||
{
|
||||
char *cp = filespec + strlen (filespec);
|
||||
|
||||
while (--cp >= filespec) {
|
||||
|
||||
if (*cp == '\\' || *cp == ':')
|
||||
break;
|
||||
}
|
||||
|
||||
if (strlen (cp + 1))
|
||||
return cp + 1;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
char *filespec_name (char *filespec)
|
||||
{
|
||||
char *cp = filespec + strlen (filespec);
|
||||
|
||||
while (--cp >= filespec)
|
||||
if (*cp == '/')
|
||||
break;
|
||||
|
||||
if (strlen (cp + 1))
|
||||
return cp + 1;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// This function allows the user to type 'y', 'n', or 'a' (with Enter) in //
|
||||
// response to a system query. The return value is the key typed as //
|
||||
// lowercase (regardless of the typed case). //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int waiting_input;
|
||||
|
||||
char yna (void)
|
||||
{
|
||||
char choice = 0;
|
||||
int key;
|
||||
|
||||
waiting_input = 1;
|
||||
|
||||
while (1) {
|
||||
#if defined(_WIN32)
|
||||
key = _getch ();
|
||||
#else
|
||||
key = fgetc(stdin);
|
||||
#endif
|
||||
if (key == 3) {
|
||||
fprintf (stderr, "^C\n");
|
||||
exit (1);
|
||||
}
|
||||
else if (key == EOF) {
|
||||
fprintf (stderr, "\r\n");
|
||||
exit (1);
|
||||
}
|
||||
else if (key == '\r' || key == '\n') {
|
||||
if (choice) {
|
||||
fprintf (stderr, "\r\n");
|
||||
fflush (stderr);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
fprintf (stderr, "%c", 7);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
else if (key == 'Y' || key == 'y') {
|
||||
#ifdef _WIN32
|
||||
fprintf (stderr, "%c\b", key);
|
||||
fflush (stderr);
|
||||
#endif
|
||||
choice = 'y';
|
||||
}
|
||||
else if (key == 'N' || key == 'n') {
|
||||
#ifdef _WIN32
|
||||
fprintf (stderr, "%c\b", key);
|
||||
fflush (stderr);
|
||||
#endif
|
||||
choice = 'n';
|
||||
}
|
||||
else if (key == 'A' || key == 'a') {
|
||||
#ifdef _WIN32
|
||||
fprintf (stderr, "%c\b", key);
|
||||
fflush (stderr);
|
||||
#endif
|
||||
choice = 'a';
|
||||
}
|
||||
else {
|
||||
fprintf (stderr, "%c", 7);
|
||||
fflush (stderr);
|
||||
}
|
||||
}
|
||||
|
||||
waiting_input = 0;
|
||||
|
||||
return choice;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Display the specified message on the console through stderr. Note that //
|
||||
// the cursor may start anywhere in the line and all text already on the //
|
||||
// line is erased. A terminating newline is not needed and function works //
|
||||
// with printf strings and args. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
extern int debug_logging_mode;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
int get_app_path (char *app_path)
|
||||
{
|
||||
static char file_path [MAX_PATH], tried, result;
|
||||
|
||||
HINSTANCE hinstLib;
|
||||
FARPROC ProcAdd;
|
||||
|
||||
if (tried) {
|
||||
if (result)
|
||||
strcpy (app_path, file_path);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
tried = TRUE;
|
||||
hinstLib = LoadLibrary ("shell32.dll");
|
||||
|
||||
if (hinstLib) {
|
||||
ProcAdd = GetProcAddress (hinstLib, "SHGetFolderPathA");
|
||||
|
||||
if (ProcAdd && SUCCEEDED ((ProcAdd) (NULL, CSIDL_APPDATA | 0x8000, NULL, 0, file_path)))
|
||||
result = TRUE;
|
||||
|
||||
if (!result) {
|
||||
ProcAdd = GetProcAddress (hinstLib, "SHGetSpecialFolderPathA");
|
||||
|
||||
if (ProcAdd && SUCCEEDED ((ProcAdd) (NULL, file_path, CSIDL_APPDATA, TRUE)))
|
||||
result = TRUE;
|
||||
}
|
||||
|
||||
FreeLibrary (hinstLib);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
hinstLib = LoadLibrary ("shfolder.dll");
|
||||
|
||||
if (hinstLib) {
|
||||
ProcAdd = GetProcAddress (hinstLib, "SHGetFolderPathA");
|
||||
|
||||
if (ProcAdd && SUCCEEDED ((ProcAdd) (NULL, CSIDL_APPDATA | 0x8000, NULL, 0, file_path)))
|
||||
result = TRUE;
|
||||
|
||||
FreeLibrary (hinstLib);
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
strcpy (app_path, file_path);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void error_line (char *error, ...)
|
||||
{
|
||||
char error_msg [512];
|
||||
va_list argptr;
|
||||
|
||||
error_msg [0] = '\r';
|
||||
va_start (argptr, error);
|
||||
vsprintf (error_msg + 1, error, argptr);
|
||||
va_end (argptr);
|
||||
fputs (error_msg, stderr);
|
||||
finish_line ();
|
||||
|
||||
if (debug_logging_mode) {
|
||||
char file_path [MAX_PATH];
|
||||
FILE *error_log = NULL;
|
||||
|
||||
if (get_app_path (file_path)) {
|
||||
strcat (file_path, "\\WavPack\\wavpack.log");
|
||||
error_log = fopen (file_path, "a+");
|
||||
|
||||
if (!error_log) {
|
||||
get_app_path (file_path);
|
||||
strcat (file_path, "\\WavPack");
|
||||
|
||||
if (CreateDirectory (file_path, NULL)) {
|
||||
strcat (file_path, "\\wavpack.log");
|
||||
error_log = fopen (file_path, "a+");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!error_log)
|
||||
error_log = fopen ("c:\\wavpack.log", "a+");
|
||||
|
||||
if (error_log) {
|
||||
fputs (error_msg + 1, error_log);
|
||||
fputc ('\n', error_log);
|
||||
fclose (error_log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void error_line (char *error, ...)
|
||||
{
|
||||
char error_msg [512];
|
||||
va_list argptr;
|
||||
|
||||
error_msg [0] = '\r';
|
||||
va_start (argptr, error);
|
||||
vsprintf (error_msg + 1, error, argptr);
|
||||
va_end (argptr);
|
||||
fputs (error_msg, stderr);
|
||||
finish_line ();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Function to intercept ^C or ^Break typed at the console. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#if defined(_WIN32)
|
||||
static int break_flag;
|
||||
|
||||
BOOL WINAPI ctrl_handler (DWORD ctrl)
|
||||
{
|
||||
if (ctrl == CTRL_C_EVENT) {
|
||||
break_flag = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (ctrl == CTRL_BREAK_EVENT) {
|
||||
|
||||
if (waiting_input) {
|
||||
return FALSE;
|
||||
}
|
||||
else {
|
||||
break_flag = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Function to initialize console for intercepting ^C and ^Break. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void setup_break (void)
|
||||
{
|
||||
HANDLE hConIn = GetStdHandle (STD_INPUT_HANDLE);
|
||||
|
||||
SetConsoleMode (hConIn, ENABLE_PROCESSED_INPUT);
|
||||
FlushConsoleInputBuffer (hConIn);
|
||||
SetConsoleCtrlHandler (ctrl_handler, TRUE);
|
||||
break_flag = 0;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Function to determine whether ^C or ^Break has been issued by user. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int check_break (void)
|
||||
{
|
||||
return break_flag;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Function to clear the stderr console to the end of the current line (and //
|
||||
// go to the beginning next line). //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void finish_line (void)
|
||||
{
|
||||
HANDLE hConIn = GetStdHandle (STD_ERROR_HANDLE);
|
||||
CONSOLE_SCREEN_BUFFER_INFO coninfo;
|
||||
|
||||
if (hConIn && GetConsoleScreenBufferInfo (hConIn, &coninfo) &&
|
||||
(coninfo.dwCursorPosition.X || coninfo.dwCursorPosition.Y)) {
|
||||
unsigned char spaces = coninfo.dwSize.X - coninfo.dwCursorPosition.X;
|
||||
|
||||
while (spaces--)
|
||||
fputc (' ', stderr);
|
||||
}
|
||||
else
|
||||
fprintf (stderr, " \n");
|
||||
|
||||
fflush (stderr);
|
||||
}
|
||||
#else
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Function to clear the stderr console to the end of the current line (and //
|
||||
// go to the beginning next line). //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void finish_line (void)
|
||||
{
|
||||
fprintf (stderr, " \n");
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Function to initialize console for intercepting ^C and ^Break. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
static int break_flag;
|
||||
|
||||
static void int_handler(int s)
|
||||
{
|
||||
break_flag = 1;
|
||||
}
|
||||
|
||||
void setup_break (void)
|
||||
{
|
||||
struct sigaction sigIntHandler;
|
||||
|
||||
break_flag = 0;
|
||||
sigIntHandler.sa_handler = int_handler;
|
||||
sigemptyset (&sigIntHandler.sa_mask);
|
||||
sigIntHandler.sa_flags = 0;
|
||||
sigaction (SIGINT, &sigIntHandler, NULL);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Function to determine whether ^C or ^Break has been issued by user. //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int check_break (void)
|
||||
{
|
||||
return break_flag;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//////////////////////////// File I/O Wrapper ////////////////////////////////
|
||||
|
||||
int DoReadFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead, uint32_t *lpNumberOfBytesRead)
|
||||
{
|
||||
uint32_t bcount;
|
||||
|
||||
*lpNumberOfBytesRead = 0;
|
||||
|
||||
while (nNumberOfBytesToRead) {
|
||||
bcount = (uint32_t) fread ((unsigned char *) lpBuffer + *lpNumberOfBytesRead, 1, nNumberOfBytesToRead, hFile);
|
||||
|
||||
if (bcount) {
|
||||
*lpNumberOfBytesRead += bcount;
|
||||
nNumberOfBytesToRead -= bcount;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return !ferror (hFile);
|
||||
}
|
||||
|
||||
int DoWriteFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToWrite, uint32_t *lpNumberOfBytesWritten)
|
||||
{
|
||||
uint32_t bcount;
|
||||
|
||||
*lpNumberOfBytesWritten = 0;
|
||||
|
||||
while (nNumberOfBytesToWrite) {
|
||||
bcount = (uint32_t) fwrite ((unsigned char *) lpBuffer + *lpNumberOfBytesWritten, 1, nNumberOfBytesToWrite, hFile);
|
||||
|
||||
if (bcount) {
|
||||
*lpNumberOfBytesWritten += bcount;
|
||||
nNumberOfBytesToWrite -= bcount;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return !ferror (hFile);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
int64_t DoGetFileSize (FILE *hFile)
|
||||
{
|
||||
LARGE_INTEGER Size;
|
||||
HANDLE fHandle;
|
||||
|
||||
if (hFile == NULL)
|
||||
return 0;
|
||||
|
||||
fHandle = (HANDLE)_get_osfhandle(_fileno(hFile));
|
||||
if (fHandle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
Size.u.LowPart = GetFileSize(fHandle, &Size.u.HighPart);
|
||||
|
||||
if (Size.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
|
||||
return 0;
|
||||
|
||||
return (int64_t)Size.QuadPart;
|
||||
}
|
||||
|
||||
int64_t DoGetFilePosition (FILE *hFile)
|
||||
{
|
||||
return _ftelli64 (hFile);
|
||||
}
|
||||
|
||||
int DoSetFilePositionAbsolute (FILE *hFile, int64_t pos)
|
||||
{
|
||||
return _fseeki64 (hFile, pos, SEEK_SET);
|
||||
}
|
||||
|
||||
int DoSetFilePositionRelative (FILE *hFile, int64_t pos, int mode)
|
||||
{
|
||||
return _fseeki64 (hFile, pos, mode);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int64_t DoGetFileSize (FILE *hFile)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (!hFile || fstat (fileno (hFile), &statbuf) || !S_ISREG(statbuf.st_mode))
|
||||
return 0;
|
||||
|
||||
return (int64_t) statbuf.st_size;
|
||||
}
|
||||
|
||||
int64_t DoGetFilePosition (FILE *hFile)
|
||||
{
|
||||
return ftell (hFile);
|
||||
}
|
||||
|
||||
int DoSetFilePositionAbsolute (FILE *hFile, int64_t pos)
|
||||
{
|
||||
return fseek (hFile, pos, SEEK_SET);
|
||||
}
|
||||
|
||||
int DoSetFilePositionRelative (FILE *hFile, int64_t pos, int mode)
|
||||
{
|
||||
return fseek (hFile, pos, mode);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// if ungetc() is not available, a seek of -1 is fine also because we do not
|
||||
// change the byte read.
|
||||
|
||||
int DoUngetc (int c, FILE *hFile)
|
||||
{
|
||||
return ungetc (c, hFile);
|
||||
}
|
||||
|
||||
int DoCloseHandle (FILE *hFile)
|
||||
{
|
||||
return hFile ? !fclose (hFile) : 0;
|
||||
}
|
||||
|
||||
int DoTruncateFile (FILE *hFile)
|
||||
{
|
||||
if (hFile) {
|
||||
fflush (hFile);
|
||||
#if defined(_WIN32)
|
||||
return !_chsize (_fileno (hFile), 0);
|
||||
#else
|
||||
return !ftruncate(fileno (hFile), 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DoDeleteFile (char *filename)
|
||||
{
|
||||
return filename ? !remove (filename) : 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Function to set the name of the console window. This is very handy for //
|
||||
// displaying progress of batch operations with the console window minimized. //
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
void DoSetConsoleTitle (char *text)
|
||||
{
|
||||
SetConsoleTitle (text);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void DoSetConsoleTitle (char *text)
|
||||
{
|
||||
fprintf (stderr, "\033]0;%s\007", text);
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2006 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// utils.h
|
||||
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#ifdef MAX_PATH
|
||||
#define PATH_MAX MAX_PATH
|
||||
#elif defined (MAXPATHLEN)
|
||||
#define PATH_MAX MAXPATHLEN
|
||||
#else
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#undef VERSION_OS
|
||||
#ifdef _WIN64
|
||||
#define VERSION_OS "Win64"
|
||||
#else
|
||||
#define VERSION_OS "Win32"
|
||||
#endif
|
||||
#define PACKAGE_VERSION "5.2.0"
|
||||
#endif
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
#define CLEAR(destin) memset (&destin, 0, sizeof (destin));
|
||||
|
||||
int copy_timestamp (const char *src_filename, const char *dst_filename);
|
||||
char *filespec_ext (char *filespec), *filespec_path (char *filespec);
|
||||
char *filespec_name (char *filespec), *filespec_wild (char *filespec);
|
||||
void error_line (char *error, ...);
|
||||
void setup_break (void), finish_line (void);
|
||||
int check_break (void);
|
||||
char yna (void);
|
||||
|
||||
int DoReadFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead, uint32_t *lpNumberOfBytesRead);
|
||||
int DoWriteFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToWrite, uint32_t *lpNumberOfBytesWritten);
|
||||
int64_t DoGetFileSize (FILE *hFile);
|
||||
int64_t DoGetFilePosition (FILE *hFile);
|
||||
int DoSetFilePositionAbsolute (FILE *hFile, int64_t pos);
|
||||
int DoSetFilePositionRelative (FILE *hFile, int64_t pos, int mode);
|
||||
int DoUngetc (int c, FILE *hFile);
|
||||
int DoCloseHandle (FILE *hFile);
|
||||
int DoTruncateFile (FILE *hFile);
|
||||
int DoDeleteFile (char *filename);
|
||||
void DoSetConsoleTitle (char *text);
|
||||
|
||||
#define FN_FIT(fn) ((strlen (fn) > 30) ? filespec_name (fn) : fn)
|
||||
|
||||
#endif
|
|
@ -1,707 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2019 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// wavpack_local.h
|
||||
|
||||
#ifndef WAVPACK_LOCAL_H
|
||||
#define WAVPACK_LOCAL_H
|
||||
|
||||
#include "wavpack.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define strdup(x) _strdup(x)
|
||||
#define FASTCALL __fastcall
|
||||
#else
|
||||
#define FASTCALL
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || \
|
||||
(defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN)) || \
|
||||
(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
|
||||
#define BITSTREAM_SHORTS // use 16-bit "shorts" for reading/writing bitstreams (instead of chars)
|
||||
// (only works on little-endian machines)
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
// This header file contains all the definitions required by WavPack.
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1600
|
||||
#include <stdlib.h>
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int8 int8_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
// Because the C99 specification states that "The order of allocation of
|
||||
// bit-fields within a unit (high-order to low-order or low-order to
|
||||
// high-order) is implementation-defined" (6.7.2.1), I decided to change
|
||||
// the representation of floating-point values from a structure of
|
||||
// bit-fields to a 32-bit integer with access macros. Note that the WavPack
|
||||
// library doesn't use any floating-point math to implement compression of
|
||||
// floating-point data (although a little floating-point math is used in
|
||||
// high-level functions unrelated to the codec).
|
||||
|
||||
typedef int32_t f32;
|
||||
|
||||
#define get_mantissa(f) ((f) & 0x7fffff)
|
||||
#define get_magnitude(f) ((f) & 0x7fffffff)
|
||||
#define get_exponent(f) (((f) >> 23) & 0xff)
|
||||
#define get_sign(f) (((f) >> 31) & 0x1)
|
||||
|
||||
#define set_mantissa(f,v) (f) ^= (((f) ^ (v)) & 0x7fffff)
|
||||
#define set_exponent(f,v) (f) ^= (((f) ^ ((v) << 23)) & 0x7f800000)
|
||||
#define set_sign(f,v) (f) ^= (((f) ^ ((v) << 31)) & 0x80000000)
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
// ID3v1 and APEv2 TAG formats (may occur at the end of WavPack files)
|
||||
|
||||
typedef struct {
|
||||
char tag_id [3], title [30], artist [30], album [30];
|
||||
char year [4], comment [30], genre;
|
||||
} ID3_Tag;
|
||||
|
||||
typedef struct {
|
||||
char ID [8];
|
||||
int32_t version, length, item_count, flags;
|
||||
char res [8];
|
||||
} APE_Tag_Hdr;
|
||||
|
||||
#define APE_Tag_Hdr_Format "8LLLL"
|
||||
|
||||
#define APE_TAG_TYPE_TEXT 0x0
|
||||
#define APE_TAG_TYPE_BINARY 0x1
|
||||
#define APE_TAG_THIS_IS_HEADER 0x20000000
|
||||
#define APE_TAG_CONTAINS_HEADER 0x80000000
|
||||
#define APE_TAG_MAX_LENGTH (1024 * 1024 * 16)
|
||||
|
||||
typedef struct {
|
||||
int64_t tag_file_pos;
|
||||
int tag_begins_file;
|
||||
ID3_Tag id3_tag;
|
||||
APE_Tag_Hdr ape_tag_hdr;
|
||||
unsigned char *ape_tag_data;
|
||||
} M_Tag;
|
||||
|
||||
// or-values for "flags"
|
||||
|
||||
#define CUR_STREAM_VERS 0x407 // universally compatible stream version
|
||||
|
||||
|
||||
//////////////////////////// WavPack Metadata /////////////////////////////////
|
||||
|
||||
// This is an internal representation of metadata.
|
||||
|
||||
typedef struct {
|
||||
int32_t byte_length;
|
||||
void *data;
|
||||
unsigned char id;
|
||||
} WavpackMetadata;
|
||||
|
||||
#define ID_UNIQUE 0x3f
|
||||
#define ID_OPTIONAL_DATA 0x20
|
||||
#define ID_ODD_SIZE 0x40
|
||||
#define ID_LARGE 0x80
|
||||
|
||||
#define ID_DUMMY 0x0
|
||||
#define ID_ENCODER_INFO 0x1
|
||||
#define ID_DECORR_TERMS 0x2
|
||||
#define ID_DECORR_WEIGHTS 0x3
|
||||
#define ID_DECORR_SAMPLES 0x4
|
||||
#define ID_ENTROPY_VARS 0x5
|
||||
#define ID_HYBRID_PROFILE 0x6
|
||||
#define ID_SHAPING_WEIGHTS 0x7
|
||||
#define ID_FLOAT_INFO 0x8
|
||||
#define ID_INT32_INFO 0x9
|
||||
#define ID_WV_BITSTREAM 0xa
|
||||
#define ID_WVC_BITSTREAM 0xb
|
||||
#define ID_WVX_BITSTREAM 0xc
|
||||
#define ID_CHANNEL_INFO 0xd
|
||||
#define ID_DSD_BLOCK 0xe
|
||||
|
||||
#define ID_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1)
|
||||
#define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2)
|
||||
#define ID_ALT_HEADER (ID_OPTIONAL_DATA | 0x3)
|
||||
#define ID_ALT_TRAILER (ID_OPTIONAL_DATA | 0x4)
|
||||
#define ID_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0x5)
|
||||
#define ID_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x6)
|
||||
#define ID_SAMPLE_RATE (ID_OPTIONAL_DATA | 0x7)
|
||||
#define ID_ALT_EXTENSION (ID_OPTIONAL_DATA | 0x8)
|
||||
#define ID_ALT_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x9)
|
||||
#define ID_NEW_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0xa)
|
||||
#define ID_CHANNEL_IDENTITIES (ID_OPTIONAL_DATA | 0xb)
|
||||
#define ID_BLOCK_CHECKSUM (ID_OPTIONAL_DATA | 0xf)
|
||||
|
||||
#define CONFIG_BYTES_STORED 3 // 1-4 bytes/sample
|
||||
#define CONFIG_MONO_FLAG 4 // not stereo
|
||||
#define CONFIG_FLOAT_DATA 0x80 // ieee 32-bit floating point data
|
||||
|
||||
#define CONFIG_AUTO_SHAPING 0x4000 // automatic noise shaping
|
||||
#define CONFIG_LOSSY_MODE 0x1000000 // obsolete (for information)
|
||||
|
||||
/*
|
||||
* These config flags were never actually used, or are no longer used, or are
|
||||
* used for something else now. They may be used in the future for what they
|
||||
* say, or for something else. WavPack files in the wild *may* have some of
|
||||
* these bit set in their config flags (with these older meanings), but only
|
||||
* if the stream version is 0x410 or less than 0x407. Of course, this is not
|
||||
* very important because once the file has been encoded, the config bits are
|
||||
* just for information purposes (i.e., they do not affect decoding),
|
||||
*
|
||||
#define CONFIG_ADOBE_MODE 0x100 // "adobe" mode for 32-bit floats
|
||||
#define CONFIG_VERY_FAST_FLAG 0x400 // double fast
|
||||
#define CONFIG_COPY_TIME 0x20000 // copy file-time from source
|
||||
#define CONFIG_QUALITY_MODE 0x200000 // psychoacoustic quality mode
|
||||
#define CONFIG_RAW_FLAG 0x400000 // raw mode (not implemented yet)
|
||||
#define CONFIG_QUIET_MODE 0x10000000 // don't report progress %
|
||||
#define CONFIG_IGNORE_LENGTH 0x20000000 // ignore length in wav header
|
||||
#define CONFIG_NEW_RIFF_HEADER 0x40000000 // generate new RIFF wav header
|
||||
*
|
||||
*/
|
||||
|
||||
#define EXTRA_SCAN_ONLY 1
|
||||
#define EXTRA_STEREO_MODES 2
|
||||
#define EXTRA_TRY_DELTAS 8
|
||||
#define EXTRA_ADJUST_DELTAS 16
|
||||
#define EXTRA_SORT_FIRST 32
|
||||
#define EXTRA_BRANCHES 0x1c0
|
||||
#define EXTRA_SKIP_8TO16 512
|
||||
#define EXTRA_TERMS 0x3c00
|
||||
#define EXTRA_DUMP_TERMS 16384
|
||||
#define EXTRA_SORT_LAST 32768
|
||||
|
||||
//////////////////////////////// WavPack Stream ///////////////////////////////
|
||||
|
||||
// This internal structure contains everything required to handle a WavPack
|
||||
// "stream", which is defined as a stereo or mono stream of audio samples. For
|
||||
// multichannel audio several of these would be required. Each stream contains
|
||||
// pointers to hold a complete allocated block of WavPack data, although it's
|
||||
// possible to decode WavPack blocks without buffering an entire block.
|
||||
|
||||
typedef struct bs {
|
||||
#ifdef BITSTREAM_SHORTS
|
||||
uint16_t *buf, *end, *ptr;
|
||||
#else
|
||||
unsigned char *buf, *end, *ptr;
|
||||
#endif
|
||||
void (*wrap)(struct bs *bs);
|
||||
int error, bc;
|
||||
uint32_t sr;
|
||||
} Bitstream;
|
||||
|
||||
#define MAX_WRAPPER_BYTES 16777216
|
||||
#define NEW_MAX_STREAMS 4096
|
||||
#define OLD_MAX_STREAMS 8
|
||||
#define MAX_NTERMS 16
|
||||
#define MAX_TERM 8
|
||||
|
||||
// DSD-specific definitions
|
||||
|
||||
#define MAX_HISTORY_BITS 5 // maximum number of history bits in DSD "fast" mode
|
||||
// note that 5 history bits requires 32 history bins
|
||||
#define MAX_BYTES_PER_BIN 1280 // maximum bytes for the value lookup array (per bin)
|
||||
// such that the total storage per bin = 2K (also
|
||||
// counting probabilities and summed_probabilities)
|
||||
|
||||
// Note that this structure is directly accessed in assembly files, so modify with care
|
||||
|
||||
struct decorr_pass {
|
||||
int32_t term, delta, weight_A, weight_B;
|
||||
int32_t samples_A [MAX_TERM], samples_B [MAX_TERM];
|
||||
int32_t aweight_A, aweight_B;
|
||||
int32_t sum_A, sum_B;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
signed char joint_stereo, delta, terms [MAX_NTERMS+1];
|
||||
} WavpackDecorrSpec;
|
||||
|
||||
struct entropy_data {
|
||||
uint32_t median [3], slow_level, error_limit;
|
||||
};
|
||||
|
||||
struct words_data {
|
||||
uint32_t bitrate_delta [2], bitrate_acc [2];
|
||||
uint32_t pend_data, holding_one, zeros_acc;
|
||||
int holding_zero, pend_count;
|
||||
struct entropy_data c [2];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int32_t value, filter0, filter1, filter2, filter3, filter4, filter5, filter6, factor, byte;
|
||||
} DSDfilters;
|
||||
|
||||
typedef struct {
|
||||
WavpackHeader wphdr;
|
||||
struct words_data w;
|
||||
|
||||
unsigned char *blockbuff, *blockend;
|
||||
unsigned char *block2buff, *block2end;
|
||||
int32_t *sample_buffer;
|
||||
|
||||
int64_t sample_index;
|
||||
int bits, num_terms, mute_error, joint_stereo, false_stereo, shift;
|
||||
int num_decorrs, num_passes, best_decorr, mask_decorr;
|
||||
uint32_t crc, crc_x, crc_wvx;
|
||||
Bitstream wvbits, wvcbits, wvxbits;
|
||||
int init_done, wvc_skip;
|
||||
float delta_decay;
|
||||
|
||||
unsigned char int32_sent_bits, int32_zeros, int32_ones, int32_dups;
|
||||
unsigned char float_flags, float_shift, float_max_exp, float_norm_exp;
|
||||
|
||||
struct {
|
||||
int32_t shaping_acc [2], shaping_delta [2], error [2];
|
||||
double noise_sum, noise_ave, noise_max;
|
||||
int16_t *shaping_data, *shaping_array;
|
||||
int32_t shaping_samples;
|
||||
} dc;
|
||||
|
||||
struct decorr_pass decorr_passes [MAX_NTERMS], analysis_pass;
|
||||
const WavpackDecorrSpec *decorr_specs;
|
||||
|
||||
struct {
|
||||
unsigned char *byteptr, *endptr, (*probabilities) [256], *lookup_buffer, **value_lookup, mode, ready;
|
||||
int history_bins, p0, p1;
|
||||
int16_t (*summed_probabilities) [256];
|
||||
uint32_t low, high, value;
|
||||
DSDfilters filters [2];
|
||||
int32_t *ptable;
|
||||
} dsd;
|
||||
|
||||
} WavpackStream;
|
||||
|
||||
// flags for float_flags:
|
||||
|
||||
#define FLOAT_SHIFT_ONES 1 // bits left-shifted into float = '1'
|
||||
#define FLOAT_SHIFT_SAME 2 // bits left-shifted into float are the same
|
||||
#define FLOAT_SHIFT_SENT 4 // bits shifted into float are sent literally
|
||||
#define FLOAT_ZEROS_SENT 8 // "zeros" are not all real zeros
|
||||
#define FLOAT_NEG_ZEROS 0x10 // contains negative zeros
|
||||
#define FLOAT_EXCEPTIONS 0x20 // contains exceptions (inf, nan, etc.)
|
||||
|
||||
/////////////////////////////// WavPack Context ///////////////////////////////
|
||||
|
||||
// This internal structure holds everything required to encode or decode WavPack
|
||||
// files. It is recommended that direct access to this structure be minimized
|
||||
// and the provided utilities used instead.
|
||||
|
||||
struct WavpackContext {
|
||||
WavpackConfig config;
|
||||
|
||||
WavpackMetadata *metadata;
|
||||
uint32_t metabytes;
|
||||
int metacount;
|
||||
|
||||
unsigned char *wrapper_data;
|
||||
uint32_t wrapper_bytes;
|
||||
|
||||
WavpackBlockOutput blockout;
|
||||
void *wv_out, *wvc_out;
|
||||
|
||||
WavpackStreamReader64 *reader;
|
||||
void *wv_in, *wvc_in;
|
||||
|
||||
int64_t filelen, file2len, filepos, file2pos, total_samples, initial_index;
|
||||
uint32_t crc_errors, first_flags;
|
||||
int wvc_flag, open_flags, norm_offset, reduced_channels, lossy_blocks, version_five;
|
||||
uint32_t block_samples, ave_block_samples, block_boundary, max_samples, acc_samples, riff_trailer_bytes;
|
||||
int riff_header_added, riff_header_created;
|
||||
M_Tag m_tag;
|
||||
|
||||
int current_stream, num_streams, max_streams, stream_version;
|
||||
WavpackStream **streams;
|
||||
void *stream3;
|
||||
|
||||
// these items were added in 5.0 to support alternate file types (especially CAF & DSD)
|
||||
unsigned char file_format, *channel_reordering, *channel_identities;
|
||||
uint32_t channel_layout, dsd_multiplier;
|
||||
void *decimation_context;
|
||||
char file_extension [8];
|
||||
|
||||
void (*close_callback)(void *wpc);
|
||||
char error_message [80];
|
||||
};
|
||||
|
||||
//////////////////////// function prototypes and macros //////////////////////
|
||||
|
||||
#define CLEAR(destin) memset (&destin, 0, sizeof (destin));
|
||||
|
||||
//////////////////////////////// decorrelation //////////////////////////////
|
||||
// modules: pack.c, unpack.c, unpack_floats.c, extra1.c, extra2.c
|
||||
|
||||
// #define SKIP_DECORRELATION // experimental switch to disable all decorrelation on encode
|
||||
|
||||
// These macros implement the weight application and update operations
|
||||
// that are at the heart of the decorrelation loops. Note that there are
|
||||
// sometimes two and even three versions of each macro. Theses should be
|
||||
// equivalent and produce identical results, but some may perform better
|
||||
// or worse on a given architecture.
|
||||
|
||||
#if 1 // PERFCOND - apply decorrelation weight when no 32-bit overflow possible
|
||||
#define apply_weight_i(weight, sample) ((weight * sample + 512) >> 10)
|
||||
#else
|
||||
#define apply_weight_i(weight, sample) ((((weight * sample) >> 8) + 2) >> 2)
|
||||
#endif
|
||||
|
||||
#if 1 // PERFCOND - apply decorrelation weight when 32-bit overflow is possible
|
||||
#define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \
|
||||
(((sample & ~0xffff) >> 9) * weight) + 1) >> 1)
|
||||
#elif 1
|
||||
#define apply_weight_f(weight, sample) ((int32_t)((weight * (int64_t) sample + 512) >> 10))
|
||||
#else
|
||||
#define apply_weight_f(weight, sample) ((int32_t)floor(((double) weight * sample + 512.0) / 1024.0))
|
||||
#endif
|
||||
|
||||
#if 1 // PERFCOND - universal version that checks input magnitude or always uses long version
|
||||
#define apply_weight(weight, sample) (sample != (int16_t) sample ? \
|
||||
apply_weight_f (weight, sample) : apply_weight_i (weight, sample))
|
||||
#else
|
||||
#define apply_weight(weight, sample) (apply_weight_f (weight, sample))
|
||||
#endif
|
||||
|
||||
#if 1 // PERFCOND
|
||||
#define update_weight(weight, delta, source, result) \
|
||||
if (source && result) { int32_t s = (int32_t) (source ^ result) >> 31; weight = (delta ^ s) + (weight - s); }
|
||||
#elif 1
|
||||
#define update_weight(weight, delta, source, result) \
|
||||
if (source && result) weight += (((source ^ result) >> 30) | 1) * delta;
|
||||
#else
|
||||
#define update_weight(weight, delta, source, result) \
|
||||
if (source && result) (source ^ result) < 0 ? (weight -= delta) : (weight += delta);
|
||||
#endif
|
||||
|
||||
#define update_weight_clip(weight, delta, source, result) \
|
||||
if (source && result) { \
|
||||
const int32_t s = (source ^ result) >> 31; \
|
||||
if ((weight = (weight ^ s) + (delta - s)) > 1024) weight = 1024; \
|
||||
weight = (weight ^ s) - s; \
|
||||
}
|
||||
|
||||
void pack_init (WavpackContext *wpc);
|
||||
int pack_block (WavpackContext *wpc, int32_t *buffer);
|
||||
void send_general_metadata (WavpackContext *wpc);
|
||||
void free_metadata (WavpackMetadata *wpmd);
|
||||
int copy_metadata (WavpackMetadata *wpmd, unsigned char *buffer_start, unsigned char *buffer_end);
|
||||
double WavpackGetEncodedNoise (WavpackContext *wpc, double *peak);
|
||||
int unpack_init (WavpackContext *wpc);
|
||||
int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count);
|
||||
int check_crc_error (WavpackContext *wpc);
|
||||
int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values);
|
||||
void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values);
|
||||
void float_values (WavpackStream *wps, int32_t *values, int32_t num_values);
|
||||
void dynamic_noise_shaping (WavpackContext *wpc, int32_t *buffer, int shortening_allowed);
|
||||
void execute_stereo (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples);
|
||||
void execute_mono (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples);
|
||||
|
||||
////////////////////////// DSD related (including decimation) //////////////////////////
|
||||
// modules: pack_dsd.c unpack_dsd.c
|
||||
|
||||
void pack_dsd_init (WavpackContext *wpc);
|
||||
int pack_dsd_block (WavpackContext *wpc, int32_t *buffer);
|
||||
int init_dsd_block (WavpackContext *wpc, WavpackMetadata *wpmd);
|
||||
int32_t unpack_dsd_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count);
|
||||
|
||||
void *decimate_dsd_init (int num_channels);
|
||||
void decimate_dsd_reset (void *decimate_context);
|
||||
void decimate_dsd_run (void *decimate_context, int32_t *samples, int num_samples);
|
||||
void decimate_dsd_destroy (void *decimate_context);
|
||||
|
||||
///////////////////////////////// CPU feature detection ////////////////////////////////
|
||||
|
||||
int unpack_cpu_has_feature_x86 (int findex), pack_cpu_has_feature_x86 (int findex);
|
||||
|
||||
#define CPU_FEATURE_MMX 23
|
||||
|
||||
///////////////////////////// pre-4.0 version decoding ////////////////////////////
|
||||
// modules: unpack3.c, unpack3_open.c, unpack3_seek.c
|
||||
|
||||
WavpackContext *open_file3 (WavpackContext *wpc, char *error);
|
||||
int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count);
|
||||
int seek_sample3 (WavpackContext *wpc, uint32_t desired_index);
|
||||
uint32_t get_sample_index3 (WavpackContext *wpc);
|
||||
void free_stream3 (WavpackContext *wpc);
|
||||
int get_version3 (WavpackContext *wpc);
|
||||
|
||||
////////////////////////////// bitstream macros & functions /////////////////////////////
|
||||
|
||||
#define bs_is_open(bs) ((bs)->ptr != NULL)
|
||||
uint32_t bs_close_read (Bitstream *bs);
|
||||
|
||||
#define getbit(bs) ( \
|
||||
(((bs)->bc) ? \
|
||||
((bs)->bc--, (bs)->sr & 1) : \
|
||||
(((++((bs)->ptr) != (bs)->end) ? (void) 0 : (bs)->wrap (bs)), (bs)->bc = sizeof (*((bs)->ptr)) * 8 - 1, ((bs)->sr = *((bs)->ptr)) & 1) \
|
||||
) ? \
|
||||
((bs)->sr >>= 1, 1) : \
|
||||
((bs)->sr >>= 1, 0) \
|
||||
)
|
||||
|
||||
#define getbits(value, nbits, bs) do { \
|
||||
while ((nbits) > (bs)->bc) { \
|
||||
if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \
|
||||
(bs)->sr |= (int32_t)*((bs)->ptr) << (bs)->bc; \
|
||||
(bs)->bc += sizeof (*((bs)->ptr)) * 8; \
|
||||
} \
|
||||
*(value) = (bs)->sr; \
|
||||
if ((bs)->bc > 32) { \
|
||||
(bs)->bc -= (nbits); \
|
||||
(bs)->sr = *((bs)->ptr) >> (sizeof (*((bs)->ptr)) * 8 - (bs)->bc); \
|
||||
} \
|
||||
else { \
|
||||
(bs)->bc -= (nbits); \
|
||||
(bs)->sr >>= (nbits); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define putbit(bit, bs) do { if (bit) (bs)->sr |= (1 << (bs)->bc); \
|
||||
if (++((bs)->bc) == sizeof (*((bs)->ptr)) * 8) { \
|
||||
*((bs)->ptr) = (bs)->sr; \
|
||||
(bs)->sr = (bs)->bc = 0; \
|
||||
if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \
|
||||
}} while (0)
|
||||
|
||||
#define putbit_0(bs) do { \
|
||||
if (++((bs)->bc) == sizeof (*((bs)->ptr)) * 8) { \
|
||||
*((bs)->ptr) = (bs)->sr; \
|
||||
(bs)->sr = (bs)->bc = 0; \
|
||||
if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \
|
||||
}} while (0)
|
||||
|
||||
#define putbit_1(bs) do { (bs)->sr |= (1 << (bs)->bc); \
|
||||
if (++((bs)->bc) == sizeof (*((bs)->ptr)) * 8) { \
|
||||
*((bs)->ptr) = (bs)->sr; \
|
||||
(bs)->sr = (bs)->bc = 0; \
|
||||
if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \
|
||||
}} while (0)
|
||||
|
||||
#define putbits(value, nbits, bs) do { \
|
||||
(bs)->sr |= (int32_t)(value) << (bs)->bc; \
|
||||
if (((bs)->bc += (nbits)) >= sizeof (*((bs)->ptr)) * 8) \
|
||||
do { \
|
||||
*((bs)->ptr) = (bs)->sr; \
|
||||
(bs)->sr >>= sizeof (*((bs)->ptr)) * 8; \
|
||||
if (((bs)->bc -= sizeof (*((bs)->ptr)) * 8) > 32 - sizeof (*((bs)->ptr)) * 8) \
|
||||
(bs)->sr |= ((value) >> ((nbits) - (bs)->bc)); \
|
||||
if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \
|
||||
} while ((bs)->bc >= sizeof (*((bs)->ptr)) * 8); \
|
||||
} while (0)
|
||||
|
||||
///////////////////////////// entropy encoder / decoder ////////////////////////////
|
||||
// modules: entropy_utils.c, read_words.c, write_words.c
|
||||
|
||||
// these control the time constant "slow_level" which is used for hybrid mode
|
||||
// that controls bitrate as a function of residual level (HYBRID_BITRATE).
|
||||
#define SLS 8
|
||||
#define SLO ((1 << (SLS - 1)))
|
||||
|
||||
#define LIMIT_ONES 16 // maximum consecutive 1s sent for "div" data
|
||||
|
||||
// these control the time constant of the 3 median level breakpoints
|
||||
#define DIV0 128 // 5/7 of samples
|
||||
#define DIV1 64 // 10/49 of samples
|
||||
#define DIV2 32 // 20/343 of samples
|
||||
|
||||
// this macro retrieves the specified median breakpoint (without frac; min = 1)
|
||||
#define GET_MED(med) (((c->median [med]) >> 4) + 1)
|
||||
|
||||
// These macros update the specified median breakpoints. Note that the median
|
||||
// is incremented when the sample is higher than the median, else decremented.
|
||||
// They are designed so that the median will never drop below 1 and the value
|
||||
// is essentially stationary if there are 2 increments for every 5 decrements.
|
||||
|
||||
#define INC_MED0() (c->median [0] += ((c->median [0] + DIV0) / DIV0) * 5)
|
||||
#define DEC_MED0() (c->median [0] -= ((c->median [0] + (DIV0-2)) / DIV0) * 2)
|
||||
#define INC_MED1() (c->median [1] += ((c->median [1] + DIV1) / DIV1) * 5)
|
||||
#define DEC_MED1() (c->median [1] -= ((c->median [1] + (DIV1-2)) / DIV1) * 2)
|
||||
#define INC_MED2() (c->median [2] += ((c->median [2] + DIV2) / DIV2) * 5)
|
||||
#define DEC_MED2() (c->median [2] -= ((c->median [2] + (DIV2-2)) / DIV2) * 2)
|
||||
|
||||
#ifdef HAVE___BUILTIN_CLZ
|
||||
#define count_bits(av) ((av) ? 32 - __builtin_clz (av) : 0)
|
||||
#elif defined (_WIN64)
|
||||
static __inline int count_bits (uint32_t av) { unsigned long res; return _BitScanReverse (&res, av) ? (int)(res + 1) : 0; }
|
||||
#else
|
||||
#define count_bits(av) ( \
|
||||
(av) < (1 << 8) ? nbits_table [av] : \
|
||||
( \
|
||||
(av) < (1L << 16) ? nbits_table [(av) >> 8] + 8 : \
|
||||
((av) < (1L << 24) ? nbits_table [(av) >> 16] + 16 : nbits_table [(av) >> 24] + 24) \
|
||||
) \
|
||||
)
|
||||
#endif
|
||||
|
||||
void init_words (WavpackStream *wps);
|
||||
void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
void write_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int32_t FASTCALL send_word (WavpackStream *wps, int32_t value, int chan);
|
||||
void send_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples);
|
||||
int32_t FASTCALL get_word (WavpackStream *wps, int chan, int32_t *correction);
|
||||
int32_t get_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples);
|
||||
void flush_word (WavpackStream *wps);
|
||||
int32_t nosend_word (WavpackStream *wps, int32_t value, int chan);
|
||||
void scan_word (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir);
|
||||
void update_error_limit (WavpackStream *wps);
|
||||
|
||||
extern const uint32_t bitset [32];
|
||||
extern const uint32_t bitmask [32];
|
||||
extern const char nbits_table [256];
|
||||
|
||||
int wp_log2s (int32_t value);
|
||||
int32_t wp_exp2s (int log);
|
||||
int FASTCALL wp_log2 (uint32_t avalue);
|
||||
|
||||
#ifdef OPT_ASM_X86
|
||||
#define LOG2BUFFER log2buffer_x86
|
||||
#elif defined(OPT_ASM_X64) && (defined (_WIN64) || defined(__CYGWIN__) || defined(__MINGW64__) || defined(__midipix__))
|
||||
#define LOG2BUFFER log2buffer_x64win
|
||||
#elif defined(OPT_ASM_X64)
|
||||
#define LOG2BUFFER log2buffer_x64
|
||||
#else
|
||||
#define LOG2BUFFER log2buffer
|
||||
#endif
|
||||
|
||||
uint32_t LOG2BUFFER (int32_t *samples, uint32_t num_samples, int limit);
|
||||
|
||||
signed char store_weight (int weight);
|
||||
int restore_weight (signed char weight);
|
||||
|
||||
#define WORD_EOF ((int32_t)(1L << 31))
|
||||
|
||||
void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp);
|
||||
|
||||
/////////////////////////// high-level unpacking API and support ////////////////////////////
|
||||
// modules: open_utils.c, unpack_utils.c, unpack_seek.c, unpack_floats.c
|
||||
|
||||
WavpackContext *WavpackOpenFileInputEx64 (WavpackStreamReader64 *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset);
|
||||
WavpackContext *WavpackOpenFileInputEx (WavpackStreamReader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset);
|
||||
WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset);
|
||||
|
||||
#define OPEN_WVC 0x1 // open/read "correction" file
|
||||
#define OPEN_TAGS 0x2 // read ID3v1 / APEv2 tags (seekable file)
|
||||
#define OPEN_WRAPPER 0x4 // make audio wrapper available (i.e. RIFF)
|
||||
#define OPEN_2CH_MAX 0x8 // open multichannel as stereo (no downmix)
|
||||
#define OPEN_NORMALIZE 0x10 // normalize floating point data to +/- 1.0
|
||||
#define OPEN_STREAMING 0x20 // "streaming" mode blindly unpacks blocks
|
||||
// w/o regard to header file position info
|
||||
#define OPEN_EDIT_TAGS 0x40 // allow editing of tags
|
||||
#define OPEN_FILE_UTF8 0x80 // assume filenames are UTF-8 encoded, not ANSI (Windows only)
|
||||
|
||||
// new for version 5
|
||||
|
||||
#define OPEN_DSD_NATIVE 0x100 // open DSD files as bitstreams
|
||||
// (returned as 8-bit "samples" stored in 32-bit words)
|
||||
#define OPEN_DSD_AS_PCM 0x200 // open DSD files as 24-bit PCM (decimated 8x)
|
||||
#define OPEN_ALT_TYPES 0x400 // application is aware of alternate file types & qmode
|
||||
// (just affects retrieving wrappers & MD5 checksums)
|
||||
#define OPEN_NO_CHECKSUM 0x800 // don't verify block checksums before decoding
|
||||
|
||||
int WavpackGetMode (WavpackContext *wpc);
|
||||
|
||||
int WavpackGetQualifyMode (WavpackContext *wpc);
|
||||
int WavpackGetVersion (WavpackContext *wpc);
|
||||
uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples);
|
||||
int WavpackSeekSample (WavpackContext *wpc, uint32_t sample);
|
||||
int WavpackSeekSample64 (WavpackContext *wpc, int64_t sample);
|
||||
int WavpackGetMD5Sum (WavpackContext *wpc, unsigned char data [16]);
|
||||
|
||||
int WavpackVerifySingleBlock (unsigned char *buffer, int verify_checksum);
|
||||
uint32_t read_next_header (WavpackStreamReader64 *reader, void *id, WavpackHeader *wphdr);
|
||||
int read_wvc_block (WavpackContext *wpc);
|
||||
|
||||
/////////////////////////// high-level packing API and support ////////////////////////////
|
||||
// modules: pack_utils.c, pack_floats.c
|
||||
|
||||
WavpackContext *WavpackOpenFileOutput (WavpackBlockOutput blockout, void *wv_id, void *wvc_id);
|
||||
int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples);
|
||||
int WavpackSetConfiguration64 (WavpackContext *wpc, WavpackConfig *config, int64_t total_samples, const unsigned char *chan_ids);
|
||||
int WavpackPackInit (WavpackContext *wpc);
|
||||
int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount);
|
||||
int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count);
|
||||
int WavpackFlushSamples (WavpackContext *wpc);
|
||||
int WavpackStoreMD5Sum (WavpackContext *wpc, unsigned char data [16]);
|
||||
void WavpackSeekTrailingWrapper (WavpackContext *wpc);
|
||||
void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block);
|
||||
void *WavpackGetWrapperLocation (void *first_block, uint32_t *size);
|
||||
|
||||
/////////////////////////////////// common utilities ////////////////////////////////////
|
||||
// module: common_utils.c
|
||||
|
||||
extern const uint32_t sample_rates [16];
|
||||
uint32_t WavpackGetLibraryVersion (void);
|
||||
const char *WavpackGetLibraryVersionString (void);
|
||||
uint32_t WavpackGetSampleRate (WavpackContext *wpc);
|
||||
int WavpackGetBitsPerSample (WavpackContext *wpc);
|
||||
int WavpackGetBytesPerSample (WavpackContext *wpc);
|
||||
int WavpackGetNumChannels (WavpackContext *wpc);
|
||||
int WavpackGetChannelMask (WavpackContext *wpc);
|
||||
int WavpackGetReducedChannels (WavpackContext *wpc);
|
||||
int WavpackGetFloatNormExp (WavpackContext *wpc);
|
||||
uint32_t WavpackGetNumSamples (WavpackContext *wpc);
|
||||
int64_t WavpackGetNumSamples64 (WavpackContext *wpc);
|
||||
uint32_t WavpackGetSampleIndex (WavpackContext *wpc);
|
||||
int64_t WavpackGetSampleIndex64 (WavpackContext *wpc);
|
||||
char *WavpackGetErrorMessage (WavpackContext *wpc);
|
||||
int WavpackGetNumErrors (WavpackContext *wpc);
|
||||
int WavpackLossyBlocks (WavpackContext *wpc);
|
||||
uint32_t WavpackGetWrapperBytes (WavpackContext *wpc);
|
||||
unsigned char *WavpackGetWrapperData (WavpackContext *wpc);
|
||||
void WavpackFreeWrapper (WavpackContext *wpc);
|
||||
double WavpackGetProgress (WavpackContext *wpc);
|
||||
uint32_t WavpackGetFileSize (WavpackContext *wpc);
|
||||
int64_t WavpackGetFileSize64 (WavpackContext *wpc);
|
||||
double WavpackGetRatio (WavpackContext *wpc);
|
||||
double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc);
|
||||
double WavpackGetInstantBitrate (WavpackContext *wpc);
|
||||
WavpackContext *WavpackCloseFile (WavpackContext *wpc);
|
||||
void WavpackLittleEndianToNative (void *data, char *format);
|
||||
void WavpackNativeToLittleEndian (void *data, char *format);
|
||||
void WavpackBigEndianToNative (void *data, char *format);
|
||||
void WavpackNativeToBigEndian (void *data, char *format);
|
||||
|
||||
void install_close_callback (WavpackContext *wpc, void cb_func (void *wpc));
|
||||
void free_dsd_tables (WavpackStream *wps);
|
||||
void free_streams (WavpackContext *wpc);
|
||||
|
||||
/////////////////////////////////// tag utilities ////////////////////////////////////
|
||||
// modules: tags.c, tag_utils.c
|
||||
|
||||
int WavpackGetNumTagItems (WavpackContext *wpc);
|
||||
int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size);
|
||||
int WavpackGetTagItemIndexed (WavpackContext *wpc, int index, char *item, int size);
|
||||
int WavpackGetNumBinaryTagItems (WavpackContext *wpc);
|
||||
int WavpackGetBinaryTagItem (WavpackContext *wpc, const char *item, char *value, int size);
|
||||
int WavpackGetBinaryTagItemIndexed (WavpackContext *wpc, int index, char *item, int size);
|
||||
int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize);
|
||||
int WavpackAppendBinaryTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize);
|
||||
int WavpackDeleteTagItem (WavpackContext *wpc, const char *item);
|
||||
int WavpackWriteTag (WavpackContext *wpc);
|
||||
int load_tag (WavpackContext *wpc);
|
||||
void free_tag (M_Tag *m_tag);
|
||||
int valid_tag (M_Tag *m_tag);
|
||||
int editable_tag (M_Tag *m_tag);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2019 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// wavpack_version.h
|
||||
|
||||
#ifndef WAVPACK_VERSION_H
|
||||
#define WAVPACK_VERSION_H
|
||||
|
||||
#define LIBWAVPACK_MAJOR 5
|
||||
#define LIBWAVPACK_MINOR 2
|
||||
#define LIBWAVPACK_MICRO 0
|
||||
#define LIBWAVPACK_VERSION_STRING "5.2.0"
|
||||
|
||||
#endif
|
|
@ -1,688 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// write_words.c
|
||||
|
||||
// This module provides entropy word encoding functions using
|
||||
// a variation on the Rice method. This was introduced in version 3.93
|
||||
// because it allows splitting the data into a "lossy" stream and a
|
||||
// "correction" stream in a very efficient manner and is therefore ideal
|
||||
// for the "hybrid" mode. For 4.0, the efficiency of this method was
|
||||
// significantly improved by moving away from the normal Rice restriction of
|
||||
// using powers of two for the modulus divisions and now the method can be
|
||||
// used for both hybrid and pure lossless encoding.
|
||||
|
||||
// Samples are divided by median probabilities at 5/7 (71.43%), 10/49 (20.41%),
|
||||
// and 20/343 (5.83%). Each zone has 3.5 times fewer samples than the
|
||||
// previous. Using standard Rice coding on this data would result in 1.4
|
||||
// bits per sample average (not counting sign bit). However, there is a
|
||||
// very simple encoding that is over 99% efficient with this data and
|
||||
// results in about 1.22 bits per sample.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// Initialize entropy encoder for the specified stream. In lossless mode there
|
||||
// are no parameters to select; in hybrid mode the bitrate mode and value need
|
||||
// be initialized.
|
||||
|
||||
static void word_set_bitrate (WavpackStream *wps);
|
||||
|
||||
void init_words (WavpackStream *wps)
|
||||
{
|
||||
CLEAR (wps->w);
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_FLAG)
|
||||
word_set_bitrate (wps);
|
||||
}
|
||||
|
||||
// Set up parameters for hybrid mode based on header flags and "bits" field.
|
||||
// This is currently only set up for the HYBRID_BITRATE mode in which the
|
||||
// allowed error varies with the residual level (from "slow_level"). The
|
||||
// simpler mode (which is not used yet) has the error level directly
|
||||
// controlled from the metadata.
|
||||
|
||||
static void word_set_bitrate (WavpackStream *wps)
|
||||
{
|
||||
int bitrate_0, bitrate_1;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
if (wps->wphdr.flags & FALSE_STEREO)
|
||||
bitrate_0 = (wps->bits * 2 - 512) < 568 ? 0 : (wps->bits * 2 - 512) - 568;
|
||||
else
|
||||
bitrate_0 = wps->bits < 568 ? 0 : wps->bits - 568;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BALANCE)
|
||||
bitrate_1 = (wps->wphdr.flags & JOINT_STEREO) ? 256 : 0;
|
||||
else {
|
||||
bitrate_1 = bitrate_0;
|
||||
|
||||
if (wps->wphdr.flags & JOINT_STEREO) {
|
||||
if (bitrate_0 < 128) {
|
||||
bitrate_1 += bitrate_0;
|
||||
bitrate_0 = 0;
|
||||
}
|
||||
else {
|
||||
bitrate_0 -= 128;
|
||||
bitrate_1 += 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
bitrate_1 = 0;
|
||||
}
|
||||
else
|
||||
bitrate_0 = bitrate_1 = 0;
|
||||
|
||||
wps->w.bitrate_acc [0] = (int32_t) bitrate_0 << 16;
|
||||
wps->w.bitrate_acc [1] = (int32_t) bitrate_1 << 16;
|
||||
}
|
||||
|
||||
// Allocates the correct space in the metadata structure and writes the
|
||||
// current median values to it. Values are converted from 32-bit unsigned
|
||||
// to our internal 16-bit wp_log2 values, and read_entropy_vars () is called
|
||||
// to read the values back because we must compensate for the loss through
|
||||
// the log function.
|
||||
|
||||
void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char *byteptr;
|
||||
int temp;
|
||||
|
||||
byteptr = wpmd->data = malloc (12);
|
||||
wpmd->id = ID_ENTROPY_VARS;
|
||||
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [0]);
|
||||
*byteptr++ = temp >> 8;
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [1]);
|
||||
*byteptr++ = temp >> 8;
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [2]);
|
||||
*byteptr++ = temp >> 8;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [0]);
|
||||
*byteptr++ = temp >> 8;
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [1]);
|
||||
*byteptr++ = temp >> 8;
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [2]);
|
||||
*byteptr++ = temp >> 8;
|
||||
}
|
||||
|
||||
wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data);
|
||||
read_entropy_vars (wps, wpmd);
|
||||
}
|
||||
|
||||
// Allocates enough space in the metadata structure and writes the current
|
||||
// high word of the bitrate accumulator and the slow_level values to it. The
|
||||
// slow_level values are converted from 32-bit unsigned to our internal 16-bit
|
||||
// wp_log2 values. Afterward, read_entropy_vars () is called to read the values
|
||||
// back because we must compensate for the loss through the log function and
|
||||
// the truncation of the bitrate.
|
||||
|
||||
void write_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char *byteptr;
|
||||
int temp;
|
||||
|
||||
word_set_bitrate (wps);
|
||||
byteptr = wpmd->data = malloc (512);
|
||||
wpmd->id = ID_HYBRID_PROFILE;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
*byteptr++ = temp = wp_log2s (wps->w.c [0].slow_level);
|
||||
*byteptr++ = temp >> 8;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
*byteptr++ = temp = wp_log2s (wps->w.c [1].slow_level);
|
||||
*byteptr++ = temp >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
*byteptr++ = temp = wps->w.bitrate_acc [0] >> 16;
|
||||
*byteptr++ = temp >> 8;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
*byteptr++ = temp = wps->w.bitrate_acc [1] >> 16;
|
||||
*byteptr++ = temp >> 8;
|
||||
}
|
||||
|
||||
if (wps->w.bitrate_delta [0] | wps->w.bitrate_delta [1]) {
|
||||
*byteptr++ = temp = wp_log2s (wps->w.bitrate_delta [0]);
|
||||
*byteptr++ = temp >> 8;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
*byteptr++ = temp = wp_log2s (wps->w.bitrate_delta [1]);
|
||||
*byteptr++ = temp >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data);
|
||||
read_hybrid_profile (wps, wpmd);
|
||||
}
|
||||
|
||||
// This function writes the specified word to the open bitstream "wvbits" and,
|
||||
// if the bitstream "wvcbits" is open, writes any correction data there. This
|
||||
// function will work for either lossless or hybrid but because a version
|
||||
// optimized for lossless exits below, it would normally be used for the hybrid
|
||||
// mode only. The return value is the actual value stored to the stream (even
|
||||
// if a correction file is being created) and is used as feedback to the
|
||||
// predictor.
|
||||
|
||||
int32_t FASTCALL send_word (WavpackStream *wps, int32_t value, int chan)
|
||||
{
|
||||
struct entropy_data *c = wps->w.c + chan;
|
||||
uint32_t ones_count, low, mid, high;
|
||||
int sign = (value < 0) ? 1 : 0;
|
||||
|
||||
if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) {
|
||||
if (wps->w.zeros_acc) {
|
||||
if (value)
|
||||
flush_word (wps);
|
||||
else {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
wps->w.zeros_acc++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (value)
|
||||
putbit_0 (&wps->wvbits);
|
||||
else {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
CLEAR (wps->w.c [0].median);
|
||||
CLEAR (wps->w.c [1].median);
|
||||
wps->w.zeros_acc = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (sign)
|
||||
value = ~value;
|
||||
|
||||
if ((wps->wphdr.flags & HYBRID_FLAG) && !chan)
|
||||
update_error_limit (wps);
|
||||
|
||||
if (value < (int32_t) GET_MED (0)) {
|
||||
ones_count = low = 0;
|
||||
high = GET_MED (0) - 1;
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (value - low < GET_MED (1)) {
|
||||
ones_count = 1;
|
||||
high = low + GET_MED (1) - 1;
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (value - low < GET_MED (2)) {
|
||||
ones_count = 2;
|
||||
high = low + GET_MED (2) - 1;
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
ones_count = 2 + (value - low) / GET_MED (2);
|
||||
low += (ones_count - 2) * GET_MED (2);
|
||||
high = low + GET_MED (2) - 1;
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mid = (high + low + 1) >> 1;
|
||||
|
||||
if (wps->w.holding_zero) {
|
||||
if (ones_count)
|
||||
wps->w.holding_one++;
|
||||
|
||||
flush_word (wps);
|
||||
|
||||
if (ones_count) {
|
||||
wps->w.holding_zero = 1;
|
||||
ones_count--;
|
||||
}
|
||||
else
|
||||
wps->w.holding_zero = 0;
|
||||
}
|
||||
else
|
||||
wps->w.holding_zero = 1;
|
||||
|
||||
wps->w.holding_one = ones_count * 2;
|
||||
|
||||
if (!c->error_limit) {
|
||||
if (high != low) {
|
||||
uint32_t maxcode = high - low, code = value - low;
|
||||
int bitcount = count_bits (maxcode);
|
||||
uint32_t extras = bitset [bitcount] - maxcode - 1;
|
||||
|
||||
if (code < extras) {
|
||||
wps->w.pend_data |= code << wps->w.pend_count;
|
||||
wps->w.pend_count += bitcount - 1;
|
||||
}
|
||||
else {
|
||||
wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count;
|
||||
wps->w.pend_count += bitcount - 1;
|
||||
wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++;
|
||||
}
|
||||
}
|
||||
|
||||
mid = value;
|
||||
}
|
||||
else
|
||||
while (high - low > c->error_limit)
|
||||
if (value < (int32_t) mid) {
|
||||
mid = ((high = mid - 1) + low + 1) >> 1;
|
||||
wps->w.pend_count++;
|
||||
}
|
||||
else {
|
||||
mid = (high + (low = mid) + 1) >> 1;
|
||||
wps->w.pend_data |= bitset [wps->w.pend_count++];
|
||||
}
|
||||
|
||||
wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++);
|
||||
|
||||
if (!wps->w.holding_zero)
|
||||
flush_word (wps);
|
||||
|
||||
if (bs_is_open (&wps->wvcbits) && c->error_limit) {
|
||||
uint32_t code = value - low, maxcode = high - low;
|
||||
int bitcount = count_bits (maxcode);
|
||||
uint32_t extras = bitset [bitcount] - maxcode - 1;
|
||||
|
||||
if (bitcount) {
|
||||
if (code < extras)
|
||||
putbits (code, bitcount - 1, &wps->wvcbits);
|
||||
else {
|
||||
putbits ((code + extras) >> 1, bitcount - 1, &wps->wvcbits);
|
||||
putbit ((code + extras) & 1, &wps->wvcbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
c->slow_level += wp_log2 (mid);
|
||||
}
|
||||
|
||||
return sign ? ~mid : mid;
|
||||
}
|
||||
|
||||
// This function is an optimized version of send_word() that only handles
|
||||
// lossless (error_limit == 0) and sends an entire buffer of either mono or
|
||||
// stereo data rather than a single sample. Unlike the generalized
|
||||
// send_word(), it does not return values because it always encodes
|
||||
// the exact value passed.
|
||||
|
||||
void send_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples)
|
||||
{
|
||||
struct entropy_data *c = wps->w.c;
|
||||
int32_t value, csamples;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
nsamples *= 2;
|
||||
|
||||
for (csamples = 0; csamples < nsamples; ++csamples) {
|
||||
int sign = ((value = *buffer++) < 0) ? 1 : 0;
|
||||
uint32_t ones_count, low, high;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
c = wps->w.c + (csamples & 1);
|
||||
|
||||
if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) {
|
||||
if (wps->w.zeros_acc) {
|
||||
if (value)
|
||||
flush_word (wps);
|
||||
else {
|
||||
wps->w.zeros_acc++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (value)
|
||||
putbit_0 (&wps->wvbits);
|
||||
else {
|
||||
CLEAR (wps->w.c [0].median);
|
||||
CLEAR (wps->w.c [1].median);
|
||||
wps->w.zeros_acc = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (sign)
|
||||
value = ~value;
|
||||
|
||||
if (value < (int32_t) GET_MED (0)) {
|
||||
ones_count = low = 0;
|
||||
high = GET_MED (0) - 1;
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (value - low < GET_MED (1)) {
|
||||
ones_count = 1;
|
||||
high = low + GET_MED (1) - 1;
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (value - low < GET_MED (2)) {
|
||||
ones_count = 2;
|
||||
high = low + GET_MED (2) - 1;
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
ones_count = 2 + (value - low) / GET_MED (2);
|
||||
low += (ones_count - 2) * GET_MED (2);
|
||||
high = low + GET_MED (2) - 1;
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wps->w.holding_zero) {
|
||||
if (ones_count)
|
||||
wps->w.holding_one++;
|
||||
|
||||
flush_word (wps);
|
||||
|
||||
if (ones_count) {
|
||||
wps->w.holding_zero = 1;
|
||||
ones_count--;
|
||||
}
|
||||
else
|
||||
wps->w.holding_zero = 0;
|
||||
}
|
||||
else
|
||||
wps->w.holding_zero = 1;
|
||||
|
||||
wps->w.holding_one = ones_count * 2;
|
||||
|
||||
if (high != low) {
|
||||
uint32_t maxcode = high - low, code = value - low;
|
||||
int bitcount = count_bits (maxcode);
|
||||
uint32_t extras = bitset [bitcount] - maxcode - 1;
|
||||
|
||||
if (code < extras) {
|
||||
wps->w.pend_data |= code << wps->w.pend_count;
|
||||
wps->w.pend_count += bitcount - 1;
|
||||
}
|
||||
else {
|
||||
wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count;
|
||||
wps->w.pend_count += bitcount - 1;
|
||||
wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++;
|
||||
}
|
||||
}
|
||||
|
||||
wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++);
|
||||
|
||||
if (!wps->w.holding_zero)
|
||||
flush_word (wps);
|
||||
}
|
||||
}
|
||||
|
||||
// Used by send_word() and send_word_lossless() to actually send most the
|
||||
// accumulated data onto the bitstream. This is also called directly from
|
||||
// clients when all words have been sent.
|
||||
|
||||
void flush_word (WavpackStream *wps)
|
||||
{
|
||||
if (wps->w.zeros_acc) {
|
||||
int cbits = count_bits (wps->w.zeros_acc);
|
||||
|
||||
while (cbits--)
|
||||
putbit_1 (&wps->wvbits);
|
||||
|
||||
putbit_0 (&wps->wvbits);
|
||||
|
||||
while (wps->w.zeros_acc > 1) {
|
||||
putbit (wps->w.zeros_acc & 1, &wps->wvbits);
|
||||
wps->w.zeros_acc >>= 1;
|
||||
}
|
||||
|
||||
wps->w.zeros_acc = 0;
|
||||
}
|
||||
|
||||
if (wps->w.holding_one) {
|
||||
#ifdef LIMIT_ONES
|
||||
if (wps->w.holding_one >= LIMIT_ONES) {
|
||||
int cbits;
|
||||
|
||||
putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, &wps->wvbits);
|
||||
wps->w.holding_one -= LIMIT_ONES;
|
||||
cbits = count_bits (wps->w.holding_one);
|
||||
|
||||
while (cbits--)
|
||||
putbit_1 (&wps->wvbits);
|
||||
|
||||
putbit_0 (&wps->wvbits);
|
||||
|
||||
while (wps->w.holding_one > 1) {
|
||||
putbit (wps->w.holding_one & 1, &wps->wvbits);
|
||||
wps->w.holding_one >>= 1;
|
||||
}
|
||||
|
||||
wps->w.holding_zero = 0;
|
||||
}
|
||||
else
|
||||
putbits (bitmask [wps->w.holding_one], wps->w.holding_one, &wps->wvbits);
|
||||
|
||||
wps->w.holding_one = 0;
|
||||
#else
|
||||
do {
|
||||
putbit_1 (&wps->wvbits);
|
||||
} while (--wps->w.holding_one);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (wps->w.holding_zero) {
|
||||
putbit_0 (&wps->wvbits);
|
||||
wps->w.holding_zero = 0;
|
||||
}
|
||||
|
||||
if (wps->w.pend_count) {
|
||||
putbits (wps->w.pend_data, wps->w.pend_count, &wps->wvbits);
|
||||
wps->w.pend_data = wps->w.pend_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This function is similar to send_word() except that no data is actually
|
||||
// written to any stream, but it does return the value that would have been
|
||||
// sent to a hybrid stream. It is used to determine beforehand how much noise
|
||||
// will be added to samples.
|
||||
|
||||
int32_t nosend_word (WavpackStream *wps, int32_t value, int chan)
|
||||
{
|
||||
struct entropy_data *c = wps->w.c + chan;
|
||||
uint32_t ones_count, low, mid, high;
|
||||
int sign = (value < 0) ? 1 : 0;
|
||||
|
||||
if (sign)
|
||||
value = ~value;
|
||||
|
||||
if ((wps->wphdr.flags & HYBRID_FLAG) && !chan)
|
||||
update_error_limit (wps);
|
||||
|
||||
if (value < (int32_t) GET_MED (0)) {
|
||||
low = 0;
|
||||
high = GET_MED (0) - 1;
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (value - low < GET_MED (1)) {
|
||||
high = low + GET_MED (1) - 1;
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (value - low < GET_MED (2)) {
|
||||
high = low + GET_MED (2) - 1;
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
ones_count = 2 + (value - low) / GET_MED (2);
|
||||
low += (ones_count - 2) * GET_MED (2);
|
||||
high = low + GET_MED (2) - 1;
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mid = (high + low + 1) >> 1;
|
||||
|
||||
if (!c->error_limit)
|
||||
mid = value;
|
||||
else
|
||||
while (high - low > c->error_limit)
|
||||
if (value < (int32_t) mid)
|
||||
mid = ((high = mid - 1) + low + 1) >> 1;
|
||||
else
|
||||
mid = (high + (low = mid) + 1) >> 1;
|
||||
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
c->slow_level += wp_log2 (mid);
|
||||
|
||||
return sign ? ~mid : mid;
|
||||
}
|
||||
|
||||
// This function is used to scan some number of samples to set the variables
|
||||
// "slow_level" and the "median" array. In pure symmetrical encoding mode this
|
||||
// would not be needed because these values would simply be continued from the
|
||||
// previous block. However, in the -X modes and the 32-bit modes we cannot do
|
||||
// this because parameters may change between blocks and the variables might
|
||||
// not apply. This function can work in mono or stereo and can scan a block
|
||||
// in either direction.
|
||||
|
||||
static void scan_word_pass (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir)
|
||||
{
|
||||
uint32_t flags = wps->wphdr.flags, value, low;
|
||||
struct entropy_data *c = wps->w.c;
|
||||
int chan;
|
||||
|
||||
if (flags & MONO_DATA) {
|
||||
if (dir < 0) {
|
||||
samples += (num_samples - 1);
|
||||
dir = -1;
|
||||
}
|
||||
else
|
||||
dir = 1;
|
||||
}
|
||||
else {
|
||||
if (dir < 0) {
|
||||
samples += (num_samples - 1) * 2;
|
||||
dir = -2;
|
||||
}
|
||||
else
|
||||
dir = 2;
|
||||
}
|
||||
|
||||
while (num_samples--) {
|
||||
|
||||
value = labs (samples [chan = 0]);
|
||||
|
||||
if (flags & HYBRID_BITRATE) {
|
||||
wps->w.c [0].slow_level -= (wps->w.c [0].slow_level + SLO) >> SLS;
|
||||
wps->w.c [0].slow_level += wp_log2 (value);
|
||||
}
|
||||
|
||||
if (value < GET_MED (0)) {
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (value - low < GET_MED (1)) {
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (value - low < GET_MED (2)) {
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & MONO_DATA)) {
|
||||
value = labs (samples [chan = 1]);
|
||||
c++;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
wps->w.c [1].slow_level -= (wps->w.c [1].slow_level + SLO) >> SLS;
|
||||
wps->w.c [1].slow_level += wp_log2 (value);
|
||||
}
|
||||
|
||||
if (value < GET_MED (0)) {
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (value - low < GET_MED (1)) {
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (value - low < GET_MED (2)) {
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c--;
|
||||
}
|
||||
|
||||
samples += dir;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper for scan_word_pass() than ensures that at least 2048 samples are processed by
|
||||
// potentially making multiple passes through the data. See description of scan_word_pass()
|
||||
// for more details.
|
||||
|
||||
void scan_word (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir)
|
||||
{
|
||||
init_words (wps);
|
||||
|
||||
if (num_samples) {
|
||||
int passes = (2048 + num_samples - 1) / num_samples; // i.e., ceil (2048.0 / num_samples)
|
||||
|
||||
while (passes--)
|
||||
scan_word_pass (wps, samples, num_samples, dir);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,554 +0,0 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
8310BA351D7377850055CEC5 /* common_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA281D7377850055CEC5 /* common_utils.c */; };
|
||||
8310BA361D7377850055CEC5 /* decorr_tables.h in Headers */ = {isa = PBXBuildFile; fileRef = 8310BA291D7377850055CEC5 /* decorr_tables.h */; };
|
||||
8310BA371D7377850055CEC5 /* decorr_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2A1D7377850055CEC5 /* decorr_utils.c */; };
|
||||
8310BA381D7377850055CEC5 /* entropy_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2B1D7377850055CEC5 /* entropy_utils.c */; };
|
||||
8310BA391D7377850055CEC5 /* open_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2C1D7377850055CEC5 /* open_utils.c */; };
|
||||
8310BA3A1D7377850055CEC5 /* read_words.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2D1D7377850055CEC5 /* read_words.c */; };
|
||||
8310BA3B1D7377850055CEC5 /* tag_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2E1D7377850055CEC5 /* tag_utils.c */; };
|
||||
8310BA3C1D7377850055CEC5 /* unpack_dsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2F1D7377850055CEC5 /* unpack_dsd.c */; };
|
||||
8310BA3D1D7377850055CEC5 /* unpack_floats.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA301D7377850055CEC5 /* unpack_floats.c */; };
|
||||
8310BA3E1D7377850055CEC5 /* unpack_seek.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA311D7377850055CEC5 /* unpack_seek.c */; };
|
||||
8310BA3F1D7377850055CEC5 /* unpack_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA321D7377850055CEC5 /* unpack_utils.c */; };
|
||||
8310BA401D7377850055CEC5 /* unpack3_open.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA331D7377850055CEC5 /* unpack3_open.c */; };
|
||||
8310BA411D7377850055CEC5 /* unpack3_seek.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA341D7377850055CEC5 /* unpack3_seek.c */; };
|
||||
8310BA431D7377B80055CEC5 /* write_words.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA421D7377B80055CEC5 /* write_words.c */; };
|
||||
8310BA4A1D7377DC0055CEC5 /* open_filename.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA441D7377DC0055CEC5 /* open_filename.c */; };
|
||||
8310BA4B1D7377DC0055CEC5 /* open_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA451D7377DC0055CEC5 /* open_legacy.c */; };
|
||||
8310BA4C1D7377DC0055CEC5 /* pack_dns.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA461D7377DC0055CEC5 /* pack_dns.c */; };
|
||||
8310BA4D1D7377DC0055CEC5 /* pack_dsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA471D7377DC0055CEC5 /* pack_dsd.c */; };
|
||||
8310BA4E1D7377DC0055CEC5 /* pack_floats.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA481D7377DC0055CEC5 /* pack_floats.c */; };
|
||||
8310BA4F1D7377DC0055CEC5 /* pack_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA491D7377DC0055CEC5 /* pack_utils.c */; };
|
||||
83DD1DD017FA038A00249519 /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DD1DCD17FA038A00249519 /* utils.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
83DD1DD117FA038A00249519 /* wavpack_local.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DD1DCE17FA038A00249519 /* wavpack_local.h */; };
|
||||
83DD1DD217FA038A00249519 /* wavpack_version.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DD1DCF17FA038A00249519 /* wavpack_version.h */; };
|
||||
83DD1DD417FA03F900249519 /* tags.c in Sources */ = {isa = PBXBuildFile; fileRef = 83DD1DD317FA03F900249519 /* tags.c */; };
|
||||
8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; };
|
||||
8E7574B309F31BB90080F1EE /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E7574AF09F31BB90080F1EE /* md5.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8E7574B409F31BB90080F1EE /* unpack3.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E7574B009F31BB90080F1EE /* unpack3.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8E7574B509F31BB90080F1EE /* wavpack.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E7574B109F31BB90080F1EE /* wavpack.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
8E7574C609F31BD50080F1EE /* extra1.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574B809F31BD50080F1EE /* extra1.c */; };
|
||||
8E7574C709F31BD50080F1EE /* extra2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574B909F31BD50080F1EE /* extra2.c */; };
|
||||
8E7574C909F31BD50080F1EE /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BB09F31BD50080F1EE /* md5.c */; };
|
||||
8E7574CB09F31BD50080F1EE /* pack.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BD09F31BD50080F1EE /* pack.c */; };
|
||||
8E7574CC09F31BD50080F1EE /* unpack.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BE09F31BD50080F1EE /* unpack.c */; };
|
||||
8E7574CD09F31BD50080F1EE /* unpack3.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BF09F31BD50080F1EE /* unpack3.c */; };
|
||||
8E7574CE09F31BD50080F1EE /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574C009F31BD50080F1EE /* utils.c */; };
|
||||
8E7574F509F31C7D0080F1EE /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E7574F409F31C7D0080F1EE /* libiconv.dylib */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
8310BA281D7377850055CEC5 /* common_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = common_utils.c; path = Files/common_utils.c; sourceTree = "<group>"; };
|
||||
8310BA291D7377850055CEC5 /* decorr_tables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = decorr_tables.h; path = Files/decorr_tables.h; sourceTree = "<group>"; };
|
||||
8310BA2A1D7377850055CEC5 /* decorr_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = decorr_utils.c; path = Files/decorr_utils.c; sourceTree = "<group>"; };
|
||||
8310BA2B1D7377850055CEC5 /* entropy_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = entropy_utils.c; path = Files/entropy_utils.c; sourceTree = "<group>"; };
|
||||
8310BA2C1D7377850055CEC5 /* open_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = open_utils.c; path = Files/open_utils.c; sourceTree = "<group>"; };
|
||||
8310BA2D1D7377850055CEC5 /* read_words.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = read_words.c; path = Files/read_words.c; sourceTree = "<group>"; };
|
||||
8310BA2E1D7377850055CEC5 /* tag_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tag_utils.c; path = Files/tag_utils.c; sourceTree = "<group>"; };
|
||||
8310BA2F1D7377850055CEC5 /* unpack_dsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_dsd.c; path = Files/unpack_dsd.c; sourceTree = "<group>"; };
|
||||
8310BA301D7377850055CEC5 /* unpack_floats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_floats.c; path = Files/unpack_floats.c; sourceTree = "<group>"; };
|
||||
8310BA311D7377850055CEC5 /* unpack_seek.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_seek.c; path = Files/unpack_seek.c; sourceTree = "<group>"; };
|
||||
8310BA321D7377850055CEC5 /* unpack_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_utils.c; path = Files/unpack_utils.c; sourceTree = "<group>"; };
|
||||
8310BA331D7377850055CEC5 /* unpack3_open.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack3_open.c; path = Files/unpack3_open.c; sourceTree = "<group>"; };
|
||||
8310BA341D7377850055CEC5 /* unpack3_seek.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack3_seek.c; path = Files/unpack3_seek.c; sourceTree = "<group>"; };
|
||||
8310BA421D7377B80055CEC5 /* write_words.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = write_words.c; path = Files/write_words.c; sourceTree = "<group>"; };
|
||||
8310BA441D7377DC0055CEC5 /* open_filename.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = open_filename.c; path = Files/open_filename.c; sourceTree = "<group>"; };
|
||||
8310BA451D7377DC0055CEC5 /* open_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = open_legacy.c; path = Files/open_legacy.c; sourceTree = "<group>"; };
|
||||
8310BA461D7377DC0055CEC5 /* pack_dns.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_dns.c; path = Files/pack_dns.c; sourceTree = "<group>"; };
|
||||
8310BA471D7377DC0055CEC5 /* pack_dsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_dsd.c; path = Files/pack_dsd.c; sourceTree = "<group>"; };
|
||||
8310BA481D7377DC0055CEC5 /* pack_floats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_floats.c; path = Files/pack_floats.c; sourceTree = "<group>"; };
|
||||
8310BA491D7377DC0055CEC5 /* pack_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_utils.c; path = Files/pack_utils.c; sourceTree = "<group>"; };
|
||||
833F683A1CDBCAB200AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
835C889B22CC188A001B4B3F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
83747BDC2862D5C50021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = "<group>"; };
|
||||
838EE8D329A8600D00CD0580 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
83DD1DCD17FA038A00249519 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = utils.h; path = Files/utils.h; sourceTree = "<group>"; };
|
||||
83DD1DCE17FA038A00249519 /* wavpack_local.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wavpack_local.h; path = Files/wavpack_local.h; sourceTree = "<group>"; };
|
||||
83DD1DCF17FA038A00249519 /* wavpack_version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wavpack_version.h; path = Files/wavpack_version.h; sourceTree = "<group>"; };
|
||||
83DD1DD317FA03F900249519 /* tags.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tags.c; path = Files/tags.c; sourceTree = "<group>"; };
|
||||
83F0E6CD287CAB4400D84594 /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
8DC2EF5B0486A6940098B216 /* WavPack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WavPack.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8E7574AF09F31BB90080F1EE /* md5.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = md5.h; path = Files/md5.h; sourceTree = "<group>"; };
|
||||
8E7574B009F31BB90080F1EE /* unpack3.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = unpack3.h; path = Files/unpack3.h; sourceTree = "<group>"; };
|
||||
8E7574B109F31BB90080F1EE /* wavpack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = wavpack.h; path = Files/wavpack.h; sourceTree = "<group>"; };
|
||||
8E7574B809F31BD50080F1EE /* extra1.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = extra1.c; path = Files/extra1.c; sourceTree = "<group>"; };
|
||||
8E7574B909F31BD50080F1EE /* extra2.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = extra2.c; path = Files/extra2.c; sourceTree = "<group>"; };
|
||||
8E7574BB09F31BD50080F1EE /* md5.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = md5.c; path = Files/md5.c; sourceTree = "<group>"; };
|
||||
8E7574BD09F31BD50080F1EE /* pack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = pack.c; path = Files/pack.c; sourceTree = "<group>"; };
|
||||
8E7574BE09F31BD50080F1EE /* unpack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = unpack.c; path = Files/unpack.c; sourceTree = "<group>"; };
|
||||
8E7574BF09F31BD50080F1EE /* unpack3.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = unpack3.c; path = Files/unpack3.c; sourceTree = "<group>"; };
|
||||
8E7574C009F31BD50080F1EE /* utils.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = utils.c; path = Files/utils.c; sourceTree = "<group>"; };
|
||||
8E7574F409F31C7D0080F1EE /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = /usr/lib/libiconv.dylib; sourceTree = "<absolute>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
8DC2EF560486A6940098B216 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8E7574F509F31C7D0080F1EE /* libiconv.dylib in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
034768DFFF38A50411DB9C8B /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8DC2EF5B0486A6940098B216 /* WavPack.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0867D691FE84028FC02AAC07 /* WavPack */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
83747BDB2862D5C50021245F /* Xcode-config */,
|
||||
8E7574A909F31B9A0080F1EE /* Headers */,
|
||||
8E7574A809F31B940080F1EE /* Source */,
|
||||
089C1665FE841158C02AAC07 /* Resources */,
|
||||
0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
|
||||
034768DFFF38A50411DB9C8B /* Products */,
|
||||
);
|
||||
name = WavPack;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */,
|
||||
1058C7B2FEA5585E11CA2CBB /* Other Frameworks */,
|
||||
);
|
||||
name = "External Frameworks and Libraries";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
089C1665FE841158C02AAC07 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8DC2EF5A0486A6940098B216 /* Info.plist */,
|
||||
089C1666FE841158C02AAC07 /* InfoPlist.strings */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8E7574F409F31C7D0080F1EE /* libiconv.dylib */,
|
||||
);
|
||||
name = "Linked Frameworks";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = "Other Frameworks";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
83747BDB2862D5C50021245F /* Xcode-config */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
83747BDC2862D5C50021245F /* Shared.xcconfig */,
|
||||
);
|
||||
name = "Xcode-config";
|
||||
path = "../../Xcode-config";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8E7574A809F31B940080F1EE /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8310BA441D7377DC0055CEC5 /* open_filename.c */,
|
||||
8310BA451D7377DC0055CEC5 /* open_legacy.c */,
|
||||
8310BA461D7377DC0055CEC5 /* pack_dns.c */,
|
||||
8310BA471D7377DC0055CEC5 /* pack_dsd.c */,
|
||||
8310BA481D7377DC0055CEC5 /* pack_floats.c */,
|
||||
8310BA491D7377DC0055CEC5 /* pack_utils.c */,
|
||||
8310BA421D7377B80055CEC5 /* write_words.c */,
|
||||
8310BA281D7377850055CEC5 /* common_utils.c */,
|
||||
8310BA2A1D7377850055CEC5 /* decorr_utils.c */,
|
||||
8310BA2B1D7377850055CEC5 /* entropy_utils.c */,
|
||||
8310BA2C1D7377850055CEC5 /* open_utils.c */,
|
||||
8310BA2D1D7377850055CEC5 /* read_words.c */,
|
||||
8310BA2E1D7377850055CEC5 /* tag_utils.c */,
|
||||
8310BA2F1D7377850055CEC5 /* unpack_dsd.c */,
|
||||
8310BA301D7377850055CEC5 /* unpack_floats.c */,
|
||||
8310BA311D7377850055CEC5 /* unpack_seek.c */,
|
||||
8310BA321D7377850055CEC5 /* unpack_utils.c */,
|
||||
8310BA331D7377850055CEC5 /* unpack3_open.c */,
|
||||
8310BA341D7377850055CEC5 /* unpack3_seek.c */,
|
||||
83DD1DD317FA03F900249519 /* tags.c */,
|
||||
8E7574B809F31BD50080F1EE /* extra1.c */,
|
||||
8E7574B909F31BD50080F1EE /* extra2.c */,
|
||||
8E7574BB09F31BD50080F1EE /* md5.c */,
|
||||
8E7574BD09F31BD50080F1EE /* pack.c */,
|
||||
8E7574BE09F31BD50080F1EE /* unpack.c */,
|
||||
8E7574BF09F31BD50080F1EE /* unpack3.c */,
|
||||
8E7574C009F31BD50080F1EE /* utils.c */,
|
||||
);
|
||||
name = Source;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
8E7574A909F31B9A0080F1EE /* Headers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8310BA291D7377850055CEC5 /* decorr_tables.h */,
|
||||
83DD1DCD17FA038A00249519 /* utils.h */,
|
||||
83DD1DCE17FA038A00249519 /* wavpack_local.h */,
|
||||
83DD1DCF17FA038A00249519 /* wavpack_version.h */,
|
||||
8E7574AF09F31BB90080F1EE /* md5.h */,
|
||||
8E7574B009F31BB90080F1EE /* unpack3.h */,
|
||||
8E7574B109F31BB90080F1EE /* wavpack.h */,
|
||||
);
|
||||
name = Headers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
8DC2EF500486A6940098B216 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8E7574B309F31BB90080F1EE /* md5.h in Headers */,
|
||||
83DD1DD117FA038A00249519 /* wavpack_local.h in Headers */,
|
||||
8E7574B409F31BB90080F1EE /* unpack3.h in Headers */,
|
||||
83DD1DD017FA038A00249519 /* utils.h in Headers */,
|
||||
83DD1DD217FA038A00249519 /* wavpack_version.h in Headers */,
|
||||
8310BA361D7377850055CEC5 /* decorr_tables.h in Headers */,
|
||||
8E7574B509F31BB90080F1EE /* wavpack.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
8DC2EF4F0486A6940098B216 /* WavPack Framework */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "WavPack Framework" */;
|
||||
buildPhases = (
|
||||
8DC2EF500486A6940098B216 /* Headers */,
|
||||
8DC2EF520486A6940098B216 /* Resources */,
|
||||
8DC2EF540486A6940098B216 /* Sources */,
|
||||
8DC2EF560486A6940098B216 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "WavPack Framework";
|
||||
productInstallPath = "$(HOME)/Library/Frameworks";
|
||||
productName = WavPack;
|
||||
productReference = 8DC2EF5B0486A6940098B216 /* WavPack.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
0867D690FE84028FC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1620;
|
||||
TargetAttributes = {
|
||||
8DC2EF4F0486A6940098B216 = {
|
||||
DevelopmentTeam = "";
|
||||
ProvisioningStyle = Manual;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "WavPack" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
en,
|
||||
es,
|
||||
Base,
|
||||
pl,
|
||||
tr,
|
||||
);
|
||||
mainGroup = 0867D691FE84028FC02AAC07 /* WavPack */;
|
||||
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
8DC2EF4F0486A6940098B216 /* WavPack Framework */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
8DC2EF520486A6940098B216 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
8DC2EF540486A6940098B216 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8310BA4A1D7377DC0055CEC5 /* open_filename.c in Sources */,
|
||||
8310BA4B1D7377DC0055CEC5 /* open_legacy.c in Sources */,
|
||||
8310BA4C1D7377DC0055CEC5 /* pack_dns.c in Sources */,
|
||||
8310BA4D1D7377DC0055CEC5 /* pack_dsd.c in Sources */,
|
||||
8310BA4E1D7377DC0055CEC5 /* pack_floats.c in Sources */,
|
||||
8310BA4F1D7377DC0055CEC5 /* pack_utils.c in Sources */,
|
||||
8310BA431D7377B80055CEC5 /* write_words.c in Sources */,
|
||||
8310BA351D7377850055CEC5 /* common_utils.c in Sources */,
|
||||
8310BA371D7377850055CEC5 /* decorr_utils.c in Sources */,
|
||||
8310BA381D7377850055CEC5 /* entropy_utils.c in Sources */,
|
||||
8310BA391D7377850055CEC5 /* open_utils.c in Sources */,
|
||||
8310BA3A1D7377850055CEC5 /* read_words.c in Sources */,
|
||||
8310BA3B1D7377850055CEC5 /* tag_utils.c in Sources */,
|
||||
8310BA3C1D7377850055CEC5 /* unpack_dsd.c in Sources */,
|
||||
8310BA3D1D7377850055CEC5 /* unpack_floats.c in Sources */,
|
||||
8310BA3E1D7377850055CEC5 /* unpack_seek.c in Sources */,
|
||||
8310BA3F1D7377850055CEC5 /* unpack_utils.c in Sources */,
|
||||
8310BA401D7377850055CEC5 /* unpack3_open.c in Sources */,
|
||||
8310BA411D7377850055CEC5 /* unpack3_seek.c in Sources */,
|
||||
83DD1DD417FA03F900249519 /* tags.c in Sources */,
|
||||
8E7574C609F31BD50080F1EE /* extra1.c in Sources */,
|
||||
8E7574C709F31BD50080F1EE /* extra2.c in Sources */,
|
||||
8E7574C909F31BD50080F1EE /* md5.c in Sources */,
|
||||
8E7574CB09F31BD50080F1EE /* pack.c in Sources */,
|
||||
8E7574CC09F31BD50080F1EE /* unpack.c in Sources */,
|
||||
8E7574CD09F31BD50080F1EE /* unpack3.c in Sources */,
|
||||
8E7574CE09F31BD50080F1EE /* utils.c in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
089C1666FE841158C02AAC07 /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
833F683A1CDBCAB200AFB9F0 /* es */,
|
||||
835C889B22CC188A001B4B3F /* en */,
|
||||
83F0E6CD287CAB4400D84594 /* pl */,
|
||||
838EE8D329A8600D00CD0580 /* tr */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
1DEB91AE08733DA50010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
FRAMEWORK_VERSION = A;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = NO;
|
||||
GCC_PREFIX_HEADER = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
ENABLE_DSD,
|
||||
ENABLE_LEGACY,
|
||||
PACK,
|
||||
UNPACK,
|
||||
USE_FSTREAMS,
|
||||
TAGS,
|
||||
SEEKING,
|
||||
VER3,
|
||||
"PACKAGE_NAME='\"wavpack\"'",
|
||||
"PACKAGE_TARNAME='\"wavpack\"'",
|
||||
"PACKAGE_VERSION='\"5.2.0\"'",
|
||||
"PACKAGE_STRING='\"wavpack 5.2.0\"'",
|
||||
"PACKAGE_BUGREPORT='\"bryant@wavpack.com\"'",
|
||||
"VERSION_OS='\"Darwin\"'",
|
||||
);
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "@loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.lib.wavpack;
|
||||
PRODUCT_NAME = WavPack;
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
WRAPPER_EXTENSION = framework;
|
||||
ZERO_LINK = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB91AF08733DA50010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
FRAMEWORK_VERSION = A;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = NO;
|
||||
GCC_PREFIX_HEADER = "";
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
ENABLE_DSD,
|
||||
ENABLE_LEGACY,
|
||||
PACK,
|
||||
UNPACK,
|
||||
USE_FSTREAMS,
|
||||
TAGS,
|
||||
SEEKING,
|
||||
VER3,
|
||||
"PACKAGE_NAME='\"wavpack\"'",
|
||||
"PACKAGE_TARNAME='\"wavpack\"'",
|
||||
"PACKAGE_VERSION='\"4.70.0\"'",
|
||||
"PACKAGE_STRING='\"wavpack 4.70.0\"'",
|
||||
"PACKAGE_BUGREPORT='\"bryant@wavpack.com\"'",
|
||||
"VERSION_OS='\"Darwin\"'",
|
||||
);
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "@loader_path/../Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.lib.wavpack;
|
||||
PRODUCT_NAME = WavPack;
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = YES;
|
||||
WRAPPER_EXTENSION = framework;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
1DEB91B208733DA50010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 83747BDC2862D5C50021245F /* Shared.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = "-Wframe-larger-than=4000";
|
||||
OTHER_CPLUSPLUSFLAGS = "-Wframe-larger-than=16000";
|
||||
SDKROOT = macosx;
|
||||
SYMROOT = ../../build;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB91B308733DA50010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 83747BDC2862D5C50021245F /* Shared.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.13;
|
||||
OTHER_CFLAGS = "-Wframe-larger-than=4000";
|
||||
OTHER_CPLUSPLUSFLAGS = "-Wframe-larger-than=16000";
|
||||
SDKROOT = macosx;
|
||||
SYMROOT = ../../build;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "WavPack Framework" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB91AE08733DA50010E9CD /* Debug */,
|
||||
1DEB91AF08733DA50010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "WavPack" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB91B208733DA50010E9CD /* Debug */,
|
||||
1DEB91B308733DA50010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
|
||||
BuildableName = "WavPack.framework"
|
||||
BlueprintName = "WavPack Framework"
|
||||
ReferencedContainer = "container:WavPack.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
|
||||
BuildableName = "WavPack.framework"
|
||||
BlueprintName = "WavPack Framework"
|
||||
ReferencedContainer = "container:WavPack.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "8DC2EF4F0486A6940098B216"
|
||||
BuildableName = "WavPack.framework"
|
||||
BlueprintName = "WavPack Framework"
|
||||
ReferencedContainer = "container:WavPack.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
Binary file not shown.
|
@ -1,3 +0,0 @@
|
|||
/* Localized versions of Info.plist keys */
|
||||
|
||||
NSHumanReadableCopyright = "© __MyCompanyName__, 2006";
|
Binary file not shown.
Binary file not shown.
|
@ -8,28 +8,10 @@
|
|||
|
||||
/* Begin PBXBuildFile section */
|
||||
1745C4DA0B90C42500A6768C /* WavPackDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 1745C4D60B90C42500A6768C /* WavPackDecoder.m */; };
|
||||
17F562D80C3BDA6C0019975C /* WavPack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17F562CA0C3BDA5A0019975C /* WavPack.framework */; };
|
||||
17F562DB0C3BDA6E0019975C /* WavPack.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 17F562CA0C3BDA5A0019975C /* WavPack.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
83E83F792D964AFE0054365C /* libwavpack.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 83E83F782D964AFE0054365C /* libwavpack.a */; };
|
||||
8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
17F562C90C3BDA5A0019975C /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 17F562C20C3BDA5A0019975C /* WavPack.xcodeproj */;
|
||||
proxyType = 2;
|
||||
remoteGlobalIDString = 8DC2EF5B0486A6940098B216;
|
||||
remoteInfo = WavPack;
|
||||
};
|
||||
17F562DC0C3BDA830019975C /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 17F562C20C3BDA5A0019975C /* WavPack.xcodeproj */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 8DC2EF4F0486A6940098B216;
|
||||
remoteInfo = WavPack;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
1745C4FE0B90C4CD00A6768C /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
|
@ -37,7 +19,6 @@
|
|||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
17F562DB0C3BDA6E0019975C /* WavPack.framework in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -50,11 +31,11 @@
|
|||
1745C4D50B90C42500A6768C /* WavPackDecoder.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WavPackDecoder.h; sourceTree = "<group>"; };
|
||||
1745C4D60B90C42500A6768C /* WavPackDecoder.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = WavPackDecoder.m; sourceTree = "<group>"; };
|
||||
177FCF940B90C9450011C3B5 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = Plugin.h; path = ../../Audio/Plugin.h; sourceTree = SOURCE_ROOT; };
|
||||
17F562C20C3BDA5A0019975C /* WavPack.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = WavPack.xcodeproj; path = ../../Frameworks/WavPack/WavPack.xcodeproj; sourceTree = SOURCE_ROOT; };
|
||||
32DBCF630370AF2F00C91783 /* WavPack_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WavPack_Prefix.pch; sourceTree = "<group>"; };
|
||||
834A42AA287AEFC300EB9D9B /* AudioChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AudioChunk.h; path = ../../Audio/Chain/AudioChunk.h; sourceTree = "<group>"; };
|
||||
83747BE62862D8D60021245F /* Shared.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Shared.xcconfig; sourceTree = "<group>"; };
|
||||
83849133180819EB00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
||||
83E83F782D964AFE0054365C /* libwavpack.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libwavpack.a; path = /Users/chris/Source/Repos/cog/ThirdParty/WavPack/lib/libwavpack.a; sourceTree = "<absolute>"; };
|
||||
8D5B49B6048680CD000E48DA /* WavPack.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WavPack.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
8D5B49B7048680CD000E48DA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D2F7E65807B2D6F200F64583 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
|
||||
|
@ -65,8 +46,8 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
17F562D80C3BDA6C0019975C /* WavPack.framework in Frameworks */,
|
||||
8D5B49B4048680CD000E48DA /* Cocoa.framework in Frameworks */,
|
||||
83E83F792D964AFE0054365C /* libwavpack.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -118,7 +99,7 @@
|
|||
1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
17F562C20C3BDA5A0019975C /* WavPack.xcodeproj */,
|
||||
83E83F782D964AFE0054365C /* libwavpack.a */,
|
||||
1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */,
|
||||
);
|
||||
name = "Linked Frameworks";
|
||||
|
@ -134,14 +115,6 @@
|
|||
name = "Other Frameworks";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
17F562C30C3BDA5A0019975C /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
17F562CA0C3BDA5A0019975C /* WavPack.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
19C28FB8FE9D52D311CA2CBB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -182,7 +155,6 @@
|
|||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
17F562DD0C3BDA830019975C /* PBXTargetDependency */,
|
||||
);
|
||||
name = "WavPack Plugin";
|
||||
productInstallPath = "$(HOME)/Library/Bundles";
|
||||
|
@ -215,12 +187,6 @@
|
|||
);
|
||||
mainGroup = 089C166AFE841209C02AAC07 /* WavPack */;
|
||||
projectDirPath = "";
|
||||
projectReferences = (
|
||||
{
|
||||
ProductGroup = 17F562C30C3BDA5A0019975C /* Products */;
|
||||
ProjectRef = 17F562C20C3BDA5A0019975C /* WavPack.xcodeproj */;
|
||||
},
|
||||
);
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
8D5B49AC048680CD000E48DA /* WavPack Plugin */,
|
||||
|
@ -228,16 +194,6 @@
|
|||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXReferenceProxy section */
|
||||
17F562CA0C3BDA5A0019975C /* WavPack.framework */ = {
|
||||
isa = PBXReferenceProxy;
|
||||
fileType = wrapper.framework;
|
||||
path = WavPack.framework;
|
||||
remoteRef = 17F562C90C3BDA5A0019975C /* PBXContainerItemProxy */;
|
||||
sourceTree = BUILT_PRODUCTS_DIR;
|
||||
};
|
||||
/* End PBXReferenceProxy section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
8D5B49AF048680CD000E48DA /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
|
@ -259,14 +215,6 @@
|
|||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
17F562DD0C3BDA830019975C /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
name = WavPack;
|
||||
targetProxy = 17F562DC0C3BDA830019975C /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
1DEB913B08733D840010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
|
@ -286,8 +234,10 @@
|
|||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = WavPack_Prefix.pch;
|
||||
HEADER_SEARCH_PATHS = ../../ThirdParty/WavPack/include;
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "$(HOME)/Library/Bundles";
|
||||
LIBRARY_SEARCH_PATHS = ../../ThirdParty/WavPack/lib;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.wavpack;
|
||||
PRODUCT_NAME = WavPack;
|
||||
SDKROOT = macosx;
|
||||
|
@ -312,8 +262,10 @@
|
|||
GCC_MODEL_TUNING = G5;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = WavPack_Prefix.pch;
|
||||
HEADER_SEARCH_PATHS = ../../ThirdParty/WavPack/include;
|
||||
INFOPLIST_FILE = Info.plist;
|
||||
INSTALL_PATH = "$(HOME)/Library/Bundles";
|
||||
LIBRARY_SEARCH_PATHS = ../../ThirdParty/WavPack/lib;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cogx.wavpack;
|
||||
PRODUCT_NAME = WavPack;
|
||||
SDKROOT = macosx;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#define ChunkHeader WavPackChunkHeader
|
||||
|
||||
#import <WavPack/wavpack.h>
|
||||
#import <wavpack.h>
|
||||
|
||||
@interface WavPackReader : NSObject {
|
||||
id<CogSource> source;
|
||||
|
@ -34,6 +34,9 @@
|
|||
int32_t *inputBuffer;
|
||||
size_t inputBufferSize;
|
||||
|
||||
uint8_t *outputBuffer;
|
||||
size_t outputBufferSize;
|
||||
|
||||
BOOL isDSD;
|
||||
BOOL isLossy;
|
||||
|
||||
|
|
|
@ -10,7 +10,31 @@
|
|||
|
||||
#import "Logging.h"
|
||||
|
||||
#import <sys/sysctl.h>
|
||||
|
||||
static int worker_threads;
|
||||
|
||||
int get_default_worker_threads (void)
|
||||
{
|
||||
int num_processors = 1;
|
||||
|
||||
size_t len = sizeof (num_processors);
|
||||
int mib[2] = { CTL_HW, HW_NCPU };
|
||||
sysctl (mib, 2, &num_processors, &len, NULL, 0);
|
||||
|
||||
if (num_processors <= 1)
|
||||
return 0;
|
||||
else if (num_processors > 4)
|
||||
return 4;
|
||||
else
|
||||
return num_processors;
|
||||
}
|
||||
|
||||
@implementation WavPackReader
|
||||
+ (void)initialize {
|
||||
worker_threads = get_default_worker_threads ();
|
||||
}
|
||||
|
||||
- (id)initWithSource:(id<CogSource>)s {
|
||||
self = [super init];
|
||||
if(self) {
|
||||
|
@ -137,6 +161,9 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) {
|
|||
if(![s seekable])
|
||||
open_flags |= OPEN_STREAMING;
|
||||
|
||||
if (worker_threads)
|
||||
open_flags |= worker_threads << OPEN_THREADS_SHFT;
|
||||
|
||||
wpc = WavpackOpenFileInputEx(&reader, (__bridge void *)(wv), (__bridge void *)(wvc), error, open_flags, 0);
|
||||
if(!wpc) {
|
||||
DLog(@"Unable to open file..");
|
||||
|
@ -199,6 +226,15 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) {
|
|||
*/
|
||||
- (AudioChunk *)readAudio {
|
||||
int32_t frames = 1024;
|
||||
if(worker_threads) {
|
||||
if(channels <= 2)
|
||||
frames = (worker_threads + 1) * 48000;
|
||||
else
|
||||
frames = 48000;
|
||||
|
||||
while(frames * channels > 8388608 / sizeof(int32_t))
|
||||
frames >>= 1;
|
||||
}
|
||||
|
||||
id audioChunkClass = NSClassFromString(@"AudioChunk");
|
||||
AudioChunk *chunk = [[audioChunkClass alloc] initWithProperties:[self properties]];
|
||||
|
@ -211,12 +247,22 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) {
|
|||
int32_t *alias32;
|
||||
|
||||
const size_t bufferSize = frames * [chunk format].mBytesPerFrame;
|
||||
uint8_t buffer[bufferSize];
|
||||
void *buf = (void *)buffer;
|
||||
void *buf = (void *)outputBuffer;
|
||||
if(!buf || outputBufferSize < bufferSize) {
|
||||
buf = realloc(outputBuffer, bufferSize);
|
||||
if(!buf) {
|
||||
return nil;
|
||||
}
|
||||
outputBuffer = (uint8_t *)buf;
|
||||
}
|
||||
|
||||
size_t newSize = frames * sizeof(int32_t) * channels;
|
||||
if(!inputBuffer || newSize > inputBufferSize) {
|
||||
inputBuffer = realloc(inputBuffer, inputBufferSize = newSize);
|
||||
void *inp = realloc(inputBuffer, inputBufferSize = newSize);
|
||||
if(!inp) {
|
||||
return nil;
|
||||
}
|
||||
inputBuffer = (int32_t *)inp;
|
||||
}
|
||||
|
||||
samplesRead = WavpackUnpackSamples(wpc, inputBuffer, frames);
|
||||
|
@ -263,7 +309,7 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) {
|
|||
frame += samplesRead;
|
||||
|
||||
[chunk setStreamTimestamp:streamTimestamp];
|
||||
[chunk assignSamples:buffer frameCount:samplesRead];
|
||||
[chunk assignSamples:outputBuffer frameCount:samplesRead];
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
@ -291,6 +337,11 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) {
|
|||
inputBuffer = NULL;
|
||||
inputBufferSize = 0;
|
||||
}
|
||||
if(outputBuffer) {
|
||||
free(outputBuffer);
|
||||
outputBuffer = NULL;
|
||||
outputBufferSize = 0;
|
||||
}
|
||||
wvc = nil;
|
||||
wv = nil;
|
||||
}
|
||||
|
|
8
ThirdParty/BASS/README.md
vendored
8
ThirdParty/BASS/README.md
vendored
|
@ -12,8 +12,8 @@ already use @rpath now.
|
|||
As of editing, they are:
|
||||
|
||||
BASS 2.4.17
|
||||
BASSMIDI 2.4.14.1
|
||||
BASSFLAC 2.4.5.3
|
||||
BASSOPUS 2.4.2.3
|
||||
BASSMIDI 2.4.15.3
|
||||
BASSFLAC 2.4.5.5
|
||||
BASSOPUS 2.4.3
|
||||
BASS_MPC 2.4.1.2
|
||||
BASSWV 2.4.7.3
|
||||
BASSWV 2.4.7.4
|
||||
|
|
22
ThirdParty/BASS/bassmidi.h
vendored
22
ThirdParty/BASS/bassmidi.h
vendored
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
BASSMIDI 2.4 C/C++ header file
|
||||
Copyright (c) 2006-2022 Un4seen Developments Ltd.
|
||||
Copyright (c) 2006-2024 Un4seen Developments Ltd.
|
||||
|
||||
See the BASSMIDI.CHM file for more detailed documentation
|
||||
*/
|
||||
|
@ -25,6 +25,8 @@ extern "C" {
|
|||
|
||||
#ifndef BASSMIDIDEF
|
||||
#define BASSMIDIDEF(f) WINAPI f
|
||||
#else
|
||||
#define NOBASSMIDIOVERLOADS
|
||||
#endif
|
||||
|
||||
typedef DWORD HSOUNDFONT; // soundfont handle
|
||||
|
@ -58,6 +60,7 @@ typedef DWORD HSOUNDFONT; // soundfont handle
|
|||
#define BASS_SYNC_MIDI_KEYSIG 0x10007
|
||||
|
||||
// Additional BASS_MIDI_StreamCreateFile/etc flags
|
||||
#define BASS_MIDI_NODRUMPARAMUSER 0x200
|
||||
#define BASS_MIDI_NODRUMPARAM 0x400
|
||||
#define BASS_MIDI_NOSYSRESET 0x800
|
||||
#define BASS_MIDI_DECAYEND 0x1000
|
||||
|
@ -76,8 +79,10 @@ typedef DWORD HSOUNDFONT; // soundfont handle
|
|||
#define BASS_MIDI_FONT_LINATTMOD 0x100000
|
||||
#define BASS_MIDI_FONT_LINDECVOL 0x200000
|
||||
#define BASS_MIDI_FONT_NORAMPIN 0x400000
|
||||
#define BASS_MIDI_FONT_NOLIMITS 0x800000
|
||||
#define BASS_MIDI_FONT_NOSBLIMITS 0x800000
|
||||
#define BASS_MIDI_FONT_NOLIMITS BASS_MIDI_FONT_NOSBLIMITS
|
||||
#define BASS_MIDI_FONT_MINFX 0x1000000
|
||||
#define BASS_MIDI_FONT_SBLIMITS 0x2000000
|
||||
|
||||
typedef struct {
|
||||
HSOUNDFONT font; // soundfont
|
||||
|
@ -136,6 +141,7 @@ typedef struct {
|
|||
#define BASS_MIDI_MARK_TRACK 7 // track name
|
||||
#define BASS_MIDI_MARK_INST 8 // instrument name
|
||||
#define BASS_MIDI_MARK_TRACKSTART 9 // track start (SMF2)
|
||||
#define BASS_MIDI_MARK_SEQSPEC 10 // sequencer-specific
|
||||
#define BASS_MIDI_MARK_TICK 0x10000 // flag: get position in ticks (otherwise bytes)
|
||||
|
||||
// MIDI events
|
||||
|
@ -278,6 +284,9 @@ typedef struct {
|
|||
#define BASS_ATTRIB_MIDI_SPEED 0x12008
|
||||
#define BASS_ATTRIB_MIDI_REVERB 0x12009
|
||||
#define BASS_ATTRIB_MIDI_VOL 0x1200a
|
||||
#define BASS_ATTRIB_MIDI_QUEUE_TICK 0x1200b
|
||||
#define BASS_ATTRIB_MIDI_QUEUE_BYTE 0x1200c
|
||||
#define BASS_ATTRIB_MIDI_QUEUE_ASYNC 0x1200d
|
||||
#define BASS_ATTRIB_MIDI_TRACK_VOL 0x12100 // + track #
|
||||
|
||||
// Additional tag type
|
||||
|
@ -369,6 +378,7 @@ BOOL BASSMIDIDEF(BASS_MIDI_InStop)(DWORD device);
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
#ifndef NOBASSMIDIOVERLOADS
|
||||
static inline BOOL BASS_MIDI_StreamSetFonts(HSTREAM handle, const BASS_MIDI_FONTEX *fonts, DWORD count)
|
||||
{
|
||||
return BASS_MIDI_StreamSetFonts(handle, (const void*)fonts, count | BASS_MIDI_FONT_EX);
|
||||
|
@ -389,6 +399,13 @@ static inline DWORD BASS_MIDI_StreamGetFonts(HSTREAM handle, BASS_MIDI_FONTEX2 *
|
|||
return BASS_MIDI_StreamGetFonts(handle, (void*)fonts, count | BASS_MIDI_FONT_EX2);
|
||||
}
|
||||
|
||||
#if __cplusplus >= 200707 || _MSC_VER >= 1600
|
||||
static inline DWORD BASS_MIDI_StreamGetFonts(HSTREAM handle, decltype(nullptr) fonts, DWORD count)
|
||||
{
|
||||
return BASS_MIDI_StreamGetFonts(handle, (void*)fonts, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
static inline HSTREAM BASS_MIDI_StreamCreateFile(BOOL mem, const WCHAR *file, QWORD offset, QWORD length, DWORD flags, DWORD freq)
|
||||
{
|
||||
|
@ -416,6 +433,7 @@ static inline BOOL BASS_MIDI_FontUnpack(HSOUNDFONT handle, const WCHAR *outfile,
|
|||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __OBJC__
|
||||
#undef BOOL
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2019 David Bryant. //
|
||||
// Copyright (c) 1998 - 2024 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -146,6 +146,15 @@ typedef struct {
|
|||
#define MIN_STREAM_VERS 0x402 // lowest stream version we'll decode
|
||||
#define MAX_STREAM_VERS 0x410 // highest stream version we'll decode or encode
|
||||
|
||||
#define WAVPACK_MAX_CHANS 4096 // max channels handled by WavPack format & library
|
||||
|
||||
// This sets the maximum number of channels that the current WavPack CLI applications
|
||||
// accept. It's somewhat arbitrary because the actual WavPack format and library can
|
||||
// handle up to 4096 channels. However, anything beyond 256 channels is obviously
|
||||
// a niche case and is not well tested, so this lower limit is defined for now.
|
||||
|
||||
#define WAVPACK_MAX_CLI_CHANS 256
|
||||
|
||||
// These are the mask bit definitions for the metadata chunk id byte (see format.txt)
|
||||
|
||||
#define ID_UNIQUE 0x3f
|
||||
|
@ -167,6 +176,7 @@ typedef struct {
|
|||
#define ID_WVC_BITSTREAM 0xb
|
||||
#define ID_WVX_BITSTREAM 0xc
|
||||
#define ID_CHANNEL_INFO 0xd
|
||||
#define ID_DSD_BLOCK 0xe
|
||||
|
||||
#define ID_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1)
|
||||
#define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2)
|
||||
|
@ -178,6 +188,8 @@ typedef struct {
|
|||
#define ID_ALT_EXTENSION (ID_OPTIONAL_DATA | 0x8)
|
||||
#define ID_ALT_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x9)
|
||||
#define ID_NEW_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0xa)
|
||||
#define ID_CHANNEL_IDENTITIES (ID_OPTIONAL_DATA | 0xb)
|
||||
#define ID_WVX_NEW_BITSTREAM (ID_OPTIONAL_DATA | ID_WVX_BITSTREAM)
|
||||
#define ID_BLOCK_CHECKSUM (ID_OPTIONAL_DATA | 0xf)
|
||||
|
||||
///////////////////////// WavPack Configuration ///////////////////////////////
|
||||
|
@ -190,7 +202,7 @@ typedef struct {
|
|||
float bitrate, shaping_weight;
|
||||
int bits_per_sample, bytes_per_sample;
|
||||
int qmode, flags, xmode, num_channels, float_norm_exp;
|
||||
int32_t block_samples, extra_flags, sample_rate, channel_mask;
|
||||
int32_t block_samples, worker_threads, sample_rate, channel_mask;
|
||||
unsigned char md5_checksum [16], md5_read;
|
||||
int num_tag_strings; // this field is not used
|
||||
char **tag_strings; // this field is not used
|
||||
|
@ -209,7 +221,7 @@ typedef struct {
|
|||
#define CONFIG_DYNAMIC_SHAPING 0x20000 // dynamic noise shaping
|
||||
#define CONFIG_CREATE_EXE 0x40000 // create executable
|
||||
#define CONFIG_CREATE_WVC 0x80000 // create correction file
|
||||
#define CONFIG_OPTIMIZE_WVC 0x100000 // maximize bybrid compression
|
||||
#define CONFIG_OPTIMIZE_WVC 0x100000 // maximize hybrid compression
|
||||
#define CONFIG_COMPATIBLE_WRITE 0x400000 // write files for decoders < 4.3
|
||||
#define CONFIG_CALC_NOISE 0x800000 // calc noise in hybrid mode
|
||||
#define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode
|
||||
|
@ -217,6 +229,7 @@ typedef struct {
|
|||
#define CONFIG_MD5_CHECKSUM 0x8000000 // store MD5 signature
|
||||
#define CONFIG_MERGE_BLOCKS 0x10000000 // merge blocks of equal redundancy (for lossyWAV)
|
||||
#define CONFIG_PAIR_UNDEF_CHANS 0x20000000 // encode undefined channels in stereo pairs
|
||||
#define CONFIG_OPTIMIZE_32BIT 0x40000000 // new optimizations for 32-bit integer files
|
||||
#define CONFIG_OPTIMIZE_MONO 0x80000000 // optimize for mono streams posing as stereo
|
||||
|
||||
// The lower 8 bits of qmode indicate the use of new features in version 5 that (presently)
|
||||
|
@ -244,6 +257,7 @@ typedef struct {
|
|||
#define QMODE_CHANS_UNASSIGNED 0x400 // user specified "..." in --channel-order option
|
||||
#define QMODE_IGNORE_LENGTH 0x800 // user specified to ignore length in file header
|
||||
#define QMODE_RAW_PCM 0x1000 // user specified raw PCM format (no header present)
|
||||
#define QMODE_EVEN_BYTE_DEPTH 0x2000 // user specified to force even byte bit-depth
|
||||
|
||||
////////////// Callbacks used for reading & writing WavPack streams //////////
|
||||
|
||||
|
@ -316,6 +330,11 @@ WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int f
|
|||
// (just affects retrieving wrappers & MD5 checksums)
|
||||
#define OPEN_NO_CHECKSUM 0x800 // don't verify block checksums before decoding
|
||||
|
||||
// new for multithreaded
|
||||
|
||||
#define OPEN_THREADS_SHFT 12 // specify number of additional worker threads here for
|
||||
#define OPEN_THREADS_MASK 0xF000 // decode; 0 to disable, otherwise 1-15 added threads
|
||||
|
||||
int WavpackGetMode (WavpackContext *wpc);
|
||||
|
||||
#define MODE_WVC 0x1
|
||||
|
@ -385,11 +404,12 @@ int WavpackWriteTag (WavpackContext *wpc);
|
|||
WavpackContext *WavpackOpenFileOutput (WavpackBlockOutput blockout, void *wv_id, void *wvc_id);
|
||||
void WavpackSetFileInformation (WavpackContext *wpc, char *file_extension, unsigned char file_format);
|
||||
|
||||
#define WP_FORMAT_WAV 0 // Microsoft RIFF, including BWF and RF64 varients
|
||||
#define WP_FORMAT_WAV 0 // Microsoft RIFF, including BWF and RF64 variants
|
||||
#define WP_FORMAT_W64 1 // Sony Wave64
|
||||
#define WP_FORMAT_CAF 2 // Apple CoreAudio
|
||||
#define WP_FORMAT_DFF 3 // Philips DSDIFF
|
||||
#define WP_FORMAT_DSF 4 // Sony DSD Format
|
||||
#define WP_FORMAT_AIF 5 // Apple AIFF
|
||||
|
||||
int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples);
|
||||
int WavpackSetConfiguration64 (WavpackContext *wpc, WavpackConfig *config, int64_t total_samples, const unsigned char *chan_ids);
|
BIN
ThirdParty/libraries-debug-overlay.tar.xz
vendored
BIN
ThirdParty/libraries-debug-overlay.tar.xz
vendored
Binary file not shown.
BIN
ThirdParty/libraries.tar.xz
vendored
BIN
ThirdParty/libraries.tar.xz
vendored
Binary file not shown.
Loading…
Reference in a new issue