diff --git a/Changelog b/Changelog index 8f6e06c5d..2920a3387 100644 --- a/Changelog +++ b/Changelog @@ -1,6 +1,7 @@ 0.05 alpha 4 ------------ Volume slider now gravitates to 100%, in the middle. +Fixes endian issues for intel? 0.05 alpha 3 ------------ diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index 57f7d1933..1528ace05 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -157,7 +157,7 @@ 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 32CA4F630368D1EE00C91783 /* Cog_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Cog_Prefix.pch; sourceTree = ""; }; 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - 8D1107320486CEB800E47090 /* Cog.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = Cog.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D1107320486CEB800E47090 /* Cog.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Cog.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8E75751309F31D130080F1EE /* French */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = French; path = French.lproj/MainMenu.nib; sourceTree = ""; }; 8E75751809F31D5A0080F1EE /* AppController.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = AppController.h; sourceTree = ""; }; 8E75751909F31D5A0080F1EE /* AppController.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = AppController.m; sourceTree = ""; }; diff --git a/English.lproj/MainMenu.nib/keyedobjects.nib b/English.lproj/MainMenu.nib/keyedobjects.nib index 89b915e94..bb01b2e3a 100644 Binary files a/English.lproj/MainMenu.nib/keyedobjects.nib and b/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/Libraries/WavPack/Files/ChangeLog b/Libraries/WavPack/Files/ChangeLog index 4daae17d1..a8e47ee05 100644 --- a/Libraries/WavPack/Files/ChangeLog +++ b/Libraries/WavPack/Files/ChangeLog @@ -1,3 +1,107 @@ + ---------------------- + Update - April 5, 2006 + ---------------------- + + WavPack Library Source Code - 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 --------------------------- diff --git a/Libraries/WavPack/Files/Makefile.am b/Libraries/WavPack/Files/Makefile.am index 820a49baa..fc1549260 100644 --- a/Libraries/WavPack/Files/Makefile.am +++ b/Libraries/WavPack/Files/Makefile.am @@ -1,27 +1,32 @@ -AUTOMAKE_OPTIONS = foreign -bin_PROGRAMS = wavpack wvunpack - -lib_LTLIBRARIES = libwavpack.la - -wpincludedir = $(prefix)/include/wavpack - -wpinclude_HEADERS = md5.h wavpack.h wputils.h unpack3.h - -libwavpack_la_SOURCES = bits.c float.c metadata.c unpack.c unpack3.c utils.c \ - wputils.c words.c md5.c extra1.c extra2.c pack.c \ - md5.h wavpack.h wputils.h unpack3.h -libwavpack_la_CFLAGS = -DPACK -DUNPACK -DUSE_FSTREAMS -DTAGS -DSEEKING -DVER3 -libwavpack_la_LDFLAGS = -lm @ICONV_LIBS@ - -wavpack_SOURCES = wavpack.c -wavpack_CFLAGS = -DPACK -wavpack_LDFLAGS = -lm -lcurses -wavpack_LDADD = libwavpack.la - -wvunpack_SOURCES = wvunpack.c -wvunpack_CFLAGS = -DUNPACK -DUSE_FSTREAMS -wvunpack_LDFLAGS = -lm -lcurses -wvunpack_LDADD = libwavpack.la - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = wavpack.pc +AUTOMAKE_OPTIONS = foreign +bin_PROGRAMS = wavpack wvunpack wvgain + +lib_LTLIBRARIES = libwavpack.la + +wpincludedir = $(prefix)/include/wavpack + +wpinclude_HEADERS = md5.h wavpack.h wputils.h unpack3.h + +libwavpack_la_SOURCES = bits.c float.c metadata.c unpack.c unpack3.c \ + wputils.c words.c md5.c extra1.c extra2.c pack.c \ + md5.h wavpack.h wputils.h unpack3.h +libwavpack_la_CFLAGS = -DPACK -DUNPACK -DUSE_FSTREAMS -DTAGS -DSEEKING -DVER3 +libwavpack_la_LDFLAGS = -lm @ICONV_LIBS@ + +wavpack_SOURCES = wavpack.c utils.c +wavpack_CFLAGS = -DPACK +wavpack_LDFLAGS = -lm +wavpack_LDADD = libwavpack.la + +wvunpack_SOURCES = wvunpack.c utils.c +wvunpack_CFLAGS = -DUNPACK -DUSE_FSTREAMS +wvunpack_LDFLAGS = -lm +wvunpack_LDADD = libwavpack.la + +wvgain_SOURCES = wvgain.c utils.c +wvgain_CFLAGS = -DUNPACK -DUSE_FSTREAMS +wvgain_LDFLAGS = -lm +wvgain_LDADD = libwavpack.la + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = wavpack.pc diff --git a/Libraries/WavPack/Files/README b/Libraries/WavPack/Files/README index df3507acd..9666000c0 100644 --- a/Libraries/WavPack/Files/README +++ b/Libraries/WavPack/Files/README @@ -13,10 +13,9 @@ of the plugin sources in the Windows source release. To build everything, type: -1. ./autogen.sh -2. ./configure -3. make -4. make install (optionally, to install into /usr/local/bin) +1. ./configure +2. make +3. make install (optionally, to install into /usr/local/bin) Notes: @@ -31,10 +30,10 @@ Notes: a "short" must be 16-bits an "int" must be at least 16-bits, but may be larger - a "char" must default to signed (Watcom users take note!) For version 4.2 references to "long" variables were eliminated to allow - compilation on 64-bit machines. + compilation on 64-bit machines. For version 4.3 "char" types may default + to signed or unsigned. 2. For WavPack file decoding, a library interface in "wputils.c" provides all the functionality required for both the winamp plugin and the "wvunpack" diff --git a/Libraries/WavPack/Files/bits.c b/Libraries/WavPack/Files/bits.c index d062d7cf1..0ad3d208b 100644 --- a/Libraries/WavPack/Files/bits.c +++ b/Libraries/WavPack/Files/bits.c @@ -1,259 +1,259 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// bits.c - -// This module provides utilities to support the BitStream structure which is -// used to read and write all WavPack audio data streams. It also contains a -// wrapper for the stream I/O functions and a set of functions dealing with -// endian-ness, both for enhancing portability. Finally, a debug wrapper for -// the malloc() system is provided. - -#include "wavpack.h" - -#include -#include -#include -#include - -#if defined(WIN32) -#include -#else -#include -#endif - -////////////////////////// Bitstream functions //////////////////////////////// - -#if defined(UNPACK) || defined(INFO_ONLY) - -// Open the specified BitStream and associate with the specified buffer. - -static void bs_read (Bitstream *bs); - -void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end) -{ - bs->error = bs->sr = bs->bc = 0; - bs->ptr = (bs->buf = buffer_start) - 1; - bs->end = buffer_end; - bs->wrap = bs_read; -} - -// This function is only called from the getbit() and getbits() macros when -// the BitStream has been exhausted and more data is required. Sinve these -// bistreams no longer access files, this function simple sets an error and -// resets the buffer. - -static void bs_read (Bitstream *bs) -{ - bs->ptr = bs->buf - 1; - bs->error = 1; -} - -// This function is called to close the bitstream. It returns the number of -// full bytes actually read as bits. - -uint32_t bs_close_read (Bitstream *bs) -{ - uint32_t bytes_read; - - if (bs->bc < 8) - bs->ptr++; - - if ((bs->buf - bs->ptr) & 1) - bs->ptr++; - - bytes_read = bs->ptr - bs->buf; - CLEAR (*bs); - return bytes_read; -} - -#endif - -#ifdef PACK - -// Open the specified BitStream using the specified buffer pointers. It is -// assumed that enough buffer space has been allocated for all data that will -// be written, otherwise an error will be generated. - -static void bs_write (Bitstream *bs); - -void bs_open_write (Bitstream *bs, uchar *buffer_start, uchar *buffer_end) -{ - bs->error = bs->sr = bs->bc = 0; - bs->ptr = bs->buf = buffer_start; - bs->end = buffer_end; - bs->wrap = bs_write; -} - -// This function is only called from the putbit() and putbits() macros when -// the buffer is full, which is now flagged as an error. - -static void bs_write (Bitstream *bs) -{ - bs->ptr = bs->buf; - bs->error = 1; -} - -// This function forces a flushing write of the specified BitStream, and -// returns the total number of bytes written into the buffer. - -uint32_t bs_close_write (Bitstream *bs) -{ - uint32_t bytes_written; - - if (bs->error) - return (uint32_t) -1; - - while (bs->bc || ((bs->ptr - bs->buf) & 1)) putbit_1 (bs); - bytes_written = bs->ptr - bs->buf; - CLEAR (*bs); - return bytes_written; -} - -#endif - -/////////////////////// Endian Correction Routines //////////////////////////// - -void little_endian_to_native (void *data, char *format) -{ - uchar *cp = (uchar *) data; - int32_t temp; - - while (*format) { - switch (*format) { - case 'L': - temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24); - * (int32_t *) cp = temp; - cp += 4; - break; - - case 'S': - temp = cp [0] + (cp [1] << 8); - * (short *) cp = (short) temp; - cp += 2; - break; - - default: - if (isdigit (*format)) - cp += *format - '0'; - - break; - } - - format++; - } -} - -void native_to_little_endian (void *data, char *format) -{ - uchar *cp = (uchar *) data; - int32_t temp; - - while (*format) { - switch (*format) { - case 'L': - temp = * (int32_t *) cp; - *cp++ = (uchar) temp; - *cp++ = (uchar) (temp >> 8); - *cp++ = (uchar) (temp >> 16); - *cp++ = (uchar) (temp >> 24); - break; - - case 'S': - temp = * (short *) cp; - *cp++ = (uchar) temp; - *cp++ = (uchar) (temp >> 8); - break; - - default: - if (isdigit (*format)) - cp += *format - '0'; - - break; - } - - format++; - } -} - -////////////////////////// Debug Wrapper for Malloc /////////////////////////// - -#ifdef DEBUG_ALLOC - -void *vptrs [512]; - -static void *add_ptr (void *ptr) -{ - int i; - - for (i = 0; i < 512; ++i) - if (!vptrs [i]) { - vptrs [i] = ptr; - break; - } - - if (i == 512) - error_line ("too many mallocs!"); - - return ptr; -} - -static void *del_ptr (void *ptr) -{ - int i; - - for (i = 0; i < 512; ++i) - if (vptrs [i] == ptr) { - vptrs [i] = NULL; - break; - } - - if (i == 512) - error_line ("free invalid ptr!"); - - return ptr; -} - -void *malloc_db (uint32_t size) -{ - if (size) - return add_ptr (malloc (size)); - else - return NULL; -} - -void free_db (void *ptr) -{ - if (ptr) - free (del_ptr (ptr)); -} - -void *realloc_db (void *ptr, uint32_t size) -{ - if (ptr && size) - return add_ptr (realloc (del_ptr (ptr), size)); - else if (size) - return malloc_db (size); - else - free_db (ptr); - - return NULL; -} - -int32_t dump_alloc (void) -{ - int i, j; - - for (j = i = 0; i < 512; ++i) - if (vptrs [i]) - j++; - - return j; -} - -#endif +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// bits.c + +// This module provides utilities to support the BitStream structure which is +// used to read and write all WavPack audio data streams. It also contains a +// wrapper for the stream I/O functions and a set of functions dealing with +// endian-ness, both for enhancing portability. Finally, a debug wrapper for +// the malloc() system is provided. + +#include "wavpack.h" + +#include +#include +#include +#include + +#if defined(WIN32) +#include +#else +#include +#endif + +////////////////////////// Bitstream functions //////////////////////////////// + +#if defined(UNPACK) || defined(INFO_ONLY) + +// Open the specified BitStream and associate with the specified buffer. + +static void bs_read (Bitstream *bs); + +void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end) +{ + bs->error = bs->sr = bs->bc = 0; + bs->ptr = (bs->buf = buffer_start) - 1; + bs->end = buffer_end; + bs->wrap = bs_read; +} + +// This function is only called from the getbit() and getbits() macros when +// the BitStream has been exhausted and more data is required. Sinve these +// bistreams no longer access files, this function simple sets an error and +// resets the buffer. + +static void bs_read (Bitstream *bs) +{ + bs->ptr = bs->buf - 1; + bs->error = 1; +} + +// This function is called to close the bitstream. It returns the number of +// full bytes actually read as bits. + +uint32_t bs_close_read (Bitstream *bs) +{ + uint32_t bytes_read; + + if (bs->bc < 8) + bs->ptr++; + + if ((bs->buf - bs->ptr) & 1) + bs->ptr++; + + bytes_read = bs->ptr - bs->buf; + CLEAR (*bs); + return bytes_read; +} + +#endif + +#ifdef PACK + +// Open the specified BitStream using the specified buffer pointers. It is +// assumed that enough buffer space has been allocated for all data that will +// be written, otherwise an error will be generated. + +static void bs_write (Bitstream *bs); + +void bs_open_write (Bitstream *bs, uchar *buffer_start, uchar *buffer_end) +{ + bs->error = bs->sr = bs->bc = 0; + bs->ptr = bs->buf = buffer_start; + bs->end = buffer_end; + bs->wrap = bs_write; +} + +// This function is only called from the putbit() and putbits() macros when +// the buffer is full, which is now flagged as an error. + +static void bs_write (Bitstream *bs) +{ + bs->ptr = bs->buf; + bs->error = 1; +} + +// This function forces a flushing write of the specified BitStream, and +// returns the total number of bytes written into the buffer. + +uint32_t bs_close_write (Bitstream *bs) +{ + uint32_t bytes_written; + + if (bs->error) + return (uint32_t) -1; + + while (bs->bc || ((bs->ptr - bs->buf) & 1)) putbit_1 (bs); + bytes_written = bs->ptr - bs->buf; + CLEAR (*bs); + return bytes_written; +} + +#endif + +/////////////////////// Endian Correction Routines //////////////////////////// + +void little_endian_to_native (void *data, char *format) +{ + uchar *cp = (uchar *) data; + int32_t temp; + + while (*format) { + switch (*format) { + case 'L': + temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24); + * (int32_t *) cp = temp; + cp += 4; + break; + + case 'S': + temp = cp [0] + (cp [1] << 8); + * (short *) cp = (short) temp; + cp += 2; + break; + + default: + if (isdigit (*format)) + cp += *format - '0'; + + break; + } + + format++; + } +} + +void native_to_little_endian (void *data, char *format) +{ + uchar *cp = (uchar *) data; + int32_t temp; + + while (*format) { + switch (*format) { + case 'L': + temp = * (int32_t *) cp; + *cp++ = (uchar) temp; + *cp++ = (uchar) (temp >> 8); + *cp++ = (uchar) (temp >> 16); + *cp++ = (uchar) (temp >> 24); + break; + + case 'S': + temp = * (short *) cp; + *cp++ = (uchar) temp; + *cp++ = (uchar) (temp >> 8); + break; + + default: + if (isdigit (*format)) + cp += *format - '0'; + + break; + } + + format++; + } +} + +////////////////////////// Debug Wrapper for Malloc /////////////////////////// + +#ifdef DEBUG_ALLOC + +void *vptrs [512]; + +static void *add_ptr (void *ptr) +{ + int i; + + for (i = 0; i < 512; ++i) + if (!vptrs [i]) { + vptrs [i] = ptr; + break; + } + + if (i == 512) + error_line ("too many mallocs!"); + + return ptr; +} + +static void *del_ptr (void *ptr) +{ + int i; + + for (i = 0; i < 512; ++i) + if (vptrs [i] == ptr) { + vptrs [i] = NULL; + break; + } + + if (i == 512) + error_line ("free invalid ptr!"); + + return ptr; +} + +void *malloc_db (uint32_t size) +{ + if (size) + return add_ptr (malloc (size)); + else + return NULL; +} + +void free_db (void *ptr) +{ + if (ptr) + free (del_ptr (ptr)); +} + +void *realloc_db (void *ptr, uint32_t size) +{ + if (ptr && size) + return add_ptr (realloc (del_ptr (ptr), size)); + else if (size) + return malloc_db (size); + else + free_db (ptr); + + return NULL; +} + +int32_t dump_alloc (void) +{ + int i, j; + + for (j = i = 0; i < 512; ++i) + if (vptrs [i]) + j++; + + return j; +} + +#endif diff --git a/Libraries/WavPack/Files/configure.ac b/Libraries/WavPack/Files/configure.ac index 441c9b2bd..71bdc891a 100644 --- a/Libraries/WavPack/Files/configure.ac +++ b/Libraries/WavPack/Files/configure.ac @@ -1,7 +1,7 @@ -# wavpack 4.2 configure.ac +# wavpack 4.32 configure.ac -AC_INIT(wavpack, 4.2, bryant@wavpack.com) -AM_INIT_AUTOMAKE(wavpack, 4.2, bryant@wavpack.com) +AC_INIT(wavpack, 4.32, bryant@wavpack.com) +AM_INIT_AUTOMAKE(wavpack, 4.32, bryant@wavpack.com) AC_CONFIG_SRCDIR([pack.c]) # Check for os version diff --git a/Libraries/WavPack/Files/extra1.c b/Libraries/WavPack/Files/extra1.c index 9c7064069..77a302859 100644 --- a/Libraries/WavPack/Files/extra1.c +++ b/Libraries/WavPack/Files/extra1.c @@ -1,563 +1,559 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 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 "wavpack.h" - -#include -#include -#include -#include - -// #define EXTRA_DUMP - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -#endif - -//////////////////////////////// local tables /////////////////////////////// - -extern const char default_terms [], high_terms [], fast_terms []; - -// #define MINMAX_WEIGHTS - -#ifdef MINMAX_WEIGHTS -static int32_t min_weight, max_weight; -static int min_term, max_term; -#endif - -static void decorr_mono_pass (int32_t *in_samples, int32_t *out_samples, uint32_t num_samples, struct decorr_pass *dpp, int dir) -{ - int m = 0; - - dpp->sum_A = 0; - -#ifdef MINMAX_WEIGHTS - dpp->min = dpp->max = 0; -#endif - - if (dir < 0) { - out_samples += (num_samples - 1); - in_samples += (num_samples - 1); - dir = -1; - } - else - dir = 1; - - 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; -#ifdef MINMAX_WEIGHTS - if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; - if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; -#endif - 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; -#ifdef MINMAX_WEIGHTS - if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; - if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; -#endif - out_samples [0] = left; - in_samples += dir; - out_samples += dir; - } - } - -#ifdef MINMAX_WEIGHTS - if (dpp->term != 0) { - if (dpp->max > max_weight) { max_weight = dpp->max; max_term = dpp->term; } - if (dpp->min < min_weight) { min_weight = dpp->min; min_term = dpp->term; } - } -#endif - - 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); - } - } -} - -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 delta = dpp->delta, pre_delta, term = dpp->term; - struct decorr_pass dp; - - 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; - reverse_mono_decorr (&dp); - memcpy (dpp->samples_A, dp.samples_A, sizeof (dp.samples_A)); - dpp->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, dpp->samples_A, sizeof (dp.samples_A)); - dpp->weight_A = dp.weight_A = dp.sum_A / num_samples; - } - -// if (memcmp (dpp, &dp, sizeof (dp))) -// error_line ("decorr_passes don't match, delta = %d", delta); - - decorr_mono_pass (samples, outsamples, num_samples, &dp, 1); -} - -static void recurse_mono (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], - int depth, int nterms, int delta, uint32_t input_bits, uint32_t *best_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 == nterms) - branches = 1; - - CLEAR (term_bits); - samples = sampleptrs [depth]; - outsamples = sampleptrs [depth + 1]; - - for (term = 1; term <= 18; ++term) { - if (term == 17 && branches == 1 && depth + 1 < nterms) - continue; - - if (term >= 9 && term <= 16) - if (term > MAX_TERM || !(wpc->config.flags & CONFIG_HIGH_FLAG) || (wpc->config.extra_flags & EXTRA_SKIP_8TO16)) - continue; - - if ((wpc->config.flags & CONFIG_FAST_FLAG) && (term >= 5 && term <= 16)) - continue; - - dps [depth].term = term; - dps [depth].delta = delta; - decorr_mono_buffer (samples, outsamples, wps->wphdr.block_samples, &dps [depth]); - bits = log2buffer (outsamples, wps->wphdr.block_samples); - - if (bits < *best_bits) { - *best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * (depth + 1)); - memcpy (sampleptrs [nterms + 1], sampleptrs [depth + 1], wps->wphdr.block_samples * 4); - } - - term_bits [term + 3] = bits; - } - - while (depth + 1 < 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; - - dps [depth].term = best_term; - dps [depth].delta = delta; - decorr_mono_buffer (samples, outsamples, wps->wphdr.block_samples, &dps [depth]); - -// if (log2buffer (outsamples, wps->wphdr.block_samples * 2) != local_best_bits) -// error_line ("data doesn't match!"); - - recurse_mono (wpc, sampleptrs, dps, depth + 1, nterms, delta, local_best_bits, best_bits); - } -} - -static void delta_mono (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], - int nterms, uint32_t *best_bits) -{ - 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 < nterms && wps->decorr_passes [i].term; ++i) { - dps [i].term = wps->decorr_passes [i].term; - dps [i].delta = d; - decorr_mono_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); - } - - bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); - - if (bits < *best_bits) { - lower = TRUE; - *best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 4); - } - else - break; - } - - for (d = delta + 1; !lower && d <= 7; ++d) { - int i; - - for (i = 0; i < nterms && wps->decorr_passes [i].term; ++i) { - dps [i].term = wps->decorr_passes [i].term; - dps [i].delta = d; - decorr_mono_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); - } - - bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); - - if (bits < *best_bits) { - *best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 4); - } - else - break; - } -} - -static void sort_mono (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], - int nterms, uint32_t *best_bits) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - int reversed = TRUE; - uint32_t bits; - - while (reversed) { - int ri, i; - - memcpy (dps, wps->decorr_passes, sizeof (wps->decorr_passes)); - reversed = FALSE; - - for (ri = 0; ri < nterms && wps->decorr_passes [ri].term; ++ri) { - - if (ri + 1 >= nterms || !wps->decorr_passes [ri+1].term) - break; - - if (wps->decorr_passes [ri].term == wps->decorr_passes [ri+1].term) { - decorr_mono_buffer (sampleptrs [ri], sampleptrs [ri+1], wps->wphdr.block_samples, &dps [ri]); - continue; - } - - dps [ri] = wps->decorr_passes [ri+1]; - dps [ri+1] = wps->decorr_passes [ri]; - - for (i = ri; i < nterms && wps->decorr_passes [i].term; ++i) - decorr_mono_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); - - bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); - - if (bits < *best_bits) { - reversed = TRUE; - *best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 4); - } - else { - dps [ri] = wps->decorr_passes [ri]; - dps [ri+1] = wps->decorr_passes [ri+1]; - decorr_mono_buffer (sampleptrs [ri], sampleptrs [ri+1], wps->wphdr.block_samples, &dps [ri]); - } - } - } -} - -#define EXTRA_ADVANCED (EXTRA_BRANCHES | EXTRA_SORT_FIRST | EXTRA_SORT_LAST | EXTRA_TRY_DELTAS) - -void analyze_mono (WavpackContext *wpc, int32_t *samples) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; -#ifdef EXTRA_DUMP - uint32_t bits, best_bits, default_bits, cnt; -#else - uint32_t bits, best_bits, cnt; -#endif - const char *decorr_terms = default_terms, *tp; - int32_t *sampleptrs [MAX_NTERMS+2], *lptr; - struct decorr_pass dps [MAX_NTERMS]; - int nterms, i; - - CLEAR (wps->decorr_passes); - cnt = wps->wphdr.block_samples; - lptr = samples; - - while (cnt--) - if (*lptr++) - break; - - if (cnt == (uint32_t) -1) { - scan_word (wps, samples, wps->wphdr.block_samples, -1); - wps->num_terms = 0; - return; - } - - if (wpc->config.flags & CONFIG_HIGH_FLAG) - decorr_terms = high_terms; - else if (wpc->config.flags & CONFIG_FAST_FLAG) - decorr_terms = fast_terms; - - for (nterms = 0, tp = decorr_terms; *tp; tp++) - if (*tp > 0) - ++nterms; - - if (wpc->config.extra_flags & EXTRA_TERMS) - if ((nterms += (wpc->config.extra_flags & EXTRA_TERMS) >> 10) > MAX_NTERMS) - nterms = MAX_NTERMS; - - for (i = 0; i < nterms + 2; ++i) - sampleptrs [i] = malloc (wps->wphdr.block_samples * 4); - - memcpy (sampleptrs [nterms + 1], samples, wps->wphdr.block_samples * 4); - best_bits = log2buffer (sampleptrs [nterms + 1], wps->wphdr.block_samples); - memcpy (sampleptrs [0], samples, wps->wphdr.block_samples * 4); - CLEAR (dps); - - for (tp = decorr_terms, i = 0; *tp; tp++) - if (*tp > 0) { - dps [i].term = *tp; - dps [i].delta = 2; - decorr_mono_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); - ++i; - } - -#ifdef EXTRA_DUMP - default_bits = bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); -#else - bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); -#endif - - if (bits < best_bits) { - best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 4); - } - - if ((wps->wphdr.flags & HYBRID_FLAG) && (wpc->config.extra_flags & EXTRA_ADVANCED)) { - int shaping_weight, new = wps->wphdr.flags & NEW_SHAPING; - int32_t *rptr = sampleptrs [nterms + 1], error = 0, temp; - - scan_word (wps, rptr, wps->wphdr.block_samples, -1); - cnt = wps->wphdr.block_samples; - lptr = sampleptrs [0]; - - if (wps->wphdr.flags & HYBRID_SHAPE) { - while (cnt--) { - 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++; - } - - 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++; - } - - memcpy (dps, wps->decorr_passes, sizeof (dps)); - - for (i = 0; i < nterms && dps [i].term; ++i) - decorr_mono_buffer (sampleptrs [i], sampleptrs [i + 1], wps->wphdr.block_samples, dps + i); - -#ifdef EXTRA_DUMP - best_bits = default_bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); -#else - best_bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples); -#endif - - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 4); - } - - if (wpc->config.extra_flags & EXTRA_BRANCHES) - recurse_mono (wpc, sampleptrs, dps, 0, nterms, (int) floor (wps->delta_decay + 0.5), - log2buffer (sampleptrs [0], wps->wphdr.block_samples), &best_bits); - - if (wpc->config.extra_flags & EXTRA_SORT_FIRST) - sort_mono (wpc, sampleptrs, dps, nterms, &best_bits); - - if (wpc->config.extra_flags & EXTRA_TRY_DELTAS) { - delta_mono (wpc, sampleptrs, dps, nterms, &best_bits); - - if ((wpc->config.extra_flags & EXTRA_ADJUST_DELTAS) && wps->decorr_passes [0].term) - wps->delta_decay = (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, sampleptrs, dps, nterms, &best_bits); - -#if 0 - memcpy (dps, wps->decorr_passes, sizeof (dps)); - - for (i = 0; i < nterms && dps [i].term; ++i) - decorr_mono_pass (sampleptrs [i], sampleptrs [i + 1], wps->wphdr.block_samples, dps + i, 1); - - if (log2buffer (sampleptrs [i], wps->wphdr.block_samples) != best_bits) - error_line ("(1) samples do not match!"); - - if (log2buffer (sampleptrs [nterms + 1], wps->wphdr.block_samples) != best_bits) - error_line ("(2) samples do not match!"); -#endif - - scan_word (wps, sampleptrs [nterms + 1], wps->wphdr.block_samples, -1); - -#ifdef EXTRA_DUMP - if (wpc->config.extra_flags & EXTRA_DUMP_TERMS) { - char string [256], substring [20]; - int i; - - sprintf (string, "M: delta = %.4f%%, terms =", - ((double) best_bits - default_bits) / 256.0 / wps->wphdr.block_samples / 32.0 * 100.0); - - for (i = 0; i < nterms; ++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 - - for (i = 0; i < nterms; ++i) - if (!wps->decorr_passes [i].term) - break; - - wps->num_terms = i; - - for (i = 0; i < nterms + 2; ++i) - free (sampleptrs [i]); - -#ifdef MINMAX_WEIGHTS - error_line ("weight range = %ld (%d) to %ld (%d)", min_weight, min_term, max_weight, max_term); -#endif -} +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 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 "wavpack.h" + +#include +#include +#include +#include + +#define LOG_LIMIT 6912 +// #define EXTRA_DUMP + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +//////////////////////////////// local tables /////////////////////////////// + +typedef struct { + int32_t *sampleptrs [MAX_NTERMS+2]; + struct decorr_pass dps [MAX_NTERMS]; + int nterms, log_limit; + uint32_t best_bits; +} WavpackExtraInfo; + +extern const signed char default_terms [], high_terms [], fast_terms []; + +static void decorr_mono_pass (int32_t *in_samples, int32_t *out_samples, uint32_t num_samples, struct decorr_pass *dpp, int dir) +{ + int m = 0, i; + + dpp->sum_A = 0; + + if (dir < 0) { + out_samples += (num_samples - 1); + in_samples += (num_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] = exp2s (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); + } + } +} + +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 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 >= 9 && term <= 16) + if (term > MAX_TERM || !(wpc->config.flags & CONFIG_HIGH_FLAG) || (wpc->config.extra_flags & EXTRA_SKIP_8TO16)) + continue; + + if ((wpc->config.flags & CONFIG_FAST_FLAG) && (term >= 5 && term <= 16)) + 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 < 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; + + 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 < 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 < 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 < 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); + } + } + } +} + +#define EXTRA_ADVANCED (EXTRA_BRANCHES | EXTRA_SORT_FIRST | EXTRA_SORT_LAST | EXTRA_TRY_DELTAS) + +//extern uint32_t crc3; + +void analyze_mono (WavpackContext *wpc, int32_t *samples) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; +#ifdef EXTRA_DUMP + uint32_t bits, default_bits, cnt; +#else + uint32_t bits, cnt; +#endif + const signed char *decorr_terms = default_terms, *tp; + WavpackExtraInfo info; + int32_t *lptr; + 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 + + CLEAR (wps->decorr_passes); + cnt = wps->wphdr.block_samples; + lptr = samples; + + while (cnt--) + if (*lptr++) + break; + + if (cnt == (uint32_t) -1) { + scan_word (wps, samples, wps->wphdr.block_samples, -1); + wps->num_terms = 0; + return; + } + + if (wpc->config.flags & CONFIG_HIGH_FLAG) + decorr_terms = high_terms; + else if (wpc->config.flags & CONFIG_FAST_FLAG) + decorr_terms = fast_terms; + + for (info.nterms = 0, tp = decorr_terms; *tp; tp++) + if (*tp > 0) + ++info.nterms; + + if (wpc->config.extra_flags & EXTRA_TERMS) + if ((info.nterms += (wpc->config.extra_flags & EXTRA_TERMS) >> 10) > MAX_NTERMS) + info.nterms = MAX_NTERMS; + + for (i = 0; i < info.nterms + 2; ++i) + info.sampleptrs [i] = malloc (wps->wphdr.block_samples * 4); + + memcpy (info.sampleptrs [info.nterms + 1], samples, wps->wphdr.block_samples * 4); + info.best_bits = log2buffer (info.sampleptrs [info.nterms + 1], wps->wphdr.block_samples, 0); + memcpy (info.sampleptrs [0], samples, wps->wphdr.block_samples * 4); + CLEAR (info.dps); + + for (tp = decorr_terms, i = 0; *tp; tp++) + if (*tp > 0) { + info.dps [i].term = *tp; + info.dps [i].delta = 2; + decorr_mono_buffer (info.sampleptrs [i], info.sampleptrs [i+1], wps->wphdr.block_samples, info.dps, i); + ++i; + } + +#ifdef EXTRA_DUMP + default_bits = bits = log2buffer (info.sampleptrs [i], wps->wphdr.block_samples, 0); +#else + bits = log2buffer (info.sampleptrs [i], wps->wphdr.block_samples, 0); +#endif + + 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); + } + + if ((wps->wphdr.flags & HYBRID_FLAG) && (wpc->config.extra_flags & EXTRA_ADVANCED)) { + int shaping_weight, new = wps->wphdr.flags & NEW_SHAPING; + int32_t *rptr = info.sampleptrs [info.nterms + 1], error = 0, temp; + + scan_word (wps, rptr, wps->wphdr.block_samples, -1); + cnt = wps->wphdr.block_samples; + lptr = info.sampleptrs [0]; + + if (wps->wphdr.flags & HYBRID_SHAPE) { + while (cnt--) { + 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++; + } + + 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++; + } + + memcpy (info.dps, wps->decorr_passes, sizeof (info.dps)); + + for (i = 0; i < info.nterms && info.dps [i].term; ++i) + decorr_mono_buffer (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps, i); + +#ifdef EXTRA_DUMP + info.best_bits = default_bits = log2buffer (info.sampleptrs [i], wps->wphdr.block_samples, 0); +#else + info.best_bits = log2buffer (info.sampleptrs [i], wps->wphdr.block_samples, 0); +#endif + + 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); + } + + 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 = (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 0 + memcpy (info.dps, wps->decorr_passes, sizeof (info.dps)); + + 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); + + if (log2buffer (info.sampleptrs [i], wps->wphdr.block_samples, 0) != info.best_bits) + error_line ("(1) samples do not match!"); + + if (log2buffer (info.sampleptrs [info.nterms + 1], wps->wphdr.block_samples, 0) != info.best_bits) + error_line ("(2) samples do not match!"); +#endif + + scan_word (wps, info.sampleptrs [info.nterms + 1], wps->wphdr.block_samples, -1); + +#ifdef EXTRA_DUMP + if (1) { + char string [256], substring [20]; + int i; + + sprintf (string, "M: delta = %.4f%%, terms =", + ((double) info.best_bits - default_bits) / 256.0 / wps->wphdr.block_samples / 32.0 * 100.0); + + for (i = 0; i < info.nterms; ++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 + + 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]); +} diff --git a/Libraries/WavPack/Files/extra2.c b/Libraries/WavPack/Files/extra2.c index 777abe3be..96c4d433b 100644 --- a/Libraries/WavPack/Files/extra2.c +++ b/Libraries/WavPack/Files/extra2.c @@ -1,792 +1,758 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// extra2.c - -// This module handles the "extra" mode for stereo files. - -#include "wavpack.h" - -#include -#include -#include -#include - -// #define EXTRA_DUMP - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -#endif - -extern const char default_terms [], high_terms [], fast_terms []; - -// #define MINMAX_WEIGHTS - -#ifdef MINMAX_WEIGHTS -static int32_t min_weight, max_weight; -static int min_term, max_term; -#endif - -static void decorr_stereo_pass (int32_t *in_samples, int32_t *out_samples, int32_t num_samples, struct decorr_pass *dpp, int dir) -{ - int m = 0; - - dpp->sum_A = dpp->sum_B = 0; - -#ifdef MINMAX_WEIGHTS - dpp->min = dpp->max = 0; -#endif - - if (dir < 0) { - out_samples += (num_samples - 1) * 2; - in_samples += (num_samples - 1) * 2; - dir = -2; - } - else - dir = 2; - - if (dpp->term == 17) { - while (num_samples--) { - int32_t left, right; - int32_t sam_A, sam_B; - - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [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; - - sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = right = in_samples [1]; - right -= apply_weight (dpp->weight_B, sam_B); - update_weight (dpp->weight_B, dpp->delta, sam_B, right); - dpp->sum_B += dpp->weight_B; - out_samples [1] = right; - -#ifdef MINMAX_WEIGHTS - if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; - if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; - if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; - if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; -#endif - in_samples += dir; - out_samples += dir; - } - } - else if (dpp->term == 18) { - while (num_samples--) { - int32_t left, right; - int32_t sam_A, sam_B; - - 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; - - sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = right = in_samples [1]; - right -= apply_weight (dpp->weight_B, sam_B); - update_weight (dpp->weight_B, dpp->delta, sam_B, right); - dpp->sum_B += dpp->weight_B; - out_samples [1] = right; - -#ifdef MINMAX_WEIGHTS - if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; - if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; - if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; - if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; -#endif - 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, right; - int32_t sam_A, sam_B; - - sam_A = dpp->samples_A [m]; - dpp->samples_A [k] = 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; - - sam_B = dpp->samples_B [m]; - dpp->samples_B [k] = right = in_samples [1]; - right -= apply_weight (dpp->weight_B, sam_B); - update_weight (dpp->weight_B, dpp->delta, sam_B, right); - dpp->sum_B += dpp->weight_B; - out_samples [1] = right; - -#ifdef MINMAX_WEIGHTS - if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; - if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; - if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; - if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; -#endif - in_samples += dir; - out_samples += dir; - m = (m + 1) & (MAX_TERM - 1); - } - } - else if (dpp->term == -1) { - while (num_samples--) { - int32_t left = in_samples [0]; - int32_t right = in_samples [1]; - int32_t sam_A = dpp->samples_A [0], sam_B = left; - - dpp->samples_A [0] = right; - right -= apply_weight (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); - left -= apply_weight (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); - dpp->sum_A += dpp->weight_A; - dpp->sum_B += dpp->weight_B; -#ifdef MINMAX_WEIGHTS - if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; - if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; - if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; - if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; -#endif - out_samples [0] = left; - out_samples [1] = right; - in_samples += dir; - out_samples += dir; - } - } - else if (dpp->term == -2) { - while (num_samples--) { - int32_t left = in_samples [0]; - int32_t right = in_samples [1]; - int32_t sam_B = dpp->samples_B [0], sam_A = right; - - dpp->samples_B [0] = left; - left -= apply_weight (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); - right -= apply_weight (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); - dpp->sum_A += dpp->weight_A; - dpp->sum_B += dpp->weight_B; -#ifdef MINMAX_WEIGHTS - if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; - if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; - if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; - if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; -#endif - out_samples [0] = left; - out_samples [1] = right; - in_samples += dir; - out_samples += dir; - } - } - else if (dpp->term == -3) { - while (num_samples--) { - int32_t left = in_samples [0]; - int32_t right = in_samples [1]; - int32_t sam_A = dpp->samples_A [0], sam_B = dpp->samples_B [0]; - - dpp->samples_A [0] = right; - dpp->samples_B [0] = left; - left -= apply_weight (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); - right -= apply_weight (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); - dpp->sum_A += dpp->weight_A; - dpp->sum_B += dpp->weight_B; -#ifdef MINMAX_WEIGHTS - if (dpp->weight_A > dpp->max) dpp->max = dpp->weight_A; - if (dpp->weight_B > dpp->max) dpp->max = dpp->weight_B; - if (dpp->weight_A < dpp->min) dpp->min = dpp->weight_A; - if (dpp->weight_B < dpp->min) dpp->min = dpp->weight_B; -#endif - out_samples [0] = left; - out_samples [1] = right; - in_samples += dir; - out_samples += dir; - } - } - -#ifdef MINMAX_WEIGHTS - if (dpp->term != 0) { - if (dpp->max > max_weight) { max_weight = dpp->max; max_term = dpp->term; } - if (dpp->min < min_weight) { min_weight = dpp->min; min_term = dpp->term; } - } -#endif - - if (m && 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); - } - } -} - -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--]; - } - -// CLEAR (dpp->samples_A); -// CLEAR (dpp->samples_B); - } - else if (dpp->term == -1) { - } - else if (dpp->term == -2) { - } - else if (dpp->term == -3) { - } -} - -static void decorr_stereo_buffer (int32_t *samples, int32_t *outsamples, int32_t num_samples, struct decorr_pass *dpp) -{ - int delta = dpp->delta, pre_delta; - int term = dpp->term; - struct decorr_pass dp; - - 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; - reverse_decorr (&dp); - memcpy (dpp->samples_A, dp.samples_A, sizeof (dp.samples_A)); - memcpy (dpp->samples_B, dp.samples_B, sizeof (dp.samples_B)); - dpp->weight_A = dp.weight_A; - dpp->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, dpp->samples_A, sizeof (dp.samples_A)); - memcpy (dp.samples_B, dpp->samples_B, sizeof (dp.samples_B)); - dpp->weight_A = dp.weight_A = dp.sum_A / num_samples; - dpp->weight_B = dp.weight_B = dp.sum_B / num_samples; - } - -// if (memcmp (dpp, &dp, sizeof (dp))) -// error_line ("decorr_passes don't match, delta = %d", delta); - - decorr_stereo_pass (samples, outsamples, num_samples, &dp, 1); -} - -static void recurse_stereo (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], - int depth, int nterms, int delta, uint32_t input_bits, uint32_t *best_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 == nterms) - branches = 1; - - CLEAR (term_bits); - samples = sampleptrs [depth]; - outsamples = sampleptrs [depth + 1]; - - for (term = -3; term <= 18; ++term) { - if (!term) - continue; - - if (term == 17 && branches == 1 && depth + 1 < nterms) - continue; - - if (term == -1 || term == -2) - if (!(wps->wphdr.flags & CROSS_DECORR)) - continue; - - if (term >= 9 && term <= 16) - if (term > MAX_TERM || !(wpc->config.flags & CONFIG_HIGH_FLAG) || (wpc->config.extra_flags & EXTRA_SKIP_8TO16)) - continue; - - if ((wpc->config.flags & CONFIG_FAST_FLAG) && (term >= 5 && term <= 16)) - continue; - - dps [depth].term = term; - dps [depth].delta = delta; - decorr_stereo_buffer (samples, outsamples, wps->wphdr.block_samples, &dps [depth]); - bits = log2buffer (outsamples, wps->wphdr.block_samples * 2); - - if (bits < *best_bits) { - *best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * (depth + 1)); - memcpy (sampleptrs [nterms + 1], sampleptrs [depth + 1], wps->wphdr.block_samples * 8); - } - - term_bits [term + 3] = bits; - } - - while (depth + 1 < 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; - - dps [depth].term = best_term; - dps [depth].delta = delta; - decorr_stereo_buffer (samples, outsamples, wps->wphdr.block_samples, &dps [depth]); - -// if (log2buffer (outsamples, wps->wphdr.block_samples * 2) != local_best_bits) -// error_line ("data doesn't match!"); - - recurse_stereo (wpc, sampleptrs, dps, depth + 1, nterms, delta, local_best_bits, best_bits); - } -} - -static void delta_stereo (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], - int nterms, uint32_t *best_bits) -{ - 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 < nterms && wps->decorr_passes [i].term; ++i) { - dps [i].term = wps->decorr_passes [i].term; - dps [i].delta = d; - decorr_stereo_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); - } - - bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); - - if (bits < *best_bits) { - lower = TRUE; - *best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); - } - else - break; - } - - for (d = delta + 1; !lower && d <= 7; ++d) { - int i; - - for (i = 0; i < nterms && wps->decorr_passes [i].term; ++i) { - dps [i].term = wps->decorr_passes [i].term; - dps [i].delta = d; - decorr_stereo_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); - } - - bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); - - if (bits < *best_bits) { - *best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); - } - else - break; - } -} - -static void sort_stereo (WavpackContext *wpc, int32_t *sampleptrs[], struct decorr_pass dps[], - int nterms, uint32_t *best_bits) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - int reversed = TRUE; - uint32_t bits; - - while (reversed) { - int ri, i; - - memcpy (dps, wps->decorr_passes, sizeof (wps->decorr_passes)); - reversed = FALSE; - - for (ri = 0; ri < nterms && wps->decorr_passes [ri].term; ++ri) { - - if (ri + 1 >= nterms || !wps->decorr_passes [ri+1].term) - break; - - if (wps->decorr_passes [ri].term == wps->decorr_passes [ri+1].term) { - decorr_stereo_buffer (sampleptrs [ri], sampleptrs [ri+1], wps->wphdr.block_samples, &dps [ri]); - continue; - } - - dps [ri] = wps->decorr_passes [ri+1]; - dps [ri+1] = wps->decorr_passes [ri]; - - for (i = ri; i < nterms && wps->decorr_passes [i].term; ++i) - decorr_stereo_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); - - bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); - - if (bits < *best_bits) { - reversed = TRUE; - *best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); - } - else { - dps [ri] = wps->decorr_passes [ri]; - dps [ri+1] = wps->decorr_passes [ri+1]; - decorr_stereo_buffer (sampleptrs [ri], sampleptrs [ri+1], wps->wphdr.block_samples, &dps [ri]); - } - } - } -} - -#define EXTRA_ADVANCED (EXTRA_BRANCHES | EXTRA_SORT_FIRST | EXTRA_SORT_LAST | EXTRA_TRY_DELTAS) - -void analyze_stereo (WavpackContext *wpc, int32_t *samples) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; -#ifdef EXTRA_DUMP - uint32_t bits, best_bits, default_bits, cnt; -#else - uint32_t bits, best_bits, cnt; -#endif - const char *decorr_terms = default_terms, *tp; - int32_t *sampleptrs [MAX_NTERMS+2], *lptr; - struct decorr_pass dps [MAX_NTERMS]; - int nterms, i; - - - CLEAR (wps->decorr_passes); - cnt = wps->wphdr.block_samples * 2; - lptr = samples; - - while (cnt--) - if (*lptr++) - break; - - if (cnt == (uint32_t) -1) { - scan_word (wps, samples, wps->wphdr.block_samples, -1); - wps->num_terms = 0; - return; - } - - if (wpc->config.flags & CONFIG_HIGH_FLAG) - decorr_terms = high_terms; - else if (wpc->config.flags & CONFIG_FAST_FLAG) - decorr_terms = fast_terms; - - nterms = strlen (decorr_terms); - - if (wpc->config.extra_flags & EXTRA_TERMS) - if ((nterms += (wpc->config.extra_flags & EXTRA_TERMS) >> 10) > MAX_NTERMS) - nterms = MAX_NTERMS; - - for (i = 0; i < nterms + 2; ++i) - sampleptrs [i] = malloc (wps->wphdr.block_samples * 8); - - memcpy (sampleptrs [nterms + 1], samples, wps->wphdr.block_samples * 8); - best_bits = log2buffer (sampleptrs [nterms + 1], wps->wphdr.block_samples * 2); - - if ((wpc->config.extra_flags & EXTRA_STEREO_MODES) || !(wps->wphdr.flags & JOINT_STEREO)) { - memcpy (sampleptrs [0], samples, wps->wphdr.block_samples * 8); - - CLEAR (dps); - - for (tp = decorr_terms, i = 0; *tp;) { - if (*tp > 0 || (wps->wphdr.flags & CROSS_DECORR)) - dps [i].term = *tp++; - else { - dps [i].term = -3; - tp++; - } - - dps [i].delta = 2; - decorr_stereo_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); - ++i; - } - -#ifdef EXTRA_DUMP - default_bits = bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); -#else - bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); -#endif - - wps->wphdr.flags &= ~JOINT_STEREO; - - if (bits < best_bits) { - best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); - } - } - - if ((wpc->config.extra_flags & EXTRA_STEREO_MODES) || (wps->wphdr.flags & JOINT_STEREO)) { - memcpy (sampleptrs [0], samples, wps->wphdr.block_samples * 8); - cnt = wps->wphdr.block_samples; - lptr = sampleptrs [0]; - - while (cnt--) { - lptr [1] += ((lptr [0] -= lptr [1]) >> 1); - lptr += 2; - } - - CLEAR (dps); - - for (tp = decorr_terms, i = 0; *tp;) { - if (*tp > 0 || (wps->wphdr.flags & CROSS_DECORR)) - dps [i].term = *tp++; - else { - dps [i].term = -3; - tp++; - } - - dps [i].delta = 2; - decorr_stereo_buffer (sampleptrs [i], sampleptrs [i+1], wps->wphdr.block_samples, &dps [i]); - ++i; - } - -#ifdef EXTRA_DUMP - default_bits = bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); -#else - bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); -#endif - - wps->wphdr.flags |= JOINT_STEREO; - - if (bits < best_bits) { - best_bits = bits; - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); - } - else { - memcpy (sampleptrs [0], samples, wps->wphdr.block_samples * 8); - wps->wphdr.flags &= ~JOINT_STEREO; - } - } - - if ((wps->wphdr.flags & HYBRID_FLAG) && (wpc->config.extra_flags & EXTRA_ADVANCED)) { - int shaping_weight, new = wps->wphdr.flags & NEW_SHAPING; - int32_t *rptr = sampleptrs [nterms + 1], error [2], temp; - - scan_word (wps, rptr, wps->wphdr.block_samples, -1); - cnt = wps->wphdr.block_samples; - lptr = sampleptrs [0]; - CLEAR (error); - - if (wps->wphdr.flags & HYBRID_SHAPE) { - while (cnt--) { - 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; - - 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; - } - - 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; - } - - memcpy (dps, wps->decorr_passes, sizeof (dps)); - - for (i = 0; i < nterms && dps [i].term; ++i) - decorr_stereo_buffer (sampleptrs [i], sampleptrs [i + 1], wps->wphdr.block_samples, dps + i); - -#ifdef EXTRA_DUMP - best_bits = default_bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); -#else - best_bits = log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2); -#endif - - CLEAR (wps->decorr_passes); - memcpy (wps->decorr_passes, dps, sizeof (dps [0]) * i); - memcpy (sampleptrs [nterms + 1], sampleptrs [i], wps->wphdr.block_samples * 8); - } - - if (wpc->config.extra_flags & EXTRA_BRANCHES) - recurse_stereo (wpc, sampleptrs, dps, 0, nterms, (int) floor (wps->delta_decay + 0.5), - log2buffer (sampleptrs [0], wps->wphdr.block_samples * 2), &best_bits); - - if (wpc->config.extra_flags & EXTRA_SORT_FIRST) - sort_stereo (wpc, sampleptrs, dps, nterms, &best_bits); - - if (wpc->config.extra_flags & EXTRA_TRY_DELTAS) { - delta_stereo (wpc, sampleptrs, dps, nterms, &best_bits); - - if ((wpc->config.extra_flags & EXTRA_ADJUST_DELTAS) && wps->decorr_passes [0].term) - wps->delta_decay = (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, sampleptrs, dps, nterms, &best_bits); - -#if 0 - memcpy (dps, wps->decorr_passes, sizeof (dps)); - - for (i = 0; i < nterms && dps [i].term; ++i) - decorr_stereo_pass (sampleptrs [i], sampleptrs [i + 1], wps->wphdr.block_samples, dps + i, 1); - - if (log2buffer (sampleptrs [i], wps->wphdr.block_samples * 2) != best_bits) - error_line ("(1) samples do not match!"); - - if (log2buffer (sampleptrs [nterms + 1], wps->wphdr.block_samples * 2) != best_bits) - error_line ("(2) samples do not match!"); -#endif - - scan_word (wps, sampleptrs [nterms + 1], wps->wphdr.block_samples, -1); - -#ifdef EXTRA_DUMP - if (1) { - char string [256], substring [20]; - int i; - - sprintf (string, "%s: delta = %.4f%%, terms =", - (wps->wphdr.flags & JOINT_STEREO) ? "JS" : "TS", - ((double) best_bits - default_bits) / 256.0 / wps->wphdr.block_samples / 32.0 * 100.0); - - for (i = 0; i < nterms; ++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 - - for (i = 0; i < nterms; ++i) - if (!wps->decorr_passes [i].term) - break; - - wps->num_terms = i; - - for (i = 0; i < nterms + 2; ++i) - free (sampleptrs [i]); - -#ifdef MINMAX_WEIGHTS - error_line ("weight range = %ld (%d) to %ld (%d)", min_weight, min_term, max_weight, max_term); -#endif -} +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// extra2.c + +// This module handles the "extra" mode for stereo files. + +#include "wavpack.h" + +#include +#include +#include +#include + +#define LOG_LIMIT 6912 +//#define EXTRA_DUMP + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +//////////////////////////////// local tables /////////////////////////////// + +typedef struct { + int32_t *sampleptrs [MAX_NTERMS+2]; + struct decorr_pass dps [MAX_NTERMS]; + int nterms, log_limit; + uint32_t best_bits; +} WavpackExtraInfo; + +extern const signed char default_terms [], high_terms [], fast_terms []; + +static void decorr_stereo_pass (int32_t *in_samples, int32_t *out_samples, int32_t num_samples, struct decorr_pass *dpp, int dir) +{ + int m = 0, i; + + dpp->sum_A = dpp->sum_B = 0; + + if (dir < 0) { + out_samples += (num_samples - 1) * 2; + in_samples += (num_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] = exp2s (log2s (dpp->samples_A [i])); + dpp->samples_B [i] = exp2s (log2s (dpp->samples_B [i])); + } + + if (dpp->term == 17) { + while (num_samples--) { + int32_t left, right; + int32_t sam_A, sam_B; + + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [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; + + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = right = in_samples [1]; + right -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, right); + dpp->sum_B += dpp->weight_B; + out_samples [1] = right; + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term == 18) { + while (num_samples--) { + int32_t left, right; + int32_t sam_A, sam_B; + + 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; + + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = right = in_samples [1]; + right -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, right); + dpp->sum_B += dpp->weight_B; + out_samples [1] = right; + 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, right; + int32_t sam_A, sam_B; + + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = 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; + + sam_B = dpp->samples_B [m]; + dpp->samples_B [k] = right = in_samples [1]; + right -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, right); + dpp->sum_B += dpp->weight_B; + out_samples [1] = right; + in_samples += dir; + out_samples += dir; + m = (m + 1) & (MAX_TERM - 1); + } + } + else if (dpp->term == -1) { + while (num_samples--) { + int32_t left = in_samples [0]; + int32_t right = in_samples [1]; + int32_t sam_A = dpp->samples_A [0], sam_B = left; + + dpp->samples_A [0] = right; + right -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); + left -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); + dpp->sum_A += dpp->weight_A; + dpp->sum_B += dpp->weight_B; + out_samples [0] = left; + out_samples [1] = right; + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term == -2) { + while (num_samples--) { + int32_t left = in_samples [0]; + int32_t right = in_samples [1]; + int32_t sam_B = dpp->samples_B [0], sam_A = right; + + dpp->samples_B [0] = left; + left -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); + right -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); + dpp->sum_A += dpp->weight_A; + dpp->sum_B += dpp->weight_B; + out_samples [0] = left; + out_samples [1] = right; + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term == -3) { + while (num_samples--) { + int32_t left = in_samples [0]; + int32_t right = in_samples [1]; + int32_t sam_A = dpp->samples_A [0], sam_B = dpp->samples_B [0]; + + dpp->samples_A [0] = right; + dpp->samples_B [0] = left; + left -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); + right -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); + dpp->sum_A += dpp->weight_A; + dpp->sum_B += dpp->weight_B; + out_samples [0] = left; + out_samples [1] = right; + in_samples += dir; + out_samples += dir; + } + } + + if (m && 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); + } + } +} + +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 (int32_t *samples, int32_t *outsamples, int32_t num_samples, struct decorr_pass *dpp, int tindex) +{ + struct decorr_pass dp, *dppi = dpp + 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 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) + continue; + + if (term == 17 && branches == 1 && depth + 1 < info->nterms) + continue; + + if (term == -1 || term == -2) + if (!(wps->wphdr.flags & CROSS_DECORR)) + continue; + + if (term >= 9 && term <= 16) + if (term > MAX_TERM || !(wpc->config.flags & CONFIG_HIGH_FLAG) || (wpc->config.extra_flags & EXTRA_SKIP_8TO16)) + continue; + + if ((wpc->config.flags & CONFIG_FAST_FLAG) && (term >= 5 && term <= 16)) + continue; + + info->dps [depth].term = term; + info->dps [depth].delta = delta; + decorr_stereo_buffer (samples, outsamples, wps->wphdr.block_samples, info->dps, depth); + bits = log2buffer (outsamples, wps->wphdr.block_samples * 2, info->log_limit); + + 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; + + info->dps [depth].term = best_term; + info->dps [depth].delta = delta; + decorr_stereo_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_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->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, info->dps, i); + } + + bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); + + 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->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, info->dps, i); + } + + bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); + + 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->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_stereo_buffer (info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, info->dps, i); + + bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); + + 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->sampleptrs [ri], info->sampleptrs [ri+1], wps->wphdr.block_samples, info->dps, ri); + } + } + } +} + +#define EXTRA_ADVANCED (EXTRA_BRANCHES | EXTRA_SORT_FIRST | EXTRA_SORT_LAST | EXTRA_TRY_DELTAS) + +void analyze_stereo (WavpackContext *wpc, int32_t *samples) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; +#ifdef EXTRA_DUMP + uint32_t bits, default_bits, cnt; +#else + uint32_t bits, cnt; +#endif + const signed char *decorr_terms = default_terms, *tp; + WavpackExtraInfo info; + int32_t *lptr; + 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 + + CLEAR (wps->decorr_passes); + cnt = wps->wphdr.block_samples * 2; + lptr = samples; + + while (cnt--) + if (*lptr++) + break; + + if (cnt == (uint32_t) -1) { + scan_word (wps, samples, wps->wphdr.block_samples, -1); + wps->num_terms = 0; + return; + } + + if (wpc->config.flags & CONFIG_HIGH_FLAG) + decorr_terms = high_terms; + else if (wpc->config.flags & CONFIG_FAST_FLAG) + decorr_terms = fast_terms; + + info.nterms = strlen (decorr_terms); + + if (wpc->config.extra_flags & EXTRA_TERMS) + if ((info.nterms += (wpc->config.extra_flags & EXTRA_TERMS) >> 10) > MAX_NTERMS) + info.nterms = MAX_NTERMS; + + for (i = 0; i < info.nterms + 2; ++i) + info.sampleptrs [i] = malloc (wps->wphdr.block_samples * 8); + + memcpy (info.sampleptrs [info.nterms + 1], samples, wps->wphdr.block_samples * 8); + info.best_bits = log2buffer (info.sampleptrs [info.nterms + 1], wps->wphdr.block_samples * 2, 0); + + if ((wpc->config.extra_flags & EXTRA_STEREO_MODES) || !(wps->wphdr.flags & JOINT_STEREO)) { + memcpy (info.sampleptrs [0], samples, wps->wphdr.block_samples * 8); + + CLEAR (info.dps); + + for (tp = decorr_terms, i = 0; *tp;) { + if (*tp > 0 || (wps->wphdr.flags & CROSS_DECORR)) + info.dps [i].term = *tp++; + else { + info.dps [i].term = -3; + tp++; + } + + info.dps [i].delta = 2; + decorr_stereo_buffer (info.sampleptrs [i], info.sampleptrs [i+1], wps->wphdr.block_samples, info.dps, i); + ++i; + } + +#ifdef EXTRA_DUMP + default_bits = bits = log2buffer (info.sampleptrs [i], wps->wphdr.block_samples * 2, 0); +#else + bits = log2buffer (info.sampleptrs [i], wps->wphdr.block_samples * 2, 0); +#endif + + wps->wphdr.flags &= ~JOINT_STEREO; + + 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); + } + } + + if ((wpc->config.extra_flags & EXTRA_STEREO_MODES) || (wps->wphdr.flags & JOINT_STEREO)) { + memcpy (info.sampleptrs [0], samples, wps->wphdr.block_samples * 8); + cnt = wps->wphdr.block_samples; + lptr = info.sampleptrs [0]; + + while (cnt--) { + lptr [1] += ((lptr [0] -= lptr [1]) >> 1); + lptr += 2; + } + + CLEAR (info.dps); + + for (tp = decorr_terms, i = 0; *tp;) { + if (*tp > 0 || (wps->wphdr.flags & CROSS_DECORR)) + info.dps [i].term = *tp++; + else { + info.dps [i].term = -3; + tp++; + } + + info.dps [i].delta = 2; + decorr_stereo_buffer (info.sampleptrs [i], info.sampleptrs [i+1], wps->wphdr.block_samples, info.dps, i); + ++i; + } + +#ifdef EXTRA_DUMP + default_bits = bits = log2buffer (info.sampleptrs [i], wps->wphdr.block_samples * 2, 0); +#else + bits = log2buffer (info.sampleptrs [i], wps->wphdr.block_samples * 2, 0); +#endif + + wps->wphdr.flags |= JOINT_STEREO; + + 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 { + memcpy (info.sampleptrs [0], samples, wps->wphdr.block_samples * 8); + wps->wphdr.flags &= ~JOINT_STEREO; + } + } + + if ((wps->wphdr.flags & HYBRID_FLAG) && (wpc->config.extra_flags & EXTRA_ADVANCED)) { + int shaping_weight, new = wps->wphdr.flags & NEW_SHAPING; + int32_t *rptr = info.sampleptrs [info.nterms + 1], error [2], temp; + + scan_word (wps, rptr, wps->wphdr.block_samples, -1); + cnt = wps->wphdr.block_samples; + lptr = info.sampleptrs [0]; + CLEAR (error); + + if (wps->wphdr.flags & HYBRID_SHAPE) { + while (cnt--) { + 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; + + 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; + } + + 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; + } + + memcpy (info.dps, wps->decorr_passes, sizeof (info.dps)); + + for (i = 0; i < info.nterms && info.dps [i].term; ++i) + decorr_stereo_buffer (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps, i); + +#ifdef EXTRA_DUMP + info.best_bits = default_bits = log2buffer (info.sampleptrs [i], wps->wphdr.block_samples * 2, 0); +#else + info.best_bits = log2buffer (info.sampleptrs [i], wps->wphdr.block_samples * 2, 0); +#endif + + 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); + } + + 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 = (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 0 + memcpy (info.dps, wps->decorr_passes, sizeof (info.dps)); + + 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); + + if (log2buffer (info.sampleptrs [i], wps->wphdr.block_samples * 2, 0) != info.best_bits) + error_line ("(1) samples do not match!"); + + if (log2buffer (info.sampleptrs [info.nterms + 1], wps->wphdr.block_samples * 2, 0) != info.best_bits) + error_line ("(2) samples do not match!"); +#endif + + scan_word (wps, info.sampleptrs [info.nterms + 1], wps->wphdr.block_samples, -1); + +#ifdef EXTRA_DUMP + if (1) { + char string [256], substring [20]; + int i; + + sprintf (string, "%s: delta = %.4f%%, terms =", + (wps->wphdr.flags & JOINT_STEREO) ? "JS" : "TS", + ((double) info.best_bits - default_bits) / 256.0 / wps->wphdr.block_samples / 32.0 * 100.0); + + for (i = 0; i < info.nterms; ++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 + + 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]); +} diff --git a/Libraries/WavPack/Files/float.c b/Libraries/WavPack/Files/float.c index 19fb3a460..eeb32f017 100644 --- a/Libraries/WavPack/Files/float.c +++ b/Libraries/WavPack/Files/float.c @@ -1,371 +1,371 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// float.c - -#include "wavpack.h" - -#include - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -#endif - -#ifdef PACK - -void write_float_info (WavpackStream *wps, WavpackMetadata *wpmd) -{ - char *byteptr; - - byteptr = wpmd->data = malloc (4); - wpmd->id = ID_FLOAT_INFO; - *byteptr++ = wps->float_flags; - *byteptr++ = wps->float_shift; - *byteptr++ = wps->float_max_exp; - *byteptr++ = wps->float_norm_exp; - wpmd->byte_length = byteptr - (char *) wpmd->data; -} - -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; - uint32_t ordata = 0, crc = 0xffffffff; - int max_exp = 0, shift_count; - int32_t count, value; - f32 *dp; - - wps->float_shift = wps->float_flags = 0; - - for (dp = values, count = num_values; count--; dp++) { - crc = crc * 27 + dp->mantissa * 9 + dp->exponent * 3 + dp->sign; - - if (dp->exponent > max_exp && dp->exponent < 255) - max_exp = dp->exponent; - } - - wps->crc_x = crc; - - for (dp = values, count = num_values; count--; dp++) { - if (dp->exponent == 255) { - wps->float_flags |= FLOAT_EXCEPTIONS; - value = 0x1000000; - shift_count = 0; - } - else if (dp->exponent) { - shift_count = max_exp - dp->exponent; - value = 0x800000 + dp->mantissa; - } - else { - shift_count = max_exp ? max_exp - 1 : 0; - value = dp->mantissa; - -// if (dp->mantissa) -// denormals++; - } - - if (shift_count < 25) - value >>= shift_count; - else - value = 0; - - if (!value) { - if (dp->exponent || dp->mantissa) - ++false_zeros; - else if (dp->sign) - ++neg_zeros; - } - else if (shift_count) { - int32_t mask = (1 << shift_count) - 1; - - if (!(dp->mantissa & mask)) - shifted_zeros++; - else if ((dp->mantissa & mask) == mask) - shifted_ones++; - else - shifted_both++; - } - - ordata |= value; - * (int32_t *) dp = (dp->sign) ? -value : value; - } - - wps->float_max_exp = max_exp; - - 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; - else if (ordata && !(ordata & 1)) { - while (!(ordata & 1)) { - wps->float_shift++; - ordata >>= 1; - } - - for (dp = values, count = num_values; count--; dp++) - * (int32_t *) dp >>= wps->float_shift; - } - - wps->wphdr.flags &= ~MAG_MASK; - - while (ordata) { - wps->wphdr.flags += 1 << MAG_LSB; - ordata >>= 1; - } - - if (false_zeros || neg_zeros) - wps->float_flags |= FLOAT_ZEROS_SENT; - - if (neg_zeros) - wps->float_flags |= FLOAT_NEG_ZEROS; - -// error_line ("samples = %d, max exp = %d, pre-shift = %d, denormals = %d", -// num_values, max_exp, wps->float_shift, denormals); -// if (wps->float_flags & FLOAT_EXCEPTIONS) -// error_line ("exceptions!"); -// error_line ("shifted ones/zeros/both = %d/%d/%d, true/neg/false zeros = %d/%d/%d", -// shifted_ones, shifted_zeros, shifted_both, true_zeros, neg_zeros, false_zeros); - - return wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME); -} - -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 (dp->exponent == 255) { - if (dp->mantissa) { - putbit_1 (&wps->wvxbits); - putbits (dp->mantissa, 23, &wps->wvxbits); - } - else { - putbit_0 (&wps->wvxbits); - } - - value = 0x1000000; - shift_count = 0; - } - else if (dp->exponent) { - shift_count = max_exp - dp->exponent; - value = 0x800000 + dp->mantissa; - } - else { - shift_count = max_exp ? max_exp - 1 : 0; - value = dp->mantissa; - } - - if (shift_count < 25) - value >>= shift_count; - else - value = 0; - - if (!value) { - if (wps->float_flags & FLOAT_ZEROS_SENT) { - if (dp->exponent || dp->mantissa) { - putbit_1 (&wps->wvxbits); - putbits (dp->mantissa, 23, &wps->wvxbits); - - if (max_exp >= 25) { - putbits (dp->exponent, 8, &wps->wvxbits); - } - - putbit (dp->sign, &wps->wvxbits); - } - else { - putbit_0 (&wps->wvxbits); - - if (wps->float_flags & FLOAT_NEG_ZEROS) - putbit (dp->sign, &wps->wvxbits); - } - } - } - else if (shift_count) { - if (wps->float_flags & FLOAT_SHIFT_SENT) { - int32_t data = dp->mantissa & ((1 << shift_count) - 1); - putbits (data, shift_count, &wps->wvxbits); - } - else if (wps->float_flags & FLOAT_SHIFT_SAME) { - putbit (dp->mantissa & 1, &wps->wvxbits); - } - } - } -} - -#endif - -#if defined(UNPACK) || defined(INFO_ONLY) - -int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd) -{ - int bytecnt = wpmd->byte_length; - char *byteptr = wpmd->data; - - if (bytecnt != 4) - return FALSE; - - wps->float_flags = *byteptr++; - wps->float_shift = *byteptr++; - wps->float_max_exp = *byteptr++; - wps->float_norm_exp = *byteptr; - return TRUE; -} - -#endif - -#ifdef UNPACK - -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, 0, 0 }; - uint32_t temp; - - if (*values == 0) { - if (wps->float_flags & FLOAT_ZEROS_SENT) { - if (getbit (&wps->wvxbits)) { - getbits (&temp, 23, &wps->wvxbits); - outval.mantissa = temp; - - if (exp >= 25) { - getbits (&temp, 8, &wps->wvxbits); - outval.exponent = temp; - } - - outval.sign = getbit (&wps->wvxbits); - } - else if (wps->float_flags & FLOAT_NEG_ZEROS) - outval.sign = getbit (&wps->wvxbits); - } - } - else { - *values <<= wps->float_shift; - - if (*values < 0) { - *values = -*values; - outval.sign = 1; - } - - if (*values == 0x1000000) { - if (getbit (&wps->wvxbits)) { - getbits (&temp, 23, &wps->wvxbits); - outval.mantissa = temp; - } - - outval.exponent = 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); - } - } - - outval.mantissa = *values; - outval.exponent = exp; - } - } - - crc = crc * 27 + outval.mantissa * 9 + outval.exponent * 3 + outval.sign; - * (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, 0, 0 }; - - if (*values) { - *values <<= wps->float_shift; - - if (*values < 0) { - *values = -*values; - outval.sign = 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); - } - - outval.mantissa = *values; - outval.exponent = exp; - } - - * (f32 *) values++ = outval; - } -} - -void float_normalize (int32_t *values, int32_t num_values, int delta_exp) -{ - f32 *fvalues = (f32 *) values, fzero = { 0, 0, 0 }; - int exp; - - if (!delta_exp) - return; - - while (num_values--) { - if ((exp = fvalues->exponent) == 0 || exp + delta_exp <= 0) - *fvalues = fzero; - else if (exp == 255 || (exp += delta_exp) >= 255) { - fvalues->exponent = 255; - fvalues->mantissa = 0; - } - else - fvalues->exponent = exp; - - fvalues++; - } -} - -#endif +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// float.c + +#include "wavpack.h" + +#include + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +#ifdef PACK + +void write_float_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_FLOAT_INFO; + *byteptr++ = wps->float_flags; + *byteptr++ = wps->float_shift; + *byteptr++ = wps->float_max_exp; + *byteptr++ = wps->float_norm_exp; + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +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; + uint32_t ordata = 0, crc = 0xffffffff; + int max_exp = 0, shift_count; + int32_t count, value; + f32 *dp; + + wps->float_shift = wps->float_flags = 0; + + for (dp = values, count = num_values; count--; dp++) { + crc = crc * 27 + dp->mantissa * 9 + dp->exponent * 3 + dp->sign; + + if (dp->exponent > max_exp && dp->exponent < 255) + max_exp = dp->exponent; + } + + wps->crc_x = crc; + + for (dp = values, count = num_values; count--; dp++) { + if (dp->exponent == 255) { + wps->float_flags |= FLOAT_EXCEPTIONS; + value = 0x1000000; + shift_count = 0; + } + else if (dp->exponent) { + shift_count = max_exp - dp->exponent; + value = 0x800000 + dp->mantissa; + } + else { + shift_count = max_exp ? max_exp - 1 : 0; + value = dp->mantissa; + +// if (dp->mantissa) +// denormals++; + } + + if (shift_count < 25) + value >>= shift_count; + else + value = 0; + + if (!value) { + if (dp->exponent || dp->mantissa) + ++false_zeros; + else if (dp->sign) + ++neg_zeros; + } + else if (shift_count) { + int32_t mask = (1 << shift_count) - 1; + + if (!(dp->mantissa & mask)) + shifted_zeros++; + else if ((dp->mantissa & mask) == mask) + shifted_ones++; + else + shifted_both++; + } + + ordata |= value; + * (int32_t *) dp = (dp->sign) ? -value : value; + } + + wps->float_max_exp = max_exp; + + 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; + else if (ordata && !(ordata & 1)) { + while (!(ordata & 1)) { + wps->float_shift++; + ordata >>= 1; + } + + for (dp = values, count = num_values; count--; dp++) + * (int32_t *) dp >>= wps->float_shift; + } + + wps->wphdr.flags &= ~MAG_MASK; + + while (ordata) { + wps->wphdr.flags += 1 << MAG_LSB; + ordata >>= 1; + } + + if (false_zeros || neg_zeros) + wps->float_flags |= FLOAT_ZEROS_SENT; + + if (neg_zeros) + wps->float_flags |= FLOAT_NEG_ZEROS; + +// error_line ("samples = %d, max exp = %d, pre-shift = %d, denormals = %d", +// num_values, max_exp, wps->float_shift, denormals); +// if (wps->float_flags & FLOAT_EXCEPTIONS) +// error_line ("exceptions!"); +// error_line ("shifted ones/zeros/both = %d/%d/%d, true/neg/false zeros = %d/%d/%d", +// shifted_ones, shifted_zeros, shifted_both, true_zeros, neg_zeros, false_zeros); + + return wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME); +} + +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 (dp->exponent == 255) { + if (dp->mantissa) { + putbit_1 (&wps->wvxbits); + putbits (dp->mantissa, 23, &wps->wvxbits); + } + else { + putbit_0 (&wps->wvxbits); + } + + value = 0x1000000; + shift_count = 0; + } + else if (dp->exponent) { + shift_count = max_exp - dp->exponent; + value = 0x800000 + dp->mantissa; + } + else { + shift_count = max_exp ? max_exp - 1 : 0; + value = dp->mantissa; + } + + if (shift_count < 25) + value >>= shift_count; + else + value = 0; + + if (!value) { + if (wps->float_flags & FLOAT_ZEROS_SENT) { + if (dp->exponent || dp->mantissa) { + putbit_1 (&wps->wvxbits); + putbits (dp->mantissa, 23, &wps->wvxbits); + + if (max_exp >= 25) { + putbits (dp->exponent, 8, &wps->wvxbits); + } + + putbit (dp->sign, &wps->wvxbits); + } + else { + putbit_0 (&wps->wvxbits); + + if (wps->float_flags & FLOAT_NEG_ZEROS) + putbit (dp->sign, &wps->wvxbits); + } + } + } + else if (shift_count) { + if (wps->float_flags & FLOAT_SHIFT_SENT) { + int32_t data = dp->mantissa & ((1 << shift_count) - 1); + putbits (data, shift_count, &wps->wvxbits); + } + else if (wps->float_flags & FLOAT_SHIFT_SAME) { + putbit (dp->mantissa & 1, &wps->wvxbits); + } + } + } +} + +#endif + +#if defined(UNPACK) || defined(INFO_ONLY) + +int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + char *byteptr = wpmd->data; + + if (bytecnt != 4) + return FALSE; + + wps->float_flags = *byteptr++; + wps->float_shift = *byteptr++; + wps->float_max_exp = *byteptr++; + wps->float_norm_exp = *byteptr; + return TRUE; +} + +#endif + +#ifdef UNPACK + +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, 0, 0 }; + uint32_t temp; + + if (*values == 0) { + if (wps->float_flags & FLOAT_ZEROS_SENT) { + if (getbit (&wps->wvxbits)) { + getbits (&temp, 23, &wps->wvxbits); + outval.mantissa = temp; + + if (exp >= 25) { + getbits (&temp, 8, &wps->wvxbits); + outval.exponent = temp; + } + + outval.sign = getbit (&wps->wvxbits); + } + else if (wps->float_flags & FLOAT_NEG_ZEROS) + outval.sign = getbit (&wps->wvxbits); + } + } + else { + *values <<= wps->float_shift; + + if (*values < 0) { + *values = -*values; + outval.sign = 1; + } + + if (*values == 0x1000000) { + if (getbit (&wps->wvxbits)) { + getbits (&temp, 23, &wps->wvxbits); + outval.mantissa = temp; + } + + outval.exponent = 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); + } + } + + outval.mantissa = *values; + outval.exponent = exp; + } + } + + crc = crc * 27 + outval.mantissa * 9 + outval.exponent * 3 + outval.sign; + * (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, 0, 0 }; + + if (*values) { + *values <<= wps->float_shift; + + if (*values < 0) { + *values = -*values; + outval.sign = 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); + } + + outval.mantissa = *values; + outval.exponent = exp; + } + + * (f32 *) values++ = outval; + } +} + +#endif + +void float_normalize (int32_t *values, int32_t num_values, int delta_exp) +{ + f32 *fvalues = (f32 *) values, fzero = { 0, 0, 0 }; + int exp; + + if (!delta_exp) + return; + + while (num_values--) { + if ((exp = fvalues->exponent) == 0 || exp + delta_exp <= 0) + *fvalues = fzero; + else if (exp == 255 || (exp += delta_exp) >= 255) { + fvalues->exponent = 255; + fvalues->mantissa = 0; + } + else + fvalues->exponent = exp; + + fvalues++; + } +} diff --git a/Libraries/WavPack/Files/md5.c b/Libraries/WavPack/Files/md5.c index fe27c4539..2b5ff9987 100644 --- a/Libraries/WavPack/Files/md5.c +++ b/Libraries/WavPack/Files/md5.c @@ -1,263 +1,263 @@ -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ - -/* Brutally hacked by John Walker back from ANSI C to K&R (no - prototypes) to maintain the tradition that Netfone will compile - with Sun's original "cc". */ - -#include /* for memcpy() */ -#include "md5.h" - -#ifdef sgi -#define HIGHFIRST -#endif - -#ifdef sun -#define HIGHFIRST -#endif - -#ifndef HIGHFIRST -#define byteReverse(buf, len) /* Nothing */ -#else -/* - * Note: this code is harmless on little-endian machines. - */ -void byteReverse(buf, longs) - unsigned char *buf; unsigned longs; -{ - uint32 t; - do { - t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(uint32 *) buf = t; - buf += 4; - } while (--longs); -} -#endif - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void MD5Init(ctx) - struct MD5Context *ctx; -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void MD5Update(ctx, buf, len) - struct MD5Context *ctx; unsigned char *buf; unsigned len; -{ - uint32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *) ctx->in); - buf += t; - len -= t; - } - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void MD5Final(digest, ctx) - unsigned char digest[16]; struct MD5Context *ctx; -{ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *) ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((uint32 *) ctx->in)[14] = ctx->bits[0]; - ((uint32 *) ctx->in)[15] = ctx->bits[1]; - - MD5Transform(ctx->buf, (uint32 *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ -} - - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -void MD5Transform(buf, in) - uint32 buf[4]; uint32 in[16]; -{ - register uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +/* Brutally hacked by John Walker back from ANSI C to K&R (no + prototypes) to maintain the tradition that Netfone will compile + with Sun's original "cc". */ + +#include /* for memcpy() */ +#include "md5.h" + +#ifdef sgi +#define HIGHFIRST +#endif + +#ifdef sun +#define HIGHFIRST +#endif + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +void byteReverse(buf, longs) + unsigned char *buf; unsigned longs; +{ + uint32 t; + do { + t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(ctx) + struct MD5Context *ctx; +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(ctx, buf, len) + struct MD5Context *ctx; unsigned char *buf; unsigned len; +{ + uint32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(digest, ctx) + unsigned char digest[16]; struct MD5Context *ctx; +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (uint32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32 *) ctx->in)[14] = ctx->bits[0]; + ((uint32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (uint32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void MD5Transform(buf, in) + uint32 buf[4]; uint32 in[16]; +{ + register uint32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} diff --git a/Libraries/WavPack/Files/md5.h b/Libraries/WavPack/Files/md5.h index 5aa29d201..de11f8bae 100644 --- a/Libraries/WavPack/Files/md5.h +++ b/Libraries/WavPack/Files/md5.h @@ -1,26 +1,26 @@ -#ifndef MD5_H -#define MD5_H - -#if defined (__alpha__) || defined (__x86_64__) -typedef unsigned int uint32; -#else -typedef unsigned long uint32; -#endif - -struct MD5Context { - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; - -extern void MD5Init(); -extern void MD5Update(); -extern void MD5Final(); -extern void MD5Transform(); - -/* - * This is needed to make RSAREF happy on some MS-DOS compilers. - */ -typedef struct MD5Context MD5_CTX; - -#endif /* !MD5_H */ +#ifndef MD5_H +#define MD5_H + +#if defined (__alpha__) || defined (__x86_64__) +typedef unsigned int uint32; +#else +typedef unsigned long uint32; +#endif + +struct MD5Context { + uint32 buf[4]; + uint32 bits[2]; + unsigned char in[64]; +}; + +extern void MD5Init (struct MD5Context *ctx); +extern void MD5Update (struct MD5Context *ctx, unsigned char *buf, unsigned len); +extern void MD5Final (unsigned char digest[16], struct MD5Context *ctx); +extern void MD5Transform (uint32 buf[4], uint32 in[16]); + +/* + * This is needed to make RSAREF happy on some MS-DOS compilers. + */ +typedef struct MD5Context MD5_CTX; + +#endif /* !MD5_H */ diff --git a/Libraries/WavPack/Files/metadata.c b/Libraries/WavPack/Files/metadata.c index 922c16694..b5291c386 100644 --- a/Libraries/WavPack/Files/metadata.c +++ b/Libraries/WavPack/Files/metadata.c @@ -1,310 +1,313 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// metadata.c - -// This module handles the metadata structure introduced in WavPack 4.0 - -#include "wavpack.h" - -#include -#include - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -#endif - -#if defined(UNPACK) || defined(INFO_ONLY) - -int read_metadata_buff (WavpackMetadata *wpmd, uchar *blockbuff, uchar **buffptr) -{ - WavpackHeader *wphdr = (WavpackHeader *) blockbuff; - uchar *buffend = blockbuff + wphdr->ckSize + 8; - - if (buffend - *buffptr < 2) - return FALSE; - - wpmd->id = *(*buffptr)++; - wpmd->byte_length = *(*buffptr)++ << 1; - - if (wpmd->id & ID_LARGE) { - wpmd->id &= ~ID_LARGE; - - if (buffend - *buffptr < 2) - return FALSE; - - wpmd->byte_length += *(*buffptr)++ << 9; - wpmd->byte_length += *(*buffptr)++ << 17; - } - - if (wpmd->id & ID_ODD_SIZE) { - wpmd->id &= ~ID_ODD_SIZE; - wpmd->byte_length--; - } - - if (wpmd->byte_length) { - if (buffend - *buffptr < wpmd->byte_length + (wpmd->byte_length & 1)) { - wpmd->data = NULL; - return FALSE; - } - - wpmd->data = *buffptr; - (*buffptr) += wpmd->byte_length + (wpmd->byte_length & 1); - } - else - wpmd->data = NULL; - - return TRUE; -} - -int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - - switch (wpmd->id) { - case ID_DUMMY: - return TRUE; - - case ID_DECORR_TERMS: - return read_decorr_terms (wps, wpmd); - - case ID_DECORR_WEIGHTS: - return read_decorr_weights (wps, wpmd); - - case ID_DECORR_SAMPLES: - return read_decorr_samples (wps, wpmd); - - case ID_ENTROPY_VARS: - return read_entropy_vars (wps, wpmd); - - case ID_HYBRID_PROFILE: - return read_hybrid_profile (wps, wpmd); - - case ID_SHAPING_WEIGHTS: - return read_shaping_info (wps, wpmd); - - case ID_FLOAT_INFO: - return read_float_info (wps, wpmd); - - case ID_INT32_INFO: - return read_int32_info (wps, wpmd); - - case ID_CHANNEL_INFO: - return read_channel_info (wpc, wpmd); - - case ID_CONFIG_BLOCK: - return read_config_info (wpc, wpmd); - - case ID_WV_BITSTREAM: - return init_wv_bitstream (wps, wpmd); - - case ID_WVC_BITSTREAM: - return init_wvc_bitstream (wps, wpmd); - - case ID_WVX_BITSTREAM: - return init_wvx_bitstream (wps, wpmd); - - case ID_RIFF_HEADER: case ID_RIFF_TRAILER: - return read_wrapper_data (wpc, wpmd); - - case ID_MD5_CHECKSUM: - if (wpmd->byte_length == 16) { - memcpy (wpc->config.md5_checksum, wpmd->data, 16); - wpc->config.flags |= CONFIG_MD5_CHECKSUM; - wpc->config.md5_read = 1; - } - - return TRUE; - - default: - return (wpmd->id & ID_OPTIONAL_DATA) ? TRUE : FALSE; - } -} - -#endif - -#ifdef PACK - -int copy_metadata (WavpackMetadata *wpmd, uchar *buffer_start, uchar *buffer_end) -{ - uint32_t mdsize = wpmd->byte_length + (wpmd->byte_length & 1); - WavpackHeader *wphdr = (WavpackHeader *) buffer_start; - - if (wpmd->byte_length & 1) - ((char *) wpmd->data) [wpmd->byte_length] = 0; - - mdsize += (wpmd->byte_length > 510) ? 4 : 2; - buffer_start += wphdr->ckSize + 8; - - if (buffer_start + mdsize >= buffer_end) - return FALSE; - - buffer_start [0] = wpmd->id | (wpmd->byte_length & 1 ? ID_ODD_SIZE : 0); - buffer_start [1] = (wpmd->byte_length + 1) >> 1; - - if (wpmd->byte_length > 510) { - buffer_start [0] |= ID_LARGE; - buffer_start [2] = (wpmd->byte_length + 1) >> 9; - buffer_start [3] = (wpmd->byte_length + 1) >> 17; - } - - if (wpmd->data && wpmd->byte_length) { - if (wpmd->byte_length > 510) { - buffer_start [0] |= ID_LARGE; - buffer_start [2] = (wpmd->byte_length + 1) >> 9; - buffer_start [3] = (wpmd->byte_length + 1) >> 17; - memcpy (buffer_start + 4, wpmd->data, mdsize - 4); - } - else - memcpy (buffer_start + 2, wpmd->data, mdsize - 2); - } - - wphdr->ckSize += mdsize; - return TRUE; -} - -int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, uchar id) -{ - WavpackMetadata *mdp; - uchar *src = data; - - while (bcount) { - if (wpc->metacount) { - uint32_t bc = bcount; - - mdp = wpc->metadata + wpc->metacount - 1; - - if (mdp->id == id) { - if (wpc->metabytes + bcount > 1000000) - bc = 1000000 - wpc->metabytes; - - mdp->data = realloc (mdp->data, mdp->byte_length + bc); - memcpy ((char *) mdp->data + mdp->byte_length, src, bc); - mdp->byte_length += bc; - wpc->metabytes += bc; - bcount -= bc; - src += bc; - - if (wpc->metabytes >= 1000000 && !write_metadata_block (wpc)) - return FALSE; - } - } - - if (bcount) { - wpc->metadata = realloc (wpc->metadata, (wpc->metacount + 1) * sizeof (WavpackMetadata)); - mdp = wpc->metadata + wpc->metacount++; - mdp->byte_length = 0; - mdp->data = NULL; - mdp->id = id; - } - } - - return TRUE; -} - -static char *write_metadata (WavpackMetadata *wpmd, char *outdata) -{ - uchar id = wpmd->id, wordlen [3]; - - wordlen [0] = (wpmd->byte_length + 1) >> 1; - wordlen [1] = (wpmd->byte_length + 1) >> 9; - wordlen [2] = (wpmd->byte_length + 1) >> 17; - - if (wpmd->byte_length & 1) { -// ((char *) wpmd->data) [wpmd->byte_length] = 0; - id |= ID_ODD_SIZE; - } - - if (wordlen [1] || wordlen [2]) - id |= ID_LARGE; - - *outdata++ = id; - *outdata++ = wordlen [0]; - - if (id & ID_LARGE) { - *outdata++ = wordlen [1]; - *outdata++ = wordlen [2]; - } - - if (wpmd->data && wpmd->byte_length) { - memcpy (outdata, wpmd->data, wpmd->byte_length); - outdata += wpmd->byte_length; - - if (wpmd->byte_length & 1) - *outdata++ = 0; - } - - return outdata; -} - -int write_metadata_block (WavpackContext *wpc) -{ - char *block_buff, *block_ptr; - WavpackHeader *wphdr; - - if (wpc->metacount) { - int metacount = wpc->metacount, block_size = sizeof (WavpackHeader); - WavpackMetadata *wpmdp = wpc->metadata; - - while (metacount--) { - block_size += wpmdp->byte_length + (wpmdp->byte_length & 1); - block_size += (wpmdp->byte_length > 510) ? 4 : 2; - wpmdp++; - } - - wphdr = (WavpackHeader *) (block_buff = malloc (block_size)); - - CLEAR (*wphdr); - memcpy (wphdr->ckID, "wvpk", 4); - wphdr->total_samples = wpc->total_samples; - wphdr->version = 0x403; - wphdr->ckSize = block_size - 8; - wphdr->block_samples = 0; - - block_ptr = (char *)(wphdr + 1); - - wpmdp = wpc->metadata; - - while (wpc->metacount) { - block_ptr = write_metadata (wpmdp, block_ptr); - wpc->metabytes -= wpmdp->byte_length; - free_metadata (wpmdp++); - wpc->metacount--; - } - - free (wpc->metadata); - wpc->metadata = NULL; - native_to_little_endian ((WavpackHeader *) block_buff, WavpackHeaderFormat); - - if (!wpc->blockout (wpc->wv_out, block_buff, block_size)) { - free (block_buff); - strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); - return FALSE; - } - - free (block_buff); - } - - return TRUE; -} - -#endif - -void free_metadata (WavpackMetadata *wpmd) -{ - if (wpmd->data) { - free (wpmd->data); - wpmd->data = NULL; - } -} +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// metadata.c + +// This module handles the metadata structure introduced in WavPack 4.0 + +#include "wavpack.h" + +#include +#include + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +#if defined(UNPACK) || defined(INFO_ONLY) + +int read_metadata_buff (WavpackMetadata *wpmd, uchar *blockbuff, uchar **buffptr) +{ + WavpackHeader *wphdr = (WavpackHeader *) blockbuff; + uchar *buffend = blockbuff + wphdr->ckSize + 8; + + if (buffend - *buffptr < 2) + return FALSE; + + wpmd->id = *(*buffptr)++; + wpmd->byte_length = *(*buffptr)++ << 1; + + if (wpmd->id & ID_LARGE) { + wpmd->id &= ~ID_LARGE; + + if (buffend - *buffptr < 2) + return FALSE; + + wpmd->byte_length += *(*buffptr)++ << 9; + wpmd->byte_length += *(*buffptr)++ << 17; + } + + if (wpmd->id & ID_ODD_SIZE) { + wpmd->id &= ~ID_ODD_SIZE; + wpmd->byte_length--; + } + + if (wpmd->byte_length) { + if (buffend - *buffptr < wpmd->byte_length + (wpmd->byte_length & 1)) { + wpmd->data = NULL; + return FALSE; + } + + wpmd->data = *buffptr; + (*buffptr) += wpmd->byte_length + (wpmd->byte_length & 1); + } + else + wpmd->data = NULL; + + return TRUE; +} + +int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + switch (wpmd->id) { + case ID_DUMMY: + return TRUE; + + case ID_DECORR_TERMS: + return read_decorr_terms (wps, wpmd); + + case ID_DECORR_WEIGHTS: + return read_decorr_weights (wps, wpmd); + + case ID_DECORR_SAMPLES: + return read_decorr_samples (wps, wpmd); + + case ID_ENTROPY_VARS: + return read_entropy_vars (wps, wpmd); + + case ID_HYBRID_PROFILE: + return read_hybrid_profile (wps, wpmd); + + case ID_SHAPING_WEIGHTS: + return read_shaping_info (wps, wpmd); + + case ID_FLOAT_INFO: + return read_float_info (wps, wpmd); + + case ID_INT32_INFO: + return read_int32_info (wps, wpmd); + + case ID_CHANNEL_INFO: + return read_channel_info (wpc, wpmd); + + case ID_CONFIG_BLOCK: + return read_config_info (wpc, wpmd); + + case ID_SAMPLE_RATE: + return read_sample_rate (wpc, wpmd); + + case ID_WV_BITSTREAM: + return init_wv_bitstream (wps, wpmd); + + case ID_WVC_BITSTREAM: + return init_wvc_bitstream (wps, wpmd); + + case ID_WVX_BITSTREAM: + return init_wvx_bitstream (wps, wpmd); + + case ID_RIFF_HEADER: case ID_RIFF_TRAILER: + return read_wrapper_data (wpc, wpmd); + + case ID_MD5_CHECKSUM: + if (wpmd->byte_length == 16) { + memcpy (wpc->config.md5_checksum, wpmd->data, 16); + wpc->config.flags |= CONFIG_MD5_CHECKSUM; + wpc->config.md5_read = 1; + } + + return TRUE; + + default: + return (wpmd->id & ID_OPTIONAL_DATA) ? TRUE : FALSE; + } +} + +#endif + +#ifdef PACK + +int copy_metadata (WavpackMetadata *wpmd, uchar *buffer_start, uchar *buffer_end) +{ + uint32_t mdsize = wpmd->byte_length + (wpmd->byte_length & 1); + WavpackHeader *wphdr = (WavpackHeader *) buffer_start; + + if (wpmd->byte_length & 1) + ((char *) wpmd->data) [wpmd->byte_length] = 0; + + mdsize += (wpmd->byte_length > 510) ? 4 : 2; + buffer_start += wphdr->ckSize + 8; + + if (buffer_start + mdsize >= buffer_end) + return FALSE; + + buffer_start [0] = wpmd->id | (wpmd->byte_length & 1 ? ID_ODD_SIZE : 0); + buffer_start [1] = (wpmd->byte_length + 1) >> 1; + + if (wpmd->byte_length > 510) { + buffer_start [0] |= ID_LARGE; + buffer_start [2] = (wpmd->byte_length + 1) >> 9; + buffer_start [3] = (wpmd->byte_length + 1) >> 17; + } + + if (wpmd->data && wpmd->byte_length) { + if (wpmd->byte_length > 510) { + buffer_start [0] |= ID_LARGE; + buffer_start [2] = (wpmd->byte_length + 1) >> 9; + buffer_start [3] = (wpmd->byte_length + 1) >> 17; + memcpy (buffer_start + 4, wpmd->data, mdsize - 4); + } + else + memcpy (buffer_start + 2, wpmd->data, mdsize - 2); + } + + wphdr->ckSize += mdsize; + return TRUE; +} + +int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, uchar id) +{ + WavpackMetadata *mdp; + uchar *src = data; + + while (bcount) { + if (wpc->metacount) { + uint32_t bc = bcount; + + mdp = wpc->metadata + wpc->metacount - 1; + + if (mdp->id == id) { + if (wpc->metabytes + bcount > 1000000) + bc = 1000000 - wpc->metabytes; + + mdp->data = realloc (mdp->data, mdp->byte_length + bc); + memcpy ((char *) mdp->data + mdp->byte_length, src, bc); + mdp->byte_length += bc; + wpc->metabytes += bc; + bcount -= bc; + src += bc; + + if (wpc->metabytes >= 1000000 && !write_metadata_block (wpc)) + return FALSE; + } + } + + if (bcount) { + wpc->metadata = realloc (wpc->metadata, (wpc->metacount + 1) * sizeof (WavpackMetadata)); + mdp = wpc->metadata + wpc->metacount++; + mdp->byte_length = 0; + mdp->data = NULL; + mdp->id = id; + } + } + + return TRUE; +} + +static char *write_metadata (WavpackMetadata *wpmd, char *outdata) +{ + uchar id = wpmd->id, wordlen [3]; + + wordlen [0] = (wpmd->byte_length + 1) >> 1; + wordlen [1] = (wpmd->byte_length + 1) >> 9; + wordlen [2] = (wpmd->byte_length + 1) >> 17; + + if (wpmd->byte_length & 1) { +// ((char *) wpmd->data) [wpmd->byte_length] = 0; + id |= ID_ODD_SIZE; + } + + if (wordlen [1] || wordlen [2]) + id |= ID_LARGE; + + *outdata++ = id; + *outdata++ = wordlen [0]; + + if (id & ID_LARGE) { + *outdata++ = wordlen [1]; + *outdata++ = wordlen [2]; + } + + if (wpmd->data && wpmd->byte_length) { + memcpy (outdata, wpmd->data, wpmd->byte_length); + outdata += wpmd->byte_length; + + if (wpmd->byte_length & 1) + *outdata++ = 0; + } + + return outdata; +} + +int write_metadata_block (WavpackContext *wpc) +{ + char *block_buff, *block_ptr; + WavpackHeader *wphdr; + + if (wpc->metacount) { + int metacount = wpc->metacount, block_size = sizeof (WavpackHeader); + WavpackMetadata *wpmdp = wpc->metadata; + + while (metacount--) { + block_size += wpmdp->byte_length + (wpmdp->byte_length & 1); + block_size += (wpmdp->byte_length > 510) ? 4 : 2; + wpmdp++; + } + + wphdr = (WavpackHeader *) (block_buff = malloc (block_size)); + + CLEAR (*wphdr); + memcpy (wphdr->ckID, "wvpk", 4); + wphdr->total_samples = wpc->total_samples; + wphdr->version = wpc->stream_version; + wphdr->ckSize = block_size - 8; + wphdr->block_samples = 0; + + block_ptr = (char *)(wphdr + 1); + + wpmdp = wpc->metadata; + + while (wpc->metacount) { + block_ptr = write_metadata (wpmdp, block_ptr); + wpc->metabytes -= wpmdp->byte_length; + free_metadata (wpmdp++); + wpc->metacount--; + } + + free (wpc->metadata); + wpc->metadata = NULL; + native_to_little_endian ((WavpackHeader *) block_buff, WavpackHeaderFormat); + + if (!wpc->blockout (wpc->wv_out, block_buff, block_size)) { + free (block_buff); + strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); + return FALSE; + } + + free (block_buff); + } + + return TRUE; +} + +#endif + +void free_metadata (WavpackMetadata *wpmd) +{ + if (wpmd->data) { + free (wpmd->data); + wpmd->data = NULL; + } +} diff --git a/Libraries/WavPack/Files/pack.c b/Libraries/WavPack/Files/pack.c index 46871041d..9d9366b24 100644 --- a/Libraries/WavPack/Files/pack.c +++ b/Libraries/WavPack/Files/pack.c @@ -1,1413 +1,1484 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// pack.c - -// This module actually handles the compression of the audio data, except for -// the entropy coding which is handled by the words? modules. For efficiency, -// the conversion is isolated to tight loops that handle an entire buffer. - -#include "wavpack.h" - -#include -#include -#include -#include - -// This flag provides faster encoding speed at the expense of more code. The -// improvement applies to 16-bit stereo lossless only. - -#define FAST_ENCODE - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -#endif - -//////////////////////////////// local tables /////////////////////////////// - -// These two tables specify the characteristics of the decorrelation filters. -// Each term represents one layer of the sequential filter, where positive -// values indicate the relative sample involved from the same channel (1=prev), -// 17 & 18 are special functions using the previous 2 samples, and negative -// values indicate cross channel decorrelation (in stereo only). - -const char default_terms [] = { 18,18,2,3,-2,0 }; -const char high_terms [] = { 18,18,2,3,-2,18,2,4,7,5,3,6,8,-1,18,2,0 }; -const char fast_terms [] = { 17,17,0 }; - -///////////////////////////// executable code //////////////////////////////// - -// This function initializes everything required to pack WavPack bitstreams -// and must be called BEFORE any other function in this module. - -void pack_init (WavpackContext *wpc) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - uint32_t flags = wps->wphdr.flags; - struct decorr_pass *dpp; - const char *term_string; - int ti; - - wps->sample_index = 0; - wps->delta_decay = 2.0; - CLEAR (wps->decorr_passes); - CLEAR (wps->dc); - - if (wpc->config.flags & CONFIG_AUTO_SHAPING) - wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = - (wpc->config.sample_rate < 64000 || (wps->wphdr.flags & CROSS_DECORR)) ? -512L << 16 : 1024L << 16; - else { - int32_t weight = (int32_t) floor (wpc->config.shaping_weight * 1024.0 + 0.5); - - if (weight <= -1000) - weight = -1000; - - wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = weight << 16; - } - - if (wpc->config.flags & CONFIG_HIGH_FLAG) - term_string = high_terms; - else if (wpc->config.flags & CONFIG_FAST_FLAG) - term_string = fast_terms; - else - term_string = default_terms; - - for (dpp = wps->decorr_passes, ti = 0; ti < strlen (term_string); ti++) - if (term_string [ti] >= 0 || (flags & CROSS_DECORR)) { - dpp->term = term_string [ti]; - dpp++->delta = 2; - } - else if (!(flags & MONO_FLAG)) { - dpp->term = -3; - dpp++->delta = 2; - } - - wps->num_terms = dpp - wps->decorr_passes; - init_words (wps); -} - -// Allocate room for and copy the decorrelation terms from the decorr_passes -// array into the specified metadata structure. Both the actual term id and -// the delta are packed into single characters. - -void write_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) -{ - int tcount = wps->num_terms; - struct decorr_pass *dpp; - char *byteptr; - - byteptr = wpmd->data = malloc (tcount + 1); - wpmd->id = ID_DECORR_TERMS; - - for (dpp = wps->decorr_passes; tcount--; ++dpp) - *byteptr++ = ((dpp->term + 5) & 0x1f) | ((dpp->delta << 5) & 0xe0); - - wpmd->byte_length = byteptr - (char *) wpmd->data; -} - -// Allocate room for and copy the decorrelation term weights from the -// decorr_passes array into the specified metadata structure. The weights -// range +/-1024, but are rounded and truncated to fit in signed chars for -// metadata storage. Weights are separate for the two channels - -void write_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) -{ - int tcount = wps->num_terms; - struct decorr_pass *dpp; - char *byteptr; - - byteptr = wpmd->data = malloc ((tcount * 2) + 1); - wpmd->id = ID_DECORR_WEIGHTS; - - for (dpp = wps->decorr_passes; tcount--; ++dpp) { - dpp->weight_A = restore_weight (*byteptr++ = store_weight (dpp->weight_A)); - - if (!(wps->wphdr.flags & MONO_FLAG)) - dpp->weight_B = restore_weight (*byteptr++ = store_weight (dpp->weight_B)); - } - - wpmd->byte_length = byteptr - (char *) wpmd->data; -} - -// Allocate room for and copy the decorrelation samples from the decorr_passes -// array into the specified metadata structure. 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 first term -// with unspecified samples set to zero. The number of samples stored varies -// with the actual term value, so those must obviously be specified before -// these in the metadata list. Any number of terms can have their samples -// specified from no terms to all the terms, however I have found that -// sending more than the first term's samples is a waste. The "wcount" -// variable can be set to the number of terms to have their samples stored. - -void write_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) -{ - int tcount = wps->num_terms, wcount = 1, temp; - struct decorr_pass *dpp; - uchar *byteptr; - - byteptr = wpmd->data = malloc (256); - wpmd->id = ID_DECORR_SAMPLES; - - for (dpp = wps->decorr_passes; tcount--; ++dpp) - if (wcount) { - if (dpp->term > MAX_TERM) { - dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - dpp->samples_A [1] = exp2s (temp = log2s (dpp->samples_A [1])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - dpp->samples_B [1] = exp2s (temp = log2s (dpp->samples_B [1])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - } - } - else if (dpp->term < 0) { - dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - } - else { - int m = 0, cnt = dpp->term; - - while (cnt--) { - dpp->samples_A [m] = exp2s (temp = log2s (dpp->samples_A [m])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - dpp->samples_B [m] = exp2s (temp = log2s (dpp->samples_B [m])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - } - - m++; - } - } - - wcount--; - } - else { - CLEAR (dpp->samples_A); - CLEAR (dpp->samples_B); - } - - wpmd->byte_length = byteptr - (uchar *) wpmd->data; -} - -// Allocate room for and copy the noise shaping info into the specified -// metadata structure. These would normally be written to the -// "correction" file and are used for lossless reconstruction of -// hybrid data. The "delta" parameter is not yet used in encoding as it -// will be part of the "quality" mode. - -void write_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd) -{ - char *byteptr; - int temp; - -#if 0 - if (wps->wphdr.block_samples) { - wps->dc.shaping_delta [0] = (-wps->dc.shaping_acc [0] - wps->dc.shaping_acc [0]) / (int32_t) wps->wphdr.block_samples; - wps->dc.shaping_delta [1] = (-wps->dc.shaping_acc [1] - wps->dc.shaping_acc [1]) / (int32_t) wps->wphdr.block_samples; - } -#endif - - byteptr = wpmd->data = malloc (12); - wpmd->id = ID_SHAPING_WEIGHTS; - - wps->dc.error [0] = exp2s (temp = log2s (wps->dc.error [0])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - wps->dc.shaping_acc [0] = exp2s (temp = log2s (wps->dc.shaping_acc [0])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - wps->dc.error [1] = exp2s (temp = log2s (wps->dc.error [1])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - wps->dc.shaping_acc [1] = exp2s (temp = log2s (wps->dc.shaping_acc [1])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - } - - if (wps->dc.shaping_delta [0] | wps->dc.shaping_delta [1]) { - wps->dc.shaping_delta [0] = exp2s (temp = log2s (wps->dc.shaping_delta [0])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - wps->dc.shaping_delta [1] = exp2s (temp = log2s (wps->dc.shaping_delta [1])); - *byteptr++ = temp; - *byteptr++ = temp >> 8; - } - } - - wpmd->byte_length = byteptr - (char *) wpmd->data; -} - -// Allocate room for and copy the int32 data values into the specified -// metadata structure. This data is used for integer data that has more -// than 24 bits of magnitude or, in some cases, it's used to eliminate -// redundant bits from any audio stream. - -void write_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) -{ - char *byteptr; - - byteptr = wpmd->data = malloc (4); - wpmd->id = ID_INT32_INFO; - *byteptr++ = wps->int32_sent_bits; - *byteptr++ = wps->int32_zeros; - *byteptr++ = wps->int32_ones; - *byteptr++ = wps->int32_dups; - wpmd->byte_length = byteptr - (char *) wpmd->data; -} - -// Allocate room for and copy the multichannel information into the specified -// metadata structure. The first byte is the total number of channels and the -// following bytes represent the channel_mask as described for Microsoft -// WAVEFORMATEX. - -void write_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) -{ - uint32_t mask = wpc->config.channel_mask; - char *byteptr; - - byteptr = wpmd->data = malloc (4); - wpmd->id = ID_CHANNEL_INFO; - *byteptr++ = wpc->config.num_channels; - - while (mask) { - *byteptr++ = mask; - mask >>= 8; - } - - wpmd->byte_length = byteptr - (char *) wpmd->data; -} - -// Allocate room for and copy the configuration information into the specified -// metadata structure. Currently, we just store the upper 3 bytes of -// config.flags and only in the first block of audio data. Note that this is -// for informational purposes not required for playback or decoding (like -// whether high or fast mode was specified). - -void write_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) -{ - char *byteptr; - - byteptr = wpmd->data = malloc (4); - wpmd->id = ID_CONFIG_BLOCK; - *byteptr++ = (char) (wpc->config.flags >> 8); - *byteptr++ = (char) (wpc->config.flags >> 16); - *byteptr++ = (char) (wpc->config.flags >> 24); - wpmd->byte_length = byteptr - (char *) wpmd->data; -} - -// 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. - -static int scan_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values); -static void send_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values); -static int pack_samples (WavpackContext *wpc, int32_t *buffer); - -int pack_block (WavpackContext *wpc, int32_t *buffer) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - uint32_t flags = wps->wphdr.flags, sflags = wps->wphdr.flags; - uint32_t sample_count = wps->wphdr.block_samples; - int32_t *orig_data = NULL; - - if (flags & SHIFT_MASK) { - int shift = (flags & SHIFT_MASK) >> SHIFT_LSB; - int mag = (flags & MAG_MASK) >> MAG_LSB; - uint32_t cnt = sample_count; - int32_t *ptr = buffer; - - if (flags & MONO_FLAG) - while (cnt--) - *ptr++ >>= shift; - else - while (cnt--) { - *ptr++ >>= shift; - *ptr++ >>= shift; - } - - if ((mag -= shift) < 0) - flags &= ~MAG_MASK; - else - flags -= (1 << MAG_LSB) * shift; - - wps->wphdr.flags = flags; - } - - if ((flags & FLOAT_DATA) || (flags & MAG_MASK) >> MAG_LSB >= 24) { - if ((!(flags & HYBRID_FLAG) || wpc->wvc_flag) && !(wpc->config.flags & CONFIG_SKIP_WVX)) { - orig_data = malloc (sizeof (f32) * ((flags & MONO_FLAG) ? sample_count : sample_count * 2)); - memcpy (orig_data, buffer, sizeof (f32) * ((flags & MONO_FLAG) ? sample_count : sample_count * 2)); - - if (flags & FLOAT_DATA) { - wps->float_norm_exp = wpc->config.float_norm_exp; - - if (!scan_float_data (wps, (f32 *) buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2)) { - free (orig_data); - orig_data = NULL; - } - } - else { - if (!scan_int32_data (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2)) { - free (orig_data); - orig_data = NULL; - } - } - } - else { - if (flags & FLOAT_DATA) { - wps->float_norm_exp = wpc->config.float_norm_exp; - - if (scan_float_data (wps, (f32 *) buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2)) - wpc->lossy_blocks = TRUE; - } - else if (scan_int32_data (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2)) - wpc->lossy_blocks = TRUE; - } - - wpc->config.extra_flags |= EXTRA_SCAN_ONLY; - } - else if (wpc->config.extra_flags) - scan_int32_data (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2); - - if (wpc->config.extra_flags) { - if (flags & MONO_FLAG) - analyze_mono (wpc, buffer); - else - analyze_stereo (wpc, buffer); - } - else if (!wps->sample_index || !wps->num_terms) { - wpc->config.extra_flags = EXTRA_SCAN_ONLY; - - if (flags & MONO_FLAG) - analyze_mono (wpc, buffer); - else - analyze_stereo (wpc, buffer); - - wpc->config.extra_flags = 0; - } - - if (!pack_samples (wpc, buffer)) { - wps->wphdr.flags = sflags; - - if (orig_data) - free (orig_data); - - return FALSE; - } - else - wps->wphdr.flags = sflags; - - if (orig_data) { - uint32_t data_count; - uchar *cptr; - - if (wpc->wvc_flag) - cptr = wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 8; - else - cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8; - - bs_open_write (&wps->wvxbits, cptr + 8, wpc->wvc_flag ? wps->block2end : wps->blockend); - - if (flags & FLOAT_DATA) - send_float_data (wps, (f32*) orig_data, (flags & MONO_FLAG) ? sample_count : sample_count * 2); - else - send_int32_data (wps, orig_data, (flags & MONO_FLAG) ? sample_count : sample_count * 2); - - data_count = bs_close_write (&wps->wvxbits); - free (orig_data); - - if (data_count) { - if (data_count != (uint32_t) -1) { - *cptr++ = ID_WVX_BITSTREAM | ID_LARGE; - *cptr++ = (data_count += 4) >> 1; - *cptr++ = data_count >> 9; - *cptr++ = data_count >> 17; - *cptr++ = wps->crc_x; - *cptr++ = wps->crc_x >> 8; - *cptr++ = wps->crc_x >> 16; - *cptr = wps->crc_x >> 24; - - if (wpc->wvc_flag) - ((WavpackHeader *) wps->block2buff)->ckSize += data_count + 4; - else - ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4; - } - else - return FALSE; - } - } - - return TRUE; -} - -// Scan a buffer of long integer data and determine whether any redundancy in -// the LSBs can be used to reduce the data's magnitude. If yes, then the -// INT32_DATA flag is set and the int32 parameters are set. If bits must still -// be transmitted literally to get down to 24 bits (which is all the integer -// compression code can handle) then we return TRUE to indicate that a wvx -// stream must be created in either lossless mode. - -static int scan_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values) -{ - uint32_t magdata = 0, ordata = 0, xordata = 0, anddata = ~0; - uint32_t crc = 0xffffffff; - int total_shift = 0; - int32_t *dp, count; - - wps->int32_sent_bits = wps->int32_zeros = wps->int32_ones = wps->int32_dups = 0; - - for (dp = values, count = num_values; count--; dp++) { - crc = crc * 9 + (*dp & 0xffff) * 3 + ((*dp >> 16) & 0xffff); - magdata |= (*dp < 0) ? ~*dp : *dp; - xordata |= *dp ^ -(*dp & 1); - anddata &= *dp; - ordata |= *dp; - } - - wps->crc_x = crc; - wps->wphdr.flags &= ~MAG_MASK; - - while (magdata) { - wps->wphdr.flags += 1 << MAG_LSB; - magdata >>= 1; - } - - if (!((wps->wphdr.flags & MAG_MASK) >> MAG_LSB)) { - wps->wphdr.flags &= ~INT32_DATA; - return FALSE; - } - - if (!(ordata & 1)) - while (!(ordata & 1)) { - wps->wphdr.flags -= 1 << MAG_LSB; - wps->int32_zeros++; - total_shift++; - ordata >>= 1; - } - else if (anddata & 1) - while (anddata & 1) { - wps->wphdr.flags -= 1 << MAG_LSB; - wps->int32_ones++; - total_shift++; - anddata >>= 1; - } - else if (!(xordata & 2)) - while (!(xordata & 2)) { - wps->wphdr.flags -= 1 << MAG_LSB; - wps->int32_dups++; - total_shift++; - xordata >>= 1; - } - - if (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) > 23) { - wps->int32_sent_bits = ((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) - 23; - total_shift += wps->int32_sent_bits; - wps->wphdr.flags &= ~MAG_MASK; - wps->wphdr.flags += 23 << MAG_LSB; - } - - if (total_shift) { - wps->wphdr.flags |= INT32_DATA; - - for (dp = values, count = num_values; count--; dp++) - *dp >>= total_shift; - } - -#if 0 - if (wps->int32_sent_bits + wps->int32_zeros + wps->int32_ones + wps->int32_dups) - error_line ("sent bits = %d, zeros/ones/dups = %d/%d/%d", wps->int32_sent_bits, - wps->int32_zeros, wps->int32_ones, wps->int32_dups); -#endif - - return wps->int32_sent_bits; -} - -// For the specified buffer values and the int32 parameters stored in "wps", -// send the literal bits required to the "wvxbits" bitstream. - -static void send_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values) -{ - int sent_bits = wps->int32_sent_bits, pre_shift; - int32_t mask = (1 << sent_bits) - 1; - int32_t count, value, *dp; - - pre_shift = wps->int32_zeros + wps->int32_ones + wps->int32_dups; - - if (sent_bits) - for (dp = values, count = num_values; count--; dp++) { - value = (*dp >> pre_shift) & mask; - putbits (value, sent_bits, &wps->wvxbits); - } -} - -// 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 void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); -static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); -static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); - -static int pack_samples (WavpackContext *wpc, int32_t *buffer) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - uint32_t sample_count = wps->wphdr.block_samples; - uint32_t flags = wps->wphdr.flags, data_count; - int mag16 = ((flags & MAG_MASK) >> MAG_LSB) >= 16; - int tcount, lossy = FALSE, m = 0; - double noise_acc = 0.0, noise; - struct decorr_pass *dpp; - WavpackMetadata wpmd; - uint32_t crc, crc2, i; - int32_t *bptr; - - crc = crc2 = 0xffffffff; - - 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; - - write_decorr_terms (wps, &wpmd); - copy_metadata (&wpmd, wps->blockbuff, wps->blockend); - free_metadata (&wpmd); - - write_decorr_weights (wps, &wpmd); - copy_metadata (&wpmd, wps->blockbuff, wps->blockend); - free_metadata (&wpmd); - - write_decorr_samples (wps, &wpmd); - copy_metadata (&wpmd, wps->blockbuff, wps->blockend); - free_metadata (&wpmd); - - write_entropy_vars (wps, &wpmd); - copy_metadata (&wpmd, wps->blockbuff, wps->blockend); - free_metadata (&wpmd); - - if (flags & HYBRID_FLAG) { - write_hybrid_profile (wps, &wpmd); - copy_metadata (&wpmd, wps->blockbuff, wps->blockend); - free_metadata (&wpmd); - } - - if (flags & FLOAT_DATA) { - write_float_info (wps, &wpmd); - copy_metadata (&wpmd, wps->blockbuff, wps->blockend); - free_metadata (&wpmd); - } - - if (flags & INT32_DATA) { - write_int32_info (wps, &wpmd); - copy_metadata (&wpmd, wps->blockbuff, wps->blockend); - free_metadata (&wpmd); - } - - if ((flags & INITIAL_BLOCK) && - (wpc->config.num_channels > 2 || - wpc->config.channel_mask != 0x5 - wpc->config.num_channels)) { - write_channel_info (wpc, &wpmd); - copy_metadata (&wpmd, wps->blockbuff, wps->blockend); - free_metadata (&wpmd); - } - - if ((flags & INITIAL_BLOCK) && !wps->sample_index) { - write_config_info (wpc, &wpmd); - copy_metadata (&wpmd, wps->blockbuff, wps->blockend); - free_metadata (&wpmd); - } - - bs_open_write (&wps->wvbits, wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12, wps->blockend); - - if (wpc->wvc_flag) { - wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; - memcpy (wps->block2buff, &wps->wphdr, sizeof (WavpackHeader)); - - if (flags & HYBRID_SHAPE) { - write_shaping_info (wps, &wpmd); - copy_metadata (&wpmd, wps->block2buff, wps->block2end); - free_metadata (&wpmd); - } - - bs_open_write (&wps->wvcbits, wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 12, wps->block2end); - } - - /////////////////////// handle lossless mono mode ///////////////////////// - - if (!(flags & HYBRID_FLAG) && (flags & MONO_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t code; - - crc = crc * 3 + (code = *bptr++); - - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { - int32_t sam; - - 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]; - dpp->samples_A [0] = code; - } - else { - sam = dpp->samples_A [m]; - dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = code; - } - - code -= apply_weight (dpp->weight_A, sam); - update_weight (dpp->weight_A, dpp->delta, sam, code); - } - - m = (m + 1) & (MAX_TERM - 1); - send_word_lossless (wps, code, 0); - } - - //////////////////// handle the lossless stereo mode ////////////////////// - -#ifdef FAST_ENCODE - else if (!(flags & HYBRID_FLAG) && !(flags & MONO_FLAG)) { - int32_t *eptr = buffer + (sample_count * 2), sam_A, sam_B; - - if (flags & JOINT_STEREO) - for (bptr = buffer; bptr < eptr; bptr += 2) { - crc = crc * 9 + bptr [0] * 3 + bptr [1]; - bptr [1] += ((bptr [0] -= bptr [1]) >> 1); - } - else - for (bptr = buffer; bptr < eptr; bptr += 2) - crc = crc * 9 + bptr [0] * 3 + bptr [1]; - - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) - if (((flags & MAG_MASK) >> MAG_LSB) >= 16) - decorr_stereo_pass (dpp, buffer, sample_count); - else if (dpp->delta != 2) - decorr_stereo_pass_i (dpp, buffer, sample_count); - else - decorr_stereo_pass_id2 (dpp, buffer, sample_count); - - for (bptr = buffer; bptr < eptr; bptr += 2) { - send_word_lossless (wps, bptr [0], 0); - send_word_lossless (wps, bptr [1], 1); - } - - m = sample_count & (MAX_TERM - 1); - } -#else - else if (!(flags & HYBRID_FLAG) && !(flags & MONO_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i, bptr += 2) { - int32_t left, right, sam_A, sam_B; - - crc = crc * 3 + (left = bptr [0]); - crc = crc * 3 + (right = bptr [1]); - - if (flags & JOINT_STEREO) - right += ((left -= right) >> 1); - - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) { - 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; - } - - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_A [0] = left; - dpp->samples_B [0] = right; - } - else { - int k = (m + dpp->term) & (MAX_TERM - 1); - - sam_A = dpp->samples_A [m]; - sam_B = dpp->samples_B [m]; - dpp->samples_A [k] = left; - dpp->samples_B [k] = right; - } - - left -= apply_weight (dpp->weight_A, sam_A); - right -= apply_weight (dpp->weight_B, sam_B); - update_weight (dpp->weight_A, dpp->delta, sam_A, left); - update_weight (dpp->weight_B, dpp->delta, sam_B, right); - } - else { - sam_A = (dpp->term == -2) ? right : dpp->samples_A [0]; - sam_B = (dpp->term == -1) ? left : dpp->samples_B [0]; - dpp->samples_A [0] = right; - dpp->samples_B [0] = left; - left -= apply_weight (dpp->weight_A, sam_A); - right -= apply_weight (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); - } - } - - m = (m + 1) & (MAX_TERM - 1); - send_word_lossless (wps, left, 0); - send_word_lossless (wps, right, 1); - } -#endif - - /////////////////// handle the lossy/hybrid mono mode ///////////////////// - - else if ((flags & HYBRID_FLAG) && (flags & MONO_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t code, temp; - - crc2 = crc2 * 3 + (code = *bptr++); - - if (flags & HYBRID_SHAPE) { - int 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] = -code; - code += temp; - } - else - wps->dc.error [0] = -(code += temp); - } - - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) - if (dpp->term > MAX_TERM) { - if (dpp->term & 1) - dpp->samples_A [2] = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - else - dpp->samples_A [2] = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; - - code -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [2])); - } - else - code -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [m])); - - code = send_word (wps, code, 0); - - while (--dpp >= wps->decorr_passes) { - if (dpp->term > MAX_TERM) { - update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [2], code); - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = (code += dpp->aweight_A); - } - else { - int32_t sam = dpp->samples_A [m]; - - update_weight (dpp->weight_A, dpp->delta, sam, code); - dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = (code += dpp->aweight_A); - } - } - - wps->dc.error [0] += code; - m = (m + 1) & (MAX_TERM - 1); - - if ((crc = crc * 3 + code) != crc2) - lossy = TRUE; - - if (wpc->config.flags & CONFIG_CALC_NOISE) { - noise = code - bptr [-1]; - - noise_acc += noise *= noise; - wps->dc.noise_ave = (wps->dc.noise_ave * 0.99) + (noise * 0.01); - - if (wps->dc.noise_ave > wps->dc.noise_max) - wps->dc.noise_max = wps->dc.noise_ave; - } - } - - /////////////////// handle the lossy/hybrid stereo mode /////////////////// - - else if ((flags & HYBRID_FLAG) && !(flags & MONO_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t left, right, temp; - int shaping_weight; - - left = *bptr++; - crc2 = (crc2 * 3 + left) * 3 + (right = *bptr++); - - if (flags & HYBRID_SHAPE) { - 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] = -left; - left += temp; - } - else - wps->dc.error [0] = -(left += temp); - - 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] = -right; - right += temp; - } - else - wps->dc.error [1] = -(right += temp); - } - - if (flags & JOINT_STEREO) - right += ((left -= right) >> 1); - - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) - if (dpp->term > MAX_TERM) { - if (dpp->term & 1) { - dpp->samples_A [2] = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_B [2] = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - } - else { - dpp->samples_A [2] = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; - dpp->samples_B [2] = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; - } - - left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [2])); - right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [2])); - } - else if (dpp->term > 0) { - left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [m])); - right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [m])); - } - else { - if (dpp->term == -1) - dpp->samples_B [0] = left; - else if (dpp->term == -2) - dpp->samples_A [0] = right; - - left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [0])); - right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [0])); - } -#if 0 -if (labs (left) > 60000000 || labs (right) > 60000000) - error_line ("sending %d, %d; samples = %d, %d", left, right, bptr [-2], bptr [-1]); -#endif - left = send_word (wps, left, 0); - right = send_word (wps, right, 1); - - while (--dpp >= wps->decorr_passes) - if (dpp->term > MAX_TERM) { - update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [2], left); - update_weight (dpp->weight_B, dpp->delta, dpp->samples_B [2], right); - - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_B [1] = dpp->samples_B [0]; - - dpp->samples_A [0] = (left += dpp->aweight_A); - dpp->samples_B [0] = (right += dpp->aweight_B); - } - else if (dpp->term > 0) { - int k = (m + dpp->term) & (MAX_TERM - 1); - - update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [m], left); - dpp->samples_A [k] = (left += dpp->aweight_A); - - update_weight (dpp->weight_B, dpp->delta, dpp->samples_B [m], right); - dpp->samples_B [k] = (right += dpp->aweight_B); - } - else { - if (dpp->term == -1) { - dpp->samples_B [0] = left + dpp->aweight_A; - dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [0]); - } - else if (dpp->term == -2) { - dpp->samples_A [0] = right + dpp->aweight_B; - dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [0]); - } - - update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], left); - update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], right); - dpp->samples_B [0] = (left += dpp->aweight_A); - dpp->samples_A [0] = (right += dpp->aweight_B); - } - - if (flags & JOINT_STEREO) - left += (right -= (left >> 1)); - - wps->dc.error [0] += left; - wps->dc.error [1] += right; - m = (m + 1) & (MAX_TERM - 1); - - if ((crc = (crc * 3 + left) * 3 + right) != crc2) - lossy = TRUE; - - if (wpc->config.flags & CONFIG_CALC_NOISE) { - noise = (double)(left - bptr [-2]) * (left - bptr [-2]); - noise += (double)(right - bptr [-1]) * (right - bptr [-1]); - - noise_acc += noise /= 2.0; - wps->dc.noise_ave = (wps->dc.noise_ave * 0.99) + (noise * 0.01); - - if (wps->dc.noise_ave > wps->dc.noise_max) - wps->dc.noise_max = wps->dc.noise_ave; - } - } - - 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); - } - } - - if (wpc->config.flags & CONFIG_CALC_NOISE) - wps->dc.noise_sum += noise_acc; - - flush_word (wps); - data_count = bs_close_write (&wps->wvbits); - - if (data_count) { - if (data_count != (uint32_t) -1) { - uchar *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8; - - *cptr++ = ID_WV_BITSTREAM | ID_LARGE; - *cptr++ = data_count >> 1; - *cptr++ = data_count >> 9; - *cptr++ = data_count >> 17; - ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4; - } - else - return FALSE; - } - - ((WavpackHeader *) wps->blockbuff)->crc = crc; - - if (wpc->wvc_flag) { - data_count = bs_close_write (&wps->wvcbits); - - if (data_count && lossy) { - if (data_count != (uint32_t) -1) { - uchar *cptr = wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 8; - - *cptr++ = ID_WVC_BITSTREAM | ID_LARGE; - *cptr++ = data_count >> 1; - *cptr++ = data_count >> 9; - *cptr++ = data_count >> 17; - ((WavpackHeader *) wps->block2buff)->ckSize += data_count + 4; - } - else - return FALSE; - } - - ((WavpackHeader *) wps->block2buff)->crc = crc2; - } - else if (lossy) - wpc->lossy_blocks = TRUE; - - wps->sample_index += sample_count; - return TRUE; -} - -#ifdef FAST_ENCODE - -static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; - int m, k; - - switch (dpp->term) { - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - - sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = bptr [1]; - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - - sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = bptr [1]; - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - case 8: - for (m = 0, bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [m]; - dpp->samples_A [m] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - - sam_B = dpp->samples_B [m]; - dpp->samples_B [m] = bptr [1]; - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - m = (m + 1) & (MAX_TERM - 1); - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - dpp->samples_A [k] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, dpp->samples_A [m]); - update_weight_d2 (dpp->weight_A, dpp->delta, dpp->samples_A [m], bptr [0]); - - dpp->samples_B [k] = bptr [1]; - bptr [1] -= apply_weight_i (dpp->weight_B, dpp->samples_B [m]); - update_weight_d2 (dpp->weight_B, dpp->delta, dpp->samples_B [m], bptr [1]); - - m = (m + 1) & (MAX_TERM - 1); - k = (k + 1) & (MAX_TERM - 1); - } - - break; - - case -1: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [0]; - sam_B = bptr [0]; - dpp->samples_A [0] = bptr [1]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = bptr [1]; - sam_B = dpp->samples_B [0]; - dpp->samples_B [0] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [0]; - sam_B = dpp->samples_B [0]; - dpp->samples_A [0] = bptr [1]; - dpp->samples_B [0] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - } -} - -static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; - int m, k; - - switch (dpp->term) { - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - - sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = bptr [1]; - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - - sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = bptr [1]; - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [m]; - dpp->samples_A [k] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - - sam_B = dpp->samples_B [m]; - dpp->samples_B [k] = bptr [1]; - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - m = (m + 1) & (MAX_TERM - 1); - k = (k + 1) & (MAX_TERM - 1); - } - - break; - - case -1: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [0]; - sam_B = bptr [0]; - dpp->samples_A [0] = bptr [1]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = bptr [1]; - sam_B = dpp->samples_B [0]; - dpp->samples_B [0] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [0]; - sam_B = dpp->samples_B [0]; - dpp->samples_A [0] = bptr [1]; - dpp->samples_B [0] = bptr [0]; - bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - } -} - -static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; - int m, k; - - switch (dpp->term) { - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = bptr [0]; - bptr [0] -= apply_weight (dpp->weight_A, sam_A); - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - - sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = bptr [1]; - bptr [1] -= apply_weight (dpp->weight_B, sam_B); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = bptr [0]; - bptr [0] -= apply_weight (dpp->weight_A, sam_A); - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - - sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = bptr [1]; - bptr [1] -= apply_weight (dpp->weight_B, sam_B); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [m]; - dpp->samples_A [k] = bptr [0]; - bptr [0] -= apply_weight (dpp->weight_A, sam_A); - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - - sam_B = dpp->samples_B [m]; - dpp->samples_B [k] = bptr [1]; - bptr [1] -= apply_weight (dpp->weight_B, sam_B); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - m = (m + 1) & (MAX_TERM - 1); - k = (k + 1) & (MAX_TERM - 1); - } - - break; - - case -1: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [0]; - sam_B = bptr [0]; - dpp->samples_A [0] = bptr [1]; - bptr [0] -= apply_weight (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - bptr [1] -= apply_weight (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = bptr [1]; - sam_B = dpp->samples_B [0]; - dpp->samples_B [0] = bptr [0]; - bptr [0] -= apply_weight (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - bptr [1] -= apply_weight (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [0]; - sam_B = dpp->samples_B [0]; - dpp->samples_A [0] = bptr [1]; - dpp->samples_B [0] = bptr [0]; - bptr [0] -= apply_weight (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - bptr [1] -= apply_weight (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - } - - break; - } -} - -#endif - -////////////////////////////////////////////////////////////////////////////// -// This function returns the accumulated RMS noise as a double if the // -// CALC_NOISE bit was set in the WavPack header. The peak noise can also be // -// returned if desired. See wavpack.c for the calculations required to // -// convert this into decibels of noise below full scale. // -////////////////////////////////////////////////////////////////////////////// - -double pack_noise (WavpackContext *wpc, double *peak) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - - if (peak) - *peak = wps->dc.noise_max; - - return wps->dc.noise_sum; -} +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// pack.c + +// This module actually handles the compression of the audio data, except for +// the entropy coding which is handled by the words? modules. For efficiency, +// the conversion is isolated to tight loops that handle an entire buffer. + +#include "wavpack.h" + +#include +#include +#include +#include + +// This flag provides faster encoding speed at the expense of more code. The +// improvement applies to 16-bit stereo lossless only. + +#define FAST_ENCODE + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +//////////////////////////////// local tables /////////////////////////////// + +// These two tables specify the characteristics of the decorrelation filters. +// Each term represents one layer of the sequential filter, where positive +// values indicate the relative sample involved from the same channel (1=prev), +// 17 & 18 are special functions using the previous 2 samples, and negative +// values indicate cross channel decorrelation (in stereo only). + +const signed char default_terms [] = { 18,18,2,3,-2,0 }; +const signed char high_terms [] = { 18,18,2,3,-2,18,2,4,7,5,3,6,8,-1,18,2,0 }; +const signed char fast_terms [] = { 17,17,0 }; + +///////////////////////////// executable code //////////////////////////////// + +// This function initializes everything required to pack WavPack bitstreams +// and must be called BEFORE any other function in this module. + +void pack_init (WavpackContext *wpc) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags; + + wps->sample_index = 0; + wps->delta_decay = 2.0; + CLEAR (wps->decorr_passes); + CLEAR (wps->dc); + + if (wpc->config.flags & CONFIG_AUTO_SHAPING) + wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = + (wpc->config.sample_rate < 64000 || (wps->wphdr.flags & CROSS_DECORR)) ? -512L << 16 : 1024L << 16; + else { + int32_t weight = (int32_t) floor (wpc->config.shaping_weight * 1024.0 + 0.5); + + if (weight <= -1000) + weight = -1000; + + wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = weight << 16; + } + + init_words (wps); +} + +// Allocate room for and copy the decorrelation terms from the decorr_passes +// array into the specified metadata structure. Both the actual term id and +// the delta are packed into single characters. + +void write_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int tcount = wps->num_terms; + struct decorr_pass *dpp; + char *byteptr; + + byteptr = wpmd->data = malloc (tcount + 1); + wpmd->id = ID_DECORR_TERMS; + + for (dpp = wps->decorr_passes; tcount--; ++dpp) + *byteptr++ = ((dpp->term + 5) & 0x1f) | ((dpp->delta << 5) & 0xe0); + + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the decorrelation term weights from the +// decorr_passes array into the specified metadata structure. The weights +// range +/-1024, but are rounded and truncated to fit in signed chars for +// metadata storage. Weights are separate for the two channels + +void write_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) +{ + struct decorr_pass *dpp = wps->decorr_passes; + int tcount = wps->num_terms, i; + char *byteptr; + + byteptr = wpmd->data = malloc ((tcount * 2) + 1); + wpmd->id = ID_DECORR_WEIGHTS; + + for (i = wps->num_terms - 1; i >= 0; --i) + if (store_weight (dpp [i].weight_A) || + (!(wps->wphdr.flags & MONO_DATA) && store_weight (dpp [i].weight_B))) + break; + + tcount = i + 1; + + for (i = 0; i < wps->num_terms; ++i) { + if (i < tcount) { + dpp [i].weight_A = restore_weight (*byteptr++ = store_weight (dpp [i].weight_A)); + + if (!(wps->wphdr.flags & MONO_DATA)) + dpp [i].weight_B = restore_weight (*byteptr++ = store_weight (dpp [i].weight_B)); + } + else + dpp [i].weight_A = dpp [i].weight_B = 0; + } + + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the decorrelation samples from the decorr_passes +// array into the specified metadata structure. 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 first term +// with unspecified samples set to zero. The number of samples stored varies +// with the actual term value, so those must obviously be specified before +// these in the metadata list. Any number of terms can have their samples +// specified from no terms to all the terms, however I have found that +// sending more than the first term's samples is a waste. The "wcount" +// variable can be set to the number of terms to have their samples stored. + +void write_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int tcount = wps->num_terms, wcount = 1, temp; + struct decorr_pass *dpp; + uchar *byteptr; + + byteptr = wpmd->data = malloc (256); + wpmd->id = ID_DECORR_SAMPLES; + + for (dpp = wps->decorr_passes; tcount--; ++dpp) + if (wcount) { + if (dpp->term > MAX_TERM) { + dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + dpp->samples_A [1] = exp2s (temp = log2s (dpp->samples_A [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + dpp->samples_B [1] = exp2s (temp = log2s (dpp->samples_B [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + } + else if (dpp->term < 0) { + dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + else { + int m = 0, cnt = dpp->term; + + while (cnt--) { + dpp->samples_A [m] = exp2s (temp = log2s (dpp->samples_A [m])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + dpp->samples_B [m] = exp2s (temp = log2s (dpp->samples_B [m])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + + m++; + } + } + + wcount--; + } + else { + CLEAR (dpp->samples_A); + CLEAR (dpp->samples_B); + } + + wpmd->byte_length = byteptr - (uchar *) wpmd->data; +} + +// Allocate room for and copy the noise shaping info into the specified +// metadata structure. These would normally be written to the +// "correction" file and are used for lossless reconstruction of +// hybrid data. The "delta" parameter is not yet used in encoding as it +// will be part of the "quality" mode. + +void write_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + char *byteptr; + int temp; + + byteptr = wpmd->data = malloc (12); + wpmd->id = ID_SHAPING_WEIGHTS; + + wps->dc.error [0] = exp2s (temp = log2s (wps->dc.error [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + wps->dc.shaping_acc [0] = exp2s (temp = log2s (wps->dc.shaping_acc [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->dc.error [1] = exp2s (temp = log2s (wps->dc.error [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + wps->dc.shaping_acc [1] = exp2s (temp = log2s (wps->dc.shaping_acc [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + + if (wps->dc.shaping_delta [0] | wps->dc.shaping_delta [1]) { + wps->dc.shaping_delta [0] = exp2s (temp = log2s (wps->dc.shaping_delta [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->dc.shaping_delta [1] = exp2s (temp = log2s (wps->dc.shaping_delta [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + } + + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the int32 data values into the specified +// metadata structure. This data is used for integer data that has more +// than 24 bits of magnitude or, in some cases, it's used to eliminate +// redundant bits from any audio stream. + +void write_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_INT32_INFO; + *byteptr++ = wps->int32_sent_bits; + *byteptr++ = wps->int32_zeros; + *byteptr++ = wps->int32_ones; + *byteptr++ = wps->int32_dups; + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the multichannel information into the specified +// metadata structure. The first byte is the total number of channels and the +// following bytes represent the channel_mask as described for Microsoft +// WAVEFORMATEX. + +void write_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + uint32_t mask = wpc->config.channel_mask; + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_CHANNEL_INFO; + *byteptr++ = wpc->config.num_channels; + + while (mask) { + *byteptr++ = mask; + mask >>= 8; + } + + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the configuration information into the specified +// metadata structure. Currently, we just store the upper 3 bytes of +// config.flags and only in the first block of audio data. Note that this is +// for informational purposes not required for playback or decoding (like +// whether high or fast mode was specified). + +void write_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_CONFIG_BLOCK; + *byteptr++ = (char) (wpc->config.flags >> 8); + *byteptr++ = (char) (wpc->config.flags >> 16); + *byteptr++ = (char) (wpc->config.flags >> 24); + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// Allocate room for and copy the non-standard sampling rateinto the specified +// metadata structure. We just store the lower 3 bytes of the sampling rate. +// Note that this would only be used when the sampling rate was not included +// in the table of 15 "standard" values. + +void write_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd) + +{ + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_SAMPLE_RATE; + *byteptr++ = (char) (wpc->config.sample_rate); + *byteptr++ = (char) (wpc->config.sample_rate >> 8); + *byteptr++ = (char) (wpc->config.sample_rate >> 16); + wpmd->byte_length = byteptr - (char *) wpmd->data; +} + +// 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. + +static int scan_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values); +static void scan_int32_quick (WavpackStream *wps, int32_t *values, int32_t num_values); +static void send_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values); +static int pack_samples (WavpackContext *wpc, int32_t *buffer); + +int pack_block (WavpackContext *wpc, int32_t *buffer) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags, sflags = wps->wphdr.flags; + uint32_t sample_count = wps->wphdr.block_samples; + int32_t *orig_data = NULL; + + if (flags & SHIFT_MASK) { + int shift = (flags & SHIFT_MASK) >> SHIFT_LSB; + int mag = (flags & MAG_MASK) >> MAG_LSB; + uint32_t cnt = sample_count; + int32_t *ptr = buffer; + + if (flags & MONO_DATA) + while (cnt--) + *ptr++ >>= shift; + else + while (cnt--) { + *ptr++ >>= shift; + *ptr++ >>= shift; + } + + if ((mag -= shift) < 0) + flags &= ~MAG_MASK; + else + flags -= (1 << MAG_LSB) * shift; + + wps->wphdr.flags = flags; + } + + if ((flags & FLOAT_DATA) || (flags & MAG_MASK) >> MAG_LSB >= 24) { + if ((!(flags & HYBRID_FLAG) || wpc->wvc_flag) && !(wpc->config.flags & CONFIG_SKIP_WVX)) { + orig_data = malloc (sizeof (f32) * ((flags & MONO_DATA) ? sample_count : sample_count * 2)); + memcpy (orig_data, buffer, sizeof (f32) * ((flags & MONO_DATA) ? sample_count : sample_count * 2)); + + if (flags & FLOAT_DATA) { + wps->float_norm_exp = wpc->config.float_norm_exp; + + if (!scan_float_data (wps, (f32 *) buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2)) { + free (orig_data); + orig_data = NULL; + } + } + else { + if (!scan_int32_data (wps, buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2)) { + free (orig_data); + orig_data = NULL; + } + } + } + else { + if (flags & FLOAT_DATA) { + wps->float_norm_exp = wpc->config.float_norm_exp; + + if (scan_float_data (wps, (f32 *) buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2)) + wpc->lossy_blocks = TRUE; + } + else if (scan_int32_data (wps, buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2)) + wpc->lossy_blocks = TRUE; + } + + wpc->config.extra_flags |= EXTRA_SCAN_ONLY; + } + else if (wpc->config.extra_flags) + scan_int32_data (wps, buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2); + else { + scan_int32_quick (wps, buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2); + + if (wps->shift != wps->int32_zeros + wps->int32_ones + wps->int32_dups) { + wps->shift = wps->int32_zeros + wps->int32_ones + wps->int32_dups; + wps->num_terms = 0; + } + } + + if (wpc->config.extra_flags) { + if (flags & MONO_DATA) + analyze_mono (wpc, buffer); + else + analyze_stereo (wpc, buffer); + } + else if (!wps->sample_index || !wps->num_terms) { + wpc->config.extra_flags = EXTRA_SCAN_ONLY; + + if (flags & MONO_DATA) + analyze_mono (wpc, buffer); + else + analyze_stereo (wpc, buffer); + + wpc->config.extra_flags = 0; + } + + if (!pack_samples (wpc, buffer)) { + wps->wphdr.flags = sflags; + + if (orig_data) + free (orig_data); + + return FALSE; + } + else + wps->wphdr.flags = sflags; + + if (orig_data) { + uint32_t data_count; + uchar *cptr; + + if (wpc->wvc_flag) + cptr = wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 8; + else + cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8; + + bs_open_write (&wps->wvxbits, cptr + 8, wpc->wvc_flag ? wps->block2end : wps->blockend); + + if (flags & FLOAT_DATA) + send_float_data (wps, (f32*) orig_data, (flags & MONO_DATA) ? sample_count : sample_count * 2); + else + send_int32_data (wps, orig_data, (flags & MONO_DATA) ? sample_count : sample_count * 2); + + data_count = bs_close_write (&wps->wvxbits); + free (orig_data); + + if (data_count) { + if (data_count != (uint32_t) -1) { + *cptr++ = ID_WVX_BITSTREAM | ID_LARGE; + *cptr++ = (data_count += 4) >> 1; + *cptr++ = data_count >> 9; + *cptr++ = data_count >> 17; + *cptr++ = wps->crc_x; + *cptr++ = wps->crc_x >> 8; + *cptr++ = wps->crc_x >> 16; + *cptr = wps->crc_x >> 24; + + if (wpc->wvc_flag) + ((WavpackHeader *) wps->block2buff)->ckSize += data_count + 4; + else + ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4; + } + else + return FALSE; + } + } + + return TRUE; +} + +// Quickly scan a buffer of long integer data and determine whether any +// redundancy in the LSBs can be used to reduce the data's magnitude. If yes, +// then the INT32_DATA flag is set and the int32 parameters are set. This +// version is designed to terminate as soon as it figures out that no +// redundancy is available so that it can be used for all files. + +static void scan_int32_quick (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + uint32_t magdata = 0, ordata = 0, xordata = 0, anddata = ~0; + int total_shift = 0; + int32_t *dp, count; + + wps->int32_sent_bits = wps->int32_zeros = wps->int32_ones = wps->int32_dups = 0; + + for (dp = values, count = num_values; count--; dp++) { + magdata |= (*dp < 0) ? ~*dp : *dp; + xordata |= *dp ^ -(*dp & 1); + anddata &= *dp; + ordata |= *dp; + + if ((ordata & 1) && !(anddata & 1) && (xordata & 2)) + return; + } + + wps->wphdr.flags &= ~MAG_MASK; + + while (magdata) { + wps->wphdr.flags += 1 << MAG_LSB; + magdata >>= 1; + } + + if (!(wps->wphdr.flags & MAG_MASK)) + return; + + if (!(ordata & 1)) + while (!(ordata & 1)) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_zeros++; + total_shift++; + ordata >>= 1; + } + else if (anddata & 1) + while (anddata & 1) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_ones++; + total_shift++; + anddata >>= 1; + } + else if (!(xordata & 2)) + while (!(xordata & 2)) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_dups++; + total_shift++; + xordata >>= 1; + } + + if (total_shift) { + wps->wphdr.flags |= INT32_DATA; + + for (dp = values, count = num_values; count--; dp++) + *dp >>= total_shift; + } +} + +// Scan a buffer of long integer data and determine whether any redundancy in +// the LSBs can be used to reduce the data's magnitude. If yes, then the +// INT32_DATA flag is set and the int32 parameters are set. If bits must still +// be transmitted literally to get down to 24 bits (which is all the integer +// compression code can handle) then we return TRUE to indicate that a wvx +// stream must be created in either lossless mode. + +static int scan_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + uint32_t magdata = 0, ordata = 0, xordata = 0, anddata = ~0; + uint32_t crc = 0xffffffff; + int total_shift = 0; + int32_t *dp, count; + + wps->int32_sent_bits = wps->int32_zeros = wps->int32_ones = wps->int32_dups = 0; + + for (dp = values, count = num_values; count--; dp++) { + crc = crc * 9 + (*dp & 0xffff) * 3 + ((*dp >> 16) & 0xffff); + magdata |= (*dp < 0) ? ~*dp : *dp; + xordata |= *dp ^ -(*dp & 1); + anddata &= *dp; + ordata |= *dp; + } + + wps->crc_x = crc; + wps->wphdr.flags &= ~MAG_MASK; + + while (magdata) { + wps->wphdr.flags += 1 << MAG_LSB; + magdata >>= 1; + } + + if (!((wps->wphdr.flags & MAG_MASK) >> MAG_LSB)) { + wps->wphdr.flags &= ~INT32_DATA; + return FALSE; + } + + if (!(ordata & 1)) + while (!(ordata & 1)) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_zeros++; + total_shift++; + ordata >>= 1; + } + else if (anddata & 1) + while (anddata & 1) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_ones++; + total_shift++; + anddata >>= 1; + } + else if (!(xordata & 2)) + while (!(xordata & 2)) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_dups++; + total_shift++; + xordata >>= 1; + } + + if (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) > 23) { + wps->int32_sent_bits = ((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) - 23; + total_shift += wps->int32_sent_bits; + wps->wphdr.flags &= ~MAG_MASK; + wps->wphdr.flags += 23 << MAG_LSB; + } + + if (total_shift) { + wps->wphdr.flags |= INT32_DATA; + + for (dp = values, count = num_values; count--; dp++) + *dp >>= total_shift; + } + + return wps->int32_sent_bits; +} + +// For the specified buffer values and the int32 parameters stored in "wps", +// send the literal bits required to the "wvxbits" bitstream. + +static void send_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + int sent_bits = wps->int32_sent_bits, pre_shift; + int32_t mask = (1 << sent_bits) - 1; + int32_t count, value, *dp; + + pre_shift = wps->int32_zeros + wps->int32_ones + wps->int32_dups; + + if (sent_bits) + for (dp = values, count = num_values; count--; dp++) { + value = (*dp >> pre_shift) & mask; + putbits (value, sent_bits, &wps->wvxbits); + } +} + +// 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 void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); + +static int pack_samples (WavpackContext *wpc, int32_t *buffer) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t sample_count = wps->wphdr.block_samples; + uint32_t flags = wps->wphdr.flags, data_count; + int mag16 = ((flags & MAG_MASK) >> MAG_LSB) >= 16; + int tcount, lossy = FALSE, m = 0; + double noise_acc = 0.0, noise; + struct decorr_pass *dpp; + WavpackMetadata wpmd; + uint32_t crc, crc2, i; + int32_t *bptr; + + crc = crc2 = 0xffffffff; + + 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; + + write_decorr_terms (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + write_decorr_weights (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + write_decorr_samples (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + write_entropy_vars (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + if ((flags & SRATE_MASK) == SRATE_MASK && wpc->config.sample_rate != 44100) { + write_sample_rate (wpc, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if (flags & HYBRID_FLAG) { + write_hybrid_profile (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if (flags & FLOAT_DATA) { + write_float_info (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if (flags & INT32_DATA) { + write_int32_info (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if ((flags & INITIAL_BLOCK) && + (wpc->config.num_channels > 2 || + wpc->config.channel_mask != 0x5 - wpc->config.num_channels)) { + write_channel_info (wpc, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if ((flags & INITIAL_BLOCK) && !wps->sample_index) { + write_config_info (wpc, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + bs_open_write (&wps->wvbits, wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12, wps->blockend); + + if (wpc->wvc_flag) { + wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; + memcpy (wps->block2buff, &wps->wphdr, sizeof (WavpackHeader)); + + if (flags & HYBRID_SHAPE) { + write_shaping_info (wps, &wpmd); + copy_metadata (&wpmd, wps->block2buff, wps->block2end); + free_metadata (&wpmd); + } + + bs_open_write (&wps->wvcbits, wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 12, wps->block2end); + } + + /////////////////////// handle lossless mono mode ///////////////////////// + + if (!(flags & HYBRID_FLAG) && (flags & MONO_DATA)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t code; + + crc = crc * 3 + (code = *bptr++); + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam; + + 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]; + dpp->samples_A [0] = code; + } + else { + sam = dpp->samples_A [m]; + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = code; + } + + code -= apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, code); + } + + m = (m + 1) & (MAX_TERM - 1); + send_word_lossless (wps, code, 0); + } + + //////////////////// handle the lossless stereo mode ////////////////////// + +#ifdef FAST_ENCODE + else if (!(flags & HYBRID_FLAG) && !(flags & MONO_DATA)) { + int32_t *eptr = buffer + (sample_count * 2); + + if (flags & JOINT_STEREO) + for (bptr = buffer; bptr < eptr; bptr += 2) { + crc = crc * 9 + bptr [0] * 3 + bptr [1]; + bptr [1] += ((bptr [0] -= bptr [1]) >> 1); + } + else + for (bptr = buffer; bptr < eptr; bptr += 2) + crc = crc * 9 + bptr [0] * 3 + bptr [1]; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) + if (((flags & MAG_MASK) >> MAG_LSB) >= 16) + decorr_stereo_pass (dpp, buffer, sample_count); + else if (dpp->delta != 2) + decorr_stereo_pass_i (dpp, buffer, sample_count); + else + decorr_stereo_pass_id2 (dpp, buffer, sample_count); + + for (bptr = buffer; bptr < eptr; bptr += 2) { + send_word_lossless (wps, bptr [0], 0); + send_word_lossless (wps, bptr [1], 1); + } + + m = sample_count & (MAX_TERM - 1); + } +#else + else if (!(flags & HYBRID_FLAG) && !(flags & MONO_DATA)) + for (bptr = buffer, i = 0; i < sample_count; ++i, bptr += 2) { + int32_t left, right, sam_A, sam_B; + + crc = crc * 3 + (left = bptr [0]); + crc = crc * 3 + (right = bptr [1]); + + if (flags & JOINT_STEREO) + right += ((left -= right) >> 1); + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) { + 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; + } + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_A [0] = left; + dpp->samples_B [0] = right; + } + else { + int k = (m + dpp->term) & (MAX_TERM - 1); + + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + dpp->samples_A [k] = left; + dpp->samples_B [k] = right; + } + + left -= apply_weight (dpp->weight_A, sam_A); + right -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + update_weight (dpp->weight_B, dpp->delta, sam_B, right); + } + else { + sam_A = (dpp->term == -2) ? right : dpp->samples_A [0]; + sam_B = (dpp->term == -1) ? left : dpp->samples_B [0]; + dpp->samples_A [0] = right; + dpp->samples_B [0] = left; + left -= apply_weight (dpp->weight_A, sam_A); + right -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, left); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, right); + } + } + + m = (m + 1) & (MAX_TERM - 1); + send_word_lossless (wps, left, 0); + send_word_lossless (wps, right, 1); + } +#endif + + /////////////////// handle the lossy/hybrid mono mode ///////////////////// + + else if ((flags & HYBRID_FLAG) && (flags & MONO_DATA)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t code, temp; + + crc2 = crc2 * 3 + (code = *bptr++); + + if (flags & HYBRID_SHAPE) { + int 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] = -code; + code += temp; + } + else + wps->dc.error [0] = -(code += temp); + } + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) + dpp->samples_A [2] = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + dpp->samples_A [2] = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + code -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [2])); + } + else + code -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [m])); + + code = send_word (wps, code, 0); + + while (--dpp >= wps->decorr_passes) { + if (dpp->term > MAX_TERM) { + update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [2], code); + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = (code += dpp->aweight_A); + } + else { + int32_t sam = dpp->samples_A [m]; + + update_weight (dpp->weight_A, dpp->delta, sam, code); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = (code += dpp->aweight_A); + } + } + + wps->dc.error [0] += code; + m = (m + 1) & (MAX_TERM - 1); + + if ((crc = crc * 3 + code) != crc2) + lossy = TRUE; + + if (wpc->config.flags & CONFIG_CALC_NOISE) { + noise = code - bptr [-1]; + + noise_acc += noise *= noise; + wps->dc.noise_ave = (wps->dc.noise_ave * 0.99) + (noise * 0.01); + + if (wps->dc.noise_ave > wps->dc.noise_max) + wps->dc.noise_max = wps->dc.noise_ave; + } + } + + /////////////////// handle the lossy/hybrid stereo mode /////////////////// + + else if ((flags & HYBRID_FLAG) && !(flags & MONO_DATA)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t left, right, temp; + int shaping_weight; + + left = *bptr++; + crc2 = (crc2 * 3 + left) * 3 + (right = *bptr++); + + if (flags & HYBRID_SHAPE) { + 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] = -left; + left += temp; + } + else + wps->dc.error [0] = -(left += temp); + + 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] = -right; + right += temp; + } + else + wps->dc.error [1] = -(right += temp); + } + + if (flags & JOINT_STEREO) + right += ((left -= right) >> 1); + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) { + dpp->samples_A [2] = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_B [2] = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + dpp->samples_A [2] = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_B [2] = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + + left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [2])); + right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [2])); + } + else if (dpp->term > 0) { + left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [m])); + right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [m])); + } + else { + if (dpp->term == -1) + dpp->samples_B [0] = left; + else if (dpp->term == -2) + dpp->samples_A [0] = right; + + left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [0])); + right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [0])); + } + + left = send_word (wps, left, 0); + right = send_word (wps, right, 1); + + while (--dpp >= wps->decorr_passes) + if (dpp->term > MAX_TERM) { + update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [2], left); + update_weight (dpp->weight_B, dpp->delta, dpp->samples_B [2], right); + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = (left += dpp->aweight_A); + dpp->samples_B [0] = (right += dpp->aweight_B); + } + else if (dpp->term > 0) { + int k = (m + dpp->term) & (MAX_TERM - 1); + + update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [m], left); + dpp->samples_A [k] = (left += dpp->aweight_A); + + update_weight (dpp->weight_B, dpp->delta, dpp->samples_B [m], right); + dpp->samples_B [k] = (right += dpp->aweight_B); + } + else { + if (dpp->term == -1) { + dpp->samples_B [0] = left + dpp->aweight_A; + dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [0]); + } + else if (dpp->term == -2) { + dpp->samples_A [0] = right + dpp->aweight_B; + dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [0]); + } + + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], left); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], right); + dpp->samples_B [0] = (left += dpp->aweight_A); + dpp->samples_A [0] = (right += dpp->aweight_B); + } + + if (flags & JOINT_STEREO) + left += (right -= (left >> 1)); + + wps->dc.error [0] += left; + wps->dc.error [1] += right; + m = (m + 1) & (MAX_TERM - 1); + + if ((crc = (crc * 3 + left) * 3 + right) != crc2) + lossy = TRUE; + + if (wpc->config.flags & CONFIG_CALC_NOISE) { + noise = (double)(left - bptr [-2]) * (left - bptr [-2]); + noise += (double)(right - bptr [-1]) * (right - bptr [-1]); + + noise_acc += noise /= 2.0; + wps->dc.noise_ave = (wps->dc.noise_ave * 0.99) + (noise * 0.01); + + if (wps->dc.noise_ave > wps->dc.noise_max) + wps->dc.noise_max = wps->dc.noise_ave; + } + } + + 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); + } + } + + if (wpc->config.flags & CONFIG_CALC_NOISE) + wps->dc.noise_sum += noise_acc; + + flush_word (wps); + data_count = bs_close_write (&wps->wvbits); + + if (data_count) { + if (data_count != (uint32_t) -1) { + uchar *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8; + + *cptr++ = ID_WV_BITSTREAM | ID_LARGE; + *cptr++ = data_count >> 1; + *cptr++ = data_count >> 9; + *cptr++ = data_count >> 17; + ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4; + } + else + return FALSE; + } + + ((WavpackHeader *) wps->blockbuff)->crc = crc; + + if (wpc->wvc_flag) { + data_count = bs_close_write (&wps->wvcbits); + + if (data_count && lossy) { + if (data_count != (uint32_t) -1) { + uchar *cptr = wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 8; + + *cptr++ = ID_WVC_BITSTREAM | ID_LARGE; + *cptr++ = data_count >> 1; + *cptr++ = data_count >> 9; + *cptr++ = data_count >> 17; + ((WavpackHeader *) wps->block2buff)->ckSize += data_count + 4; + } + else + return FALSE; + } + + ((WavpackHeader *) wps->block2buff)->crc = crc2; + } + else if (lossy) + wpc->lossy_blocks = TRUE; + + wps->sample_index += sample_count; + return TRUE; +} + +#ifdef FAST_ENCODE + +static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case 8: + for (m = 0, bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + dpp->samples_A [m] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = dpp->samples_B [m]; + dpp->samples_B [m] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + m = (m + 1) & (MAX_TERM - 1); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + dpp->samples_A [k] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, dpp->samples_A [m]); + update_weight_d2 (dpp->weight_A, dpp->delta, dpp->samples_A [m], bptr [0]); + + dpp->samples_B [k] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, dpp->samples_B [m]); + update_weight_d2 (dpp->weight_B, dpp->delta, dpp->samples_B [m], bptr [1]); + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = bptr [0]; + dpp->samples_A [0] = bptr [1]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [1]; + sam_B = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = dpp->samples_B [0]; + dpp->samples_A [0] = bptr [1]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + } +} + +static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = dpp->samples_B [m]; + dpp->samples_B [k] = bptr [1]; + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = bptr [0]; + dpp->samples_A [0] = bptr [1]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [1]; + sam_B = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = dpp->samples_B [0]; + dpp->samples_A [0] = bptr [1]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + } +} + +static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = bptr [0]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [1]; + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = bptr [0]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + + sam_B = dpp->samples_B [m]; + dpp->samples_B [k] = bptr [1]; + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = bptr [0]; + dpp->samples_A [0] = bptr [1]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [1]; + sam_B = dpp->samples_B [0]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [0]; + sam_B = dpp->samples_B [0]; + dpp->samples_A [0] = bptr [1]; + dpp->samples_B [0] = bptr [0]; + bptr [0] -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + bptr [1] -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + } + + break; + } +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// This function returns the accumulated RMS noise as a double if the // +// CALC_NOISE bit was set in the WavPack header. The peak noise can also be // +// returned if desired. See wavpack.c for the calculations required to // +// convert this into decibels of noise below full scale. // +////////////////////////////////////////////////////////////////////////////// + +double pack_noise (WavpackContext *wpc, double *peak) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + if (peak) + *peak = wps->dc.noise_max; + + return wps->dc.noise_sum; +} diff --git a/Libraries/WavPack/Files/unpack.c b/Libraries/WavPack/Files/unpack.c index 2e1f0e653..96f6f9444 100644 --- a/Libraries/WavPack/Files/unpack.c +++ b/Libraries/WavPack/Files/unpack.c @@ -1,1453 +1,1476 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 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 words? modules. For -// maximum efficiency, the conversion is isolated to tight loops that handle -// an entire buffer. - -#include "wavpack.h" - -#include -#include -#include -#include - -// This flag provides faster decoding speed at the expense of more code. The -// improvement applies to 16-bit stereo lossless only. - -#define FAST_DECODE - -#define LOSSY_MUTE - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -#endif - -///////////////////////////// executable code //////////////////////////////// - -// This function initializes everything required to unpack a WavPack block -// and must be called before unpack_samples() is called to obtain audio data. -// It is assumed that the WavpackHeader has been read into the wps->wphdr -// (in the current WavpackStream) and that the entire block has been read at -// wps->blockbuff. If a correction file is available (wpc->wvc_flag = TRUE) -// then the corresponding correction block must be read into wps->block2buff -// and its WavpackHeader has overwritten the header at wps->wphdr. This is -// where all the metadata blocks are scanned including those that contain -// bitstream data. - -int unpack_init (WavpackContext *wpc) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - uchar *blockptr, *block2ptr; - WavpackMetadata wpmd; - - if (wps->wphdr.block_samples && wps->wphdr.block_index != (uint32_t) -1) - wps->sample_index = wps->wphdr.block_index; - - wps->mute_error = FALSE; - wps->crc = wps->crc_x = 0xffffffff; - CLEAR (wps->wvbits); - CLEAR (wps->wvcbits); - CLEAR (wps->wvxbits); - CLEAR (wps->decorr_passes); - CLEAR (wps->dc); - CLEAR (wps->w); - - blockptr = wps->blockbuff + sizeof (WavpackHeader); - - while (read_metadata_buff (&wpmd, wps->blockbuff, &blockptr)) - if (!process_metadata (wpc, &wpmd)) { - sprintf (wpc->error_message, "invalid metadata %2x!", wpmd.id); - return FALSE; - } - - block2ptr = wps->block2buff + sizeof (WavpackHeader); - - while (wpc->wvc_flag && wps->wphdr.block_samples && read_metadata_buff (&wpmd, wps->block2buff, &block2ptr)) - if (!process_metadata (wpc, &wpmd)) { - sprintf (wpc->error_message, "invalid metadata %2x in wvc file!", wpmd.id); - return FALSE; - } - - if (wps->wphdr.block_samples && !bs_is_open (&wps->wvbits)) { - if (bs_is_open (&wps->wvcbits)) - strcpy (wpc->error_message, "can't unpack correction files alone!"); - - return FALSE; - } - - if (wps->wphdr.block_samples && !bs_is_open (&wps->wvxbits)) { - if ((wps->wphdr.flags & INT32_DATA) && wps->int32_sent_bits) - wpc->lossy_blocks = TRUE; - - if ((wps->wphdr.flags & FLOAT_DATA) && - wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME)) - wpc->lossy_blocks = TRUE; - } - - return TRUE; -} - -// This function initialzes the main bitstream for audio samples, which must -// be in the "wv" file. - -int init_wv_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) -{ - bs_open_read (&wps->wvbits, wpmd->data, (char *) wpmd->data + wpmd->byte_length); - return TRUE; -} - -// This function initialzes the "correction" bitstream for audio samples, -// which currently must be in the "wvc" file. - -int init_wvc_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) -{ - bs_open_read (&wps->wvcbits, wpmd->data, (char *) wpmd->data + wpmd->byte_length); - return TRUE; -} - -// This function initialzes the "extra" bitstream for audio samples which -// contains the information required to losslessly decompress 32-bit float data -// or integer data that exceeds 24 bits. This bitstream is in the "wv" file -// for pure lossless data or the "wvc" file for hybrid lossless. This data -// would not be used for hybrid lossy mode. There is also a 32-bit CRC stored -// in the first 4 bytes of these blocks. - -int init_wvx_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) -{ - uchar *cp = wpmd->data; - - wps->crc_wvx = *cp++; - wps->crc_wvx |= (int32_t) *cp++ << 8; - wps->crc_wvx |= (int32_t) *cp++ << 16; - wps->crc_wvx |= (int32_t) *cp++ << 24; - - bs_open_read (&wps->wvxbits, cp, (char *) wpmd->data + wpmd->byte_length); - return TRUE; -} - -// 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; - uchar *byteptr = 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) - 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 = wpmd->data; - struct decorr_pass *dpp; - - if (!(wps->wphdr.flags & MONO_FLAG)) - 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_FLAG)) - 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) -{ - uchar *byteptr = wpmd->data; - uchar *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)) { - wps->dc.error [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); - byteptr += 2; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - wps->dc.error [1] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); - byteptr += 2; - } - } - - while (dpp-- > wps->decorr_passes && byteptr < endptr) - if (dpp->term > MAX_TERM) { - dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); - dpp->samples_A [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); - byteptr += 4; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - dpp->samples_B [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); - dpp->samples_B [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); - byteptr += 4; - } - } - else if (dpp->term < 0) { - dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); - dpp->samples_B [0] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); - byteptr += 4; - } - else { - int m = 0, cnt = dpp->term; - - while (cnt--) { - dpp->samples_A [m] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); - byteptr += 2; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - dpp->samples_B [m] = exp2s ((short)(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 = 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_FLAG ? 4 : 8)) { - uchar *byteptr = wpmd->data; - - wps->dc.error [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); - wps->dc.shaping_acc [0] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); - byteptr += 4; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - wps->dc.error [1] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); - wps->dc.shaping_acc [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); - byteptr += 4; - } - - if (wpmd->byte_length == (wps->wphdr.flags & MONO_FLAG ? 6 : 12)) { - wps->dc.shaping_delta [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); - - if (!(wps->wphdr.flags & MONO_FLAG)) - wps->dc.shaping_delta [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); - } - - return TRUE; - } - - return FALSE; -} - -// Read the int32 data from the specified metadata into the specified stream. -// This data is used for integer data that has more than 24 bits of magnitude -// or, in some cases, used to eliminate redundant bits from any audio stream. - -int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) -{ - int bytecnt = wpmd->byte_length; - char *byteptr = wpmd->data; - - if (bytecnt != 4) - return FALSE; - - wps->int32_sent_bits = *byteptr++; - wps->int32_zeros = *byteptr++; - wps->int32_ones = *byteptr++; - wps->int32_dups = *byteptr; - - return TRUE; -} - -// Read multichannel information from metadata. The first byte is the total -// number of channels and the following bytes represent the channel_mask -// as described for Microsoft WAVEFORMATEX. - -int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) -{ - int bytecnt = wpmd->byte_length, shift = 0; - char *byteptr = wpmd->data; - uint32_t mask = 0; - - if (!bytecnt || bytecnt > 5) - return FALSE; - - wpc->config.num_channels = *byteptr++; - - while (--bytecnt) { - mask |= (uint32_t) *byteptr++ << shift; - shift += 8; - } - - wpc->config.channel_mask = mask; - return TRUE; -} - -// Read configuration information from metadata. - -int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) -{ - int bytecnt = wpmd->byte_length; - uchar *byteptr = wpmd->data; - - if (bytecnt >= 3) { - wpc->config.flags &= 0xff; - wpc->config.flags |= (int32_t) *byteptr++ << 8; - wpc->config.flags |= (int32_t) *byteptr++ << 16; - wpc->config.flags |= (int32_t) *byteptr << 24; - } - - return TRUE; -} - -// Read wrapper data from metadata. Currently, this consists of the RIFF -// header and trailer that wav files contain around the audio data but could -// be used for other formats as well. Because WavPack files contain all the -// information required for decoding and playback, this data can probably -// be ignored except when an exact wavefile restoration is needed. - -int read_wrapper_data (WavpackContext *wpc, WavpackMetadata *wpmd) -{ - if (wpc->open_flags & OPEN_WRAPPER) { - wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + wpmd->byte_length); - memcpy (wpc->wrapper_data + wpc->wrapper_bytes, wpmd->data, wpmd->byte_length); - wpc->wrapper_bytes += wpmd->byte_length; - } - - return TRUE; -} - -#ifdef UNPACK - -// This monster actually unpacks the WavPack bitstream(s) into the specified -// buffer as 32-bit integers or floats (depending on orignal 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_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); -static void decorr_stereo_pass_id0 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); -static void decorr_stereo_pass_id1 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); -static void decorr_stereo_pass_id2 (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; - - if (wps->sample_index + sample_count > wps->wphdr.block_index + wps->wphdr.block_samples) - sample_count = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; - - if (wps->mute_error) { - memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8)); - wps->sample_index += sample_count; - return sample_count; - } - - if ((flags & HYBRID_FLAG) && !wpc->wvc_flag) - mute_limit *= 2; - - ///////////////// handle version 4 lossless mono data ///////////////////// - - if (!(flags & HYBRID_FLAG) && (flags & MONO_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - if ((read_word = get_word_lossless (wps, 0)) == 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; - } - - if (labs (read_word) > mute_limit) - break; - - m = (m + 1) & (MAX_TERM - 1); - crc = crc * 3 + read_word; - *bptr++ = read_word; - } - - //////////////// handle version 4 lossless stereo data //////////////////// - - else if (!wpc->wvc_flag && !(flags & MONO_FLAG)) { - int32_t *eptr = buffer + (sample_count * 2); - - i = sample_count; - - if (flags & HYBRID_FLAG) { - 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 = (bptr - buffer) / 2; - break; - } - } - else - for (bptr = buffer; bptr < eptr; bptr += 2) - if ((bptr [0] = get_word_lossless (wps, 0)) == WORD_EOF || - (bptr [1] = get_word_lossless (wps, 1)) == WORD_EOF) { - i = (bptr - buffer) / 2; - break; - } - -#ifdef FAST_DECODE - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - if (((flags & MAG_MASK) >> MAG_LSB) >= 16) - decorr_stereo_pass (dpp, buffer, sample_count); - else if (dpp->delta > 2) - decorr_stereo_pass_i (dpp, buffer, sample_count); - else if (dpp->delta == 2) - decorr_stereo_pass_id2 (dpp, buffer, sample_count); - else if (dpp->delta == 1) - decorr_stereo_pass_id1 (dpp, buffer, sample_count); - else - decorr_stereo_pass_id0 (dpp, buffer, sample_count); -#else - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - decorr_stereo_pass (dpp, buffer, sample_count); -#endif - - if (flags & JOINT_STEREO) - for (bptr = buffer; bptr < eptr; bptr += 2) { - bptr [0] += (bptr [1] -= (bptr [0] >> 1)); - - if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { - i = (bptr - buffer) / 2; - break; - } - - crc = (crc * 3 + bptr [0]) * 3 + bptr [1]; - } - else - for (bptr = buffer; bptr < eptr; bptr += 2) { - if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { - i = (bptr - buffer) / 2; - break; - } - - crc = (crc * 3 + bptr [0]) * 3 + bptr [1]; - } - - m = sample_count & (MAX_TERM - 1); - } - - //////////////// handle version 4 lossy/hybrid mono data ////////////////// - - else if ((flags & HYBRID_FLAG) && (flags & MONO_FLAG)) - 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 (wpc->wvc_flag) { - 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 * 3 + read_word; - -#ifdef LOSSY_MUTE - if (labs (read_word) > mute_limit) - break; -#endif - *bptr++ = read_word; - } - - //////////////// handle version 4 lossy/hybrid stereo data //////////////// - - else if (wpc->wvc_flag && !(flags & MONO_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t left, right, left_c, right_c, left2, right2; - - 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; - } - -#ifdef LOSSY_MUTE - if (labs (left) > mute_limit || labs (right) > mute_limit) - break; -#endif - crc = (crc * 3 + left) * 3 + right; - *bptr++ = left; - *bptr++ = right; - } - - 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)) - float_normalize (buffer, (flags & MONO_FLAG) ? i : i * 2, - 127 - wps->float_norm_exp + wpc->norm_offset); - - wps->sample_index += i; - wps->crc = crc; - - return i; -} - -static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; - int m, k; - - switch (dpp->term) { - - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_B [1] = dpp->samples_B [0]; - - dpp->samples_A [0] = apply_weight (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [0] = apply_weight (dpp->weight_B, sam_B) + bptr [1]; - - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [0]; - bptr [1] = dpp->samples_B [0]; - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - 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] = apply_weight (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [0] = apply_weight (dpp->weight_B, sam_B) + bptr [1]; - - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [0]; - bptr [1] = dpp->samples_B [0]; - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [m]; - sam_B = dpp->samples_B [m]; - - dpp->samples_A [k] = apply_weight (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [k] = apply_weight (dpp->weight_B, sam_B) + bptr [1]; - - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [k]; - 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) { - 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]); - bptr [0] = sam_A; - dpp->samples_A [0] = bptr [1] + apply_weight (dpp->weight_B, sam_A); - update_weight_clip (dpp->weight_B, dpp->delta, sam_A, bptr [1]); - bptr [1] = dpp->samples_A [0]; - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - 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 [1] = sam_B; - dpp->samples_B [0] = bptr [0] + apply_weight (dpp->weight_A, sam_B); - update_weight_clip (dpp->weight_A, dpp->delta, sam_B, bptr [0]); - bptr [0] = dpp->samples_B [0]; - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - 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; - } -} - -#ifdef FAST_DECODE - -static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; - int m, k; - - switch (dpp->term) { - - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_B [1] = dpp->samples_B [0]; - - dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; - - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [0]; - bptr [1] = dpp->samples_B [0]; - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - 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] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; - - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [0]; - bptr [1] = dpp->samples_B [0]; - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [m]; - sam_B = dpp->samples_B [m]; - - dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; - - update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [k]; - 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) { - sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); - update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); - bptr [0] = sam_A; - dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam_A); - update_weight_clip (dpp->weight_B, dpp->delta, sam_A, bptr [1]); - bptr [1] = dpp->samples_A [0]; - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); - update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); - bptr [1] = sam_B; - dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam_B); - update_weight_clip (dpp->weight_A, dpp->delta, sam_B, bptr [0]); - bptr [0] = dpp->samples_B [0]; - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = bptr [0] + apply_weight_i (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_i (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; - } -} - -static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; - int m, k; - - switch (dpp->term) { - - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_B [1] = dpp->samples_B [0]; - - dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; - - update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [0]; - bptr [1] = dpp->samples_B [0]; - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - 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] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; - - update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [0]; - bptr [1] = dpp->samples_B [0]; - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [m]; - sam_B = dpp->samples_B [m]; - - dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; - - update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [k]; - 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) { - sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); - update_weight_clip_d2 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); - bptr [0] = sam_A; - dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam_A); - update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_A, bptr [1]); - bptr [1] = dpp->samples_A [0]; - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); - update_weight_clip_d2 (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); - bptr [1] = sam_B; - dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam_B); - update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_B, bptr [0]); - bptr [0] = dpp->samples_B [0]; - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); - update_weight_clip_d2 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); - sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); - update_weight_clip_d2 (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; - } -} - -static void decorr_stereo_pass_id1 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; - int m, k; - - switch (dpp->term) { - - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_B [1] = dpp->samples_B [0]; - - dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; - - update_weight_d1 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight_d1 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [0]; - bptr [1] = dpp->samples_B [0]; - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - 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] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; - - update_weight_d1 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight_d1 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [0]; - bptr [1] = dpp->samples_B [0]; - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [m]; - sam_B = dpp->samples_B [m]; - - dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; - dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; - - update_weight_d1 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); - update_weight_d1 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); - - bptr [0] = dpp->samples_A [k]; - 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) { - sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); - update_weight_clip_d1 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); - bptr [0] = sam_A; - dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam_A); - update_weight_clip_d1 (dpp->weight_B, dpp->delta, sam_A, bptr [1]); - bptr [1] = dpp->samples_A [0]; - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); - update_weight_clip_d1 (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); - bptr [1] = sam_B; - dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam_B); - update_weight_clip_d1 (dpp->weight_A, dpp->delta, sam_B, bptr [0]); - bptr [0] = dpp->samples_B [0]; - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); - update_weight_clip_d1 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); - sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); - update_weight_clip_d1 (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; - } -} - -static void decorr_stereo_pass_id0 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; - int m, k; - - switch (dpp->term) { - - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_B [1] = dpp->samples_B [0]; - - dpp->samples_A [0] = bptr [0] += apply_weight_i (dpp->weight_A, sam_A); - dpp->samples_B [0] = bptr [1] += apply_weight_i (dpp->weight_B, sam_B); - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - 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] = bptr [0] += apply_weight_i (dpp->weight_A, sam_A); - dpp->samples_B [0] = bptr [1] += apply_weight_i (dpp->weight_B, sam_B); - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - dpp->samples_A [k] = bptr [0] += apply_weight_i (dpp->weight_A, dpp->samples_A [m]); - dpp->samples_B [k] = bptr [1] += apply_weight_i (dpp->weight_B, dpp->samples_B [m]); - m = (m + 1) & (MAX_TERM - 1); - k = (k + 1) & (MAX_TERM - 1); - } - - break; - - case -1: - for (bptr = buffer; bptr < eptr; bptr += 2) { - bptr [0] += apply_weight_i (dpp->weight_A, dpp->samples_A [0]); - dpp->samples_A [0] = bptr [1] += apply_weight_i (dpp->weight_B, bptr [0]); - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - bptr [1] += apply_weight_i (dpp->weight_B, dpp->samples_B [0]); - dpp->samples_B [0] = bptr [0] += apply_weight_i (dpp->weight_A, bptr [1]); - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - bptr [0] += apply_weight_i (dpp->weight_A, dpp->samples_A [0]); - dpp->samples_A [0] = bptr [1] += apply_weight_i (dpp->weight_B, dpp->samples_B [0]); - dpp->samples_B [0] = bptr [0]; - } - - break; - } -} - -#endif - -// 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) && !wpc->wvc_flag; - int shift = (flags & SHIFT_MASK) >> SHIFT_LSB; - - if (flags & FLOAT_DATA) { - float_values (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2); - return; - } - - if (flags & INT32_DATA) { - uint32_t count = (flags & MONO_FLAG) ? 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: - min_shifted = (min_value = (int32_t) 0x80000000 >> shift) << shift; - max_shifted = (max_value = (int32_t) 0x7fffffff >> shift) << shift; - break; - } - - if (!(flags & MONO_FLAG)) - 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_FLAG)) - 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; -} - -#endif +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 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 words? modules. For +// maximum efficiency, the conversion is isolated to tight loops that handle +// an entire buffer. + +#include "wavpack.h" + +#include +#include +#include +#include + +// This flag provides faster decoding speed at the expense of more code. The +// improvement applies to 16-bit stereo lossless only. + +#define FAST_DECODE + +#define LOSSY_MUTE + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +///////////////////////////// executable code //////////////////////////////// + +// This function initializes everything required to unpack a WavPack block +// and must be called before unpack_samples() is called to obtain audio data. +// It is assumed that the WavpackHeader has been read into the wps->wphdr +// (in the current WavpackStream) and that the entire block has been read at +// wps->blockbuff. If a correction file is available (wpc->wvc_flag = TRUE) +// then the corresponding correction block must be read into wps->block2buff +// and its WavpackHeader has overwritten the header at wps->wphdr. This is +// where all the metadata blocks are scanned including those that contain +// bitstream data. + +int unpack_init (WavpackContext *wpc) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uchar *blockptr, *block2ptr; + WavpackMetadata wpmd; + + if (wps->wphdr.block_samples && wps->wphdr.block_index != (uint32_t) -1) + wps->sample_index = wps->wphdr.block_index; + + wps->mute_error = FALSE; + wps->crc = wps->crc_x = 0xffffffff; + CLEAR (wps->wvbits); + CLEAR (wps->wvcbits); + CLEAR (wps->wvxbits); + CLEAR (wps->decorr_passes); + CLEAR (wps->dc); + CLEAR (wps->w); + + blockptr = wps->blockbuff + sizeof (WavpackHeader); + + while (read_metadata_buff (&wpmd, wps->blockbuff, &blockptr)) + if (!process_metadata (wpc, &wpmd)) + return FALSE; + + block2ptr = wps->block2buff + sizeof (WavpackHeader); + + while (wpc->wvc_flag && wps->wphdr.block_samples && read_metadata_buff (&wpmd, wps->block2buff, &block2ptr)) + if (!process_metadata (wpc, &wpmd)) + return FALSE; + + if (wps->wphdr.block_samples && !bs_is_open (&wps->wvbits)) { + if (bs_is_open (&wps->wvcbits)) + strcpy (wpc->error_message, "can't unpack correction files alone!"); + + return FALSE; + } + + if (wps->wphdr.block_samples && !bs_is_open (&wps->wvxbits)) { + if ((wps->wphdr.flags & INT32_DATA) && wps->int32_sent_bits) + wpc->lossy_blocks = TRUE; + + if ((wps->wphdr.flags & FLOAT_DATA) && + wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME)) + wpc->lossy_blocks = TRUE; + } + + return TRUE; +} + +// This function initialzes the main bitstream for audio samples, which must +// be in the "wv" file. + +int init_wv_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + bs_open_read (&wps->wvbits, wpmd->data, (char *) wpmd->data + wpmd->byte_length); + return TRUE; +} + +// This function initialzes the "correction" bitstream for audio samples, +// which currently must be in the "wvc" file. + +int init_wvc_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + bs_open_read (&wps->wvcbits, wpmd->data, (char *) wpmd->data + wpmd->byte_length); + return TRUE; +} + +// This function initialzes the "extra" bitstream for audio samples which +// contains the information required to losslessly decompress 32-bit float data +// or integer data that exceeds 24 bits. This bitstream is in the "wv" file +// for pure lossless data or the "wvc" file for hybrid lossless. This data +// would not be used for hybrid lossy mode. There is also a 32-bit CRC stored +// in the first 4 bytes of these blocks. + +int init_wvx_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + uchar *cp = wpmd->data; + + wps->crc_wvx = *cp++; + wps->crc_wvx |= (int32_t) *cp++ << 8; + wps->crc_wvx |= (int32_t) *cp++ << 16; + wps->crc_wvx |= (int32_t) *cp++ << 24; + + bs_open_read (&wps->wvxbits, cp, (char *) wpmd->data + wpmd->byte_length); + return TRUE; +} + +// 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; + uchar *byteptr = 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) + 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 = 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) +{ + uchar *byteptr = wpmd->data; + uchar *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)) { + wps->dc.error [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->dc.error [1] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + } + } + + while (dpp-- > wps->decorr_passes && byteptr < endptr) + if (dpp->term > MAX_TERM) { + dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_A [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + + if (!(wps->wphdr.flags & MONO_DATA)) { + dpp->samples_B [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_B [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + } + else if (dpp->term < 0) { + dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_B [0] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + else { + int m = 0, cnt = dpp->term; + + while (cnt--) { + dpp->samples_A [m] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + dpp->samples_B [m] = exp2s ((short)(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 = 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)) { + uchar *byteptr = wpmd->data; + + wps->dc.error [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + wps->dc.shaping_acc [0] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->dc.error [1] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + wps->dc.shaping_acc [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + + if (wpmd->byte_length == (wps->wphdr.flags & MONO_DATA ? 6 : 12)) { + wps->dc.shaping_delta [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + + if (!(wps->wphdr.flags & MONO_DATA)) + wps->dc.shaping_delta [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + } + + return TRUE; + } + + return FALSE; +} + +// Read the int32 data from the specified metadata into the specified stream. +// This data is used for integer data that has more than 24 bits of magnitude +// or, in some cases, used to eliminate redundant bits from any audio stream. + +int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + char *byteptr = wpmd->data; + + if (bytecnt != 4) + return FALSE; + + wps->int32_sent_bits = *byteptr++; + wps->int32_zeros = *byteptr++; + wps->int32_ones = *byteptr++; + wps->int32_dups = *byteptr; + + return TRUE; +} + +// Read multichannel information from metadata. The first byte is the total +// number of channels and the following bytes represent the channel_mask +// as described for Microsoft WAVEFORMATEX. + +int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length, shift = 0; + char *byteptr = wpmd->data; + uint32_t mask = 0; + + if (!bytecnt || bytecnt > 5) + return FALSE; + + wpc->config.num_channels = *byteptr++; + + while (--bytecnt) { + mask |= (uint32_t) *byteptr++ << shift; + shift += 8; + } + + wpc->config.channel_mask = mask; + return TRUE; +} + +// Read configuration information from metadata. + +int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + uchar *byteptr = wpmd->data; + + if (bytecnt >= 3) { + wpc->config.flags &= 0xff; + wpc->config.flags |= (int32_t) *byteptr++ << 8; + wpc->config.flags |= (int32_t) *byteptr++ << 16; + wpc->config.flags |= (int32_t) *byteptr << 24; + } + + return TRUE; +} + +// Read non-standard sampling rate from metadata. + +int read_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + uchar *byteptr = wpmd->data; + + if (bytecnt == 3) { + wpc->config.sample_rate = (int32_t) *byteptr++; + wpc->config.sample_rate |= (int32_t) *byteptr++ << 8; + wpc->config.sample_rate |= (int32_t) *byteptr++ << 16; + } + + return TRUE; +} + +// Read wrapper data from metadata. Currently, this consists of the RIFF +// header and trailer that wav files contain around the audio data but could +// be used for other formats as well. Because WavPack files contain all the +// information required for decoding and playback, this data can probably +// be ignored except when an exact wavefile restoration is needed. + +int read_wrapper_data (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + wpmd->byte_length); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, wpmd->data, wpmd->byte_length); + wpc->wrapper_bytes += wpmd->byte_length; + } + + return TRUE; +} + +#ifdef UNPACK + +// This monster actually unpacks the WavPack bitstream(s) into the specified +// buffer as 32-bit integers or floats (depending on orignal 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_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_id0 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_id1 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_id2 (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; + + if (wps->sample_index + sample_count > wps->wphdr.block_index + wps->wphdr.block_samples) + sample_count = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; + + if (wps->mute_error) { + memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8)); + wps->sample_index += sample_count; + return sample_count; + } + + if ((flags & HYBRID_FLAG) && !wpc->wvc_flag) + mute_limit *= 2; + + ///////////////// handle version 4 lossless mono data ///////////////////// + + if (!(flags & HYBRID_FLAG) && (flags & MONO_DATA)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + if ((read_word = get_word_lossless (wps, 0)) == 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; + } + + if (labs (read_word) > mute_limit) + break; + + m = (m + 1) & (MAX_TERM - 1); + crc = crc * 3 + read_word; + *bptr++ = read_word; + } + + //////////////// handle version 4 lossless stereo data //////////////////// + + else if (!wpc->wvc_flag && !(flags & MONO_DATA)) { + int32_t *eptr = buffer + (sample_count * 2); + + i = sample_count; + + if (flags & HYBRID_FLAG) { + 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 = (bptr - buffer) / 2; + break; + } + } + else + for (bptr = buffer; bptr < eptr; bptr += 2) + if ((bptr [0] = get_word_lossless (wps, 0)) == WORD_EOF || + (bptr [1] = get_word_lossless (wps, 1)) == WORD_EOF) { + i = (bptr - buffer) / 2; + break; + } + +#ifdef FAST_DECODE + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (((flags & MAG_MASK) >> MAG_LSB) >= 16) + decorr_stereo_pass (dpp, buffer, sample_count); + else if (dpp->delta > 2) + decorr_stereo_pass_i (dpp, buffer, sample_count); + else if (dpp->delta == 2) + decorr_stereo_pass_id2 (dpp, buffer, sample_count); + else if (dpp->delta == 1) + decorr_stereo_pass_id1 (dpp, buffer, sample_count); + else + decorr_stereo_pass_id0 (dpp, buffer, sample_count); +#else + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + decorr_stereo_pass (dpp, buffer, sample_count); +#endif + + if (flags & JOINT_STEREO) + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [0] += (bptr [1] -= (bptr [0] >> 1)); + + if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { + i = (bptr - buffer) / 2; + break; + } + + crc = (crc * 3 + bptr [0]) * 3 + bptr [1]; + } + else + for (bptr = buffer; bptr < eptr; bptr += 2) { + if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { + i = (bptr - buffer) / 2; + break; + } + + crc = (crc * 3 + bptr [0]) * 3 + bptr [1]; + } + + m = sample_count & (MAX_TERM - 1); + } + + //////////////// handle version 4 lossy/hybrid 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 (wpc->wvc_flag) { + 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 * 3 + read_word; + +#ifdef LOSSY_MUTE + if (labs (read_word) > mute_limit) + break; +#endif + *bptr++ = read_word; + } + + //////////////// handle version 4 lossy/hybrid stereo data //////////////// + + else if (wpc->wvc_flag && !(flags & MONO_DATA)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t left, right, left_c, right_c, left2, right2; + + 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; + } + +#ifdef LOSSY_MUTE + if (labs (left) > mute_limit || labs (right) > mute_limit) + break; +#endif + crc = (crc * 3 + left) * 3 + right; + *bptr++ = left; + *bptr++ = right; + } + + 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)) + float_normalize (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; +} + +static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + 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] = apply_weight (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + + dpp->samples_A [k] = apply_weight (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [k] = apply_weight (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [k]; + 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) { + 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]); + bptr [0] = sam_A; + dpp->samples_A [0] = bptr [1] + apply_weight (dpp->weight_B, sam_A); + update_weight_clip (dpp->weight_B, dpp->delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + 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 [1] = sam_B; + dpp->samples_B [0] = bptr [0] + apply_weight (dpp->weight_A, sam_B); + update_weight_clip (dpp->weight_A, dpp->delta, sam_B, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + 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; + } +} + +#ifdef FAST_DECODE + +static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + 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] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + + dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [k]; + 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) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + bptr [0] = sam_A; + dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam_A); + update_weight_clip (dpp->weight_B, dpp->delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [1] = sam_B; + dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam_B); + update_weight_clip (dpp->weight_A, dpp->delta, sam_B, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight_i (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_i (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; + } +} + +static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + 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] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + + dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d2 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d2 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [k]; + 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) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + bptr [0] = sam_A; + dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam_A); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [1] = sam_B; + dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam_B); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_B, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip_d2 (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; + } +} + +static void decorr_stereo_pass_id1 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d1 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d1 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + 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] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d1 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d1 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [0]; + bptr [1] = dpp->samples_B [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + + dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam_A) + bptr [0]; + dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam_B) + bptr [1]; + + update_weight_d1 (dpp->weight_A, dpp->delta, sam_A, bptr [0]); + update_weight_d1 (dpp->weight_B, dpp->delta, sam_B, bptr [1]); + + bptr [0] = dpp->samples_A [k]; + 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) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip_d1 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + bptr [0] = sam_A; + dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam_A); + update_weight_clip_d1 (dpp->weight_B, dpp->delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip_d1 (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [1] = sam_B; + dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam_B); + update_weight_clip_d1 (dpp->weight_A, dpp->delta, sam_B, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip_d1 (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip_d1 (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; + } +} + +static void decorr_stereo_pass_id0 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2), sam_A, sam_B; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = bptr [0] += apply_weight_i (dpp->weight_A, sam_A); + dpp->samples_B [0] = bptr [1] += apply_weight_i (dpp->weight_B, sam_B); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + 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] = bptr [0] += apply_weight_i (dpp->weight_A, sam_A); + dpp->samples_B [0] = bptr [1] += apply_weight_i (dpp->weight_B, sam_B); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + dpp->samples_A [k] = bptr [0] += apply_weight_i (dpp->weight_A, dpp->samples_A [m]); + dpp->samples_B [k] = bptr [1] += apply_weight_i (dpp->weight_B, dpp->samples_B [m]); + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [0] += apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + dpp->samples_A [0] = bptr [1] += apply_weight_i (dpp->weight_B, bptr [0]); + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [1] += apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + dpp->samples_B [0] = bptr [0] += apply_weight_i (dpp->weight_A, bptr [1]); + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [0] += apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + dpp->samples_A [0] = bptr [1] += apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + dpp->samples_B [0] = bptr [0]; + } + + break; + } +} + +#endif + +// 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) && !wpc->wvc_flag; + 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: + 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; +} + +#endif diff --git a/Libraries/WavPack/Files/unpack3.c b/Libraries/WavPack/Files/unpack3.c index 8f8e0c5d0..10a77bd3a 100644 --- a/Libraries/WavPack/Files/unpack3.c +++ b/Libraries/WavPack/Files/unpack3.c @@ -1,2010 +1,2010 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// unpack3.c - -// This module provides unpacking for 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 documenation is provided in the version -// 3.97 source code. - -#include -#include -#include -#include - -#include "wavpack.h" -#include "unpack3.h" - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -#endif - -static void unpack_init3 (WavpackStream3 *wps); -static int bs_open_read3 (Bitstream3 *bs, stream_reader *reader, void *id); -static void bs_close_read3 (Bitstream3 *bs); -#ifdef SEEKING -static void bs_restore3 (Bitstream3 *bs); -#endif - -// 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; - - wpc->stream3 = wps = (WavpackStream3 *) malloc (sizeof (WavpackStream3)); - CLEAR (*wps); - - if (wpc->reader->read_bytes (wpc->wv_in, &RiffChunkHeader, sizeof (RiffChunkHeader)) != - sizeof (RiffChunkHeader)) { - 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 = 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)) { - strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - else { - if (wpc->open_flags & OPEN_WRAPPER) { - wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (ChunkHeader)); - memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &ChunkHeader, sizeof (ChunkHeader)); - wpc->wrapper_bytes += sizeof (ChunkHeader); - } - - little_endian_to_native (&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)) { - strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - else if (wpc->open_flags & OPEN_WRAPPER) { - wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (wavhdr)); - memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &wavhdr, sizeof (wavhdr)); - wpc->wrapper_bytes += sizeof (wavhdr); - } - - little_endian_to_native (&wavhdr, WaveHeader3Format); - - if (ChunkHeader.ckSize > sizeof (wavhdr)) { - uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1 - sizeof (wavhdr)) & ~1L; - - if (wpc->open_flags & OPEN_WRAPPER) { - wpc->wrapper_data = 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 { - uchar *temp = malloc (bytes_to_skip); - wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); - free (temp); - } - } - } - else if (!strncmp (ChunkHeader.ckID, "data", 4)) { - wpc->total_samples = ChunkHeader.ckSize / wavhdr.NumChannels / - ((wavhdr.BitsPerSample > 16) ? 3 : 2); - - break; - } - else if ((ChunkHeader.ckSize + 1) & ~1L) { - uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1) & ~1L; - - if (wpc->open_flags & OPEN_WRAPPER) { - wpc->wrapper_data = 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 { - uchar *temp = malloc (bytes_to_skip); - wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); - free (temp); - } - } - } - } - } - else { - strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - if (wpc->reader->read_bytes (wpc->wv_in, &wphdr, 10) != 10) { - 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)) { - 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)) { - strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - little_endian_to_native (&wphdr, WavpackHeader3Format); - - // make sure this is a version we know about - - if (strncmp (wphdr.ckID, "wvpk", 4) || wphdr.version < 1 || wphdr.version > 3) { - 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)))) { - 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 = 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; - - 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) { -#ifdef SEEKING - if (wps->unpack_data) - free (wps->unpack_data); -#endif - if (wps->wphdr.flags & WVC_FLAG) - bs_close_read3 (&wps->wvcbits); - - bs_close_read3 (&wps->wvbits); - - free (wps); - } -} - -static void bs_read3 (Bitstream3 *bs) -{ - uint32_t bytes_read; - - bytes_read = bs->reader->read_bytes (bs->id, bs->buf, bs->bufsiz); - bs->end = bs->buf + bytes_read; - bs->fpos += bytes_read; - - if (bs->end == bs->buf) { - memset (bs->buf, -1, bs->bufsiz); - bs->end += bs->bufsiz; - } - - bs->ptr = bs->buf; -} - -// Open the specified BitStream and associate with the specified file. The -// "bufsiz" field of the structure must be preset with the desired buffer -// size and the file's read pointer must be set to where the desired bit -// data is located. A return value of TRUE indicates an error in -// allocating buffer space. - -static int bs_open_read3 (Bitstream3 *bs, stream_reader *reader, void *id) -{ - bs->fpos = (bs->reader = reader)->get_pos (bs->id = id); - - if (!bs->buf) - bs->buf = (uchar *) malloc (bs->bufsiz); - - bs->end = bs->buf + bs->bufsiz; - bs->ptr = bs->end - 1; - bs->sr = bs->bc = 0; - bs->error = bs->buf ? 0 : 1; - bs->wrap = bs_read3; - return bs->error; -} - -#ifdef SEEKING - -// 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. - -void bs_restore3 (Bitstream3 *bs) -{ - uint32_t bytes_to_read = 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 - -// This function is called to release any resources used by the BitStream -// and position the file pointer to the first byte past the read bits. - -static void bs_close_read3 (Bitstream3 *bs) -{ - if (bs->buf) { - free (bs->buf); - CLEAR (*bs); - } -} - -static uint32_t bs_unused_bytes (Bitstream3 *bs) -{ - if (bs->bc < 8) { - bs->bc += 8; - bs->ptr++; - } - - return bs->end - bs->ptr; -} - -static uchar *bs_unused_data (Bitstream3 *bs) -{ - if (bs->bc < 8) { - bs->bc += 8; - bs->ptr++; - } - - return bs->ptr; -} - -#ifdef UNPACK - -//////////////////////////////// local macros ///////////////////////////////// - -#define apply_weight_n(bits, weight, sample) ((weight * sample + (1 << (bits - 1))) >> bits) - -#define update_weight_n(bits, weight, source, result) \ - if (source && result) { \ - if ((source ^ result) >= 0) { if (weight++ == (1 << bits)) weight--; } \ - else if (weight-- == min_weight) weight++; \ - } - -#define apply_weight24(weight, sample) (((((sample & 0xffff) * weight) >> 7) + \ - (((sample & ~0xffff) >> 7) * weight) + 1) >> 1) - -#define update_weight2(weight, source, result) \ - if (source && result) { \ - if ((source ^ result) >= 0) { if (weight++ == 256) weight--; } \ - else if (weight-- == min_weight) weight++; \ - } - -//////////////////////////////// local tables /////////////////////////////// - -// These three tables specify the characteristics of the decorrelation filters. -// Each term represents one layer of the sequential filter, where positive -// values indicate the relative sample involved from the same channel (1=prev) -// while -1 and -2 indicate cross channel decorrelation (in stereo only). The -// "simple_terms" table is no longer used for writing, but is kept for older -// file decoding. - -static const char extreme_terms [] = { 1,1,1,2,4,-1,1,2,3,6,-2,8,5,7,4,1,2,3 }; -static const char default_terms [] = { 1,1,1,-1,2,1,-2 }; -static const char simple_terms [] = { 1,1,1,1 }; - -// This function initializes everything required to unpack WavPack -// bitstreams and must be called before any unpacking is performed. Note -// that the (WavpackHeader3 *) in the WavpackStream3 struct must be valid. - -static void init_words3 (WavpackStream3 *wps); - -static void unpack_init3 (WavpackStream3 *wps) -{ - int flags = wps->wphdr.flags; - struct decorr_pass *dpp; - int ti; - - CLEAR (wps->decorr_passes); - CLEAR (wps->dc); - - if (flags & EXTREME_DECORR) { - for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (extreme_terms); ti++) - if (extreme_terms [sizeof (extreme_terms) - ti - 1] > 0 || (flags & CROSS_DECORR)) - dpp++->term = extreme_terms [sizeof (extreme_terms) - ti - 1]; - } - else if (flags & NEW_DECORR_FLAG) { - for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (default_terms); ti++) - if (default_terms [sizeof (default_terms) - ti - 1] > 0 || (flags & CROSS_DECORR)) - dpp++->term = default_terms [sizeof (default_terms) - ti - 1]; - } - else - for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (simple_terms); ti++) - dpp++->term = simple_terms [sizeof (simple_terms) - ti - 1]; - - wps->num_terms = dpp - wps->decorr_passes; - init_words3 (wps); -} - -#ifdef SEEKING - -#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); } - -// This function returns the size (in bytes) required to save the unpacking -// context. Note that the (WavpackHeader3 *) in the WavpackStream3 struct -// must be valid. - -static int unpack_size (WavpackStream3 *wps) -{ - int flags = wps->wphdr.flags, byte_sum = 0, tcount; - struct decorr_pass *dpp; - - byte_sum += sizeof (wps->wvbits); - - if (flags & WVC_FLAG) - byte_sum += sizeof (wps->wvcbits); - - if (wps->wphdr.version == 3) { - if (wps->wphdr.bits) - byte_sum += sizeof (wps->w4); - else - byte_sum += sizeof (wps->w1); - - byte_sum += sizeof (wps->w3) + sizeof (wps->dc.crc); - } - else - byte_sum += sizeof (wps->w2); - - if (wps->wphdr.bits) - byte_sum += sizeof (wps->dc.error); - else - byte_sum += sizeof (wps->dc.sum_level) + sizeof (wps->dc.left_level) + - sizeof (wps->dc.right_level) + sizeof (wps->dc.diff_level); - - if (flags & OVER_20) - byte_sum += sizeof (wps->dc.last_extra_bits) + sizeof (wps->dc.extra_bits_count); - - if (!(flags & EXTREME_DECORR)) { - byte_sum += sizeof (wps->dc.sample); - byte_sum += sizeof (wps->dc.weight); - } - - if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - if (dpp->term > 0) { - byte_sum += sizeof (dpp->samples_A [0]) * dpp->term; - byte_sum += sizeof (dpp->weight_A); - - if (!(flags & MONO_FLAG)) { - byte_sum += sizeof (dpp->samples_B [0]) * dpp->term; - byte_sum += sizeof (dpp->weight_B); - } - } - else { - byte_sum += sizeof (dpp->samples_A [0]) + sizeof (dpp->samples_B [0]); - byte_sum += sizeof (dpp->weight_A) + sizeof (dpp->weight_B); - } - - return byte_sum; -} - -// This function saves the unpacking context at the specified pointer and -// returns the updated pointer. The actual amount of data required can be -// determined beforehand by calling unpack_size() but must be allocated by -// the caller. - -static void *unpack_save (WavpackStream3 *wps, void *destin) -{ - int flags = wps->wphdr.flags, tcount; - struct decorr_pass *dpp; - - SAVE (destin, wps->wvbits); - - if (flags & WVC_FLAG) - SAVE (destin, wps->wvcbits); - - if (wps->wphdr.version == 3) { - if (wps->wphdr.bits) { - SAVE (destin, wps->w4); - } - else { - SAVE (destin, wps->w1); - } - - SAVE (destin, wps->w3); - SAVE (destin, wps->dc.crc); - } - else - SAVE (destin, wps->w2); - - if (wps->wphdr.bits) { - SAVE (destin, wps->dc.error); - } - else { - SAVE (destin, wps->dc.sum_level); - SAVE (destin, wps->dc.left_level); - SAVE (destin, wps->dc.right_level); - SAVE (destin, wps->dc.diff_level); - } - - if (flags & OVER_20) { - SAVE (destin, wps->dc.last_extra_bits); - SAVE (destin, wps->dc.extra_bits_count); - } - - if (!(flags & EXTREME_DECORR)) { - SAVE (destin, wps->dc.sample); - SAVE (destin, wps->dc.weight); - } - - 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; - - SAVE (destin, dpp->weight_A); - - while (count--) { - SAVE (destin, dpp->samples_A [index]); - index = (index + 1) & (MAX_TERM - 1); - } - - if (!(flags & MONO_FLAG)) { - count = dpp->term; - index = wps->dc.m; - - SAVE (destin, dpp->weight_B); - - while (count--) { - SAVE (destin, dpp->samples_B [index]); - index = (index + 1) & (MAX_TERM - 1); - } - } - } - else { - SAVE (destin, dpp->weight_A); - SAVE (destin, dpp->weight_B); - SAVE (destin, dpp->samples_A [0]); - SAVE (destin, dpp->samples_B [0]); - } - - return destin; -} - -// 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; - uchar *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 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 / ((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; -} - - -#endif - -// This monster actually unpacks the WavPack bitstream(s) into the specified -// buffer as longs, and serves as an extension to WavpackUnpackSamples(). -// Note that WavPack files created prior to version 4.0 could only contain 16 -// or 24 bit values, and these values are right-justified in the 32-bit values. -// So, if the original file contained 16-bit values, then the range of the -// returned longs would be +/- 32K. 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. - -static int32_t FASTCALL get_word1 (WavpackStream3 *wps, int chan); -static int32_t FASTCALL get_old_word1 (WavpackStream3 *wps, int chan); -static int32_t FASTCALL get_word2 (WavpackStream3 *wps, int chan); -static int32_t FASTCALL get_word3 (WavpackStream3 *wps, int chan); -static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *correction); - -int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count) -{ - WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; - int shift = wps->wphdr.shift, flags = wps->wphdr.flags, min_weight = 0, m = wps->dc.m, tcount; -#ifdef SEEKING - int points_index = wps->sample_index / ((wpc->total_samples >> 8) + 1); -#endif - int32_t min_value, max_value, min_shifted, max_shifted; - int32_t correction [2], crc = wps->dc.crc; - struct decorr_pass *dpp; - int32_t read_word, *bptr; - int32_t sample [2] [2]; - int weight [2] [1]; - uint i; - - if (wps->sample_index + sample_count > wpc->total_samples) - sample_count = wpc->total_samples - wps->sample_index; - - if (!sample_count) - return 0; - - if (!wps->sample_index) { - unpack_init3 (wps); - - bs_open_read3 (&wps->wvbits, wpc->reader, wpc->wv_in); - - if (wpc->wvc_flag) - bs_open_read3 (&wps->wvcbits, wpc->reader, wpc->wvc_in); - } - -#ifdef SEEKING - if (!wps->index_points [points_index].saved) { - - if (!wps->unpack_data) - wps->unpack_data = (uchar *) malloc (256 * (wps->unpack_size = unpack_size (wps))); - - wps->index_points [points_index].sample_index = wps->sample_index; - unpack_save (wps, wps->unpack_data + points_index * wps->unpack_size); - wps->index_points [points_index].saved = TRUE; - } -#endif - - memcpy (sample, wps->dc.sample, sizeof (sample)); - memcpy (weight, wps->dc.weight, sizeof (weight)); - - if (wps->wphdr.bits) { - if (flags & (NEW_DECORR_FLAG | EXTREME_DECORR)) - min_weight = -256; - } - else - if (flags & NEW_DECORR_FLAG) - min_weight = (flags & EXTREME_DECORR) ? -512 : -256; - - if (flags & BYTES_3) { - min_shifted = (min_value = -8388608 >> shift) << shift; - max_shifted = (max_value = 8388607 >> shift) << shift; - } - else { - min_shifted = (min_value = -32768 >> shift) << shift; - max_shifted = (max_value = 32767 >> shift) << shift; - } - - ///////////////// handle version 3 lossless mono data ///////////////////// - - if (wps->wphdr.version == 3 && !wps->wphdr.bits && (flags & MONO_FLAG)) { - if (flags & FAST_FLAG) { - if (flags & OVER_20) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t temp; - - if ((read_word = get_word3 (wps, 0)) == WORD_EOF) - break; - - sample [0] [0] += sample [0] [1] += read_word; - getbits (&temp, 4, &wps->wvbits); - crc = crc * 3 + (temp = (temp & 0xf) + (sample [0] [0] << 4)); - *bptr++ = temp; - } - else - for (bptr = buffer, i = 0; i < sample_count; ++i) { - if ((read_word = get_word3 (wps, 0)) == WORD_EOF) - break; - - crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); - *bptr++ = sample [0] [0] << shift; - } - } - else if (flags & HIGH_FLAG) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t temp; - - if (flags & NEW_HIGH_FLAG) { - if ((read_word = get_word1 (wps, 0)) == WORD_EOF) - break; - } - else { - if ((read_word = get_old_word1 (wps, 0)) == WORD_EOF) - break; - } - - if (flags & EXTREME_DECORR) - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { - int32_t sam = dpp->samples_A [m]; - - temp = apply_weight_n (9, dpp->weight_A, sam) + read_word; - update_weight_n (9, dpp->weight_A, sam, read_word); - dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; - } - else - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { - int32_t sam = dpp->samples_A [m]; - - temp = apply_weight_n (8, dpp->weight_A, sam) + read_word; - update_weight_n (8, dpp->weight_A, sam, read_word); - dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; - } - - m = (m + 1) & (MAX_TERM - 1); - - if (flags & OVER_20) { - if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { - getbits (&temp, 4, &wps->wvbits); - - if ((temp &= 0xf) != wps->dc.last_extra_bits) { - wps->dc.last_extra_bits = temp; - wps->dc.extra_bits_count = 0; - } - else - ++wps->dc.extra_bits_count; - } - - crc = crc * 3 + (temp = wps->dc.last_extra_bits + (read_word << 4)); - *bptr++ = temp; - } - else { - crc = crc * 3 + read_word; - *bptr++ = read_word << shift; - } - } - else - for (bptr = buffer, i = 0; i < sample_count; ++i) { - - int32_t temp; - - if ((read_word = get_word3 (wps, 0)) == WORD_EOF) - break; - - temp = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; - - if ((sample [0] [1] >= 0) == (read_word > 0)) { - if (weight [0] [0]++ == 256) - weight [0] [0]--; - } - else if (weight [0] [0]-- == 0) - weight [0] [0]++; - - sample [0] [0] += (sample [0] [1] = temp - sample [0] [0]); - - if (flags & OVER_20) { - if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { - getbits (&temp, 4, &wps->wvbits); - - if ((temp &= 0xf) != wps->dc.last_extra_bits) { - wps->dc.last_extra_bits = temp; - wps->dc.extra_bits_count = 0; - } - else - ++wps->dc.extra_bits_count; - } - - crc = crc * 3 + (*bptr++ = temp = wps->dc.last_extra_bits + (sample [0] [0] << 4)); - } - else { - crc = crc * 3 + sample [0] [0]; - *bptr++ = sample [0] [0] << shift; - } - } - } - - //////////////// handle version 3 lossless stereo data //////////////////// - - else if (wps->wphdr.version == 3 && !wps->wphdr.bits && !(flags & MONO_FLAG)) { - int32_t left_level = wps->dc.left_level, right_level = wps->dc.right_level; - int32_t sum_level = wps->dc.sum_level, diff_level = wps->dc.diff_level; - - if (flags & FAST_FLAG) { - if (flags & OVER_20) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t sum, diff, temp; - - read_word = get_word3 (wps, 0); - - if (read_word == WORD_EOF) - break; - - sum = (read_word << 1) | ((diff = get_word3 (wps, 1)) & 1); - sample [0] [0] += sample [0] [1] += ((sum + diff) >> 1); - sample [1] [0] += sample [1] [1] += ((sum - diff) >> 1); - getbits (&temp, 8, &wps->wvbits); - crc = crc * 3 + (*bptr++ = (sample [0] [0] << 4) + ((temp >> 4) & 0xf)); - crc = crc * 3 + (*bptr++ = (sample [1] [0] << 4) + (temp & 0xf)); - } - else - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t sum, diff; - - read_word = get_word3 (wps, 0); - - if (read_word == WORD_EOF) - break; - - sum = (read_word << 1) | ((diff = get_word3 (wps, 1)) & 1); - sample [0] [1] += ((sum + diff) >> 1); - sample [1] [1] += ((sum - diff) >> 1); - crc = crc * 3 + (sample [0] [0] += sample [0] [1]); - crc = crc * 3 + (sample [1] [0] += sample [1] [1]); - *bptr++ = sample [0] [0] << shift; - *bptr++ = sample [1] [0] << shift; - } - } - else if (flags & HIGH_FLAG) { - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t sum, left, right, diff, left2, right2, extra_bits, next_word; - - if (flags & CROSS_DECORR) { - left = get_word1 (wps, 0); - - if (left == WORD_EOF) - break; - - right = get_word1 (wps, 1); - } - else { - if (flags & NEW_HIGH_FLAG) { - read_word = get_word1 (wps, 0); - - if (read_word == WORD_EOF) - break; - - next_word = get_word1 (wps, 1); - - if (right_level > left_level) { - if (left_level + right_level < sum_level + diff_level && right_level < diff_level) { - sum = (right = read_word) + (left = next_word); - diff = left - right; - } - else { - diff = read_word; - - if (sum_level < left_level) { - sum = (next_word << 1) | (diff & 1); - left = (sum + diff) >> 1; - right = (sum - diff) >> 1; - } - else - sum = left + (right = (left = next_word) - diff); - } - } - else { - if (left_level + right_level < sum_level + diff_level && left_level < diff_level) { - sum = (left = read_word) + (right = next_word); - diff = left - right; - } - else { - diff = read_word; - - if (sum_level < right_level) { - sum = (next_word << 1) | (diff & 1); - left = (sum + diff) >> 1; - right = (sum - diff) >> 1; - } - else - sum = (left = diff + (right = next_word)) + right; - } - } - } - else { - read_word = get_old_word1 (wps, 0); - - if (read_word == WORD_EOF) - break; - - next_word = get_old_word1 (wps, 1); - - if (sum_level <= right_level && sum_level <= left_level) { - sum = (next_word << 1) | (read_word & 1); - left = (sum + read_word) >> 1; - right = (sum - read_word) >> 1; - } - else if (left_level <= right_level) - sum = left + (right = (left = next_word) - read_word); - else - sum = right + (left = read_word + (right = next_word)); - - diff = left - right; - } - - sum_level = sum_level - (sum_level >> 8) + labs (sum >> 1); - left_level = left_level - (left_level >> 8) + labs (left); - right_level = right_level - (right_level >> 8) + labs (right); - diff_level = diff_level - (diff_level >> 8) + labs (diff); - - if (flags & JOINT_STEREO) { - left = diff; - right = sum >> 1; - } - } - - if (flags & EXTREME_DECORR) { - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - if (dpp->term > 0) { - int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; - int k = (m + dpp->term) & (MAX_TERM - 1); - - left2 = apply_weight_n (9, dpp->weight_A, sam_A) + left; - right2 = apply_weight_n (9, dpp->weight_B, sam_B) + right; - - update_weight_n (9, dpp->weight_A, sam_A, left); - update_weight_n (9, dpp->weight_B, sam_B, right); - - dpp->samples_A [k] = left = left2; - dpp->samples_B [k] = right = right2; - } - else if (dpp->term == -1) { - left2 = left + apply_weight_n (9, dpp->weight_A, dpp->samples_A [0]); - update_weight_n (9, dpp->weight_A, dpp->samples_A [0], left); - left = left2; - right2 = right + apply_weight_n (9, dpp->weight_B, left); - update_weight_n (9, dpp->weight_B, left, right); - dpp->samples_A [0] = right = right2; - } - else { - right2 = right + apply_weight_n (9, dpp->weight_A, dpp->samples_A [0]); - update_weight_n (9, dpp->weight_A, dpp->samples_A [0], right); - right = right2; - left2 = left + apply_weight_n (9, dpp->weight_B, right); - update_weight_n (9, dpp->weight_B, right, left); - dpp->samples_A [0] = left = left2; - } - } - else { - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - if (dpp->term > 0) { - int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; - int k = (m + dpp->term) & (MAX_TERM - 1); - - left2 = apply_weight_n (8, dpp->weight_A, sam_A) + left; - right2 = apply_weight_n (8, dpp->weight_B, sam_B) + right; - - update_weight_n (8, dpp->weight_A, sam_A, left); - update_weight_n (8, dpp->weight_B, sam_B, right); - - dpp->samples_A [k] = left = left2; - dpp->samples_B [k] = right = right2; - } - else if (dpp->term == -1) { - left2 = left + apply_weight_n (8, dpp->weight_A, dpp->samples_A [0]); - update_weight_n (8, dpp->weight_A, dpp->samples_A [0], left); - left = left2; - right2 = right + apply_weight_n (8, dpp->weight_B, left); - update_weight_n (8, dpp->weight_B, left, right); - dpp->samples_A [0] = right = right2; - } - else { - right2 = right + apply_weight_n (8, dpp->weight_A, dpp->samples_A [0]); - update_weight_n (8, dpp->weight_A, dpp->samples_A [0], right); - right = right2; - left2 = left + apply_weight_n (8, dpp->weight_B, right); - update_weight_n (8, dpp->weight_B, right, left); - dpp->samples_A [0] = left = left2; - } - } - - m = (m + 1) & (MAX_TERM - 1); - - if (flags & JOINT_STEREO) { - sum = (right << 1) | ((diff = left) & 1); - right = (sum - diff) >> 1; - left = (sum + diff) >> 1; - } - - if (flags & OVER_20) { - if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { - getbits (&extra_bits, 8, &wps->wvbits); - - if ((extra_bits &= 0xff) != wps->dc.last_extra_bits) { - wps->dc.last_extra_bits = extra_bits; - wps->dc.extra_bits_count = 0; - } - else - ++wps->dc.extra_bits_count; - } - - crc = crc * 3 + (*bptr++ = left = (left << 4) + (wps->dc.last_extra_bits >> 4)); - crc = crc * 3 + (*bptr++ = right = (right << 4) + (wps->dc.last_extra_bits & 0xf)); - } - else { - crc = crc * 9 + left * 3 + right; - *bptr++ = left << shift; - *bptr++ = right << shift; - } - } - } - else - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t sum, left, right, left2, right2, extra_bits; - - read_word = get_word3 (wps, 0); - - if (read_word == WORD_EOF) - break; - - if (sum_level <= right_level && sum_level <= left_level) { - sum = (get_word3 (wps, 1) << 1) | (read_word & 1); - left = (sum + read_word) >> 1; - right = (sum - read_word) >> 1; - } - else if (left_level <= right_level) - sum = left + (right = (left = get_word3 (wps, 1)) - read_word); - else - sum = right + (left = read_word + (right = get_word3 (wps, 1))); - - sum_level = sum_level - (sum_level >> 8) + labs (sum >> 1); - left_level = left_level - (left_level >> 8) + labs (left); - right_level = right_level - (right_level >> 8) + labs (right); - - left2 = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + left; - right2 = sample [1] [0] + ((sample [1] [1] * weight [1] [0] + 128) >> 8) + right; - - if ((sample [0] [1] >= 0) == (left > 0)) { - if (weight [0] [0]++ == 256) - weight [0] [0]--; - } - else if (weight [0] [0]-- == 0) - weight [0] [0]++; - - if ((sample [1] [1] >= 0) == (right > 0)) { - if (weight [1] [0]++ == 256) - weight [1] [0]--; - } - else if (weight [1] [0]-- == 0) - weight [1] [0]++; - - sample [0] [0] += (sample [0] [1] = left2 - sample [0] [0]); - sample [1] [0] += (sample [1] [1] = right2 - sample [1] [0]); - - if (flags & OVER_20) { - if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { - getbits (&extra_bits, 8, &wps->wvbits); - - if ((extra_bits &= 0xff) != wps->dc.last_extra_bits) { - wps->dc.last_extra_bits = extra_bits; - wps->dc.extra_bits_count = 0; - } - else - ++wps->dc.extra_bits_count; - } - - crc = crc * 3 + (*bptr++ = left2 = (sample [0] [0] << 4) + (wps->dc.last_extra_bits >> 4)); - crc = crc * 3 + (*bptr++ = right2 = (sample [1] [0] << 4) + (wps->dc.last_extra_bits & 0xf)); - } - else { - crc = crc * 9 + sample [0] [0] * 3 + sample [1] [0]; - *bptr++ = sample [0] [0] << shift; - *bptr++ = sample [1] [0] << shift; - } - } - - wps->dc.left_level = left_level; - wps->dc.right_level = right_level; - wps->dc.sum_level = sum_level; - wps->dc.diff_level = diff_level; - } - - //////////////// handle version 3 lossy/hybrid mono data ////////////////// - - else if (wps->wphdr.version == 3 && wps->wphdr.bits && (flags & MONO_FLAG)) { - if (flags & FAST_FLAG) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - - if ((read_word = get_word3 (wps, 0)) == WORD_EOF) - break; - - crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); - - if (sample [0] [0] < min_value) - *bptr++ = min_shifted; - else if (sample [0] [0] > max_value) - *bptr++ = max_shifted; - else - *bptr++ = sample [0] [0] << shift; - } - else if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t temp; - - read_word = (flags & NEW_HIGH_FLAG) ? - get_word4 (wps, 0, correction) : get_word3 (wps, 0); - - if (read_word == WORD_EOF) - break; - - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { - int32_t sam = dpp->samples_A [m]; - - temp = apply_weight24 (dpp->weight_A, sam) + read_word; - update_weight2 (dpp->weight_A, sam, read_word); - dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; - } - - m = (m + 1) & (MAX_TERM - 1); - - if (flags & WVC_FLAG) { - if (flags & LOSSY_SHAPE) { - crc = crc * 3 + (read_word += correction [0] + wps->dc.error [0]); - wps->dc.error [0] = -correction [0]; - } - else - crc = crc * 3 + (read_word += correction [0]); - - *bptr++ = read_word << shift; - } - else { - crc = crc * 3 + read_word; - - if (read_word < min_value) - *bptr++ = min_shifted; - else if (read_word > max_value) - *bptr++ = max_shifted; - else - *bptr++ = read_word << shift; - } - } - else - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t new_sample; - - if ((read_word = get_word3 (wps, 0)) == WORD_EOF) - break; - - new_sample = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; - - if ((sample [0] [1] >= 0) == (read_word > 0)) { - if (weight [0] [0]++ == 256) - weight [0] [0]--; - } - else if (weight [0] [0]-- == 0) - weight [0] [0]++; - - sample [0] [1] = new_sample - sample [0] [0]; - crc = crc * 3 + (sample [0] [0] = new_sample); - - if (sample [0] [0] < min_value) - *bptr++ = min_shifted; - else if (sample [0] [0] > max_value) - *bptr++ = max_shifted; - else - *bptr++ = sample [0] [0] << shift; - } - } - - //////////////// handle version 3 lossy/hybrid stereo data //////////////// - - else if (wps->wphdr.version == 3 && wps->wphdr.bits && !(flags & MONO_FLAG)) { - if (flags & FAST_FLAG) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - - if ((read_word = get_word3 (wps, 0)) == WORD_EOF) - break; - - crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); - - if (sample [0] [0] < min_value) - *bptr++ = min_shifted; - else if (sample [0] [0] > max_value) - *bptr++ = max_shifted; - else - *bptr++ = sample [0] [0] << shift; - - crc = crc * 3 + (sample [1] [0] += sample [1] [1] += get_word3 (wps, 1)); - - if (sample [1] [0] < min_value) - *bptr++ = min_shifted; - else if (sample [1] [0] > max_value) - *bptr++ = max_shifted; - else - *bptr++ = sample [1] [0] << shift; - } - else if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t left, right, left2, right2, sum, diff; - - if (flags & NEW_HIGH_FLAG) { - left = get_word4 (wps, 0, correction); - right = get_word4 (wps, 1, correction + 1); - } - else { - left = get_word3 (wps, 0); - right = get_word3 (wps, 1); - } - - if (left == WORD_EOF) - break; - - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { - int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; - int k = (m + dpp->term) & (MAX_TERM - 1); - - left2 = apply_weight24 (dpp->weight_A, sam_A) + left; - update_weight2 (dpp->weight_A, sam_A, left); - dpp->samples_A [k] = left = left2; - - right2 = apply_weight24 (dpp->weight_B, sam_B) + right; - update_weight2 (dpp->weight_B, sam_B, right); - dpp->samples_B [k] = right = right2; - } - - m = (m + 1) & (MAX_TERM - 1); - - if (flags & WVC_FLAG) { - if (flags & LOSSY_SHAPE) { - left += correction [0] + wps->dc.error [0]; - right += correction [1] + wps->dc.error [1]; - wps->dc.error [0] = -correction [0]; - wps->dc.error [1] = -correction [1]; - } - else { - left += correction [0]; - right += correction [1]; - } - } - - if (flags & JOINT_STEREO) { - right = ((sum = (right << 1) | (left & 1)) - (diff = left)) >> 1; - left = (sum + diff) >> 1; - } - - crc = crc * 9 + left * 3 + right; - - if (flags & WVC_FLAG) { - *bptr++ = left << shift; - *bptr++ = right << shift; - } - else { - if (left < min_value) - *bptr++ = min_shifted; - else if (left > max_value) - *bptr++ = max_shifted; - else - *bptr++ = left << shift; - - if (right < min_value) - *bptr++ = min_shifted; - else if (right > max_value) - *bptr++ = max_shifted; - else - *bptr++ = right << shift; - } - } - else - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t new_sample; - - if ((read_word = get_word3 (wps, 0)) == WORD_EOF) - break; - - new_sample = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; - - if ((sample [0] [1] >= 0) == (read_word > 0)) { - if (weight [0] [0]++ == 256) - weight [0] [0]--; - } - else if (weight [0] [0]-- == 0) - weight [0] [0]++; - - sample [0] [1] = new_sample - sample [0] [0]; - crc = crc * 3 + (sample [0] [0] = new_sample); - - read_word = get_word3 (wps, 1); - new_sample = sample [1] [0] + ((sample [1] [1] * weight [1] [0] + 128) >> 8) + read_word; - - if ((sample [1] [1] >= 0) == (read_word > 0)) { - if (weight [1] [0]++ == 256) - weight [1] [0]--; - } - else if (weight [1] [0]-- == 0) - weight [1] [0]++; - - sample [1] [1] = new_sample - sample [1] [0]; - crc = crc * 3 + (sample [1] [0] = new_sample); - - if (sample [0] [0] < min_value) - *bptr++ = min_shifted; - else if (sample [0] [0] > max_value) - *bptr++ = max_shifted; - else - *bptr++ = sample [0] [0] << shift; - - if (sample [1] [0] < min_value) - *bptr++ = min_shifted; - else if (sample [1] [0] > max_value) - *bptr++ = max_shifted; - else - *bptr++ = sample [1] [0] << shift; - } - } - - //////////////////// finally, handle version 2 data /////////////////////// - - else if (wps->wphdr.version == 2 && (flags & MONO_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - if ((read_word = get_word2 (wps, 0)) == WORD_EOF) - break; - - sample [0] [0] += sample [0] [1] += read_word; - - if (wps->wphdr.bits) { - if (sample [0] [0] < min_value) - sample [0] [0] = min_value; - else if (sample [0] [0] > max_value) - sample [0] [0] = max_value; - } - - *bptr++ = sample [0] [0] << shift; - } - else if (wps->wphdr.version < 3 && !(flags & MONO_FLAG)) - for (bptr = buffer, i = 0; i < sample_count; ++i) { - int32_t sum, diff; - - read_word = get_word2 (wps, 0); - - if (read_word == WORD_EOF) - break; - - sum = (read_word << 1) | ((diff = get_word2 (wps, 1)) & 1); - sample [0] [0] += sample [0] [1] += ((sum + diff) >> 1); - sample [1] [0] += sample [1] [1] += ((sum - diff) >> 1); - - if (wps->wphdr.bits) { - if (sample [0] [0] < min_value) - sample [0] [0] = min_value; - else if (sample [0] [0] > max_value) - sample [0] [0] = max_value; - - if (sample [1] [0] < min_value) - sample [1] [0] = min_value; - else if (sample [1] [0] > max_value) - sample [1] [0] = max_value; - } - - *bptr++ = sample [0] [0] << shift; - *bptr++ = sample [1] [0] << shift; - } - - if (i && (wps->sample_index += i) == wpc->total_samples) { - - if (wps->wphdr.version == 3 && crc != (wpc->wvc_flag ? wps->wphdr.crc2 : wps->wphdr.crc)) - wpc->crc_errors++; - - if (wpc->open_flags & OPEN_WRAPPER) { - uchar *temp = malloc (1024); - uint32_t bcount; - - if (bs_unused_bytes (&wps->wvbits)) { - wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bs_unused_bytes (&wps->wvbits)); - memcpy (wpc->wrapper_data + wpc->wrapper_bytes, bs_unused_data (&wps->wvbits), bs_unused_bytes (&wps->wvbits)); - wpc->wrapper_bytes += bs_unused_bytes (&wps->wvbits); - } - - while (1) { - bcount = wpc->reader->read_bytes (wpc->wv_in, temp, sizeof (temp)); - - if (!bcount) - break; - - wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bcount); - memcpy (wpc->wrapper_data + wpc->wrapper_bytes, temp, bcount); - wpc->wrapper_bytes += bcount; - } - - free (temp); - - if (wpc->wrapper_bytes > 16) { - int c; - - for (c = 0; c < 16 && wpc->wrapper_data [c] == 0xff; ++c); - - if (c == 16) { - memcpy (wpc->wrapper_data, wpc->wrapper_data + 16, wpc->wrapper_bytes - 16); - wpc->wrapper_bytes -= 16; - } - else { - free (wpc->wrapper_data); - wpc->wrapper_data = NULL; - wpc->wrapper_bytes = 0; - } - } - } - } - - memcpy (wps->dc.sample, sample, sizeof (sample)); - memcpy (wps->dc.weight, weight, sizeof (weight)); - wps->dc.crc = crc; - wps->dc.m = m; - - return i; -} - -///////////////////////////// local table storage //////////////////////////// - -extern const uint32_t bitset []; -extern const uint32_t bitmask []; -extern const char nbits_table []; - -// This function initializes everything required to receive words with this -// module and must be called BEFORE any other function in this module. - -static void init_words3 (WavpackStream3 *wps) -{ - CLEAR (wps->w1); - CLEAR (wps->w2); - CLEAR (wps->w3); - CLEAR (wps->w4); - - if (wps->wphdr.flags & MONO_FLAG) - wps->w4.bitrate = wps->wphdr.bits - 768; - else - wps->w4.bitrate = (wps->wphdr.bits / 2) - 768; -} - -// This macro counts the number of bits that are required to specify the -// unsigned 32-bit value, counting from the LSB to the most significant bit -// that is set. Return range is 0 - 32. - -#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) \ - ) \ -) - -static int32_t FASTCALL get_word1 (WavpackStream3 *wps, int chan) -{ - uint32_t tmp1, tmp2, avalue; - uint ones_count; - int k; - - if ((wps->wphdr.flags & EXTREME_DECORR) && !(wps->wphdr.flags & OVER_20)) { - if (wps->w1.zeros_acc) { - if (--wps->w1.zeros_acc) - return 0; - } - else if (wps->w1.ave_level [0] [0] < 0x20 && wps->w1.ave_level [0] [1] < 0x20) { - int32_t mask; - int cbits; - - for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); - - if (cbits == 33) - return WORD_EOF; - - if (cbits < 2) - wps->w1.zeros_acc = cbits; - else { - for (mask = 1, wps->w1.zeros_acc = 0; --cbits; mask <<= 1) - if (getbit (&wps->wvbits)) - wps->w1.zeros_acc |= mask; - - wps->w1.zeros_acc |= mask; - } - - if (wps->w1.zeros_acc) - return 0; - } - } - - // count consecutive ones in bitstream, > 25 indicates error (or EOF) - - for (ones_count = 0; ones_count < 25 && getbit (&wps->wvbits); ++ones_count); - - if (ones_count == 25) - return WORD_EOF; - - k = (wps->w1.ave_level [0] [chan] + (wps->w1.ave_level [0] [chan] >> 3) + 0x40) >> 7; - k = count_bits (k); - - if (ones_count == 0) { - getbits (&avalue, k, &wps->wvbits); - avalue &= bitmask [k]; - } - else { - tmp1 = bitset [k]; - k = (wps->w1.ave_level [1] [chan] + (wps->w1.ave_level [1] [chan] >> 4) + 0x20) >> 6; - k = count_bits (k); - - if (ones_count == 1) { - getbits (&avalue, k, &wps->wvbits); - avalue &= bitmask [k]; - } - else { - tmp2 = bitset [k]; - - // If the ones count is exactly 24, then next 24 bits are literal - - if (ones_count == 24) { - getbits (&avalue, 24, &wps->wvbits); - avalue &= 0xffffff; - } - else { - k = (wps->w1.ave_level [2] [chan] + 0x10) >> 5; - k = count_bits (k); - getbits (&avalue, k, &wps->wvbits); - avalue = (avalue & bitmask [k]) + (bitset [k] * (ones_count - 2)); - } - - wps->w1.ave_level [2] [chan] -= ((wps->w1.ave_level [2] [chan] + 0x8) >> 4); - wps->w1.ave_level [2] [chan] += avalue; - avalue += tmp2; - } - - wps->w1.ave_level [1] [chan] -= ((wps->w1.ave_level [1] [chan] + 0x10) >> 5); - wps->w1.ave_level [1] [chan] += avalue; - avalue += tmp1; - } - - wps->w1.ave_level [0] [chan] -= ((wps->w1.ave_level [0] [chan] + 0x20) >> 6); - wps->w1.ave_level [0] [chan] += avalue; - - return (avalue && getbit (&wps->wvbits)) ? -(int32_t)avalue : avalue; -} - -#define NUM_SAMPLES 128 - -static int32_t FASTCALL get_old_word1 (WavpackStream3 *wps, int chan) -{ - uint32_t avalue; - uint bc; - int k; - - if (!wps->w1.index [chan]) { - - int guess_k = (wps->w1.ave_k [chan] + 128) >> 8, ones; - - for (ones = 0; ones < 72 && getbit (&wps->wvbits); ++ones); - - if (ones == 72) - return WORD_EOF; - - if (ones % 3 == 1) - wps->w1.k_value [chan] = guess_k - (ones / 3) - 1; - else - wps->w1.k_value [chan] = guess_k + ones - ((ones + 1) / 3); - - wps->w1.ave_k [chan] -= (wps->w1.ave_k [chan] + 0x10) >> 5; - wps->w1.ave_k [chan] += wps->w1.k_value [chan] << 3; - } - - if (++wps->w1.index [chan] == NUM_SAMPLES) - wps->w1.index [chan] = 0; - - k = wps->w1.k_value [chan]; - getbits (&avalue, k, &wps->wvbits); - - for (bc = 0; bc < 32 && getbit (&wps->wvbits); ++bc); - - if (bc == 32) - return WORD_EOF; - - avalue = (avalue & bitmask [k]) + bitset [k] * bc; - return (avalue && getbit (&wps->wvbits)) ? -(int32_t)avalue : avalue; -} - -static int32_t FASTCALL get_word2 (WavpackStream3 *wps, int chan) -{ - int cbits, delta_dbits, dbits; - int32_t value, mask = 1; - - cbits = 0; - - while (getbit (&wps->wvbits)) - if ((cbits += 2) == 50) - return WORD_EOF; - - if (getbit (&wps->wvbits)) - cbits++; - - if (cbits == 0) - delta_dbits = 0; - else if (cbits & 1) { - delta_dbits = (cbits + 1) / 2; - - if (wps->w2.last_delta_sign [chan] > 0) - delta_dbits *= -1; - - wps->w2.last_delta_sign [chan] = delta_dbits; - } - else { - delta_dbits = cbits / 2; - - if (wps->w2.last_delta_sign [chan] <= 0) - delta_dbits *= -1; - } - - dbits = (wps->w2.last_dbits [chan] += delta_dbits); - - if (dbits < 0 || dbits > 20) - return WORD_EOF; - - if (!dbits) - return 0L; - - if (wps->wphdr.bits) { - for (value = 1L << (dbits - 1); --dbits; mask <<= 1) - if (dbits < wps->wphdr.bits && getbit (&wps->wvbits)) - value |= mask; - } - else - for (value = 1L << (dbits - 1); --dbits; mask <<= 1) - if (getbit (&wps->wvbits)) - value |= mask; - - return getbit (&wps->wvbits) ? -(int32_t)value : value; -} - -static int32_t FASTCALL get_word3 (WavpackStream3 *wps, int chan) -{ - int cbits, delta_dbits, dbits; - int32_t value; - - for (cbits = 0; cbits < 72 && getbit (&wps->wvbits); ++cbits); - - if (cbits == 72) - return WORD_EOF; - - if (cbits || getbit (&wps->wvbits)) - ++cbits; - - if (!((cbits + 1) % 3)) - delta_dbits = (cbits + 1) / 3; - else - delta_dbits = -(cbits - cbits / 3); - - if (chan) { - dbits = (wps->w3.ave_dbits [1] >> 8) + 1 + delta_dbits; - wps->w3.ave_dbits [1] -= (wps->w3.ave_dbits [1] + 0x10) >> 5; - wps->w3.ave_dbits [1] += dbits << 3; - } - else { - dbits = (wps->w3.ave_dbits [0] >> 8) + 1 + delta_dbits; - wps->w3.ave_dbits [0] -= (wps->w3.ave_dbits [0] + 0x10) >> 5; - wps->w3.ave_dbits [0] += dbits << 3; - } - - if (dbits < 0 || dbits > 24) - return WORD_EOF; - - if (!dbits) - return 0L; - - if (wps->wphdr.bits && dbits > wps->wphdr.bits) { - getbits (&value, wps->wphdr.bits, &wps->wvbits); - - if (value & bitset [wps->wphdr.bits - 1]) - return -(int32_t)(value & bitmask [wps->wphdr.bits]) << (dbits - wps->wphdr.bits); - else - return ((value & bitmask [wps->wphdr.bits - 1]) | bitset [wps->wphdr.bits - 1]) << (dbits - wps->wphdr.bits); - } - else { - getbits (&value, dbits, &wps->wvbits); - - if (value & bitset [dbits - 1]) - return -(int32_t)(value & bitmask [dbits]); - else - return (value & bitmask [dbits - 1]) | bitset [dbits - 1]; - } -} - -static int FASTCALL _log2 (uint32_t avalue); - -static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *correction) -{ - uint32_t base, ones_count, avalue; - int32_t value, low, mid, high; - int bitcount; - - // count consecutive ones in bitstream, > 25 indicates error (or EOF) - - for (ones_count = 0; ones_count < 25 && getbit (&wps->wvbits); ++ones_count); - - if (ones_count == 25) - return WORD_EOF; - - // if the ones count is exactly 24, then we switch to non-unary method - - if (ones_count == 24) { - int32_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 += 24; - } - - if (!chan) { - int slow_log_0, slow_log_1, balance; - - if (wps->wphdr.flags & MONO_FLAG) { - wps->w4.bits_acc [0] += wps->w4.bitrate + _log2 (wps->w4.fast_level [0]) - _log2 (wps->w4.slow_level [0]) + (3 << 8); - - if (wps->w4.bits_acc [0] < 0) - wps->w4.bits_acc [0] = 0; - } - else { - slow_log_0 = _log2 (wps->w4.slow_level [0]); - slow_log_1 = _log2 (wps->w4.slow_level [1]); - - if (wps->wphdr.flags & JOINT_STEREO) - balance = (slow_log_1 - slow_log_0 + 257) >> 1; - else - balance = (slow_log_1 - slow_log_0 + 1) >> 1; - - wps->w4.bits_acc [0] += wps->w4.bitrate - balance + _log2 (wps->w4.fast_level [0]) - slow_log_0 + (3 << 8); - wps->w4.bits_acc [1] += wps->w4.bitrate + balance + _log2 (wps->w4.fast_level [1]) - slow_log_1 + (3 << 8); - - if (wps->w4.bits_acc [0] + wps->w4.bits_acc [1] < 0) - wps->w4.bits_acc [0] = wps->w4.bits_acc [1] = 0; - else if (wps->w4.bits_acc [0] < 0) { - wps->w4.bits_acc [1] += wps->w4.bits_acc [0]; - wps->w4.bits_acc [0] = 0; - } - else if (wps->w4.bits_acc [1] < 0) { - wps->w4.bits_acc [0] += wps->w4.bits_acc [1]; - wps->w4.bits_acc [1] = 0; - } - } - } - - base = (wps->w4.fast_level [chan] + 48) / 96; - bitcount = wps->w4.bits_acc [chan] >> 8; - wps->w4.bits_acc [chan] &= 0xff; - - if (!base) { - if (ones_count) - high = low = mid = (getbit (&wps->wvbits)) ? -(int32_t)ones_count : ones_count; - else - high = low = mid = 0; - } - else { - mid = (ones_count * 2 + 1) * base; - if (getbit (&wps->wvbits)) mid = -mid; - low = mid - base; - high = mid + base - 1; - - while (bitcount--) { - if (getbit (&wps->wvbits)) - mid = (high + (low = mid) + 1) >> 1; - else - mid = ((high = mid - 1) + low + 1) >> 1; - - if (high == low) - break; - } - } - - wps->w4.fast_level [chan] -= ((wps->w4.fast_level [chan] + 0x10) >> 5); - wps->w4.fast_level [chan] += (avalue = labs (mid)); - wps->w4.slow_level [chan] -= ((wps->w4.slow_level [chan] + 0x80) >> 8); - wps->w4.slow_level [chan] += avalue; - - if (bs_is_open (&wps->wvcbits)) { - - if (high != low) { - uint32_t maxcode = high - low; - int bitcount = count_bits (maxcode); - uint32_t extras = (1L << bitcount) - maxcode - 1; - - getbits (&avalue, bitcount - 1, &wps->wvcbits); - avalue &= bitmask [bitcount - 1]; - - if (avalue >= extras) { - avalue = (avalue << 1) - extras; - - if (getbit (&wps->wvcbits)) - ++avalue; - } - - value = (mid < 0) ? high - avalue : avalue + low; - - if (correction) - *correction = value - mid; - } - else if (correction) - *correction = 0; - } - - return mid; -} - -// This function calculates an approximate base-2 logarithm (with 8 bits of -// fraction) from the supplied value. Using logarithms makes comparing -// signal level values and calculating fractional bitrates much easier. - -static int FASTCALL _log2 (uint32_t avalue) -{ - int dbits; - - if ((avalue += avalue >> 9) < (1 << 8)) { - dbits = nbits_table [avalue]; - return (dbits << 8) + ((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) + ((avalue >> (dbits - 9)) & 0xff); - } -} - -#endif +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack3.c + +// This module provides unpacking for 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 documenation is provided in the version +// 3.97 source code. + +#include +#include +#include +#include + +#include "wavpack.h" +#include "unpack3.h" + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +static void unpack_init3 (WavpackStream3 *wps); +static int bs_open_read3 (Bitstream3 *bs, WavpackStreamReader *reader, void *id); +static void bs_close_read3 (Bitstream3 *bs); +#ifdef SEEKING +static void bs_restore3 (Bitstream3 *bs); +#endif + +// 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; + + wpc->stream3 = wps = (WavpackStream3 *) malloc (sizeof (WavpackStream3)); + CLEAR (*wps); + + if (wpc->reader->read_bytes (wpc->wv_in, &RiffChunkHeader, sizeof (RiffChunkHeader)) != + sizeof (RiffChunkHeader)) { + 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 = 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)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + else { + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (ChunkHeader)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &ChunkHeader, sizeof (ChunkHeader)); + wpc->wrapper_bytes += sizeof (ChunkHeader); + } + + little_endian_to_native (&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)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + else if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (wavhdr)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &wavhdr, sizeof (wavhdr)); + wpc->wrapper_bytes += sizeof (wavhdr); + } + + little_endian_to_native (&wavhdr, WaveHeader3Format); + + if (ChunkHeader.ckSize > sizeof (wavhdr)) { + uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1 - sizeof (wavhdr)) & ~1L; + + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = 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 { + uchar *temp = malloc (bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); + free (temp); + } + } + } + else if (!strncmp (ChunkHeader.ckID, "data", 4)) { + wpc->total_samples = ChunkHeader.ckSize / wavhdr.NumChannels / + ((wavhdr.BitsPerSample > 16) ? 3 : 2); + + break; + } + else if ((ChunkHeader.ckSize + 1) & ~1L) { + uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1) & ~1L; + + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = 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 { + uchar *temp = malloc (bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); + free (temp); + } + } + } + } + } + else { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wpc->reader->read_bytes (wpc->wv_in, &wphdr, 10) != 10) { + 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)) { + 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)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + little_endian_to_native (&wphdr, WavpackHeader3Format); + + // make sure this is a version we know about + + if (strncmp (wphdr.ckID, "wvpk", 4) || wphdr.version < 1 || wphdr.version > 3) { + 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)))) { + 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 = 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; + + 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) { +#ifdef SEEKING + if (wps->unpack_data) + free (wps->unpack_data); +#endif + if (wps->wphdr.flags & WVC_FLAG) + bs_close_read3 (&wps->wvcbits); + + bs_close_read3 (&wps->wvbits); + + free (wps); + } +} + +static void bs_read3 (Bitstream3 *bs) +{ + uint32_t bytes_read; + + bytes_read = bs->reader->read_bytes (bs->id, bs->buf, bs->bufsiz); + bs->end = bs->buf + bytes_read; + bs->fpos += bytes_read; + + if (bs->end == bs->buf) { + memset (bs->buf, -1, bs->bufsiz); + bs->end += bs->bufsiz; + } + + bs->ptr = bs->buf; +} + +// Open the specified BitStream and associate with the specified file. The +// "bufsiz" field of the structure must be preset with the desired buffer +// size and the file's read pointer must be set to where the desired bit +// data is located. A return value of TRUE indicates an error in +// allocating buffer space. + +static int bs_open_read3 (Bitstream3 *bs, WavpackStreamReader *reader, void *id) +{ + bs->fpos = (bs->reader = reader)->get_pos (bs->id = id); + + if (!bs->buf) + bs->buf = (uchar *) malloc (bs->bufsiz); + + bs->end = bs->buf + bs->bufsiz; + bs->ptr = bs->end - 1; + bs->sr = bs->bc = 0; + bs->error = bs->buf ? 0 : 1; + bs->wrap = bs_read3; + return bs->error; +} + +#ifdef SEEKING + +// 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. + +void bs_restore3 (Bitstream3 *bs) +{ + uint32_t bytes_to_read = 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 + +// This function is called to release any resources used by the BitStream +// and position the file pointer to the first byte past the read bits. + +static void bs_close_read3 (Bitstream3 *bs) +{ + if (bs->buf) { + free (bs->buf); + CLEAR (*bs); + } +} + +static uint32_t bs_unused_bytes (Bitstream3 *bs) +{ + if (bs->bc < 8) { + bs->bc += 8; + bs->ptr++; + } + + return bs->end - bs->ptr; +} + +static uchar *bs_unused_data (Bitstream3 *bs) +{ + if (bs->bc < 8) { + bs->bc += 8; + bs->ptr++; + } + + return bs->ptr; +} + +#ifdef UNPACK + +//////////////////////////////// local macros ///////////////////////////////// + +#define apply_weight_n(bits, weight, sample) ((weight * sample + (1 << (bits - 1))) >> bits) + +#define update_weight_n(bits, weight, source, result) \ + if (source && result) { \ + if ((source ^ result) >= 0) { if (weight++ == (1 << bits)) weight--; } \ + else if (weight-- == min_weight) weight++; \ + } + +#define apply_weight24(weight, sample) (((((sample & 0xffff) * weight) >> 7) + \ + (((sample & ~0xffff) >> 7) * weight) + 1) >> 1) + +#define update_weight2(weight, source, result) \ + if (source && result) { \ + if ((source ^ result) >= 0) { if (weight++ == 256) weight--; } \ + else if (weight-- == min_weight) weight++; \ + } + +//////////////////////////////// local tables /////////////////////////////// + +// These three tables specify the characteristics of the decorrelation filters. +// Each term represents one layer of the sequential filter, where positive +// values indicate the relative sample involved from the same channel (1=prev) +// while -1 and -2 indicate cross channel decorrelation (in stereo only). The +// "simple_terms" table is no longer used for writing, but is kept for older +// file decoding. + +static const signed char extreme_terms [] = { 1,1,1,2,4,-1,1,2,3,6,-2,8,5,7,4,1,2,3 }; +static const signed char default_terms [] = { 1,1,1,-1,2,1,-2 }; +static const signed char simple_terms [] = { 1,1,1,1 }; + +// This function initializes everything required to unpack WavPack +// bitstreams and must be called before any unpacking is performed. Note +// that the (WavpackHeader3 *) in the WavpackStream3 struct must be valid. + +static void init_words3 (WavpackStream3 *wps); + +static void unpack_init3 (WavpackStream3 *wps) +{ + int flags = wps->wphdr.flags; + struct decorr_pass *dpp; + int ti; + + CLEAR (wps->decorr_passes); + CLEAR (wps->dc); + + if (flags & EXTREME_DECORR) { + for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (extreme_terms); ti++) + if (extreme_terms [sizeof (extreme_terms) - ti - 1] > 0 || (flags & CROSS_DECORR)) + dpp++->term = extreme_terms [sizeof (extreme_terms) - ti - 1]; + } + else if (flags & NEW_DECORR_FLAG) { + for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (default_terms); ti++) + if (default_terms [sizeof (default_terms) - ti - 1] > 0 || (flags & CROSS_DECORR)) + dpp++->term = default_terms [sizeof (default_terms) - ti - 1]; + } + else + for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (simple_terms); ti++) + dpp++->term = simple_terms [sizeof (simple_terms) - ti - 1]; + + wps->num_terms = dpp - wps->decorr_passes; + init_words3 (wps); +} + +#ifdef SEEKING + +#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); } + +// This function returns the size (in bytes) required to save the unpacking +// context. Note that the (WavpackHeader3 *) in the WavpackStream3 struct +// must be valid. + +static int unpack_size (WavpackStream3 *wps) +{ + int flags = wps->wphdr.flags, byte_sum = 0, tcount; + struct decorr_pass *dpp; + + byte_sum += sizeof (wps->wvbits); + + if (flags & WVC_FLAG) + byte_sum += sizeof (wps->wvcbits); + + if (wps->wphdr.version == 3) { + if (wps->wphdr.bits) + byte_sum += sizeof (wps->w4); + else + byte_sum += sizeof (wps->w1); + + byte_sum += sizeof (wps->w3) + sizeof (wps->dc.crc); + } + else + byte_sum += sizeof (wps->w2); + + if (wps->wphdr.bits) + byte_sum += sizeof (wps->dc.error); + else + byte_sum += sizeof (wps->dc.sum_level) + sizeof (wps->dc.left_level) + + sizeof (wps->dc.right_level) + sizeof (wps->dc.diff_level); + + if (flags & OVER_20) + byte_sum += sizeof (wps->dc.last_extra_bits) + sizeof (wps->dc.extra_bits_count); + + if (!(flags & EXTREME_DECORR)) { + byte_sum += sizeof (wps->dc.sample); + byte_sum += sizeof (wps->dc.weight); + } + + if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + byte_sum += sizeof (dpp->samples_A [0]) * dpp->term; + byte_sum += sizeof (dpp->weight_A); + + if (!(flags & MONO_FLAG)) { + byte_sum += sizeof (dpp->samples_B [0]) * dpp->term; + byte_sum += sizeof (dpp->weight_B); + } + } + else { + byte_sum += sizeof (dpp->samples_A [0]) + sizeof (dpp->samples_B [0]); + byte_sum += sizeof (dpp->weight_A) + sizeof (dpp->weight_B); + } + + return byte_sum; +} + +// This function saves the unpacking context at the specified pointer and +// returns the updated pointer. The actual amount of data required can be +// determined beforehand by calling unpack_size() but must be allocated by +// the caller. + +static void *unpack_save (WavpackStream3 *wps, void *destin) +{ + int flags = wps->wphdr.flags, tcount; + struct decorr_pass *dpp; + + SAVE (destin, wps->wvbits); + + if (flags & WVC_FLAG) + SAVE (destin, wps->wvcbits); + + if (wps->wphdr.version == 3) { + if (wps->wphdr.bits) { + SAVE (destin, wps->w4); + } + else { + SAVE (destin, wps->w1); + } + + SAVE (destin, wps->w3); + SAVE (destin, wps->dc.crc); + } + else + SAVE (destin, wps->w2); + + if (wps->wphdr.bits) { + SAVE (destin, wps->dc.error); + } + else { + SAVE (destin, wps->dc.sum_level); + SAVE (destin, wps->dc.left_level); + SAVE (destin, wps->dc.right_level); + SAVE (destin, wps->dc.diff_level); + } + + if (flags & OVER_20) { + SAVE (destin, wps->dc.last_extra_bits); + SAVE (destin, wps->dc.extra_bits_count); + } + + if (!(flags & EXTREME_DECORR)) { + SAVE (destin, wps->dc.sample); + SAVE (destin, wps->dc.weight); + } + + 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; + + SAVE (destin, dpp->weight_A); + + while (count--) { + SAVE (destin, dpp->samples_A [index]); + index = (index + 1) & (MAX_TERM - 1); + } + + if (!(flags & MONO_FLAG)) { + count = dpp->term; + index = wps->dc.m; + + SAVE (destin, dpp->weight_B); + + while (count--) { + SAVE (destin, dpp->samples_B [index]); + index = (index + 1) & (MAX_TERM - 1); + } + } + } + else { + SAVE (destin, dpp->weight_A); + SAVE (destin, dpp->weight_B); + SAVE (destin, dpp->samples_A [0]); + SAVE (destin, dpp->samples_B [0]); + } + + return destin; +} + +// 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; + uchar *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 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 / ((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; +} + + +#endif + +// This monster actually unpacks the WavPack bitstream(s) into the specified +// buffer as longs, and serves as an extension to WavpackUnpackSamples(). +// Note that WavPack files created prior to version 4.0 could only contain 16 +// or 24 bit values, and these values are right-justified in the 32-bit values. +// So, if the original file contained 16-bit values, then the range of the +// returned longs would be +/- 32K. 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. + +static int32_t FASTCALL get_word1 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_old_word1 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_word2 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_word3 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *correction); + +int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count) +{ + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + int shift = wps->wphdr.shift, flags = wps->wphdr.flags, min_weight = 0, m = wps->dc.m, tcount; +#ifdef SEEKING + int points_index = wps->sample_index / ((wpc->total_samples >> 8) + 1); +#endif + int32_t min_value, max_value, min_shifted, max_shifted; + int32_t correction [2], crc = wps->dc.crc; + struct decorr_pass *dpp; + int32_t read_word, *bptr; + int32_t sample [2] [2]; + int weight [2] [1]; + uint i; + + if (wps->sample_index + sample_count > wpc->total_samples) + sample_count = wpc->total_samples - wps->sample_index; + + if (!sample_count) + return 0; + + if (!wps->sample_index) { + unpack_init3 (wps); + + bs_open_read3 (&wps->wvbits, wpc->reader, wpc->wv_in); + + if (wpc->wvc_flag) + bs_open_read3 (&wps->wvcbits, wpc->reader, wpc->wvc_in); + } + +#ifdef SEEKING + if (!wps->index_points [points_index].saved) { + + if (!wps->unpack_data) + wps->unpack_data = (uchar *) malloc (256 * (wps->unpack_size = unpack_size (wps))); + + wps->index_points [points_index].sample_index = wps->sample_index; + unpack_save (wps, wps->unpack_data + points_index * wps->unpack_size); + wps->index_points [points_index].saved = TRUE; + } +#endif + + memcpy (sample, wps->dc.sample, sizeof (sample)); + memcpy (weight, wps->dc.weight, sizeof (weight)); + + if (wps->wphdr.bits) { + if (flags & (NEW_DECORR_FLAG | EXTREME_DECORR)) + min_weight = -256; + } + else + if (flags & NEW_DECORR_FLAG) + min_weight = (flags & EXTREME_DECORR) ? -512 : -256; + + if (flags & BYTES_3) { + min_shifted = (min_value = -8388608 >> shift) << shift; + max_shifted = (max_value = 8388607 >> shift) << shift; + } + else { + min_shifted = (min_value = -32768 >> shift) << shift; + max_shifted = (max_value = 32767 >> shift) << shift; + } + + ///////////////// handle version 3 lossless mono data ///////////////////// + + if (wps->wphdr.version == 3 && !wps->wphdr.bits && (flags & MONO_FLAG)) { + if (flags & FAST_FLAG) { + if (flags & OVER_20) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t temp; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + sample [0] [0] += sample [0] [1] += read_word; + getbits (&temp, 4, &wps->wvbits); + crc = crc * 3 + (temp = (temp & 0xf) + (sample [0] [0] << 4)); + *bptr++ = temp; + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); + *bptr++ = sample [0] [0] << shift; + } + } + else if (flags & HIGH_FLAG) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t temp; + + if (flags & NEW_HIGH_FLAG) { + if ((read_word = get_word1 (wps, 0)) == WORD_EOF) + break; + } + else { + if ((read_word = get_old_word1 (wps, 0)) == WORD_EOF) + break; + } + + if (flags & EXTREME_DECORR) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam = dpp->samples_A [m]; + + temp = apply_weight_n (9, dpp->weight_A, sam) + read_word; + update_weight_n (9, dpp->weight_A, sam, read_word); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; + } + else + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam = dpp->samples_A [m]; + + temp = apply_weight_n (8, dpp->weight_A, sam) + read_word; + update_weight_n (8, dpp->weight_A, sam, read_word); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&temp, 4, &wps->wvbits); + + if ((temp &= 0xf) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = temp; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (temp = wps->dc.last_extra_bits + (read_word << 4)); + *bptr++ = temp; + } + else { + crc = crc * 3 + read_word; + *bptr++ = read_word << shift; + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + int32_t temp; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + temp = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; + + if ((sample [0] [1] >= 0) == (read_word > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + sample [0] [0] += (sample [0] [1] = temp - sample [0] [0]); + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&temp, 4, &wps->wvbits); + + if ((temp &= 0xf) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = temp; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (*bptr++ = temp = wps->dc.last_extra_bits + (sample [0] [0] << 4)); + } + else { + crc = crc * 3 + sample [0] [0]; + *bptr++ = sample [0] [0] << shift; + } + } + } + + //////////////// handle version 3 lossless stereo data //////////////////// + + else if (wps->wphdr.version == 3 && !wps->wphdr.bits && !(flags & MONO_FLAG)) { + int32_t left_level = wps->dc.left_level, right_level = wps->dc.right_level; + int32_t sum_level = wps->dc.sum_level, diff_level = wps->dc.diff_level; + + if (flags & FAST_FLAG) { + if (flags & OVER_20) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, diff, temp; + + read_word = get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + sum = (read_word << 1) | ((diff = get_word3 (wps, 1)) & 1); + sample [0] [0] += sample [0] [1] += ((sum + diff) >> 1); + sample [1] [0] += sample [1] [1] += ((sum - diff) >> 1); + getbits (&temp, 8, &wps->wvbits); + crc = crc * 3 + (*bptr++ = (sample [0] [0] << 4) + ((temp >> 4) & 0xf)); + crc = crc * 3 + (*bptr++ = (sample [1] [0] << 4) + (temp & 0xf)); + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, diff; + + read_word = get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + sum = (read_word << 1) | ((diff = get_word3 (wps, 1)) & 1); + sample [0] [1] += ((sum + diff) >> 1); + sample [1] [1] += ((sum - diff) >> 1); + crc = crc * 3 + (sample [0] [0] += sample [0] [1]); + crc = crc * 3 + (sample [1] [0] += sample [1] [1]); + *bptr++ = sample [0] [0] << shift; + *bptr++ = sample [1] [0] << shift; + } + } + else if (flags & HIGH_FLAG) { + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, left, right, diff, left2, right2, extra_bits, next_word; + + if (flags & CROSS_DECORR) { + left = get_word1 (wps, 0); + + if (left == WORD_EOF) + break; + + right = get_word1 (wps, 1); + } + else { + if (flags & NEW_HIGH_FLAG) { + read_word = get_word1 (wps, 0); + + if (read_word == WORD_EOF) + break; + + next_word = get_word1 (wps, 1); + + if (right_level > left_level) { + if (left_level + right_level < sum_level + diff_level && right_level < diff_level) { + sum = (right = read_word) + (left = next_word); + diff = left - right; + } + else { + diff = read_word; + + if (sum_level < left_level) { + sum = (next_word << 1) | (diff & 1); + left = (sum + diff) >> 1; + right = (sum - diff) >> 1; + } + else + sum = left + (right = (left = next_word) - diff); + } + } + else { + if (left_level + right_level < sum_level + diff_level && left_level < diff_level) { + sum = (left = read_word) + (right = next_word); + diff = left - right; + } + else { + diff = read_word; + + if (sum_level < right_level) { + sum = (next_word << 1) | (diff & 1); + left = (sum + diff) >> 1; + right = (sum - diff) >> 1; + } + else + sum = (left = diff + (right = next_word)) + right; + } + } + } + else { + read_word = get_old_word1 (wps, 0); + + if (read_word == WORD_EOF) + break; + + next_word = get_old_word1 (wps, 1); + + if (sum_level <= right_level && sum_level <= left_level) { + sum = (next_word << 1) | (read_word & 1); + left = (sum + read_word) >> 1; + right = (sum - read_word) >> 1; + } + else if (left_level <= right_level) + sum = left + (right = (left = next_word) - read_word); + else + sum = right + (left = read_word + (right = next_word)); + + diff = left - right; + } + + sum_level = sum_level - (sum_level >> 8) + labs (sum >> 1); + left_level = left_level - (left_level >> 8) + labs (left); + right_level = right_level - (right_level >> 8) + labs (right); + diff_level = diff_level - (diff_level >> 8) + labs (diff); + + if (flags & JOINT_STEREO) { + left = diff; + right = sum >> 1; + } + } + + if (flags & EXTREME_DECORR) { + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; + int k = (m + dpp->term) & (MAX_TERM - 1); + + left2 = apply_weight_n (9, dpp->weight_A, sam_A) + left; + right2 = apply_weight_n (9, dpp->weight_B, sam_B) + right; + + update_weight_n (9, dpp->weight_A, sam_A, left); + update_weight_n (9, dpp->weight_B, sam_B, right); + + dpp->samples_A [k] = left = left2; + dpp->samples_B [k] = right = right2; + } + else if (dpp->term == -1) { + left2 = left + apply_weight_n (9, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (9, dpp->weight_A, dpp->samples_A [0], left); + left = left2; + right2 = right + apply_weight_n (9, dpp->weight_B, left); + update_weight_n (9, dpp->weight_B, left, right); + dpp->samples_A [0] = right = right2; + } + else { + right2 = right + apply_weight_n (9, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (9, dpp->weight_A, dpp->samples_A [0], right); + right = right2; + left2 = left + apply_weight_n (9, dpp->weight_B, right); + update_weight_n (9, dpp->weight_B, right, left); + dpp->samples_A [0] = left = left2; + } + } + else { + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; + int k = (m + dpp->term) & (MAX_TERM - 1); + + left2 = apply_weight_n (8, dpp->weight_A, sam_A) + left; + right2 = apply_weight_n (8, dpp->weight_B, sam_B) + right; + + update_weight_n (8, dpp->weight_A, sam_A, left); + update_weight_n (8, dpp->weight_B, sam_B, right); + + dpp->samples_A [k] = left = left2; + dpp->samples_B [k] = right = right2; + } + else if (dpp->term == -1) { + left2 = left + apply_weight_n (8, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (8, dpp->weight_A, dpp->samples_A [0], left); + left = left2; + right2 = right + apply_weight_n (8, dpp->weight_B, left); + update_weight_n (8, dpp->weight_B, left, right); + dpp->samples_A [0] = right = right2; + } + else { + right2 = right + apply_weight_n (8, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (8, dpp->weight_A, dpp->samples_A [0], right); + right = right2; + left2 = left + apply_weight_n (8, dpp->weight_B, right); + update_weight_n (8, dpp->weight_B, right, left); + dpp->samples_A [0] = left = left2; + } + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & JOINT_STEREO) { + sum = (right << 1) | ((diff = left) & 1); + right = (sum - diff) >> 1; + left = (sum + diff) >> 1; + } + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&extra_bits, 8, &wps->wvbits); + + if ((extra_bits &= 0xff) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = extra_bits; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (*bptr++ = left = (left << 4) + (wps->dc.last_extra_bits >> 4)); + crc = crc * 3 + (*bptr++ = right = (right << 4) + (wps->dc.last_extra_bits & 0xf)); + } + else { + crc = crc * 9 + left * 3 + right; + *bptr++ = left << shift; + *bptr++ = right << shift; + } + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, left, right, left2, right2, extra_bits; + + read_word = get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + if (sum_level <= right_level && sum_level <= left_level) { + sum = (get_word3 (wps, 1) << 1) | (read_word & 1); + left = (sum + read_word) >> 1; + right = (sum - read_word) >> 1; + } + else if (left_level <= right_level) + sum = left + (right = (left = get_word3 (wps, 1)) - read_word); + else + sum = right + (left = read_word + (right = get_word3 (wps, 1))); + + sum_level = sum_level - (sum_level >> 8) + labs (sum >> 1); + left_level = left_level - (left_level >> 8) + labs (left); + right_level = right_level - (right_level >> 8) + labs (right); + + left2 = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + left; + right2 = sample [1] [0] + ((sample [1] [1] * weight [1] [0] + 128) >> 8) + right; + + if ((sample [0] [1] >= 0) == (left > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + if ((sample [1] [1] >= 0) == (right > 0)) { + if (weight [1] [0]++ == 256) + weight [1] [0]--; + } + else if (weight [1] [0]-- == 0) + weight [1] [0]++; + + sample [0] [0] += (sample [0] [1] = left2 - sample [0] [0]); + sample [1] [0] += (sample [1] [1] = right2 - sample [1] [0]); + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&extra_bits, 8, &wps->wvbits); + + if ((extra_bits &= 0xff) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = extra_bits; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (*bptr++ = left2 = (sample [0] [0] << 4) + (wps->dc.last_extra_bits >> 4)); + crc = crc * 3 + (*bptr++ = right2 = (sample [1] [0] << 4) + (wps->dc.last_extra_bits & 0xf)); + } + else { + crc = crc * 9 + sample [0] [0] * 3 + sample [1] [0]; + *bptr++ = sample [0] [0] << shift; + *bptr++ = sample [1] [0] << shift; + } + } + + wps->dc.left_level = left_level; + wps->dc.right_level = right_level; + wps->dc.sum_level = sum_level; + wps->dc.diff_level = diff_level; + } + + //////////////// handle version 3 lossy/hybrid mono data ////////////////// + + else if (wps->wphdr.version == 3 && wps->wphdr.bits && (flags & MONO_FLAG)) { + if (flags & FAST_FLAG) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); + + if (sample [0] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [0] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [0] [0] << shift; + } + else if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t temp; + + read_word = (flags & NEW_HIGH_FLAG) ? + get_word4 (wps, 0, correction) : get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam = dpp->samples_A [m]; + + temp = apply_weight24 (dpp->weight_A, sam) + read_word; + update_weight2 (dpp->weight_A, sam, read_word); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & WVC_FLAG) { + if (flags & LOSSY_SHAPE) { + crc = crc * 3 + (read_word += correction [0] + wps->dc.error [0]); + wps->dc.error [0] = -correction [0]; + } + else + crc = crc * 3 + (read_word += correction [0]); + + *bptr++ = read_word << shift; + } + else { + crc = crc * 3 + read_word; + + if (read_word < min_value) + *bptr++ = min_shifted; + else if (read_word > max_value) + *bptr++ = max_shifted; + else + *bptr++ = read_word << shift; + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t new_sample; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + new_sample = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; + + if ((sample [0] [1] >= 0) == (read_word > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + sample [0] [1] = new_sample - sample [0] [0]; + crc = crc * 3 + (sample [0] [0] = new_sample); + + if (sample [0] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [0] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [0] [0] << shift; + } + } + + //////////////// handle version 3 lossy/hybrid stereo data //////////////// + + else if (wps->wphdr.version == 3 && wps->wphdr.bits && !(flags & MONO_FLAG)) { + if (flags & FAST_FLAG) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); + + if (sample [0] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [0] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [0] [0] << shift; + + crc = crc * 3 + (sample [1] [0] += sample [1] [1] += get_word3 (wps, 1)); + + if (sample [1] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [1] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [1] [0] << shift; + } + else if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t left, right, left2, right2, sum, diff; + + if (flags & NEW_HIGH_FLAG) { + left = get_word4 (wps, 0, correction); + right = get_word4 (wps, 1, correction + 1); + } + else { + left = get_word3 (wps, 0); + right = get_word3 (wps, 1); + } + + if (left == WORD_EOF) + break; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; + int k = (m + dpp->term) & (MAX_TERM - 1); + + left2 = apply_weight24 (dpp->weight_A, sam_A) + left; + update_weight2 (dpp->weight_A, sam_A, left); + dpp->samples_A [k] = left = left2; + + right2 = apply_weight24 (dpp->weight_B, sam_B) + right; + update_weight2 (dpp->weight_B, sam_B, right); + dpp->samples_B [k] = right = right2; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & WVC_FLAG) { + if (flags & LOSSY_SHAPE) { + left += correction [0] + wps->dc.error [0]; + right += correction [1] + wps->dc.error [1]; + wps->dc.error [0] = -correction [0]; + wps->dc.error [1] = -correction [1]; + } + else { + left += correction [0]; + right += correction [1]; + } + } + + if (flags & JOINT_STEREO) { + right = ((sum = (right << 1) | (left & 1)) - (diff = left)) >> 1; + left = (sum + diff) >> 1; + } + + crc = crc * 9 + left * 3 + right; + + if (flags & WVC_FLAG) { + *bptr++ = left << shift; + *bptr++ = right << shift; + } + else { + if (left < min_value) + *bptr++ = min_shifted; + else if (left > max_value) + *bptr++ = max_shifted; + else + *bptr++ = left << shift; + + if (right < min_value) + *bptr++ = min_shifted; + else if (right > max_value) + *bptr++ = max_shifted; + else + *bptr++ = right << shift; + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t new_sample; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + new_sample = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; + + if ((sample [0] [1] >= 0) == (read_word > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + sample [0] [1] = new_sample - sample [0] [0]; + crc = crc * 3 + (sample [0] [0] = new_sample); + + read_word = get_word3 (wps, 1); + new_sample = sample [1] [0] + ((sample [1] [1] * weight [1] [0] + 128) >> 8) + read_word; + + if ((sample [1] [1] >= 0) == (read_word > 0)) { + if (weight [1] [0]++ == 256) + weight [1] [0]--; + } + else if (weight [1] [0]-- == 0) + weight [1] [0]++; + + sample [1] [1] = new_sample - sample [1] [0]; + crc = crc * 3 + (sample [1] [0] = new_sample); + + if (sample [0] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [0] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [0] [0] << shift; + + if (sample [1] [0] < min_value) + *bptr++ = min_shifted; + else if (sample [1] [0] > max_value) + *bptr++ = max_shifted; + else + *bptr++ = sample [1] [0] << shift; + } + } + + //////////////////// finally, handle version 2 data /////////////////////// + + else if (wps->wphdr.version == 2 && (flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + if ((read_word = get_word2 (wps, 0)) == WORD_EOF) + break; + + sample [0] [0] += sample [0] [1] += read_word; + + if (wps->wphdr.bits) { + if (sample [0] [0] < min_value) + sample [0] [0] = min_value; + else if (sample [0] [0] > max_value) + sample [0] [0] = max_value; + } + + *bptr++ = sample [0] [0] << shift; + } + else if (wps->wphdr.version < 3 && !(flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, diff; + + read_word = get_word2 (wps, 0); + + if (read_word == WORD_EOF) + break; + + sum = (read_word << 1) | ((diff = get_word2 (wps, 1)) & 1); + sample [0] [0] += sample [0] [1] += ((sum + diff) >> 1); + sample [1] [0] += sample [1] [1] += ((sum - diff) >> 1); + + if (wps->wphdr.bits) { + if (sample [0] [0] < min_value) + sample [0] [0] = min_value; + else if (sample [0] [0] > max_value) + sample [0] [0] = max_value; + + if (sample [1] [0] < min_value) + sample [1] [0] = min_value; + else if (sample [1] [0] > max_value) + sample [1] [0] = max_value; + } + + *bptr++ = sample [0] [0] << shift; + *bptr++ = sample [1] [0] << shift; + } + + if (i && (wps->sample_index += i) == wpc->total_samples) { + + if (wps->wphdr.version == 3 && crc != (wpc->wvc_flag ? wps->wphdr.crc2 : wps->wphdr.crc)) + wpc->crc_errors++; + + if (wpc->open_flags & OPEN_WRAPPER) { + uchar *temp = malloc (1024); + uint32_t bcount; + + if (bs_unused_bytes (&wps->wvbits)) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bs_unused_bytes (&wps->wvbits)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, bs_unused_data (&wps->wvbits), bs_unused_bytes (&wps->wvbits)); + wpc->wrapper_bytes += bs_unused_bytes (&wps->wvbits); + } + + while (1) { + bcount = wpc->reader->read_bytes (wpc->wv_in, temp, sizeof (temp)); + + if (!bcount) + break; + + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bcount); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, temp, bcount); + wpc->wrapper_bytes += bcount; + } + + free (temp); + + if (wpc->wrapper_bytes > 16) { + int c; + + for (c = 0; c < 16 && wpc->wrapper_data [c] == 0xff; ++c); + + if (c == 16) { + memcpy (wpc->wrapper_data, wpc->wrapper_data + 16, wpc->wrapper_bytes - 16); + wpc->wrapper_bytes -= 16; + } + else { + free (wpc->wrapper_data); + wpc->wrapper_data = NULL; + wpc->wrapper_bytes = 0; + } + } + } + } + + memcpy (wps->dc.sample, sample, sizeof (sample)); + memcpy (wps->dc.weight, weight, sizeof (weight)); + wps->dc.crc = crc; + wps->dc.m = m; + + return i; +} + +///////////////////////////// local table storage //////////////////////////// + +extern const uint32_t bitset []; +extern const uint32_t bitmask []; +extern const char nbits_table []; + +// This function initializes everything required to receive words with this +// module and must be called BEFORE any other function in this module. + +static void init_words3 (WavpackStream3 *wps) +{ + CLEAR (wps->w1); + CLEAR (wps->w2); + CLEAR (wps->w3); + CLEAR (wps->w4); + + if (wps->wphdr.flags & MONO_FLAG) + wps->w4.bitrate = wps->wphdr.bits - 768; + else + wps->w4.bitrate = (wps->wphdr.bits / 2) - 768; +} + +// This macro counts the number of bits that are required to specify the +// unsigned 32-bit value, counting from the LSB to the most significant bit +// that is set. Return range is 0 - 32. + +#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) \ + ) \ +) + +static int32_t FASTCALL get_word1 (WavpackStream3 *wps, int chan) +{ + uint32_t tmp1, tmp2, avalue; + uint ones_count; + int k; + + if ((wps->wphdr.flags & EXTREME_DECORR) && !(wps->wphdr.flags & OVER_20)) { + if (wps->w1.zeros_acc) { + if (--wps->w1.zeros_acc) + return 0; + } + else if (wps->w1.ave_level [0] [0] < 0x20 && wps->w1.ave_level [0] [1] < 0x20) { + int32_t mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + wps->w1.zeros_acc = cbits; + else { + for (mask = 1, wps->w1.zeros_acc = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + wps->w1.zeros_acc |= mask; + + wps->w1.zeros_acc |= mask; + } + + if (wps->w1.zeros_acc) + return 0; + } + } + + // count consecutive ones in bitstream, > 25 indicates error (or EOF) + + for (ones_count = 0; ones_count < 25 && getbit (&wps->wvbits); ++ones_count); + + if (ones_count == 25) + return WORD_EOF; + + k = (wps->w1.ave_level [0] [chan] + (wps->w1.ave_level [0] [chan] >> 3) + 0x40) >> 7; + k = count_bits (k); + + if (ones_count == 0) { + getbits (&avalue, k, &wps->wvbits); + avalue &= bitmask [k]; + } + else { + tmp1 = bitset [k]; + k = (wps->w1.ave_level [1] [chan] + (wps->w1.ave_level [1] [chan] >> 4) + 0x20) >> 6; + k = count_bits (k); + + if (ones_count == 1) { + getbits (&avalue, k, &wps->wvbits); + avalue &= bitmask [k]; + } + else { + tmp2 = bitset [k]; + + // If the ones count is exactly 24, then next 24 bits are literal + + if (ones_count == 24) { + getbits (&avalue, 24, &wps->wvbits); + avalue &= 0xffffff; + } + else { + k = (wps->w1.ave_level [2] [chan] + 0x10) >> 5; + k = count_bits (k); + getbits (&avalue, k, &wps->wvbits); + avalue = (avalue & bitmask [k]) + (bitset [k] * (ones_count - 2)); + } + + wps->w1.ave_level [2] [chan] -= ((wps->w1.ave_level [2] [chan] + 0x8) >> 4); + wps->w1.ave_level [2] [chan] += avalue; + avalue += tmp2; + } + + wps->w1.ave_level [1] [chan] -= ((wps->w1.ave_level [1] [chan] + 0x10) >> 5); + wps->w1.ave_level [1] [chan] += avalue; + avalue += tmp1; + } + + wps->w1.ave_level [0] [chan] -= ((wps->w1.ave_level [0] [chan] + 0x20) >> 6); + wps->w1.ave_level [0] [chan] += avalue; + + return (avalue && getbit (&wps->wvbits)) ? -(int32_t)avalue : avalue; +} + +#define NUM_SAMPLES 128 + +static int32_t FASTCALL get_old_word1 (WavpackStream3 *wps, int chan) +{ + uint32_t avalue; + uint bc; + int k; + + if (!wps->w1.index [chan]) { + + int guess_k = (wps->w1.ave_k [chan] + 128) >> 8, ones; + + for (ones = 0; ones < 72 && getbit (&wps->wvbits); ++ones); + + if (ones == 72) + return WORD_EOF; + + if (ones % 3 == 1) + wps->w1.k_value [chan] = guess_k - (ones / 3) - 1; + else + wps->w1.k_value [chan] = guess_k + ones - ((ones + 1) / 3); + + wps->w1.ave_k [chan] -= (wps->w1.ave_k [chan] + 0x10) >> 5; + wps->w1.ave_k [chan] += wps->w1.k_value [chan] << 3; + } + + if (++wps->w1.index [chan] == NUM_SAMPLES) + wps->w1.index [chan] = 0; + + k = wps->w1.k_value [chan]; + getbits (&avalue, k, &wps->wvbits); + + for (bc = 0; bc < 32 && getbit (&wps->wvbits); ++bc); + + if (bc == 32) + return WORD_EOF; + + avalue = (avalue & bitmask [k]) + bitset [k] * bc; + return (avalue && getbit (&wps->wvbits)) ? -(int32_t)avalue : avalue; +} + +static int32_t FASTCALL get_word2 (WavpackStream3 *wps, int chan) +{ + int cbits, delta_dbits, dbits; + int32_t value, mask = 1; + + cbits = 0; + + while (getbit (&wps->wvbits)) + if ((cbits += 2) == 50) + return WORD_EOF; + + if (getbit (&wps->wvbits)) + cbits++; + + if (cbits == 0) + delta_dbits = 0; + else if (cbits & 1) { + delta_dbits = (cbits + 1) / 2; + + if (wps->w2.last_delta_sign [chan] > 0) + delta_dbits *= -1; + + wps->w2.last_delta_sign [chan] = delta_dbits; + } + else { + delta_dbits = cbits / 2; + + if (wps->w2.last_delta_sign [chan] <= 0) + delta_dbits *= -1; + } + + dbits = (wps->w2.last_dbits [chan] += delta_dbits); + + if (dbits < 0 || dbits > 20) + return WORD_EOF; + + if (!dbits) + return 0L; + + if (wps->wphdr.bits) { + for (value = 1L << (dbits - 1); --dbits; mask <<= 1) + if (dbits < wps->wphdr.bits && getbit (&wps->wvbits)) + value |= mask; + } + else + for (value = 1L << (dbits - 1); --dbits; mask <<= 1) + if (getbit (&wps->wvbits)) + value |= mask; + + return getbit (&wps->wvbits) ? -(int32_t)value : value; +} + +static int32_t FASTCALL get_word3 (WavpackStream3 *wps, int chan) +{ + int cbits, delta_dbits, dbits; + int32_t value; + + for (cbits = 0; cbits < 72 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 72) + return WORD_EOF; + + if (cbits || getbit (&wps->wvbits)) + ++cbits; + + if (!((cbits + 1) % 3)) + delta_dbits = (cbits + 1) / 3; + else + delta_dbits = -(cbits - cbits / 3); + + if (chan) { + dbits = (wps->w3.ave_dbits [1] >> 8) + 1 + delta_dbits; + wps->w3.ave_dbits [1] -= (wps->w3.ave_dbits [1] + 0x10) >> 5; + wps->w3.ave_dbits [1] += dbits << 3; + } + else { + dbits = (wps->w3.ave_dbits [0] >> 8) + 1 + delta_dbits; + wps->w3.ave_dbits [0] -= (wps->w3.ave_dbits [0] + 0x10) >> 5; + wps->w3.ave_dbits [0] += dbits << 3; + } + + if (dbits < 0 || dbits > 24) + return WORD_EOF; + + if (!dbits) + return 0L; + + if (wps->wphdr.bits && dbits > wps->wphdr.bits) { + getbits (&value, wps->wphdr.bits, &wps->wvbits); + + if (value & bitset [wps->wphdr.bits - 1]) + return -(int32_t)(value & bitmask [wps->wphdr.bits]) << (dbits - wps->wphdr.bits); + else + return ((value & bitmask [wps->wphdr.bits - 1]) | bitset [wps->wphdr.bits - 1]) << (dbits - wps->wphdr.bits); + } + else { + getbits (&value, dbits, &wps->wvbits); + + if (value & bitset [dbits - 1]) + return -(int32_t)(value & bitmask [dbits]); + else + return (value & bitmask [dbits - 1]) | bitset [dbits - 1]; + } +} + +static int FASTCALL _log2 (uint32_t avalue); + +static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *correction) +{ + uint32_t base, ones_count, avalue; + int32_t value, low, mid, high; + int bitcount; + + // count consecutive ones in bitstream, > 25 indicates error (or EOF) + + for (ones_count = 0; ones_count < 25 && getbit (&wps->wvbits); ++ones_count); + + if (ones_count == 25) + return WORD_EOF; + + // if the ones count is exactly 24, then we switch to non-unary method + + if (ones_count == 24) { + int32_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 += 24; + } + + if (!chan) { + int slow_log_0, slow_log_1, balance; + + if (wps->wphdr.flags & MONO_FLAG) { + wps->w4.bits_acc [0] += wps->w4.bitrate + _log2 (wps->w4.fast_level [0]) - _log2 (wps->w4.slow_level [0]) + (3 << 8); + + if (wps->w4.bits_acc [0] < 0) + wps->w4.bits_acc [0] = 0; + } + else { + slow_log_0 = _log2 (wps->w4.slow_level [0]); + slow_log_1 = _log2 (wps->w4.slow_level [1]); + + if (wps->wphdr.flags & JOINT_STEREO) + balance = (slow_log_1 - slow_log_0 + 257) >> 1; + else + balance = (slow_log_1 - slow_log_0 + 1) >> 1; + + wps->w4.bits_acc [0] += wps->w4.bitrate - balance + _log2 (wps->w4.fast_level [0]) - slow_log_0 + (3 << 8); + wps->w4.bits_acc [1] += wps->w4.bitrate + balance + _log2 (wps->w4.fast_level [1]) - slow_log_1 + (3 << 8); + + if (wps->w4.bits_acc [0] + wps->w4.bits_acc [1] < 0) + wps->w4.bits_acc [0] = wps->w4.bits_acc [1] = 0; + else if (wps->w4.bits_acc [0] < 0) { + wps->w4.bits_acc [1] += wps->w4.bits_acc [0]; + wps->w4.bits_acc [0] = 0; + } + else if (wps->w4.bits_acc [1] < 0) { + wps->w4.bits_acc [0] += wps->w4.bits_acc [1]; + wps->w4.bits_acc [1] = 0; + } + } + } + + base = (wps->w4.fast_level [chan] + 48) / 96; + bitcount = wps->w4.bits_acc [chan] >> 8; + wps->w4.bits_acc [chan] &= 0xff; + + if (!base) { + if (ones_count) + high = low = mid = (getbit (&wps->wvbits)) ? -(int32_t)ones_count : ones_count; + else + high = low = mid = 0; + } + else { + mid = (ones_count * 2 + 1) * base; + if (getbit (&wps->wvbits)) mid = -mid; + low = mid - base; + high = mid + base - 1; + + while (bitcount--) { + if (getbit (&wps->wvbits)) + mid = (high + (low = mid) + 1) >> 1; + else + mid = ((high = mid - 1) + low + 1) >> 1; + + if (high == low) + break; + } + } + + wps->w4.fast_level [chan] -= ((wps->w4.fast_level [chan] + 0x10) >> 5); + wps->w4.fast_level [chan] += (avalue = labs (mid)); + wps->w4.slow_level [chan] -= ((wps->w4.slow_level [chan] + 0x80) >> 8); + wps->w4.slow_level [chan] += avalue; + + if (bs_is_open (&wps->wvcbits)) { + + if (high != low) { + uint32_t maxcode = high - low; + int bitcount = count_bits (maxcode); + uint32_t extras = (1L << bitcount) - maxcode - 1; + + getbits (&avalue, bitcount - 1, &wps->wvcbits); + avalue &= bitmask [bitcount - 1]; + + if (avalue >= extras) { + avalue = (avalue << 1) - extras; + + if (getbit (&wps->wvcbits)) + ++avalue; + } + + value = (mid < 0) ? high - avalue : avalue + low; + + if (correction) + *correction = value - mid; + } + else if (correction) + *correction = 0; + } + + return mid; +} + +// This function calculates an approximate base-2 logarithm (with 8 bits of +// fraction) from the supplied value. Using logarithms makes comparing +// signal level values and calculating fractional bitrates much easier. + +static int FASTCALL _log2 (uint32_t avalue) +{ + int dbits; + + if ((avalue += avalue >> 9) < (1 << 8)) { + dbits = nbits_table [avalue]; + return (dbits << 8) + ((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) + ((avalue >> (dbits - 9)) & 0xff); + } +} + +#endif diff --git a/Libraries/WavPack/Files/unpack3.h b/Libraries/WavPack/Files/unpack3.h index d958141b4..f089b540c 100644 --- a/Libraries/WavPack/Files/unpack3.h +++ b/Libraries/WavPack/Files/unpack3.h @@ -1,113 +1,113 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 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 { - ushort FormatTag, NumChannels; - uint32_t SampleRate, BytesPerSecond; - ushort BlockAlign, BitsPerSample; -} WaveHeader3; - -#define WaveHeader3Format "SSLLSS" - -typedef struct { - char ckID [4]; - int32_t ckSize; - short version; - short bits; // added for version 2.00 - short 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); - uchar *buf, *end, *ptr; - uint32_t bufsiz, fpos, sr; - stream_reader *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; - -#ifdef SEEKING - struct index_point { - char saved; - uint32_t sample_index; - } index_points [256]; - - uchar *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 { - uint 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; +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 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 { + ushort FormatTag, NumChannels; + uint32_t SampleRate, BytesPerSecond; + ushort BlockAlign, BitsPerSample; +} WaveHeader3; + +#define WaveHeader3Format "SSLLSS" + +typedef struct { + char ckID [4]; + int32_t ckSize; + short version; + short bits; // added for version 2.00 + short 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); + uchar *buf, *end, *ptr; + uint32_t bufsiz, fpos, sr; + WavpackStreamReader *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; + +#ifdef SEEKING + struct index_point { + char saved; + uint32_t sample_index; + } index_points [256]; + + uchar *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 { + uint 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; diff --git a/Libraries/WavPack/Files/utils.c b/Libraries/WavPack/Files/utils.c index 36d25e612..6d344f908 100644 --- a/Libraries/WavPack/Files/utils.c +++ b/Libraries/WavPack/Files/utils.c @@ -1,640 +1,702 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 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) -#include -#include -#include -#elif defined(__GNUC__) -#include -#endif - -#ifndef WIN32 -#include -#include -#endif - -#include -#include -#include -#include - -#include "wavpack.h" - - -#ifdef WIN32 - -int copy_timestamp (const char *src_filename, const char *dst_filename) -{ - FILETIME last_modified; - HANDLE src, dst; - int res = TRUE; - - if (*src_filename == '-' || *dst_filename == '-') - return res; - - src = CreateFile (src_filename, GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); - - dst = CreateFile (dst_filename, 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); - - return res; -} - -#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 3 letters don't count. // -////////////////////////////////////////////////////////////////////////////// - -#if defined(WIN32) - -static int is_second_byte (char *filespec, char *pos); - -char *filespec_ext (char *filespec) -{ - char *cp = filespec + strlen (filespec); - LANGID langid = GetSystemDefaultLangID (); - - while (--cp >= filespec) { - - if (langid == 0x411 && is_second_byte (filespec, cp)) - --cp; - - if (*cp == '\\' || *cp == ':') - return NULL; - - if (*cp == '.') { - if (strlen (cp) > 1 && strlen (cp) <= 4) - return cp; - else - return NULL; - } - } - - return NULL; -} - -#else - -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) <= 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(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 == '\\' || *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)) { - globfree(&globs); - filespec[0] = '\0'; - return strcat (filespec, globs.gl_pathv[0]); - } - } - globfree(&globs); - - return NULL; -} - -#else - -char *filespec_path (char *filespec) -{ - char *cp = filespec + strlen (filespec); - LANGID langid = GetSystemDefaultLangID (); - struct _finddata_t finddata; - int32_t file; - - if (cp == filespec || filespec_wild (filespec)) - return NULL; - - --cp; - - if (langid == 0x411 && is_second_byte (filespec, cp)) - --cp; - - if (*cp == '\\' || *cp == ':') - return filespec; - - if (*cp == '.' && cp == filespec) - return strcat (filespec, "\\"); - - if ((file = _findfirst (filespec, &finddata)) != -1L && - (finddata.attrib & _A_SUBDIR)) { - _findclose (file); - return strcat (filespec, "\\"); - } - if (file != -1L) - _findclose(file); - - 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); - LANGID langid = GetSystemDefaultLangID (); - - while (--cp >= filespec) { - if (langid == 0x411 && is_second_byte (filespec, cp)) - --cp; - - 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 == '\\' || *cp == ':') - break; - - if (strlen (cp + 1)) - return cp + 1; - else - return NULL; -} - -#endif - -////////////////////////////////////////////////////////////////////////////// -// This function returns TRUE if "pos" is pointing to the second byte of a // -// double-byte character in the string "filespec" which is assumed to be // -// shift-JIS. // -////////////////////////////////////////////////////////////////////////////// - -#if defined(WIN32) - -static int is_second_byte (char *filespec, char *pos) -{ - uchar *cp = pos; - - while (cp > filespec && ((cp [-1] >= 0x81 && cp [-1] <= 0x9f) || - (cp [-1] >= 0xe0 && cp [-1] <= 0xfc))) - cp--; - - return ((int) pos - (int) cp) & 1; -} - -#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 == '\r' || key == '\n') { - if (choice) { - fprintf (stderr, "\r\n"); - break; - } - else - fprintf (stderr, "%c", 7); - } - else if (key == 'Y' || key == 'y') { - fprintf (stderr, "%c\b", key); - choice = 'y'; - } - else if (key == 'N' || key == 'n') { - fprintf (stderr, "%c\b", key); - choice = 'n'; - } - else if (key == 'A' || key == 'a') { - fprintf (stderr, "%c\b", key); - choice = 'a'; - } - else - fprintf (stderr, "%c", 7); - } - - 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. // -////////////////////////////////////////////////////////////////////////////// - -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 0 - { - FILE *error_log = fopen ("c:\\wavpack.log", "a+"); - - if (error_log) { - fputs (error_msg + 1, error_log); - fputc ('\n', error_log); - fclose (error_log); - } - } -#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) { -#ifdef __BORLANDC__ - fprintf (stderr, "^C\n"); -#endif - 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)) { - char spaces = coninfo.dwSize.X - coninfo.dwCursorPosition.X; - - while (spaces--) - fputc (' ', stderr); - } - else - fputc ('\n', 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) -{ -/* char spaces = 1; - - while (spaces--) - putc (' ', stderr); - else*/ - fputc ('\n', stderr); -} - -////////////////////////////////////////////////////////////////////////////// -// Function to initialize console for intercepting ^C and ^Break. // -////////////////////////////////////////////////////////////////////////////// - -void setup_break (void) -{ -} - -////////////////////////////////////////////////////////////////////////////// -// Function to determine whether ^C or ^Break has been issued by user. // -////////////////////////////////////////////////////////////////////////////// - -int check_break (void) -{ - return 0; -} - -#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 = fread ((uchar *) 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 = fwrite ((uchar *) lpBuffer + *lpNumberOfBytesWritten, 1, nNumberOfBytesToWrite, hFile); - - if (bcount) { - *lpNumberOfBytesWritten += bcount; - nNumberOfBytesToWrite -= bcount; - } - else - break; - } - - return !ferror (hFile); -} - -uint32_t DoGetFileSize (FILE *hFile) -{ - struct stat statbuf; - - if (!hFile || fstat (fileno (hFile), &statbuf) || !(statbuf.st_mode & S_IFREG)) - return 0; - - return statbuf.st_size; -} - -uint32_t DoGetFilePosition (FILE *hFile) -{ - return ftell (hFile); -} - -int DoSetFilePositionAbsolute (FILE *hFile, uint32_t pos) -{ - return fseek (hFile, pos, SEEK_SET); -} - -int DoSetFilePositionRelative (FILE *hFile, int32_t pos, int mode) -{ - return fseek (hFile, pos, mode); -} - -// 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 !remove (filename); -} - -// Convert the Unicode wide-format string into a UTF-8 string using no more -// than the specified buffer length. The wide-format string must be NULL -// terminated and the resulting string will be NULL terminated. The actual -// number of characters converted (not counting terminator) is returned, which -// may be less than the number of characters in the wide string if the buffer -// length is exceeded. - -static int WideCharToUTF8 (const ushort *Wide, uchar *pUTF8, int len) -{ - const ushort *pWide = Wide; - int outndx = 0; - - while (*pWide) { - if (*pWide < 0x80 && outndx + 1 < len) - pUTF8 [outndx++] = (uchar) *pWide++; - else if (*pWide < 0x800 && outndx + 2 < len) { - pUTF8 [outndx++] = (uchar) (0xc0 | ((*pWide >> 6) & 0x1f)); - pUTF8 [outndx++] = (uchar) (0x80 | (*pWide++ & 0x3f)); - } - else if (outndx + 3 < len) { - pUTF8 [outndx++] = (uchar) (0xe0 | ((*pWide >> 12) & 0xf)); - pUTF8 [outndx++] = (uchar) (0x80 | ((*pWide >> 6) & 0x3f)); - pUTF8 [outndx++] = (uchar) (0x80 | (*pWide++ & 0x3f)); - } - else - break; - } - - pUTF8 [outndx] = 0; - return pWide - Wide; -} - -// Convert a Ansi string into its Unicode UTF-8 format equivalent. The -// conversion is done in-place so the maximum length of the string buffer must -// be specified because the string may become longer or shorter. If the -// resulting string will not fit in the specified buffer size then it is -// truncated. - -void AnsiToUTF8 (char *string, int len) -{ - int max_chars = strlen (string); -#if defined(WIN32) - ushort *temp = (ushort *) malloc ((max_chars + 1) * 2); - - MultiByteToWideChar (CP_ACP, 0, string, -1, temp, max_chars + 1); - WideCharToUTF8 (temp, (uchar *) string, len); -#else - char *temp = malloc (len); -// memset(temp, 0, len); - char *outp = temp; - const char *inp = string; - size_t insize = max_chars; - size_t outsize = len - 1; - int err = 0; - char *old_locale; - - memset(temp, 0, len); - old_locale = setlocale (LC_CTYPE, ""); - iconv_t converter = iconv_open ("UTF-8", ""); - err = iconv (converter, &inp, &insize, &outp, &outsize); - iconv_close (converter); - setlocale (LC_CTYPE, old_locale); - - if (err == -1) { - free(temp); - return; - } - - memmove (string, temp, len); -#endif - free (temp); -} +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 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) +#include +#include +#include +#include +#elif defined(__GNUC__) +#include +#endif + +#include +#include +#include +#include + +#include "wavpack.h" + + +#ifdef WIN32 + +int copy_timestamp (const char *src_filename, const char *dst_filename) +{ + FILETIME last_modified; + HANDLE src, dst; + int res = TRUE; + + if (*src_filename == '-' || *dst_filename == '-') + return res; + + src = CreateFile (src_filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + + dst = CreateFile (dst_filename, 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); + + return res; +} + +#else + +#include +#include + +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 3 letters don't count. // +////////////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) + +static int is_second_byte (char *filespec, char *pos); + +char *filespec_ext (char *filespec) +{ + char *cp = filespec + strlen (filespec); + LANGID langid = GetSystemDefaultLangID (); + + while (--cp >= filespec) { + + if (langid == 0x411 && is_second_byte (filespec, cp)) + --cp; + + if (*cp == '\\' || *cp == ':') + return NULL; + + if (*cp == '.') { + if (strlen (cp) > 1 && strlen (cp) <= 4) + return cp; + else + return NULL; + } + } + + return NULL; +} + +#else + +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) <= 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(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 == '/' || *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); + LANGID langid = GetSystemDefaultLangID (); + struct _finddata_t finddata; + int32_t file; + + if (cp == filespec || filespec_wild (filespec)) + return NULL; + + --cp; + + if (langid == 0x411 && is_second_byte (filespec, cp)) + --cp; + + if (*cp == '\\' || *cp == ':') + return filespec; + + if (*cp == '.' && cp == filespec) + return strcat (filespec, "\\"); + + if ((file = _findfirst (filespec, &finddata)) != -1L && + (finddata.attrib & _A_SUBDIR)) { + _findclose (file); + return strcat (filespec, "\\"); + } + if (file != -1L) + _findclose(file); + + 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); + LANGID langid = GetSystemDefaultLangID (); + + while (--cp >= filespec) { + if (langid == 0x411 && is_second_byte (filespec, cp)) + --cp; + + 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 == '/' || *cp == ':') + break; + + if (strlen (cp + 1)) + return cp + 1; + else + return NULL; +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// This function returns TRUE if "pos" is pointing to the second byte of a // +// double-byte character in the string "filespec" which is assumed to be // +// shift-JIS. // +////////////////////////////////////////////////////////////////////////////// + +#if defined(WIN32) + +static int is_second_byte (char *filespec, char *pos) +{ + uchar *cp = pos; + + while (cp > filespec && ((cp [-1] >= 0x81 && cp [-1] <= 0x9f) || + (cp [-1] >= 0xe0 && cp [-1] <= 0xfc))) + cp--; + + return ((int) pos - (int) cp) & 1; +} + +#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 == '\r' || key == '\n') { + if (choice) { + fprintf (stderr, "\r\n"); + break; + } + else + fprintf (stderr, "%c", 7); + } + else if (key == 'Y' || key == 'y') { + fprintf (stderr, "%c\b", key); + choice = 'y'; + } + else if (key == 'N' || key == 'n') { + fprintf (stderr, "%c\b", key); + choice = 'n'; + } + else if (key == 'A' || key == 'a') { + fprintf (stderr, "%c\b", key); + choice = 'a'; + } + else + fprintf (stderr, "%c", 7); + } + + 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. // +////////////////////////////////////////////////////////////////////////////// + +int debug_logging_mode = FALSE; + +#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 + +void debug_line (char *error, ...) +{ + char error_msg [512]; + va_list argptr; + + if (!debug_logging_mode) + return; + + 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) { + FILE *error_log = fopen ("c:\\wavpack.log", "a+"); + + if (error_log) { + fputs (error_msg + 1, error_log); + fputc ('\n', error_log); + fclose (error_log); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +// 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)) { + unsigned char spaces = coninfo.dwSize.X - coninfo.dwCursorPosition.X; + + while (spaces--) + fputc (' ', stderr); + } + else + fputc ('\n', 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"); +} + +////////////////////////////////////////////////////////////////////////////// +// Function to initialize console for intercepting ^C and ^Break. // +////////////////////////////////////////////////////////////////////////////// + +void setup_break (void) +{ +} + +////////////////////////////////////////////////////////////////////////////// +// Function to determine whether ^C or ^Break has been issued by user. // +////////////////////////////////////////////////////////////////////////////// + +int check_break (void) +{ + return 0; +} + +#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 = fread ((uchar *) 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 = fwrite ((uchar *) lpBuffer + *lpNumberOfBytesWritten, 1, nNumberOfBytesToWrite, hFile); + + if (bcount) { + *lpNumberOfBytesWritten += bcount; + nNumberOfBytesToWrite -= bcount; + } + else + break; + } + + return !ferror (hFile); +} + +uint32_t DoGetFileSize (FILE *hFile) +{ + struct stat statbuf; + + if (!hFile || fstat (fileno (hFile), &statbuf) || !(statbuf.st_mode & S_IFREG)) + return 0; + + return statbuf.st_size; +} + +uint32_t DoGetFilePosition (FILE *hFile) +{ + return ftell (hFile); +} + +int DoSetFilePositionAbsolute (FILE *hFile, uint32_t pos) +{ + return fseek (hFile, pos, SEEK_SET); +} + +int DoSetFilePositionRelative (FILE *hFile, int32_t pos, int mode) +{ + return fseek (hFile, pos, mode); +} + +// 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 !remove (filename); +} + diff --git a/Libraries/WavPack/Files/wavpack.c b/Libraries/WavPack/Files/wavpack.c index 50ec1b34c..13c7bc31f 100644 --- a/Libraries/WavPack/Files/wavpack.c +++ b/Libraries/WavPack/Files/wavpack.c @@ -1,1448 +1,1646 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// wavpack.c - -// This is the main module for the WavPack command-line compressor. - -#if defined(WIN32) -#include -#include -#else -#include -#include -#endif - -#include -#include -#include -#include - -#include "wavpack.h" -#include "md5.h" - -#ifdef __BORLANDC__ -#include -#else -#if defined (__GNUC__) && !defined(WIN32) -#include -#include -#include -#else -#include -#endif -#endif - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -static char *strdup (const char *s) - { char *d = malloc (strlen (s) + 1); return strcpy (d, s); } -#endif - -///////////////////////////// local variable storage ////////////////////////// - -static const char *sign_on = "\n" -" WAVPACK Hybrid Lossless Wavefile Compressor %s Version %s %s\n" -" Copyright (c) 1998 - 2005 Conifer Software. All Rights Reserved.\n\n"; - -static const char *usage = -" Usage: WAVPACK [-options] [@]infile[.wav]|- [[@]outfile[.wv]|outpath|-]\n" -" (default is lossless; infile may contain wildcards: ?,*)\n\n" -" Options: -a = Adobe Audition (CoolEdit) mode for 32-bit floats\n" -" -bn = enable hybrid compression, n = 2.0 to 23.9 bits/sample, or\n" -" n = 24-9600 kbits/second (kbps)\n" -" -c = create correction file (.wvc) for hybrid mode (=lossless)\n" -" -cc = maximum hybrid compression (hurts lossy quality & decode speed)\n" -" -d = delete source file if successful (use with caution!)\n" -#if defined (WIN32) -" -e = create self-extracting executable (needs wvselfx.exe)\n" -#endif -" -f = fast mode (fast, but some compromise in compression ratio)\n" -" -h = high quality (best compression in all modes, but slower)\n" -" -i = ignore length in wav header (no pipe output allowed)\n" -" -jn = joint-stereo override (0 = left/right, 1 = mid/side)\n" -" -m = compute & store MD5 signature of raw audio data\n" -" -n = calculate average and peak quantization noise (hybrid only)\n" -" -p = practical float storage (also 32-bit ints, not lossless)\n" -" -q = quiet (keep console output to a minimum)\n" -" -sn = noise shaping override (hybrid only, n = -1.0 to 1.0, 0 = off)\n" -#if defined (WIN32) -" -t = copy input file's time stamp to output file(s)\n" -#endif -" -w \"Field=Value\" = write specified metadata to APEv2 tag\n" -" -x[n] = extra encode processing (optional n = 1-6 for less/more)\n" -" -y = yes to all warnings (use with caution!)\n\n" -" Web: Visit www.wavpack.com for latest version and info\n"; - -static int overwrite_all, num_files, file_index; - -#if defined (WIN32) -static char *wvselfx_image; -static uint32_t wvselfx_size; -#endif - -/////////////////////////// local function declarations /////////////////////// - -static int pack_file (char *infilename, char *outfilename, char *out2filename, const WavpackConfig *config); -static int pack_audio (WavpackContext *wpc, FILE *infile); -static void display_progress (double file_progress); - -#define NO_ERROR 0L -#define SOFT_ERROR 1 -#define HARD_ERROR 2 - -////////////////////////////////////////////////////////////////////////////// -// The "main" function for the command-line WavPack compressor. // -////////////////////////////////////////////////////////////////////////////// - -int main (argc, argv) int argc; char **argv; -{ - int delete_source = 0, usage_error = 0, filelist = 0, tag_next_arg = 0; - char *infilename = NULL, *outfilename = NULL, *out2filename = NULL; - char **matches = NULL; - WavpackConfig config; - int result, i; - -#if defined (WIN32) - char *selfname = malloc (strlen (*argv) + PATH_MAX); - struct _finddata_t _finddata_t; - - strcpy (selfname, *argv); -#else - glob_t globs; - struct stat fstats; -#endif - - CLEAR (config); - -#if 0 - { - char **argv_t = argv; - int argc_t = argc; - - while (--argc_t) - error_line ("%d: %s", argc - argc_t, *++argv_t); - } -#endif - - // loop through command-line arguments - - while (--argc) -#if defined (WIN32) - if ((**++argv == '-' || **argv == '/') && (*argv)[1]) -#else - if ((**++argv == '-') && (*argv)[1]) -#endif - while (*++*argv) - switch (**argv) { - - case 'Y': case 'y': - overwrite_all = 1; - break; - - case 'D': case 'd': - delete_source = 1; - break; - - case 'C': case 'c': - if (config.flags & CONFIG_CREATE_WVC) - config.flags |= CONFIG_OPTIMIZE_WVC; - else - config.flags |= CONFIG_CREATE_WVC; - - break; - - case 'X': case 'x': - config.xmode = strtol (++*argv, argv, 10); - - if (config.xmode < 0 || config.xmode > 6) { - error_line ("extra mode only goes from 1 to 6!"); - usage_error = 1; - } - else - config.flags |= CONFIG_EXTRA_MODE; - - --*argv; - break; - - case 'F': case 'f': - if (config.flags & CONFIG_FAST_FLAG) - config.flags |= CONFIG_VERY_FAST_FLAG; - else - config.flags |= CONFIG_FAST_FLAG; - - break; - - case 'H': case 'h': - if (config.flags & CONFIG_HIGH_FLAG) - config.flags |= CONFIG_VERY_HIGH_FLAG; - else - config.flags |= CONFIG_HIGH_FLAG; - - break; - - case 'N': case 'n': - config.flags |= CONFIG_CALC_NOISE; - break; - - case 'A': case 'a': - config.flags |= CONFIG_ADOBE_MODE; - break; -#if defined (WIN32) - case 'E': case 'e': - config.flags |= CONFIG_CREATE_EXE; - break; - - case 'T': case 't': - config.flags |= CONFIG_COPY_TIME; - break; -#endif - case 'P': case 'p': - config.flags |= CONFIG_SKIP_WVX; - break; - - case 'Q': case 'q': - config.flags |= CONFIG_QUIET_MODE; - break; - - case 'M': case 'm': - config.flags |= CONFIG_MD5_CHECKSUM; - break; - - case 'I': case 'i': - config.flags |= CONFIG_IGNORE_LENGTH; - break; - - case 'K': case 'k': - config.block_samples = strtol (++*argv, argv, 10); - --*argv; - break; - - case 'B': case 'b': - config.flags |= CONFIG_HYBRID_FLAG; - config.bitrate = strtod (++*argv, argv); - --*argv; - - if (config.bitrate < 2.0 || config.bitrate > 9600.0) { - error_line ("hybrid spec must be 2.0 to 9600!"); - usage_error = 1; - } - - if (config.bitrate >= 24.0) - config.flags |= CONFIG_BITRATE_KBPS; - - break; - - case 'J': case 'j': - switch (strtol (++*argv, argv, 10)) { - - case 0: - config.flags |= CONFIG_JOINT_OVERRIDE; - config.flags &= ~CONFIG_JOINT_STEREO; - break; - - case 1: - config.flags |= (CONFIG_JOINT_OVERRIDE | CONFIG_JOINT_STEREO); - break; - - default: - error_line ("-j0 or -j1 only!"); - usage_error = 1; - } - - --*argv; - break; - - case 'S': case 's': - config.shaping_weight = strtod (++*argv, argv); - - if (!config.shaping_weight) { - config.flags |= CONFIG_SHAPE_OVERRIDE; - config.flags &= ~CONFIG_HYBRID_SHAPE; - } - else if (config.shaping_weight >= -1.0 && config.shaping_weight <= 1.0) - config.flags |= (CONFIG_HYBRID_SHAPE | CONFIG_SHAPE_OVERRIDE); - else { - error_line ("-s-1.00 to -s1.00 only!"); - usage_error = 1; - } - - --*argv; - break; - - case 'W': case 'w': - tag_next_arg = 1; - break; - - default: - error_line ("illegal option: %c !", **argv); - usage_error = 1; - } - else { - if (tag_next_arg) { - char *cp = strchr (*argv, '='), *string = NULL; - - tag_next_arg = 0; - - if (cp && cp > *argv) { - int item_len = cp - *argv; - - if (cp [1] == '@') { - FILE *file = fopen (cp+2, "rb"); - - if (file) { - uint32_t bcount, file_len; - - file_len = DoGetFileSize (file); - - if (file_len < 1048576 && (string = malloc (item_len + file_len + 2)) != NULL) { - memcpy (string, *argv, item_len + 1); - - if (!DoReadFile (file, string + item_len + 1, file_len, &bcount) || bcount != file_len) { - free (string); - string = NULL; - } - else - string [item_len + file_len + 1] = 0; - } - - DoCloseHandle (file); - } - } - else - string = *argv; - } - - if (!string) { - error_line ("error in tag spec: %s !", *argv); - usage_error = 1; - } - else if (cp [1]) { - config.tag_strings = realloc (config.tag_strings, ++config.num_tag_strings * sizeof (*config.tag_strings)); - config.tag_strings [config.num_tag_strings - 1] = string; - } - } - else if (!infilename) { - infilename = malloc (strlen (*argv) + PATH_MAX); - strcpy (infilename, *argv); - } - else if (!outfilename) { - outfilename = malloc (strlen (*argv) + PATH_MAX); - strcpy (outfilename, *argv); - } - else if (!out2filename) { - out2filename = malloc (strlen (*argv) + PATH_MAX); - strcpy (out2filename, *argv); - } - else { - error_line ("extra unknown argument: %s !", *argv); - usage_error = 1; - } - } - - setup_break (); // set up console and detect ^C and ^Break - - // check for various command-line argument problems - - if (!(~config.flags & (CONFIG_HIGH_FLAG | CONFIG_FAST_FLAG))) { - error_line ("high and fast modes are mutually exclusive!"); - usage_error = 1; - } - - if ((config.flags & CONFIG_IGNORE_LENGTH) && outfilename && *outfilename == '-') { - error_line ("can't ignore length in header when using stdout!"); - usage_error = 1; - } - - if (config.flags & CONFIG_HYBRID_FLAG) { - if ((config.flags & CONFIG_CREATE_WVC) && outfilename && *outfilename == '-') { - error_line ("can't create correction file when using stdout!"); - usage_error = 1; - } - } - else { - if (config.flags & (CONFIG_CALC_NOISE | CONFIG_SHAPE_OVERRIDE | CONFIG_CREATE_WVC)) { - error_line ("-s, -n and -c options are for hybrid mode (-b) only!"); - usage_error = 1; - } - } - - if (!(config.flags & CONFIG_QUIET_MODE) && !usage_error) - fprintf (stderr, sign_on, VERSION_OS, VERSION_STR, DATE_STR); - - if (!infilename) { - printf ("%s", usage); - return 0; - } - - if (usage_error) { - free(infilename); - return 0; - } - - // If we are trying to create self-extracting .exe files, this is where - // we read the wvselfx.exe file into memory in preparation for pre-pending - // it to the WavPack files. - -#if defined (WIN32) - if (config.flags & CONFIG_CREATE_EXE) { - FILE *wvselfx_file; - uint32_t bcount; - - strcpy (filespec_name (selfname), "wvselfx.exe"); - - wvselfx_file = fopen (selfname, "rb"); - - if (!wvselfx_file) { - _searchenv ("wvselfx.exe", "PATH", selfname); - wvselfx_file = fopen (selfname, "rb"); - } - - if (wvselfx_file) { - wvselfx_size = DoGetFileSize (wvselfx_file); - - if (wvselfx_size && wvselfx_size != 26624 && wvselfx_size < 49152) { - wvselfx_image = malloc (wvselfx_size); - - if (!DoReadFile (wvselfx_file, wvselfx_image, wvselfx_size, &bcount) || bcount != wvselfx_size) { - free (wvselfx_image); - wvselfx_image = NULL; - } - } - - DoCloseHandle (wvselfx_file); - } - - if (!wvselfx_image) { - error_line ("wvselfx.exe file is not readable or is outdated!"); - free (wvselfx_image); - exit (1); - } - } -#endif - - // If the infile specification begins with a '@', then it actually points - // to a file that contains the names of the files to be converted. This - // was included for use by Wim Speekenbrink's frontends, but could be used - // for other purposes. - - if (infilename [0] == '@') { - FILE *list = fopen (infilename+1, "rt"); - int c; - - if (list == NULL) { - error_line ("file %s not found!", infilename+1); - free (infilename); - return 1; - } - - while ((c = getc (list)) != EOF) { - - while (c == '\n') - c = getc (list); - - if (c != EOF) { - char *fname = malloc (PATH_MAX); - int ci = 0; - - do - fname [ci++] = c; - while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); - - fname [ci++] = '\0'; - matches = realloc (matches, ++num_files * sizeof (*matches)); - matches [num_files - 1] = realloc (fname, ci); - } - } - - fclose (list); - free (infilename); - infilename = NULL; - filelist = 1; - } - else if (*infilename != '-') { // skip this if infile is stdin (-) - if (!(config.flags & CONFIG_RAW_FLAG) && !filespec_ext (infilename)) - strcat (infilename, ".wav"); - -#ifdef NO_WILDCARDS - matches = malloc (sizeof (*matches)); - matches [num_files++] = infilename; - filelist = 1; -#else - // search for and store any filenames that match the user supplied spec - -#ifdef __BORLANDC__ - if (findfirst (infilename, &ffblk, 0) == 0) { - do { - matches = realloc (matches, ++num_files * sizeof (*matches)); - matches [num_files - 1] = strdup (ffblk.ff_name); - } while (findnext (&ffblk) == 0); - } -#elif defined (WIN32) - if ((i = _findfirst (infilename, &_finddata_t)) != -1L) { - do { - if (!(_finddata_t.attrib & _A_SUBDIR)) { - matches = realloc (matches, ++num_files * sizeof (*matches)); - matches [num_files - 1] = strdup (_finddata_t.name); - } - } while (_findnext (i, &_finddata_t) == 0); - - _findclose (i); - } -#else - i = 0; - if (glob(infilename, 0, NULL, &globs) == 0 && globs.gl_pathc > 0) { - do { - if (stat(globs.gl_pathv[i], &fstats) == 0 && !(fstats.st_mode & S_IFDIR)) { - matches = realloc (matches, ++num_files * sizeof (*matches)); - matches [num_files - 1] = strdup (globs.gl_pathv[i]); - } - } while (i++ < globs.gl_pathc); - } - globfree(&globs); -#endif -#endif - } - else { // handle case of stdin (-) - matches = malloc (sizeof (*matches)); - matches [num_files++] = infilename; - } - - // If the outfile specification begins with a '@', then it actually points - // to a file that contains the output specification. This was included for - // use by Wim Speekenbrink's frontends because certain filenames could not - // be passed on the command-line, but could be used for other purposes. - - if (outfilename && outfilename [0] == '@') { - FILE *list = fopen (outfilename+1, "rt"); - int c; - - if (list == NULL) { - error_line ("file %s not found!", outfilename+1); - free(outfilename); - return 1; - } - - while ((c = getc (list)) == '\n'); - - if (c != EOF) { - int ci = 0; - - do - outfilename [ci++] = c; - while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); - - outfilename [ci] = '\0'; - } - else { - error_line ("output spec file is empty!"); - free(outfilename); - fclose (list); - return 1; - } - - fclose (list); - } - - if (out2filename && (num_files > 1 || !(config.flags & CONFIG_CREATE_WVC))) { - error_line ("extra unknown argument: %s !", out2filename); - return 1; - } - - // if we found any files to process, this is where we start - - if (num_files) { - char outpath, addext; - int soft_errors = 0; - - if (outfilename && *outfilename != '-') { - outpath = (filespec_path (outfilename) != NULL); - - if (num_files > 1 && !outpath) { - error_line ("%s is not a valid output path", outfilename); - free(outfilename); - return 1; - } - } - else - outpath = 0; - - addext = !outfilename || outpath || !filespec_ext (outfilename); - - // loop through and process files in list - - for (file_index = 0; file_index < num_files; ++file_index) { - if (check_break ()) - break; - - // get input filename from list - - if (filelist) - infilename = matches [file_index]; - else if (*infilename != '-') { - *filespec_name (infilename) = '\0'; - strcat (infilename, matches [file_index]); - } - - // generate output filename - - if (outpath) { - strcat (outfilename, filespec_name (matches [file_index])); - - if (filespec_ext (outfilename)) - *filespec_ext (outfilename) = '\0'; - } - else if (!outfilename) { - outfilename = malloc (strlen (infilename) + 10); - strcpy (outfilename, infilename); - - if (filespec_ext (outfilename)) - *filespec_ext (outfilename) = '\0'; - } - - if (addext && *outfilename != '-') - strcat (outfilename, (config.flags & CONFIG_CREATE_EXE) ? ".exe" : ".wv"); - - // if "correction" file is desired, generate name for that - - if (config.flags & CONFIG_CREATE_WVC) { - if (!out2filename) { - out2filename = malloc (strlen (outfilename) + 10); - strcpy (out2filename, outfilename); - } - else { - char *temp = malloc (strlen (outfilename) + PATH_MAX); - - strcpy (temp, outfilename); - strcpy (filespec_name (temp), filespec_name (out2filename)); - strcpy (out2filename, temp); - free (temp); - } - - if (filespec_ext (out2filename)) - *filespec_ext (out2filename) = '\0'; - - strcat (out2filename, ".wvc"); - } - else - out2filename = NULL; - - if (num_files > 1) - fprintf (stderr, "\n%s:\n", infilename); - - result = pack_file (infilename, outfilename, out2filename, &config); - - if (result == HARD_ERROR) - break; - else if (result == SOFT_ERROR) - ++soft_errors; - - // delete source file if that option is enabled - - if (result == NO_ERROR && delete_source) - error_line ("%s source file %s", DoDeleteFile (infilename) ? - "deleted" : "can't delete", infilename); - - // clean up in preparation for potentially another file - - if (outpath) - *filespec_name (outfilename) = '\0'; - else if (*outfilename != '-') { - free (outfilename); - outfilename = NULL; - } - - if (out2filename) { - free (out2filename); - out2filename = NULL; - } - - free (matches [file_index]); - } - - if (num_files > 1) { - if (soft_errors) - fprintf (stderr, "\n **** warning: errors occurred in %d of %d files! ****\n", soft_errors, num_files); - else if (!(config.flags & CONFIG_QUIET_MODE)) - fprintf (stderr, "\n **** %d files successfully processed ****\n", num_files); - } - - free (matches); - } - else - error_line (filespec_wild (infilename) ? "nothing to do!" : - "file %s not found!", infilename); - - if (outfilename) - free(outfilename); - -#ifdef DEBUG_ALLOC - error_line ("malloc_count = %d", dump_alloc ()); -#endif - - return 0; -} - -// This structure and function are used to write completed WavPack blocks in -// a device independent way. - -typedef struct { - uint32_t bytes_written, first_block_size; - FILE *file; - int error; -} write_id; - -static int write_block (void *id, void *data, int32_t length) -{ - write_id *wid = (write_id *) id; - uint32_t bcount; - - if (wid->error) - return FALSE; - - if (wid && wid->file && data && length) { - if (!DoWriteFile (wid->file, data, length, &bcount) || bcount != length) { - DoTruncateFile (wid->file); - DoCloseHandle (wid->file); - wid->file = NULL; - wid->error = 1; - return FALSE; - } - else { - wid->bytes_written += length; - - if (!wid->first_block_size) - wid->first_block_size = bcount; - } - } - - return TRUE; -} - -// This function packs a single file "infilename" and stores the result at -// "outfilename". If "out2filename" is specified, then the "correction" -// file would go there. The files are opened and closed in this function -// and the "config" structure specifies the mode of compression. - -static int pack_file (char *infilename, char *outfilename, char *out2filename, const WavpackConfig *config) -{ - uint32_t total_samples = 0, wrapper_size = 0, bcount; - WavpackConfig loc_config = *config; - RiffChunkHeader riff_chunk_header; - write_id wv_file, wvc_file; - ChunkHeader chunk_header; - WaveHeader WaveHeader; - WavpackContext *wpc; - double dtime; - FILE *infile; - int result; - -#ifdef __BORLANDC__ - struct time time1, time2; -#elif defined(WIN32) - struct _timeb time1, time2; -#else - struct timeval time1, time2; - struct timezone timez; -#endif - - CLEAR (wv_file); - CLEAR (wvc_file); - wpc = WavpackOpenFileOutput (write_block, &wv_file, out2filename ? &wvc_file : NULL); - - // open the source file for reading - - if (*infilename == '-') { - infile = stdin; -#if defined(WIN32) - setmode (fileno (stdin), O_BINARY); -#endif - } - else if ((infile = fopen (infilename, "rb")) == NULL) { - error_line ("can't open file %s!", infilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - // check both output files for overwrite warning required - - if (*outfilename != '-' && !overwrite_all && (wv_file.file = fopen (outfilename, "rb")) != NULL) { - DoCloseHandle (wv_file.file); - fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (outfilename)); - SetConsoleTitle ("overwrite?"); - - switch (yna ()) { - case 'n': - DoCloseHandle (infile); - WavpackCloseFile (wpc); - return SOFT_ERROR; - - case 'a': - overwrite_all = 1; - } - } - - if (out2filename && !overwrite_all && (wvc_file.file = fopen (out2filename, "rb")) != NULL) { - DoCloseHandle (wvc_file.file); - fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (out2filename)); - SetConsoleTitle ("overwrite?"); - - switch (yna ()) { - - case 'n': - DoCloseHandle (infile); - WavpackCloseFile (wpc); - return SOFT_ERROR; - - case 'a': - overwrite_all = 1; - } - } - -#ifdef __BORLANDC__ - gettime (&time1); -#elif defined(WIN32) - _ftime (&time1); -#else - gettimeofday(&time1,&timez); -#endif - - // open output file for writing - - if (*outfilename == '-') { - wv_file.file = stdout; -#if defined(WIN32) - setmode (fileno (stdout), O_BINARY); -#endif - } - else if ((wv_file.file = fopen (outfilename, "w+b")) == NULL) { - error_line ("can't create file %s!", outfilename); - DoCloseHandle (infile); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - if (!(loc_config.flags & CONFIG_QUIET_MODE)) { - if (*outfilename == '-') - fprintf (stderr, "packing %s to stdout,", *infilename == '-' ? "stdin" : FN_FIT (infilename)); - else if (out2filename) - fprintf (stderr, "creating %s (+%s),", FN_FIT (outfilename), filespec_ext (out2filename)); - else - fprintf (stderr, "creating %s,", FN_FIT (outfilename)); - } - -#if defined (WIN32) - if (loc_config.flags & CONFIG_CREATE_EXE) - if (!DoWriteFile (wv_file.file, wvselfx_image, wvselfx_size, &bcount) || bcount != wvselfx_size) { - error_line ("can't write WavPack data, disk probably full!"); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } -#endif - - // if not in "raw" mode, read (and copy to output) initial RIFF form header - - if (!(loc_config.flags & CONFIG_RAW_FLAG)) { - if ((!DoReadFile (infile, &riff_chunk_header, sizeof (RiffChunkHeader), &bcount) || - bcount != sizeof (RiffChunkHeader) || strncmp (riff_chunk_header.ckID, "RIFF", 4) || - strncmp (riff_chunk_header.formType, "WAVE", 4))) { - error_line ("%s is not a valid .WAV file!", infilename); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - else if (!WavpackAddWrapper (wpc, &riff_chunk_header, sizeof (RiffChunkHeader))) { - error_line ("%s", wpc->error_message); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - wrapper_size += sizeof (RiffChunkHeader); - } - - // if not in "raw" mode, loop through all elements of the RIFF wav header - // (until the data chuck) and copy them to the output file - - while (!(loc_config.flags & CONFIG_RAW_FLAG)) { - - if (!DoReadFile (infile, &chunk_header, sizeof (ChunkHeader), &bcount) || - bcount != sizeof (ChunkHeader)) { - error_line ("%s is not a valid .WAV file!", infilename); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - else if (!WavpackAddWrapper (wpc, &chunk_header, sizeof (ChunkHeader))) { - error_line ("%s", wpc->error_message); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - wrapper_size += sizeof (ChunkHeader); - little_endian_to_native (&chunk_header, ChunkHeaderFormat); - - // if it's the format chunk, we want to get some info out of there and - // make sure it's a .wav file we can handle - - if (!strncmp (chunk_header.ckID, "fmt ", 4)) { - int supported = TRUE, format; - - if (chunk_header.ckSize < 16 || chunk_header.ckSize > sizeof (WaveHeader) || - !DoReadFile (infile, &WaveHeader, chunk_header.ckSize, &bcount) || - bcount != chunk_header.ckSize) { - error_line ("%s is not a valid .WAV file!", infilename); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - else if (!WavpackAddWrapper (wpc, &WaveHeader, chunk_header.ckSize)) { - error_line ("%s", wpc->error_message); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - wrapper_size += chunk_header.ckSize; - little_endian_to_native (&WaveHeader, WaveHeaderFormat); - -#if 0 - error_line ("format tag size = %d", chunk_header.ckSize); - error_line ("FormatTag = %x, NumChannels = %d, BitsPerSample = %d", - WaveHeader.FormatTag, WaveHeader.NumChannels, WaveHeader.BitsPerSample); - error_line ("BlockAlign = %d, SampleRate = %d, BytesPerSecond = %d", - WaveHeader.BlockAlign, WaveHeader.SampleRate, WaveHeader.BytesPerSecond); - - if (chunk_header.ckSize > 16) - error_line ("cbSize = %d, ValidBitsPerSample = %d", WaveHeader.cbSize, - WaveHeader.ValidBitsPerSample); - - if (chunk_header.ckSize > 20) - error_line ("ChannelMask = %x, SubFormat = %d", - WaveHeader.ChannelMask, WaveHeader.SubFormat); -#endif - - if (chunk_header.ckSize > 16 && WaveHeader.cbSize == 2) - loc_config.flags |= CONFIG_ADOBE_MODE; - - format = (WaveHeader.FormatTag == 0xfffe && chunk_header.ckSize == 40) ? - WaveHeader.SubFormat : WaveHeader.FormatTag; - - loc_config.bits_per_sample = chunk_header.ckSize == 40 ? - WaveHeader.ValidBitsPerSample : WaveHeader.BitsPerSample; - - if (format != 1 && format != 3) - supported = FALSE; - - if (!WaveHeader.NumChannels || - WaveHeader.BlockAlign / WaveHeader.NumChannels > 4) - supported = FALSE; - - if (loc_config.bits_per_sample < 1 || loc_config.bits_per_sample > 32) - supported = FALSE; - - if (!supported) { - error_line ("%s is an unsupported .WAV format!", infilename); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - if (chunk_header.ckSize < 40) { - if (WaveHeader.NumChannels <= 2) - loc_config.channel_mask = 0x5 - WaveHeader.NumChannels; - else - loc_config.channel_mask = (1 << WaveHeader.NumChannels) - 1; - } - else - loc_config.channel_mask = WaveHeader.ChannelMask; - - if (format == 3) - loc_config.float_norm_exp = 127; - else if ((loc_config.flags & CONFIG_ADOBE_MODE) && - WaveHeader.BlockAlign / WaveHeader.NumChannels == 4) { - if (WaveHeader.BitsPerSample == 24) - loc_config.float_norm_exp = 127 + 23; - else if (WaveHeader.BitsPerSample == 32) - loc_config.float_norm_exp = 127 + 15; - } - } - else if (!strncmp (chunk_header.ckID, "data", 4)) { - - // on the data chunk, get size and exit loop - - total_samples = chunk_header.ckSize / WaveHeader.BlockAlign; - break; - } - else { // just copy unknown chunks to output file - - int bytes_to_copy = (chunk_header.ckSize + 1) & ~1L; - char *buff = malloc (bytes_to_copy); -#if 0 - error_line ("extra unknown chunk \"%c%c%c%c\" of %d bytes", - chunk_header.ckID [0], chunk_header.ckID [1], chunk_header.ckID [2], - chunk_header.ckID [3], chunk_header.ckSize); -#endif - if (!DoReadFile (infile, buff, bytes_to_copy, &bcount) || - bcount != bytes_to_copy || !WavpackAddWrapper (wpc, buff, bytes_to_copy)) { - error_line ("%s", wpc->error_message); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (outfilename); - free (buff); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - wrapper_size += bytes_to_copy; - free (buff); - } - } - - loc_config.bytes_per_sample = WaveHeader.BlockAlign / WaveHeader.NumChannels; - loc_config.num_channels = WaveHeader.NumChannels; - loc_config.sample_rate = WaveHeader.SampleRate; - - WavpackSetConfiguration (wpc, &loc_config, total_samples); - - // if we are creating a "correction" file, open it now for writing - - if (out2filename) { - if ((wvc_file.file = fopen (out2filename, "w+b")) == NULL) { - error_line ("can't create correction file!"); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - } - - // pack the audio portion of the file now - - result = pack_audio (wpc, infile); - - // if everything went well (and we're not ignoring length) try to read - // anything else that might be appended to the audio data and write that - // to the WavPack metadata as "wrapper" - - if (result == NO_ERROR && !(loc_config.flags & CONFIG_IGNORE_LENGTH)) { - uchar buff [16]; - - while (DoReadFile (infile, buff, sizeof (buff), &bcount) && bcount) - if (!WavpackAddWrapper (wpc, buff, bcount)) { - error_line ("%s", wpc->error_message); - result = HARD_ERROR; - break; - } - } - - DoCloseHandle (infile); // we're now done with input file, so close - - // we're now done with any WavPack blocks, so flush any remaining data - - if (result == NO_ERROR && !WavpackFlushSamples (wpc)) { - error_line ("%s", wpc->error_message); - result = HARD_ERROR; - } - - // if still no errors, check to see if we need to create & write a tag - // (which is NOT stored in regular WavPack blocks) - - if (result == NO_ERROR && config->num_tag_strings) { - int i; - - for (i = 0; i < config->num_tag_strings; ++i) { - int item_len = strchr (config->tag_strings [i], '=') - config->tag_strings [i]; - int value_len = strlen (config->tag_strings [i]) - item_len - 1; - - if (value_len) { - char *item = malloc (item_len + 1); - char *value = malloc (value_len * 2 + 1); - - strncpy (item, config->tag_strings [i], item_len); - item [item_len] = 0; - strcpy (value, config->tag_strings [i] + item_len + 1); - AnsiToUTF8 (value, value_len * 2 + 1); - WavpackAppendTagItem (wpc, item, value); - free (value); - free (item); - } - } - - if (!WavpackWriteTag (wpc)) { - error_line ("%s", wpc->error_message); - result = HARD_ERROR; - } - } - - // At this point we're done writing to the output files. However, in some - // situations we might have to back up and re-write the initial blocks. - // Currently the only case is if we're ignoring length. - - if (result == NO_ERROR && WavpackGetNumSamples (wpc) != WavpackGetSampleIndex (wpc)) { - if (loc_config.flags & CONFIG_IGNORE_LENGTH) { - char *block_buff = malloc (wv_file.first_block_size); - - if (block_buff && !DoSetFilePositionAbsolute (wv_file.file, 0) && - DoReadFile (wv_file.file, block_buff, wv_file.first_block_size, &bcount) && - bcount == wv_file.first_block_size && !strncmp (block_buff, "wvpk", 4)) { - - WavpackUpdateNumSamples (wpc, block_buff); - - if (WavpackGetWrapperLocation (block_buff)) { - RiffChunkHeader *riffhdr = WavpackGetWrapperLocation (block_buff); - ChunkHeader *datahdr = (ChunkHeader *)((char *) riffhdr + wrapper_size - sizeof (ChunkHeader)); - uint32_t data_size = WavpackGetSampleIndex (wpc) * WavpackGetNumChannels (wpc) * WavpackGetBytesPerSample (wpc); - - if (!strncmp (riffhdr->ckID, "RIFF", 4)) { - little_endian_to_native (riffhdr, ChunkHeaderFormat); - riffhdr->ckSize = wrapper_size + data_size; - native_to_little_endian (riffhdr, ChunkHeaderFormat); - } - - if (!strncmp (datahdr->ckID, "data", 4)) { - little_endian_to_native (datahdr, ChunkHeaderFormat); - datahdr->ckSize = data_size; - native_to_little_endian (datahdr, ChunkHeaderFormat); - } - } - - if (DoSetFilePositionAbsolute (wv_file.file, 0) || - !DoWriteFile (wv_file.file, block_buff, wv_file.first_block_size, &bcount) || - bcount != wv_file.first_block_size) { - error_line ("couldn't update WavPack header with actual length!!"); - result = SOFT_ERROR; - } - - free (block_buff); - } - else { - error_line ("couldn't update WavPack header with actual length!!"); - result = SOFT_ERROR; - } - - if (result == NO_ERROR && wvc_file.file) { - block_buff = malloc (wvc_file.first_block_size); - - if (block_buff && !DoSetFilePositionAbsolute (wvc_file.file, 0) && - DoReadFile (wvc_file.file, block_buff, wvc_file.first_block_size, &bcount) && - bcount == wvc_file.first_block_size && !strncmp (block_buff, "wvpk", 4)) { - - WavpackUpdateNumSamples (wpc, block_buff); - - if (DoSetFilePositionAbsolute (wvc_file.file, 0) || - !DoWriteFile (wvc_file.file, block_buff, wvc_file.first_block_size, &bcount) || - bcount != wvc_file.first_block_size) { - error_line ("couldn't update WavPack header with actual length!!"); - result = SOFT_ERROR; - } - } - else { - error_line ("couldn't update WavPack header with actual length!!"); - result = SOFT_ERROR; - } - - free (block_buff); - } - - if (result == NO_ERROR) - error_line ("warning: length was %s by %d samples, corrected", - WavpackGetSampleIndex (wpc) < total_samples ? "short" : "long", - abs (total_samples - WavpackGetSampleIndex (wpc))); - } - else { - error_line ("couldn't read all samples, file may be corrupt!!"); - result = SOFT_ERROR; - } - } - - // at this point we're done with the files, so close 'em whether there - // were any other errors or not - - if (!DoCloseHandle (wv_file.file)) { - error_line ("can't close WavPack file!"); - - if (result == NO_ERROR) - result = SOFT_ERROR; - } - - if (out2filename && !DoCloseHandle (wvc_file.file)) { - error_line ("can't close correction file!"); - - if (result == NO_ERROR) - result = SOFT_ERROR; - } - - // if there were any errors, delete the output files, close the context, - // and return the error - - if (result != NO_ERROR) { - DoDeleteFile (outfilename); - - if (out2filename) - DoDeleteFile (out2filename); - - WavpackCloseFile (wpc); - return result; - } - -#if defined (WIN32) - if (result == NO_ERROR && (loc_config.flags & CONFIG_COPY_TIME)) - if (!copy_timestamp (infilename, outfilename) || - (out2filename && !copy_timestamp (infilename, out2filename))) - error_line ("failure copying time stamp!"); -#endif - - // compute and display the time consumed along with some other details of - // the packing operation, and then return NO_ERROR - -#ifdef __BORLANDC__ - gettime (&time2); - dtime = time2.ti_sec * 100.0 + time2.ti_hund + time2.ti_min * 6000.0 + time2.ti_hour * 360000.00; - dtime -= time1.ti_sec * 100.0 + time1.ti_hund + time1.ti_min * 6000.0 + time1.ti_hour * 360000.00; - - if ((dtime /= 100.0) < 0.0) - dtime += 86400.0; -#elif defined(WIN32) - _ftime (&time2); - dtime = time2.time + time2.millitm / 1000.0; - dtime -= time1.time + time1.millitm / 1000.0; -#else - gettimeofday(&time2,&timez); - dtime = time2.tv_sec + time2.tv_usec / 1000000.0; - dtime -= time1.tv_sec + time1.tv_usec / 1000000.0; -#endif - - if ((loc_config.flags & CONFIG_CALC_NOISE) && pack_noise (wpc, NULL) > 0.0) { - int full_scale_bits = WavpackGetBitsPerSample (wpc); - double full_scale_rms = 0.5, sum, peak; - - while (full_scale_bits--) - full_scale_rms *= 2.0; - - full_scale_rms = full_scale_rms * (full_scale_rms - 1.0) * 0.5; - sum = pack_noise (wpc, &peak); - - error_line ("ave noise = %.2f dB, peak noise = %.2f dB", - log10 (sum / WavpackGetNumSamples (wpc) / full_scale_rms) * 10, - log10 (peak / full_scale_rms) * 10); - } - - if (!(loc_config.flags & CONFIG_QUIET_MODE)) { - char *file, *fext, *oper, *cmode, cratio [16] = ""; - - if (outfilename && *outfilename != '-') { - file = FN_FIT (outfilename); - fext = wvc_file.bytes_written ? " (+.wvc)" : ""; - oper = "created"; - } - else { - file = (*infilename == '-') ? "stdin" : FN_FIT (infilename); - fext = ""; - oper = "packed"; - } - - if (WavpackLossyBlocks (wpc)) { - cmode = "lossy"; - - if (WavpackGetAverageBitrate (wpc, TRUE) != 0.0) - sprintf (cratio, ", %d kbps", (int) (WavpackGetAverageBitrate (wpc, TRUE) / 1000.0)); - } - else { - cmode = "lossless"; - - if (WavpackGetRatio (wpc) != 0.0) - sprintf (cratio, ", %.2f%%", 100.0 - WavpackGetRatio (wpc) * 100.0); - } - - error_line ("%s %s%s in %.2f secs (%s%s)", oper, file, fext, dtime, cmode, cratio); - } - - WavpackCloseFile (wpc); - return NO_ERROR; -} - -// This function handles the actual audio data compression. It assumes that the -// input file is positioned at the beginning of the audio data and that the -// WavPack configuration has been set. This is where the conversion from RIFF -// little-endian standard the executing processor's format is done and where -// (if selected) the MD5 sum is calculated and displayed. - -#define INPUT_SAMPLES 65536 - -static int pack_audio (WavpackContext *wpc, FILE *infile) -{ - uint32_t samples_remaining, samples_read = 0; - double progress = -1.0; - int bytes_per_sample; - int32_t *sample_buffer; - uchar *input_buffer; - MD5_CTX md5_context; - - if (wpc->config.flags & CONFIG_MD5_CHECKSUM) - MD5Init (&md5_context); - - WavpackPackInit (wpc); - bytes_per_sample = WavpackGetBytesPerSample (wpc) * WavpackGetNumChannels (wpc); - input_buffer = malloc (INPUT_SAMPLES * bytes_per_sample); - sample_buffer = malloc (INPUT_SAMPLES * sizeof (int32_t) * WavpackGetNumChannels (wpc)); - samples_remaining = WavpackGetNumSamples (wpc); - - while (1) { - uint32_t bytes_to_read, bytes_read = 0; - uint sample_count; - - if ((wpc->config.flags & CONFIG_IGNORE_LENGTH) || samples_remaining > INPUT_SAMPLES) - bytes_to_read = INPUT_SAMPLES * bytes_per_sample; - else - bytes_to_read = samples_remaining * bytes_per_sample; - - samples_remaining -= bytes_to_read / bytes_per_sample; - DoReadFile (infile, input_buffer, bytes_to_read, &bytes_read); - samples_read += sample_count = bytes_read / bytes_per_sample; - - if (wpc->config.flags & CONFIG_MD5_CHECKSUM) - MD5Update (&md5_context, input_buffer, bytes_read); - - if (!sample_count) - break; - - if (sample_count) { - uint cnt = sample_count * WavpackGetNumChannels (wpc); - uchar *sptr = input_buffer; - int32_t *dptr = sample_buffer; - - switch (WavpackGetBytesPerSample (wpc)) { - - case 1: - while (cnt--) - *dptr++ = *sptr++ - 128; - - break; - - case 2: - while (cnt--) { - *dptr++ = sptr [0] | ((int32_t)(char) sptr [1] << 8); - sptr += 2; - } - - break; - - case 3: - while (cnt--) { - *dptr++ = sptr [0] | ((int32_t) sptr [1] << 8) | ((int32_t)(char) sptr [2] << 16); - sptr += 3; - } - - break; - - case 4: - while (cnt--) { - *dptr++ = sptr [0] | ((int32_t) sptr [1] << 8) | ((int32_t) sptr [2] << 16) | ((int32_t)(char) sptr [3] << 24); - sptr += 4; - } - - break; - } - } - - if (!WavpackPackSamples (wpc, sample_buffer, sample_count)) { - error_line ("%s", wpc->error_message); - free (sample_buffer); - free (input_buffer); - return HARD_ERROR; - } - - if (check_break ()) { - fprintf (stderr, "^C\n"); - free (sample_buffer); - free (input_buffer); - return SOFT_ERROR; - } - - if (WavpackGetProgress (wpc) != -1.0 && - progress != floor (WavpackGetProgress (wpc) * 100.0 + 0.5)) { - int nobs = progress == -1.0; - - progress = WavpackGetProgress (wpc); - display_progress (progress); - progress = floor (progress * 100.0 + 0.5); - - if (!(wpc->config.flags & CONFIG_QUIET_MODE)) - fprintf (stderr, "%s%3d%% done...", - nobs ? " " : "\b\b\b\b\b\b\b\b\b\b\b\b", (int) progress); - } - } - - free (sample_buffer); - free (input_buffer); - - if (!WavpackFlushSamples (wpc)) { - error_line ("%s", wpc->error_message); - return HARD_ERROR; - } - - if (wpc->config.flags & CONFIG_MD5_CHECKSUM) { - char md5_string [] = "original md5 signature: 00000000000000000000000000000000"; - uchar md5_digest [16]; - int i; - - MD5Final (md5_digest, &md5_context); - - for (i = 0; i < 16; ++i) - sprintf (md5_string + 24 + (i * 2), "%02x", md5_digest [i]); - - if (!(wpc->config.flags & CONFIG_QUIET_MODE)) - error_line (md5_string); - - WavpackStoreMD5Sum (wpc, md5_digest); - } - - return NO_ERROR; -} - -////////////////////////////////////////////////////////////////////////////// -// This function displays the progress status on the title bar of the DOS // -// window that WavPack is running in. The "file_progress" argument is for // -// the current file only and ranges from 0 - 1; this function takes into // -// account the total number of files to generate a batch progress number. // -////////////////////////////////////////////////////////////////////////////// - -static void display_progress (double file_progress) -{ - char title [40]; - - file_progress = (file_index + file_progress) / num_files; - sprintf (title, "%d%% (WavPack)", (int) ((file_progress * 100.0) + 0.5)); - SetConsoleTitle (title); -} +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wavpack.c + +// This is the main module for the WavPack command-line compressor. + +#if defined(WIN32) +#include +#include +#else +#include +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "wavpack.h" +#include "md5.h" + +#if defined (__GNUC__) && !defined(WIN32) +#include +#include +#include +#else +#include +#endif + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +static char *strdup (const char *s) + { char *d = malloc (strlen (s) + 1); return strcpy (d, s); } +#endif + +///////////////////////////// local variable storage ////////////////////////// + +static const char *sign_on = "\n" +" WAVPACK Hybrid Lossless Audio Compressor %s Version %s %s\n" +" Copyright (c) 1998 - 2005 Conifer Software. All Rights Reserved.\n\n"; + +static const char *usage = +#if defined (WIN32) +" Usage: WAVPACK [-options] [@]infile[.wav]|- [[@]outfile[.wv]|outpath|-]\n" +#else +" Usage: WAVPACK [-options] [@]infile[.wav]|- [...] [-o [@]outfile[.wv]|outpath|-]\n" +#endif +" (default is lossless; infile may contain wildcards: ?,*)\n\n" +" Options: -a = Adobe Audition (CoolEdit) mode for 32-bit floats\n" +" -bn = enable hybrid compression, n = 2.0 to 23.9 bits/sample, or\n" +" n = 24-9600 kbits/second (kbps)\n" +" -c = create correction file (.wvc) for hybrid mode (=lossless)\n" +" -cc = maximum hybrid compression (hurts lossy quality & decode speed)\n" +" -d = delete source file if successful (use with caution!)\n" +#if defined (WIN32) +" -e = create self-extracting executable (needs wvselfx.exe)\n" +#endif +" -f = fast mode (fast, but some compromise in compression ratio)\n" +" -h = high quality (best compression in all modes, but slower)\n" +" -i = ignore length in wav header (no pipe output allowed)\n" +" -jn = joint-stereo override (0 = left/right, 1 = mid/side)\n" +#if defined (WIN32) +" -l = run at low priority (for smoother multitasking)\n" +#endif +" -m = compute & store MD5 signature of raw audio data\n" +" -n = calculate average and peak quantization noise (hybrid only)\n" +#if !defined (WIN32) +" -o FILENAME | PATH = specify output filename or path\n" +#endif +" -p = practical float storage (also 32-bit ints, not lossless)\n" +" -r = generate new RIFF wav header (removing extra chunk info)\n" +" -q = quiet (keep console output to a minimum)\n" +" -sn = noise shaping override (hybrid only, n = -1.0 to 1.0, 0 = off)\n" +" -t = copy input file's time stamp to output file(s)\n" +" -w \"Field=Value\" = write specified metadata to APEv2 tag\n" +" -x[n] = extra encode processing (optional n = 1-6 for less/more)\n" +" -y = yes to all warnings (use with caution!)\n\n" +" Web: Visit www.wavpack.com for latest version and info\n"; + + +// this global is used to indicate the special "debug" mode where extra debug messages +// are displayed and all messages are logged to the file \wavpack.log + +int debug_logging_mode; + +static int overwrite_all, num_files, file_index; + +#if defined (WIN32) +static char *wvselfx_image; +static uint32_t wvselfx_size; +#endif + +/////////////////////////// local function declarations /////////////////////// + +static FILE *wild_fopen (char *filename, const char *mode); +static int pack_file (char *infilename, char *outfilename, char *out2filename, const WavpackConfig *config); +static int pack_audio (WavpackContext *wpc, FILE *infile); +static void display_progress (double file_progress); + +#define NO_ERROR 0L +#define SOFT_ERROR 1 +#define HARD_ERROR 2 + +////////////////////////////////////////////////////////////////////////////// +// The "main" function for the command-line WavPack compressor. // +////////////////////////////////////////////////////////////////////////////// + +int main (argc, argv) int argc; char **argv; +{ + int delete_source = 0, error_count = 0, tag_next_arg = 0, output_spec = 0; + char *outfilename = NULL, *out2filename = NULL; + char **matches = NULL; + WavpackConfig config; + int result, i; + +#if defined(WIN32) + struct _finddata_t _finddata_t; + char selfname [MAX_PATH]; + + if (GetModuleFileName (NULL, selfname, sizeof (selfname)) && filespec_name (selfname) && + strupr (filespec_name (selfname)) && strstr (filespec_name (selfname), "DEBUG")) { + char **argv_t = argv; + int argc_t = argc; + + debug_logging_mode = TRUE; + + while (--argc_t) + error_line ("arg %d: %s", argc - argc_t, *++argv_t); + } + + strcpy (selfname, *argv); +#else + if (filespec_name (*argv)) + if (strstr (filespec_name (*argv), "ebug") || strstr (filespec_name (*argv), "DEBUG")) { + char **argv_t = argv; + int argc_t = argc; + + debug_logging_mode = TRUE; + + while (--argc_t) + error_line ("arg %d: %s", argc - argc_t, *++argv_t); + } +#endif + + CLEAR (config); + + // loop through command-line arguments + + while (--argc) +#if defined (WIN32) + if ((**++argv == '-' || **argv == '/') && (*argv)[1]) +#else + if ((**++argv == '-') && (*argv)[1]) +#endif + while (*++*argv) + switch (**argv) { + + case 'Y': case 'y': + overwrite_all = 1; + break; + + case 'D': case 'd': + delete_source = 1; + break; + + case 'C': case 'c': + if (config.flags & CONFIG_CREATE_WVC) + config.flags |= CONFIG_OPTIMIZE_WVC; + else + config.flags |= CONFIG_CREATE_WVC; + + break; + + case 'X': case 'x': + config.xmode = strtol (++*argv, argv, 10); + + if (config.xmode < 0 || config.xmode > 6) { + error_line ("extra mode only goes from 1 to 6!"); + ++error_count; + } + else + config.flags |= CONFIG_EXTRA_MODE; + + --*argv; + break; + + case 'F': case 'f': + if (config.flags & CONFIG_FAST_FLAG) + config.flags |= CONFIG_VERY_FAST_FLAG; + else + config.flags |= CONFIG_FAST_FLAG; + + break; + + case 'H': case 'h': + if (config.flags & CONFIG_HIGH_FLAG) + config.flags |= CONFIG_VERY_HIGH_FLAG; + else + config.flags |= CONFIG_HIGH_FLAG; + + break; + + case 'N': case 'n': + config.flags |= CONFIG_CALC_NOISE; + break; + + case 'A': case 'a': + config.flags |= CONFIG_ADOBE_MODE; + break; +#if defined (WIN32) + case 'E': case 'e': + config.flags |= CONFIG_CREATE_EXE; + break; + + case 'L': case 'l': + SetPriorityClass (GetCurrentProcess(), IDLE_PRIORITY_CLASS); + break; +#else + case 'O': case 'o': + output_spec = 1; + break; +#endif + case 'T': case 't': + config.flags |= CONFIG_COPY_TIME; + break; + + case 'P': case 'p': + config.flags |= CONFIG_SKIP_WVX; + break; + + case 'Q': case 'q': + config.flags |= CONFIG_QUIET_MODE; + break; + + case 'M': case 'm': + config.flags |= CONFIG_MD5_CHECKSUM; + break; + + case 'I': case 'i': + config.flags |= CONFIG_IGNORE_LENGTH; + break; + + case 'R': case 'r': + config.flags |= CONFIG_NEW_RIFF_HEADER; + break; + + case 'K': case 'k': + config.block_samples = strtol (++*argv, argv, 10); + --*argv; + break; + + case 'B': case 'b': + config.flags |= CONFIG_HYBRID_FLAG; + config.bitrate = strtod (++*argv, argv); + --*argv; + + if (config.bitrate < 2.0 || config.bitrate > 9600.0) { + error_line ("hybrid spec must be 2.0 to 9600!"); + ++error_count; + } + + if (config.bitrate >= 24.0) + config.flags |= CONFIG_BITRATE_KBPS; + + break; + + case 'J': case 'j': + switch (strtol (++*argv, argv, 10)) { + + case 0: + config.flags |= CONFIG_JOINT_OVERRIDE; + config.flags &= ~CONFIG_JOINT_STEREO; + break; + + case 1: + config.flags |= (CONFIG_JOINT_OVERRIDE | CONFIG_JOINT_STEREO); + break; + + default: + error_line ("-j0 or -j1 only!"); + ++error_count; + } + + --*argv; + break; + + case 'S': case 's': + config.shaping_weight = strtod (++*argv, argv); + + if (!config.shaping_weight) { + config.flags |= CONFIG_SHAPE_OVERRIDE; + config.flags &= ~CONFIG_HYBRID_SHAPE; + } + else if (config.shaping_weight >= -1.0 && config.shaping_weight <= 1.0) + config.flags |= (CONFIG_HYBRID_SHAPE | CONFIG_SHAPE_OVERRIDE); + else { + error_line ("-s-1.00 to -s1.00 only!"); + ++error_count; + } + + --*argv; + break; + + case 'W': case 'w': + tag_next_arg = 1; + break; + + default: + error_line ("illegal option: %c !", **argv); + ++error_count; + } + else if (tag_next_arg) { + tag_next_arg = 0; + config.tag_strings = realloc (config.tag_strings, ++config.num_tag_strings * sizeof (*config.tag_strings)); + config.tag_strings [config.num_tag_strings - 1] = *argv; + } +#if defined (WIN32) + else if (!num_files) { + matches = realloc (matches, (num_files + 1) * sizeof (*matches)); + matches [num_files] = malloc (strlen (*argv) + 10); + strcpy (matches [num_files], *argv); + + if (*(matches [num_files]) != '-' && *(matches [num_files]) != '@' && + !filespec_ext (matches [num_files])) + strcat (matches [num_files], ".wav"); + + num_files++; + } + else if (!outfilename) { + outfilename = malloc (strlen (*argv) + PATH_MAX); + strcpy (outfilename, *argv); + } + else if (!out2filename) { + out2filename = malloc (strlen (*argv) + PATH_MAX); + strcpy (out2filename, *argv); + } + else { + error_line ("extra unknown argument: %s !", *argv); + ++error_count; + } +#else + else if (output_spec) { + outfilename = malloc (strlen (*argv) + PATH_MAX); + strcpy (outfilename, *argv); + output_spec = 0; + } + else { + matches = realloc (matches, (num_files + 1) * sizeof (*matches)); + matches [num_files] = malloc (strlen (*argv) + 10); + strcpy (matches [num_files], *argv); + + if (*(matches [num_files]) != '-' && *(matches [num_files]) != '@' && + !filespec_ext (matches [num_files])) + strcat (matches [num_files], ".wav"); + + num_files++; + } +#endif + + setup_break (); // set up console and detect ^C and ^Break + + // check for various command-line argument problems + + if (!(~config.flags & (CONFIG_HIGH_FLAG | CONFIG_FAST_FLAG))) { + error_line ("high and fast modes are mutually exclusive!"); + ++error_count; + } + + if ((config.flags & CONFIG_IGNORE_LENGTH) && outfilename && *outfilename == '-') { + error_line ("can't ignore length in header when using stdout!"); + ++error_count; + } + + if (config.flags & CONFIG_HYBRID_FLAG) { + if ((config.flags & CONFIG_CREATE_WVC) && outfilename && *outfilename == '-') { + error_line ("can't create correction file when using stdout!"); + ++error_count; + } + } + else { + if (config.flags & (CONFIG_CALC_NOISE | CONFIG_SHAPE_OVERRIDE | CONFIG_CREATE_WVC)) { + error_line ("-s, -n and -c options are for hybrid mode (-b) only!"); + ++error_count; + } + } + + if (!(config.flags & CONFIG_QUIET_MODE) && !error_count) + fprintf (stderr, sign_on, VERSION_OS, VERSION_STR, DATE_STR); + + if (!num_files) { + printf ("%s", usage); + return 1; + } + + // loop through any tag specification strings and check for file access + + for (i = 0; i < config.num_tag_strings; ++i) { + char *cp = strchr (config.tag_strings [i], '='), *string = NULL; + + if (cp && cp > config.tag_strings [i]) { + int item_len = cp - config.tag_strings [i]; + + if (cp [1] == '@') { + FILE *file = wild_fopen (cp+2, "rb"); + + if (!file && filespec_name (matches [0]) && *matches [0] != '-') { + char *temp = malloc (strlen (matches [0]) + PATH_MAX); + + strcpy (temp, matches [0]); + strcpy (filespec_name (temp), cp+2); + file = wild_fopen (temp, "rb"); + free (temp); + } + + if (!file && filespec_name (outfilename) && *outfilename != '-') { + char *temp = malloc (strlen (outfilename) + PATH_MAX); + + strcpy (temp, outfilename); + strcpy (filespec_name (temp), cp+2); + file = wild_fopen (temp, "rb"); + free (temp); + } + + if (file) { + uint32_t bcount, file_len; + + file_len = DoGetFileSize (file); + if (file_len < 1048576 && (string = malloc (item_len + file_len + 2)) != NULL) { + memcpy (string, config.tag_strings [i], item_len + 1); + + if (!DoReadFile (file, string + item_len + 1, file_len, &bcount) || bcount != file_len) { + free (string); + string = NULL; + } + else + string [item_len + file_len + 1] = 0; + } + + DoCloseHandle (file); + } + } + else + string = config.tag_strings [i]; + } + + if (!string) { + error_line ("error in tag spec: %s !", config.tag_strings [i]); + ++error_count; + } + else { + config.tag_strings [i] = string; +// error_line ("final tag data: %s", string); + } + } + + if (error_count) + return 1; + + // If we are trying to create self-extracting .exe files, this is where + // we read the wvselfx.exe file into memory in preparation for pre-pending + // it to the WavPack files. + +#if defined (WIN32) + if (config.flags & CONFIG_CREATE_EXE) { + FILE *wvselfx_file; + uint32_t bcount; + + strcpy (filespec_name (selfname), "wvselfx.exe"); + + wvselfx_file = fopen (selfname, "rb"); + + if (!wvselfx_file) { + _searchenv ("wvselfx.exe", "PATH", selfname); + wvselfx_file = fopen (selfname, "rb"); + } + + if (wvselfx_file) { + wvselfx_size = DoGetFileSize (wvselfx_file); + + if (wvselfx_size && wvselfx_size != 26624 && wvselfx_size < 49152) { + wvselfx_image = malloc (wvselfx_size); + + if (!DoReadFile (wvselfx_file, wvselfx_image, wvselfx_size, &bcount) || bcount != wvselfx_size) { + free (wvselfx_image); + wvselfx_image = NULL; + } + } + + DoCloseHandle (wvselfx_file); + } + + if (!wvselfx_image) { + error_line ("wvselfx.exe file is not readable or is outdated!"); + free (wvselfx_image); + exit (1); + } + } +#endif + + for (file_index = 0; file_index < num_files; ++file_index) { + char *infilename = matches [file_index]; + + // If the single infile specification begins with a '@', then it + // actually points to a file that contains the names of the files + // to be converted. This was included for use by Wim Speekenbrink's + // frontends, but could be used for other purposes. + + if (*infilename == '@') { + FILE *list = fopen (infilename+1, "rt"); + int di, c; + + for (di = file_index; di < num_files - 1; di++) + matches [di] = matches [di + 1]; + + file_index--; + num_files--; + + if (list == NULL) { + error_line ("file %s not found!", infilename+1); + free (infilename); + return 1; + } + + while ((c = getc (list)) != EOF) { + + while (c == '\n') + c = getc (list); + + if (c != EOF) { + char *fname = malloc (PATH_MAX); + int ci = 0; + + do + fname [ci++] = c; + while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); + + fname [ci++] = '\0'; + fname = realloc (fname, ci); + matches = realloc (matches, ++num_files * sizeof (*matches)); + + for (di = num_files - 1; di > file_index + 1; di--) + matches [di] = matches [di - 1]; + + matches [++file_index] = fname; + } + } + + fclose (list); + free (infilename); + } +#if defined (WIN32) + else if (filespec_wild (infilename)) { + FILE *list = fopen (infilename+1, "rt"); + int di; + + for (di = file_index; di < num_files - 1; di++) + matches [di] = matches [di + 1]; + + file_index--; + num_files--; + + if ((i = _findfirst (infilename, &_finddata_t)) != -1L) { + do { + if (!(_finddata_t.attrib & _A_SUBDIR)) { + matches = realloc (matches, ++num_files * sizeof (*matches)); + + for (di = num_files - 1; di > file_index + 1; di--) + matches [di] = matches [di - 1]; + + matches [++file_index] = malloc (strlen (infilename) + strlen (_finddata_t.name) + 10); + strcpy (matches [file_index], infilename); + *filespec_name (matches [file_index]) = '\0'; + strcat (matches [file_index], _finddata_t.name); + } + } while (_findnext (i, &_finddata_t) == 0); + + _findclose (i); + } + + free (infilename); + } +#endif + } + + // If the outfile specification begins with a '@', then it actually points + // to a file that contains the output specification. This was included for + // use by Wim Speekenbrink's frontends because certain filenames could not + // be passed on the command-line, but could be used for other purposes. + + if (outfilename && outfilename [0] == '@') { + FILE *list = fopen (outfilename+1, "rt"); + int c; + + if (list == NULL) { + error_line ("file %s not found!", outfilename+1); + free(outfilename); + return 1; + } + + while ((c = getc (list)) == '\n'); + + if (c != EOF) { + int ci = 0; + + do + outfilename [ci++] = c; + while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); + + outfilename [ci] = '\0'; + } + else { + error_line ("output spec file is empty!"); + free(outfilename); + fclose (list); + return 1; + } + + fclose (list); + } + + if (out2filename && (num_files > 1 || !(config.flags & CONFIG_CREATE_WVC))) { + error_line ("extra unknown argument: %s !", out2filename); + return 1; + } + + // if we found any files to process, this is where we start + + if (num_files) { + char outpath, addext; + + if (outfilename && *outfilename != '-') { + outpath = (filespec_path (outfilename) != NULL); + + if (num_files > 1 && !outpath) { + error_line ("%s is not a valid output path", outfilename); + free(outfilename); + return 1; + } + } + else + outpath = 0; + + addext = !outfilename || outpath || !filespec_ext (outfilename); + + // loop through and process files in list + + for (file_index = 0; file_index < num_files; ++file_index) { + if (check_break ()) + break; + + // generate output filename + + if (outpath) { + strcat (outfilename, filespec_name (matches [file_index])); + + if (filespec_ext (outfilename)) + *filespec_ext (outfilename) = '\0'; + } + else if (!outfilename) { + outfilename = malloc (strlen (matches [file_index]) + 10); + strcpy (outfilename, matches [file_index]); + + if (filespec_ext (outfilename)) + *filespec_ext (outfilename) = '\0'; + } + + if (addext && *outfilename != '-') + strcat (outfilename, (config.flags & CONFIG_CREATE_EXE) ? ".exe" : ".wv"); + + // if "correction" file is desired, generate name for that + + if (config.flags & CONFIG_CREATE_WVC) { + if (!out2filename) { + out2filename = malloc (strlen (outfilename) + 10); + strcpy (out2filename, outfilename); + } + else { + char *temp = malloc (strlen (outfilename) + PATH_MAX); + + strcpy (temp, outfilename); + strcpy (filespec_name (temp), filespec_name (out2filename)); + strcpy (out2filename, temp); + free (temp); + } + + if (filespec_ext (out2filename)) + *filespec_ext (out2filename) = '\0'; + + strcat (out2filename, ".wvc"); + } + else + out2filename = NULL; + + if (num_files > 1) + fprintf (stderr, "\n%s:\n", matches [file_index]); + + result = pack_file (matches [file_index], outfilename, out2filename, &config); + + if (result != NO_ERROR) + ++error_count; + + if (result == HARD_ERROR) + break; + + // delete source file if that option is enabled + + if (result == NO_ERROR && delete_source) + error_line ("%s source file %s", DoDeleteFile (matches [file_index]) ? + "deleted" : "can't delete", matches [file_index]); + + // clean up in preparation for potentially another file + + if (outpath) + *filespec_name (outfilename) = '\0'; + else if (*outfilename != '-') { + free (outfilename); + outfilename = NULL; + } + + if (out2filename) { + free (out2filename); + out2filename = NULL; + } + + free (matches [file_index]); + } + + if (num_files > 1) { + if (error_count) + fprintf (stderr, "\n **** warning: errors occurred in %d of %d files! ****\n", error_count, num_files); + else if (!(config.flags & CONFIG_QUIET_MODE)) + fprintf (stderr, "\n **** %d files successfully processed ****\n", num_files); + } + + free (matches); + } + else { + error_line ("nothing to do!"); + ++error_count; + } + + if (outfilename) + free (outfilename); + +#ifdef DEBUG_ALLOC + error_line ("malloc_count = %d", dump_alloc ()); +#endif + + return error_count ? 1 : 0; +} + +// This structure and function are used to write completed WavPack blocks in +// a device independent way. + +typedef struct { + uint32_t bytes_written, first_block_size; + FILE *file; + int error; +} write_id; + +static int write_block (void *id, void *data, int32_t length) +{ + write_id *wid = (write_id *) id; + uint32_t bcount; + + if (wid->error) + return FALSE; + + if (wid && wid->file && data && length) { + if (!DoWriteFile (wid->file, data, length, &bcount) || bcount != length) { + DoTruncateFile (wid->file); + DoCloseHandle (wid->file); + wid->file = NULL; + wid->error = 1; + return FALSE; + } + else { + wid->bytes_written += length; + + if (!wid->first_block_size) + wid->first_block_size = bcount; + } + } + + return TRUE; +} + +// Special version of fopen() that allows a wildcard specification for the +// filename. If a wildcard is specified, then it must match 1 and only 1 +// file to be acceptable (i.e. it won't match just the "first" file). + +#if defined (WIN32) + +static FILE *wild_fopen (char *filename, const char *mode) +{ + struct _finddata_t _finddata_t; + char *matchname = NULL; + FILE *res = NULL; + int i; + + if (!filespec_wild (filename) || !filespec_name (filename)) + return fopen (filename, mode); + + if ((i = _findfirst (filename, &_finddata_t)) != -1L) { + do { + if (!(_finddata_t.attrib & _A_SUBDIR)) { + if (matchname) { + free (matchname); + matchname = NULL; + break; + } + else { + matchname = malloc (strlen (filename) + strlen (_finddata_t.name)); + strcpy (matchname, filename); + strcpy (filespec_name (matchname), _finddata_t.name); + } + } + } while (_findnext (i, &_finddata_t) == 0); + + _findclose (i); + } + + if (matchname) { + res = fopen (matchname, mode); + free (matchname); + } + + return res; +} + +#else + +static FILE *wild_fopen (char *filename, const char *mode) +{ + return fopen (filename, mode); +} + +#endif + + +// This function packs a single file "infilename" and stores the result at +// "outfilename". If "out2filename" is specified, then the "correction" +// file would go there. The files are opened and closed in this function +// and the "config" structure specifies the mode of compression. + +static void AnsiToUTF8 (char *string, int len); + +static int pack_file (char *infilename, char *outfilename, char *out2filename, const WavpackConfig *config) +{ + uint32_t total_samples = 0, bcount; + WavpackConfig loc_config = *config; + RiffChunkHeader riff_chunk_header; + write_id wv_file, wvc_file; + ChunkHeader chunk_header; + WaveHeader WaveHeader; + WavpackContext *wpc; + double dtime; + FILE *infile; + int result; + +#if defined(WIN32) + struct _timeb time1, time2; +#else + struct timeval time1, time2; + struct timezone timez; +#endif + + CLEAR (wv_file); + CLEAR (wvc_file); + wpc = WavpackOpenFileOutput (write_block, &wv_file, out2filename ? &wvc_file : NULL); + + // open the source file for reading + + if (*infilename == '-') { + infile = stdin; +#if defined(WIN32) + setmode (fileno (stdin), O_BINARY); +#endif + } + else if ((infile = fopen (infilename, "rb")) == NULL) { + error_line ("can't open file %s!", infilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + // check both output files for overwrite warning required + + if (*outfilename != '-' && !overwrite_all && (wv_file.file = fopen (outfilename, "rb")) != NULL) { + DoCloseHandle (wv_file.file); + fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (outfilename)); + SetConsoleTitle ("overwrite?"); + + switch (yna ()) { + case 'n': + DoCloseHandle (infile); + WavpackCloseFile (wpc); + return SOFT_ERROR; + + case 'a': + overwrite_all = 1; + } + } + + if (out2filename && !overwrite_all && (wvc_file.file = fopen (out2filename, "rb")) != NULL) { + DoCloseHandle (wvc_file.file); + fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (out2filename)); + SetConsoleTitle ("overwrite?"); + + switch (yna ()) { + + case 'n': + DoCloseHandle (infile); + WavpackCloseFile (wpc); + return SOFT_ERROR; + + case 'a': + overwrite_all = 1; + } + } + +#if defined(WIN32) + _ftime (&time1); +#else + gettimeofday(&time1,&timez); +#endif + + // open output file for writing + + if (*outfilename == '-') { + wv_file.file = stdout; +#if defined(WIN32) + setmode (fileno (stdout), O_BINARY); +#endif + } + else if ((wv_file.file = fopen (outfilename, "w+b")) == NULL) { + error_line ("can't create file %s!", outfilename); + DoCloseHandle (infile); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + if (!(loc_config.flags & CONFIG_QUIET_MODE)) { + if (*outfilename == '-') + fprintf (stderr, "packing %s to stdout,", *infilename == '-' ? "stdin" : FN_FIT (infilename)); + else if (out2filename) + fprintf (stderr, "creating %s (+%s),", FN_FIT (outfilename), filespec_ext (out2filename)); + else + fprintf (stderr, "creating %s,", FN_FIT (outfilename)); + } + +#if defined (WIN32) + if (loc_config.flags & CONFIG_CREATE_EXE) + if (!DoWriteFile (wv_file.file, wvselfx_image, wvselfx_size, &bcount) || bcount != wvselfx_size) { + error_line ("can't write WavPack data, disk probably full!"); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } +#endif + + // if not in "raw" mode, read (and copy to output) initial RIFF form header + + if (!(loc_config.flags & CONFIG_RAW_FLAG)) { + if ((!DoReadFile (infile, &riff_chunk_header, sizeof (RiffChunkHeader), &bcount) || + bcount != sizeof (RiffChunkHeader) || strncmp (riff_chunk_header.ckID, "RIFF", 4) || + strncmp (riff_chunk_header.formType, "WAVE", 4))) { + error_line ("%s is not a valid .WAV file!", infilename); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + else if (!(loc_config.flags & CONFIG_NEW_RIFF_HEADER) && + !WavpackAddWrapper (wpc, &riff_chunk_header, sizeof (RiffChunkHeader))) { + error_line ("%s", wpc->error_message); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + } + + // if not in "raw" mode, loop through all elements of the RIFF wav header + // (until the data chuck) and copy them to the output file + + while (!(loc_config.flags & CONFIG_RAW_FLAG)) { + + if (!DoReadFile (infile, &chunk_header, sizeof (ChunkHeader), &bcount) || + bcount != sizeof (ChunkHeader)) { + error_line ("%s is not a valid .WAV file!", infilename); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + else if (!(loc_config.flags & CONFIG_NEW_RIFF_HEADER) && + !WavpackAddWrapper (wpc, &chunk_header, sizeof (ChunkHeader))) { + error_line ("%s", wpc->error_message); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + little_endian_to_native (&chunk_header, ChunkHeaderFormat); + + // if it's the format chunk, we want to get some info out of there and + // make sure it's a .wav file we can handle + + if (!strncmp (chunk_header.ckID, "fmt ", 4)) { + int supported = TRUE, format; + + if (chunk_header.ckSize < 16 || chunk_header.ckSize > sizeof (WaveHeader) || + !DoReadFile (infile, &WaveHeader, chunk_header.ckSize, &bcount) || + bcount != chunk_header.ckSize) { + error_line ("%s is not a valid .WAV file!", infilename); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + else if (!(loc_config.flags & CONFIG_NEW_RIFF_HEADER) && + !WavpackAddWrapper (wpc, &WaveHeader, chunk_header.ckSize)) { + error_line ("%s", wpc->error_message); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + little_endian_to_native (&WaveHeader, WaveHeaderFormat); + + if (debug_logging_mode) { + error_line ("format tag size = %d", chunk_header.ckSize); + error_line ("FormatTag = %x, NumChannels = %d, BitsPerSample = %d", + WaveHeader.FormatTag, WaveHeader.NumChannels, WaveHeader.BitsPerSample); + error_line ("BlockAlign = %d, SampleRate = %d, BytesPerSecond = %d", + WaveHeader.BlockAlign, WaveHeader.SampleRate, WaveHeader.BytesPerSecond); + + if (chunk_header.ckSize > 16) + error_line ("cbSize = %d, ValidBitsPerSample = %d", WaveHeader.cbSize, + WaveHeader.ValidBitsPerSample); + + if (chunk_header.ckSize > 20) + error_line ("ChannelMask = %x, SubFormat = %d", + WaveHeader.ChannelMask, WaveHeader.SubFormat); + } + + if (chunk_header.ckSize > 16 && WaveHeader.cbSize == 2) + loc_config.flags |= CONFIG_ADOBE_MODE; + + format = (WaveHeader.FormatTag == 0xfffe && chunk_header.ckSize == 40) ? + WaveHeader.SubFormat : WaveHeader.FormatTag; + + loc_config.bits_per_sample = chunk_header.ckSize == 40 ? + WaveHeader.ValidBitsPerSample : WaveHeader.BitsPerSample; + + if (format != 1 && format != 3) + supported = FALSE; + + if (!WaveHeader.NumChannels || + WaveHeader.BlockAlign / WaveHeader.NumChannels > 4) + supported = FALSE; + + if (loc_config.bits_per_sample < 1 || loc_config.bits_per_sample > 32) + supported = FALSE; + + if (!supported) { + error_line ("%s is an unsupported .WAV format!", infilename); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + if (chunk_header.ckSize < 40) { + if (WaveHeader.NumChannels <= 2) + loc_config.channel_mask = 0x5 - WaveHeader.NumChannels; + else + loc_config.channel_mask = (1 << WaveHeader.NumChannels) - 1; + } + else + loc_config.channel_mask = WaveHeader.ChannelMask; + + if (format == 3) + loc_config.float_norm_exp = 127; + else if ((loc_config.flags & CONFIG_ADOBE_MODE) && + WaveHeader.BlockAlign / WaveHeader.NumChannels == 4) { + if (WaveHeader.BitsPerSample == 24) + loc_config.float_norm_exp = 127 + 23; + else if (WaveHeader.BitsPerSample == 32) + loc_config.float_norm_exp = 127 + 15; + } + + if (debug_logging_mode) { + if (loc_config.float_norm_exp == 127) + error_line ("data format: normalized 32-bit floating point"); + else if (loc_config.float_norm_exp) + error_line ("data format: 32-bit floating point (Audition %d:%d float type 1)", + loc_config.float_norm_exp - 126, 150 - loc_config.float_norm_exp); + else + error_line ("data format: %d-bit integers stored in %d byte(s)", + loc_config.bits_per_sample, WaveHeader.BlockAlign / WaveHeader.NumChannels); + } + } + else if (!strncmp (chunk_header.ckID, "data", 4)) { + + // on the data chunk, get size and exit loop + + total_samples = chunk_header.ckSize / WaveHeader.BlockAlign; + break; + } + else { // just copy unknown chunks to output file + + int bytes_to_copy = (chunk_header.ckSize + 1) & ~1L; + char *buff = malloc (bytes_to_copy); + + if (debug_logging_mode) + error_line ("extra unknown chunk \"%c%c%c%c\" of %d bytes", + chunk_header.ckID [0], chunk_header.ckID [1], chunk_header.ckID [2], + chunk_header.ckID [3], chunk_header.ckSize); + + if (!DoReadFile (infile, buff, bytes_to_copy, &bcount) || + bcount != bytes_to_copy || + (!(loc_config.flags & CONFIG_NEW_RIFF_HEADER) && + !WavpackAddWrapper (wpc, buff, bytes_to_copy))) { + error_line ("%s", wpc->error_message); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + free (buff); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + free (buff); + } + } + + loc_config.bytes_per_sample = WaveHeader.BlockAlign / WaveHeader.NumChannels; + loc_config.num_channels = WaveHeader.NumChannels; + loc_config.sample_rate = WaveHeader.SampleRate; + + WavpackSetConfiguration (wpc, &loc_config, total_samples); + + // if we are creating a "correction" file, open it now for writing + + if (out2filename) { + if ((wvc_file.file = fopen (out2filename, "w+b")) == NULL) { + error_line ("can't create correction file!"); + DoCloseHandle (infile); + DoCloseHandle (wv_file.file); + DoDeleteFile (outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + } + + // pack the audio portion of the file now + + result = pack_audio (wpc, infile); + + // if everything went well (and we're not ignoring length) try to read + // anything else that might be appended to the audio data and write that + // to the WavPack metadata as "wrapper" + + if (result == NO_ERROR && !(loc_config.flags & CONFIG_IGNORE_LENGTH)) { + uchar buff [16]; + + while (DoReadFile (infile, buff, sizeof (buff), &bcount) && bcount) + if (!(loc_config.flags & CONFIG_NEW_RIFF_HEADER) && + !WavpackAddWrapper (wpc, buff, bcount)) { + error_line ("%s", wpc->error_message); + result = HARD_ERROR; + break; + } + } + + DoCloseHandle (infile); // we're now done with input file, so close + + // we're now done with any WavPack blocks, so flush any remaining data + + if (result == NO_ERROR && !WavpackFlushSamples (wpc)) { + error_line ("%s", wpc->error_message); + result = HARD_ERROR; + } + + // if still no errors, check to see if we need to create & write a tag + // (which is NOT stored in regular WavPack blocks) + + if (result == NO_ERROR && config->num_tag_strings) { + int i; + + for (i = 0; i < config->num_tag_strings; ++i) { + int item_len = strchr (config->tag_strings [i], '=') - config->tag_strings [i]; + int value_len = strlen (config->tag_strings [i]) - item_len - 1; + + if (value_len) { + char *item = malloc (item_len + 1); + char *value = malloc (value_len * 2 + 1); + + strncpy (item, config->tag_strings [i], item_len); + item [item_len] = 0; + strcpy (value, config->tag_strings [i] + item_len + 1); + AnsiToUTF8 (value, value_len * 2 + 1); + WavpackAppendTagItem (wpc, item, value, strlen (value)); + free (value); + free (item); + } + } + + if (!WavpackWriteTag (wpc)) { + error_line ("%s", wpc->error_message); + result = HARD_ERROR; + } + } + + // At this point we're done writing to the output files. However, in some + // situations we might have to back up and re-write the initial blocks. + // Currently the only case is if we're ignoring length. + + if (result == NO_ERROR && WavpackGetNumSamples (wpc) != WavpackGetSampleIndex (wpc)) { + if (loc_config.flags & CONFIG_IGNORE_LENGTH) { + char *block_buff = malloc (wv_file.first_block_size); + uint32_t wrapper_size; + + if (block_buff && !DoSetFilePositionAbsolute (wv_file.file, 0) && + DoReadFile (wv_file.file, block_buff, wv_file.first_block_size, &bcount) && + bcount == wv_file.first_block_size && !strncmp (block_buff, "wvpk", 4)) { + + WavpackUpdateNumSamples (wpc, block_buff); + + if (WavpackGetWrapperLocation (block_buff, &wrapper_size)) { + RiffChunkHeader *riffhdr = WavpackGetWrapperLocation (block_buff, NULL); + ChunkHeader *datahdr = (ChunkHeader *)((char *) riffhdr + wrapper_size - sizeof (ChunkHeader)); + uint32_t data_size = WavpackGetSampleIndex (wpc) * WavpackGetNumChannels (wpc) * WavpackGetBytesPerSample (wpc); + + if (!strncmp (riffhdr->ckID, "RIFF", 4)) { + little_endian_to_native (riffhdr, ChunkHeaderFormat); + riffhdr->ckSize = wrapper_size + data_size - 8; + native_to_little_endian (riffhdr, ChunkHeaderFormat); + } + + if (!strncmp (datahdr->ckID, "data", 4)) { + little_endian_to_native (datahdr, ChunkHeaderFormat); + datahdr->ckSize = data_size; + native_to_little_endian (datahdr, ChunkHeaderFormat); + } + } + + if (DoSetFilePositionAbsolute (wv_file.file, 0) || + !DoWriteFile (wv_file.file, block_buff, wv_file.first_block_size, &bcount) || + bcount != wv_file.first_block_size) { + error_line ("couldn't update WavPack header with actual length!!"); + result = SOFT_ERROR; + } + + free (block_buff); + } + else { + error_line ("couldn't update WavPack header with actual length!!"); + result = SOFT_ERROR; + } + + if (result == NO_ERROR && wvc_file.file) { + block_buff = malloc (wvc_file.first_block_size); + + if (block_buff && !DoSetFilePositionAbsolute (wvc_file.file, 0) && + DoReadFile (wvc_file.file, block_buff, wvc_file.first_block_size, &bcount) && + bcount == wvc_file.first_block_size && !strncmp (block_buff, "wvpk", 4)) { + + WavpackUpdateNumSamples (wpc, block_buff); + + if (DoSetFilePositionAbsolute (wvc_file.file, 0) || + !DoWriteFile (wvc_file.file, block_buff, wvc_file.first_block_size, &bcount) || + bcount != wvc_file.first_block_size) { + error_line ("couldn't update WavPack header with actual length!!"); + result = SOFT_ERROR; + } + } + else { + error_line ("couldn't update WavPack header with actual length!!"); + result = SOFT_ERROR; + } + + free (block_buff); + } + + if (result == NO_ERROR) + error_line ("warning: length was %s by %d samples, corrected", + WavpackGetSampleIndex (wpc) < total_samples ? "short" : "long", + abs (total_samples - WavpackGetSampleIndex (wpc))); + } + else { + error_line ("couldn't read all samples, file may be corrupt!!"); + result = SOFT_ERROR; + } + } + + // at this point we're done with the files, so close 'em whether there + // were any other errors or not + + if (!DoCloseHandle (wv_file.file)) { + error_line ("can't close WavPack file!"); + + if (result == NO_ERROR) + result = SOFT_ERROR; + } + + if (out2filename && !DoCloseHandle (wvc_file.file)) { + error_line ("can't close correction file!"); + + if (result == NO_ERROR) + result = SOFT_ERROR; + } + + // if there were any errors, delete the output files, close the context, + // and return the error + + if (result != NO_ERROR) { + DoDeleteFile (outfilename); + + if (out2filename) + DoDeleteFile (out2filename); + + WavpackCloseFile (wpc); + return result; + } + + if (result == NO_ERROR && (loc_config.flags & CONFIG_COPY_TIME)) + if (!copy_timestamp (infilename, outfilename) || + (out2filename && !copy_timestamp (infilename, out2filename))) + error_line ("failure copying time stamp!"); + + // compute and display the time consumed along with some other details of + // the packing operation, and then return NO_ERROR + +#if defined(WIN32) + _ftime (&time2); + dtime = time2.time + time2.millitm / 1000.0; + dtime -= time1.time + time1.millitm / 1000.0; +#else + gettimeofday(&time2,&timez); + dtime = time2.tv_sec + time2.tv_usec / 1000000.0; + dtime -= time1.tv_sec + time1.tv_usec / 1000000.0; +#endif + + if ((loc_config.flags & CONFIG_CALC_NOISE) && pack_noise (wpc, NULL) > 0.0) { + int full_scale_bits = WavpackGetBitsPerSample (wpc); + double full_scale_rms = 0.5, sum, peak; + + while (full_scale_bits--) + full_scale_rms *= 2.0; + + full_scale_rms = full_scale_rms * (full_scale_rms - 1.0) * 0.5; + sum = pack_noise (wpc, &peak); + + error_line ("ave noise = %.2f dB, peak noise = %.2f dB", + log10 (sum / WavpackGetNumSamples (wpc) / full_scale_rms) * 10, + log10 (peak / full_scale_rms) * 10); + } + + if (!(loc_config.flags & CONFIG_QUIET_MODE)) { + char *file, *fext, *oper, *cmode, cratio [16] = ""; + + if (outfilename && *outfilename != '-') { + file = FN_FIT (outfilename); + fext = wvc_file.bytes_written ? " (+.wvc)" : ""; + oper = "created"; + } + else { + file = (*infilename == '-') ? "stdin" : FN_FIT (infilename); + fext = ""; + oper = "packed"; + } + + if (WavpackLossyBlocks (wpc)) { + cmode = "lossy"; + + if (WavpackGetAverageBitrate (wpc, TRUE) != 0.0) + sprintf (cratio, ", %d kbps", (int) (WavpackGetAverageBitrate (wpc, TRUE) / 1000.0)); + } + else { + cmode = "lossless"; + + if (WavpackGetRatio (wpc) != 0.0) + sprintf (cratio, ", %.2f%%", 100.0 - WavpackGetRatio (wpc) * 100.0); + } + + error_line ("%s %s%s in %.2f secs (%s%s)", oper, file, fext, dtime, cmode, cratio); + } + + WavpackCloseFile (wpc); + return NO_ERROR; +} + +// This function handles the actual audio data compression. It assumes that the +// input file is positioned at the beginning of the audio data and that the +// WavPack configuration has been set. This is where the conversion from RIFF +// little-endian standard the executing processor's format is done and where +// (if selected) the MD5 sum is calculated and displayed. + +#define INPUT_SAMPLES 65536 + +static int pack_audio (WavpackContext *wpc, FILE *infile) +{ + uint32_t samples_remaining, samples_read = 0; + double progress = -1.0; + int bytes_per_sample; + int32_t *sample_buffer; + uchar *input_buffer; + MD5_CTX md5_context; + + if (wpc->config.flags & CONFIG_MD5_CHECKSUM) + MD5Init (&md5_context); + + WavpackPackInit (wpc); + bytes_per_sample = WavpackGetBytesPerSample (wpc) * WavpackGetNumChannels (wpc); + input_buffer = malloc (INPUT_SAMPLES * bytes_per_sample); + sample_buffer = malloc (INPUT_SAMPLES * sizeof (int32_t) * WavpackGetNumChannels (wpc)); + samples_remaining = WavpackGetNumSamples (wpc); + + while (1) { + uint32_t bytes_to_read, bytes_read = 0; + uint sample_count; + + if ((wpc->config.flags & CONFIG_IGNORE_LENGTH) || samples_remaining > INPUT_SAMPLES) + bytes_to_read = INPUT_SAMPLES * bytes_per_sample; + else + bytes_to_read = samples_remaining * bytes_per_sample; + + samples_remaining -= bytes_to_read / bytes_per_sample; + DoReadFile (infile, input_buffer, bytes_to_read, &bytes_read); + samples_read += sample_count = bytes_read / bytes_per_sample; + + if (wpc->config.flags & CONFIG_MD5_CHECKSUM) + MD5Update (&md5_context, input_buffer, bytes_read); + + if (!sample_count) + break; + + if (sample_count) { + uint cnt = sample_count * WavpackGetNumChannels (wpc); + uchar *sptr = input_buffer; + int32_t *dptr = sample_buffer; + + switch (WavpackGetBytesPerSample (wpc)) { + + case 1: + while (cnt--) + *dptr++ = *sptr++ - 128; + + break; + + case 2: + while (cnt--) { + *dptr++ = sptr [0] | ((int32_t)(signed char) sptr [1] << 8); + sptr += 2; + } + + break; + + case 3: + while (cnt--) { + *dptr++ = sptr [0] | ((int32_t) sptr [1] << 8) | ((int32_t)(signed char) sptr [2] << 16); + sptr += 3; + } + + break; + + case 4: + while (cnt--) { + *dptr++ = sptr [0] | ((int32_t) sptr [1] << 8) | ((int32_t) sptr [2] << 16) | ((int32_t)(signed char) sptr [3] << 24); + sptr += 4; + } + + break; + } + } + + if (!WavpackPackSamples (wpc, sample_buffer, sample_count)) { + error_line ("%s", wpc->error_message); + free (sample_buffer); + free (input_buffer); + return HARD_ERROR; + } + + if (check_break ()) { + fprintf (stderr, "^C\n"); + free (sample_buffer); + free (input_buffer); + return SOFT_ERROR; + } + + if (WavpackGetProgress (wpc) != -1.0 && + progress != floor (WavpackGetProgress (wpc) * 100.0 + 0.5)) { + int nobs = progress == -1.0; + + progress = WavpackGetProgress (wpc); + display_progress (progress); + progress = floor (progress * 100.0 + 0.5); + + if (!(wpc->config.flags & CONFIG_QUIET_MODE)) + fprintf (stderr, "%s%3d%% done...", + nobs ? " " : "\b\b\b\b\b\b\b\b\b\b\b\b", (int) progress); + } + } + + free (sample_buffer); + free (input_buffer); + + if (!WavpackFlushSamples (wpc)) { + error_line ("%s", wpc->error_message); + return HARD_ERROR; + } + + if (wpc->config.flags & CONFIG_MD5_CHECKSUM) { + char md5_string [] = "original md5 signature: 00000000000000000000000000000000"; + uchar md5_digest [16]; + int i; + + MD5Final (md5_digest, &md5_context); + + for (i = 0; i < 16; ++i) + sprintf (md5_string + 24 + (i * 2), "%02x", md5_digest [i]); + + if (!(wpc->config.flags & CONFIG_QUIET_MODE)) + error_line (md5_string); + + WavpackStoreMD5Sum (wpc, md5_digest); + } + + return NO_ERROR; +} + +// Convert the Unicode wide-format string into a UTF-8 string using no more +// than the specified buffer length. The wide-format string must be NULL +// terminated and the resulting string will be NULL terminated. The actual +// number of characters converted (not counting terminator) is returned, which +// may be less than the number of characters in the wide string if the buffer +// length is exceeded. + +static int WideCharToUTF8 (const ushort *Wide, uchar *pUTF8, int len) +{ + const ushort *pWide = Wide; + int outndx = 0; + + while (*pWide) { + if (*pWide < 0x80 && outndx + 1 < len) + pUTF8 [outndx++] = (uchar) *pWide++; + else if (*pWide < 0x800 && outndx + 2 < len) { + pUTF8 [outndx++] = (uchar) (0xc0 | ((*pWide >> 6) & 0x1f)); + pUTF8 [outndx++] = (uchar) (0x80 | (*pWide++ & 0x3f)); + } + else if (outndx + 3 < len) { + pUTF8 [outndx++] = (uchar) (0xe0 | ((*pWide >> 12) & 0xf)); + pUTF8 [outndx++] = (uchar) (0x80 | ((*pWide >> 6) & 0x3f)); + pUTF8 [outndx++] = (uchar) (0x80 | (*pWide++ & 0x3f)); + } + else + break; + } + + pUTF8 [outndx] = 0; + return pWide - Wide; +} + +// Convert a Ansi string into its Unicode UTF-8 format equivalent. The +// conversion is done in-place so the maximum length of the string buffer must +// be specified because the string may become longer or shorter. If the +// resulting string will not fit in the specified buffer size then it is +// truncated. + +static void AnsiToUTF8 (char *string, int len) +{ + int max_chars = strlen (string); +#if defined(WIN32) + ushort *temp = (ushort *) malloc ((max_chars + 1) * 2); + + MultiByteToWideChar (CP_ACP, 0, string, -1, temp, max_chars + 1); + WideCharToUTF8 (temp, (uchar *) string, len); +#else + char *temp = malloc (len); + char *outp = temp; + char *inp = string; + size_t insize = max_chars; + size_t outsize = len - 1; + int err = 0; + char *old_locale; + + memset(temp, 0, len); + old_locale = setlocale (LC_CTYPE, ""); + iconv_t converter = iconv_open ("UTF-8", ""); + err = iconv (converter, &inp, &insize, &outp, &outsize); + iconv_close (converter); + setlocale (LC_CTYPE, old_locale); + + if (err == -1) { + free(temp); + return; + } + + memmove (string, temp, len); +#endif + free (temp); +} + +////////////////////////////////////////////////////////////////////////////// +// This function displays the progress status on the title bar of the DOS // +// window that WavPack is running in. The "file_progress" argument is for // +// the current file only and ranges from 0 - 1; this function takes into // +// account the total number of files to generate a batch progress number. // +////////////////////////////////////////////////////////////////////////////// + +static void display_progress (double file_progress) +{ + char title [40]; + + file_progress = (file_index + file_progress) / num_files; + sprintf (title, "%d%% (WavPack)", (int) ((file_progress * 100.0) + 0.5)); + SetConsoleTitle (title); +} diff --git a/Libraries/WavPack/Files/wavpack.h b/Libraries/WavPack/Files/wavpack.h index e2c4274ac..3b9ddbc67 100644 --- a/Libraries/WavPack/Files/wavpack.h +++ b/Libraries/WavPack/Files/wavpack.h @@ -1,656 +1,680 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// wavpack.h - -#ifndef WAVPACK_H -#define WAVPACK_H - -#if defined(WIN32) -#define FASTCALL __fastcall -#else -#define FASTCALL -#define SetConsoleTitle(x) -#endif - -#include - -// This header file contains all the definitions required by WavPack. - -#if defined(_WIN32) && !defined(__MINGW32__) -#include -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; -typedef float float32_t; -#else -#include -#endif - -typedef unsigned char uchar; - -#if !defined(__GNUC__) || defined(WIN32) -typedef unsigned short ushort; -typedef unsigned int uint; -#endif - -#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 - -// This structure is used to access the individual fields of 32-bit ieee -// floating point numbers. This will not be compatible with compilers that -// allocate bit fields from the most significant bits, although I'm not sure -// how common that is. - -typedef struct { - unsigned mantissa : 23; - unsigned exponent : 8; - unsigned sign : 1; -} f32; - -#include - -#define FALSE 0 -#define TRUE 1 - -#if defined(WIN32) -#undef VERSION_OS -#define VERSION_OS "Win32" -#endif -#define VERSION_STR "4.2 " -#define DATE_STR "2005-04-02" - -// ID3v1 and APEv2 TAG formats (may occur at the end of WavPack files) - -typedef struct { - uchar tag_id [3], title [30], artist [30], album [30]; - uchar 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" - -typedef struct { - ID3_Tag id3_tag; - APE_Tag_Hdr ape_tag_hdr; - char *ape_tag_data; -} M_Tag; - -// RIFF / wav header formats (these occur at the beginning of both wav files -// and pre-4.0 WavPack files that are not in the "raw" mode) - -typedef struct { - char ckID [4]; - uint32_t ckSize; - char formType [4]; -} RiffChunkHeader; - -typedef struct { - char ckID [4]; - uint32_t ckSize; -} ChunkHeader; - -#define ChunkHeaderFormat "4L" - -typedef struct { - ushort FormatTag, NumChannels; - uint32_t SampleRate, BytesPerSecond; - ushort BlockAlign, BitsPerSample; - ushort cbSize, ValidBitsPerSample; - int32_t ChannelMask; - ushort SubFormat; - char GUID [14]; -} WaveHeader; - -#define WaveHeaderFormat "SSLLSSSSLS" - -////////////////////////////// WavPack Header ///////////////////////////////// - -// Note that this is the ONLY structure that is written to (or read from) -// WavPack 4.0 files, and is the preamble to every block in both the .wv -// and .wvc files. - -typedef struct { - char ckID [4]; - uint32_t ckSize; - short version; - uchar track_no, index_no; - uint32_t total_samples, block_index, block_samples, flags, crc; -} WavpackHeader; - -#define WavpackHeaderFormat "4LS2LLLLL" - -// or-values for "flags" - -#define BYTES_STORED 3 // 1-4 bytes/sample -#define MONO_FLAG 4 // not stereo -#define HYBRID_FLAG 8 // hybrid mode -#define JOINT_STEREO 0x10 // joint stereo -#define CROSS_DECORR 0x20 // no-delay cross decorrelation -#define HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) -#define FLOAT_DATA 0x80 // ieee 32-bit floating point data - -#define INT32_DATA 0x100 // special extended int handling -#define HYBRID_BITRATE 0x200 // bitrate noise (hybrid mode only) -#define HYBRID_BALANCE 0x400 // balance noise (hybrid stereo mode only) - -#define INITIAL_BLOCK 0x800 // initial block of multichannel segment -#define FINAL_BLOCK 0x1000 // final block of multichannel segment - -#define SHIFT_LSB 13 -#define SHIFT_MASK (0x1fL << SHIFT_LSB) - -#define MAG_LSB 18 -#define MAG_MASK (0x1fL << MAG_LSB) - -#define SRATE_LSB 23 -#define SRATE_MASK (0xfL << SRATE_LSB) - -#define IGNORED_FLAGS 0x18000000 // reserved, but ignore if encountered -#define NEW_SHAPING 0x20000000 // use IIR filter for negative shaping -#define UNKNOWN_FLAGS 0xC0000000 // also reserved, but refuse decode if - // encountered - -//////////////////////////// WavPack Metadata ///////////////////////////////// - -// This is an internal representation of metadata. - -typedef struct { - int32_t byte_length; - void *data; - uchar id; -} WavpackMetadata; - -#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_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1) -#define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2) -#define ID_REPLAY_GAIN (ID_OPTIONAL_DATA | 0x3) -#define ID_CUESHEET (ID_OPTIONAL_DATA | 0x4) -#define ID_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0x5) -#define ID_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x6) - -///////////////////////// WavPack Configuration /////////////////////////////// - -// This internal structure is used during encode to provide configuration to -// the encoding engine and during decoding to provide fle information back to -// the higher level functions. Not all fields are used in both modes. - -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; - uchar md5_checksum [16], md5_read; - int num_tag_strings; - char **tag_strings; -} WavpackConfig; - -#define CONFIG_BYTES_STORED 3 // 1-4 bytes/sample -#define CONFIG_MONO_FLAG 4 // not stereo -#define CONFIG_HYBRID_FLAG 8 // hybrid mode -#define CONFIG_JOINT_STEREO 0x10 // joint stereo -#define CONFIG_CROSS_DECORR 0x20 // no-delay cross decorrelation -#define CONFIG_HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) -#define CONFIG_FLOAT_DATA 0x80 // ieee 32-bit floating point data - -#define CONFIG_ADOBE_MODE 0x100 // "adobe" mode for 32-bit floats -#define CONFIG_FAST_FLAG 0x200 // fast mode -#define CONFIG_VERY_FAST_FLAG 0x400 // double fast -#define CONFIG_HIGH_FLAG 0x800 // high quality mode -#define CONFIG_VERY_HIGH_FLAG 0x1000 // double high (not used yet) -#define CONFIG_BITRATE_KBPS 0x2000 // bitrate is kbps, not bits / sample -#define CONFIG_AUTO_SHAPING 0x4000 // automatic noise shaping -#define CONFIG_SHAPE_OVERRIDE 0x8000 // shaping mode specified -#define CONFIG_JOINT_OVERRIDE 0x10000 // joint-stereo mode specified -#define CONFIG_COPY_TIME 0x20000 // copy file-time from source -#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_QUALITY_MODE 0x200000 // psychoacoustic quality mode -#define CONFIG_RAW_FLAG 0x400000 // raw mode (not implemented yet) -#define CONFIG_CALC_NOISE 0x800000 // calc noise in hybrid mode -#define CONFIG_LOSSY_MODE 0x1000000 // obsolete (for information) -#define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode -#define CONFIG_SKIP_WVX 0x4000000 // no wvx stream w/ floats & big ints -#define CONFIG_MD5_CHECKSUM 0x8000000 // compute & store MD5 signature -#define CONFIG_QUIET_MODE 0x10000000 // don't report progress % -#define CONFIG_IGNORE_LENGTH 0x20000000 // ignore length in wav header - -#define EXTRA_SCAN_ONLY 1 -#define EXTRA_STEREO_MODES 2 -//#define EXTRA_CHECK_TERMS 4 -#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 { - uchar *buf, *end, *ptr; - void (*wrap)(struct bs *bs); - int error, bc; - uint32_t sr; -} Bitstream; - -#define MAX_STREAMS 8 -#define MAX_NTERMS 16 -#define MAX_TERM 8 - -struct decorr_pass { - int term, delta, weight_A, weight_B; - int32_t samples_A [MAX_TERM], samples_B [MAX_TERM]; - int32_t aweight_A, aweight_B; -#ifdef PACK - int32_t sum_A, sum_B, min, max; -#endif -}; - -typedef struct { - WavpackHeader wphdr; - - uchar *blockbuff, *blockend; - uchar *block2buff, *block2end; - int32_t *sample_buffer; - - uint32_t sample_index, crc, crc_x, crc_wvx; - Bitstream wvbits, wvcbits, wvxbits; - int bits, num_terms, mute_error; - float delta_decay; - - uchar int32_sent_bits, int32_zeros, int32_ones, int32_dups; - uchar 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; - } dc; - - struct decorr_pass decorr_passes [MAX_NTERMS]; - - struct { - uint32_t bitrate_delta [2], bitrate_acc [2]; - uint32_t median [3] [2], slow_level [2], error_limit [2]; - uint32_t pend_data, holding_one, zeros_acc; - int holding_zero, pend_count; - } w; -} 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. - -typedef struct { - int32_t (*read_bytes)(void *id, void *data, int32_t bcount); - uint32_t (*get_pos)(void *id); - int (*set_pos_abs)(void *id, uint32_t pos); - int (*set_pos_rel)(void *id, int32_t delta, int mode); - int (*push_back_byte)(void *id, int c); - uint32_t (*get_length)(void *id); - int (*can_seek)(void *id); -} stream_reader; - -typedef int (*blockout)(void *id, void *data, int32_t bcount); - -typedef struct { - WavpackConfig config; - - WavpackMetadata *metadata; - uint32_t metabytes; - int metacount; - - uchar *wrapper_data; - uint32_t wrapper_bytes; - - blockout blockout; - void *wv_out, *wvc_out; - - stream_reader *reader; - void *wv_in, *wvc_in; - - uint32_t filelen, file2len, filepos, file2pos, total_samples, crc_errors, first_flags; - int wvc_flag, open_flags, norm_offset, reduced_channels, lossy_blocks, close_files; - int block_samples, max_samples, acc_samples; - M_Tag m_tag; - - int current_stream, num_streams; - WavpackStream *streams [8]; - void *stream3; - - char error_message [80]; -} WavpackContext; - -//////////////////////// function prototypes and macros ////////////////////// - -#define CLEAR(destin) memset (&destin, 0, sizeof (destin)); - -// these macros implement the weight application and update operations -// that are at the heart of the decorrelation loops - -#define apply_weight_i(weight, sample) ((weight * sample + 512) >> 10) - -#define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \ - (((sample & ~0xffff) >> 9) * weight) + 1) >> 1) - -#if 1 // PERFCOND -#define apply_weight(weight, sample) (sample != (short) sample ? \ - apply_weight_f (weight, sample) : apply_weight_i (weight, sample)) -#else -#define apply_weight(weight, sample) ((int32_t)((weight * (int64_t) sample + 512) >> 10)) -#endif - -#if 1 // PERFCOND -#define update_weight(weight, delta, source, result) \ - if (source && result) weight -= ((((source ^ result) >> 30) & 2) - 1) * delta; -#else -#define update_weight(weight, delta, source, result) \ - if (source && result) (source ^ result) < 0 ? (weight -= delta) : (weight += delta); -#endif - -#define update_weight_d1(weight, delta, source, result) \ - if (source && result) weight -= (((source ^ result) >> 30) & 2) - 1; - -#define update_weight_d2(weight, delta, source, result) \ - if (source && result) weight -= (((source ^ result) >> 29) & 4) - 2; - -#define update_weight_clip(weight, delta, source, result) \ - if (source && result && ((source ^ result) < 0 ? (weight -= delta) < -1024 : (weight += delta) > 1024)) \ - weight = weight < 0 ? -1024 : 1024; - -#define update_weight_clip_d1(weight, delta, source, result) \ - if (source && result && abs (weight -= (((source ^ result) >> 30) & 2) - 1) > 1024) \ - weight = weight < 0 ? -1024 : 1024; - -#define update_weight_clip_d2(weight, delta, source, result) \ - if (source && result && abs (weight -= (((source ^ result) >> 29) & 4) - 2) > 1024) \ - weight = weight < 0 ? -1024 : 1024; - -// bits.c - -void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end); -void bs_open_write (Bitstream *bs, uchar *buffer_start, uchar *buffer_end); -uint32_t bs_close_read (Bitstream *bs); -uint32_t bs_close_write (Bitstream *bs); - -int DoReadFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead, uint32_t *lpNumberOfBytesRead); -int DoWriteFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToWrite, uint32_t *lpNumberOfBytesWritten); -uint32_t DoGetFileSize (FILE *hFile), DoGetFilePosition (FILE *hFile); -int DoSetFilePositionRelative (FILE *hFile, int32_t pos, int mode); -int DoSetFilePositionAbsolute (FILE *hFile, uint32_t pos); -int DoUngetc (int c, FILE *hFile), DoDeleteFile (char *filename); -int DoCloseHandle (FILE *hFile), DoTruncateFile (FILE *hFile); - -#define bs_is_open(bs) ((bs)->ptr != NULL) - -#define getbit(bs) ( \ - (((bs)->bc) ? \ - ((bs)->bc--, (bs)->sr & 1) : \ - (((++((bs)->ptr) != (bs)->end) ? (void) 0 : (bs)->wrap (bs)), (bs)->bc = 7, ((bs)->sr = *((bs)->ptr)) & 1) \ - ) ? \ - ((bs)->sr >>= 1, 1) : \ - ((bs)->sr >>= 1, 0) \ -) - -#define getbits(value, nbits, bs) { \ - while ((nbits) > (bs)->bc) { \ - if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ - (bs)->sr |= (int32_t)*((bs)->ptr) << (bs)->bc; \ - (bs)->bc += 8; \ - } \ - *(value) = (bs)->sr; \ - (bs)->sr >>= (nbits); \ - (bs)->bc -= (nbits); \ -} - -#define putbit(bit, bs) { if (bit) (bs)->sr |= (1 << (bs)->bc); \ - if (++((bs)->bc) == 8) { \ - *((bs)->ptr) = (bs)->sr; \ - (bs)->sr = (bs)->bc = 0; \ - if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ - }} - -#define putbit_0(bs) { \ - if (++((bs)->bc) == 8) { \ - *((bs)->ptr) = (bs)->sr; \ - (bs)->sr = (bs)->bc = 0; \ - if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ - }} - -#define putbit_1(bs) { (bs)->sr |= (1 << (bs)->bc); \ - if (++((bs)->bc) == 8) { \ - *((bs)->ptr) = (bs)->sr; \ - (bs)->sr = (bs)->bc = 0; \ - if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ - }} - -#define putbits(value, nbits, bs) { \ - (bs)->sr |= (int32_t)(value) << (bs)->bc; \ - if (((bs)->bc += (nbits)) >= 8) \ - do { \ - *((bs)->ptr) = (bs)->sr; \ - (bs)->sr >>= 8; \ - if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ - } while (((bs)->bc -= 8) >= 8); \ -} - -void little_endian_to_native (void *data, char *format); -void native_to_little_endian (void *data, char *format); - -// pack.c - -void pack_init (WavpackContext *wpc); -int pack_block (WavpackContext *wpc, int32_t *buffer); -double pack_noise (WavpackContext *wpc, double *peak); - -// unpack.c - -int unpack_init (WavpackContext *wpc); -int init_wv_bitstream (WavpackStream *wps, WavpackMetadata *wpmd); -int init_wvc_bitstream (WavpackStream *wps, WavpackMetadata *wpmd); -int init_wvx_bitstream (WavpackStream *wps, WavpackMetadata *wpmd); -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); -int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd); -int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd); -int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd); -int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd); -int read_wrapper_data (WavpackContext *wpc, WavpackMetadata *wpmd); -int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count); -int check_crc_error (WavpackContext *wpc); - -// unpack3.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); - -// utils.c - -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, ...), finish_line (void); -void setup_break (void); -int check_break (void); -char yna (void); -void AnsiToUTF8 (char *string, int len); - -#define FN_FIT(fn) ((strlen (fn) > 30) ? filespec_name (fn) : fn) - -// metadata.c stuff - -int read_metadata_buff (WavpackMetadata *wpmd, uchar *blockbuff, uchar **buffptr); -int write_metadata_block (WavpackContext *wpc); -int copy_metadata (WavpackMetadata *wpmd, uchar *buffer_start, uchar *buffer_end); -int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, uchar id); -int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd); -void free_metadata (WavpackMetadata *wpmd); - -// words.c stuff - -void init_words (WavpackStream *wps); -void word_set_bitrate (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 FASTCALL send_word_lossless (WavpackStream *wps, int32_t value, int chan); -int32_t FASTCALL get_word (WavpackStream *wps, int chan, int32_t *correction); -int32_t FASTCALL get_word_lossless (WavpackStream *wps, int chan); -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); - -int log2s (int32_t value); -int32_t exp2s (int log); -uint32_t log2buffer (int32_t *samples, uint32_t num_samples); - -char store_weight (int weight); -int restore_weight (char weight); - -#define WORD_EOF (1L << 31) - -// float.c - -void write_float_info (WavpackStream *wps, WavpackMetadata *wpmd); -int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values); -void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values); -int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd); -void float_values (WavpackStream *wps, int32_t *values, int32_t num_values); -void float_normalize (int32_t *values, int32_t num_values, int delta_exp); - -// analyze?.c - -void analyze_stereo (WavpackContext *wpc, int32_t *samples); -void analyze_mono (WavpackContext *wpc, int32_t *samples); - -// wputils.c - -WavpackContext *WavpackOpenFileInputEx (stream_reader *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 - -int WavpackGetMode (WavpackContext *wpc); - -#define MODE_WVC 0x1 -#define MODE_LOSSLESS 0x2 -#define MODE_HYBRID 0x4 -#define MODE_FLOAT 0x8 -#define MODE_VALID_TAG 0x10 -#define MODE_HIGH 0x20 -#define MODE_FAST 0x40 -#define MODE_EXTRA 0x80 -#define MODE_APETAG 0x100 -#define MODE_SFX 0x200 - -int WavpackGetVersion (WavpackContext *wpc); -uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples); -uint32_t WavpackGetNumSamples (WavpackContext *wpc); -uint32_t WavpackGetSampleIndex (WavpackContext *wpc); -int WavpackGetNumErrors (WavpackContext *wpc); -int WavpackLossyBlocks (WavpackContext *wpc); -int WavpackSeekSample (WavpackContext *wpc, uint32_t sample); -WavpackContext *WavpackCloseFile (WavpackContext *wpc); -uint32_t WavpackGetSampleRate (WavpackContext *wpc); -int WavpackGetBitsPerSample (WavpackContext *wpc); -int WavpackGetBytesPerSample (WavpackContext *wpc); -int WavpackGetNumChannels (WavpackContext *wpc); -int WavpackGetReducedChannels (WavpackContext *wpc); -int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]); -uint32_t WavpackGetWrapperBytes (WavpackContext *wpc); -uchar *WavpackGetWrapperData (WavpackContext *wpc); -void WavpackFreeWrapper (WavpackContext *wpc); -double WavpackGetProgress (WavpackContext *wpc); -uint32_t WavpackGetFileSize (WavpackContext *wpc); -double WavpackGetRatio (WavpackContext *wpc); -double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc); -double WavpackGetInstantBitrate (WavpackContext *wpc); -int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size); -int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value); -int WavpackWriteTag (WavpackContext *wpc); - -WavpackContext *WavpackOpenFileOutput (blockout blockout, void *wv_id, void *wvc_id); -int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples); -int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount); -int WavpackStoreMD5Sum (WavpackContext *wpc, uchar data [16]); -int WavpackPackInit (WavpackContext *wpc); -int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count); -int WavpackFlushSamples (WavpackContext *wpc); -void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block); -void *WavpackGetWrapperLocation (void *first_block); - -#endif +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wavpack.h + +#ifndef WAVPACK_H +#define WAVPACK_H + +#if defined(WIN32) +#define FASTCALL __fastcall +#else +#define FASTCALL +#define SetConsoleTitle(x) +#endif + +#include + +// This header file contains all the definitions required by WavPack. + +#if defined(_WIN32) && !defined(__MINGW32__) +#include +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; +typedef float float32_t; +#else +#include +#endif + +typedef unsigned char uchar; + +#if !defined(__GNUC__) || defined(WIN32) +typedef unsigned short ushort; +typedef unsigned int uint; +#endif + +#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 + +// This structure is used to access the individual fields of 32-bit ieee +// floating point numbers. This will not be compatible with compilers that +// allocate bit fields from the most significant bits, although I'm not sure +// how common that is. + +typedef struct { + unsigned mantissa : 23; + unsigned exponent : 8; + unsigned sign : 1; +} f32; + +#include + +#define FALSE 0 +#define TRUE 1 + +#if defined(WIN32) +#undef VERSION_OS +#define VERSION_OS "Win32" +#endif +#define VERSION_STR "4.32" +#define DATE_STR "2006-04-05" + +// ID3v1 and APEv2 TAG formats (may occur at the end of WavPack files) + +typedef struct { + uchar tag_id [3], title [30], artist [30], album [30]; + uchar 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" + +typedef struct { + int32_t tag_file_pos; + ID3_Tag id3_tag; + APE_Tag_Hdr ape_tag_hdr; + char *ape_tag_data; +} M_Tag; + +// RIFF / wav header formats (these occur at the beginning of both wav files +// and pre-4.0 WavPack files that are not in the "raw" mode) + +typedef struct { + char ckID [4]; + uint32_t ckSize; + char formType [4]; +} RiffChunkHeader; + +typedef struct { + char ckID [4]; + uint32_t ckSize; +} ChunkHeader; + +#define ChunkHeaderFormat "4L" + +typedef struct { + ushort FormatTag, NumChannels; + uint32_t SampleRate, BytesPerSecond; + ushort BlockAlign, BitsPerSample; + ushort cbSize, ValidBitsPerSample; + int32_t ChannelMask; + ushort SubFormat; + char GUID [14]; +} WaveHeader; + +#define WaveHeaderFormat "SSLLSSSSLS" + +////////////////////////////// WavPack Header ///////////////////////////////// + +// Note that this is the ONLY structure that is written to (or read from) +// WavPack 4.0 files, and is the preamble to every block in both the .wv +// and .wvc files. + +typedef struct { + char ckID [4]; + uint32_t ckSize; + short version; + uchar track_no, index_no; + uint32_t total_samples, block_index, block_samples, flags, crc; +} WavpackHeader; + +#define WavpackHeaderFormat "4LS2LLLLL" + +// or-values for "flags" + +#define BYTES_STORED 3 // 1-4 bytes/sample +#define MONO_FLAG 4 // not stereo +#define HYBRID_FLAG 8 // hybrid mode +#define JOINT_STEREO 0x10 // joint stereo +#define CROSS_DECORR 0x20 // no-delay cross decorrelation +#define HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) +#define FLOAT_DATA 0x80 // ieee 32-bit floating point data + +#define INT32_DATA 0x100 // special extended int handling +#define HYBRID_BITRATE 0x200 // bitrate noise (hybrid mode only) +#define HYBRID_BALANCE 0x400 // balance noise (hybrid stereo mode only) + +#define INITIAL_BLOCK 0x800 // initial block of multichannel segment +#define FINAL_BLOCK 0x1000 // final block of multichannel segment + +#define SHIFT_LSB 13 +#define SHIFT_MASK (0x1fL << SHIFT_LSB) + +#define MAG_LSB 18 +#define MAG_MASK (0x1fL << MAG_LSB) + +#define SRATE_LSB 23 +#define SRATE_MASK (0xfL << SRATE_LSB) + +#define FALSE_STEREO 0x40000000 // block is stereo, but data is mono + +#define IGNORED_FLAGS 0x18000000 // reserved, but ignore if encountered +#define NEW_SHAPING 0x20000000 // use IIR filter for negative shaping +#define UNKNOWN_FLAGS 0x80000000 // also reserved, but refuse decode if + // encountered + +#define MONO_DATA (MONO_FLAG | FALSE_STEREO) + +#define MIN_STREAM_VERS 0x402 // lowest stream version we'll decode +#define MAX_STREAM_VERS 0x410 // highest stream version we'll decode +#define CUR_STREAM_VERS 0x404 // stream version we are writing now + + +//////////////////////////// WavPack Metadata ///////////////////////////////// + +// This is an internal representation of metadata. + +typedef struct { + int32_t byte_length; + void *data; + uchar 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_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1) +#define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2) +#define ID_REPLAY_GAIN (ID_OPTIONAL_DATA | 0x3) +#define ID_CUESHEET (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) + +///////////////////////// WavPack Configuration /////////////////////////////// + +// This internal structure is used during encode to provide configuration to +// the encoding engine and during decoding to provide fle information back to +// the higher level functions. Not all fields are used in both modes. + +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; + uchar md5_checksum [16], md5_read; + int num_tag_strings; + char **tag_strings; +} WavpackConfig; + +#define CONFIG_BYTES_STORED 3 // 1-4 bytes/sample +#define CONFIG_MONO_FLAG 4 // not stereo +#define CONFIG_HYBRID_FLAG 8 // hybrid mode +#define CONFIG_JOINT_STEREO 0x10 // joint stereo +#define CONFIG_CROSS_DECORR 0x20 // no-delay cross decorrelation +#define CONFIG_HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) +#define CONFIG_FLOAT_DATA 0x80 // ieee 32-bit floating point data + +#define CONFIG_ADOBE_MODE 0x100 // "adobe" mode for 32-bit floats +#define CONFIG_FAST_FLAG 0x200 // fast mode +#define CONFIG_VERY_FAST_FLAG 0x400 // double fast +#define CONFIG_HIGH_FLAG 0x800 // high quality mode +#define CONFIG_VERY_HIGH_FLAG 0x1000 // double high (not used yet) +#define CONFIG_BITRATE_KBPS 0x2000 // bitrate is kbps, not bits / sample +#define CONFIG_AUTO_SHAPING 0x4000 // automatic noise shaping +#define CONFIG_SHAPE_OVERRIDE 0x8000 // shaping mode specified +#define CONFIG_JOINT_OVERRIDE 0x10000 // joint-stereo mode specified +#define CONFIG_COPY_TIME 0x20000 // copy file-time from source +#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_QUALITY_MODE 0x200000 // psychoacoustic quality mode +#define CONFIG_RAW_FLAG 0x400000 // raw mode (not implemented yet) +#define CONFIG_CALC_NOISE 0x800000 // calc noise in hybrid mode +#define CONFIG_LOSSY_MODE 0x1000000 // obsolete (for information) +#define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode +#define CONFIG_SKIP_WVX 0x4000000 // no wvx stream w/ floats & big ints +#define CONFIG_MD5_CHECKSUM 0x8000000 // compute & store MD5 signature +#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 { + uchar *buf, *end, *ptr; + void (*wrap)(struct bs *bs); + int error, bc; + uint32_t sr; +} Bitstream; + +#define MAX_STREAMS 8 +#define MAX_NTERMS 16 +#define MAX_TERM 8 + +struct decorr_pass { + int 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 { + WavpackHeader wphdr; + + uchar *blockbuff, *blockend; + uchar *block2buff, *block2end; + int32_t *sample_buffer; + + int bits, num_terms, mute_error, false_stereo, shift; + uint32_t sample_index, crc, crc_x, crc_wvx; + Bitstream wvbits, wvcbits, wvxbits; + float delta_decay; + + uchar int32_sent_bits, int32_zeros, int32_ones, int32_dups; + uchar 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; + } dc; + + struct decorr_pass decorr_passes [MAX_NTERMS]; + + struct { + uint32_t bitrate_delta [2], bitrate_acc [2]; + uint32_t median [3] [2], slow_level [2], error_limit [2]; + uint32_t pend_data, holding_one, zeros_acc; + int holding_zero, pend_count; + } w; +} 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. + +typedef struct { + int32_t (*read_bytes)(void *id, void *data, int32_t bcount); + uint32_t (*get_pos)(void *id); + int (*set_pos_abs)(void *id, uint32_t pos); + int (*set_pos_rel)(void *id, int32_t delta, int mode); + int (*push_back_byte)(void *id, int c); + uint32_t (*get_length)(void *id); + int (*can_seek)(void *id); + + // this callback is for writing edited tags only + int32_t (*write_bytes)(void *id, void *data, int32_t bcount); +} WavpackStreamReader; + +typedef int (*WavpackBlockOutput)(void *id, void *data, int32_t bcount); + +typedef struct { + WavpackConfig config; + + WavpackMetadata *metadata; + uint32_t metabytes; + int metacount; + + uchar *wrapper_data; + uint32_t wrapper_bytes; + + WavpackBlockOutput blockout; + void *wv_out, *wvc_out; + + WavpackStreamReader *reader; + void *wv_in, *wvc_in; + + uint32_t filelen, file2len, filepos, file2pos, total_samples, crc_errors, first_flags; + int wvc_flag, open_flags, norm_offset, reduced_channels, lossy_blocks, close_files; + int block_samples, max_samples, acc_samples, riff_header_added, riff_header_created; + M_Tag m_tag; + + int current_stream, num_streams, stream_version; + WavpackStream *streams [8]; + void *stream3; + + char error_message [80]; +} WavpackContext; + +//////////////////////// function prototypes and macros ////////////////////// + +#define CLEAR(destin) memset (&destin, 0, sizeof (destin)); + +// these macros implement the weight application and update operations +// that are at the heart of the decorrelation loops + +#define apply_weight_i(weight, sample) ((weight * sample + 512) >> 10) + +#define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \ + (((sample & ~0xffff) >> 9) * weight) + 1) >> 1) + +#if 1 // PERFCOND +#define apply_weight(weight, sample) (sample != (short) sample ? \ + apply_weight_f (weight, sample) : apply_weight_i (weight, sample)) +#else +#define apply_weight(weight, sample) ((int32_t)((weight * (int64_t) sample + 512) >> 10)) +#endif + +#if 1 // PERFCOND +#define update_weight(weight, delta, source, result) \ + if (source && result) weight -= ((((source ^ result) >> 30) & 2) - 1) * delta; +#else +#define update_weight(weight, delta, source, result) \ + if (source && result) (source ^ result) < 0 ? (weight -= delta) : (weight += delta); +#endif + +#define update_weight_d1(weight, delta, source, result) \ + if (source && result) weight -= (((source ^ result) >> 30) & 2) - 1; + +#define update_weight_d2(weight, delta, source, result) \ + if (source && result) weight -= (((source ^ result) >> 29) & 4) - 2; + +#define update_weight_clip(weight, delta, source, result) \ + if (source && result && ((source ^ result) < 0 ? (weight -= delta) < -1024 : (weight += delta) > 1024)) \ + weight = weight < 0 ? -1024 : 1024; + +#define update_weight_clip_d1(weight, delta, source, result) \ + if (source && result && abs (weight -= (((source ^ result) >> 30) & 2) - 1) > 1024) \ + weight = weight < 0 ? -1024 : 1024; + +#define update_weight_clip_d2(weight, delta, source, result) \ + if (source && result && abs (weight -= (((source ^ result) >> 29) & 4) - 2) > 1024) \ + weight = weight < 0 ? -1024 : 1024; + +// bits.c + +void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end); +void bs_open_write (Bitstream *bs, uchar *buffer_start, uchar *buffer_end); +uint32_t bs_close_read (Bitstream *bs); +uint32_t bs_close_write (Bitstream *bs); + +int DoReadFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead, uint32_t *lpNumberOfBytesRead); +int DoWriteFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToWrite, uint32_t *lpNumberOfBytesWritten); +uint32_t DoGetFileSize (FILE *hFile), DoGetFilePosition (FILE *hFile); +int DoSetFilePositionRelative (FILE *hFile, int32_t pos, int mode); +int DoSetFilePositionAbsolute (FILE *hFile, uint32_t pos); +int DoUngetc (int c, FILE *hFile), DoDeleteFile (char *filename); +int DoCloseHandle (FILE *hFile), DoTruncateFile (FILE *hFile); + +#define bs_is_open(bs) ((bs)->ptr != NULL) + +#define getbit(bs) ( \ + (((bs)->bc) ? \ + ((bs)->bc--, (bs)->sr & 1) : \ + (((++((bs)->ptr) != (bs)->end) ? (void) 0 : (bs)->wrap (bs)), (bs)->bc = 7, ((bs)->sr = *((bs)->ptr)) & 1) \ + ) ? \ + ((bs)->sr >>= 1, 1) : \ + ((bs)->sr >>= 1, 0) \ +) + +#define getbits(value, nbits, bs) { \ + while ((nbits) > (bs)->bc) { \ + if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ + (bs)->sr |= (int32_t)*((bs)->ptr) << (bs)->bc; \ + (bs)->bc += 8; \ + } \ + *(value) = (bs)->sr; \ + if ((bs)->bc > 32) { \ + (bs)->bc -= (nbits); \ + (bs)->sr = *((bs)->ptr) >> (8 - (bs)->bc); \ + } \ + else { \ + (bs)->bc -= (nbits); \ + (bs)->sr >>= (nbits); \ + } \ +} + +#define putbit(bit, bs) { if (bit) (bs)->sr |= (1 << (bs)->bc); \ + if (++((bs)->bc) == 8) { \ + *((bs)->ptr) = (bs)->sr; \ + (bs)->sr = (bs)->bc = 0; \ + if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ + }} + +#define putbit_0(bs) { \ + if (++((bs)->bc) == 8) { \ + *((bs)->ptr) = (bs)->sr; \ + (bs)->sr = (bs)->bc = 0; \ + if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ + }} + +#define putbit_1(bs) { (bs)->sr |= (1 << (bs)->bc); \ + if (++((bs)->bc) == 8) { \ + *((bs)->ptr) = (bs)->sr; \ + (bs)->sr = (bs)->bc = 0; \ + if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ + }} + +#define putbits(value, nbits, bs) { \ + (bs)->sr |= (int32_t)(value) << (bs)->bc; \ + if (((bs)->bc += (nbits)) >= 8) \ + do { \ + *((bs)->ptr) = (bs)->sr; \ + (bs)->sr >>= 8; \ + if (((bs)->bc -= 8) > 24) (bs)->sr |= ((value) >> ((nbits) - (bs)->bc)); \ + if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \ + } while ((bs)->bc >= 8); \ +} + +void little_endian_to_native (void *data, char *format); +void native_to_little_endian (void *data, char *format); + +// pack.c + +void pack_init (WavpackContext *wpc); +int pack_block (WavpackContext *wpc, int32_t *buffer); +double pack_noise (WavpackContext *wpc, double *peak); + +// unpack.c + +int unpack_init (WavpackContext *wpc); +int init_wv_bitstream (WavpackStream *wps, WavpackMetadata *wpmd); +int init_wvc_bitstream (WavpackStream *wps, WavpackMetadata *wpmd); +int init_wvx_bitstream (WavpackStream *wps, WavpackMetadata *wpmd); +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); +int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd); +int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd); +int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd); +int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd); +int read_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd); +int read_wrapper_data (WavpackContext *wpc, WavpackMetadata *wpmd); +int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count); +int check_crc_error (WavpackContext *wpc); + +// unpack3.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); + +// utils.c + +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); + +#define FN_FIT(fn) ((strlen (fn) > 30) ? filespec_name (fn) : fn) + +// metadata.c stuff + +int read_metadata_buff (WavpackMetadata *wpmd, uchar *blockbuff, uchar **buffptr); +int write_metadata_block (WavpackContext *wpc); +int copy_metadata (WavpackMetadata *wpmd, uchar *buffer_start, uchar *buffer_end); +int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, uchar id); +int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd); +void free_metadata (WavpackMetadata *wpmd); + +// words.c stuff + +void init_words (WavpackStream *wps); +void word_set_bitrate (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 FASTCALL send_word_lossless (WavpackStream *wps, int32_t value, int chan); +int32_t FASTCALL get_word (WavpackStream *wps, int chan, int32_t *correction); +int32_t FASTCALL get_word_lossless (WavpackStream *wps, int chan); +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); + +int log2s (int32_t value); +int32_t exp2s (int log); +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 (1L << 31) + +// float.c + +void write_float_info (WavpackStream *wps, WavpackMetadata *wpmd); +int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values); +void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values); +int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd); +void float_values (WavpackStream *wps, int32_t *values, int32_t num_values); +void float_normalize (int32_t *values, int32_t num_values, int delta_exp); + +// analyze?.c + +void analyze_stereo (WavpackContext *wpc, int32_t *samples); +void analyze_mono (WavpackContext *wpc, int32_t *samples); + +// wputils.c + +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 + +int WavpackGetMode (WavpackContext *wpc); + +#define MODE_WVC 0x1 +#define MODE_LOSSLESS 0x2 +#define MODE_HYBRID 0x4 +#define MODE_FLOAT 0x8 +#define MODE_VALID_TAG 0x10 +#define MODE_HIGH 0x20 +#define MODE_FAST 0x40 +#define MODE_EXTRA 0x80 +#define MODE_APETAG 0x100 +#define MODE_SFX 0x200 + +int WavpackGetVersion (WavpackContext *wpc); +uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples); +uint32_t WavpackGetNumSamples (WavpackContext *wpc); +uint32_t WavpackGetSampleIndex (WavpackContext *wpc); +int WavpackGetNumErrors (WavpackContext *wpc); +int WavpackLossyBlocks (WavpackContext *wpc); +int WavpackSeekSample (WavpackContext *wpc, uint32_t sample); +WavpackContext *WavpackCloseFile (WavpackContext *wpc); +uint32_t WavpackGetSampleRate (WavpackContext *wpc); +int WavpackGetBitsPerSample (WavpackContext *wpc); +int WavpackGetBytesPerSample (WavpackContext *wpc); +int WavpackGetNumChannels (WavpackContext *wpc); +int WavpackGetReducedChannels (WavpackContext *wpc); +int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]); +uint32_t WavpackGetWrapperBytes (WavpackContext *wpc); +uchar *WavpackGetWrapperData (WavpackContext *wpc); +void WavpackFreeWrapper (WavpackContext *wpc); +double WavpackGetProgress (WavpackContext *wpc); +uint32_t WavpackGetFileSize (WavpackContext *wpc); +double WavpackGetRatio (WavpackContext *wpc); +double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc); +double WavpackGetInstantBitrate (WavpackContext *wpc); +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 WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize); +int WavpackDeleteTagItem (WavpackContext *wpc, const char *item); +int WavpackWriteTag (WavpackContext *wpc); + +WavpackContext *WavpackOpenFileOutput (WavpackBlockOutput blockout, void *wv_id, void *wvc_id); +int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples); +int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount); +int WavpackStoreMD5Sum (WavpackContext *wpc, uchar data [16]); +int WavpackPackInit (WavpackContext *wpc); +int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count); +int WavpackFlushSamples (WavpackContext *wpc); +void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block); +void *WavpackGetWrapperLocation (void *first_block, uint32_t *size); + +#endif diff --git a/Libraries/WavPack/Files/words.c b/Libraries/WavPack/Files/words.c index 4b8fde6c3..41dd68cb0 100644 --- a/Libraries/WavPack/Files/words.c +++ b/Libraries/WavPack/Files/words.c @@ -1,1437 +1,1433 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -//////////////////////////////////////////////////////////////////////////// - -// words.c - -// This module provides entropy word encoding and 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 "wavpack.h" - -#include -#include - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -#endif - -// #define DEBUG_WORDS // debug module by sending all 32 bits literally - -//////////////////////////////// local macros ///////////////////////////////// - -#define LIMIT_ONES 16 // maximum consecutive 1s sent for "div" data - -// 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))) - -// 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) (((wps->w.median [med] [chan]) >> 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() (wps->w.median [0] [chan] += ((wps->w.median [0] [chan] + DIV0) / DIV0) * 5) -#define DEC_MED0() (wps->w.median [0] [chan] -= ((wps->w.median [0] [chan] + (DIV0-2)) / DIV0) * 2) -#define INC_MED1() (wps->w.median [1] [chan] += ((wps->w.median [1] [chan] + DIV1) / DIV1) * 5) -#define DEC_MED1() (wps->w.median [1] [chan] -= ((wps->w.median [1] [chan] + (DIV1-2)) / DIV1) * 2) -#define INC_MED2() (wps->w.median [2] [chan] += ((wps->w.median [2] [chan] + DIV2) / DIV2) * 5) -#define DEC_MED2() (wps->w.median [2] [chan] -= ((wps->w.median [2] [chan] + (DIV2-2)) / DIV2) * 2) - -#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) \ - ) \ -) - -///////////////////////////// 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 uchar 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 uchar 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 -}; - -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 -}; - -///////////////////////////// executable code //////////////////////////////// - -static int FASTCALL mylog2 (uint32_t avalue); - -// 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. - -#ifdef PACK - -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. - -void word_set_bitrate (WavpackStream *wps) -{ - int bitrate_0, bitrate_1; - - if (wps->wphdr.flags & HYBRID_BITRATE) { - bitrate_0 = wps->bits < 568 ? 0 : wps->bits - 568; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - - 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_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 mylog2 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) -{ - uchar *byteptr; - int temp; - - byteptr = wpmd->data = malloc (12); - wpmd->id = ID_ENTROPY_VARS; - - *byteptr++ = temp = mylog2 (wps->w.median [0] [0]); - *byteptr++ = temp >> 8; - *byteptr++ = temp = mylog2 (wps->w.median [1] [0]); - *byteptr++ = temp >> 8; - *byteptr++ = temp = mylog2 (wps->w.median [2] [0]); - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - *byteptr++ = temp = mylog2 (wps->w.median [0] [1]); - *byteptr++ = temp >> 8; - *byteptr++ = temp = mylog2 (wps->w.median [1] [1]); - *byteptr++ = temp >> 8; - *byteptr++ = temp = mylog2 (wps->w.median [2] [1]); - *byteptr++ = temp >> 8; - } - - wpmd->byte_length = byteptr - (uchar *) 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 -// mylog2 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) -{ - uchar *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 = log2s (wps->w.slow_level [0]); - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - *byteptr++ = temp = log2s (wps->w.slow_level [1]); - *byteptr++ = temp >> 8; - } - } - - *byteptr++ = temp = wps->w.bitrate_acc [0] >> 16; - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - *byteptr++ = temp = wps->w.bitrate_acc [1] >> 16; - *byteptr++ = temp >> 8; - } - - if (wps->w.bitrate_delta [0] | wps->w.bitrate_delta [1]) { - *byteptr++ = temp = log2s (wps->w.bitrate_delta [0]); - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - *byteptr++ = temp = log2s (wps->w.bitrate_delta [1]); - *byteptr++ = temp >> 8; - } - } - - wpmd->byte_length = byteptr - (uchar *) wpmd->data; - read_hybrid_profile (wps, wpmd); -} - -#endif - -// Read the median log2 values from the specifed 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) -{ - uchar *byteptr = wpmd->data; - - if (wpmd->byte_length != ((wps->wphdr.flags & MONO_FLAG) ? 6 : 12)) - return FALSE; - - wps->w.median [0] [0] = exp2s (byteptr [0] + (byteptr [1] << 8)); - wps->w.median [1] [0] = exp2s (byteptr [2] + (byteptr [3] << 8)); - wps->w.median [2] [0] = exp2s (byteptr [4] + (byteptr [5] << 8)); - - if (!(wps->wphdr.flags & MONO_FLAG)) { - wps->w.median [0] [1] = exp2s (byteptr [6] + (byteptr [7] << 8)); - wps->w.median [1] [1] = exp2s (byteptr [8] + (byteptr [9] << 8)); - wps->w.median [2] [1] = exp2s (byteptr [10] + (byteptr [11] << 8)); - } - - return TRUE; -} - -// Read the hybrid related values from the specifed 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) -{ - uchar *byteptr = wpmd->data; - uchar *endptr = byteptr + wpmd->byte_length; - - if (wps->wphdr.flags & HYBRID_BITRATE) { - wps->w.slow_level [0] = exp2s (byteptr [0] + (byteptr [1] << 8)); - byteptr += 2; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - wps->w.slow_level [1] = exp2s (byteptr [0] + (byteptr [1] << 8)); - byteptr += 2; - } - } - - wps->w.bitrate_acc [0] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16; - byteptr += 2; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - wps->w.bitrate_acc [1] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16; - byteptr += 2; - } - - if (byteptr < endptr) { - wps->w.bitrate_delta [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); - byteptr += 2; - - if (!(wps->wphdr.flags & MONO_FLAG)) { - wps->w.bitrate_delta [1] = exp2s ((short)(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. - -static 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_FLAG) { - if (wps->wphdr.flags & HYBRID_BITRATE) { - int slow_log_0 = (wps->w.slow_level [0] + SLO) >> SLS; - - if (slow_log_0 - bitrate_0 > -0x100) - wps->w.error_limit [0] = exp2s (slow_log_0 - bitrate_0 + 0x100); - else - wps->w.error_limit [0] = 0; - } - else - wps->w.error_limit [0] = 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.slow_level [0] + SLO) >> SLS; - int slow_log_1 = (wps->w.slow_level [1] + 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.error_limit [0] = exp2s (slow_log_0 - bitrate_0 + 0x100); - else - wps->w.error_limit [0] = 0; - - if (slow_log_1 - bitrate_1 > -0x100) - wps->w.error_limit [1] = exp2s (slow_log_1 - bitrate_1 + 0x100); - else - wps->w.error_limit [1] = 0; - } - else { - wps->w.error_limit [0] = exp2s (bitrate_0); - wps->w.error_limit [1] = exp2s (bitrate_1); - } - } -} - -#ifdef PACK - -// 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) -{ - uint32_t ones_count, low, mid, high; - int sign = (value < 0) ? 1 : 0; - -#ifdef DEBUG_WORDS - mid = value; - ones_count = 32; - while (ones_count--) { - putbit (value & 1, &wps->wvbits); - value >>= 1; - } - return mid; -#endif - - if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !(wps->w.median [0] [1] & ~1)) { - if (wps->w.zeros_acc) { - if (value) - flush_word (wps); - else { - wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; - wps->w.zeros_acc++; - return 0; - } - } - else if (value) { - putbit_0 (&wps->wvbits); - } - else { - wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; - CLEAR (wps->w.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 < 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 (!wps->w.error_limit [chan]) { - 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 > wps->w.error_limit [chan]) - if (value < 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) && wps->w.error_limit [chan]) { - 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) { - wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; - wps->w.slow_level [chan] += mylog2 (mid); - } - - return sign ? ~mid : mid; -} - -// This function is an optimized version of send_word() that only handles -// lossless (error_limit == 0). It does not return a value because it always -// encodes the exact value passed. - -void FASTCALL send_word_lossless (WavpackStream *wps, int32_t value, int chan) -{ - int sign = (value < 0) ? 1 : 0; - uint32_t ones_count, low, high; - -#ifdef DEBUG_WORDS - ones_count = 32; - while (ones_count--) { - putbit (value & 1, &wps->wvbits); - value >>= 1; - } - return; -#endif - - if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !(wps->w.median [0] [1] & ~1)) { - if (wps->w.zeros_acc) { - if (value) - flush_word (wps); - else { - wps->w.zeros_acc++; - return; - } - } - else if (value) { - putbit_0 (&wps->wvbits); - } - else { - CLEAR (wps->w.median); - wps->w.zeros_acc = 1; - return; - } - } - - if (sign) - value = ~value; - - if (value < 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) { - - while (wps->w.pend_count > 24) { - putbit (wps->w.pend_data & 1, &wps->wvbits); - wps->w.pend_data >>= 1; - 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) -{ - 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 < 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 (!wps->w.error_limit [chan]) - mid = value; - else - while (high - low > wps->w.error_limit [chan]) - if (value < mid) - mid = ((high = mid - 1) + low + 1) >> 1; - else - mid = (high + (low = mid) + 1) >> 1; - - wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; - wps->w.slow_level [chan] += mylog2 (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 symetrical 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. - -void scan_word (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir) -{ - uint32_t flags = wps->wphdr.flags, value, low; - int chan; - - CLEAR (wps->w.slow_level); - CLEAR (wps->w.median); - - if (flags & MONO_FLAG) { - 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.slow_level [0] -= (wps->w.slow_level [0] + SLO) >> SLS; - wps->w.slow_level [0] += mylog2 (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_FLAG)) { - value = labs (samples [chan = 1]); - - if (wps->wphdr.flags & HYBRID_BITRATE) { - wps->w.slow_level [1] -= (wps->w.slow_level [1] + SLO) >> SLS; - wps->w.slow_level [1] += mylog2 (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 (); - } - } - } - } - - samples += dir; - } -} - -#endif - -#ifdef UNPACK - -static uint32_t FASTCALL 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) -{ - uint32_t ones_count, low, mid, high; - int next8, sign; - int32_t value; - - if (correction) - *correction = 0; - -#ifdef DEBUG_WORDS - ones_count = 32; - while (ones_count--) - value = getbit (&wps->wvbits) ? (value >> 1) | 0x80000000 : (value >> 1) & 0x7fffffff; - return value; -#endif - - if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.median [0] [1] & ~1)) { - uint32_t mask; - int cbits; - - if (wps->w.zeros_acc) { - if (--wps->w.zeros_acc) { - wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + 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) { - wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; - CLEAR (wps->w.median); - return 0; - } - } - } - - if (wps->w.holding_zero) - ones_count = wps->w.holding_zero = 0; - else { - 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 += 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; - } - - 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 (); - } - } - } - - mid = (high + low + 1) >> 1; - - if (!wps->w.error_limit [chan]) - mid = read_code (&wps->wvbits, high - low) + low; - else while (high - low > wps->w.error_limit [chan]) { - 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) && wps->w.error_limit [chan]) { - value = read_code (&wps->wvcbits, high - low) + low; - - if (correction) - *correction = sign ? (mid - value) : (value - mid); - } - - if (wps->wphdr.flags & HYBRID_BITRATE) { - wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; - wps->w.slow_level [chan] += mylog2 (mid); - } - - return sign ? ~mid : mid; -} - -// This is an optimized version of get_word() that is used for lossless only -// (error_limit == 0). There are two versions of an internal section; they -// are identical from a functional standpoint, but one may be faster than the -// other under different compilers / processors. - -int32_t FASTCALL get_word_lossless (WavpackStream *wps, int chan) -{ - uint32_t ones_count, low, high; - int next8; - -#ifdef DEBUG_WORDS - ones_count = 32; - while (ones_count--) - low = getbit (&wps->wvbits) ? (low >> 1) | 0x80000000 : (low >> 1) & 0x7fffffff; - return low; -#endif - - if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.median [0] [1] & ~1)) { - uint32_t mask; - int cbits; - - if (wps->w.zeros_acc) { - if (--wps->w.zeros_acc) - 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) { - CLEAR (wps->w.median); - return 0; - } - } - } - - if (wps->w.holding_zero) - ones_count = wps->w.holding_zero = 0; - else { - 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 += 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; - } - - 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 (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 (&wps->wvbits, high - low); - return (getbit (&wps->wvbits)) ? ~low : low; -} - -// 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 FASTCALL read_code (Bitstream *bs, uint32_t maxcode) -{ - int bitcount = count_bits (maxcode); - uint32_t extras = bitset [bitcount] - maxcode - 1, code; - - if (!bitcount) - return 0; - - getbits (&code, bitcount - 1, bs); - code &= bitmask [bitcount - 1]; - - if (code >= extras) { - code = (code << 1) - extras; - - if (getbit (bs)) - ++code; - } - - return code; -} - -#endif - -// 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. - -static int FASTCALL mylog2 (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. - -uint32_t log2buffer (int32_t *samples, uint32_t num_samples) -{ - 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 << 8) + log2_table [(avalue >> (dbits - 9)) & 0xff]; - } - } - - return result; -} - -// 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 log2s (int32_t value) -{ - return (value < 0) ? -mylog2 (-value) : mylog2 (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 exp2s (int log) -{ - uint32_t value; - - if (log < 0) - return -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. - -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 (char weight) -{ - int result; - - if ((result = (int) weight << 3) > 0) - result += (result + 64) >> 7; - - return result; -} +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +//////////////////////////////////////////////////////////////////////////// + +// words.c + +// This module provides entropy word encoding and 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 "wavpack.h" + +#include +#include + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +// #define DEBUG_WORDS // debug module by sending all 32 bits literally + +//////////////////////////////// local macros ///////////////////////////////// + +#define LIMIT_ONES 16 // maximum consecutive 1s sent for "div" data + +// 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))) + +// 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) (((wps->w.median [med] [chan]) >> 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() (wps->w.median [0] [chan] += ((wps->w.median [0] [chan] + DIV0) / DIV0) * 5) +#define DEC_MED0() (wps->w.median [0] [chan] -= ((wps->w.median [0] [chan] + (DIV0-2)) / DIV0) * 2) +#define INC_MED1() (wps->w.median [1] [chan] += ((wps->w.median [1] [chan] + DIV1) / DIV1) * 5) +#define DEC_MED1() (wps->w.median [1] [chan] -= ((wps->w.median [1] [chan] + (DIV1-2)) / DIV1) * 2) +#define INC_MED2() (wps->w.median [2] [chan] += ((wps->w.median [2] [chan] + DIV2) / DIV2) * 5) +#define DEC_MED2() (wps->w.median [2] [chan] -= ((wps->w.median [2] [chan] + (DIV2-2)) / DIV2) * 2) + +#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) \ + ) \ +) + +///////////////////////////// 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 uchar 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 uchar 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 +}; + +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 +}; + +///////////////////////////// executable code //////////////////////////////// + +static int FASTCALL mylog2 (uint32_t avalue); + +// 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. + +#ifdef PACK + +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. + +void word_set_bitrate (WavpackStream *wps) +{ + int bitrate_0, bitrate_1; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + 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_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 mylog2 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) +{ + uchar *byteptr; + int temp; + + byteptr = wpmd->data = malloc (12); + wpmd->id = ID_ENTROPY_VARS; + + *byteptr++ = temp = mylog2 (wps->w.median [0] [0]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.median [1] [0]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.median [2] [0]); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + *byteptr++ = temp = mylog2 (wps->w.median [0] [1]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.median [1] [1]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.median [2] [1]); + *byteptr++ = temp >> 8; + } + + wpmd->byte_length = byteptr - (uchar *) 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 +// mylog2 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) +{ + uchar *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 = log2s (wps->w.slow_level [0]); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + *byteptr++ = temp = log2s (wps->w.slow_level [1]); + *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 = log2s (wps->w.bitrate_delta [0]); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + *byteptr++ = temp = log2s (wps->w.bitrate_delta [1]); + *byteptr++ = temp >> 8; + } + } + + wpmd->byte_length = byteptr - (uchar *) wpmd->data; + read_hybrid_profile (wps, wpmd); +} + +#endif + +// Read the median log2 values from the specifed 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) +{ + uchar *byteptr = wpmd->data; + + if (wpmd->byte_length != ((wps->wphdr.flags & MONO_DATA) ? 6 : 12)) + return FALSE; + + wps->w.median [0] [0] = exp2s (byteptr [0] + (byteptr [1] << 8)); + wps->w.median [1] [0] = exp2s (byteptr [2] + (byteptr [3] << 8)); + wps->w.median [2] [0] = exp2s (byteptr [4] + (byteptr [5] << 8)); + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->w.median [0] [1] = exp2s (byteptr [6] + (byteptr [7] << 8)); + wps->w.median [1] [1] = exp2s (byteptr [8] + (byteptr [9] << 8)); + wps->w.median [2] [1] = exp2s (byteptr [10] + (byteptr [11] << 8)); + } + + return TRUE; +} + +// Read the hybrid related values from the specifed 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) +{ + uchar *byteptr = wpmd->data; + uchar *endptr = byteptr + wpmd->byte_length; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + wps->w.slow_level [0] = exp2s (byteptr [0] + (byteptr [1] << 8)); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->w.slow_level [1] = exp2s (byteptr [0] + (byteptr [1] << 8)); + byteptr += 2; + } + } + + 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) { + wps->w.bitrate_delta [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->w.bitrate_delta [1] = exp2s ((short)(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. + +static 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.slow_level [0] + SLO) >> SLS; + + if (slow_log_0 - bitrate_0 > -0x100) + wps->w.error_limit [0] = exp2s (slow_log_0 - bitrate_0 + 0x100); + else + wps->w.error_limit [0] = 0; + } + else + wps->w.error_limit [0] = 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.slow_level [0] + SLO) >> SLS; + int slow_log_1 = (wps->w.slow_level [1] + 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.error_limit [0] = exp2s (slow_log_0 - bitrate_0 + 0x100); + else + wps->w.error_limit [0] = 0; + + if (slow_log_1 - bitrate_1 > -0x100) + wps->w.error_limit [1] = exp2s (slow_log_1 - bitrate_1 + 0x100); + else + wps->w.error_limit [1] = 0; + } + else { + wps->w.error_limit [0] = exp2s (bitrate_0); + wps->w.error_limit [1] = exp2s (bitrate_1); + } + } +} + +#ifdef PACK + +// 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) +{ + uint32_t ones_count, low, mid, high; + int sign = (value < 0) ? 1 : 0; + +#ifdef DEBUG_WORDS + mid = value; + ones_count = 32; + while (ones_count--) { + putbit (value & 1, &wps->wvbits); + value >>= 1; + } + return mid; +#endif + + if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !(wps->w.median [0] [1] & ~1)) { + if (wps->w.zeros_acc) { + if (value) + flush_word (wps); + else { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + wps->w.zeros_acc++; + return 0; + } + } + else if (value) { + putbit_0 (&wps->wvbits); + } + else { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + CLEAR (wps->w.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 < 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 (!wps->w.error_limit [chan]) { + 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 > wps->w.error_limit [chan]) + if (value < 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) && wps->w.error_limit [chan]) { + 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) { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + wps->w.slow_level [chan] += mylog2 (mid); + } + + return sign ? ~mid : mid; +} + +// This function is an optimized version of send_word() that only handles +// lossless (error_limit == 0). It does not return a value because it always +// encodes the exact value passed. + +void FASTCALL send_word_lossless (WavpackStream *wps, int32_t value, int chan) +{ + int sign = (value < 0) ? 1 : 0; + uint32_t ones_count, low, high; + +#ifdef DEBUG_WORDS + ones_count = 32; + while (ones_count--) { + putbit (value & 1, &wps->wvbits); + value >>= 1; + } + return; +#endif + + if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !(wps->w.median [0] [1] & ~1)) { + if (wps->w.zeros_acc) { + if (value) + flush_word (wps); + else { + wps->w.zeros_acc++; + return; + } + } + else if (value) { + putbit_0 (&wps->wvbits); + } + else { + CLEAR (wps->w.median); + wps->w.zeros_acc = 1; + return; + } + } + + if (sign) + value = ~value; + + if (value < 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) +{ + 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 < 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 (!wps->w.error_limit [chan]) + mid = value; + else + while (high - low > wps->w.error_limit [chan]) + if (value < mid) + mid = ((high = mid - 1) + low + 1) >> 1; + else + mid = (high + (low = mid) + 1) >> 1; + + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + wps->w.slow_level [chan] += mylog2 (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 symetrical 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. + +void scan_word (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir) +{ + uint32_t flags = wps->wphdr.flags, value, low; + int chan; + + CLEAR (wps->w.slow_level); + CLEAR (wps->w.median); + + 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.slow_level [0] -= (wps->w.slow_level [0] + SLO) >> SLS; + wps->w.slow_level [0] += mylog2 (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]); + + if (wps->wphdr.flags & HYBRID_BITRATE) { + wps->w.slow_level [1] -= (wps->w.slow_level [1] + SLO) >> SLS; + wps->w.slow_level [1] += mylog2 (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 (); + } + } + } + } + + samples += dir; + } +} + +#endif + +#ifdef UNPACK + +static uint32_t FASTCALL 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) +{ + uint32_t ones_count, low, mid, high; + int next8, sign; + int32_t value; + + if (correction) + *correction = 0; + +#ifdef DEBUG_WORDS + ones_count = 32; + while (ones_count--) + value = getbit (&wps->wvbits) ? (value >> 1) | 0x80000000 : (value >> 1) & 0x7fffffff; + return value; +#endif + + if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.median [0] [1] & ~1)) { + uint32_t mask; + int cbits; + + if (wps->w.zeros_acc) { + if (--wps->w.zeros_acc) { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + 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) { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + CLEAR (wps->w.median); + return 0; + } + } + } + + if (wps->w.holding_zero) + ones_count = wps->w.holding_zero = 0; + else { + 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 += 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; + } + + 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 (); + } + } + } + + mid = (high + low + 1) >> 1; + + if (!wps->w.error_limit [chan]) + mid = read_code (&wps->wvbits, high - low) + low; + else while (high - low > wps->w.error_limit [chan]) { + 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) && wps->w.error_limit [chan]) { + value = read_code (&wps->wvcbits, high - low) + low; + + if (correction) + *correction = sign ? (mid - value) : (value - mid); + } + + if (wps->wphdr.flags & HYBRID_BITRATE) { + wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS; + wps->w.slow_level [chan] += mylog2 (mid); + } + + return sign ? ~mid : mid; +} + +// This is an optimized version of get_word() that is used for lossless only +// (error_limit == 0). There are two versions of an internal section; they +// are identical from a functional standpoint, but one may be faster than the +// other under different compilers / processors. + +int32_t FASTCALL get_word_lossless (WavpackStream *wps, int chan) +{ + uint32_t ones_count, low, high; + int next8; + +#ifdef DEBUG_WORDS + ones_count = 32; + while (ones_count--) + low = getbit (&wps->wvbits) ? (low >> 1) | 0x80000000 : (low >> 1) & 0x7fffffff; + return low; +#endif + + if (!(wps->w.median [0] [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.median [0] [1] & ~1)) { + uint32_t mask; + int cbits; + + if (wps->w.zeros_acc) { + if (--wps->w.zeros_acc) + 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) { + CLEAR (wps->w.median); + return 0; + } + } + } + + if (wps->w.holding_zero) + ones_count = wps->w.holding_zero = 0; + else { + 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 += 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; + } + + 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 (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 (&wps->wvbits, high - low); + return (getbit (&wps->wvbits)) ? ~low : low; +} + +// 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 FASTCALL read_code (Bitstream *bs, uint32_t maxcode) +{ + int bitcount = count_bits (maxcode); + uint32_t extras = bitset [bitcount] - maxcode - 1, code; + + if (!bitcount) + return 0; + + getbits (&code, bitcount - 1, bs); + code &= bitmask [bitcount - 1]; + + if (code >= extras) { + code = (code << 1) - extras; + + if (getbit (bs)) + ++code; + } + + return code; +} + +#endif + +// 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. + +static int FASTCALL mylog2 (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. + +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; +} + +// 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 log2s (int32_t value) +{ + return (value < 0) ? -mylog2 (-value) : mylog2 (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 exp2s (int log) +{ + uint32_t value; + + if (log < 0) + return -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; +} diff --git a/Libraries/WavPack/Files/wputils.c b/Libraries/WavPack/Files/wputils.c index 3c2dbbad7..5886d8c34 100644 --- a/Libraries/WavPack/Files/wputils.c +++ b/Libraries/WavPack/Files/wputils.c @@ -1,2107 +1,2666 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// wputils.c - -// This module provides a high-level interface to reading and writing WavPack -// files. WavPack input files can be opened as standard "C" streams using a -// provided filename. However, an alternate entry uses stream-reading -// callbacks to make using another file I/O method easy. Note that in this -// case the user application is responsible for finding and opening the .wvc -// file if the use of them is desired. - -// For writing WavPack files there are no I/O routines used; a callback for -// writing completed blocks is provided. - -#include -#include -#include -#include -#include - -#ifdef WIN32 -#include -#endif - -#include "wavpack.h" - -#if !defined(WIN32) -#define stricmp(x,y) strcasecmp(x,y) -#endif - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -#endif - -static void free_streams (WavpackContext *wpc); - -///////////////////////////// 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 //////////////////////////////// - -#ifdef TAGS -static int load_tag (WavpackContext *wpc); -static int valid_tag (M_Tag *m_tag); -static void free_tag (M_Tag *m_tag); -#endif - -#if defined(UNPACK) || defined(INFO_ONLY) - -static uint32_t read_next_header (stream_reader *reader, void *id, WavpackHeader *wphdr); -static uint32_t seek_final_index (stream_reader *reader, void *id); - -// This code provides an interface between the reader callback mechanism that -// WavPack uses internally and the standard fstream C library. - -#ifdef USE_FSTREAMS - -static int32_t read_bytes (void *id, void *data, int32_t bcount) -{ - return fread (data, 1, bcount, (FILE*) id); -} - -static uint32_t get_pos (void *id) -{ - return ftell ((FILE*) id); -} - -static int set_pos_abs (void *id, uint32_t pos) -{ - return fseek (id, pos, SEEK_SET); -} - -static int set_pos_rel (void *id, int32_t delta, int mode) -{ - return fseek (id, delta, mode); -} - -static int push_back_byte (void *id, int c) -{ - return ungetc (c, id); -} - -static uint32_t get_length (void *id) -{ - FILE *file = id; - struct stat statbuf; - - if (!file || fstat (fileno (file), &statbuf) || !(statbuf.st_mode & S_IFREG)) - return 0; - - return statbuf.st_size; -} - -static int can_seek (void *id) -{ - FILE *file = id; - struct stat statbuf; - - return file && !fstat (fileno (file), &statbuf) && (statbuf.st_mode & S_IFREG); -} - -static stream_reader freader = { - read_bytes, get_pos, set_pos_abs, set_pos_rel, push_back_byte, get_length, can_seek -}; - -// 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" -// 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 - -// 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) -{ - FILE *wv_id, *wvc_id; - WavpackContext *wpc; - - if (*infilename == '-') { - wv_id = stdin; -#if defined(WIN32) - setmode (fileno (stdin), O_BINARY); -#endif - } - else if ((wv_id = fopen (infilename, "rb")) == NULL) { - strcpy (error, "can't open file"); - return NULL; - } - - if (wv_id != stdin && (flags & OPEN_WVC)) { - char *in2filename = malloc (strlen (infilename) + 10); - - strcpy (in2filename, infilename); - strcat (in2filename, "c"); - wvc_id = fopen (in2filename, "rb"); - } - else - wvc_id = NULL; - - wpc = WavpackOpenFileInputEx (&freader, wv_id, wvc_id, error, flags, norm_offset); - - if (!wpc) { - if (wv_id) - fclose (wv_id); - - if (wvc_id) - fclose (wvc_id); - } - else - wpc->close_files = TRUE; - - return wpc; -} - -#endif - -// This function is identical to WavpackOpenFileInput() except that instead -// of providing a filename to open, the caller provides a pointer to a set of -// reader callbacks and instances of up to two streams. The first of these -// streams is required and contains the regular WavPack data stream; the second -// contains the "correction" file if desired. Unlike the standard open -// function which handles the correction file transparently, in this case it -// is the responsibility of the caller to be aware of correction files. - -WavpackContext *WavpackOpenFileInputEx (stream_reader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset) -{ - WavpackContext *wpc = malloc (sizeof (WavpackContext)); - WavpackStream *wps; - uchar first_byte; - uint32_t bcount; - - if (!wpc) { - strcpy (error, "can't allocate memory"); - return NULL; - } - - CLEAR (*wpc); - wpc->wv_in = wv_id; - wpc->wvc_in = wvc_id; - wpc->reader = reader; - wpc->total_samples = (uint32_t) -1; - wpc->norm_offset = norm_offset; - wpc->open_flags = flags; - - wpc->filelen = wpc->reader->get_length (wpc->wv_in); - -#ifdef TAGS - if ((flags & OPEN_TAGS) && wpc->reader->can_seek (wpc->wv_in)) { - load_tag (wpc); - wpc->reader->set_pos_abs (wpc->wv_in, 0); - } -#endif - -#ifdef VER3 - if (wpc->reader->read_bytes (wpc->wv_in, &first_byte, 1) != 1) { - strcpy (error, "can't read all of WavPack file!"); - return WavpackCloseFile (wpc); - } - - wpc->reader->push_back_byte (wpc->wv_in, first_byte); - - if (first_byte == 'R') - return open_file3 (wpc, error); -#endif - - wpc->streams [0] = wps = malloc (sizeof (WavpackStream)); - wpc->num_streams = 1; - CLEAR (*wps); - - while (!wps->wphdr.block_samples) { - - wpc->filepos = wpc->reader->get_pos (wpc->wv_in); - bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); - - if (bcount == (uint32_t) -1) { - strcpy (error, "not compatible with this version of WavPack file!"); - return WavpackCloseFile (wpc); - } - - wpc->filepos += bcount; - wps->blockbuff = 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) { - strcpy (error, "can't read all of WavPack file!"); - return WavpackCloseFile (wpc); - } - - if ((wps->wphdr.flags & UNKNOWN_FLAGS) || wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { - strcpy (error, "not compatible with this version of WavPack file!"); - return WavpackCloseFile (wpc); - } - - if (wps->wphdr.block_samples && !(flags & OPEN_STREAMING)) { - if (wps->wphdr.total_samples == (uint32_t) -1 && wpc->reader->can_seek (wpc->wv_in)) { - uint32_t pos_save = wpc->reader->get_pos (wpc->wv_in); - uint32_t final_index = seek_final_index (wpc->reader, wpc->wv_in); - - if (final_index != (uint32_t) -1) - wpc->total_samples = final_index - wps->wphdr.block_index; - - wpc->reader->set_pos_abs (wpc->wv_in, pos_save); - } - else - wpc->total_samples = wps->wphdr.total_samples; - } - - if (wpc->wvc_in && wps->wphdr.block_samples && (wps->wphdr.flags & HYBRID_FLAG)) { - wpc->file2len = wpc->reader->get_length (wpc->wvc_in); - wpc->wvc_flag = TRUE; - } - - if (wpc->wvc_flag) { - wpc->file2pos = wpc->reader->get_pos (wpc->wvc_in); - bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); - - if (bcount == (uint32_t) -1) { - strcpy (error, "problem with correction file"); - return WavpackCloseFile (wpc); - } - - wpc->file2pos += bcount; - wps->block2buff = malloc (wps->wphdr.ckSize + 8); - memcpy (wps->block2buff, &wps->wphdr, 32); - - if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != - wps->wphdr.ckSize - 24) { - strcpy (error, "can't read all of WavPack file!"); - return WavpackCloseFile (wpc); - } - } - - if (!unpack_init (wpc)) { - strcpy (error, wpc->error_message [0] ? wpc->error_message : - "not compatible with this version of WavPack file!"); - - return WavpackCloseFile (wpc); - } - } - - wpc->config.flags &= ~0xff; - wpc->config.flags |= wps->wphdr.flags & 0xff; - wpc->config.bytes_per_sample = (wps->wphdr.flags & BYTES_STORED) + 1; - wpc->config.float_norm_exp = wps->float_norm_exp; - - wpc->config.bits_per_sample = (wpc->config.bytes_per_sample * 8) - - ((wps->wphdr.flags & SHIFT_MASK) >> SHIFT_LSB); - - if (!wpc->config.sample_rate) { - if (!wps || !wps->wphdr.block_samples || (wps->wphdr.flags & SRATE_MASK) == SRATE_MASK) - wpc->config.sample_rate = 44100; - else - wpc->config.sample_rate = sample_rates [(wps->wphdr.flags & SRATE_MASK) >> SRATE_LSB]; - } - - if (!wpc->config.num_channels) { - wpc->config.num_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; - wpc->config.channel_mask = 0x5 - wpc->config.num_channels; - } - - if ((flags & OPEN_2CH_MAX) && !(wps->wphdr.flags & FINAL_BLOCK)) - wpc->reduced_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; - - return wpc; -} - -// This function obtains general information about an open 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 conatins 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 - -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) - mode |= MODE_HIGH; - - if (wpc->config.flags & CONFIG_FAST_FLAG) - mode |= MODE_FAST; - - if (wpc->config.flags & CONFIG_EXTRA_MODE) - mode |= MODE_EXTRA; - - if (wpc->config.flags & CONFIG_CREATE_EXE) - mode |= MODE_SFX; - -#ifdef TAGS - if (valid_tag (&wpc->m_tag)) { - mode |= MODE_VALID_TAG; - - if (valid_tag (&wpc->m_tag) == 'A') - mode |= MODE_APETAG; - } -#endif - } - - return mode; -} - -// This function returns the major version number of the WavPack program -// (or library) that created the open file. Currently, this can be 1 to 4. -// Minor versions are not recorded in WavPack files. - -int WavpackGetVersion (WavpackContext *wpc) -{ - if (wpc) { -#ifdef VER3 - if (wpc->stream3) - return get_version3 (wpc); -#endif - return 4; - } - - return 0; -} - -#endif - -#ifdef UNPACK - -// 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. - -uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream = 0]; - uint32_t bcount, samples_unpacked = 0, samples_to_unpack; - int num_channels = wpc->config.num_channels; - -#ifdef VER3 - if (wpc->stream3) - return unpack_samples3 (wpc, buffer, samples); -#endif - - while (samples) { - if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || - wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) { - free_streams (wpc); - wpc->filepos = wpc->reader->get_pos (wpc->wv_in); - bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); - - if (bcount == (uint32_t) -1) - break; - - if (wpc->open_flags & OPEN_STREAMING) - wps->wphdr.block_index = wps->sample_index = 0; - - wpc->filepos += bcount; - wps->blockbuff = 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) { - strcpy (wpc->error_message, "can't read all of WavPack file!"); - break; - } - - if (wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { - strcpy (wpc->error_message, "not compatible with this version of WavPack file!"); - break; - } - - if (wps->wphdr.block_samples && wpc->wvc_flag) { - wpc->file2pos = wpc->reader->get_pos (wpc->wvc_in); - bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); - - if (bcount == (uint32_t) -1) - break; - - if (wpc->open_flags & OPEN_STREAMING) - wps->wphdr.block_index = wps->sample_index = 0; - - wpc->file2pos += bcount; - wps->block2buff = malloc (wps->wphdr.ckSize + 8); - memcpy (wps->block2buff, &wps->wphdr, 32); - - if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != - wps->wphdr.ckSize - 24) - break; - } - - if (!wps->wphdr.block_samples || wps->sample_index == wps->wphdr.block_index) - if (!unpack_init (wpc)) - break; - } - - if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || - wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) - continue; - - if (wps->sample_index < wps->wphdr.block_index) { - samples_to_unpack = wps->wphdr.block_index - wps->sample_index; - - if (samples_to_unpack > samples) - samples_to_unpack = samples; - - wps->sample_index += samples_to_unpack; - samples_unpacked += samples_to_unpack; - samples -= samples_to_unpack; - - if (wpc->reduced_channels) - samples_to_unpack *= wpc->reduced_channels; - else - samples_to_unpack *= num_channels; - - while (samples_to_unpack--) - *buffer++ = 0; - - continue; - } - - samples_to_unpack = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; - - if (samples_to_unpack > samples) - samples_to_unpack = samples; - - if (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) { - int32_t *temp_buffer = malloc (samples_to_unpack * 8), *src, *dst; - int offset = 0; - uint32_t samcnt; - - while (1) { - if (wpc->current_stream == wpc->num_streams) { - wps = wpc->streams [wpc->num_streams++] = malloc (sizeof (WavpackStream)); - CLEAR (*wps); - bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); - - if (bcount == (uint32_t) -1) - break; - - if (wpc->open_flags & OPEN_STREAMING) - wps->wphdr.block_index = wps->sample_index = 0; - - wps->blockbuff = 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) { - strcpy (wpc->error_message, "can't read all of WavPack file!"); - break; - } - - if (wpc->wvc_flag) { - bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); - - if (bcount == (uint32_t) -1) - break; - - if (wpc->open_flags & OPEN_STREAMING) - wps->wphdr.block_index = wps->sample_index = 0; - - wps->block2buff = malloc (wps->wphdr.ckSize + 8); - memcpy (wps->block2buff, &wps->wphdr, 32); - - if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != - wps->wphdr.ckSize - 24) - break; - } - - if (!unpack_init (wpc)) - break; - } - else - wps = wpc->streams [wpc->current_stream]; - - unpack_samples (wpc, src = temp_buffer, samples_to_unpack); - samcnt = samples_to_unpack; - dst = buffer + offset; - - if (wps->wphdr.flags & MONO_FLAG) { - while (samcnt--) { - dst [0] = *src++; - dst += num_channels; - } - - offset++; - } - else { - while (samcnt--) { - dst [0] = *src++; - dst [1] = *src++; - dst += num_channels; - } - - offset += 2; - } - - if (wps->wphdr.flags & FINAL_BLOCK) - break; - else - wpc->current_stream++; - } - - wps = wpc->streams [wpc->current_stream = 0]; - free (temp_buffer); - } - else - unpack_samples (wpc, buffer, samples_to_unpack); - - if (wpc->reduced_channels) - buffer += samples_to_unpack * wpc->reduced_channels; - else - buffer += samples_to_unpack * num_channels; - - samples_unpacked += samples_to_unpack; - samples -= samples_to_unpack; - - if (wps->sample_index == wps->wphdr.block_index + wps->wphdr.block_samples) { - if (check_crc_error (wpc) && wps->blockbuff) { - - if (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 (wps->sample_index == wpc->total_samples) - break; - } - - return samples_unpacked; -} - -#ifdef SEEKING - -static uint32_t find_sample (WavpackContext *wpc, void *infile, uint32_t header_pos, uint32_t sample); - -// Seek to the specifed 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. - -int WavpackSeekSample (WavpackContext *wpc, uint32_t sample) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream = 0]; - uint32_t bcount, samples_to_skip; - int32_t *buffer; - - if (wpc->total_samples == (uint32_t) -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 VER3 - if (wpc->stream3) - return seek_sample3 (wpc, sample); -#endif - - if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || sample < wps->wphdr.block_index || - sample >= wps->wphdr.block_index + wps->wphdr.block_samples) { - - free_streams (wpc); - wpc->filepos = find_sample (wpc, wpc->wv_in, wpc->filepos, sample); - - if (wpc->filepos == (uint32_t) -1) - return FALSE; - - if (wpc->wvc_flag) { - wpc->file2pos = find_sample (wpc, wpc->wvc_in, 0, sample); - - if (wpc->file2pos == (uint32_t) -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)); - little_endian_to_native (&wps->wphdr, WavpackHeaderFormat); - wps->blockbuff = 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; - } - - 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)); - little_endian_to_native (&wps->wphdr, WavpackHeaderFormat); - wps->block2buff = 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; - } - } - - if (!unpack_init (wpc)) { - free_streams (wpc); - return FALSE; - } - } - - while (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) { - if (++wpc->current_stream == wpc->num_streams) { - wps = wpc->streams [wpc->num_streams++] = malloc (sizeof (WavpackStream)); - CLEAR (*wps); - bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); - - if (bcount == (uint32_t) -1) - break; - - wps->blockbuff = 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) { - strcpy (wpc->error_message, "can't read all of WavPack file!"); - break; - } - - if (wpc->wvc_flag) { - bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); - - if (bcount == (uint32_t) -1) - break; - - wps->block2buff = malloc (wps->wphdr.ckSize + 8); - memcpy (wps->block2buff, &wps->wphdr, 32); - - if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != - wps->wphdr.ckSize - 24) - break; - } - - if (!unpack_init (wpc)) - break; - } - 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; - - samples_to_skip = sample - wps->sample_index; - - if (samples_to_skip) { - buffer = malloc (samples_to_skip * 8); - - for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++) - unpack_samples (wpc, buffer, samples_to_skip); - - free (buffer); - } - - wpc->current_stream = 0; - return TRUE; -} - -#endif - -#ifdef TAGS - -// Attempt to get the specified item from the specified 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. - -static void tagcpy (char *dest, char *src, int tag_size); - -int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size) -{ - M_Tag *m_tag = &wpc->m_tag; - char *lvalue = NULL; - - if (value) - *value = 0; - - if (m_tag->ape_tag_hdr.ID [0] == 'A') { - char *p = m_tag->ape_tag_data; - 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, flags, isize; - - vsize = * (int32_t *) p; p += 4; - flags = * (int32_t *) p; p += 4; - isize = strlen (p); - - little_endian_to_native (&vsize, "L"); - little_endian_to_native (&flags, "L"); - - if (p + isize + vsize + 1 > q) - break; - - if (isize && vsize && !stricmp (item, p) && !(flags & 6)) { - - if ((lvalue = malloc (vsize + 1)) != NULL) { - strncpy (lvalue, p + isize + 1, vsize); - lvalue [vsize] = 0; - } - - break; - } - else - p += isize + vsize + 1; - } - } - else if (m_tag->id3_tag.tag_id [0] == 'T') { - if ((lvalue = malloc (128)) == NULL) - return FALSE; - - 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.title)); - - if (!lvalue [0]) { - free (lvalue); - return FALSE; - } - } - else - return FALSE; - - if (lvalue) { - if (value && size >= 4) { - if (strlen (lvalue) >= size) { - lvalue [size - 4] = lvalue [size - 3] = lvalue [size - 2] = '.'; - lvalue [size - 1] = 0; - } - - strcpy (value, lvalue); - } - - free (lvalue); - return TRUE; - } - else - return FALSE; -} - -#endif - -#endif - -#ifdef PACK - -// Open context for writing WavPack files. The returned context pointer is used -// in all following calls to the library. The "blockout" function will be used -// to store the actual completed WavPack blocks and will be called with the id -// pointers containing user defined data (one for the wv file and one for the -// wvc file). A return value of NULL indicates that memory could not be -// allocated for the context. - -WavpackContext *WavpackOpenFileOutput (blockout blockout, void *wv_id, void *wvc_id) -{ - WavpackContext *wpc = malloc (sizeof (WavpackContext)); - - if (!wpc) - return NULL; - - CLEAR (*wpc); - wpc->blockout = blockout; - wpc->wv_out = wv_id; - wpc->wvc_out = wvc_id; - return wpc; -} - -// Set configuration for writing WavPack files. This must be done before -// sending any actual samples, however it is okay to send wrapper or other -// metadata before calling this. The "config" structure contains the following -// required information: - -// config->bytes_per_sample see WavpackGetBytesPerSample() for info -// config->bits_per_sample see WavpackGetBitsPerSample() for info -// config->channel_mask Microsoft standard (mono = 4, stereo = 3) -// config->num_channels self evident -// config->sample_rate self evident - -// In addition, the following fields and flags may be set: - -// config->flags: -// -------------- -// o CONFIG_HYBRID_FLAG select hybrid mode (must set bitrate) -// o CONFIG_JOINT_STEREO select joint stereo (must set override also) -// o CONFIG_JOINT_OVERRIDE override default joint stereo selection -// o CONFIG_HYBRID_SHAPE select hybrid noise shaping (set override & -// shaping_weight != 0.0) -// o CONFIG_SHAPE_OVERRIDE override default hybrid noise shaping -// (set CONFIG_HYBRID_SHAPE and shaping_weight) -// o CONFIG_FAST_FLAG "fast" compression mode -// o CONFIG_HIGH_FLAG "high" compression mode -// o CONFIG_BITRATE_KBPS hybrid bitrate is kbps, not bits / sample -// o CONFIG_CREATE_WVC create correction file -// o CONFIG_OPTIMIZE_WVC maximize bybrid compression (-cc option) -// o CONFIG_CALC_NOISE calc noise in hybrid mode -// o CONFIG_EXTRA_MODE extra processing mode (slow!) -// o CONFIG_SKIP_WVX no wvx stream for floats & large ints - -// config->bitrate hybrid bitrate in either bits/sample or kbps -// config->shaping_weight hybrid noise shaping coefficient override -// config->block_samples force samples per WavPack block (0 = use deflt) -// config->float_norm_exp select floating-point data (127 for +/-1.0) -// config->xmode extra mode processing value override - -// If the number of samples to be written is known then it should be passed -// here. If the duration is not known then pass -1. In the case that the size -// is not known (or the writing is terminated early) then it is suggested that -// the application retrieve the first block written and let the library update -// the total samples indication. A function is provided to do this update and -// it should be done to the "correction" file also. If this cannot be done -// (because a pipe is being used, for instance) then a valid WavPack will still -// be created, but when applications want to access that file they will have -// to seek all the way to the end to determine the actual duration. Also, if -// a RIFF header has been included then it should be updated as well or the -// WavPack file will not be directly unpackable to a valid wav file (although -// it will still be usable by itself). A return of FALSE indicates an error. - -static const uint32_t xtable [] = { 123, 3, 27, 59, 123, 187, 251 }; -static const uint32_t f_xtable [] = { 251, 3, 27, 59, 123, 187, 251 }; -static const uint32_t h_xtable [] = { 91, 3, 27, 91, 123, 187, 251 }; - -int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples) -{ - uint32_t flags = (config->bytes_per_sample - 1), bps = 0, shift = 0; - uint32_t chan_mask = config->channel_mask; - int num_chans = config->num_channels; - int i; - - wpc->total_samples = total_samples; - wpc->config.sample_rate = config->sample_rate; - wpc->config.num_channels = config->num_channels; - wpc->config.channel_mask = config->channel_mask; - wpc->config.bits_per_sample = config->bits_per_sample; - wpc->config.bytes_per_sample = config->bytes_per_sample; - wpc->config.block_samples = config->block_samples; - wpc->config.flags = config->flags; - - if (config->float_norm_exp) { - wpc->config.float_norm_exp = config->float_norm_exp; - flags |= FLOAT_DATA; - } - else - shift = (config->bytes_per_sample * 8) - config->bits_per_sample; - - for (i = 0; i < 15; ++i) - if (wpc->config.sample_rate == sample_rates [i]) - break; - - flags |= i << SRATE_LSB; - flags |= shift << SHIFT_LSB; - - if (config->flags & CONFIG_HYBRID_FLAG) { - flags |= HYBRID_FLAG | HYBRID_BITRATE | HYBRID_BALANCE; - - if (!(wpc->config.flags & CONFIG_SHAPE_OVERRIDE)) { - wpc->config.flags |= CONFIG_HYBRID_SHAPE | CONFIG_AUTO_SHAPING; - flags |= HYBRID_SHAPE | NEW_SHAPING; - } - else if (wpc->config.flags & CONFIG_HYBRID_SHAPE) { - wpc->config.shaping_weight = config->shaping_weight; - flags |= HYBRID_SHAPE | NEW_SHAPING; - } - - if (wpc->config.flags & CONFIG_OPTIMIZE_WVC) - flags |= CROSS_DECORR; - - if (config->flags & CONFIG_BITRATE_KBPS) { - bps = floor (config->bitrate * 256000.0 / config->sample_rate / config->num_channels + 0.5); - - if (bps > (64 << 8)) - bps = 64 << 8; - } - else - bps = floor (config->bitrate * 256.0 + 0.5); - } - else - flags |= CROSS_DECORR; - - if (!(config->flags & CONFIG_JOINT_OVERRIDE) || (config->flags & CONFIG_JOINT_STEREO)) - flags |= JOINT_STEREO; - - if (config->flags & CONFIG_CREATE_WVC) - wpc->wvc_flag = TRUE; - - for (wpc->current_stream = 0; num_chans; wpc->current_stream++) { - WavpackStream *wps = malloc (sizeof (WavpackStream)); - uint32_t stereo_mask, mono_mask; - int pos, chans; - - wpc->streams [wpc->current_stream] = wps; - CLEAR (*wps); - - for (pos = 1; pos <= 18; ++pos) { - stereo_mask = 3 << (pos - 1); - mono_mask = 1 << (pos - 1); - - if ((chan_mask & stereo_mask) == stereo_mask && (mono_mask & 0x251)) { - chan_mask &= ~stereo_mask; - chans = 2; - break; - } - else if (chan_mask & mono_mask) { - chan_mask &= ~mono_mask; - chans = 1; - break; - } - } - - if (pos == 19) - chans = num_chans > 1 ? 2 : 1; - - num_chans -= chans; - - if (num_chans && wpc->current_stream == MAX_STREAMS - 1) - break; - - memcpy (wps->wphdr.ckID, "wvpk", 4); - wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; - wps->wphdr.total_samples = wpc->total_samples; - wps->wphdr.version = 0x403; - wps->wphdr.flags = flags; - wps->bits = bps; - - if (!wpc->current_stream) - wps->wphdr.flags |= INITIAL_BLOCK; - - if (!num_chans) - wps->wphdr.flags |= FINAL_BLOCK; - - if (chans == 1) { - wps->wphdr.flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE); - wps->wphdr.flags |= MONO_FLAG; - } - } - - wpc->num_streams = wpc->current_stream; - wpc->current_stream = 0; - - if (num_chans) { - strcpy (wpc->error_message, "too many channels!"); - return FALSE; - } - - if (config->flags & CONFIG_EXTRA_MODE) { - - if (config->flags & CONFIG_HIGH_FLAG) - wpc->config.extra_flags = h_xtable [config->xmode]; - else if (config->flags & CONFIG_FAST_FLAG) - wpc->config.extra_flags = f_xtable [config->xmode]; - else - wpc->config.extra_flags = xtable [config->xmode]; - - if (config->flags & CONFIG_JOINT_OVERRIDE) - wpc->config.extra_flags &= ~EXTRA_STEREO_MODES; - } - - return TRUE; -} - -// Prepare to actually pack samples by determining the size of the WavPack -// blocks and allocating sample buffers and initializing each stream. Call -// after WavpackSetConfiguration() and before WavpackPackSamples(). A return -// of FALSE indicates an error. - -int WavpackPackInit (WavpackContext *wpc) -{ - if (wpc->metabytes > 4096) - write_metadata_block (wpc); - - if (wpc->config.block_samples) - wpc->block_samples = wpc->config.block_samples; - else { - if (wpc->config.flags & CONFIG_HIGH_FLAG) - wpc->block_samples = wpc->config.sample_rate; -// else if ((wpc->config.flags & CONFIG_FAST_FLAG) && !(wpc->config.sample_rate % 4)) -// wpc->block_samples = wpc->config.sample_rate / 4; - else if (!(wpc->config.sample_rate % 2)) - wpc->block_samples = wpc->config.sample_rate / 2; - else - wpc->block_samples = wpc->config.sample_rate; - - while (wpc->block_samples * wpc->config.num_channels > 100000) - wpc->block_samples /= 2; - - while (wpc->block_samples * wpc->config.num_channels < 40000) - wpc->block_samples *= 2; - } - - wpc->max_samples = wpc->block_samples + (wpc->block_samples >> 1); - - for (wpc->current_stream = 0; wpc->streams [wpc->current_stream]; wpc->current_stream++) { - WavpackStream *wps = wpc->streams [wpc->current_stream]; - - wps->sample_buffer = malloc (wpc->max_samples * (wps->wphdr.flags & MONO_FLAG ? 4 : 8)); - pack_init (wpc); - } - - return TRUE; -} - -// Pack the specified samples. Samples must be stored in longs in the native -// endian format of the executing processor. The number of samples specified -// indicates composite samples (sometimes called "frames"). So, the actual -// number of data points would be this "sample_count" times the number of -// channels. Note that samples are accumulated here until enough exist to -// create a complete WavPack block (or several blocks for multichannel audio). -// If an application wants to break a block at a specific sample, then it must -// simply call WavpackFlushSamples() to force an early termination. Completed -// WavPack blocks are send to the function provided in the initial call to -// WavpackOpenFileOutput(). A return of FALSE indicates an error. - -static int pack_streams (WavpackContext *wpc, uint32_t block_samples); - -int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count) -{ - int nch = wpc->config.num_channels; - - while (sample_count) { - int32_t *source_pointer = sample_buffer; - uint samples_to_copy; - - if (wpc->acc_samples + sample_count > wpc->max_samples) - samples_to_copy = wpc->max_samples - wpc->acc_samples; - else - samples_to_copy = sample_count; - - for (wpc->current_stream = 0; wpc->streams [wpc->current_stream]; wpc->current_stream++) { - WavpackStream *wps = wpc->streams [wpc->current_stream]; - int32_t *dptr, *sptr, cnt; - - dptr = wps->sample_buffer + wpc->acc_samples * (wps->wphdr.flags & MONO_FLAG ? 1 : 2); - sptr = source_pointer; - cnt = samples_to_copy; - - if (wps->wphdr.flags & MONO_FLAG) { - while (cnt--) { - *dptr++ = *sptr; - sptr += nch; - } - - source_pointer++; - } - else { - while (cnt--) { - *dptr++ = sptr [0]; - *dptr++ = sptr [1]; - sptr += nch; - } - - source_pointer += 2; - } - } - - sample_buffer += samples_to_copy * nch; - sample_count -= samples_to_copy; - - if ((wpc->acc_samples += samples_to_copy) == wpc->max_samples && - !pack_streams (wpc, wpc->block_samples)) - return FALSE; - } - - return TRUE; -} - -// Flush all accumulated samples into WavPack blocks. This is normally called -// after all samples have been sent to WavpackPackSamples(), but can also be -// called to terminate a WavPack block at a specific sample (in other words it -// is possible to continue after this operation). This is also called to -// dump non-audio blocks like those holding metadata for various purposes. -// A return of FALSE indicates an error. - -int WavpackFlushSamples (WavpackContext *wpc) -{ - while (wpc->acc_samples) { - uint32_t block_samples; - - if (wpc->acc_samples > wpc->block_samples) - block_samples = wpc->acc_samples / 2; - else - block_samples = wpc->acc_samples; - - if (!pack_streams (wpc, block_samples)) - return FALSE; - } - - if (wpc->metacount) - write_metadata_block (wpc); - - return TRUE; -} - -// Add wrapper (currently RIFF only) to WavPack blocks. This should be called -// before sending any audio samples for the RIFF header or after all samples -// have been sent for any RIFF trailer. WavpackFlushSamples() should be called -// between sending the last samples and calling this for trailer data to make -// sure that headers and trailers don't get mixed up in very short files. If -// the exact contents of the RIFF header are not known because, for example, -// the file duration is uncertain or trailing chunks are possible, simply write -// a "dummy" header of the correct length. When all data has been written it -// will be possible to read the first block written and update the header -// directly. An example of this can be found in the Audition filter. A -// return of FALSE indicates an error. - -int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount) -{ - uint32_t index = WavpackGetSampleIndex (wpc); - - return add_to_metadata (wpc, data, bcount, - (uchar)((!index || index == (uint32_t) -1) ? ID_RIFF_HEADER : ID_RIFF_TRAILER)); -} - -// Store computed MD5 sum in WavPack metadata. Note that the user must compute -// the 16 byte sum; it is not done here. A return of FALSE indicates an error. - -int WavpackStoreMD5Sum (WavpackContext *wpc, uchar data [16]) -{ - return add_to_metadata (wpc, data, 16, ID_MD5_CHECKSUM); -} - -static int pack_streams (WavpackContext *wpc, uint32_t block_samples) -{ - uint32_t max_blocksize = block_samples * 10 + 4096, bcount; - uchar *outbuff, *outend, *out2buff, *out2end; - int result; - - out2buff = (wpc->wvc_flag) ? malloc (max_blocksize) : NULL; - out2end = out2buff + max_blocksize; - outbuff = malloc (max_blocksize); - outend = outbuff + max_blocksize; - - for (wpc->current_stream = 0; wpc->streams [wpc->current_stream]; wpc->current_stream++) { - WavpackStream *wps = wpc->streams [wpc->current_stream]; - uint32_t flags = wps->wphdr.flags; - - flags &= ~MAG_MASK; - flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7); - - wps->wphdr.block_index = wps->sample_index; - wps->wphdr.block_samples = block_samples; - wps->wphdr.flags = flags; - wps->block2buff = out2buff; - wps->block2end = out2end; - wps->blockbuff = outbuff; - wps->blockend = outend; - - result = pack_block (wpc, wps->sample_buffer); - wps->blockbuff = wps->block2buff = NULL; - - if (!result) { - strcpy (wpc->error_message, "output buffer overflowed!"); - break; - } - - bcount = ((WavpackHeader *) outbuff)->ckSize + 8; - native_to_little_endian ((WavpackHeader *) outbuff, WavpackHeaderFormat); - result = wpc->blockout (wpc->wv_out, outbuff, bcount); - - if (!result) { - strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); - break; - } - - wpc->filelen += bcount; - - if (out2buff) { - bcount = ((WavpackHeader *) out2buff)->ckSize + 8; - native_to_little_endian ((WavpackHeader *) out2buff, WavpackHeaderFormat); - result = wpc->blockout (wpc->wvc_out, out2buff, bcount); - - if (!result) { - strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); - break; - } - - wpc->file2len += bcount; - } - - if (wpc->acc_samples != block_samples) - memcpy (wps->sample_buffer, wps->sample_buffer + block_samples * (flags & MONO_FLAG ? 1 : 2), - (wpc->acc_samples - block_samples) * sizeof (int32_t) * (flags & MONO_FLAG ? 1 : 2)); - } - - wpc->current_stream = 0; - wpc->acc_samples -= block_samples; - free (outbuff); - - if (out2buff) - free (out2buff); - - return result; -} - -// Given the pointer to the first block written (to either a .wv or .wvc file), -// update the block with the actual number of samples written. This should -// be done if WavpackSetConfiguration() was called with an incorrect number -// of samples (or -1). It is the responsibility of the application to read and -// rewrite the block. An example of this can be found in the Audition filter. - -void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block) -{ - little_endian_to_native (wpc, WavpackHeaderFormat); - ((WavpackHeader *) first_block)->total_samples = WavpackGetSampleIndex (wpc); - native_to_little_endian (wpc, WavpackHeaderFormat); -} - -// Given the pointer to the first block written to a WavPack file, this -// function returns the location of the stored RIFF header that was originally -// written with WavpackAddWrapper(). This would normally be used to update -// the wav header to indicate that a different number of samples was actually -// written or if additional RIFF chunks are written at the end of the file. -// It is the responsibility of the application to read and rewrite the block. -// An example of this can be found in the Audition filter. - -void *WavpackGetWrapperLocation (void *first_block) -{ - if (((uchar *) first_block) [32] == ID_RIFF_HEADER) - return ((uchar *) first_block) + 34; - else - return NULL; -} - -#ifdef TAGS - -// Limited functionality to append APEv2 tags to WavPack files when they are -// created has been added for version 4.2. This function is used to append the -// specified field to the tag being created. 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. Note that ID3 tags are not -// supported and that no editing of existing tags is allowed (there are several -// fine libraries available for this). - -int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value) -{ - M_Tag *m_tag = &wpc->m_tag; - int vsize = strlen (value); - int isize = strlen (item); - - if (!m_tag->ape_tag_hdr.ID [0]) { - strncpy (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 = 0x80000000; - } - - if (m_tag->ape_tag_hdr.ID [0] == 'A') { - int new_item_len = vsize + isize + 9, flags = 0; - char *p; - - m_tag->ape_tag_hdr.item_count++; - m_tag->ape_tag_hdr.length += new_item_len; - p = m_tag->ape_tag_data = 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; - native_to_little_endian (&vsize, "L"); - native_to_little_endian (&flags, "L"); - * (int32_t *) p = vsize; p += 4; - * (int32_t *) p = flags; p += 4; - little_endian_to_native (&vsize, "L"); - little_endian_to_native (&flags, "L"); - strcpy (p, item); - p += isize + 1; - memcpy (p, value, vsize); - - return TRUE; - } - else - return FALSE; -} - -// 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. - -int WavpackWriteTag (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.flags |= 0x20000000; - native_to_little_endian (&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)); - little_endian_to_native (&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 &= ~0x20000000; - native_to_little_endian (&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)); - little_endian_to_native (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); - } - else if (m_tag->id3_tag.tag_id [0] == 'T') - result = wpc->blockout (wpc->wv_out, &m_tag->id3_tag, sizeof (m_tag->id3_tag)); - - if (!result) - strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); - - return result; -} - -#endif - -#endif - -// Get total number of samples contained in the WavPack file, or -1 if unknown - -uint32_t WavpackGetNumSamples (WavpackContext *wpc) -{ - return wpc ? wpc->total_samples : (uint32_t) -1; -} - -// Get the current sample index position, or -1 if unknown - -uint32_t WavpackGetSampleIndex (WavpackContext *wpc) -{ - if (wpc) { -#ifdef VER3 - if (wpc->stream3) - return get_sample_index3 (wpc); - else if (wpc->streams [0]) - return wpc->streams [0]->sample_index; -#else - if (wpc->streams [0]) - return wpc->streams [0]->sample_index; -#endif - } - - return (uint32_t) -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 != (uint32_t) -1 && wpc->total_samples != 0) - return (double) WavpackGetSampleIndex (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 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 != (uint32_t) -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 != (uint32_t) -1 && wpc->filelen) { - double output_time = (double) wpc->total_samples / wpc->config.sample_rate; - double input_size = (double) wpc->filelen + (count_wvc ? wpc->file2len : 0); - - if (output_time >= 1.0 && input_size >= 1.0) - return input_size * 8.0 / output_time; - } - - return 0.0; -} - -#ifdef UNPACK - -// 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->stream3) - return WavpackGetAverageBitrate (wpc, TRUE); - - if (wpc && wpc->streams [0] && wpc->streams [0]->wphdr.block_samples) { - double output_time = (double) wpc->streams [0]->wphdr.block_samples / wpc->config.sample_rate; - 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; -} - -#endif - -// Close the specified WavPack file and release all resources used by it. -// Returns NULL. - -WavpackContext *WavpackCloseFile (WavpackContext *wpc) -{ - free_streams (wpc); - - if (wpc->streams [0]) - free (wpc->streams [0]); - -#ifdef VER3 - if (wpc->stream3) - free_stream3 (wpc); -#endif - -#if defined(UNPACK) || defined(INFO_ONLY) - if (wpc->close_files) { -#ifdef USE_FSTREAMS - if (wpc->wv_in != NULL) - fclose (wpc->wv_in); - - if (wpc->wvc_in != NULL) - fclose (wpc->wvc_in); -#endif - } - - WavpackFreeWrapper (wpc); -#endif - -#ifdef TAGS - free_tag (&wpc->m_tag); -#endif - - free (wpc); - - return NULL; -} - -// Returns the sample rate of the specified WavPack file - -uint32_t WavpackGetSampleRate (WavpackContext *wpc) -{ - return wpc ? 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; -} - -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 defined(UNPACK) || defined(INFO_ONLY) - -// 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; -} - -// 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; -} - -uchar *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; - } -} - -// Get any MD5 checksum stored in the metadata (should be called after reading -// last sample or an extra seek will occur). A return value of FALSE indicates -// that no MD5 checksum was stored. - -static int seek_md5 (stream_reader *reader, void *id, uchar data [16]); - -int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]) -{ - if (wpc->config.flags & CONFIG_MD5_CHECKSUM) { - if (wpc->config.md5_read) { - memcpy (data, wpc->config.md5_checksum, 16); - return TRUE; - } - else if (wpc->reader->can_seek (wpc->wv_in)) { - uint32_t pos_save = wpc->reader->get_pos (wpc->wv_in); - - wpc->config.md5_read = seek_md5 (wpc->reader, wpc->wv_in, wpc->config.md5_checksum); - wpc->reader->set_pos_abs (wpc->wv_in, pos_save); - - if (wpc->config.md5_read) { - memcpy (data, wpc->config.md5_checksum, 16); - return TRUE; - } - else - return FALSE; - } - } - - return FALSE; -} - -#endif - -// Free all memory allocated for raw WavPack blocks (for all allocated streams) -// and free all additonal streams. This does not free the default stream ([0]) -// which is always kept around. - -static 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 (si) { - wpc->num_streams--; - free (wpc->streams [si]); - wpc->streams [si] = NULL; - } - } - - wpc->current_stream = 0; -} - -#ifdef TAGS - -// Return TRUE is a valid ID3v1 or APEv2 tag has been loaded. - -static 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; -} - -// Free the data for any APEv2 tag that was allocated. - -static void free_tag (M_Tag *m_tag) -{ - if (m_tag->ape_tag_data) { - free (m_tag->ape_tag_data); - m_tag->ape_tag_data = 0; - } -} - -#endif - -#if defined(UNPACK) || defined(INFO_ONLY) - -// Read from current file position until a valid 32-byte WavPack 4.0 header is -// found and read into the specified pointer. The number of bytes skipped is -// returned. If no WavPack header is found within 1 meg, then a -1 is returned -// to indicate the error. No additional bytes are read past the header and it -// is returned in the processor's native endian mode. Seeking is not required. - -static uint32_t read_next_header (stream_reader *reader, void *id, WavpackHeader *wphdr) -{ - char buffer [sizeof (*wphdr)], *sp = buffer + sizeof (*wphdr), *ep = sp; - uint32_t bytes_skipped = 0; - int bleft; - - while (1) { - if (sp < ep) { - bleft = ep - sp; - memcpy (buffer, sp, bleft); - } - else - bleft = 0; - - if (reader->read_bytes (id, buffer + bleft, sizeof (*wphdr) - bleft) != sizeof (*wphdr) - bleft) - return -1; - - sp = buffer; - - if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' && - !(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 && sp [4] >= 2 && sp [4] <= 0xf) { - memcpy (wphdr, buffer, sizeof (*wphdr)); - little_endian_to_native (wphdr, WavpackHeaderFormat); - return bytes_skipped; - } - - while (sp < ep && *sp != 'w') - sp++; - - if ((bytes_skipped += sp - buffer) > 1024 * 1024) - return -1; - } -} - -// This function is used to seek to end of a file to determine its actual -// length in samples by reading the last header block containing data. -// Currently, all WavPack files contain the sample length in the first block -// containing samples, however this might not always be the case. Obviously, -// this function requires a seekable file or stream and leaves the file -// pointer undefined. A return value of -1 indicates the length could not -// be determined. - -static uint32_t seek_final_index (stream_reader *reader, void *id) -{ - uint32_t result = (uint32_t) -1, bcount; - WavpackHeader wphdr; - - if (reader->get_length (id) > 1200000L) - reader->set_pos_rel (id, -1048576L, SEEK_END); - - while (1) { - bcount = read_next_header (reader, id, &wphdr); - - if (bcount == (uint32_t) -1) - return result; - - if (wphdr.block_samples && (wphdr.flags & FINAL_BLOCK)) - result = wphdr.block_index + wphdr.block_samples; - - if (wphdr.ckSize > sizeof (WavpackHeader) - 8) - reader->set_pos_rel (id, wphdr.ckSize - sizeof (WavpackHeader) + 8, SEEK_CUR); - } -} - -static int seek_md5 (stream_reader *reader, void *id, uchar data [16]) -{ - uchar meta_id, c1, c2; - uint32_t bcount, meta_bc; - WavpackHeader wphdr; - - if (reader->get_length (id) > 1200000L) - reader->set_pos_rel (id, -1048576L, SEEK_END); - - while (1) { - bcount = read_next_header (reader, id, &wphdr); - - if (bcount == (uint32_t) -1) - return FALSE; - - bcount = wphdr.ckSize - sizeof (WavpackHeader) + 8; - - while (bcount >= 2) { - if (reader->read_bytes (id, &meta_id, 1) != 1 || - reader->read_bytes (id, &c1, 1) != 1) - return FALSE; - - meta_bc = c1 << 1; - bcount -= 2; - - if (meta_id & ID_LARGE) { - if (bcount < 2 || reader->read_bytes (id, &c1, 1) != 1 || - reader->read_bytes (id, &c2, 1) != 1) - return FALSE; - - meta_bc += ((uint32_t) c1 << 9) + ((uint32_t) c2 << 17); - bcount -= 2; - } - - if (meta_id == ID_MD5_CHECKSUM) - return (meta_bc == 16 && bcount >= 16 && - reader->read_bytes (id, data, 16) == 16); - - reader->set_pos_rel (id, meta_bc, SEEK_CUR); - bcount -= meta_bc; - } - } -} - -#ifdef SEEKING - -// 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 uint32_t find_header (stream_reader *reader, void *id, uint32_t filepos, WavpackHeader *wphdr) -{ - char *buffer = 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 = ep - sp; - memcpy (buffer, sp, bleft); - ep -= (sp - buffer); - sp = buffer; - } - else { - if (sp > ep) - if (reader->set_pos_rel (id, 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 [5] == 4 && sp [4] >= 2 && sp [4] <= 0xf) { - memcpy (wphdr, sp - 4, sizeof (*wphdr)); - little_endian_to_native (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 uint32_t find_sample (WavpackContext *wpc, void *infile, uint32_t header_pos, uint32_t sample) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - uint32_t file_pos1 = 0, file_pos2 = wpc->reader->get_length (infile); - uint32_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) { - if (wps->wphdr.block_index > sample) { - sample_pos2 = wps->wphdr.block_index; - file_pos2 = header_pos; - } - else if (wps->wphdr.block_index + wps->wphdr.block_samples <= sample) { - sample_pos1 = wps->wphdr.block_index; - file_pos1 = header_pos; - } - else - return header_pos; - } - - while (1) { - double bytes_per_sample; - uint32_t seek_pos; - - bytes_per_sample = file_pos2 - file_pos1; - bytes_per_sample /= sample_pos2 - sample_pos1; - seek_pos = file_pos1 + (file_skip ? 32 : 0); - seek_pos += (uint32_t)(bytes_per_sample * (sample - sample_pos1) * ratio); - seek_pos = find_header (wpc->reader, infile, seek_pos, &wps->wphdr); - - if (seek_pos == (uint32_t) -1 || seek_pos >= file_pos2) { - if (ratio > 0.0) { - if ((ratio -= 0.24) < 0.0) - ratio = 0.0; - } - else - return -1; - } - else if (wps->wphdr.block_index > sample) { - sample_pos2 = wps->wphdr.block_index; - file_pos2 = seek_pos; - } - else if (wps->wphdr.block_index + wps->wphdr.block_samples <= sample) { - - if (seek_pos == file_pos1) - file_skip = 1; - else { - sample_pos1 = wps->wphdr.block_index; - file_pos1 = seek_pos; - } - } - else - return seek_pos; - } -} - -#endif - -#ifdef TAGS - -// 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 accomodate 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. - -static int load_tag (WavpackContext *wpc) -{ - M_Tag *m_tag = &wpc->m_tag; - - CLEAR (*m_tag); - - // First, attempt to find an APEv2 tag... - - wpc->reader->set_pos_rel (wpc->wv_in, -sizeof (APE_Tag_Hdr), SEEK_END); - - 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)) { - - little_endian_to_native (&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 < (1024 * 1024) && - (m_tag->ape_tag_data = malloc (m_tag->ape_tag_hdr.length)) != NULL) { - - memset (m_tag->ape_tag_data, 0, m_tag->ape_tag_hdr.length); - wpc->reader->set_pos_rel (wpc->wv_in, -m_tag->ape_tag_hdr.length, SEEK_END); - - if (wpc->reader->read_bytes (wpc->wv_in, m_tag->ape_tag_data, m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr)) != - m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr)) { - free (m_tag->ape_tag_data); - CLEAR (*m_tag); - return FALSE; - } - else - return TRUE; - } - } - - // ...if not, try a ID3v1 tag - - wpc->reader->set_pos_rel (wpc->wv_in, -sizeof (ID3_Tag), 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)) - return TRUE; - else { - CLEAR (*m_tag); - return FALSE; - } -} - -// 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; - - while (s1 <= s2) - if (*s1 == ' ') - ++s1; - else if (!*s2 || *s2 == ' ') - --s2; - else - break; - - while (*s1 && s1 <= s2) - *dest++ = *s1++; - - *dest = 0; -} - -#endif - -#endif +/////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wputils.c + +// This module provides a high-level interface to reading and writing WavPack +// files. WavPack input files can be opened as standard "C" streams using a +// provided filename. However, an alternate entry uses stream-reading +// callbacks to make using another file I/O method easy. Note that in this +// case the user application is responsible for finding and opening the .wvc +// file if the use of them is desired. + +// For writing WavPack files there are no I/O routines used; a callback for +// writing completed blocks is provided. + +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#endif + +#include "wavpack.h" + +#if !defined(WIN32) +#define stricmp(x,y) strcasecmp(x,y) +#endif + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +#endif + +static void free_streams (WavpackContext *wpc); + +///////////////////////////// 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 //////////////////////////////// + +#ifdef TAGS +static int load_tag (WavpackContext *wpc); +static int valid_tag (M_Tag *m_tag); +static void free_tag (M_Tag *m_tag); +#endif + +#if defined(UNPACK) || defined(INFO_ONLY) + +static uint32_t read_next_header (WavpackStreamReader *reader, void *id, WavpackHeader *wphdr); +static uint32_t seek_final_index (WavpackStreamReader *reader, void *id); + +// This code provides an interface between the reader callback mechanism that +// WavPack uses internally and the standard fstream C library. + +#ifdef USE_FSTREAMS + +static int32_t read_bytes (void *id, void *data, int32_t bcount) +{ + return fread (data, 1, bcount, (FILE*) id); +} + +static uint32_t get_pos (void *id) +{ + return ftell ((FILE*) id); +} + +static int set_pos_abs (void *id, uint32_t pos) +{ + return fseek (id, pos, SEEK_SET); +} + +static int set_pos_rel (void *id, int32_t delta, int mode) +{ + return fseek (id, delta, mode); +} + +static int push_back_byte (void *id, int c) +{ + return ungetc (c, id); +} + +static uint32_t get_length (void *id) +{ + FILE *file = id; + struct stat statbuf; + + if (!file || fstat (fileno (file), &statbuf) || !(statbuf.st_mode & S_IFREG)) + return 0; + + return statbuf.st_size; +} + +static int can_seek (void *id) +{ + FILE *file = id; + struct stat statbuf; + + return file && !fstat (fileno (file), &statbuf) && (statbuf.st_mode & S_IFREG); +} + +static int32_t write_bytes (void *id, void *data, int32_t bcount) +{ + return fwrite (data, 1, bcount, (FILE*) id); +} + +static WavpackStreamReader freader = { + read_bytes, get_pos, set_pos_abs, set_pos_rel, push_back_byte, get_length, can_seek, + write_bytes +}; + +// 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) + +// 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 *wv_id, *wvc_id; + WavpackContext *wpc; + + if (*infilename == '-') { + wv_id = stdin; +#if defined(WIN32) + setmode (fileno (stdin), O_BINARY); +#endif + } + else if ((wv_id = fopen (infilename, file_mode)) == NULL) { + strcpy (error, (flags & OPEN_EDIT_TAGS) ? "can't open file for editing" : "can't open file"); + return NULL; + } + + if (wv_id != stdin && (flags & OPEN_WVC)) { + char *in2filename = malloc (strlen (infilename) + 10); + + strcpy (in2filename, infilename); + strcat (in2filename, "c"); + wvc_id = fopen (in2filename, "rb"); + free (in2filename); + } + else + wvc_id = NULL; + + wpc = WavpackOpenFileInputEx (&freader, wv_id, wvc_id, error, flags, norm_offset); + + if (!wpc) { + if (wv_id) + fclose (wv_id); + + if (wvc_id) + fclose (wvc_id); + } + else + wpc->close_files = TRUE; + + return wpc; +} + +#endif + +// This function is identical to WavpackOpenFileInput() except that instead +// of providing a filename to open, the caller provides a pointer to a set of +// reader callbacks and instances of up to two streams. The first of these +// streams is required and contains the regular WavPack data stream; the second +// contains the "correction" file if desired. Unlike the standard open +// function which handles the correction file transparently, in this case it +// is the responsibility of the caller to be aware of correction files. + +WavpackContext *WavpackOpenFileInputEx (WavpackStreamReader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset) +{ + WavpackContext *wpc = malloc (sizeof (WavpackContext)); + WavpackStream *wps; + uchar first_byte; + uint32_t bcount; + + if (!wpc) { + strcpy (error, "can't allocate memory"); + return NULL; + } + + CLEAR (*wpc); + wpc->wv_in = wv_id; + wpc->wvc_in = wvc_id; + wpc->reader = reader; + wpc->total_samples = (uint32_t) -1; + wpc->norm_offset = norm_offset; + wpc->open_flags = flags; + + wpc->filelen = wpc->reader->get_length (wpc->wv_in); + +#ifdef TAGS + if ((flags & (OPEN_TAGS | OPEN_EDIT_TAGS)) && wpc->reader->can_seek (wpc->wv_in)) { + load_tag (wpc); + wpc->reader->set_pos_abs (wpc->wv_in, 0); + } +#endif + +#ifdef VER3 + if (wpc->reader->read_bytes (wpc->wv_in, &first_byte, 1) != 1) { + strcpy (error, "can't read all of WavPack file!"); + return WavpackCloseFile (wpc); + } + + wpc->reader->push_back_byte (wpc->wv_in, first_byte); + + if (first_byte == 'R') + return open_file3 (wpc, error); +#endif + + wpc->streams [0] = wps = malloc (sizeof (WavpackStream)); + wpc->num_streams = 1; + CLEAR (*wps); + + while (!wps->wphdr.block_samples) { + + wpc->filepos = wpc->reader->get_pos (wpc->wv_in); + bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) { + strcpy (error, "not compatible with this version of WavPack file!"); + return WavpackCloseFile (wpc); + } + + wpc->filepos += bcount; + wps->blockbuff = 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) { + strcpy (error, "can't read all of WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wps->wphdr.flags & UNKNOWN_FLAGS) { + strcpy (error, "not compatible with this version of WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wps->wphdr.block_samples && !(flags & OPEN_STREAMING)) { + if (wps->wphdr.total_samples == (uint32_t) -1 && wpc->reader->can_seek (wpc->wv_in)) { + uint32_t pos_save = wpc->reader->get_pos (wpc->wv_in); + uint32_t final_index = seek_final_index (wpc->reader, wpc->wv_in); + + if (final_index != (uint32_t) -1) + wpc->total_samples = final_index - wps->wphdr.block_index; + + wpc->reader->set_pos_abs (wpc->wv_in, pos_save); + } + else + wpc->total_samples = wps->wphdr.total_samples; + } + + if (wpc->wvc_in && wps->wphdr.block_samples && (wps->wphdr.flags & HYBRID_FLAG)) { + wpc->file2len = wpc->reader->get_length (wpc->wvc_in); + wpc->wvc_flag = TRUE; + } + + if (wpc->wvc_flag) { + wpc->file2pos = wpc->reader->get_pos (wpc->wvc_in); + bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) { + strcpy (error, "not compatible with this version of correction file!"); + return WavpackCloseFile (wpc); + } + + wpc->file2pos += bcount; + wps->block2buff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->block2buff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + strcpy (error, "problem with correction file!"); + return WavpackCloseFile (wpc); + } + + if (wps->wphdr.flags & UNKNOWN_FLAGS) { + strcpy (error, "not compatible with this version of correction file!"); + return WavpackCloseFile (wpc); + } + } + + if (!unpack_init (wpc)) { + strcpy (error, wpc->error_message [0] ? wpc->error_message : + "not compatible with this version of WavPack file!"); + + return WavpackCloseFile (wpc); + } + } + + wpc->config.flags &= ~0xff; + wpc->config.flags |= wps->wphdr.flags & 0xff; + wpc->config.bytes_per_sample = (wps->wphdr.flags & BYTES_STORED) + 1; + wpc->config.float_norm_exp = wps->float_norm_exp; + + wpc->config.bits_per_sample = (wpc->config.bytes_per_sample * 8) - + ((wps->wphdr.flags & SHIFT_MASK) >> SHIFT_LSB); + + if (!wpc->config.sample_rate) { + if (!wps || !wps->wphdr.block_samples || (wps->wphdr.flags & SRATE_MASK) == SRATE_MASK) + wpc->config.sample_rate = 44100; + else + wpc->config.sample_rate = sample_rates [(wps->wphdr.flags & SRATE_MASK) >> SRATE_LSB]; + } + + if (!wpc->config.num_channels) { + wpc->config.num_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; + wpc->config.channel_mask = 0x5 - wpc->config.num_channels; + } + + if ((flags & OPEN_2CH_MAX) && !(wps->wphdr.flags & FINAL_BLOCK)) + wpc->reduced_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; + + return wpc; +} + +// 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 conatins 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 + +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) + mode |= MODE_HIGH; + + if (wpc->config.flags & CONFIG_FAST_FLAG) + mode |= MODE_FAST; + + if (wpc->config.flags & CONFIG_EXTRA_MODE) + mode |= MODE_EXTRA; + + if (wpc->config.flags & CONFIG_CREATE_EXE) + mode |= MODE_SFX; + +#ifdef TAGS + if (valid_tag (&wpc->m_tag)) { + mode |= MODE_VALID_TAG; + + if (valid_tag (&wpc->m_tag) == 'A') + mode |= MODE_APETAG; + } +#endif + } + + return mode; +} + +// This function returns the major version number of the WavPack program +// (or library) that created the open file. Currently, this can be 1 to 4. +// Minor versions are not recorded in WavPack files. + +int WavpackGetVersion (WavpackContext *wpc) +{ + if (wpc) { +#ifdef VER3 + if (wpc->stream3) + return get_version3 (wpc); +#endif + return 4; + } + + return 0; +} + +#endif + +#ifdef UNPACK + +// 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->current_stream = 0]; + uint32_t bcount, samples_unpacked = 0, samples_to_unpack; + int num_channels = wpc->config.num_channels; + int file_done = FALSE; + +#ifdef VER3 + if (wpc->stream3) + return unpack_samples3 (wpc, buffer, samples); +#endif + + while (samples) { + if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || + wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) { + free_streams (wpc); + wpc->filepos = wpc->reader->get_pos (wpc->wv_in); + bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) { + file_done = TRUE; + break; + } + + if (wpc->open_flags & OPEN_STREAMING) + wps->wphdr.block_index = wps->sample_index = 0; + + wpc->filepos += bcount; + wps->blockbuff = 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) { + strcpy (wpc->error_message, "can't read all of WavPack file!"); + file_done = TRUE; + break; + } + + if (wps->wphdr.flags & UNKNOWN_FLAGS) { + strcpy (wpc->error_message, "not compatible with this version of WavPack file!"); + wpc->crc_errors++; + break; + } + + if (wps->wphdr.block_samples && wpc->wvc_flag) { + wpc->file2pos = wpc->reader->get_pos (wpc->wvc_in); + bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) { + file_done = TRUE; + break; + } + + if (wpc->open_flags & OPEN_STREAMING) + wps->wphdr.block_index = wps->sample_index = 0; + + wpc->file2pos += bcount; + wps->block2buff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->block2buff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + file_done = TRUE; + break; + } + + if (wps->wphdr.flags & UNKNOWN_FLAGS) { + strcpy (wpc->error_message, "not compatible with this version of WavPack file!"); + wpc->crc_errors++; + break; + } + } + + if (!wps->wphdr.block_samples || wps->sample_index == wps->wphdr.block_index) + if (!unpack_init (wpc)) { + wpc->crc_errors++; + break; + } + } + + if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || + wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) + continue; + + if (wps->sample_index < wps->wphdr.block_index) { + samples_to_unpack = wps->wphdr.block_index - wps->sample_index; + + if (samples_to_unpack > samples) + samples_to_unpack = samples; + + wps->sample_index += samples_to_unpack; + samples_unpacked += samples_to_unpack; + samples -= samples_to_unpack; + + if (wpc->reduced_channels) + samples_to_unpack *= wpc->reduced_channels; + else + samples_to_unpack *= num_channels; + + while (samples_to_unpack--) + *buffer++ = 0; + + continue; + } + + samples_to_unpack = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; + + if (samples_to_unpack > samples) + samples_to_unpack = samples; + + if (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) { + int32_t *temp_buffer = malloc (samples_to_unpack * 8), *src, *dst; + int offset = 0; + uint32_t samcnt; + + while (1) { + if (wpc->current_stream == wpc->num_streams) { + wps = wpc->streams [wpc->num_streams++] = malloc (sizeof (WavpackStream)); + CLEAR (*wps); + bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) { + file_done = TRUE; + break; + } + + if (wpc->open_flags & OPEN_STREAMING) + wps->wphdr.block_index = wps->sample_index = 0; + + wps->blockbuff = 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) { + strcpy (wpc->error_message, "can't read all of WavPack file!"); + file_done = TRUE; + break; + } + + if (wps->wphdr.flags & UNKNOWN_FLAGS) { + strcpy (wpc->error_message, "not compatible with this version of WavPack file!"); + wpc->crc_errors++; + break; + } + + if (wpc->wvc_flag) { + bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) { + file_done = TRUE; + break; + } + + if (wpc->open_flags & OPEN_STREAMING) + wps->wphdr.block_index = wps->sample_index = 0; + + wps->block2buff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->block2buff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + file_done = TRUE; + break; + } + + if (wps->wphdr.flags & UNKNOWN_FLAGS) { + strcpy (wpc->error_message, "not compatible with this version of WavPack file!"); + wpc->crc_errors++; + break; + } + } + + if (!unpack_init (wpc)) { + wpc->crc_errors++; + break; + } + } + else + wps = wpc->streams [wpc->current_stream]; + + unpack_samples (wpc, src = temp_buffer, samples_to_unpack); + samcnt = samples_to_unpack; + dst = buffer + offset; + + if (wps->wphdr.flags & MONO_FLAG) { + while (samcnt--) { + dst [0] = *src++; + dst += num_channels; + } + + offset++; + } + else { + while (samcnt--) { + dst [0] = *src++; + dst [1] = *src++; + dst += num_channels; + } + + offset += 2; + } + + if (wps->wphdr.flags & FINAL_BLOCK) + break; + else + wpc->current_stream++; + } + + wps = wpc->streams [wpc->current_stream = 0]; + free (temp_buffer); + } + else + unpack_samples (wpc, buffer, samples_to_unpack); + + if (wpc->reduced_channels) + buffer += samples_to_unpack * wpc->reduced_channels; + else + buffer += samples_to_unpack * num_channels; + + samples_unpacked += samples_to_unpack; + samples -= samples_to_unpack; + + if (wps->sample_index == wps->wphdr.block_index + wps->wphdr.block_samples) { + if (check_crc_error (wpc) && wps->blockbuff) { + + if (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 (wps->sample_index == wpc->total_samples) { + file_done = TRUE; + break; + } + } + + if (samples) { + if (wps->wphdr.block_samples && (wps->wphdr.flags & INITIAL_BLOCK)) + wps->sample_index = wps->wphdr.block_index + wps->wphdr.block_samples; + + if (!samples_unpacked && !file_done) { + while (num_channels--) + *buffer++ = 0; + + samples_unpacked++; + } + } + + return samples_unpacked; +} + +#ifdef SEEKING + +static uint32_t find_sample (WavpackContext *wpc, void *infile, uint32_t header_pos, uint32_t sample); + +// Seek to the specifed 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. + +int WavpackSeekSample (WavpackContext *wpc, uint32_t sample) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream = 0]; + uint32_t bcount, samples_to_skip; + int32_t *buffer; + + if (wpc->total_samples == (uint32_t) -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 VER3 + if (wpc->stream3) + return seek_sample3 (wpc, sample); +#endif + + if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || sample < wps->wphdr.block_index || + sample >= wps->wphdr.block_index + wps->wphdr.block_samples) { + + free_streams (wpc); + wpc->filepos = find_sample (wpc, wpc->wv_in, wpc->filepos, sample); + + if (wpc->filepos == (uint32_t) -1) + return FALSE; + + if (wpc->wvc_flag) { + wpc->file2pos = find_sample (wpc, wpc->wvc_in, 0, sample); + + if (wpc->file2pos == (uint32_t) -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)); + little_endian_to_native (&wps->wphdr, WavpackHeaderFormat); + wps->blockbuff = 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; + } + + 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)); + little_endian_to_native (&wps->wphdr, WavpackHeaderFormat); + wps->block2buff = 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; + } + } + + if (!unpack_init (wpc)) { + free_streams (wpc); + return FALSE; + } + } + + while (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) { + if (++wpc->current_stream == wpc->num_streams) { + wps = wpc->streams [wpc->num_streams++] = malloc (sizeof (WavpackStream)); + CLEAR (*wps); + bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) + break; + + wps->blockbuff = 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) { + strcpy (wpc->error_message, "can't read all of WavPack file!"); + break; + } + + if (wpc->wvc_flag) { + bcount = read_next_header (wpc->reader, wpc->wvc_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) + break; + + wps->block2buff = malloc (wps->wphdr.ckSize + 8); + memcpy (wps->block2buff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) + break; + } + + if (!unpack_init (wpc)) + break; + } + 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; + + samples_to_skip = sample - wps->sample_index; + + if (samples_to_skip) { + buffer = malloc (samples_to_skip * 8); + + for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++) + unpack_samples (wpc, buffer, samples_to_skip); + + free (buffer); + } + + wpc->current_stream = 0; + return TRUE; +} + +#endif + +#ifdef TAGS + +// 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; +} + +// 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. + +static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size); +static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size); + +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); + else if (m_tag->id3_tag.tag_id [0] == 'T') + return get_id3_tag_item (m_tag, item, value, size); + else + return 0; +} + +static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size) +{ + char *p = m_tag->ape_tag_data; + 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, flags, isize; + + vsize = * (int32_t *) p; p += 4; + flags = * (int32_t *) p; p += 4; + isize = strlen (p); + + little_endian_to_native (&vsize, "L"); + little_endian_to_native (&flags, "L"); + + if (p + isize + vsize + 1 > q) + break; + + if (isize && vsize && !stricmp (item, p) && !(flags & 6)) { + + if (!value || !size) + return vsize; + + 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 void tagcpy (char *dest, char *src, int tag_size); + +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 = 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; +} + +// 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. + +static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size); +static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size); + +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); + else if (m_tag->id3_tag.tag_id [0] == 'T') + return get_id3_tag_item_indexed (m_tag, index, item, size); + else + return 0; +} + +static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size) +{ + char *p = m_tag->ape_tag_data; + 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; ++i) { + int vsize, flags, isize; + + vsize = * (int32_t *) p; p += 4; + flags = * (int32_t *) p; p += 4; + isize = strlen (p); + + little_endian_to_native (&vsize, "L"); + little_endian_to_native (&flags, "L"); + + if (p + isize + vsize + 1 > q) + break; + + if (isize && vsize && !(flags & 6) && !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 tagdata (char *src, int tag_size); + +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 = 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; +} + +#endif + +#endif + +#ifdef PACK + +// Open context for writing WavPack files. The returned context pointer is used +// in all following calls to the library. The "blockout" function will be used +// to store the actual completed WavPack blocks and will be called with the id +// pointers containing user defined data (one for the wv file and one for the +// wvc file). A return value of NULL indicates that memory could not be +// allocated for the context. + +WavpackContext *WavpackOpenFileOutput (WavpackBlockOutput blockout, void *wv_id, void *wvc_id) +{ + WavpackContext *wpc = malloc (sizeof (WavpackContext)); + + if (!wpc) + return NULL; + + CLEAR (*wpc); + wpc->blockout = blockout; + wpc->wv_out = wv_id; + wpc->wvc_out = wvc_id; + return wpc; +} + +// Set configuration for writing WavPack files. This must be done before +// sending any actual samples, however it is okay to send wrapper or other +// metadata before calling this. The "config" structure contains the following +// required information: + +// config->bytes_per_sample see WavpackGetBytesPerSample() for info +// config->bits_per_sample see WavpackGetBitsPerSample() for info +// config->channel_mask Microsoft standard (mono = 4, stereo = 3) +// config->num_channels self evident +// config->sample_rate self evident + +// In addition, the following fields and flags may be set: + +// config->flags: +// -------------- +// o CONFIG_HYBRID_FLAG select hybrid mode (must set bitrate) +// o CONFIG_JOINT_STEREO select joint stereo (must set override also) +// o CONFIG_JOINT_OVERRIDE override default joint stereo selection +// o CONFIG_HYBRID_SHAPE select hybrid noise shaping (set override & +// shaping_weight != 0.0) +// o CONFIG_SHAPE_OVERRIDE override default hybrid noise shaping +// (set CONFIG_HYBRID_SHAPE and shaping_weight) +// o CONFIG_FAST_FLAG "fast" compression mode +// o CONFIG_HIGH_FLAG "high" compression mode +// o CONFIG_BITRATE_KBPS hybrid bitrate is kbps, not bits / sample +// o CONFIG_CREATE_WVC create correction file +// o CONFIG_OPTIMIZE_WVC maximize bybrid compression (-cc option) +// o CONFIG_CALC_NOISE calc noise in hybrid mode +// o CONFIG_EXTRA_MODE extra processing mode (slow!) +// o CONFIG_SKIP_WVX no wvx stream for floats & large ints +// o CONFIG_MD5_CHECKSUM specify if you plan to store MD5 signature +// o CONFIG_CREATE_EXE specify if you plan to prepend sfx module + +// config->bitrate hybrid bitrate in either bits/sample or kbps +// config->shaping_weight hybrid noise shaping coefficient override +// config->block_samples force samples per WavPack block (0 = use deflt) +// config->float_norm_exp select floating-point data (127 for +/-1.0) +// config->xmode extra mode processing value override + +// If the number of samples to be written is known then it should be passed +// here. If the duration is not known then pass -1. In the case that the size +// is not known (or the writing is terminated early) then it is suggested that +// the application retrieve the first block written and let the library update +// the total samples indication. A function is provided to do this update and +// it should be done to the "correction" file also. If this cannot be done +// (because a pipe is being used, for instance) then a valid WavPack will still +// be created, but when applications want to access that file they will have +// to seek all the way to the end to determine the actual duration. Also, if +// a RIFF header has been included then it should be updated as well or the +// WavPack file will not be directly unpackable to a valid wav file (although +// it will still be usable by itself). A return of FALSE indicates an error. + +static const uint32_t xtable [] = { 123, 3, 27, 59, 123, 187, 251 }; +static const uint32_t f_xtable [] = { 251, 3, 27, 59, 123, 187, 251 }; +static const uint32_t h_xtable [] = { 91, 3, 27, 91, 123, 187, 251 }; + +int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples) +{ + uint32_t flags = (config->bytes_per_sample - 1), bps = 0, shift = 0; + uint32_t chan_mask = config->channel_mask; + int num_chans = config->num_channels; + int i; + + wpc->total_samples = total_samples; + wpc->config.sample_rate = config->sample_rate; + wpc->config.num_channels = config->num_channels; + wpc->config.channel_mask = config->channel_mask; + wpc->config.bits_per_sample = config->bits_per_sample; + wpc->config.bytes_per_sample = config->bytes_per_sample; + wpc->config.block_samples = config->block_samples; + wpc->config.flags = config->flags; + + if (config->float_norm_exp) { + wpc->config.float_norm_exp = config->float_norm_exp; + wpc->config.flags |= CONFIG_FLOAT_DATA; + flags |= FLOAT_DATA; + } + else + shift = (config->bytes_per_sample * 8) - config->bits_per_sample; + + for (i = 0; i < 15; ++i) + if (wpc->config.sample_rate == sample_rates [i]) + break; + + flags |= i << SRATE_LSB; + flags |= shift << SHIFT_LSB; + + if (config->flags & CONFIG_HYBRID_FLAG) { + flags |= HYBRID_FLAG | HYBRID_BITRATE | HYBRID_BALANCE; + + if (!(wpc->config.flags & CONFIG_SHAPE_OVERRIDE)) { + wpc->config.flags |= CONFIG_HYBRID_SHAPE | CONFIG_AUTO_SHAPING; + flags |= HYBRID_SHAPE | NEW_SHAPING; + } + else if (wpc->config.flags & CONFIG_HYBRID_SHAPE) { + wpc->config.shaping_weight = config->shaping_weight; + flags |= HYBRID_SHAPE | NEW_SHAPING; + } + + if (wpc->config.flags & CONFIG_OPTIMIZE_WVC) + flags |= CROSS_DECORR; + + if (config->flags & CONFIG_BITRATE_KBPS) { + bps = floor (config->bitrate * 256000.0 / config->sample_rate / config->num_channels + 0.5); + + if (bps > (64 << 8)) + bps = 64 << 8; + } + else + bps = floor (config->bitrate * 256.0 + 0.5); + } + else + flags |= CROSS_DECORR; + + if (!(config->flags & CONFIG_JOINT_OVERRIDE) || (config->flags & CONFIG_JOINT_STEREO)) + flags |= JOINT_STEREO; + + if (config->flags & CONFIG_CREATE_WVC) + wpc->wvc_flag = TRUE; + + wpc->stream_version = CUR_STREAM_VERS; + + for (wpc->current_stream = 0; num_chans; wpc->current_stream++) { + WavpackStream *wps = malloc (sizeof (WavpackStream)); + uint32_t stereo_mask, mono_mask; + int pos, chans; + + wpc->streams [wpc->current_stream] = wps; + CLEAR (*wps); + + for (pos = 1; pos <= 18; ++pos) { + stereo_mask = 3 << (pos - 1); + mono_mask = 1 << (pos - 1); + + if ((chan_mask & stereo_mask) == stereo_mask && (mono_mask & 0x251)) { + chan_mask &= ~stereo_mask; + chans = 2; + break; + } + else if (chan_mask & mono_mask) { + chan_mask &= ~mono_mask; + chans = 1; + break; + } + } + + if (pos == 19) + chans = num_chans > 1 ? 2 : 1; + + num_chans -= chans; + + if (num_chans && wpc->current_stream == MAX_STREAMS - 1) + break; + + memcpy (wps->wphdr.ckID, "wvpk", 4); + wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; + wps->wphdr.total_samples = wpc->total_samples; + wps->wphdr.version = wpc->stream_version; + wps->wphdr.flags = flags; + wps->bits = bps; + + if (!wpc->current_stream) + wps->wphdr.flags |= INITIAL_BLOCK; + + if (!num_chans) + wps->wphdr.flags |= FINAL_BLOCK; + + if (chans == 1) { + wps->wphdr.flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE); + wps->wphdr.flags |= MONO_FLAG; + } + } + + wpc->num_streams = wpc->current_stream; + wpc->current_stream = 0; + + if (num_chans) { + strcpy (wpc->error_message, "too many channels!"); + return FALSE; + } + + if (config->flags & CONFIG_EXTRA_MODE) { + + if (config->flags & CONFIG_HIGH_FLAG) + wpc->config.extra_flags = h_xtable [config->xmode]; + else if (config->flags & CONFIG_FAST_FLAG) + wpc->config.extra_flags = f_xtable [config->xmode]; + else + wpc->config.extra_flags = xtable [config->xmode]; + + if (config->flags & CONFIG_JOINT_OVERRIDE) + wpc->config.extra_flags &= ~EXTRA_STEREO_MODES; + } + + return TRUE; +} + +// Prepare to actually pack samples by determining the size of the WavPack +// blocks and allocating sample buffers and initializing each stream. Call +// after WavpackSetConfiguration() and before WavpackPackSamples(). A return +// of FALSE indicates an error. + +int WavpackPackInit (WavpackContext *wpc) +{ + if (wpc->metabytes > 4096) + write_metadata_block (wpc); + + if (wpc->config.block_samples) + wpc->block_samples = wpc->config.block_samples; + else { + if (wpc->config.flags & CONFIG_HIGH_FLAG) + wpc->block_samples = wpc->config.sample_rate; + else if (!(wpc->config.sample_rate % 2)) + wpc->block_samples = wpc->config.sample_rate / 2; + else + wpc->block_samples = wpc->config.sample_rate; + + while (wpc->block_samples * wpc->config.num_channels > 150000) + wpc->block_samples /= 2; + + while (wpc->block_samples * wpc->config.num_channels < 40000) + wpc->block_samples *= 2; + } + + wpc->max_samples = wpc->block_samples + (wpc->block_samples >> 1); + + for (wpc->current_stream = 0; wpc->streams [wpc->current_stream]; wpc->current_stream++) { + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + wps->sample_buffer = malloc (wpc->max_samples * (wps->wphdr.flags & MONO_FLAG ? 4 : 8)); + pack_init (wpc); + } + + return TRUE; +} + +// Pack the specified samples. Samples must be stored in longs in the native +// endian format of the executing processor. The number of samples specified +// indicates composite samples (sometimes called "frames"). So, the actual +// number of data points would be this "sample_count" times the number of +// channels. Note that samples are accumulated here until enough exist to +// create a complete WavPack block (or several blocks for multichannel audio). +// If an application wants to break a block at a specific sample, then it must +// simply call WavpackFlushSamples() to force an early termination. Completed +// WavPack blocks are send to the function provided in the initial call to +// WavpackOpenFileOutput(). A return of FALSE indicates an error. + +static int pack_streams (WavpackContext *wpc, uint32_t block_samples); +static int create_riff_header (WavpackContext *wpc); + +int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count) +{ + int nch = wpc->config.num_channels; + + while (sample_count) { + int32_t *source_pointer = sample_buffer; + uint samples_to_copy; + + if (!wpc->riff_header_added && !wpc->riff_header_created && !create_riff_header (wpc)) + return FALSE; + + if (wpc->acc_samples + sample_count > wpc->max_samples) + samples_to_copy = wpc->max_samples - wpc->acc_samples; + else + samples_to_copy = sample_count; + + for (wpc->current_stream = 0; wpc->streams [wpc->current_stream]; wpc->current_stream++) { + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int32_t *dptr, *sptr, cnt; + + dptr = wps->sample_buffer + wpc->acc_samples * (wps->wphdr.flags & MONO_FLAG ? 1 : 2); + sptr = source_pointer; + cnt = samples_to_copy; + + if (wps->wphdr.flags & MONO_FLAG) { + while (cnt--) { + *dptr++ = *sptr; + sptr += nch; + } + + source_pointer++; + } + else { + while (cnt--) { + *dptr++ = sptr [0]; + *dptr++ = sptr [1]; + sptr += nch; + } + + source_pointer += 2; + } + } + + sample_buffer += samples_to_copy * nch; + sample_count -= samples_to_copy; + + if ((wpc->acc_samples += samples_to_copy) == wpc->max_samples && + !pack_streams (wpc, wpc->block_samples)) + return FALSE; + } + + return TRUE; +} + +// Flush all accumulated samples into WavPack blocks. This is normally called +// after all samples have been sent to WavpackPackSamples(), but can also be +// called to terminate a WavPack block at a specific sample (in other words it +// is possible to continue after this operation). This is also called to +// dump non-audio blocks like those holding metadata for various purposes. +// A return of FALSE indicates an error. + +int WavpackFlushSamples (WavpackContext *wpc) +{ + while (wpc->acc_samples) { + uint32_t block_samples; + + if (wpc->acc_samples > wpc->block_samples) + block_samples = wpc->acc_samples / 2; + else + block_samples = wpc->acc_samples; + + if (!pack_streams (wpc, block_samples)) + return FALSE; + } + + if (wpc->metacount) + write_metadata_block (wpc); + + return TRUE; +} + +// Note: The following function is no longer required because a proper wav +// header is now automatically generated for the application. However, if the +// application wants to generate its own header or wants to include additional +// chunks, then this function can still be used in which case the automatic +// wav header generation is suppressed. + +// Add wrapper (currently RIFF only) to WavPack blocks. This should be called +// before sending any audio samples for the RIFF header or after all samples +// have been sent for any RIFF trailer. WavpackFlushSamples() should be called +// between sending the last samples and calling this for trailer data to make +// sure that headers and trailers don't get mixed up in very short files. If +// the exact contents of the RIFF header are not known because, for example, +// the file duration is uncertain or trailing chunks are possible, simply write +// a "dummy" header of the correct length. When all data has been written it +// will be possible to read the first block written and update the header +// directly. An example of this can be found in the Audition filter. A +// return of FALSE indicates an error. + +int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount) +{ + uint32_t index = WavpackGetSampleIndex (wpc); + uchar meta_id; + + if (!index || index == (uint32_t) -1) { + wpc->riff_header_added = TRUE; + meta_id = ID_RIFF_HEADER; + } + else + meta_id = ID_RIFF_TRAILER; + + return add_to_metadata (wpc, data, bcount, meta_id); +} + +// Store computed MD5 sum in WavPack metadata. Note that the user must compute +// the 16 byte sum; it is not done here. A return of FALSE indicates an error. + +int WavpackStoreMD5Sum (WavpackContext *wpc, uchar data [16]) +{ + return add_to_metadata (wpc, data, 16, ID_MD5_CHECKSUM); +} + +static int create_riff_header (WavpackContext *wpc) +{ + RiffChunkHeader riffhdr; + ChunkHeader datahdr, fmthdr; + WaveHeader wavhdr; + + uint32_t total_samples = wpc->total_samples, total_data_bytes; + int32_t channel_mask = wpc->config.channel_mask; + int32_t sample_rate = wpc->config.sample_rate; + int bytes_per_sample = wpc->config.bytes_per_sample; + int bits_per_sample = wpc->config.bits_per_sample; + int format = (wpc->config.float_norm_exp) ? 3 : 1; + int num_channels = wpc->config.num_channels; + int wavhdrsize = 16; + + wpc->riff_header_created = TRUE; + + if (format == 3 && wpc->config.float_norm_exp != 127) { + strcpy (wpc->error_message, "can't create valid RIFF wav header for non-normalized floating data!"); + return FALSE; + } + + if (total_samples != (uint32_t) -1) + total_data_bytes = total_samples * bytes_per_sample * num_channels; + else + total_data_bytes = -1; + + CLEAR (wavhdr); + + wavhdr.FormatTag = format; + wavhdr.NumChannels = num_channels; + wavhdr.SampleRate = sample_rate; + wavhdr.BytesPerSecond = sample_rate * num_channels * bytes_per_sample; + wavhdr.BlockAlign = bytes_per_sample * num_channels; + wavhdr.BitsPerSample = bits_per_sample; + + if (num_channels > 2 || channel_mask != 0x5 - num_channels) { + wavhdrsize = sizeof (wavhdr); + wavhdr.cbSize = 22; + wavhdr.ValidBitsPerSample = bits_per_sample; + wavhdr.SubFormat = format; + wavhdr.ChannelMask = channel_mask; + wavhdr.FormatTag = 0xfffe; + wavhdr.BitsPerSample = bytes_per_sample * 8; + wavhdr.GUID [4] = 0x10; + wavhdr.GUID [6] = 0x80; + wavhdr.GUID [9] = 0xaa; + wavhdr.GUID [11] = 0x38; + wavhdr.GUID [12] = 0x9b; + wavhdr.GUID [13] = 0x71; + } + + strncpy (riffhdr.ckID, "RIFF", sizeof (riffhdr.ckID)); + strncpy (riffhdr.formType, "WAVE", sizeof (riffhdr.formType)); + + if (total_data_bytes != (uint32_t) -1) + riffhdr.ckSize = sizeof (riffhdr) + wavhdrsize + sizeof (datahdr) + total_data_bytes; + else + riffhdr.ckSize = total_data_bytes; + + strncpy (fmthdr.ckID, "fmt ", sizeof (fmthdr.ckID)); + fmthdr.ckSize = wavhdrsize; + + strncpy (datahdr.ckID, "data", sizeof (datahdr.ckID)); + datahdr.ckSize = total_data_bytes; + + // write the RIFF chunks up to just before the data starts + + native_to_little_endian (&riffhdr, ChunkHeaderFormat); + native_to_little_endian (&fmthdr, ChunkHeaderFormat); + native_to_little_endian (&wavhdr, WaveHeaderFormat); + native_to_little_endian (&datahdr, ChunkHeaderFormat); + + return add_to_metadata (wpc, &riffhdr, sizeof (riffhdr), ID_RIFF_HEADER) && + add_to_metadata (wpc, &fmthdr, sizeof (fmthdr), ID_RIFF_HEADER) && + add_to_metadata (wpc, &wavhdr, wavhdrsize, ID_RIFF_HEADER) && + add_to_metadata (wpc, &datahdr, sizeof (datahdr), ID_RIFF_HEADER); +} + +static int pack_streams (WavpackContext *wpc, uint32_t block_samples) +{ + uint32_t max_blocksize = block_samples * 10 + 4096, bcount; + uchar *outbuff, *outend, *out2buff, *out2end; + int result; + + out2buff = (wpc->wvc_flag) ? malloc (max_blocksize) : NULL; + out2end = out2buff + max_blocksize; + outbuff = malloc (max_blocksize); + outend = outbuff + max_blocksize; + + for (wpc->current_stream = 0; wpc->streams [wpc->current_stream]; wpc->current_stream++) { + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags; + + flags &= ~MAG_MASK; + flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7); + + wps->wphdr.block_index = wps->sample_index; + wps->wphdr.block_samples = block_samples; + wps->wphdr.flags = flags; + wps->block2buff = out2buff; + wps->block2end = out2end; + wps->blockbuff = outbuff; + wps->blockend = outend; + + result = pack_block (wpc, wps->sample_buffer); + wps->blockbuff = wps->block2buff = NULL; + + if (!result) { + strcpy (wpc->error_message, "output buffer overflowed!"); + break; + } + + bcount = ((WavpackHeader *) outbuff)->ckSize + 8; + native_to_little_endian ((WavpackHeader *) outbuff, WavpackHeaderFormat); + result = wpc->blockout (wpc->wv_out, outbuff, bcount); + + if (!result) { + strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); + break; + } + + wpc->filelen += bcount; + + if (out2buff) { + bcount = ((WavpackHeader *) out2buff)->ckSize + 8; + native_to_little_endian ((WavpackHeader *) out2buff, WavpackHeaderFormat); + result = wpc->blockout (wpc->wvc_out, out2buff, bcount); + + if (!result) { + strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); + break; + } + + wpc->file2len += bcount; + } + + if (wpc->acc_samples != block_samples) + memcpy (wps->sample_buffer, wps->sample_buffer + block_samples * (flags & MONO_FLAG ? 1 : 2), + (wpc->acc_samples - block_samples) * sizeof (int32_t) * (flags & MONO_FLAG ? 1 : 2)); + } + + wpc->current_stream = 0; + wpc->acc_samples -= block_samples; + free (outbuff); + + if (out2buff) + free (out2buff); + + return result; +} + +// Given the pointer to the first block written (to either a .wv or .wvc file), +// update the block with the actual number of samples written. If the wav +// header was generated by the library, then it is updated also. This should +// be done if WavpackSetConfiguration() was called with an incorrect number +// of samples (or -1). It is the responsibility of the application to read and +// rewrite the block. An example of this can be found in the Audition filter. + +void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block) +{ + uint32_t wrapper_size; + + little_endian_to_native (first_block, WavpackHeaderFormat); + ((WavpackHeader *) first_block)->total_samples = WavpackGetSampleIndex (wpc); + + if (wpc->riff_header_created) { + if (WavpackGetWrapperLocation (first_block, &wrapper_size)) { + RiffChunkHeader *riffhdr = WavpackGetWrapperLocation (first_block, NULL); + ChunkHeader *datahdr = (ChunkHeader *)((char *) riffhdr + wrapper_size - sizeof (ChunkHeader)); + uint32_t data_size = WavpackGetSampleIndex (wpc) * WavpackGetNumChannels (wpc) * WavpackGetBytesPerSample (wpc); + + if (!strncmp (riffhdr->ckID, "RIFF", 4)) { + little_endian_to_native (riffhdr, ChunkHeaderFormat); + riffhdr->ckSize = wrapper_size + data_size - 8; + native_to_little_endian (riffhdr, ChunkHeaderFormat); + } + + if (!strncmp (datahdr->ckID, "data", 4)) { + little_endian_to_native (datahdr, ChunkHeaderFormat); + datahdr->ckSize = data_size; + native_to_little_endian (datahdr, ChunkHeaderFormat); + } + } + } + + native_to_little_endian (first_block, WavpackHeaderFormat); +} + +// Note: The following function is no longer required because the wav header +// automatically generated for the application will also be updated by +// WavpackUpdateNumSamples (). However, if the application wants to generate +// its own header or wants to include additional chunks, then this function +// still must be used to update the application generated header. + +// Given the pointer to the first block written to a WavPack file, this +// function returns the location of the stored RIFF header that was originally +// written with WavpackAddWrapper(). This would normally be used to update +// the wav header to indicate that a different number of samples was actually +// written or if additional RIFF chunks are written at the end of the file. +// The "size" parameter can be set to non-NULL to obtain the exact size of the +// RIFF header, and the function will return FALSE if the header is not found +// in the block's metadata (or it is not a valid WavPack block). It is the +// responsibility of the application to read and rewrite the block. An example +// of this can be found in the Audition filter. + +static void *find_metadata (void *wavpack_block, int desired_id, uint32_t *size); + +void *WavpackGetWrapperLocation (void *first_block, uint32_t *size) +{ + void *loc; + + little_endian_to_native (first_block, WavpackHeaderFormat); + loc = find_metadata (first_block, ID_RIFF_HEADER, size); + native_to_little_endian (first_block, WavpackHeaderFormat); + + return loc; +} + +static void *find_metadata (void *wavpack_block, int desired_id, uint32_t *size) +{ + WavpackHeader *wphdr = wavpack_block; + uchar *dp, meta_id, c1, c2; + uint32_t bcount, meta_bc; + + if (strncmp (wphdr->ckID, "wvpk", 4)) + return NULL; + + bcount = wphdr->ckSize - sizeof (WavpackHeader) + 8; + dp = (uchar *)(wphdr + 1); + + while (bcount >= 2) { + meta_id = *dp++; + c1 = *dp++; + + meta_bc = c1 << 1; + bcount -= 2; + + if (meta_id & ID_LARGE) { + if (bcount < 2) + break; + + c1 = *dp++; + c2 = *dp++; + meta_bc += ((uint32_t) c1 << 9) + ((uint32_t) c2 << 17); + bcount -= 2; + } + + if ((meta_id & ID_UNIQUE) == desired_id) { + if (size) + *size = meta_bc + ((meta_id & ID_ODD_SIZE) ? 1 : 0); + + return dp; + } + + bcount -= meta_bc; + } + + return FALSE; +} + +#endif + +#ifdef TAGS + +// Limited functionality to append APEv2 tags to WavPack files when they are +// created has been added for version 4.2. This function is used to append the +// specified field to the tag being created. 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. Note that ID3 tags are not +// supported and that no editing of existing tags is allowed (there are several +// fine libraries available for this). A size parameter is included so that +// values containing multiple (NULL separated) strings can be written. + +int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize) +{ + M_Tag *m_tag = &wpc->m_tag; + int isize = strlen (item); + + while (WavpackDeleteTagItem (wpc, item)); + + if (!m_tag->ape_tag_hdr.ID [0]) { + strncpy (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 = 0x80000000; + } + + if (m_tag->ape_tag_hdr.ID [0] == 'A') { + int new_item_len = vsize + isize + 9, flags = 0; + char *p; + + m_tag->ape_tag_hdr.item_count++; + m_tag->ape_tag_hdr.length += new_item_len; + p = m_tag->ape_tag_data = 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; + native_to_little_endian (&vsize, "L"); + native_to_little_endian (&flags, "L"); + * (int32_t *) p = vsize; p += 4; + * (int32_t *) p = flags; p += 4; + little_endian_to_native (&vsize, "L"); + little_endian_to_native (&flags, "L"); + strcpy (p, item); + p += isize + 1; + memcpy (p, value, vsize); + + return TRUE; + } + else + return FALSE; +} + +int WavpackDeleteTagItem (WavpackContext *wpc, const char *item) +{ + M_Tag *m_tag = &wpc->m_tag; + + if (m_tag->ape_tag_hdr.ID [0] == 'A') { + char *p = m_tag->ape_tag_data; + 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, flags, isize; + + vsize = * (int32_t *) p; p += 4; + flags = * (int32_t *) p; p += 4; + isize = strlen (p); + + little_endian_to_native (&vsize, "L"); + little_endian_to_native (&flags, "L"); + + if (p + isize + vsize + 1 > q) + break; + + if (isize && vsize && !stricmp (item, p)) { + char *d = p - 8; + + p += isize + vsize + 1; + + while (p < q) + *d++ = *p++; + + m_tag->ape_tag_hdr.length = 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. + +static int write_tag_blockout (WavpackContext *wpc); +static int write_tag_reader (WavpackContext *wpc); + +int WavpackWriteTag (WavpackContext *wpc) +{ + if (wpc->blockout) + return write_tag_blockout (wpc); + else + return write_tag_reader (wpc); +} + +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) { + m_tag->ape_tag_hdr.flags |= 0x20000000; + native_to_little_endian (&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)); + little_endian_to_native (&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 &= ~0x20000000; + native_to_little_endian (&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)); + little_endian_to_native (&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; +} + +static int write_tag_reader (WavpackContext *wpc) +{ + M_Tag *m_tag = &wpc->m_tag; + uint32_t tag_size = 0; + int result = TRUE; + + 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 + sizeof (m_tag->ape_tag_hdr); + + result = (wpc->open_flags & OPEN_EDIT_TAGS) && wpc->reader->can_seek (wpc->wv_in) && + !wpc->reader->set_pos_rel (wpc->wv_in, m_tag->tag_file_pos, SEEK_END); + + if (result && tag_size < -m_tag->tag_file_pos) { + int nullcnt = -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) { + m_tag->ape_tag_hdr.flags |= 0x20000000; + native_to_little_endian (&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)); + little_endian_to_native (&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 &= ~0x20000000; + native_to_little_endian (&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)); + little_endian_to_native (&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; +} + +#endif + +// Get total number of samples contained in the WavPack file, or -1 if unknown + +uint32_t WavpackGetNumSamples (WavpackContext *wpc) +{ + return wpc ? wpc->total_samples : (uint32_t) -1; +} + +// Get the current sample index position, or -1 if unknown + +uint32_t WavpackGetSampleIndex (WavpackContext *wpc) +{ + if (wpc) { +#ifdef VER3 + if (wpc->stream3) + return get_sample_index3 (wpc); + else if (wpc->streams [0]) + return wpc->streams [0]->sample_index; +#else + if (wpc->streams [0]) + return wpc->streams [0]->sample_index; +#endif + } + + return (uint32_t) -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 != (uint32_t) -1 && wpc->total_samples != 0) + return (double) WavpackGetSampleIndex (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 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 != (uint32_t) -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 != (uint32_t) -1 && wpc->filelen) { + double output_time = (double) wpc->total_samples / wpc->config.sample_rate; + double input_size = (double) wpc->filelen + (count_wvc ? wpc->file2len : 0); + + if (output_time >= 1.0 && input_size >= 1.0) + return input_size * 8.0 / output_time; + } + + return 0.0; +} + +#ifdef UNPACK + +// 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->stream3) + return WavpackGetAverageBitrate (wpc, TRUE); + + if (wpc && wpc->streams [0] && wpc->streams [0]->wphdr.block_samples) { + double output_time = (double) wpc->streams [0]->wphdr.block_samples / wpc->config.sample_rate; + 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; +} + +#endif + +// Close the specified WavPack file and release all resources used by it. +// Returns NULL. + +WavpackContext *WavpackCloseFile (WavpackContext *wpc) +{ + free_streams (wpc); + + if (wpc->streams [0]) + free (wpc->streams [0]); + +#ifdef VER3 + if (wpc->stream3) + free_stream3 (wpc); +#endif + +#if defined(UNPACK) || defined(INFO_ONLY) + if (wpc->close_files) { +#ifdef USE_FSTREAMS + if (wpc->wv_in != NULL) + fclose (wpc->wv_in); + + if (wpc->wvc_in != NULL) + fclose (wpc->wvc_in); +#endif + } + + WavpackFreeWrapper (wpc); +#endif + +#ifdef TAGS + free_tag (&wpc->m_tag); +#endif + + free (wpc); + + return NULL; +} + +// Returns the sample rate of the specified WavPack file + +uint32_t WavpackGetSampleRate (WavpackContext *wpc) +{ + return wpc ? 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; +} + +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 defined(UNPACK) || defined(INFO_ONLY) + +// 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; +} + +// 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; +} + +uchar *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; + } +} + +// Get any MD5 checksum stored in the metadata (should be called after reading +// last sample or an extra seek will occur). A return value of FALSE indicates +// that no MD5 checksum was stored. + +static int seek_md5 (WavpackStreamReader *reader, void *id, uchar data [16]); + +int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]) +{ + if (wpc->config.flags & CONFIG_MD5_CHECKSUM) { + if (wpc->config.md5_read) { + memcpy (data, wpc->config.md5_checksum, 16); + return TRUE; + } + else if (wpc->reader->can_seek (wpc->wv_in)) { + uint32_t pos_save = wpc->reader->get_pos (wpc->wv_in); + + wpc->config.md5_read = seek_md5 (wpc->reader, wpc->wv_in, wpc->config.md5_checksum); + wpc->reader->set_pos_abs (wpc->wv_in, pos_save); + + if (wpc->config.md5_read) { + memcpy (data, wpc->config.md5_checksum, 16); + return TRUE; + } + else + return FALSE; + } + } + + return FALSE; +} + +#endif + +// Free all memory allocated for raw WavPack blocks (for all allocated streams) +// and free all additonal streams. This does not free the default stream ([0]) +// which is always kept around. + +static 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 (si) { + wpc->num_streams--; + free (wpc->streams [si]); + wpc->streams [si] = NULL; + } + } + + wpc->current_stream = 0; +} + +#ifdef TAGS + +// Return TRUE is a valid ID3v1 or APEv2 tag has been loaded. + +static 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; +} + +// Free the data for any APEv2 tag that was allocated. + +static void free_tag (M_Tag *m_tag) +{ + if (m_tag->ape_tag_data) { + free (m_tag->ape_tag_data); + m_tag->ape_tag_data = 0; + } +} + +#endif + +#if defined(UNPACK) || defined(INFO_ONLY) + +// Read from current file position until a valid 32-byte WavPack 4.0 header is +// found and read into the specified pointer. The number of bytes skipped is +// returned. If no WavPack header is found within 1 meg, then a -1 is returned +// to indicate the error. No additional bytes are read past the header and it +// is returned in the processor's native endian mode. Seeking is not required. + +static uint32_t read_next_header (WavpackStreamReader *reader, void *id, WavpackHeader *wphdr) +{ + char buffer [sizeof (*wphdr)], *sp = buffer + sizeof (*wphdr), *ep = sp; + uint32_t bytes_skipped = 0; + int bleft; + + while (1) { + if (sp < ep) { + bleft = ep - sp; + memcpy (buffer, sp, bleft); + } + else + bleft = 0; + + if (reader->read_bytes (id, buffer + bleft, sizeof (*wphdr) - bleft) != sizeof (*wphdr) - bleft) + return -1; + + sp = buffer; + + if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' && + !(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 && + sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff)) { + memcpy (wphdr, buffer, sizeof (*wphdr)); + little_endian_to_native (wphdr, WavpackHeaderFormat); + return bytes_skipped; + } + + while (sp < ep && *sp != 'w') + sp++; + + if ((bytes_skipped += sp - buffer) > 1024 * 1024) + return -1; + } +} + +// This function is used to seek to end of a file to determine its actual +// length in samples by reading the last header block containing data. +// Currently, all WavPack files contain the sample length in the first block +// containing samples, however this might not always be the case. Obviously, +// this function requires a seekable file or stream and leaves the file +// pointer undefined. A return value of -1 indicates the length could not +// be determined. + +static uint32_t seek_final_index (WavpackStreamReader *reader, void *id) +{ + uint32_t result = (uint32_t) -1, bcount; + WavpackHeader wphdr; + + if (reader->get_length (id) > 1200000L) + reader->set_pos_rel (id, -1048576L, SEEK_END); + + while (1) { + bcount = read_next_header (reader, id, &wphdr); + + if (bcount == (uint32_t) -1) + return result; + + if (wphdr.block_samples && (wphdr.flags & FINAL_BLOCK)) + result = wphdr.block_index + wphdr.block_samples; + + if (wphdr.ckSize > sizeof (WavpackHeader) - 8) + reader->set_pos_rel (id, wphdr.ckSize - sizeof (WavpackHeader) + 8, SEEK_CUR); + } +} + +static int seek_md5 (WavpackStreamReader *reader, void *id, uchar data [16]) +{ + uchar meta_id, c1, c2; + uint32_t bcount, meta_bc; + WavpackHeader wphdr; + + if (reader->get_length (id) > 1200000L) + reader->set_pos_rel (id, -1048576L, SEEK_END); + + while (1) { + bcount = read_next_header (reader, id, &wphdr); + + if (bcount == (uint32_t) -1) + return FALSE; + + bcount = wphdr.ckSize - sizeof (WavpackHeader) + 8; + + while (bcount >= 2) { + if (reader->read_bytes (id, &meta_id, 1) != 1 || + reader->read_bytes (id, &c1, 1) != 1) + return FALSE; + + meta_bc = c1 << 1; + bcount -= 2; + + if (meta_id & ID_LARGE) { + if (bcount < 2 || reader->read_bytes (id, &c1, 1) != 1 || + reader->read_bytes (id, &c2, 1) != 1) + return FALSE; + + meta_bc += ((uint32_t) c1 << 9) + ((uint32_t) c2 << 17); + bcount -= 2; + } + + if (meta_id == ID_MD5_CHECKSUM) + return (meta_bc == 16 && bcount >= 16 && + reader->read_bytes (id, data, 16) == 16); + + reader->set_pos_rel (id, meta_bc, SEEK_CUR); + bcount -= meta_bc; + } + } +} + +#ifdef SEEKING + +// 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 uint32_t find_header (WavpackStreamReader *reader, void *id, uint32_t filepos, WavpackHeader *wphdr) +{ + char *buffer = 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 = ep - sp; + memcpy (buffer, sp, bleft); + ep -= (sp - buffer); + sp = buffer; + } + else { + if (sp > ep) + if (reader->set_pos_rel (id, 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 [5] == 4 && + sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff)) { + memcpy (wphdr, sp - 4, sizeof (*wphdr)); + little_endian_to_native (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 uint32_t find_sample (WavpackContext *wpc, void *infile, uint32_t header_pos, uint32_t sample) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t file_pos1 = 0, file_pos2 = wpc->reader->get_length (infile); + uint32_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 (wps->wphdr.block_index > sample) { + sample_pos2 = wps->wphdr.block_index; + file_pos2 = header_pos; + } + else if (wps->wphdr.block_index + wps->wphdr.block_samples <= sample) { + sample_pos1 = wps->wphdr.block_index; + file_pos1 = header_pos; + } + else + return header_pos; + } + + while (1) { + double bytes_per_sample; + uint32_t seek_pos; + + bytes_per_sample = file_pos2 - file_pos1; + bytes_per_sample /= sample_pos2 - sample_pos1; + seek_pos = file_pos1 + (file_skip ? 32 : 0); + seek_pos += (uint32_t)(bytes_per_sample * (sample - sample_pos1) * ratio); + seek_pos = find_header (wpc->reader, infile, seek_pos, &wps->wphdr); + + if (seek_pos == (uint32_t) -1 || seek_pos >= file_pos2) { + if (ratio > 0.0) { + if ((ratio -= 0.24) < 0.0) + ratio = 0.0; + } + else + return -1; + } + else if (wps->wphdr.block_index > sample) { + sample_pos2 = wps->wphdr.block_index; + file_pos2 = seek_pos; + } + else if (wps->wphdr.block_index + wps->wphdr.block_samples <= sample) { + + if (seek_pos == file_pos1) + file_skip = 1; + else { + sample_pos1 = wps->wphdr.block_index; + file_pos1 = seek_pos; + } + } + else + return seek_pos; + } +} + +#endif + +#ifdef TAGS + +// 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 accomodate 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. + +static int load_tag (WavpackContext *wpc) +{ + M_Tag *m_tag = &wpc->m_tag; + + CLEAR (*m_tag); + + while (1) { + + // attempt to find an APEv2 tag either at end-of-file or before a ID3v1 tag we found + + if (m_tag->id3_tag.tag_id [0] == 'T') + wpc->reader->set_pos_rel (wpc->wv_in, -(sizeof (APE_Tag_Hdr) + sizeof (ID3_Tag)), SEEK_END); + else + wpc->reader->set_pos_rel (wpc->wv_in, -sizeof (APE_Tag_Hdr), SEEK_END); + + 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)) { + + little_endian_to_native (&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 < (1024 * 1024) && + (m_tag->ape_tag_data = malloc (m_tag->ape_tag_hdr.length)) != NULL) { + + if (m_tag->id3_tag.tag_id [0] == 'T') + m_tag->tag_file_pos = -sizeof (ID3_Tag); + else + m_tag->tag_file_pos = 0; + + m_tag->tag_file_pos -= m_tag->ape_tag_hdr.length + sizeof (APE_Tag_Hdr); + wpc->reader->set_pos_rel (wpc->wv_in, m_tag->tag_file_pos, SEEK_END); + memset (m_tag->ape_tag_data, 0, m_tag->ape_tag_hdr.length); + + 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... + } + + little_endian_to_native (&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 > (1024 * 1024)) { + 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, m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr)) != + m_tag->ape_tag_hdr.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; + } + } + } + + 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; + } + + // look for ID3v1 tag if APEv2 tag not found during first pass + + m_tag->tag_file_pos = -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)) { + CLEAR (*m_tag); + return FALSE; // neither type of tag found + } + } +} + +// 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); +} + +#endif + +#endif + diff --git a/Libraries/WavPack/Files/wputils.h b/Libraries/WavPack/Files/wputils.h index 892a793ee..8a70036d0 100644 --- a/Libraries/WavPack/Files/wputils.h +++ b/Libraries/WavPack/Files/wputils.h @@ -1,163 +1,172 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// wputils.h - -#ifndef WPUTILS_H -#define WPUTILS_H - -// This header file contains all the definitions required to use the -// functions in "wputils.c" to read and write WavPack files and streams. - -#include - -#if defined(_WIN32) && !defined(__MINGW32__) -#include -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; -typedef float float32_t; -#else -#include -#endif - -typedef unsigned char uchar; - -#if !defined(__GNUC__) || defined(WIN32) -typedef unsigned short ushort; -typedef unsigned int uint; -#endif - -///////////////////////// WavPack Configuration /////////////////////////////// - -// This external structure is used during encode to provide configuration to -// the encoding engine and during decoding to provide fle information back to -// the higher level functions. Not all fields are used in both modes. - -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; - uchar md5_checksum [16], md5_read; - int num_tag_strings; - char **tag_strings; -} WavpackConfig; - -#define CONFIG_HYBRID_FLAG 8 // hybrid mode -#define CONFIG_JOINT_STEREO 0x10 // joint stereo -#define CONFIG_HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) -#define CONFIG_FAST_FLAG 0x200 // fast mode -#define CONFIG_HIGH_FLAG 0x800 // high quality mode -#define CONFIG_BITRATE_KBPS 0x2000 // bitrate is kbps, not bits / sample -#define CONFIG_SHAPE_OVERRIDE 0x8000 // shaping mode specified -#define CONFIG_JOINT_OVERRIDE 0x10000 // joint-stereo mode specified -#define CONFIG_CREATE_WVC 0x80000 // create correction file -#define CONFIG_OPTIMIZE_WVC 0x100000 // maximize bybrid compression -#define CONFIG_CALC_NOISE 0x800000 // calc noise in hybrid mode -#define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode -#define CONFIG_SKIP_WVX 0x4000000 // no wvx stream w/ floats & big ints - -////////////// Callbacks used for reading & writing WavPack streams ////////// - -typedef struct { - int32_t (*read_bytes)(void *id, void *data, int32_t bcount); - uint32_t (*get_pos)(void *id); - int (*set_pos_abs)(void *id, uint32_t pos); - int (*set_pos_rel)(void *id, int32_t delta, int mode); - int (*push_back_byte)(void *id, int c); - uint32_t (*get_length)(void *id); - int (*can_seek)(void *id); -} stream_reader; - -typedef int (*blockout)(void *id, void *data, int32_t bcount); - -//////////////////////// function prototypes and macros ////////////////////// - -typedef void WavpackContext; - -#ifdef __cplusplus -extern "C" { -#endif - -WavpackContext *WavpackOpenFileInputEx (stream_reader *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 - -int WavpackGetMode (WavpackContext *wpc); - -#define MODE_WVC 0x1 -#define MODE_LOSSLESS 0x2 -#define MODE_HYBRID 0x4 -#define MODE_FLOAT 0x8 -#define MODE_VALID_TAG 0x10 -#define MODE_HIGH 0x20 -#define MODE_FAST 0x40 -#define MODE_EXTRA 0x80 -#define MODE_APETAG 0x100 -#define MODE_SFX 0x200 - -int WavpackGetVersion (WavpackContext *wpc); -uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples); -uint32_t WavpackGetNumSamples (WavpackContext *wpc); -uint32_t WavpackGetSampleIndex (WavpackContext *wpc); -int WavpackGetNumErrors (WavpackContext *wpc); -int WavpackLossyBlocks (WavpackContext *wpc); -int WavpackSeekSample (WavpackContext *wpc, uint32_t sample); -WavpackContext *WavpackCloseFile (WavpackContext *wpc); -uint32_t WavpackGetSampleRate (WavpackContext *wpc); -int WavpackGetBitsPerSample (WavpackContext *wpc); -int WavpackGetBytesPerSample (WavpackContext *wpc); -int WavpackGetNumChannels (WavpackContext *wpc); -int WavpackGetReducedChannels (WavpackContext *wpc); -int WavpackGetFloatNormExp (WavpackContext *wpc); -int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]); -uint32_t WavpackGetWrapperBytes (WavpackContext *wpc); -uchar *WavpackGetWrapperData (WavpackContext *wpc); -void WavpackFreeWrapper (WavpackContext *wpc); -double WavpackGetProgress (WavpackContext *wpc); -uint32_t WavpackGetFileSize (WavpackContext *wpc); -double WavpackGetRatio (WavpackContext *wpc); -double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc); -double WavpackGetInstantBitrate (WavpackContext *wpc); -int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size); -int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value); -int WavpackWriteTag (WavpackContext *wpc); - - -WavpackContext *WavpackOpenFileOutput (blockout blockout, void *wv_id, void *wvc_id); -int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples); -int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount); -int WavpackStoreMD5Sum (WavpackContext *wpc, uchar data [16]); -int WavpackPackInit (WavpackContext *wpc); -int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count); -int WavpackFlushSamples (WavpackContext *wpc); -void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block); -void *WavpackGetWrapperLocation (void *first_block); - -// this function is not actually in wputils.c, but is generally useful - -void float_normalize (int32_t *values, int32_t num_values, int delta_exp); - -#ifdef __cplusplus -} -#endif - -#endif +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wputils.h + +#ifndef WPUTILS_H +#define WPUTILS_H + +// This header file contains all the definitions required to use the +// functions in "wputils.c" to read and write WavPack files and streams. + +#include + +#if defined(_WIN32) && !defined(__MINGW32__) +#include +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; +typedef float float32_t; +#else +#include +#endif + +typedef unsigned char uchar; + +#if !defined(__GNUC__) || defined(WIN32) +typedef unsigned short ushort; +typedef unsigned int uint; +#endif + +///////////////////////// WavPack Configuration /////////////////////////////// + +// This external structure is used during encode to provide configuration to +// the encoding engine and during decoding to provide fle information back to +// the higher level functions. Not all fields are used in both modes. + +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; + uchar md5_checksum [16], md5_read; + int num_tag_strings; + char **tag_strings; +} WavpackConfig; + +#define CONFIG_HYBRID_FLAG 8 // hybrid mode +#define CONFIG_JOINT_STEREO 0x10 // joint stereo +#define CONFIG_HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) +#define CONFIG_FAST_FLAG 0x200 // fast mode +#define CONFIG_HIGH_FLAG 0x800 // high quality mode +#define CONFIG_BITRATE_KBPS 0x2000 // bitrate is kbps, not bits / sample +#define CONFIG_SHAPE_OVERRIDE 0x8000 // shaping mode specified +#define CONFIG_JOINT_OVERRIDE 0x10000 // joint-stereo mode specified +#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_CALC_NOISE 0x800000 // calc noise in hybrid mode +#define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode +#define CONFIG_SKIP_WVX 0x4000000 // no wvx stream w/ floats & big ints +#define CONFIG_MD5_CHECKSUM 0x8000000 // store MD5 signature + +////////////// Callbacks used for reading & writing WavPack streams ////////// + +typedef struct { + int32_t (*read_bytes)(void *id, void *data, int32_t bcount); + uint32_t (*get_pos)(void *id); + int (*set_pos_abs)(void *id, uint32_t pos); + int (*set_pos_rel)(void *id, int32_t delta, int mode); + int (*push_back_byte)(void *id, int c); + uint32_t (*get_length)(void *id); + int (*can_seek)(void *id); + + // this callback is for writing edited tags only + int32_t (*write_bytes)(void *id, void *data, int32_t bcount); +} WavpackStreamReader; + +typedef int (*WavpackBlockOutput)(void *id, void *data, int32_t bcount); + +//////////////////////// function prototypes and macros ////////////////////// + +typedef void WavpackContext; + +#ifdef __cplusplus +extern "C" { +#endif + +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 + +int WavpackGetMode (WavpackContext *wpc); + +#define MODE_WVC 0x1 +#define MODE_LOSSLESS 0x2 +#define MODE_HYBRID 0x4 +#define MODE_FLOAT 0x8 +#define MODE_VALID_TAG 0x10 +#define MODE_HIGH 0x20 +#define MODE_FAST 0x40 +#define MODE_EXTRA 0x80 +#define MODE_APETAG 0x100 +#define MODE_SFX 0x200 + +int WavpackGetVersion (WavpackContext *wpc); +uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples); +uint32_t WavpackGetNumSamples (WavpackContext *wpc); +uint32_t WavpackGetSampleIndex (WavpackContext *wpc); +int WavpackGetNumErrors (WavpackContext *wpc); +int WavpackLossyBlocks (WavpackContext *wpc); +int WavpackSeekSample (WavpackContext *wpc, uint32_t sample); +WavpackContext *WavpackCloseFile (WavpackContext *wpc); +uint32_t WavpackGetSampleRate (WavpackContext *wpc); +int WavpackGetBitsPerSample (WavpackContext *wpc); +int WavpackGetBytesPerSample (WavpackContext *wpc); +int WavpackGetNumChannels (WavpackContext *wpc); +int WavpackGetReducedChannels (WavpackContext *wpc); +int WavpackGetFloatNormExp (WavpackContext *wpc); +int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]); +uint32_t WavpackGetWrapperBytes (WavpackContext *wpc); +uchar *WavpackGetWrapperData (WavpackContext *wpc); +void WavpackFreeWrapper (WavpackContext *wpc); +double WavpackGetProgress (WavpackContext *wpc); +uint32_t WavpackGetFileSize (WavpackContext *wpc); +double WavpackGetRatio (WavpackContext *wpc); +double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc); +double WavpackGetInstantBitrate (WavpackContext *wpc); +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 WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize); +int WavpackDeleteTagItem (WavpackContext *wpc, const char *item); +int WavpackWriteTag (WavpackContext *wpc); + + +WavpackContext *WavpackOpenFileOutput (WavpackBlockOutput blockout, void *wv_id, void *wvc_id); +int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples); +int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount); +int WavpackStoreMD5Sum (WavpackContext *wpc, uchar data [16]); +int WavpackPackInit (WavpackContext *wpc); +int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count); +int WavpackFlushSamples (WavpackContext *wpc); +void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block); +void *WavpackGetWrapperLocation (void *first_block, uint32_t *size); + +// this function is not actually in wputils.c, but is generally useful + +void float_normalize (int32_t *values, int32_t num_values, int delta_exp); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Libraries/WavPack/Files/wvunpack.c b/Libraries/WavPack/Files/wvunpack.c index d4e776de5..a30b51d0e 100644 --- a/Libraries/WavPack/Files/wvunpack.c +++ b/Libraries/WavPack/Files/wvunpack.c @@ -1,926 +1,1098 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2005 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// wvunpack.c - -// This is the main module for the WavPack command-line decompressor. - -#if defined(WIN32) -#include -#include -#else -#include -#include -#if defined (__GNUC__) -#include -#include -#endif -#endif - -#ifdef __BORLANDC__ -#include -#elif defined(__GNUC__) && !defined(WIN32) -#include -#else -#include -#endif - -#include -#include -#include -#include - -#include "wavpack.h" -#include "md5.h" - -#ifdef DEBUG_ALLOC -#define malloc malloc_db -#define realloc realloc_db -#define free free_db -void *malloc_db (uint32_t size); -void *realloc_db (void *ptr, uint32_t size); -void free_db (void *ptr); -int32_t dump_alloc (void); -static char *strdup (const char *s) - { char *d = malloc (strlen (s) + 1); return strcpy (d, s); } -#endif - -///////////////////////////// local variable storage ////////////////////////// - -static const char *sign_on = "\n" -" WVUNPACK Hybrid Lossless Wavefile Decompressor %s Version %s %s\n" -" Copyright (c) 1998 - 2005 Conifer Software. All Rights Reserved.\n\n"; - -static const char *usage = -" Usage: WVUNPACK [-options] [@]infile[.wv]|- [[@]outfile[.wav]|outpath|-]\n" -" (infile may contain wildcards: ?,*)\n\n" -" Options: -d = delete source file if successful (use with caution!)\n" -" -i = ignore .wvc file (forces hybrid lossy decompression)\n" -" -m = calculate and display MD5 signature; verify if lossless\n" -" -q = quiet (keep console output to a minimum)\n" -" -r = force raw audio decode (skip RIFF headers & trailers)\n" -" -s = display summary information only to stdout (no decode)\n" -#if defined (WIN32) -" -t = copy input file's time stamp to output file(s)\n" -#endif -" -v = verify source data only (no output file created)\n" -" -y = yes to overwrite warning (use with caution!)\n\n" -" Web: Visit www.wavpack.com for latest version and info\n"; - -static char overwrite_all = 0, delete_source = 0, raw_decode = 0, summary = 0, - ignore_wvc = 0, quiet_mode = 0, calc_md5 = 0, copy_time = 0; - -static int num_files, file_index, outbuf_k; - -/////////////////////////// local function declarations /////////////////////// - -static int unpack_file (char *infilename, char *outfilename); -static void display_progress (double file_progress); - -#define NO_ERROR 0L -#define SOFT_ERROR 1 -#define HARD_ERROR 2 - -////////////////////////////////////////////////////////////////////////////// -// The "main" function for the command-line WavPack decompressor. // -////////////////////////////////////////////////////////////////////////////// - -int main (argc, argv) int argc; char **argv; -{ - int verify_only = 0, usage_error = 0, filelist = 0, add_extension = 0; - char *infilename = NULL, *outfilename = NULL; - char outpath, **matches = NULL; - int result, i; - -#ifdef __BORLANDC__ - struct ffblk ffblk; -#elif defined(WIN32) - struct _finddata_t _finddata_t; -#else - glob_t globs; - struct stat fstats; -#endif - - // loop through command-line arguments - - while (--argc) { -#if defined (WIN32) - if ((**++argv == '-' || **argv == '/') && (*argv)[1]) -#else - if ((**++argv == '-') && (*argv)[1]) -#endif - while (*++*argv) - switch (**argv) { - case 'Y': case 'y': - overwrite_all = 1; - break; - - case 'D': case 'd': - delete_source = 1; - break; -#if defined (WIN32) - case 'T': case 't': - copy_time = 1; - break; -#endif - case 'V': case 'v': - verify_only = 1; - break; - - case 'S': case 's': - summary = 1; - break; - - case 'K': case 'k': - outbuf_k = strtol (++*argv, argv, 10); - --*argv; - break; - - case 'M': case 'm': - calc_md5 = 1; - break; - - case 'R': case 'r': - raw_decode = 1; - break; - - case 'Q': case 'q': - quiet_mode = 1; - break; - - case 'I': case 'i': - ignore_wvc = 1; - break; - - default: - error_line ("illegal option: %c !", **argv); - usage_error = 1; - } - else { - if (!infilename) { - infilename = malloc (strlen (*argv) + PATH_MAX); - strcpy (infilename, *argv); - } - else if (!outfilename) { - outfilename = malloc (strlen (*argv) + PATH_MAX); - strcpy (outfilename, *argv); - } - else { - error_line ("extra unknown argument: %s !", *argv); - usage_error = 1; - } - } - } - - // check for various command-line argument problems - - if (verify_only && delete_source) { - error_line ("can't delete in verify mode!"); - delete_source = 0; - } - - if (verify_only && outfilename) { - error_line ("outfile specification and verify mode are incompatible!"); - usage_error = 1; - } - - if (!quiet_mode && !usage_error) - fprintf (stderr, sign_on, VERSION_OS, VERSION_STR, DATE_STR); - - if (!infilename) { - printf ("%s", usage); - return 0; - } - - if (usage_error) { - free (infilename); - return 0; - } - - setup_break (); - - // If the infile specification begins with a '@', then it actually points - // to a file that contains the names of the files to be converted. This - // was included for use by Wim Speekenbrink's frontends, but could be used - // for other purposes. - - if (infilename [0] == '@') { - FILE *list = fopen (infilename+1, "rt"); - int c; - - if (list == NULL) { - error_line ("file %s not found!", infilename+1); - free(infilename); - return 1; - } - - while ((c = getc (list)) != EOF) { - - while (c == '\n') - c = getc (list); - - if (c != EOF) { - char *fname = malloc (PATH_MAX); - int ci = 0; - - do - fname [ci++] = c; - while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); - - fname [ci++] = '\0'; - matches = realloc (matches, ++num_files * sizeof (*matches)); - matches [num_files - 1] = realloc (fname, ci); - } - } - - fclose (list); - free (infilename); - infilename = NULL; - filelist = 1; - } - else if (*infilename != '-') { // skip this if infile is stdin (-) - if (!filespec_ext (infilename)) - strcat (infilename, ".wv"); - -#ifdef NO_WILDCARDS - matches = malloc (sizeof (*matches)); - matches [num_files++] = infilename; - filelist = 1; -#else - // search for and store any filenames that match the user supplied spec - -#ifdef __BORLANDC__ - if (findfirst (infilename, &ffblk, 0) == 0) { - do { - matches = realloc (matches, ++num_files * sizeof (*matches)); - matches [num_files - 1] = strdup (ffblk.ff_name); - } while (findnext (&ffblk) == 0); - } -#elif defined (WIN32) - if ((i = _findfirst (infilename, &_finddata_t)) != -1L) { - do { - if (!(_finddata_t.attrib & _A_SUBDIR)) { - matches = realloc (matches, ++num_files * sizeof (*matches)); - matches [num_files - 1] = strdup (_finddata_t.name); - } - } while (_findnext (i, &_finddata_t) == 0); - - _findclose (i); - } -#else - i = 0; - if (glob(infilename, 0, NULL, &globs) == 0 && globs.gl_pathc > 0) { - do { - if (stat(globs.gl_pathv[i], &fstats) == 0 && !(fstats.st_mode & S_IFDIR)) { - matches = realloc (matches, ++num_files * sizeof (*matches)); - matches [num_files - 1] = strdup (globs.gl_pathv[i]); - } - } while (i++ < globs.gl_pathc); - } - globfree(&globs); -#endif -#endif - } - else { // handle case of stdin (-) - matches = malloc (sizeof (*matches)); - matches [num_files++] = infilename; - } - - // If the outfile specification begins with a '@', then it actually points - // to a file that contains the output specification. This was included for - // use by Wim Speekenbrink's frontends because certain filenames could not - // be passed on the command-line, but could be used for other purposes. - - if (outfilename && outfilename [0] == '@') { - FILE *list = fopen (outfilename+1, "rt"); - int c; - - if (list == NULL) { - error_line ("file %s not found!", outfilename+1); - free(outfilename); - return 1; - } - - while ((c = getc (list)) == '\n'); - - if (c != EOF) { - int ci = 0; - - do - outfilename [ci++] = c; - while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); - - outfilename [ci] = '\0'; - } - else { - error_line ("output spec file is empty!"); - free(outfilename); - fclose (list); - return 1; - } - - fclose (list); - } - - // if we found any files to process, this is where we start - - if (num_files) { - int soft_errors = 0; - - if (outfilename && *outfilename != '-') { - outpath = (filespec_path (outfilename) != NULL); - - if (num_files > 1 && !outpath) { - error_line ("%s is not a valid output path", outfilename); - free(outfilename); - return 1; - } - } - else - outpath = 0; - - add_extension = !outfilename || outpath || !filespec_ext (outfilename); - - // loop through and process files in list - - for (file_index = 0; file_index < num_files; ++file_index) { - if (check_break ()) - break; - - // get input filename from list - - if (filelist) - infilename = matches [file_index]; - else if (*infilename != '-') { - *filespec_name (infilename) = '\0'; - strcat (infilename, matches [file_index]); - } - - // generate output filename - - if (outpath) { - strcat (outfilename, filespec_name (matches [file_index])); - - if (filespec_ext (outfilename)) - *filespec_ext (outfilename) = '\0'; - } - else if (!outfilename) { - outfilename = malloc (strlen (infilename) + 10); - strcpy (outfilename, infilename); - - if (filespec_ext (outfilename)) - *filespec_ext (outfilename) = '\0'; - } - - if (outfilename && *outfilename != '-' && add_extension) - strcat (outfilename, raw_decode ? ".raw" : ".wav"); - - if (num_files > 1) - fprintf (stderr, "\n%s:\n", infilename); - - result = unpack_file (infilename, verify_only ? NULL : outfilename); - - if (result == HARD_ERROR) - break; - else if (result == SOFT_ERROR) - ++soft_errors; - - // clean up in preparation for potentially another file - - if (outpath) - *filespec_name (outfilename) = '\0'; - else if (*outfilename != '-') { - free (outfilename); - outfilename = NULL; - } - - free (matches [file_index]); - } - - if (num_files > 1) { - if (soft_errors) - fprintf (stderr, "\n **** warning: errors occurred in %d of %d files! ****\n", soft_errors, num_files); - else if (!quiet_mode) - fprintf (stderr, "\n **** %d files successfully processed ****\n", num_files); - } - - free (matches); - } - else - error_line (filespec_wild (infilename) ? "nothing to do!" : - "file %s not found!", infilename); - - if (outfilename) - free(outfilename); - -#ifdef DEBUG_ALLOC - error_line ("malloc_count = %d", dump_alloc ()); -#endif - - return 0; -} - -// Unpack the specified WavPack input file into the specified output file name. -// This function uses the library routines provided in wputils.c to do all -// unpacking. This function takes care of reformatting the data (which is -// returned in native-endian longs) to the standard little-endian format. This -// function also handles optionally calculating and displaying the MD5 sum of -// the resulting audio data and verifying the sum if a sum was stored in the -// source and lossless compression is used. - -static uchar *format_samples (int bps, uchar *dst, int32_t *src, uint32_t samcnt); -static void dump_summary (WavpackContext *wpc, char *name, FILE *dst); - -extern int delta_blocks [8]; - -static int unpack_file (char *infilename, char *outfilename) -{ - int result = NO_ERROR, md5_diff = FALSE, open_flags = 0, bytes_per_sample, num_channels, wvc_mode, bps; - uint32_t outfile_length, output_buffer_size, bcount, total_unpacked_samples = 0; - uchar *output_buffer = NULL, *output_pointer = NULL; - double dtime, progress = -1.0; - MD5_CTX md5_context; - WavpackContext *wpc; - int32_t *temp_buffer; - char error [80]; - FILE *outfile; - -#ifdef __BORLANDC__ - struct time time1, time2; -#elif defined(WIN32) - struct _timeb time1, time2; -#else - struct timeval time1, time2; - struct timezone timez; -#endif - - // use library to open WavPack file - - if (outfilename && !raw_decode) - open_flags |= OPEN_WRAPPER; - - if (raw_decode) - open_flags |= OPEN_STREAMING; - - if (!ignore_wvc) - open_flags |= OPEN_WVC; - - wpc = WavpackOpenFileInput (infilename, error, open_flags, 0); - - if (!wpc) { - error_line (error); - return SOFT_ERROR; - } - - if (calc_md5) - MD5Init (&md5_context); - - wvc_mode = WavpackGetMode (wpc) & MODE_WVC; - num_channels = WavpackGetNumChannels (wpc); - bps = WavpackGetBytesPerSample (wpc); - bytes_per_sample = num_channels * bps; - - if (summary) { - dump_summary (wpc, infilename, stdout); - WavpackCloseFile (wpc); - return NO_ERROR; - } - - if (outfilename) { - if (*outfilename != '-') { - - // check the output file for overwrite warning required - - if (!overwrite_all && (outfile = fopen (outfilename, "rb")) != NULL) { - DoCloseHandle (outfile); - fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (outfilename)); - SetConsoleTitle ("overwrite?"); - - switch (yna ()) { - - case 'n': - result = SOFT_ERROR; - break; - - case 'a': - overwrite_all = 1; - } - - if (result != NO_ERROR) { - WavpackCloseFile (wpc); - return result; - } - } - - // open output file for writing - - if ((outfile = fopen (outfilename, "wb")) == NULL) { - error_line ("can't create file %s!", outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - else if (!quiet_mode) - fprintf (stderr, "restoring %s,", FN_FIT (outfilename)); - } - else { // come here to open stdout as destination - - outfile = stdout; -#if defined(WIN32) - setmode (fileno (stdout), O_BINARY); -#endif - - if (!quiet_mode) - fprintf (stderr, "unpacking %s%s to stdout,", *infilename == '-' ? - "stdin" : FN_FIT (infilename), wvc_mode ? " (+.wvc)" : ""); - } - - if (outbuf_k) - output_buffer_size = outbuf_k * 1024; - else - output_buffer_size = 1024 * 256; - - output_pointer = output_buffer = malloc (output_buffer_size); - } - else { // in verify only mode we don't worry about headers - outfile = NULL; - - if (!quiet_mode) - fprintf (stderr, "verifying %s%s,", *infilename == '-' ? "stdin" : - FN_FIT (infilename), wvc_mode ? " (+.wvc)" : ""); - } - -#ifdef __BORLANDC__ - gettime (&time1); -#elif defined(WIN32) - _ftime (&time1); -#else - gettimeofday(&time1,&timez); -#endif - - if (WavpackGetWrapperBytes (wpc)) { - if (outfile && (!DoWriteFile (outfile, WavpackGetWrapperData (wpc), WavpackGetWrapperBytes (wpc), &bcount) || - bcount != WavpackGetWrapperBytes (wpc))) { - error_line ("can't write .WAV data, disk probably full!"); - DoTruncateFile (outfile); - result = HARD_ERROR; - } - - WavpackFreeWrapper (wpc); - } - - temp_buffer = malloc (4096L * num_channels * 4); - - while (result == NO_ERROR) { - uint32_t samples_to_unpack, samples_unpacked; - - if (output_buffer) { - samples_to_unpack = (output_buffer_size - (output_pointer - output_buffer)) / bytes_per_sample; - - if (samples_to_unpack > 4096) - samples_to_unpack = 4096; - } - else - samples_to_unpack = 4096; - - samples_unpacked = WavpackUnpackSamples (wpc, temp_buffer, samples_to_unpack); - total_unpacked_samples += samples_unpacked; - - if (output_buffer) { - if (samples_unpacked) - output_pointer = format_samples (bps, output_pointer, temp_buffer, samples_unpacked * num_channels); - - if (!samples_unpacked || (output_buffer_size - (output_pointer - output_buffer)) < bytes_per_sample) { - if (!DoWriteFile (outfile, output_buffer, output_pointer - output_buffer, &bcount) || - bcount != output_pointer - output_buffer) { - error_line ("can't write .WAV data, disk probably full!"); - DoTruncateFile (outfile); - result = HARD_ERROR; - break; - } - - output_pointer = output_buffer; - } - } - - if (calc_md5 && samples_unpacked) { - format_samples (bps, (uchar *) temp_buffer, temp_buffer, samples_unpacked * num_channels); - MD5Update (&md5_context, temp_buffer, bps * samples_unpacked * num_channels); - } - - if (!samples_unpacked) - break; - - if (check_break ()) { - fprintf (stderr, "^C\n"); - DoTruncateFile (outfile); - result = SOFT_ERROR; - break; - } - - if (WavpackGetProgress (wpc) != -1.0 && - progress != floor (WavpackGetProgress (wpc) * 100.0 + 0.5)) { - int nobs = progress == -1.0; - - progress = WavpackGetProgress (wpc); - display_progress (progress); - progress = floor (progress * 100.0 + 0.5); - - if (!quiet_mode) - fprintf (stderr, "%s%3d%% done...", - nobs ? " " : "\b\b\b\b\b\b\b\b\b\b\b\b", (int) progress); - } - } - - free (temp_buffer); - - if (output_buffer) - free (output_buffer); - -if (0) { -int i; -for (i = 0; i < 8; ++i) - error_line ("delta = %d, count = %d", i, delta_blocks [i]); -} - - if (!check_break () && calc_md5) { - char md5_string1 [] = "00000000000000000000000000000000"; - char md5_string2 [] = "00000000000000000000000000000000"; - uchar md5_original [16], md5_unpacked [16]; - int i; - - MD5Final (md5_unpacked, &md5_context); - - if (WavpackGetMD5Sum (wpc, md5_original)) { - - for (i = 0; i < 16; ++i) - sprintf (md5_string1 + (i * 2), "%02x", md5_original [i]); - - error_line ("original md5: %s", md5_string1); - - if (memcmp (md5_unpacked, md5_original, 16)) - md5_diff = TRUE; - } - - for (i = 0; i < 16; ++i) - sprintf (md5_string2 + (i * 2), "%02x", md5_unpacked [i]); - - error_line ("unpacked md5: %s", md5_string2); - } - - if (WavpackGetWrapperBytes (wpc)) { - if (outfile && result == NO_ERROR && - (!DoWriteFile (outfile, WavpackGetWrapperData (wpc), WavpackGetWrapperBytes (wpc), &bcount) || - bcount != WavpackGetWrapperBytes (wpc))) { - error_line ("can't write .WAV data, disk probably full!"); - DoTruncateFile (outfile); - result = HARD_ERROR; - } - - WavpackFreeWrapper (wpc); - } - - // if we are not just in verify only mode, grab the size of the output - // file and close the file - - if (outfile != NULL) { - fflush (outfile); - outfile_length = DoGetFileSize (outfile); - - if (!DoCloseHandle (outfile)) { - error_line ("can't close file!"); - result = SOFT_ERROR; - } - - if (outfilename && *outfilename != '-' && !outfile_length) - DoDeleteFile (outfilename); - } - -#if defined (WIN32) - if (result == NO_ERROR && copy_time && outfilename && - !copy_timestamp (infilename, outfilename)) - error_line ("failure copying time stamp!"); -#endif - - if (result == NO_ERROR && WavpackGetNumSamples (wpc) != (uint32_t) -1 && - total_unpacked_samples != WavpackGetNumSamples (wpc)) { - error_line ("incorrect number of samples!"); - result = SOFT_ERROR; - } - - if (result == NO_ERROR && WavpackGetNumErrors (wpc)) { - error_line ("crc errors detected in %d block(s)!", WavpackGetNumErrors (wpc)); - result = SOFT_ERROR; - } - else if (result == NO_ERROR && md5_diff && (WavpackGetMode (wpc) & MODE_LOSSLESS)) { - error_line ("MD5 signatures should match, but do not!"); - result = SOFT_ERROR; - } - - // Compute and display the time consumed along with some other details of - // the unpacking operation (assuming there was no error). - -#ifdef __BORLANDC__ - gettime (&time2); - dtime = time2.ti_sec * 100.0 + time2.ti_hund + time2.ti_min * 6000.0 + time2.ti_hour * 360000.00; - dtime -= time1.ti_sec * 100.0 + time1.ti_hund + time1.ti_min * 6000.0 + time1.ti_hour * 360000.00; - - if ((dtime /= 100.0) < 0.0) - dtime += 86400.0; -#elif defined(WIN32) - _ftime (&time2); - dtime = time2.time + time2.millitm / 1000.0; - dtime -= time1.time + time1.millitm / 1000.0; -#else - gettimeofday(&time2,&timez); - dtime = time2.tv_sec + time2.tv_usec / 1000000.0; - dtime -= time1.tv_sec + time1.tv_usec / 1000000.0; -#endif - - if (result == NO_ERROR && !quiet_mode) { - char *file, *fext, *oper, *cmode, cratio [16] = ""; - - if (outfilename && *outfilename != '-') { - file = FN_FIT (outfilename); - fext = ""; - oper = "restored"; - } - else { - file = (*infilename == '-') ? "stdin" : FN_FIT (infilename); - fext = wvc_mode ? " (+.wvc)" : ""; - oper = outfilename ? "unpacked" : "verified"; - } - - if (WavpackGetMode (wpc) & MODE_LOSSLESS) { - cmode = "lossless"; - - if (WavpackGetRatio (wpc) != 0.0) - sprintf (cratio, ", %.2f%%", 100.0 - WavpackGetRatio (wpc) * 100.0); - } - else { - cmode = "lossy"; - - if (WavpackGetAverageBitrate (wpc, TRUE) != 0.0) - sprintf (cratio, ", %d kbps", (int) (WavpackGetAverageBitrate (wpc, TRUE) / 1000.0)); - } - - error_line ("%s %s%s in %.2f secs (%s%s)", oper, file, fext, dtime, cmode, cratio); - } - - WavpackCloseFile (wpc); - - if (result == NO_ERROR && delete_source) { - error_line ("%s source file %s", DoDeleteFile (infilename) ? - "deleted" : "can't delete", infilename); - - if (wvc_mode) { - char in2filename [PATH_MAX]; - - strcpy (in2filename, infilename); - strcat (in2filename, "c"); - - error_line ("%s source file %s", DoDeleteFile (in2filename) ? - "deleted" : "can't delete", in2filename); - } - } - - return result; -} - -// Reformat samples from longs in processor's native endian mode to -// little-endian data with (possibly) less than 4 bytes / sample. - -static uchar *format_samples (int bps, uchar *dst, int32_t *src, uint32_t samcnt) -{ - int32_t temp; - - switch (bps) { - - case 1: - while (samcnt--) - *dst++ = *src++ + 128; - - break; - - case 2: - while (samcnt--) { - *dst++ = (uchar) (temp = *src++); - *dst++ = (uchar) (temp >> 8); - } - - break; - - case 3: - while (samcnt--) { - *dst++ = (uchar) (temp = *src++); - *dst++ = (uchar) (temp >> 8); - *dst++ = (uchar) (temp >> 16); - } - - break; - - case 4: - while (samcnt--) { - *dst++ = (uchar) (temp = *src++); - *dst++ = (uchar) (temp >> 8); - *dst++ = (uchar) (temp >> 16); - *dst++ = (uchar) (temp >> 24); - } - - break; - } - - return dst; -} - -static void dump_summary (WavpackContext *wpc, char *name, FILE *dst) -{ - int num_channels = WavpackGetNumChannels (wpc); - uchar md5_sum [16], modes [80]; - - fprintf (dst, "\n"); - - if (name && *name != '-') { - fprintf (dst, "file name: %s%s\n", name, (WavpackGetMode (wpc) & MODE_WVC) ? " (+wvc)" : ""); - fprintf (dst, "file size: %lu bytes\n", WavpackGetFileSize (wpc)); - } - - fprintf (dst, "source: %d-bit %s at %ld Hz\n", WavpackGetBitsPerSample (wpc), - (WavpackGetMode (wpc) & MODE_FLOAT) ? "floats" : "ints", - WavpackGetSampleRate (wpc)); - - fprintf (dst, "channels: %d (%s)\n", num_channels, - num_channels > 2 ? "multichannel" : (num_channels == 1 ? "mono" : "stereo")); - - if (WavpackGetNumSamples (wpc) != (uint32_t) -1) { - double seconds = (double) WavpackGetNumSamples (wpc) / WavpackGetSampleRate (wpc); - int minutes = (int) floor (seconds / 60.0); - int hours = (int) floor (seconds / 3600.0); - - seconds -= minutes * 60.0; - minutes -= hours * 60.0; - - fprintf (dst, "duration: %d:%02d:%0.2f\n", hours, minutes, seconds); - } - - modes [0] = 0; - - if (WavpackGetMode (wpc) & MODE_HYBRID) - strcat (modes, "hybrid "); - - strcat (modes, (WavpackGetMode (wpc) & MODE_LOSSLESS) ? "lossless" : "lossy"); - - if (WavpackGetMode (wpc) & MODE_FAST) - strcat (modes, ", fast"); - else if (WavpackGetMode (wpc) & MODE_HIGH) - strcat (modes, ", high"); - - if (WavpackGetMode (wpc) & MODE_EXTRA) - strcat (modes, ", extra"); - - if (WavpackGetMode (wpc) & MODE_SFX) - strcat (modes, ", sfx"); - - fprintf (dst, "modalities: %s\n", modes); - - if (WavpackGetRatio (wpc) != 0.0) { - fprintf (dst, "compression: %.2f%%\n", 100.0 - (100 * WavpackGetRatio (wpc))); - fprintf (dst, "ave bitrate: %d kbps\n", (int) ((WavpackGetAverageBitrate (wpc, TRUE) + 500.0) / 1000.0)); - - if (WavpackGetMode (wpc) & MODE_WVC) - fprintf (dst, "ave lossy bitrate: %d kbps\n", (int) ((WavpackGetAverageBitrate (wpc, FALSE) + 500.0) / 1000.0)); - } - - if (WavpackGetVersion (wpc)) - fprintf (dst, "encoder version: %d\n", WavpackGetVersion (wpc)); - - if (WavpackGetMD5Sum (wpc, md5_sum)) { - char md5_string [] = "00000000000000000000000000000000"; - int i; - - for (i = 0; i < 16; ++i) - sprintf (md5_string + (i * 2), "%02x", md5_sum [i]); - - fprintf (dst, "original md5: %s\n", md5_string); - } -} - -////////////////////////////////////////////////////////////////////////////// -// This function displays the progress status on the title bar of the DOS // -// window that WavPack is running in. The "file_progress" argument is for // -// the current file only and ranges from 0 - 1; this function takes into // -// account the total number of files to generate a batch progress number. // -////////////////////////////////////////////////////////////////////////////// - -void display_progress (double file_progress) -{ - char title [40]; - - file_progress = (file_index + file_progress) / num_files; - sprintf (title, "%d%% (WvUnpack)", (int) ((file_progress * 100.0) + 0.5)); - SetConsoleTitle (title); -} +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2005 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wvunpack.c + +// This is the main module for the WavPack command-line decompressor. + +#if defined(WIN32) +#include +#include +#else +#include +#include +#include +#include +#if defined (__GNUC__) +#include +#include +#endif +#endif + +#if defined(__GNUC__) && !defined(WIN32) +#include +#else +#include +#endif + +#include +#include +#include +#include + +#include "wavpack.h" +#include "md5.h" + +#ifdef DEBUG_ALLOC +#define malloc malloc_db +#define realloc realloc_db +#define free free_db +void *malloc_db (uint32_t size); +void *realloc_db (void *ptr, uint32_t size); +void free_db (void *ptr); +int32_t dump_alloc (void); +static char *strdup (const char *s) + { char *d = malloc (strlen (s) + 1); return strcpy (d, s); } +#endif + +///////////////////////////// local variable storage ////////////////////////// + +static const char *sign_on = "\n" +" WVUNPACK Hybrid Lossless Audio Decompressor %s Version %s %s\n" +" Copyright (c) 1998 - 2005 Conifer Software. All Rights Reserved.\n\n"; + +static const char *usage = +#if defined (WIN32) +" Usage: WVUNPACK [-options] [@]infile[.wv]|- [[@]outfile[.wav]|outpath|-]\n" +#else +" Usage: WVUNPACK [-options] [@]infile[.wv]|- [...] [-o [@]outfile[.wav]|outpath|-]\n" +#endif +" (infile may contain wildcards: ?,*)\n\n" +" Options: -d = delete source file if successful (use with caution!)\n" +" -i = ignore .wvc file (forces hybrid lossy decompression)\n" +#if defined (WIN32) +" -l = run at low priority (for smoother multitasking)\n" +#endif +" -m = calculate and display MD5 signature; verify if lossless\n" +" -q = quiet (keep console output to a minimum)\n" +#if !defined (WIN32) +" -o FILENAME | PATH = specify output filename or path\n" +#endif +" -r = force raw audio decode (skip RIFF headers & trailers)\n" +" -s = display summary information only to stdout (no decode)\n" +" -ss = display super summary (including tags) to stdout (no decode)\n" +" -t = copy input file's time stamp to output file(s)\n" +" -v = verify source data only (no output file created)\n" +" -y = yes to overwrite warning (use with caution!)\n\n" +" Web: Visit www.wavpack.com for latest version and info\n"; + +// this global is used to indicate the special "debug" mode where extra debug messages +// are displayed and all messages are logged to the file \wavpack.log + +int debug_logging_mode; + +static char overwrite_all = 0, delete_source = 0, raw_decode = 0, summary = 0, + ignore_wvc = 0, quiet_mode = 0, calc_md5 = 0, copy_time = 0; + +static int num_files, file_index, outbuf_k; + +/////////////////////////// local function declarations /////////////////////// + +static int unpack_file (char *infilename, char *outfilename); +static void display_progress (double file_progress); + +#define NO_ERROR 0L +#define SOFT_ERROR 1 +#define HARD_ERROR 2 + +////////////////////////////////////////////////////////////////////////////// +// The "main" function for the command-line WavPack decompressor. // +////////////////////////////////////////////////////////////////////////////// + +int main (argc, argv) int argc; char **argv; +{ + int verify_only = 0, error_count = 0, add_extension = 0, output_spec = 0; + char outpath, **matches = NULL, *outfilename = NULL; + int result, i; + +#if defined(WIN32) + struct _finddata_t _finddata_t; + char selfname [MAX_PATH]; + + if (GetModuleFileName (NULL, selfname, sizeof (selfname)) && filespec_name (selfname) && + strupr (filespec_name (selfname)) && strstr (filespec_name (selfname), "DEBUG")) { + char **argv_t = argv; + int argc_t = argc; + + debug_logging_mode = TRUE; + + while (--argc_t) + error_line ("arg %d: %s", argc - argc_t, *++argv_t); + } +#else + if (filespec_name (*argv)) + if (strstr (filespec_name (*argv), "ebug") || strstr (filespec_name (*argv), "DEBUG")) { + char **argv_t = argv; + int argc_t = argc; + + debug_logging_mode = TRUE; + + while (--argc_t) + error_line ("arg %d: %s", argc - argc_t, *++argv_t); + } +#endif + + // loop through command-line arguments + + while (--argc) { +#if defined (WIN32) + if ((**++argv == '-' || **argv == '/') && (*argv)[1]) +#else + if ((**++argv == '-') && (*argv)[1]) +#endif + while (*++*argv) + switch (**argv) { + case 'Y': case 'y': + overwrite_all = 1; + break; + + case 'D': case 'd': + delete_source = 1; + break; + +#if defined (WIN32) + case 'L': case 'l': + SetPriorityClass (GetCurrentProcess(), IDLE_PRIORITY_CLASS); + break; +#else + case 'O': case 'o': + output_spec = 1; + break; +#endif + case 'T': case 't': + copy_time = 1; + break; + + case 'V': case 'v': + verify_only = 1; + break; + + case 'S': case 's': + ++summary; + break; + + case 'K': case 'k': + outbuf_k = strtol (++*argv, argv, 10); + --*argv; + break; + + case 'M': case 'm': + calc_md5 = 1; + break; + + case 'R': case 'r': + raw_decode = 1; + break; + + case 'Q': case 'q': + quiet_mode = 1; + break; + + case 'I': case 'i': + ignore_wvc = 1; + break; + + default: + error_line ("illegal option: %c !", **argv); + ++error_count; + } + else { +#if defined (WIN32) + if (!num_files) { + matches = realloc (matches, (num_files + 1) * sizeof (*matches)); + matches [num_files] = malloc (strlen (*argv) + 10); + strcpy (matches [num_files], *argv); + + if (*(matches [num_files]) != '-' && *(matches [num_files]) != '@' && + !filespec_ext (matches [num_files])) + strcat (matches [num_files], ".wv"); + + num_files++; + } + else if (!outfilename) { + outfilename = malloc (strlen (*argv) + PATH_MAX); + strcpy (outfilename, *argv); + } + else { + error_line ("extra unknown argument: %s !", *argv); + ++error_count; + } +#else + if (output_spec) { + outfilename = malloc (strlen (*argv) + PATH_MAX); + strcpy (outfilename, *argv); + output_spec = 0; + } + else { + matches = realloc (matches, (num_files + 1) * sizeof (*matches)); + matches [num_files] = malloc (strlen (*argv) + 10); + strcpy (matches [num_files], *argv); + + if (*(matches [num_files]) != '-' && *(matches [num_files]) != '@' && + !filespec_ext (matches [num_files])) + strcat (matches [num_files], ".wv"); + + num_files++; + } +#endif + } + } + + // check for various command-line argument problems + + if (verify_only && delete_source) { + error_line ("can't delete in verify mode!"); + delete_source = 0; + } + + if (verify_only && outfilename) { + error_line ("outfile specification and verify mode are incompatible!"); + ++error_count; + } + + if (!quiet_mode && !error_count) + fprintf (stderr, sign_on, VERSION_OS, VERSION_STR, DATE_STR); + + if (!num_files) { + printf ("%s", usage); + return 1; + } + + if (error_count) + return 1; + + setup_break (); + + for (file_index = 0; file_index < num_files; ++file_index) { + char *infilename = matches [file_index]; + + // If the single infile specification begins with a '@', then it + // actually points to a file that contains the names of the files + // to be converted. This was included for use by Wim Speekenbrink's + // frontends, but could be used for other purposes. + + if (*infilename == '@') { + FILE *list = fopen (infilename+1, "rt"); + int di, c; + + for (di = file_index; di < num_files - 1; di++) + matches [di] = matches [di + 1]; + + file_index--; + num_files--; + + if (list == NULL) { + error_line ("file %s not found!", infilename+1); + free (infilename); + return 1; + } + + while ((c = getc (list)) != EOF) { + + while (c == '\n') + c = getc (list); + + if (c != EOF) { + char *fname = malloc (PATH_MAX); + int ci = 0; + + do + fname [ci++] = c; + while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); + + fname [ci++] = '\0'; + fname = realloc (fname, ci); + matches = realloc (matches, ++num_files * sizeof (*matches)); + + for (di = num_files - 1; di > file_index + 1; di--) + matches [di] = matches [di - 1]; + + matches [++file_index] = fname; + } + } + + fclose (list); + free (infilename); + } +#if defined (WIN32) + else if (filespec_wild (infilename)) { + FILE *list = fopen (infilename+1, "rt"); + int di; + + for (di = file_index; di < num_files - 1; di++) + matches [di] = matches [di + 1]; + + file_index--; + num_files--; + + if ((i = _findfirst (infilename, &_finddata_t)) != -1L) { + do { + if (!(_finddata_t.attrib & _A_SUBDIR)) { + matches = realloc (matches, ++num_files * sizeof (*matches)); + + for (di = num_files - 1; di > file_index + 1; di--) + matches [di] = matches [di - 1]; + + matches [++file_index] = malloc (strlen (infilename) + strlen (_finddata_t.name) + 10); + strcpy (matches [file_index], infilename); + *filespec_name (matches [file_index]) = '\0'; + strcat (matches [file_index], _finddata_t.name); + } + } while (_findnext (i, &_finddata_t) == 0); + + _findclose (i); + } + + free (infilename); + } +#endif + } + + // If the outfile specification begins with a '@', then it actually points + // to a file that contains the output specification. This was included for + // use by Wim Speekenbrink's frontends because certain filenames could not + // be passed on the command-line, but could be used for other purposes. + + if (outfilename && outfilename [0] == '@') { + FILE *list = fopen (outfilename+1, "rt"); + int c; + + if (list == NULL) { + error_line ("file %s not found!", outfilename+1); + free(outfilename); + return 1; + } + + while ((c = getc (list)) == '\n'); + + if (c != EOF) { + int ci = 0; + + do + outfilename [ci++] = c; + while ((c = getc (list)) != '\n' && c != EOF && ci < PATH_MAX); + + outfilename [ci] = '\0'; + } + else { + error_line ("output spec file is empty!"); + free(outfilename); + fclose (list); + return 1; + } + + fclose (list); + } + + // if we found any files to process, this is where we start + + if (num_files) { + if (outfilename && *outfilename != '-') { + outpath = (filespec_path (outfilename) != NULL); + + if (num_files > 1 && !outpath) { + error_line ("%s is not a valid output path", outfilename); + free (outfilename); + return 1; + } + } + else + outpath = 0; + + add_extension = !outfilename || outpath || !filespec_ext (outfilename); + + // loop through and process files in list + + for (file_index = 0; file_index < num_files; ++file_index) { + if (check_break ()) + break; + + // generate output filename + + if (outpath) { + strcat (outfilename, filespec_name (matches [file_index])); + + if (filespec_ext (outfilename)) + *filespec_ext (outfilename) = '\0'; + } + else if (!outfilename) { + outfilename = malloc (strlen (matches [file_index]) + 10); + strcpy (outfilename, matches [file_index]); + + if (filespec_ext (outfilename)) + *filespec_ext (outfilename) = '\0'; + } + + if (outfilename && *outfilename != '-' && add_extension) + strcat (outfilename, raw_decode ? ".raw" : ".wav"); + + if (num_files > 1) + fprintf (stderr, "\n%s:\n", matches [file_index]); + + result = unpack_file (matches [file_index], verify_only ? NULL : outfilename); + + if (result != NO_ERROR) + ++error_count; + + if (result == HARD_ERROR) + break; + + // clean up in preparation for potentially another file + + if (outpath) + *filespec_name (outfilename) = '\0'; + else if (*outfilename != '-') { + free (outfilename); + outfilename = NULL; + } + + free (matches [file_index]); + } + + if (num_files > 1) { + if (error_count) + fprintf (stderr, "\n **** warning: errors occurred in %d of %d files! ****\n", error_count, num_files); + else if (!quiet_mode) + fprintf (stderr, "\n **** %d files successfully processed ****\n", num_files); + } + + free (matches); + } + else { + error_line ("nothing to do!"); + ++error_count; + } + + if (outfilename) + free (outfilename); + +#ifdef DEBUG_ALLOC + error_line ("malloc_count = %d", dump_alloc ()); +#endif + + return error_count ? 1 : 0; +} + +// Unpack the specified WavPack input file into the specified output file name. +// This function uses the library routines provided in wputils.c to do all +// unpacking. This function takes care of reformatting the data (which is +// returned in native-endian longs) to the standard little-endian format. This +// function also handles optionally calculating and displaying the MD5 sum of +// the resulting audio data and verifying the sum if a sum was stored in the +// source and lossless compression is used. + +static uchar *format_samples (int bps, uchar *dst, int32_t *src, uint32_t samcnt); +static void dump_summary (WavpackContext *wpc, char *name, FILE *dst); + +static int unpack_file (char *infilename, char *outfilename) +{ + int result = NO_ERROR, md5_diff = FALSE, open_flags = 0, bytes_per_sample, num_channels, wvc_mode, bps; + uint32_t outfile_length, output_buffer_size, bcount, total_unpacked_samples = 0; + uchar *output_buffer = NULL, *output_pointer = NULL; + double dtime, progress = -1.0; + MD5_CTX md5_context; + WavpackContext *wpc; + int32_t *temp_buffer; + char error [80]; + FILE *outfile; + +#if defined(WIN32) + struct _timeb time1, time2; +#else + struct timeval time1, time2; + struct timezone timez; +#endif + + // use library to open WavPack file + + if (outfilename && !raw_decode) + open_flags |= OPEN_WRAPPER; + + if (raw_decode) + open_flags |= OPEN_STREAMING; + + if (!ignore_wvc) + open_flags |= OPEN_WVC; + + if (summary > 1) + open_flags |= OPEN_TAGS; + + wpc = WavpackOpenFileInput (infilename, error, open_flags, 0); + + if (!wpc) { + error_line (error); + return SOFT_ERROR; + } + + if (calc_md5) + MD5Init (&md5_context); + + wvc_mode = WavpackGetMode (wpc) & MODE_WVC; + num_channels = WavpackGetNumChannels (wpc); + bps = WavpackGetBytesPerSample (wpc); + bytes_per_sample = num_channels * bps; + + if (summary) { + dump_summary (wpc, infilename, stdout); + WavpackCloseFile (wpc); + return NO_ERROR; + } + + if (!WavpackGetWrapperBytes (wpc) && outfilename && !raw_decode) { + error_line ("no wav header, can only decode to raw file (use -r)!"); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + + if (outfilename) { + if (*outfilename != '-') { + + // check the output file for overwrite warning required + + if (!overwrite_all && (outfile = fopen (outfilename, "rb")) != NULL) { + DoCloseHandle (outfile); + fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (outfilename)); + SetConsoleTitle ("overwrite?"); + + switch (yna ()) { + + case 'n': + result = SOFT_ERROR; + break; + + case 'a': + overwrite_all = 1; + } + + if (result != NO_ERROR) { + WavpackCloseFile (wpc); + return result; + } + } + + // open output file for writing + + if ((outfile = fopen (outfilename, "wb")) == NULL) { + error_line ("can't create file %s!", outfilename); + WavpackCloseFile (wpc); + return SOFT_ERROR; + } + else if (!quiet_mode) + fprintf (stderr, "restoring %s,", FN_FIT (outfilename)); + } + else { // come here to open stdout as destination + + outfile = stdout; +#if defined(WIN32) + setmode (fileno (stdout), O_BINARY); +#endif + + if (!quiet_mode) + fprintf (stderr, "unpacking %s%s to stdout,", *infilename == '-' ? + "stdin" : FN_FIT (infilename), wvc_mode ? " (+.wvc)" : ""); + } + + if (outbuf_k) + output_buffer_size = outbuf_k * 1024; + else + output_buffer_size = 1024 * 256; + + output_pointer = output_buffer = malloc (output_buffer_size); + } + else { // in verify only mode we don't worry about headers + outfile = NULL; + + if (!quiet_mode) + fprintf (stderr, "verifying %s%s,", *infilename == '-' ? "stdin" : + FN_FIT (infilename), wvc_mode ? " (+.wvc)" : ""); + } + +#if defined(WIN32) + _ftime (&time1); +#else + gettimeofday(&time1,&timez); +#endif + + if (WavpackGetWrapperBytes (wpc)) { + if (outfile && (!DoWriteFile (outfile, WavpackGetWrapperData (wpc), WavpackGetWrapperBytes (wpc), &bcount) || + bcount != WavpackGetWrapperBytes (wpc))) { + error_line ("can't write .WAV data, disk probably full!"); + DoTruncateFile (outfile); + result = HARD_ERROR; + } + + WavpackFreeWrapper (wpc); + } + + temp_buffer = malloc (4096L * num_channels * 4); + + while (result == NO_ERROR) { + uint32_t samples_to_unpack, samples_unpacked; + + if (output_buffer) { + samples_to_unpack = (output_buffer_size - (output_pointer - output_buffer)) / bytes_per_sample; + + if (samples_to_unpack > 4096) + samples_to_unpack = 4096; + } + else + samples_to_unpack = 4096; + + samples_unpacked = WavpackUnpackSamples (wpc, temp_buffer, samples_to_unpack); + total_unpacked_samples += samples_unpacked; + + if (output_buffer) { + if (samples_unpacked) + output_pointer = format_samples (bps, output_pointer, temp_buffer, samples_unpacked * num_channels); + + if (!samples_unpacked || (output_buffer_size - (output_pointer - output_buffer)) < bytes_per_sample) { + if (!DoWriteFile (outfile, output_buffer, output_pointer - output_buffer, &bcount) || + bcount != output_pointer - output_buffer) { + error_line ("can't write .WAV data, disk probably full!"); + DoTruncateFile (outfile); + result = HARD_ERROR; + break; + } + + output_pointer = output_buffer; + } + } + + if (calc_md5 && samples_unpacked) { + format_samples (bps, (uchar *) temp_buffer, temp_buffer, samples_unpacked * num_channels); + MD5Update (&md5_context, (unsigned char *) temp_buffer, bps * samples_unpacked * num_channels); + } + + if (!samples_unpacked) + break; + + if (check_break ()) { + fprintf (stderr, "^C\n"); + DoTruncateFile (outfile); + result = SOFT_ERROR; + break; + } + + if (WavpackGetProgress (wpc) != -1.0 && + progress != floor (WavpackGetProgress (wpc) * 100.0 + 0.5)) { + int nobs = progress == -1.0; + + progress = WavpackGetProgress (wpc); + display_progress (progress); + progress = floor (progress * 100.0 + 0.5); + + if (!quiet_mode) + fprintf (stderr, "%s%3d%% done...", + nobs ? " " : "\b\b\b\b\b\b\b\b\b\b\b\b", (int) progress); + } + } + + free (temp_buffer); + + if (output_buffer) + free (output_buffer); + + if (!check_break () && calc_md5) { + char md5_string1 [] = "00000000000000000000000000000000"; + char md5_string2 [] = "00000000000000000000000000000000"; + uchar md5_original [16], md5_unpacked [16]; + int i; + + MD5Final (md5_unpacked, &md5_context); + + if (WavpackGetMD5Sum (wpc, md5_original)) { + + for (i = 0; i < 16; ++i) + sprintf (md5_string1 + (i * 2), "%02x", md5_original [i]); + + error_line ("original md5: %s", md5_string1); + + if (memcmp (md5_unpacked, md5_original, 16)) + md5_diff = TRUE; + } + + for (i = 0; i < 16; ++i) + sprintf (md5_string2 + (i * 2), "%02x", md5_unpacked [i]); + + error_line ("unpacked md5: %s", md5_string2); + } + + if (WavpackGetWrapperBytes (wpc)) { + if (outfile && result == NO_ERROR && + (!DoWriteFile (outfile, WavpackGetWrapperData (wpc), WavpackGetWrapperBytes (wpc), &bcount) || + bcount != WavpackGetWrapperBytes (wpc))) { + error_line ("can't write .WAV data, disk probably full!"); + DoTruncateFile (outfile); + result = HARD_ERROR; + } + + WavpackFreeWrapper (wpc); + } + + // if we are not just in verify only mode, grab the size of the output + // file and close the file + + if (outfile != NULL) { + fflush (outfile); + outfile_length = DoGetFileSize (outfile); + + if (!DoCloseHandle (outfile)) { + error_line ("can't close file!"); + result = SOFT_ERROR; + } + + if (outfilename && *outfilename != '-' && !outfile_length) + DoDeleteFile (outfilename); + } + + if (result == NO_ERROR && copy_time && outfilename && + !copy_timestamp (infilename, outfilename)) + error_line ("failure copying time stamp!"); + + if (result == NO_ERROR && WavpackGetNumSamples (wpc) != (uint32_t) -1 && + total_unpacked_samples != WavpackGetNumSamples (wpc)) { + error_line ("incorrect number of samples!"); + result = SOFT_ERROR; + } + + if (result == NO_ERROR && WavpackGetNumErrors (wpc)) { + error_line ("crc errors detected in %d block(s)!", WavpackGetNumErrors (wpc)); + result = SOFT_ERROR; + } + else if (result == NO_ERROR && md5_diff && (WavpackGetMode (wpc) & MODE_LOSSLESS)) { + error_line ("MD5 signatures should match, but do not!"); + result = SOFT_ERROR; + } + + // Compute and display the time consumed along with some other details of + // the unpacking operation (assuming there was no error). + +#if defined(WIN32) + _ftime (&time2); + dtime = time2.time + time2.millitm / 1000.0; + dtime -= time1.time + time1.millitm / 1000.0; +#else + gettimeofday(&time2,&timez); + dtime = time2.tv_sec + time2.tv_usec / 1000000.0; + dtime -= time1.tv_sec + time1.tv_usec / 1000000.0; +#endif + + if (result == NO_ERROR && !quiet_mode) { + char *file, *fext, *oper, *cmode, cratio [16] = ""; + + if (outfilename && *outfilename != '-') { + file = FN_FIT (outfilename); + fext = ""; + oper = "restored"; + } + else { + file = (*infilename == '-') ? "stdin" : FN_FIT (infilename); + fext = wvc_mode ? " (+.wvc)" : ""; + oper = outfilename ? "unpacked" : "verified"; + } + + if (WavpackGetMode (wpc) & MODE_LOSSLESS) { + cmode = "lossless"; + + if (WavpackGetRatio (wpc) != 0.0) + sprintf (cratio, ", %.2f%%", 100.0 - WavpackGetRatio (wpc) * 100.0); + } + else { + cmode = "lossy"; + + if (WavpackGetAverageBitrate (wpc, TRUE) != 0.0) + sprintf (cratio, ", %d kbps", (int) (WavpackGetAverageBitrate (wpc, TRUE) / 1000.0)); + } + + error_line ("%s %s%s in %.2f secs (%s%s)", oper, file, fext, dtime, cmode, cratio); + } + + WavpackCloseFile (wpc); + + if (result == NO_ERROR && delete_source) { + error_line ("%s source file %s", DoDeleteFile (infilename) ? + "deleted" : "can't delete", infilename); + + if (wvc_mode) { + char in2filename [PATH_MAX]; + + strcpy (in2filename, infilename); + strcat (in2filename, "c"); + + error_line ("%s source file %s", DoDeleteFile (in2filename) ? + "deleted" : "can't delete", in2filename); + } + } + + return result; +} + +// Reformat samples from longs in processor's native endian mode to +// little-endian data with (possibly) less than 4 bytes / sample. + +static uchar *format_samples (int bps, uchar *dst, int32_t *src, uint32_t samcnt) +{ + int32_t temp; + + switch (bps) { + + case 1: + while (samcnt--) + *dst++ = *src++ + 128; + + break; + + case 2: + while (samcnt--) { + *dst++ = (uchar) (temp = *src++); + *dst++ = (uchar) (temp >> 8); + } + + break; + + case 3: + while (samcnt--) { + *dst++ = (uchar) (temp = *src++); + *dst++ = (uchar) (temp >> 8); + *dst++ = (uchar) (temp >> 16); + } + + break; + + case 4: + while (samcnt--) { + *dst++ = (uchar) (temp = *src++); + *dst++ = (uchar) (temp >> 8); + *dst++ = (uchar) (temp >> 16); + *dst++ = (uchar) (temp >> 24); + } + + break; + } + + return dst; +} + +static UTF8ToAnsi (char *string, int len); + +static void dump_summary (WavpackContext *wpc, char *name, FILE *dst) +{ + int num_channels = WavpackGetNumChannels (wpc); + uchar md5_sum [16], modes [80]; + + fprintf (dst, "\n"); + + if (name && *name != '-') { + fprintf (dst, "file name: %s%s\n", name, (WavpackGetMode (wpc) & MODE_WVC) ? " (+wvc)" : ""); + fprintf (dst, "file size: %lu bytes\n", WavpackGetFileSize (wpc)); + } + + fprintf (dst, "source: %d-bit %s at %ld Hz\n", WavpackGetBitsPerSample (wpc), + (WavpackGetMode (wpc) & MODE_FLOAT) ? "floats" : "ints", + WavpackGetSampleRate (wpc)); + + fprintf (dst, "channels: %d (%s)\n", num_channels, + num_channels > 2 ? "multichannel" : (num_channels == 1 ? "mono" : "stereo")); + + if (WavpackGetNumSamples (wpc) != (uint32_t) -1) { + double seconds = (double) WavpackGetNumSamples (wpc) / WavpackGetSampleRate (wpc); + int minutes = (int) floor (seconds / 60.0); + int hours = (int) floor (seconds / 3600.0); + + seconds -= minutes * 60.0; + minutes -= hours * 60.0; + + fprintf (dst, "duration: %d:%02d:%05.2f\n", hours, minutes, seconds); + } + + modes [0] = 0; + + if (WavpackGetMode (wpc) & MODE_HYBRID) + strcat (modes, "hybrid "); + + strcat (modes, (WavpackGetMode (wpc) & MODE_LOSSLESS) ? "lossless" : "lossy"); + + if (WavpackGetMode (wpc) & MODE_FAST) + strcat (modes, ", fast"); + else if (WavpackGetMode (wpc) & MODE_HIGH) + strcat (modes, ", high"); + + if (WavpackGetMode (wpc) & MODE_EXTRA) + strcat (modes, ", extra"); + + if (WavpackGetMode (wpc) & MODE_SFX) + strcat (modes, ", sfx"); + + fprintf (dst, "modalities: %s\n", modes); + + if (WavpackGetRatio (wpc) != 0.0) { + fprintf (dst, "compression: %.2f%%\n", 100.0 - (100 * WavpackGetRatio (wpc))); + fprintf (dst, "ave bitrate: %d kbps\n", (int) ((WavpackGetAverageBitrate (wpc, TRUE) + 500.0) / 1000.0)); + + if (WavpackGetMode (wpc) & MODE_WVC) + fprintf (dst, "ave lossy bitrate: %d kbps\n", (int) ((WavpackGetAverageBitrate (wpc, FALSE) + 500.0) / 1000.0)); + } + + if (WavpackGetVersion (wpc)) + fprintf (dst, "encoder version: %d\n", WavpackGetVersion (wpc)); + + if (WavpackGetMD5Sum (wpc, md5_sum)) { + char md5_string [] = "00000000000000000000000000000000"; + int i; + + for (i = 0; i < 16; ++i) + sprintf (md5_string + (i * 2), "%02x", md5_sum [i]); + + fprintf (dst, "original md5: %s\n", md5_string); + } + + if (WavpackGetMode (wpc) & MODE_VALID_TAG) { + int ape_tag = WavpackGetMode (wpc) & MODE_APETAG; + int num_items = WavpackGetNumTagItems (wpc), i; + + fprintf (dst, "%s tag items: %d\n\n", ape_tag ? "APEv2" : "ID3v1", num_items); + + for (i = 0; i < num_items; ++i) { + int item_len, value_len, j; + char *item, *value; + + item_len = WavpackGetTagItemIndexed (wpc, i, NULL, 0); + item = malloc (item_len + 1); + WavpackGetTagItemIndexed (wpc, i, item, item_len + 1); + value_len = WavpackGetTagItem (wpc, item, NULL, 0); + value = malloc (value_len * 2 + 1); + WavpackGetTagItem (wpc, item, value, value_len + 1); + + for (j = 0; j < value_len; ++j) + if (!value [j]) + value [j] = '\\'; + + if (ape_tag) + UTF8ToAnsi (value, value_len * 2); + + if (item_len + value_len + 3 >= 80) + fprintf (dst, "%s =\n%s\n", item, value); + else + fprintf (dst, "%s = %s\n", item, value); + + free (value); + free (item); + } + } +} + +// Convert Unicode UTF-8 string to wide format. UTF-8 string must be NULL +// terminated. Resulting wide string must be able to fit in provided space +// and will also be NULL terminated. The number of characters converted will +// be returned (not counting terminator). + +static int UTF8ToWideChar (const unsigned char *pUTF8, unsigned short *pWide) +{ + int trail_bytes = 0; + int chrcnt = 0; + + while (*pUTF8) { + if (*pUTF8 & 0x80) { + if (*pUTF8 & 0x40) { + if (trail_bytes) { + trail_bytes = 0; + chrcnt++; + } + else { + char temp = *pUTF8; + + while (temp & 0x80) { + trail_bytes++; + temp <<= 1; + } + + pWide [chrcnt] = temp >> trail_bytes--; + } + } + else if (trail_bytes) { + pWide [chrcnt] = (pWide [chrcnt] << 6) | (*pUTF8 & 0x3f); + + if (!--trail_bytes) + chrcnt++; + } + } + else + pWide [chrcnt++] = *pUTF8; + + pUTF8++; + } + + pWide [chrcnt] = 0; + return chrcnt; +} + +// Convert a Unicode UTF-8 format string into its Ansi equivalent. The +// conversion is done in-place so the maximum length of the string buffer must +// be specified because the string may become longer or shorter. If the +// resulting string will not fit in the specified buffer size then it is +// truncated. + +static UTF8ToAnsi (char *string, int len) +{ + int max_chars = strlen (string); +#if defined (WIN32) + unsigned short *temp = malloc ((max_chars + 1) * 2); + int act_chars = UTF8ToWideChar (string, temp); + + while (act_chars) { + memset (string, 0, len); + + if (WideCharToMultiByte (CP_OEMCP, 0, temp, act_chars, string, len - 1, NULL, NULL)) + break; + else + act_chars--; + } + + if (!act_chars) + *string = 0; +#else + char *temp = malloc (len); + char *outp = temp; + char *inp = string; + size_t insize = max_chars; + size_t outsize = len - 1; + int err = 0; + char *old_locale; + + memset(temp, 0, len); + old_locale = setlocale (LC_CTYPE, ""); + iconv_t converter = iconv_open ("", "UTF-8"); + err = iconv (converter, &inp, &insize, &outp, &outsize); + iconv_close (converter); + setlocale (LC_CTYPE, old_locale); + + if (err == -1) { + free(temp); + return; + } + + memmove (string, temp, len); +#endif + free (temp); +} + +////////////////////////////////////////////////////////////////////////////// +// This function displays the progress status on the title bar of the DOS // +// window that WavPack is running in. The "file_progress" argument is for // +// the current file only and ranges from 0 - 1; this function takes into // +// account the total number of files to generate a batch progress number. // +////////////////////////////////////////////////////////////////////////////// + +void display_progress (double file_progress) +{ + char title [40]; + + file_progress = (file_index + file_progress) / num_files; + sprintf (title, "%d%% (WvUnpack)", (int) ((file_progress * 100.0) + 0.5)); + SetConsoleTitle (title); +} diff --git a/Sound/SoundFile/FlacFile.m b/Sound/SoundFile/FlacFile.m index c71d92223..6a2a09ffb 100644 --- a/Sound/SoundFile/FlacFile.m +++ b/Sound/SoundFile/FlacFile.m @@ -86,11 +86,7 @@ void ErrorProc(const FLAC__FileDecoder *decoder, FLAC__StreamDecoderErrorStatus FLAC__file_decoder_process_until_end_of_metadata(decoder); -#ifdef __BIG_ENDIAN__ - isBigEndian = YES; -#else - isBigEndian = NO; -#endif + isBigEndian = hostIsBigEndian(); return YES; } diff --git a/Sound/SoundFile/MPEGFile.mm b/Sound/SoundFile/MPEGFile.mm index f3eef3e54..1b3d2f816 100644 --- a/Sound/SoundFile/MPEGFile.mm +++ b/Sound/SoundFile/MPEGFile.mm @@ -36,11 +36,7 @@ channels = outputFormat.nChannels; bitsPerSample = 16; -#ifdef __BIG_ENDIAN__ - isBigEndian = YES; -#else - isBigEndian = NO; -#endif + isBigEndian = hostIsBigEndian(); long duration; DecMPA_GetDuration(decoder, &duration); diff --git a/Sound/SoundFile/MusepackFile.m b/Sound/SoundFile/MusepackFile.m index d343c4b5e..14d918ca1 100644 --- a/Sound/SoundFile/MusepackFile.m +++ b/Sound/SoundFile/MusepackFile.m @@ -66,11 +66,7 @@ BOOL CanSeekProc(void *data) } // DBLog(@"Ok to go..."); -#ifdef __BIG_ENDIAN__ - isBigEndian = YES; -#else - isBigEndian = NO; -#endif + isBigEndian = hostIsBigEndian(); return YES; } diff --git a/Sound/SoundFile/SoundFile.h b/Sound/SoundFile/SoundFile.h index 6a28b42d4..d056c71cc 100644 --- a/Sound/SoundFile/SoundFile.h +++ b/Sound/SoundFile/SoundFile.h @@ -14,6 +14,14 @@ #import "DBLog.h" +#ifdef __cplusplus +extern "C" { +#endif +BOOL hostIsBigEndian(); +#ifdef __cplusplus +} +#endif + @interface SoundFile : NSObject { UInt16 bitsPerSample; UInt16 channels; diff --git a/Sound/SoundFile/SoundFile.mm b/Sound/SoundFile/SoundFile.mm index d3d73c54d..48dd36b3a 100644 --- a/Sound/SoundFile/SoundFile.mm +++ b/Sound/SoundFile/SoundFile.mm @@ -18,6 +18,17 @@ #import "WavPackFile.h" #import "ShnFile.h" +extern "C" { +BOOL hostIsBigEndian() +{ +#ifdef __BIG_ENDIAN__ + return YES; +#else + return NO; +#endif +} +}; + @implementation SoundFile /*- (void)seek:(unsigned long)position diff --git a/Sound/SoundFile/WavPackFile.m b/Sound/SoundFile/WavPackFile.m index 3270f33ea..b1d458af0 100644 --- a/Sound/SoundFile/WavPackFile.m +++ b/Sound/SoundFile/WavPackFile.m @@ -21,8 +21,10 @@ return NO; channels = WavpackGetNumChannels(wpc); -// bitsPerSample = WavpackGetBitsPerSample(wpc); - bitsPerSample = 32; + bitsPerSample = WavpackGetBitsPerSample(wpc); +// bitsPerSample = 32; + NSLog(@"BYTES PER SAMPLE: %i", WavpackGetBitsPerSample(wpc)); + NSLog(@"BYTES PER SAMPLE: %i", WavpackGetBytesPerSample(wpc)); frequency = WavpackGetSampleRate(wpc); @@ -32,7 +34,7 @@ bitRate = (int)(WavpackGetAverageBitrate(wpc, TRUE)/1000.0); - //isBigEndian = YES; + isBigEndian = hostIsBigEndian(); return YES; } @@ -48,19 +50,18 @@ { int numsamples; int n; + void *sampleBuf = malloc(size*2); - numsamples = size/4/channels; + numsamples = size/(bitsPerSample/8)/channels; // DBLog(@"NUM SAMPLES: %i %i", numsamples, size); - n = WavpackUnpackSamples(wpc, buf, numsamples); + n = WavpackUnpackSamples(wpc, sampleBuf, numsamples); - n *= 4*channels; - int i; - for (i = 0; i < n/2; i++) + for (i = 0; i < n*channels; i++) { -// ((UInt32 *)buf)[i] = CFSwapInt32LittleToHost(((UInt32 *)buf)[i]); - ((UInt16 *)buf)[i] = CFSwapInt16LittleToHost(((UInt16 *)buf)[i]); + ((UInt16 *)buf)[i] = ((UInt32 *)sampleBuf)[i]; } + n *= (bitsPerSample/8)*channels; return n; } diff --git a/Sound/SoundFile/WaveFile.m b/Sound/SoundFile/WaveFile.m index b041baff8..ca5cab4db 100644 --- a/Sound/SoundFile/WaveFile.m +++ b/Sound/SoundFile/WaveFile.m @@ -37,11 +37,7 @@ break; case SF_ENDIAN_CPU: -#ifdef __BIG_ENDIAN__ - isBigEndian = YES; -#else - isBigEndian = NO; -#endif + isBigEndian = hostIsBigEndian(); //DBLog(@"&CPU ENDIAN"); break; case SF_ENDIAN_LITTLE: