diff --git a/Frameworks/WavPack/Files/ChangeLog b/Frameworks/WavPack/Files/ChangeLog index 4fca6114c..88cafad4d 100644 --- a/Frameworks/WavPack/Files/ChangeLog +++ b/Frameworks/WavPack/Files/ChangeLog @@ -1,3 +1,104 @@ + ------------------------------- + Release 4.80.0 - March 28, 2016 + ------------------------------- + + WavPack Library Source Code - 4.80.0 + wavpack.exe (command-line encoder) - 4.80.0 + wvunpack.exe (command-line decoder) - 4.80.0 + wvgain.exe (command-line ReplayGain scanner) - 4.80.0 + ----------------------------------------------------- + added: full Unicode support on Windows platform + added: new option --pre-quantize to truncate high-resolution files + to a reasonable depth (e.g., 20-bit) for better compression + fixed: Debian bug #793320 (executable stack) + fixed: LargeAddressAware problem reported on HA + fixed: several "fuzz test" failures reported on GitHub + fixed: repack blocks after possible arithmetic overflows + improved: faster assembly code for mono packing + improved: portability for various platforms + + wvtest.exe (command-line libwavpack test suite) - 4.80.0 + -------------------------------------------------------- + added: exhaustive test for WavpackSeekSample() API + + in_wv.dll (winamp plugin) - 2.8.0.1 + CoreWavPack DirectShow Filters - 1.3.0.0 + AmioWavpack.amio (Adobe Audition Plugins) - 1.5 + cool_wv4.flt (CoolEdit / Audition filter) - 2.14 + ------------------------------------------------ + updated: see 4.80.0 library changes + + + -------------------------------- + Release 4.75.2 - October 1, 2015 + -------------------------------- + + WavPack Library Source Code - 4.75.2 + ------------------------------------ + fixed: corrupt mono or multichannel files created with assembly code (rare) + fixed: building on Clang systems like Darwin and FreeBSD (req. Clang 3.5+) + fixed: explicitly sign-extend audio data (< 4-byte) to avoid corrupt files + fixed: rare decoding errors due to integer overflow (ARM assembly code) + added: assembly optimizations for "extra" mode on mono or multichannel + + wvtest.exe (command-line libwavpack test suite) - 4.75.2 + -------------------------------------------------------- + all new program to stress-test libwavpack (requires Pthreads) + + wavpack.exe (command-line encoder) - 4.75.2 + wvunpack.exe (command-line decoder) - 4.75.2 + wvgain.exe (command-line ReplayGain scanner) - 4.75.2 + ----------------------------------------------------- + fixed: corrupt mono or multichannel files created with assembly code (rare) + added: assembly optimizations for "extra" mode on mono or multichannel + improved: flush stderr after all writes + + cool_wv4.flt (CoolEdit / Audition filter) - 2.13 + AmioWavpack.amio (Adobe Audition Plugins) - 1.4 + ------------------------------------------------ + fixed: corrupt mono or multichannel files (rare) + + + ----------------------------- + Release 4.75.0 - May 25, 2015 + ----------------------------- + + WavPack Library Source Code - 4.75.0 + ------------------------------------ + improved: reorganization for modularity and to improve linking + added: assembly optimizations for encode/decode on x86 and x64 + added: assembly optimizations for decoding on ARMv7 (Linux) + improved: several minor speed optimizations using intrinsics + fixed: wavpack.pc.in not working correctly on some Linux distros + fixed: memcpy() issue causing abort() on OpenBSD + + wavpack.exe (command-line encoder) - 4.75.0 + wvunpack.exe (command-line decoder) - 4.75.0 + wvgain.exe (command-line ReplayGain scanner) - 4.75.0 + ----------------------------------------------------- + changed: writing to console title default is off (Linux only, -z1 to enable) + fixed: wvgain crashes on bad file arguments (Debian bug #716478) + + cool_wv4.flt (CoolEdit / Audition filter) - 2.12 + ------------------------------------------------ + improved: performance (from assembly optimizations) + + + ------------------------- + Update - December 7, 2013 + ------------------------- + + CoreWavPack DirectShow Filters - 1.2.0.2 + ---------------------------------------- + imported: latest filter sources from Christophe Paris and CoreCodec + updated: port to VS 2008 and add 64-bit build platform with installer + added: decode streams with full headers (tested with LAV splitter) + fixed: issues with 7.1 and non-standard channel configurations + fixed: problems with 12-bit, 20-bit, and 32-bit integer audio + fixed: crashing bug related to hybrid files with DNS + fixed: custom sampling rates being ignored + + --------------------------------- Release 4.70.0 - October 19, 2013 --------------------------------- @@ -41,6 +142,10 @@ fixed: installation issue caused by including manifest in build added: dialog to installer suggesting "Winamp Essentials Pack" + AmioWavpack.amio (Adobe Audition Plugin) - 1.0 + ---------------------------------------------- + all new plugin for Audition 4.0 (CS5.5) and later (including Audition CC) + -------------------------- Update - December 23, 2009 diff --git a/Frameworks/WavPack/Files/README b/Frameworks/WavPack/Files/README index 5c7c76b08..6439a9afe 100644 --- a/Frameworks/WavPack/Files/README +++ b/Frameworks/WavPack/Files/README @@ -1,39 +1,69 @@ //////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2013 Conifer Software. // +// Copyright (c) 1998 - 2016 David Bryant. // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// This package contains all the source code required to build the WavPack -command-line programs and the WavPack library and it has been tested on many -platforms. +library (libwavpack) and the command-line programs and it has been tested +on many platforms. Assembly language optimizations are provided for x86 +and x86-64 (AMD64) processors (encoding and decoding) and ARMv7 (decoding +only). The x86 assembly code includes a runtime check for MMX capability, +so it will work on legacy i386 processors. On Windows there are solution and project files for Visual Studio 2008 and additional sourcecode to build the CoolEdit/Audition plugin and the winamp plugin. The CoolEdit/Audition plugin provides a good example for using the -library to both read and write WavPack files. Both 32-bit and 64-bit +library to both read and write WavPack files and the winamp plugin makes +extensive use of APEv2 tag reading and writing. Both 32-bit and 64-bit platforms are provided. +Visual Studio 2008 does not support projects with x64 assembly very well. I +have provided a copy of the edited masm.rules file that works for me, but I +can't provide support if your build does not work. Please make a copy of +your masm.rules file first. On my system it lives here: + +C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\VCProjectDefaults + To build everything on Linux, type: -1. ./configure [--enable-mmx] [--enable-man] +1. ./configure [--disable-asm] [--enable-man] [--enable-rpath] [--enable-tests] 2. make 3. make install (optionally, to install into /usr/local/bin) -If you are using the code directly from SVN (rather than a distribution) -then you will need to do a ./autogen.sh before the configure step. For -processors that support MMX, use the --enable-mmx switch to utilize MMX -intrinsics to speed up encoding of stereo 24-bit (and higher) audio. +If you are using the code directly from Git (rather than a distribution) +then you will need to do a ./autogen.sh instead of the configure step. If +assembly optimizations are available for your processor they will be +automatically enabled, but if there is a problem with them then use the +--disable-asm option to revert to pure C. For Clang-based build systems +(Darwin, FreeBSD, etc.) Clang version 3.5 or higher is required. + +If you get a WARNING about unexpected libwavpack version when you run the +command-line programs, you might try using --enable-rpath to hardcode the +library location in the executables, or simply force static linking with +--disable-shared. + +There is now a cli program to do a full suite of stress tests for libwavpack, +and this is particularly useful for packagers to make sure that the assembly +language optimizations are working correctly on various platforms. It is +built with the configure option --enable-tests and requires Pthreads (it +worked out-of-the-box on all the platforms I tried it on). There are lots of +options, but the default test suite (consisting of 192 tests) is executed +with "wvtest --default". On Windows a third-party Pthreads library is +required, so I am not including this in the build for now. Notes: -1. There are two documentation files contained in the distribution: +1. There are three documentation files contained in the distribution: + + doc/wavpack_doc.html contains user-targeted documentation for the + command-line programs doc/library_use.txt contains a detailed description of the API provided by WavPack library appropriate for read and writing - WavPack files + WavPack files and manipulating APEv2 tags doc/file_format.txt contains a description of the WavPack file format, including details needed for parsing WavPack blocks @@ -45,50 +75,33 @@ Notes: www.wavpack.com/WavPack.pdf -2. This code is designed to be easy to port to other platforms. File I/O is - done with streams and all file functions (except "fopen") are handled in - a wrapper in the "utils.c" module. The code is endian-independent. +2. This code is designed to be easy to port to other platforms. It is endian- + agnostic and usually uses callbacks for I/O, although there's a convenience + function for reading files that accepts filename strings and automatically + handles correction files (and on Windows there is now an option to select + UTF-8 instead of ANSI). To maintain compatibility on various platforms, the following conventions - are used: A "short" must be 16-bits and an "int" must be 32-bits. - The "long" type is not used. The "char" type must be 8-bits, signed or - unsigned. + are used: the "char" type must be 8-bits (signed or unsigned), a "short" + must be 16-bits and the "int" and "long" types must be at least 32-bits. -3. For WavPack file decoding, a library interface in "wputils.c" provides all - the functionality required for both the winamp plugin and the "wvunpack" - command-line program (including the transparent decoding of "correction" - files). There is also an alternate entry point that uses reader callbacks - for all input, although in this case it is the caller's responsibility to - to open the "correction" file. The header file "include/wavpack.h" - includes everything needed while hiding all the WavPack internals from the - application. +3. The code's modules are organized in such a way that if major chunks of the + functionality are not referenced (for example, creating WavPack files) then + link-time dependency resolution should provide optimum binary sizes. -4. For WavPack file creation, the library interface in "wputils.c" provides - all the functionality for both the Audition filter and the "wavpack" - command-line program. No file I/O is performed by the library when creating - WavPack files. Instead, the user supplies a "write_block" function that - accepts completed WavPack blocks. It is also possible to append APEv2 tags - to WavPack files during creation and edit APEv2 tags on existing files - (although there is no support currently for "binary" fields in the tags). + However, some functionality could not be easily excluded in this way and so + there are additional macros that may be used to further reduce the size of + the binary. Note that these must be defined for all modules: -5. The following #define's can be optionally used to eliminate some functionality - to create smaller binaries. It is important that they must be specified - the same for the compilation of ALL files: - - NO_UNPACK no unpacking of audio samples from WavPack files - (also don't include unpack.c) - NO_PACK no creating WavPack files from raw audio data - (also don't include pack.c, extra1.c and extra2.c) - INFO_ONLY to obtain information from WavPack files, but not audio - (also don't include pack.c, extra1.c and extra2.c) - NO_SEEKING to not allow seeking to a specific sample index (unpack only) - NO_USE_FSTREAMS to not open WavPack files by name using fstreams + VER4_ONLY to only handle WavPack files from version 4.0 onward + (this is highly recommended for most applications + because pre-4.0 WavPack files are very old) + NO_SEEKING to not allow seeking to a specific sample index + (for applications that always read entire files) NO_TAGS to not read specified fields from ID3v1 and APEv2 tags and - create APEv2 tags - VER4_ONLY to only handle WavPack files from versions 4.0 onward - WIN32 required for Win32 platform + not create or edit APEv2 tags -6. There are alternate versions of this library available specifically designed +4. There are alternate versions of this library available specifically designed for "resource limited" CPUs or hardware encoding and decoding. There is the "tiny decoder" library which works with less than 32k of code and less than 4k of data and has assembly language optimizations for the ARM and Freescale @@ -97,8 +110,4 @@ Notes: "tiny" versions use any memory allocation functions nor do they require floating-point arithmetic support. - For applications requiring very low latency, there is a special version of - the library that supports a variation on the regular WavPack block format - to facilitate this. - -7. Questions or comments should be directed to david@wavpack.com +5. Questions or comments should be directed to david@wavpack.com diff --git a/Frameworks/WavPack/Files/bits.c b/Frameworks/WavPack/Files/bits.c deleted file mode 100644 index 2eab38bd9..000000000 --- a/Frameworks/WavPack/Files/bits.c +++ /dev/null @@ -1,274 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// 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_local.h" - -#include -#include -#include -#include - -#if defined(WIN32) -#include -#else -#if defined(__OS2__) -#include -#endif -#include -#endif - -////////////////////////// Bitstream functions //////////////////////////////// - -#if !defined(NO_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, void *buffer_start, void *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 < sizeof (*(bs->ptr)) * 8) - bs->ptr++; - - bytes_read = (uint32_t)(bs->ptr - bs->buf) * sizeof (*(bs->ptr)); - - if (!(bytes_read & 1)) - ++bytes_read; - - CLEAR (*bs); - return bytes_read; -} - -#endif - -#ifndef NO_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, void *buffer_start, void *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 (1) { - while (bs->bc) - putbit_1 (bs); - - bytes_written = (uint32_t)(bs->ptr - bs->buf) * sizeof (*(bs->ptr)); - - if (bytes_written & 1) { - putbit_1 (bs); - } - else - break; - }; - - CLEAR (*bs); - return bytes_written; -} - -#endif - -/////////////////////// Endian Correction Routines //////////////////////////// - -void little_endian_to_native (void *data, char *format) -{ - unsigned char *cp = (unsigned char *) 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) -{ - unsigned char *cp = (unsigned char *) data; - int32_t temp; - - while (*format) { - switch (*format) { - case 'L': - temp = * (int32_t *) cp; - *cp++ = (unsigned char) temp; - *cp++ = (unsigned char) (temp >> 8); - *cp++ = (unsigned char) (temp >> 16); - *cp++ = (unsigned char) (temp >> 24); - break; - - case 'S': - temp = * (short *) cp; - *cp++ = (unsigned char) temp; - *cp++ = (unsigned char) (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/Frameworks/WavPack/Files/common_utils.c b/Frameworks/WavPack/Files/common_utils.c new file mode 100644 index 000000000..d58c6eedf --- /dev/null +++ b/Frameworks/WavPack/Files/common_utils.c @@ -0,0 +1,702 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// common_utils.c + +// This module provides a lot of the trivial WavPack API functions and several +// functions that are common to both reading and writing WavPack files (like +// WavpackCloseFile()). Functions here are restricted to those that have few +// external dependancies and this is done so that applications that statically +// link to the WavPack library (like the command-line utilities on Windows) +// do not need to include the entire library image if they only use a subset +// of it. This module will be loaded for ANY WavPack application. + +#include +#include +#include + +#include "wavpack_local.h" + +#ifndef LIBWAVPACK_VERSION_STRING +#include "wavpack_version.h" +#endif + +///////////////////////////// local table storage //////////////////////////// + +const uint32_t sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050, + 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 }; + +///////////////////////////// executable code //////////////////////////////// + +// This function obtains general information about an open input file and +// returns a mask with the following bit values: + +// MODE_WVC: a .wvc file has been found and will be used for lossless +// MODE_LOSSLESS: file is lossless (either pure or hybrid) +// MODE_HYBRID: file is hybrid mode (either lossy or lossless) +// MODE_FLOAT: audio data is 32-bit ieee floating point +// MODE_VALID_TAG: file 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 +// MODE_VERY_HIGH: file was created in the "very high" mode (or in +// the "high" mode prior to 4.4) +// MODE_MD5: file contains an MD5 checksum +// MODE_XMODE: level used for extra mode (1-6, 0=unknown) +// MODE_DNS: dynamic noise shaping + +int WavpackGetMode (WavpackContext *wpc) +{ + int mode = 0; + + if (wpc) { + if (wpc->config.flags & CONFIG_HYBRID_FLAG) + mode |= MODE_HYBRID; + else if (!(wpc->config.flags & CONFIG_LOSSY_MODE)) + mode |= MODE_LOSSLESS; + + if (wpc->wvc_flag) + mode |= (MODE_LOSSLESS | MODE_WVC); + + if (wpc->lossy_blocks) + mode &= ~MODE_LOSSLESS; + + if (wpc->config.flags & CONFIG_FLOAT_DATA) + mode |= MODE_FLOAT; + + if (wpc->config.flags & (CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG)) { + mode |= MODE_HIGH; + + if ((wpc->config.flags & CONFIG_VERY_HIGH_FLAG) || + (wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.version < 0x405)) + mode |= MODE_VERY_HIGH; + } + + if (wpc->config.flags & CONFIG_FAST_FLAG) + mode |= MODE_FAST; + + if (wpc->config.flags & CONFIG_EXTRA_MODE) + mode |= (MODE_EXTRA | (wpc->config.xmode << 12)); + + if (wpc->config.flags & CONFIG_CREATE_EXE) + mode |= MODE_SFX; + + if (wpc->config.flags & CONFIG_MD5_CHECKSUM) + mode |= MODE_MD5; + + if ((wpc->config.flags & CONFIG_HYBRID_FLAG) && (wpc->config.flags & CONFIG_DYNAMIC_SHAPING) && + wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.version >= 0x407) + mode |= MODE_DNS; + +#ifndef NO_TAGS + if (valid_tag (&wpc->m_tag)) { + mode |= MODE_VALID_TAG; + + if (valid_tag (&wpc->m_tag) == 'A') + mode |= MODE_APETAG; + } +#endif + + mode |= (wpc->config.qmode << 16) & 0xFF0000; + } + + return mode; +} + +// This function obtains information about specific file features that were +// added for version 5.0, specifically qualifications added to support CAF +// and DSD files. Except for indicating the presence of DSD data, these +// bits are meant to simply indicate the format of the data in the original +// source file and do NOT indicate how the library will return the data to +// the appication (which is always the same). This means that in general an +// application that simply wants to play or process the audio data need not +// be concerned about these. If the file is DSD audio, then either of the +// QMDOE_DSD_LSB_FIRST or QMODE_DSD_MSB_FIRST bits will be set (but the +// DSD audio is always returned to the caller MSB first). + +// QMODE_BIG_ENDIAN 0x1 // big-endian data format (opposite of WAV format) +// QMODE_SIGNED_BYTES 0x2 // 8-bit audio data is signed (opposite of WAV format) +// QMODE_UNSIGNED_WORDS 0x4 // audio data (other than 8-bit) is unsigned (opposite of WAV format) +// QMODE_REORDERED_CHANS 0x8 // source channels were not Microsoft order, so they were reordered +// QMODE_DSD_LSB_FIRST 0x10 // DSD bytes, LSB first (most Sony .dsf files) +// QMODE_DSD_MSB_FIRST 0x20 // DSD bytes, MSB first (Philips .dff files) +// QMODE_DSD_IN_BLOCKS 0x40 // DSD data is blocked by channels (Sony .dsf only) + +int WavpackGetQualifyMode (WavpackContext *wpc) +{ + return wpc->config.qmode & 0xFF; +} + +// This function returns a pointer to a string describing the last error +// generated by WavPack. + +char *WavpackGetErrorMessage (WavpackContext *wpc) +{ + return wpc->error_message; +} + +// Get total number of samples contained in the WavPack file, or -1 if unknown + +uint32_t WavpackGetNumSamples (WavpackContext *wpc) +{ + return (uint32_t) WavpackGetNumSamples64 (wpc); +} + +int64_t WavpackGetNumSamples64 (WavpackContext *wpc) +{ + return wpc ? wpc->total_samples : -1; +} + +// Get the current sample index position, or -1 if unknown + +uint32_t WavpackGetSampleIndex (WavpackContext *wpc) +{ + return (uint32_t) WavpackGetSampleIndex64 (wpc); +} + +int64_t WavpackGetSampleIndex64 (WavpackContext *wpc) +{ + if (wpc) { +#ifndef VER4_ONLY + if (wpc->stream3) + return get_sample_index3 (wpc); + else if (wpc->streams && wpc->streams [0]) + return wpc->streams [0]->sample_index; +#else + if (wpc->streams && wpc->streams [0]) + return wpc->streams [0]->sample_index; +#endif + } + + return -1; +} + +// Get the number of errors encountered so far + +int WavpackGetNumErrors (WavpackContext *wpc) +{ + return wpc ? wpc->crc_errors : 0; +} + +// return TRUE if any uncorrected lossy blocks were actually written or read + +int WavpackLossyBlocks (WavpackContext *wpc) +{ + return wpc ? wpc->lossy_blocks : 0; +} + +// Calculate the progress through the file as a double from 0.0 (for begin) +// to 1.0 (for done). A return value of -1.0 indicates that the progress is +// unknown. + +double WavpackGetProgress (WavpackContext *wpc) +{ + if (wpc && wpc->total_samples != -1 && wpc->total_samples != 0) + return (double) WavpackGetSampleIndex64 (wpc) / wpc->total_samples; + else + return -1.0; +} + +// Return the total size of the WavPack file(s) in bytes. + +uint32_t WavpackGetFileSize (WavpackContext *wpc) +{ + return (uint32_t) (wpc ? wpc->filelen + wpc->file2len : 0); +} + +int64_t WavpackGetFileSize64 (WavpackContext *wpc) +{ + return wpc ? wpc->filelen + wpc->file2len : 0; +} + +// Calculate the ratio of the specified WavPack file size to the size of the +// original audio data as a double greater than 0.0 and (usually) smaller than +// 1.0. A value greater than 1.0 represents "negative" compression and a +// return value of 0.0 indicates that the ratio cannot be determined. + +double WavpackGetRatio (WavpackContext *wpc) +{ + if (wpc && wpc->total_samples != -1 && wpc->filelen) { + double output_size = (double) wpc->total_samples * wpc->config.num_channels * + wpc->config.bytes_per_sample; + double input_size = (double) wpc->filelen + wpc->file2len; + + if (output_size >= 1.0 && input_size >= 1.0) + return input_size / output_size; + } + + return 0.0; +} + +// Calculate the average bitrate of the WavPack file in bits per second. A +// return of 0.0 indicates that the bitrate cannot be determined. An option is +// provided to use (or not use) any attendant .wvc file. + +double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc) +{ + if (wpc && wpc->total_samples != -1 && wpc->filelen) { + double output_time = (double) wpc->total_samples / WavpackGetSampleRate (wpc); + double input_size = (double) wpc->filelen + (count_wvc ? wpc->file2len : 0); + + if (output_time >= 0.1 && input_size >= 1.0) + return input_size * 8.0 / output_time; + } + + return 0.0; +} + +// Calculate the bitrate of the current WavPack file block in bits per second. +// This can be used for an "instant" bit display and gets updated from about +// 1 to 4 times per second. A return of 0.0 indicates that the bitrate cannot +// be determined. + +double WavpackGetInstantBitrate (WavpackContext *wpc) +{ + if (wpc && wpc->stream3) + return WavpackGetAverageBitrate (wpc, TRUE); + + if (wpc && wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.block_samples) { + double output_time = (double) wpc->streams [0]->wphdr.block_samples / WavpackGetSampleRate (wpc); + double input_size = 0; + int si; + + for (si = 0; si < wpc->num_streams; ++si) { + if (wpc->streams [si]->blockbuff) + input_size += ((WavpackHeader *) wpc->streams [si]->blockbuff)->ckSize; + + if (wpc->streams [si]->block2buff) + input_size += ((WavpackHeader *) wpc->streams [si]->block2buff)->ckSize; + } + + if (output_time > 0.0 && input_size >= 1.0) + return input_size * 8.0 / output_time; + } + + return 0.0; +} + +// This function allows retrieving the Core Audio File channel layout, many of which do not +// conform to the Microsoft ordering standard that WavPack requires internally (at least for +// those channels present in the "channel mask"). In addition to the layout tag, this function +// returns the reordering string (if stored in the file) to allow the unpacker to reorder the +// channels back to the specified layout (if it wants to restore the CAF order). The number of +// channels in the layout is determined from the lower nybble of the layout word (and should +// probably match the number of channels in the file), and if a reorder string is requested +// then that much space must be allocated. Note that all the reordering is actually done +// outside of this library, and that if reordering is done then the appropriate qmode bit +// will be set. + +uint32_t WavpackGetChannelLayout (WavpackContext *wpc, unsigned char *reorder) +{ + if ((wpc->channel_layout & 0xff) && wpc->channel_reordering && reorder) + memcpy (reorder, wpc->channel_reordering, wpc->channel_layout & 0xff); + + return wpc->channel_layout; +} + +// Close the specified WavPack file and release all resources used by it. +// Returns NULL. + +WavpackContext *WavpackCloseFile (WavpackContext *wpc) +{ + if (wpc->streams) { + free_streams (wpc); + + if (wpc->streams [0]) + free (wpc->streams [0]); + + free (wpc->streams); + } + +#ifndef VER4_ONLY + if (wpc->stream3) + free_stream3 (wpc); +#endif + + if (wpc->reader && wpc->reader->close && wpc->wv_in) + wpc->reader->close (wpc->wv_in); + + if (wpc->reader && wpc->reader->close && wpc->wvc_in) + wpc->reader->close (wpc->wvc_in); + + WavpackFreeWrapper (wpc); + + if (wpc->channel_reordering) + free (wpc->channel_reordering); + +#ifndef NO_TAGS + free_tag (&wpc->m_tag); +#endif + + if (wpc->decimation_context) + decimate_dsd_destroy (wpc->decimation_context); + + free (wpc); + + return NULL; +} + +// These routines are used to access (and free) header and trailer data that +// was retrieved from the Wavpack file. The header will be available before +// the samples are decoded and the trailer will be available after all samples +// have been read. + +uint32_t WavpackGetWrapperBytes (WavpackContext *wpc) +{ + return wpc ? wpc->wrapper_bytes : 0; +} + +unsigned char *WavpackGetWrapperData (WavpackContext *wpc) +{ + return wpc ? wpc->wrapper_data : NULL; +} + +void WavpackFreeWrapper (WavpackContext *wpc) +{ + if (wpc && wpc->wrapper_data) { + free (wpc->wrapper_data); + wpc->wrapper_data = NULL; + wpc->wrapper_bytes = 0; + } +} + +// Returns the sample rate of the specified WavPack file + +uint32_t WavpackGetSampleRate (WavpackContext *wpc) +{ + return wpc ? (wpc->dsd_multiplier ? wpc->config.sample_rate * wpc->dsd_multiplier : wpc->config.sample_rate) : 44100; +} + +// Returns the number of channels of the specified WavPack file. Note that +// this is the actual number of channels contained in the file even if the +// OPEN_2CH_MAX flag was specified when the file was opened. + +int WavpackGetNumChannels (WavpackContext *wpc) +{ + return wpc ? wpc->config.num_channels : 2; +} + +// Returns the standard Microsoft channel mask for the specified WavPack +// file. A value of zero indicates that there is no speaker assignment +// information. + +int WavpackGetChannelMask (WavpackContext *wpc) +{ + return wpc ? wpc->config.channel_mask : 0; +} + +// Return the normalization value for floating point data (valid only +// if floating point data is present). A value of 127 indicates that +// the floating point range is +/- 1.0. Higher values indicate a +// larger floating point range. + +int WavpackGetFloatNormExp (WavpackContext *wpc) +{ + return wpc->config.float_norm_exp; +} + +// Returns the actual number of valid bits per sample contained in the +// original file, which may or may not be a multiple of 8. Floating data +// always has 32 bits, integers may be from 1 to 32 bits each. When this +// value is not a multiple of 8, then the "extra" bits are located in the +// LSBs of the results. That is, values are right justified when unpacked +// into ints, but are left justified in the number of bytes used by the +// original data. + +int WavpackGetBitsPerSample (WavpackContext *wpc) +{ + return wpc ? wpc->config.bits_per_sample : 16; +} + +// Returns the number of bytes used for each sample (1 to 4) in the original +// file. This is required information for the user of this module because the +// audio data is returned in the LOWER bytes of the long buffer and must be +// left-shifted 8, 16, or 24 bits if normalized longs are required. + +int WavpackGetBytesPerSample (WavpackContext *wpc) +{ + return wpc ? wpc->config.bytes_per_sample : 2; +} + +// If the OPEN_2CH_MAX flag is specified when opening the file, this function +// will return the actual number of channels decoded from the file (which may +// or may not be less than the actual number of channels, but will always be +// 1 or 2). Normally, this will be the front left and right channels of a +// multichannel file. + +int WavpackGetReducedChannels (WavpackContext *wpc) +{ + if (wpc) + return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels; + else + return 2; +} + +// Free all memory allocated for raw WavPack blocks (for all allocated streams) +// and free all additonal streams. This does not free the default stream ([0]) +// which is always kept around. + +void free_streams (WavpackContext *wpc) +{ + int si = wpc->num_streams; + + while (si--) { + if (wpc->streams [si]->blockbuff) { + free (wpc->streams [si]->blockbuff); + wpc->streams [si]->blockbuff = NULL; + } + + if (wpc->streams [si]->block2buff) { + free (wpc->streams [si]->block2buff); + wpc->streams [si]->block2buff = NULL; + } + + if (wpc->streams [si]->sample_buffer) { + free (wpc->streams [si]->sample_buffer); + wpc->streams [si]->sample_buffer = NULL; + } + + if (wpc->streams [si]->dc.shaping_data) { + free (wpc->streams [si]->dc.shaping_data); + wpc->streams [si]->dc.shaping_data = NULL; + } + + if (wpc->streams [si]->dsd.probabilities) { + free (wpc->streams [si]->dsd.probabilities); + wpc->streams [si]->dsd.probabilities = NULL; + } + + if (wpc->streams [si]->dsd.summed_probabilities) { + free (wpc->streams [si]->dsd.summed_probabilities); + wpc->streams [si]->dsd.summed_probabilities = NULL; + } + + if (wpc->streams [si]->dsd.value_lookup) { + int i; + + for (i = 0; i < wpc->streams [si]->dsd.history_bins; ++i) + if (wpc->streams [si]->dsd.value_lookup [i]) + free (wpc->streams [si]->dsd.value_lookup [i]); + + free (wpc->streams [si]->dsd.value_lookup); + wpc->streams [si]->dsd.value_lookup = NULL; + } + + if (wpc->streams [si]->dsd.ptable) { + free (wpc->streams [si]->dsd.ptable); + wpc->streams [si]->dsd.ptable = NULL; + } + + if (si) { + wpc->num_streams--; + free (wpc->streams [si]); + wpc->streams [si] = NULL; + } + } + + wpc->current_stream = 0; +} + +void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp) +{ + f32 *fvalues = (f32 *) values; + int exp; + + if (!delta_exp) + return; + + while (num_values--) { + if ((exp = get_exponent (*fvalues)) == 0 || exp + delta_exp <= 0) + *fvalues = 0; + else if (exp == 255 || (exp += delta_exp) >= 255) { + set_exponent (*fvalues, 255); + set_mantissa (*fvalues, 0); + } + else + set_exponent (*fvalues, exp); + + fvalues++; + } +} + +void WavpackLittleEndianToNative (void *data, char *format) +{ + unsigned char *cp = (unsigned char *) data; + int64_t temp; + + while (*format) { + switch (*format) { + case 'D': + temp = cp [0] + ((int64_t) cp [1] << 8) + ((int64_t) cp [2] << 16) + ((int64_t) cp [3] << 24) + + ((int64_t) cp [4] << 32) + ((int64_t) cp [5] << 40) + ((int64_t) cp [6] << 48) + ((int64_t) cp [7] << 56); + * (int64_t *) cp = temp; + cp += 8; + break; + + case 'L': + temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24); + * (int32_t *) cp = (int32_t) temp; + cp += 4; + break; + + case 'S': + temp = cp [0] + (cp [1] << 8); + * (int16_t *) cp = (int16_t) temp; + cp += 2; + break; + + default: + if (isdigit (*format)) + cp += *format - '0'; + + break; + } + + format++; + } +} + +void WavpackNativeToLittleEndian (void *data, char *format) +{ + unsigned char *cp = (unsigned char *) data; + int64_t temp; + + while (*format) { + switch (*format) { + case 'D': + temp = * (int64_t *) cp; + *cp++ = (unsigned char) temp; + *cp++ = (unsigned char) (temp >> 8); + *cp++ = (unsigned char) (temp >> 16); + *cp++ = (unsigned char) (temp >> 24); + *cp++ = (unsigned char) (temp >> 32); + *cp++ = (unsigned char) (temp >> 40); + *cp++ = (unsigned char) (temp >> 48); + *cp++ = (unsigned char) (temp >> 56); + break; + + case 'L': + temp = * (int32_t *) cp; + *cp++ = (unsigned char) temp; + *cp++ = (unsigned char) (temp >> 8); + *cp++ = (unsigned char) (temp >> 16); + *cp++ = (unsigned char) (temp >> 24); + break; + + case 'S': + temp = * (int16_t *) cp; + *cp++ = (unsigned char) temp; + *cp++ = (unsigned char) (temp >> 8); + break; + + default: + if (isdigit (*format)) + cp += *format - '0'; + + break; + } + + format++; + } +} + +void WavpackBigEndianToNative (void *data, char *format) +{ + unsigned char *cp = (unsigned char *) data; + int64_t temp; + + while (*format) { + switch (*format) { + case 'D': + temp = cp [7] + ((int64_t) cp [6] << 8) + ((int64_t) cp [5] << 16) + ((int64_t) cp [4] << 24) + + ((int64_t) cp [3] << 32) + ((int64_t) cp [2] << 40) + ((int64_t) cp [1] << 48) + ((int64_t) cp [0] << 56); + * (int64_t *) cp = temp; + cp += 8; + break; + + case 'L': + temp = cp [3] + ((int32_t) cp [2] << 8) + ((int32_t) cp [1] << 16) + ((int32_t) cp [0] << 24); + * (int32_t *) cp = (int32_t) temp; + cp += 4; + break; + + case 'S': + temp = cp [1] + (cp [0] << 8); + * (int16_t *) cp = (int16_t) temp; + cp += 2; + break; + + default: + if (isdigit (*format)) + cp += *format - '0'; + + break; + } + + format++; + } +} + +void WavpackNativeToBigEndian (void *data, char *format) +{ + unsigned char *cp = (unsigned char *) data; + int64_t temp; + + while (*format) { + switch (*format) { + case 'D': + temp = * (int64_t *) cp; + *cp++ = (unsigned char) (temp >> 56); + *cp++ = (unsigned char) (temp >> 48); + *cp++ = (unsigned char) (temp >> 40); + *cp++ = (unsigned char) (temp >> 32); + *cp++ = (unsigned char) (temp >> 24); + *cp++ = (unsigned char) (temp >> 16); + *cp++ = (unsigned char) (temp >> 8); + *cp++ = (unsigned char) temp; + break; + + case 'L': + temp = * (int32_t *) cp; + *cp++ = (unsigned char) (temp >> 24); + *cp++ = (unsigned char) (temp >> 16); + *cp++ = (unsigned char) (temp >> 8); + *cp++ = (unsigned char) temp; + break; + + case 'S': + temp = * (int16_t *) cp; + *cp++ = (unsigned char) (temp >> 8); + *cp++ = (unsigned char) temp; + break; + + default: + if (isdigit (*format)) + cp += *format - '0'; + + break; + } + + format++; + } +} + +uint32_t WavpackGetLibraryVersion (void) +{ + return (LIBWAVPACK_MAJOR<<16) + |(LIBWAVPACK_MINOR<<8) + |(LIBWAVPACK_MICRO<<0); +} + +const char *WavpackGetLibraryVersionString (void) +{ + return LIBWAVPACK_VERSION_STRING; +} + diff --git a/Frameworks/WavPack/Files/decorr_tables.h b/Frameworks/WavPack/Files/decorr_tables.h new file mode 100644 index 000000000..be17de958 --- /dev/null +++ b/Frameworks/WavPack/Files/decorr_tables.h @@ -0,0 +1,1077 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// decorr_tables.h + +// These four tables specify the characteristics of the decorrelation filters +// for the four basic compression modes (fast, normal, high, and very high). +// +// The first entry in the table represents the "default" filter for the +// corresponding mode; subsequent entries represent filters that are tried +// in the "extra" modes 1-3 ("extra" modes 4-6 create filters from scratch). +// +// The first value indicates whether the filter is applied to joint stereo +// data (0=L/R, 1=M/S) and the second value represents the "delta" value of +// the adaptive filter. The rest of the values (2-16, depending on mode) are +// the "terms" of the filter. +// +// 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). +// +// It would be ideal if this was the only source for the decorrelation tables, +// but unfortunately the defaults (first entry) are duplicated in the assembly +// code for the function pack_decorr_mono_buffer() and there is no check in +// that code to make sure the correct filter is being passed in. SO, IF A +// CHANGE IS MADE HERE TO ONE OF THE DEFAULT FILTERS, THEN THE CORRESPONDING +// ASSEMBLY CODE MUST BE CHANGED ALSO, OR VERY CORRUPT FILES WILL RESULT!! +// +// Since this include file contains that actual tables as static const data, +// it should only be included from ONE source file (currently pack.c)! + +static const WavpackDecorrSpec fast_specs [] = { + { 1, 2,18,17 }, // 0 + { 1, 1,17,17 }, // 1 + { 0, 2,18,17 }, // 2 + { 0, 1,17,17 }, // 3 + { 1, 3, 1,18 }, // 4 + { 1, 1,17, 1 }, // 5 + { 0, 1, 1,17 }, // 6 + { 0, 1,-2,17 }, // 7 + { 0, 2,-1,17 }, // 8 + { 1, 1,17, 2 }, // 9 + { 0, 3,18,18 }, // 10 + { 0, 1,17, 1 }, // 11 + { 1, 6, 1, 2 }, // 12 + { 1, 1,17, 3 }, // 13 + { 0, 1,-2, 3 }, // 14 + { 0, 1, 2,17 }, // 15 + { 0, 1,18,-2 }, // 16 + { 0, 1,-1,17 }, // 17 + { 0, 1,18,17 }, // 18 + { 0, 1,17, 2 }, // 19 + { 1, 2,18,-2 }, // 20 + { 1, 1, 1,17 }, // 21 + { 0, 3,18, 2 }, // 22 + { 0, 1,17,-2 }, // 23 + { 0, 1,18,-2 }, // 24 + { 1, 2,17,-3 }, // 25 + { 0, 1,18, 3 }, // 26 + { 0, 1,18,18 }, // 27 + { 1, 1, 1, 3 }, // 28 + { 1, 1,18, 3 }, // 29 + { 1, 1, 1, 3 }, // 30 + { 0, 2,18,17 }, // 31 + { 1, 1, 1,17 }, // 32 + { 1, 1,17, 3 }, // 33 + { 0, 3,18,17 }, // 34 + { 0, 1,18,18 }, // 35 + { 1, 1, 1, 3 }, // 36 + { 1, 1, 1,18 }, // 37 + { 0, 1,18,-2 }, // 38 + { 0, 2,18,17 }, // 39 + { 0, 1,-1,18 }, // 40 + { 1, 1,17, 3 }, // 41 + { 0, 1,17, 2 }, // 42 + { 0, 1,17, 3 }, // 43 + { 1, 1,18, 2 }, // 44 + { 1, 1,17,-2 }, // 45 + { 0, 1, 1,-2 }, // 46 + { 0, 2,18,17 }, // 47 + { 0, 1,17,-2 }, // 48 + { 1, 1,17,-2 }, // 49 + { 0, 1,18, 3 }, // 50 + { 0, 1, 2,17 }, // 51 + { 1, 2,18,-3 }, // 52 + { 1, 2, 1,18 }, // 53 + { 1, 2,18, 2 }, // 54 + { 0, 1,17,-1 }, // 55 + { 0, 1,17,-2 }, // 56 + { 1, 1,17,-2 }, // 57 + { 1, 1, 1, 3 }, // 58 + { 0, 1, 1,17 }, // 59 + { 1, 2,18,-2 }, // 60 + { 1, 2,17,-3 }, // 61 + { 0, 2,18,17 }, // 62 + { 0, 2,18,17 }, // 63 + { 1, 1,17, 2 }, // 64 + { 1, 2,18,18 }, // 65 + { 0, 1,17, 2 }, // 66 + { 0, 1,18,17 }, // 67 + { 1, 1, 1,17 }, // 68 + { 1, 1,17, 2 }, // 69 + { 0, 2,18,18 }, // 70 + { 0, 2,18,17 }, // 71 + { 1, 2,17,-3 }, // 72 + { 1, 6, 1, 2 }, // 73 + { 0, 3,17,17 }, // 74 + { 0, 1, 1,18 }, // 75 + { 0, 1, 1,-2 }, // 76 + { 1, 1,17, 2 }, // 77 + { 0, 2,18,17 }, // 78 + { 0, 2,18,17 }, // 79 + { 1, 1,18, 3 }, // 80 + { 1, 2,17,-3 }, // 81 + { 0, 1,17, 2 }, // 82 + { 0, 1,17, 3 }, // 83 + { 0, 1,18,-2 }, // 84 + { 1, 1,18,18 }, // 85 + { 1, 6, 1, 2 }, // 86 + { 0, 2,18,17 }, // 87 + { 0, 2,18,17 }, // 88 + { 0, 1,-1,17 }, // 89 + { 1, 1,18, 3 }, // 90 + { 0, 1,17,18 }, // 91 + { 1, 1,17, 3 }, // 92 + { 0, 1,18, 3 }, // 93 + { 0, 2,18,17 }, // 94 + { 0, 2,18,17 }, // 95 + { 1, 2,18, 2 }, // 96 + { 0, 1,-2, 3 }, // 97 + { 0, 4,18,-1 }, // 98 + { 0, 2,18,18 }, // 99 + { 0, 1,-2, 3 }, // 100 + { 1, 1,17,-2 }, // 101 + { 0, 1,17, 3 }, // 102 + { 0, 2,18,17 }, // 103 + { 0, 2,-1,18 }, // 104 + { 1, 1, 2,17 }, // 105 + { 0, 2,17,-2 }, // 106 + { 0, 1,17, 2 }, // 107 + { 1, 2,18,-3 }, // 108 + { 0, 1,17,-2 }, // 109 + { 0, 2,18,17 }, // 110 + { 0, 2,18,17 }, // 111 + { 1, 1,17,-2 }, // 112 + { 1, 2,17,-3 }, // 113 + { 1, 1, 1, 3 }, // 114 + { 1, 1, 2,17 }, // 115 + { 1, 2,18, 2 }, // 116 + { 1, 1, 2,17 }, // 117 + { 1, 1,18, 2 }, // 118 + { 0, 2,18,17 }, // 119 + { 0, 2,18,17 }, // 120 + { 0, 1,17,-2 }, // 121 + { 0, 2,18,17 }, // 122 + { 0, 2,17,-1 }, // 123 + { 0, 2,18,-2 }, // 124 + { 0, 2,18,17 }, // 125 + { 0, 2,18,17 }, // 126 + { 0, 2,18,17 }, // 127 + { 1, 1, 1, 3 }, // 128 + { 0, 2,-2,17 }, // 129 + { 0, 2,18,-2 }, // 130 + { 0, 2,17,-2 }, // 131 + { 1, 1, 2,17 }, // 132 + { 1, 1, 1, 3 }, // 133 + { 0, 1, 2,17 }, // 134 + { 0, 2,18,17 }, // 135 + { 0, 3,-1,17 }, // 136 + { 1, 1, 2,17 }, // 137 + { 0, 2,18,18 }, // 138 + { 0, 1,17, 2 }, // 139 + { 1, 4,18,-3 }, // 140 + { 1, 1,18, 1 }, // 141 + { 0, 2,18,17 }, // 142 + { 0, 2,18,17 }, // 143 + { 1, 2,18,-1 }, // 144 + { 0, 1,-1,18 }, // 145 + { 1, 6, 1, 2 }, // 146 + { 1, 1,17, 2 }, // 147 + { 1, 4,18, 3 }, // 148 + { 0, 1, 1,17 }, // 149 + { 0, 1,18, 2 }, // 150 + { 0, 2,18,17 }, // 151 + { 0, 2,18,17 }, // 152 + { 1, 2,17, 2 }, // 153 + { 0, 2,18,-2 }, // 154 + { 0, 1, 1,18 }, // 155 + { 1, 2,18,-3 }, // 156 + { 0, 2,18,17 }, // 157 + { 0, 2,18,17 }, // 158 + { 0, 2,18,17 }, // 159 + { 1, 2,18,18 }, // 160 + { 1, 3,17,17 }, // 161 + { 0, 1,-2,17 }, // 162 + { 0, 1,17,18 }, // 163 + { 0, 1,-1, 3 }, // 164 + { 1, 1, 2,17 }, // 165 + { 0, 2,18,-1 }, // 166 + { 0, 2,18,17 }, // 167 + { 0, 2,18,17 }, // 168 + { 1, 1,17,-2 }, // 169 + { 1, 2,17, 2 }, // 170 + { 1, 1,18, 3 }, // 171 + { 0, 1,18, 2 }, // 172 + { 1, 2,17,-3 }, // 173 + { 0, 2,18,17 }, // 174 + { 0, 2,18,17 }, // 175 + { 0, 1,-2,17 }, // 176 + { 0, 1,17,-1 }, // 177 + { 0, 1,18,-1 }, // 178 + { 0, 2,18,17 }, // 179 + { 1, 2,17,-3 }, // 180 + { 1, 1, 1,18 }, // 181 + { 1, 3,18, 2 }, // 182 + { 0, 2,18,17 }, // 183 + { 0, 2,18,17 }, // 184 + { 0, 2,18,17 }, // 185 + { 0, 2,18,17 }, // 186 + { 0, 3,18,18 }, // 187 + { 0, 1, 1,-2 }, // 188 + { 0, 2,18,17 }, // 189 + { 0, 2,18,17 }, // 190 + { 0, 2,18,17 }, // 191 + { 1, 2,17,-3 }, // 192 + { 1, 1,18,18 }, // 193 + { 0, 2,18, 2 }, // 194 + { 0, 1,17,18 }, // 195 + { 1, 2,18, 2 }, // 196 + { 1, 1,17,-2 }, // 197 + { 0, 2,17,-1 }, // 198 + { 0, 2,18,17 }, // 199 + { 0, 2,18,17 }, // 200 + { 0, 2,18,17 }, // 201 + { 0, 1, 1,-2 }, // 202 + { 0, 1,18, 1 }, // 203 + { 1, 2,18,-2 }, // 204 + { 0, 1,17, 2 }, // 205 + { 0, 2,18,17 }, // 206 + { 0, 2,18,17 }, // 207 + { 1, 1,17, 3 }, // 208 + { 0, 1,17,-1 }, // 209 + { 0, 1,18, 2 }, // 210 + { 1, 1,17, 3 }, // 211 + { 1, 1,17,-2 }, // 212 + { 0, 1,18,18 }, // 213 + { 0, 2,18,17 }, // 214 + { 0, 2,18,17 }, // 215 + { 0, 2,18,17 }, // 216 + { 0, 2,18,17 }, // 217 + { 0, 2,18,17 }, // 218 + { 1, 1,17,18 }, // 219 + { 0, 1,-2, 3 }, // 220 + { 0, 2,18,17 }, // 221 + { 0, 2,18,17 }, // 222 + { 0, 2,18,17 }, // 223 + { 1, 2,18,-3 }, // 224 + { 0, 2,18,17 }, // 225 + { 0, 3,18, 2 }, // 226 + { 0, 1, 1,18 }, // 227 + { 0, 2,18,17 }, // 228 + { 0, 1,17,-1 }, // 229 + { 0, 2,18,17 }, // 230 + { 0, 2,18,17 }, // 231 + { 0, 2,18,17 }, // 232 + { 0, 1,-2, 3 }, // 233 + { 0, 3,17,17 }, // 234 + { 0, 2,18,17 }, // 235 + { 0, 2,18,17 }, // 236 + { 1, 1,17, 2 }, // 237 + { 0, 2,18,17 }, // 238 + { 0, 2,18,17 }, // 239 + { 1, 1,17, 2 }, // 240 + { 0, 2,18,17 }, // 241 + { 0, 2,18,17 }, // 242 + { 0, 2,18,17 }, // 243 + { 0, 2,18, 2 }, // 244 + { 0, 2,18,17 }, // 245 + { 0, 2,18,17 }, // 246 + { 0, 2,18,17 }, // 247 + { 0, 2,18,17 }, // 248 + { 0, 2,18,17 }, // 249 + { 0, 2,18,17 }, // 250 + { 0, 2,18,17 }, // 251 + { 0, 2,18,17 }, // 252 + { 0, 2,18,17 }, // 253 + { 0, 2,18,17 }, // 254 + { 0, 2,18,17 }, // 255 +}; + +static const WavpackDecorrSpec default_specs [] = { + { 1, 2,18,18, 2,17, 3 }, // 0 + { 0, 2,18,17,-1, 3, 2 }, // 1 + { 1, 1,17,18,18,-2, 2 }, // 2 + { 0, 2,18,17, 3,-2,17 }, // 3 + { 1, 2,18,17, 2,17, 3 }, // 4 + { 0, 1,18,18,-1, 2,17 }, // 5 + { 0, 1,17,17,-2, 2, 3 }, // 6 + { 0, 1,18,-2,18, 2,17 }, // 7 + { 1, 2,18,18,-1, 2, 3 }, // 8 + { 0, 2,18,17, 3, 2, 5 }, // 9 + { 1, 1,18,17,18, 2, 5 }, // 10 + { 0, 1,17,17,-2, 2, 3 }, // 11 + { 0, 1,18,-2,18, 2, 5 }, // 12 + { 0, 1,17,-2,17, 2,-3 }, // 13 + { 1, 1,17,-2,17, 1, 2 }, // 14 + { 0, 1,17,17,-2, 2, 3 }, // 15 + { 1, 1,18, 3, 1, 5, 4 }, // 16 + { 1, 4,18,18, 2, 3,-2 }, // 17 + { 0, 1, 1,-1,-1, 2,17 }, // 18 + { 0, 2,18,17, 3, 2, 5 }, // 19 + { 0, 1,18,18,18, 2,17 }, // 20 + { 0, 1,18,17,-1, 2,18 }, // 21 + { 1, 1,17, 3, 2, 1, 7 }, // 22 + { 0, 2,18,-2,18, 2, 3 }, // 23 + { 1, 3,18,-3,18, 2, 3 }, // 24 + { 0, 3,18,17, 2, 3,17 }, // 25 + { 1, 1,17,17, 2, 1, 4 }, // 26 + { 0, 1,17,18,-2, 2,17 }, // 27 + { 1, 1,18,18, 3, 5, 2 }, // 28 + { 0, 1,17,17, 2,18, 4 }, // 29 + { 0, 1,18,17, 1, 4, 6 }, // 30 + { 1, 1, 3,17,18, 2,17 }, // 31 + { 1, 1,17, 3, 2, 1, 7 }, // 32 + { 0, 1,18,17,-1, 2, 3 }, // 33 + { 1, 1,17,17, 2, 1, 4 }, // 34 + { 1, 2,18,17,-1,17, 3 }, // 35 + { 1, 2,18,17, 2, 3,-1 }, // 36 + { 0, 2,18,18,-2, 2,17 }, // 37 + { 0, 1,17,17, 2,18, 4 }, // 38 + { 0, 5,-2,18,18,18, 2 }, // 39 + { 1, 1,18,18,-1, 6, 3 }, // 40 + { 0, 1,17,17,-2, 2, 3 }, // 41 + { 1, 1,18,17,18, 2,17 }, // 42 + { 0, 1,18,17, 4, 3, 1 }, // 43 + { 0, 1,-2,18, 2, 2,18 }, // 44 + { 1, 2,18,18,-2, 2,-1 }, // 45 + { 1, 1,17,17, 2, 1, 4 }, // 46 + { 0, 1,17,18,-2, 2,17 }, // 47 + { 1, 1,17, 3, 2, 1, 7 }, // 48 + { 1, 3,18,-3,18, 2, 3 }, // 49 + { 1, 2,18,18,-2, 2,-1 }, // 50 + { 1, 1,18,18, 3, 5, 2 }, // 51 + { 0, 2,18,18,-1, 2,17 }, // 52 + { 0, 1,18,-1,17,18, 2 }, // 53 + { 0, 1,17,-1, 2, 3, 6 }, // 54 + { 0, 1,18,-2,18, 2, 5 }, // 55 + { 1, 2,18,18,-2, 2,-1 }, // 56 + { 0, 3,18,18, 2, 3,17 }, // 57 + { 0, 1,17,17, 2,18, 4 }, // 58 + { 1, 1,17,-2,17, 1, 2 }, // 59 + { 0, 1,-1, 3, 5, 4, 7 }, // 60 + { 0, 3,18,18, 3, 2, 5 }, // 61 + { 0, 1,17,17, 2,18, 4 }, // 62 + { 0, 1,18,17,-2,18, 3 }, // 63 + { 0, 2,18,18,-2, 2,17 }, // 64 + { 0, 3,18,17,-2, 2, 3 }, // 65 + { 1, 1,18,18,-2, 2,17 }, // 66 + { 0, 1,18,17, 4, 3, 1 }, // 67 + { 1, 2, 3,18,17, 2,17 }, // 68 + { 1, 2,18,18, 2,-2,18 }, // 69 + { 1, 2,18,18,-1,18, 2 }, // 70 + { 0, 2,18,18,-2, 2,17 }, // 71 + { 1, 3,18,18, 2, 3,-2 }, // 72 + { 0, 3,18,18, 3, 2, 5 }, // 73 + { 0, 1,18,-2,18, 2, 5 }, // 74 + { 1, 1,17, 3, 2, 1, 7 }, // 75 + { 1, 3,18,18,-2, 2,18 }, // 76 + { 1, 1,17,18,18,-2, 2 }, // 77 + { 0, 1,18,-2,18, 2, 5 }, // 78 + { 0, 2,18,-2,18, 2, 3 }, // 79 + { 0, 1,-1, 3, 4, 5, 7 }, // 80 + { 1, 1,17,17, 2,-1, 7 }, // 81 + { 0, 1,18,-1,-1, 2,-2 }, // 82 + { 0, 2,18,17, 2, 3,17 }, // 83 + { 0, 1,18,17, 2,18, 2 }, // 84 + { 0, 2,18,17,-1, 2,17 }, // 85 + { 0, 1, 1,18, 3, 2, 5 }, // 86 + { 0, 2,18,-2, 4,18, 2 }, // 87 + { 1, 1,18, 3, 1, 5, 4 }, // 88 + { 0, 1,18,17,18, 2, 5 }, // 89 + { 1, 1,18, 3, 1, 5, 4 }, // 90 + { 0, 4,18,18,-2, 2,18 }, // 91 + { 1, 1,18,18, 3, 2, 5 }, // 92 + { 1, 1,17,17, 2, 1, 4 }, // 93 + { 0, 2,18,18,-2,18, 2 }, // 94 + { 0, 2,18,18,-2,18, 2 }, // 95 + { 1, 1,18,18, 2, 1, 3 }, // 96 + { 1, 1,17,17, 2, 1, 4 }, // 97 + { 1, 2,17,17, 2,18, 3 }, // 98 + { 0, 1,18,17, 1, 4, 6 }, // 99 + { 1, 2,18,18,-2, 2,-1 }, // 100 + { 0, 1,18,-2,18, 2, 5 }, // 101 + { 1, 1,17, 2,18, 2,17 }, // 102 + { 0, 2,18,18,-2,18, 2 }, // 103 + { 0, 1,18,18, 3, 6,-1 }, // 104 + { 0, 1,18,17, 2,18, 3 }, // 105 + { 0, 1,18,17,-2, 2,17 }, // 106 + { 1, 1, 3,17,18, 2,17 }, // 107 + { 1, 3,18,-3,18, 2, 3 }, // 108 + { 1, 3,18,18,-3,18, 2 }, // 109 + { 1, 1,18, 3, 1, 5, 4 }, // 110 + { 0, 1,17,-2,17, 2,-3 }, // 111 + { 1, 1,18,18, 3, 5, 2 }, // 112 + { 1, 2,18,18,-2, 2,-1 }, // 113 + { 0, 1,18,-1,-1, 2,-2 }, // 114 + { 1, 1,18, 3, 1, 5, 4 }, // 115 + { 0, 3,18,17,-1, 2,17 }, // 116 + { 1, 3,18,17, 2,18,-2 }, // 117 + { 0, 2,18,18,-2,18, 2 }, // 118 + { 1, 2,18,18,-2, 2,-1 }, // 119 + { 1, 1,18, 3, 1, 5, 4 }, // 120 + { 0, 4, 3,18,18, 2,17 }, // 121 + { 0, 2,18,18,-2,18, 2 }, // 122 + { 1, 1,18,17,-1,18, 2 }, // 123 + { 0, 2,18,18,-2,18, 2 }, // 124 + { 0, 2,18,18,-2,18, 2 }, // 125 + { 0, 2,18,18,-2,18, 2 }, // 126 + { 0, 2,18,18,-2,18, 2 }, // 127 + { 1, 1,18,18,18, 3, 2 }, // 128 + { 0, 1,17,-1, 2, 3, 6 }, // 129 + { 0, 1,17,-1, 2, 3, 6 }, // 130 + { 0, 2,18,17,-2, 3, 2 }, // 131 + { 1, 3,18,17, 2,-2,18 }, // 132 + { 0, 2,18,18, 2,17, 3 }, // 133 + { 0, 1,18,18, 2,18,-2 }, // 134 + { 0, 2,18,-2, 4,18, 2 }, // 135 + { 0, 1,-2,18, 2, 2,18 }, // 136 + { 0, 2,18,17, 3, 6, 2 }, // 137 + { 0, 1,18,17,18, 2, 5 }, // 138 + { 0, 3,18,18,-2, 3, 2 }, // 139 + { 1, 1,18,18, 2,18, 5 }, // 140 + { 0, 1,17,-1, 2, 3, 6 }, // 141 + { 1, 4,18,18, 2, 3,-2 }, // 142 + { 0, 2,18,17,18, 2,-2 }, // 143 + { 0, 1, 1,18, 3, 2, 5 }, // 144 + { 1, 4,18,-2,18, 2, 3 }, // 145 + { 1, 2,18, 2,18, 3,-2 }, // 146 + { 0, 2,18,18,18, 2, 4 }, // 147 + { 0, 2, 3,17,18, 2,17 }, // 148 + { 1, 1,18,-1,18, 2,17 }, // 149 + { 1, 2,17,17, 2,18, 3 }, // 150 + { 0, 2,18,17,-2, 3, 2 }, // 151 + { 0, 1, 1,-1,-1, 2,17 }, // 152 + { 0, 3, 3,18,18, 2,17 }, // 153 + { 0, 1,18,-1,17,18, 2 }, // 154 + { 0, 1,18,17, 2,18, 3 }, // 155 + { 0, 2,18,18,-2,18, 2 }, // 156 + { 0, 1,18,17, 2,18, 2 }, // 157 + { 0, 2,18,18,-2,18, 2 }, // 158 + { 0, 2,18,18,-2,18, 2 }, // 159 + { 1, 2,17,17, 2,18, 3 }, // 160 + { 0, 1,18,17,-2, 2, 3 }, // 161 + { 0, 1,18,-2,18, 2, 5 }, // 162 + { 1, 4,18,-2,18, 2, 3 }, // 163 + { 1, 3,18,17, 2, 3, 6 }, // 164 + { 0, 2,18,18, 2,17, 3 }, // 165 + { 0, 2,18,17, 2,18, 2 }, // 166 + { 0, 2,18,18,-2,18, 2 }, // 167 + { 1, 1,18,18, 3, 5, 2 }, // 168 + { 0, 2,18,18,-2, 2, 3 }, // 169 + { 1, 2,18,17, 2,17, 3 }, // 170 + { 0, 1,18,17, 2, 3,18 }, // 171 + { 0, 2,18,18,-2,18, 2 }, // 172 + { 1, 4,18,18, 2, 3,-2 }, // 173 + { 0, 1,17,-2,17, 2,-3 }, // 174 + { 0, 1,17,17, 2,18, 4 }, // 175 + { 1, 1,18,18,18, 2, 4 }, // 176 + { 1, 2,18, 2,18, 3,-2 }, // 177 + { 1, 1,18,18,-2, 2,17 }, // 178 + { 0, 2,18,18,-2,18, 2 }, // 179 + { 0, 2,18,18, 2,17, 3 }, // 180 + { 0, 2,18,18,18, 2, 4 }, // 181 + { 0, 2,18,18,-2,18, 2 }, // 182 + { 0, 2,18,17,-2, 3, 2 }, // 183 + { 0, 1, 1,-1,-1, 2,17 }, // 184 + { 1, 4,18,18, 2, 3,-2 }, // 185 + { 0, 2,18,18,-2,18, 2 }, // 186 + { 0, 1,18,-2,18, 3, 2 }, // 187 + { 0, 2,18,18,-2,18, 2 }, // 188 + { 0, 2,18,18,-2,18, 2 }, // 189 + { 0, 2,18,18,-2,18, 2 }, // 190 + { 0, 2,18,18,-2,18, 2 }, // 191 + { 0, 1,18,18,-2, 2,17 }, // 192 + { 0, 3,18,17, 2, 3,17 }, // 193 + { 1, 2,18,18, 2,-2,18 }, // 194 + { 0, 1,-1, 3, 5, 4, 7 }, // 195 + { 1, 1,18, 3, 1, 5, 4 }, // 196 + { 1, 1,18,18,-2,18, 3 }, // 197 + { 0, 2,18,17,18, 2,-2 }, // 198 + { 0, 2,18,18, 2,17, 3 }, // 199 + { 1, 2,18, 2,18, 3,-2 }, // 200 + { 1, 4,18,18, 2, 3,-2 }, // 201 + { 1, 3,18,17, 2, 3, 6 }, // 202 + { 0, 2,18,18,-2,18, 2 }, // 203 + { 1, 2,18,17,-2,-1,17 }, // 204 + { 0, 1,17,-1, 2, 3, 6 }, // 205 + { 0, 2,18,18,-2,18, 2 }, // 206 + { 0, 2,18,18,-2, 2, 3 }, // 207 + { 1, 1,18,18,18, 2, 5 }, // 208 + { 0, 1,17,17,-2, 2, 3 }, // 209 + { 0, 2,18,18,-2,18, 2 }, // 210 + { 0, 2,18,17, 3, 6, 2 }, // 211 + { 0, 2,18,17,18, 2, 3 }, // 212 + { 0, 3,18,17,-3,18, 2 }, // 213 + { 0, 1,18,18,18, 2, 3 }, // 214 + { 0, 1,18,-2,-3, 2, 6 }, // 215 + { 0, 2,18,18,-2,18, 2 }, // 216 + { 1, 1,18,17,18, 2, 5 }, // 217 + { 0, 2,18,18,-2,18, 2 }, // 218 + { 0, 2,18,18,-2,18, 2 }, // 219 + { 1, 1,18,17,18, 2, 5 }, // 220 + { 0, 2,18,18,-2,18, 2 }, // 221 + { 0, 2,18,18,-2,18, 2 }, // 222 + { 0, 2,18,18,-2,18, 2 }, // 223 + { 0, 1,18,18,18, 2, 3 }, // 224 + { 1, 1,17,-2,17, 1, 2 }, // 225 + { 1, 1,17,17, 2,-1, 7 }, // 226 + { 0, 1,18,17, 4, 3, 1 }, // 227 + { 1, 3,18,-3,18, 2, 3 }, // 228 + { 0, 1, 1,18, 3, 2, 5 }, // 229 + { 0, 2,18,18,-2,18, 2 }, // 230 + { 0, 2,18,18,-2,18, 2 }, // 231 + { 0, 1,18,18, 3, 6, 2 }, // 232 + { 0, 1,17,17, 2,18, 4 }, // 233 + { 0, 1,17,17, 2,18, 4 }, // 234 + { 0, 2,18,18,-2,18, 2 }, // 235 + { 0, 2,18,18,-2,18, 2 }, // 236 + { 0, 2,18,18,-2,18, 2 }, // 237 + { 1, 2,18,-2,18, 3, 2 }, // 238 + { 1, 1,17,-2,17, 1, 2 }, // 239 + { 1, 1,18,18, 3, 2, 5 }, // 240 + { 0, 1,18,18,-1, 2, 3 }, // 241 + { 0, 2,18,18,-2,18, 2 }, // 242 + { 0, 2,18,18,-2,18, 2 }, // 243 + { 0, 1,18,17,18, 2, 5 }, // 244 + { 0, 2,18,18,-2,18, 2 }, // 245 + { 0, 2,18,18,-2,18, 2 }, // 246 + { 0, 2,18,18,-2,18, 2 }, // 247 + { 0, 2,18,18,-2,18, 2 }, // 248 + { 0, 1, 3,18,18, 2,17 }, // 249 + { 0, 2,18,18,-2,18, 2 }, // 250 + { 0, 2,18,18,-2,18, 2 }, // 251 + { 0, 2,18,18,-2,18, 2 }, // 252 + { 0, 2,18,18,-2,18, 2 }, // 253 + { 0, 2,18,18,-2,18, 2 }, // 254 + { 0, 2,18,18,-2,18, 2 }, // 255 +}; + +static const WavpackDecorrSpec high_specs [] = { + { 1, 2,18,18,18,-2, 2, 3, 5,-1,17, 4 }, // 0 + { 0, 1,18,17,-2, 2,18, 3, 7, 2, 5, 4 }, // 1 + { 1, 2, 1,18, 3, 6,-2,18, 2, 3, 4, 5 }, // 2 + { 0, 2,18,18,-2, 2,18, 3, 6, 2,17, 4 }, // 3 + { 1, 2,18,18, 2,18, 3, 2,-1, 4,18, 5 }, // 4 + { 1, 1, 7, 6, 5, 3, 4, 2, 5, 4, 3, 7 }, // 5 + { 1, 1,17, 3,18, 7, 2, 6, 1, 4, 3, 5 }, // 6 + { 1, 1,-2,18,18,18, 3,-2, 6, 5, 2, 1 }, // 7 + { 1, 2,18,18,-1,18, 2, 3, 6,-2,17, 5 }, // 8 + { 0, 1,17,17,18, 3, 6, 4, 5, 2,18,-2 }, // 9 + { 1, 2, 1,18,-2, 3, 5, 2, 4,-1, 6, 1 }, // 10 + { 0, 2,18,18, 3, 6,18, 2, 4, 8, 5, 3 }, // 11 + { 0, 1,-2, 1,18, 2,-2, 7,18, 2,-1, 5 }, // 12 + { 1, 1, 4, 3, 8, 1, 5, 2, 5, 6, 2, 8 }, // 13 + { 1, 1,17,18, 2, 6, 3, 4,-1, 1, 8, 6 }, // 14 + { 0, 1,18,18, 3, 6, 3,-2, 2, 5,-1, 1 }, // 15 + { 0, 1,18,18,17,-1, 2,-2,18, 3, 4, 5 }, // 16 + { 1, 2,18,17, 2,-2,18, 3, 5, 7, 2, 4 }, // 17 + { 1, 2,18,18, 3, 6,-2,18, 2, 5, 8, 3 }, // 18 + { 0, 1,18,17, 2,18,18, 2, 6, 5,17, 7 }, // 19 + { 1, 2,18,17, 2,18, 3, 2, 6,18,-1, 4 }, // 20 + { 1, 1, 5, 3, 6, 5, 3, 4, 1, 2, 4, 7 }, // 21 + { 1, 1, 5, 3, 6, 5, 3, 4, 1, 2, 4, 7 }, // 22 + { 0, 1,-2,18,18,18,-2, 3, 2, 4, 6, 5 }, // 23 + { 1, 2,18,17,-3, 3,-1,18, 2, 3, 6, 5 }, // 24 + { 0, 1,17,18, 7, 3,-2, 7, 1, 2, 4, 5 }, // 25 + { 1, 1, 2,18,18,-2, 2, 4,-1,18, 3, 6 }, // 26 + { 0, 3, 1,18, 4, 3, 5, 2, 4,18, 2, 3 }, // 27 + { 0, 1,-2,18, 2,18, 3, 7,18, 2, 6,-2 }, // 28 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 29 + { 1, 1,18,18, 5, 4, 6, 4, 5, 1, 4, 3 }, // 30 + { 1, 1,18, 3, 6, 5, 7, 8, 2, 3, 1,-1 }, // 31 + { 1, 1,18,18,18, 2,-2, 3, 5,18, 2, 8 }, // 32 + { 0, 2,18,17,-2, 2, 3,18,-3, 5, 2, 7 }, // 33 + { 1, 1, 1, 1,-1, 8,17, 3,-2, 2, 6,17 }, // 34 + { 0, 2,18,18,17, 2,-2, 3, 2, 4,18, 5 }, // 35 + { 1, 1,17,18, 2,-1, 5, 7,18, 3, 4, 6 }, // 36 + { 1, 1, 5, 4, 5,17, 3, 6, 3, 4, 7, 2 }, // 37 + { 0, 1,17, 3, 1, 7, 4, 2, 5,-2,18, 6 }, // 38 + { 0, 1,17,18, 2,18, 4, 3, 5, 7,-3, 6 }, // 39 + { 1, 2,17,17,-3,-2, 2, 8,18,-1, 3, 5 }, // 40 + { 0, 1,17,17,18, 2, 3, 6,-2, 8, 1, 7 }, // 41 + { 1, 1, 1, 2, 6,-2,18, 2, 5,-3, 7,-2 }, // 42 + { 0, 1,18,18, 3,18, 6, 8,-2, 2, 3, 5 }, // 43 + { 0, 1,18,17, 2,18,-2, 3, 7, 6, 2, 4 }, // 44 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 45 + { 1, 1,18,18, 2,-1, 3, 6, 1, 3, 4, 8 }, // 46 + { 0, 1,18,18, 3, 6, 5, 3,-2, 2,18,-1 }, // 47 + { 0, 1,18,17,-3,18, 2, 4,-2, 3, 6,17 }, // 48 + { 1, 3, 1, 2,17, 3,18, 7,-1, 5, 2, 4 }, // 49 + { 1, 1,18, 3,18, 6, 8,18,-2, 5, 7, 2 }, // 50 + { 0, 1,17, 2,18, 6, 3, 2, 5, 4, 8, 1 }, // 51 + { 0, 1,18,17,-1, 2, 3,18,18, 2, 3,17 }, // 52 + { 1, 1,18, 7, 6, 5, 5, 3, 1, 4, 2, 4 }, // 53 + { 1, 1, 6,17, 3, 8, 1, 5, 7,-1, 2, 1 }, // 54 + { 1, 1,18,-2,18, 3,-2, 2, 7, 4, 6,18 }, // 55 + { 1, 3,18,-3,18, 2, 3,18,-1, 7, 2, 5 }, // 56 + { 0, 2,18,-2, 7, 1, 3, 2, 4, 6,-3, 7 }, // 57 + { 1, 1,18,-2, 2,-3,18,-2,17,-1, 4, 2 }, // 58 + { 0, 3,17,17, 2, 5, 3, 7,18, 6, 4, 2 }, // 59 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 60 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 61 + { 1, 1,18,17, 4, 6, 6, 4, 5, 3, 4, 1 }, // 62 + { 0, 1,18, 5, 3, 6, 2, 3, 8, 1, 3, 7 }, // 63 + { 1, 2,18,17,-2, 2,18, 3, 5, 7,-1, 2 }, // 64 + { 0, 1, 1,18,18, 3, 6,-1, 4, 8, 5, 2 }, // 65 + { 1, 1, 1, 5, 3, 4, 1, 1, 3, 5, 7, 3 }, // 66 + { 0, 1, 3,18,18, 2,18,18,-1, 2, 3,18 }, // 67 + { 1, 2,18,18,-1,18, 2, 3, 4, 6,18, 5 }, // 68 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 69 + { 1, 1,18, 3, 1, 4, 5, 2, 7, 1, 3, 6 }, // 70 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 71 + { 1, 2,18,18,-1,18, 2, 3, 5,-2, 6, 8 }, // 72 + { 1, 1,17,18, 4, 8, 3, 2, 5, 2, 7, 6 }, // 73 + { 1, 4, 1, 2, 5,18,-2, 2, 3, 7,-1, 4 }, // 74 + { 0, 2,18,17,-1, 3, 6,18, 2, 3, 7, 5 }, // 75 + { 0, 1,-2,18, 2,-3, 6,18, 4, 3,-2, 5 }, // 76 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 77 + { 0, 1,17,17, 6, 2, 4, 8, 3, 5,-1,17 }, // 78 + { 1, 1,18, 3,18, 6, 8,18,-2, 5, 7, 2 }, // 79 + { 1, 2,17,17,-3, 2,18,-2, 8, 3, 6,-1 }, // 80 + { 1, 1,18,-2,17,18, 2, 3,-2, 6, 5, 4 }, // 81 + { 1, 2,18,17,-1, 3,18, 2, 5, 3, 6,-3 }, // 82 + { 0, 1,18,17, 2,18, 7,18, 2, 4, 3,17 }, // 83 + { 1, 3,18,18, 5, 6, 4, 3, 4,18, 6, 5 }, // 84 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 85 + { 1, 1, 7, 6, 5, 3, 4, 2, 5, 4, 3, 7 }, // 86 + { 0, 1,-2,18,18,18, 3, 6, 4, 2, 5, 2 }, // 87 + { 0, 3,18,17,-3,18, 3, 2, 5,-1,17, 3 }, // 88 + { 1, 1,17,18, 7, 3, 1, 7, 4, 2, 6, 5 }, // 89 + { 1, 1,18, 2,-2,-1,18, 5, 3,-2, 1, 2 }, // 90 + { 0, 3,18,18,-1, 3, 2, 7, 5,18, 4, 3 }, // 91 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 92 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 93 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 94 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 95 + { 1, 1,17,18, 2,-2, 4, 8,18, 3, 6, 5 }, // 96 + { 0, 2,18,17, 3, 5,-2, 7, 2,18, 3,-1 }, // 97 + { 1, 1,18, 2,-2,-1,18, 5, 3,-2, 1, 2 }, // 98 + { 0, 2, 3,17,18,18, 2, 5, 7, 6,18, 3 }, // 99 + { 1, 1,17,18,18, 4, 3, 2,18, 7, 8,-1 }, // 100 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 101 + { 0, 1,17, 1, 2, 3, 5, 6, 1, 4, 8,17 }, // 102 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 103 + { 0, 2,18,17,-1,18,-3, 2, 8, 3, 6,17 }, // 104 + { 1, 1,17,17, 1, 2, 4, 5,-1, 2, 1, 6 }, // 105 + { 1, 1, 1, 2, 6,-2,18, 2,-3, 3,-2, 5 }, // 106 + { 0, 1,18, 3,18, 6,18, 5, 2, 4,-1, 8 }, // 107 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 108 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 109 + { 1, 1,18,18,-1, 2,18, 3, 6, 4,-2, 7 }, // 110 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 111 + { 0, 2,-1,18,18,18, 2,-2, 4, 7, 2, 3 }, // 112 + { 0, 3, 3,17,-2, 5, 2, 7,18, 6, 4, 5 }, // 113 + { 0, 1,17, 6,18, 3, 8, 4, 5, 3, 8,18 }, // 114 + { 0, 2,18, 2, 6, 2,18, 3, 2, 4, 5, 8 }, // 115 + { 0, 1, 3,18,18, 2,18,-1, 2,18, 2,17 }, // 116 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 117 + { 0, 1, 3, 6,17,-2, 5, 1, 2, 7, 4, 8 }, // 118 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 119 + { 1, 3, 3,18,17, 5, 6, 2, 7,-2, 8,18 }, // 120 + { 1, 1,18,-1, 3, 1, 7, 2,-1, 4, 6,17 }, // 121 + { 1, 1,18, 2,-2,-1,18, 5, 3,-2, 1, 2 }, // 122 + { 0, 2,18, 1, 2,18, 3, 6, 5, 2, 4, 8 }, // 123 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 124 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 125 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 126 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 127 + { 1, 1,17,-2, 2,18,18, 8, 5, 3, 2, 6 }, // 128 + { 0, 1,18,17, 2,18, 3, 2, 7,-2,18, 4 }, // 129 + { 1, 2, 1,18, 2, 3,-1, 5, 6, 4, 7,17 }, // 130 + { 0, 2,18,17, 3, 6,-2, 2, 3, 8, 5,17 }, // 131 + { 0, 2,18,18, 3, 2,18,-1, 2, 4, 3,17 }, // 132 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 133 + { 1, 2,17,-1,18, 2, 3,-2, 5,18, 2, 7 }, // 134 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 135 + { 1, 2,18,-3,18, 2, 3,-2,18, 5, 6,-3 }, // 136 + { 0, 2,18,17, 3, 5,-2, 7, 2,18, 3,-1 }, // 137 + { 1, 1, 1,18,-1, 2, 3, 1,-2, 8, 2, 5 }, // 138 + { 0, 1,18,18, 3, 6,18, 2, 3, 4, 8, 5 }, // 139 + { 0, 1,-2, 1,18, 2,-2, 5, 7,18, 2,-1 }, // 140 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 141 + { 1, 1,17,18,-1, 2, 8, 3, 4, 5, 1, 7 }, // 142 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 143 + { 0, 2,18,18,-1, 2,18, 3,-2, 5, 4, 2 }, // 144 + { 1, 1,18,17, 2,18, 3, 8, 5, 2, 7,17 }, // 145 + { 0, 1,18,18, 3,18, 6, 8,-2, 2, 3, 5 }, // 146 + { 0, 1,18,18, 2,18, 2, 6,18, 2,17, 7 }, // 147 + { 1, 3,18,17,18, 2, 8,18, 5,-1, 3, 6 }, // 148 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 149 + { 1, 1,18, 7, 6, 5, 5, 3, 1, 4, 2, 4 }, // 150 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 151 + { 1, 2,18,17,-1, 3, 6,18, 2, 5, 8, 3 }, // 152 + { 0, 1,17,18,18, 4, 7, 2, 3,-2,18, 5 }, // 153 + { 1, 2,18, 1, 2, 6, 2, 5,18, 2, 4, 8 }, // 154 + { 0, 4,18, 4, 1, 2, 3, 5, 4, 1, 2, 6 }, // 155 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 156 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 157 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 158 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 159 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 160 + { 0, 2,18,17, 2,-1,18, 3,-3, 5, 2, 4 }, // 161 + { 0, 1,17,17, 3, 6, 3, 5,-2, 2,18,-1 }, // 162 + { 0, 2,18,18, 3,-2,18, 2,-3, 5, 3, 6 }, // 163 + { 1, 1,17,17, 2, 4, 1, 3, 5, 2, 6,-3 }, // 164 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 165 + { 0, 1,17, 1, 3, 2, 7, 1, 6, 3, 4, 8 }, // 166 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 167 + { 0, 1,17,-1,18, 2, 1, 5, 3, 8,-1,-2 }, // 168 + { 1, 1,17,18,-1, 8, 2, 5, 3, 4, 1, 6 }, // 169 + { 1, 2, 1,18, 3,-1, 5, 1, 2, 4, 7, 6 }, // 170 + { 0, 1,18,18, 3, 6, 5, 3,-2, 2,18,-1 }, // 171 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 172 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 173 + { 0, 1, 1,18,-1, 3, 8, 5, 6, 1, 2, 3 }, // 174 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 175 + { 0, 2,18,18, 2, 3, 6,18,-1, 4, 2, 3 }, // 176 + { 1, 1, 1, 3, 5,18, 2, 6, 7, 2, 3, 1 }, // 177 + { 1, 1, 1, 3, 8,18, 5, 2, 7, 1, 3,-2 }, // 178 + { 0, 2,17, 2,18, 3, 6, 2, 4, 5, 8, 3 }, // 179 + { 0, 1,18,17, 2,18, 3, 2, 7,-2,18, 4 }, // 180 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 181 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 182 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 183 + { 1, 2,18,-3,18,-1, 3,-2, 5, 7, 1, 2 }, // 184 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 185 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 186 + { 0, 3,18,18, 2, 6,18, 5,18, 2, 3,17 }, // 187 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 188 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 189 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 190 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 191 + { 1, 3, 1,-1, 1, 3,-2, 2, 5, 7,-3,18 }, // 192 + { 1, 2,18, 7, 3,-3, 2, 8, 2, 5, 4,17 }, // 193 + { 1, 1, 1, 4, 5, 1, 3, 4, 6, 7, 8, 3 }, // 194 + { 0, 1,18,17, 2,18,-1, 2, 3,18, 2, 4 }, // 195 + { 0, 2,18,18,-2,18, 2, 3, 4, 7, 5,17 }, // 196 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 197 + { 1, 1,17,18, 2, 1, 3, 2, 5, 1, 2, 3 }, // 198 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 199 + { 0, 2,18,18,-1, 2, 3, 5, 8, 6, 1,-2 }, // 200 + { 0, 1,17,18, 8, 3, 4, 6, 5, 2, 8, 7 }, // 201 + { 1, 2, 1, 3,-2,18, 2, 5, 1, 7,-1,-2 }, // 202 + { 0, 3,18,17,-1, 3,18, 2, 3, 6, 4,17 }, // 203 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 204 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 205 + { 1, 2,18,18, 4,18, 6, 7, 8, 3,18, 2 }, // 206 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 207 + { 0, 2,17,-3,17, 2,-2, 8, 3,18, 4,-3 }, // 208 + { 1, 1,18,17, 3, 5, 6, 2, 8, 1, 3, 7 }, // 209 + { 0, 1,18,18, 3, 6, 5, 3,-2, 2,18,-1 }, // 210 + { 0, 3,18,18, 2, 6,18, 5,18, 2, 3,17 }, // 211 + { 1, 1,18,18, 5, 4, 6, 4, 5, 1, 4, 3 }, // 212 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 213 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 214 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 215 + { 0, 2, 3,17,18,-3, 2, 5,18, 6,-1, 7 }, // 216 + { 1, 1,17,18, 3, 2, 5,-1, 6, 8, 4, 7 }, // 217 + { 1, 1,18, 1,-2, 3, 2, 1, 7, 6, 3, 4 }, // 218 + { 0, 3, 1, 2,17, 3,18, 2, 7, 5, 4,-1 }, // 219 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 220 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 221 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 222 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 223 + { 1, 1,17,-2, 2,18,18, 8, 5, 3, 2, 6 }, // 224 + { 0, 2,18, 5,18, 2, 3, 7,-2, 1, 6, 8 }, // 225 + { 0, 1, 2,-1,18,-1, 2, 4,-3, 5,18, 3 }, // 226 + { 0, 1, 3,17,18, 5, 2,18, 7, 3, 6, 5 }, // 227 + { 1, 4, 1, 2, 5,18,-2, 2, 3, 7,-1, 4 }, // 228 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 229 + { 0, 1, 1,18, 2, 1, 3, 4, 1, 5, 2, 7 }, // 230 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 231 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 232 + { 0, 1,17,17,18, 2, 4, 5,18,-2, 6, 3 }, // 233 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 234 + { 0, 2,18,18,-1, 3, 5, 6, 8,18, 2, 3 }, // 235 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 236 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 237 + { 0, 1,18,18, 4, 6, 8,18, 7, 3, 2, 5 }, // 238 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 239 + { 0, 2,-1,18,18,18, 2, 4,-2, 2, 3, 6 }, // 240 + { 0, 2,18,-2, 7, 1, 3, 2, 4, 6,-3, 7 }, // 241 + { 1, 1,17,18, 8, 3, 4, 6,-2, 5, 3, 8 }, // 242 + { 0, 2,18, 1, 2, 6, 2, 8, 3,18, 5, 4 }, // 243 + { 1, 1, 3,18,18, 2,18, 2,18, 3, 2,18 }, // 244 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 245 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 246 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 247 + { 1, 1, 3,17,18, 5, 2, 6, 7, 1, 4, 8 }, // 248 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 249 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 250 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 251 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 252 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 253 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 254 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 255 +}; + +static const WavpackDecorrSpec very_high_specs [] = { + { 1, 2,18,18, 2, 3,-2,18, 2, 4, 7, 5, 3, 6, 8,-1,18, 2 }, // 0 + { 0, 1,18,18,-1,18, 2, 3, 4, 6, 5, 7,18,-3, 8, 2,-1, 3 }, // 1 + { 1, 2, 1,18,-2, 4,18, 2, 3, 6,-1, 7, 5,-2,18, 8, 2, 4 }, // 2 + { 0, 1,17,17, 2, 3, 4,18,-1, 5, 6, 7,18, 2, 8,17, 3,-2 }, // 3 + { 1, 1,18,18, 2,18, 3, 2,18, 4,-1, 3,18, 2, 6, 8,17, 5 }, // 4 + { 0, 2,18,17, 2, 3,-2, 5,18,-3, 2, 4, 7, 3, 6, 8, 5,17 }, // 5 + { 1, 1,18,-2, 2,-3,18, 5,-2,18, 2, 3, 6, 2,17, 4, 7,-1 }, // 6 + { 1, 1,17, 8,18, 3,-2, 2, 5, 4,18, 6, 3, 8, 7, 2, 5, 4 }, // 7 + { 0, 2,18,17,-2, 2,18, 3, 2, 5,-3, 4, 7,18, 3, 8, 6, 2 }, // 8 + { 1, 1, 3, 6, 5, 5, 1, 3, 7, 4, 2, 6, 4,18, 3, 7, 5, 6 }, // 9 + { 1, 2, 1,18, 3, 2,-2, 1, 5, 4, 6, 2, 7, 1, 8, 3,-1, 1 }, // 10 + { 0, 1,18,18, 2, 3, 6, 3, 5,-2, 2, 4,18, 3,-2,-1, 6, 7 }, // 11 + { 0, 1,-2,18, 2,18, 7, 2, 6,-2, 3, 4,18,18, 2,-3, 8, 5 }, // 12 + { 0, 2,18,18,18, 2, 4, 3,18, 5, 3, 6,-2, 2, 4,18, 8, 7 }, // 13 + { 0, 1,-2, 1,18, 2,-2,18,-1, 5, 7, 2, 3, 4,18, 2, 6, 2 }, // 14 + { 1, 1,17,18, 3, 2, 1, 7,-1, 2, 4, 3, 5, 6,-2,18, 7, 8 }, // 15 + { 1, 1,18,18, 2,18, 3, 4, 6,-2,18, 5, 8, 2, 3, 7, 4,-1 }, // 16 + { 0, 1,18,18,18,-1, 2, 3, 4, 6, 8,18, 3, 5, 2, 6, 7, 4 }, // 17 + { 1, 1,17,-2,18,18, 2, 5, 3, 8, 2,-1, 6, 1, 3, 4, 7, 5 }, // 18 + { 0, 1,17,17,18, 2, 3, 6,-2, 8, 1, 7, 5, 2, 3, 1, 4, 8 }, // 19 + { 1, 1,17,17, 3, 2, 7, 1, 4, 3, 6, 2, 5,-2, 8, 7,18, 6 }, // 20 + { 0, 1,18,17,-2, 2,18, 3,-3, 7, 6, 5, 2, 4,-1, 8, 3,17 }, // 21 + { 1, 1, 2,18,18,-2, 2, 4,-1, 5,18, 3, 8, 6, 2, 7,17, 4 }, // 22 + { 0, 1,17, 3, 6, 8, 5, 4, 3, 8, 1,18, 7, 2, 4, 5, 6, 3 }, // 23 + { 1, 2,17,18, 4, 8, 3, 2, 5, 7, 6, 8, 2, 7,-2,18, 3, 4 }, // 24 + { 1, 1, 6, 5, 5, 3, 4, 7, 3, 2, 4, 6, 3, 7, 1, 5, 2, 4 }, // 25 + { 1, 1, 1,18,-1, 2, 1, 3, 8,-2, 2, 5, 6, 3, 8, 7,18, 4 }, // 26 + { 0, 1, 1,17,-1,18, 3, 2, 5, 4, 6, 7, 8, 3, 4, 2, 1,-2 }, // 27 + { 0, 1,18, 2,18,18, 2,18, 6,-2,18, 7, 5, 4, 3, 2,18,-2 }, // 28 + { 0, 3, 1, 4,18, 3, 2, 4, 1, 5, 2, 3, 6,18, 8, 7, 2, 4 }, // 29 + { 0, 1,17,-2, 1,-3, 2,18, 3,-2, 4,18, 3, 6, 7,-3, 2, 8 }, // 30 + { 1, 1,17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 }, // 31 + { 1, 2,18,-1,17,18, 2, 3,-2,18, 5, 8, 2, 4, 3, 7, 6,-1 }, // 32 + { 1, 1,18,18,18,-2, 4, 2, 3,18, 5, 8, 2, 4, 6, 7,-2, 3 }, // 33 + { 1, 2,18,18,-2,18,-1, 3, 2, 5,18,-2, 7, 2, 3, 4, 6, 8 }, // 34 + { 0, 1,17,18,-1, 2, 4,18, 8, 3, 6, 5, 7,-3, 2, 4, 3,17 }, // 35 + { 1, 1,18,18,17, 2,-1,18, 3, 2,18, 6, 5, 4,18, 7, 2,-1 }, // 36 + { 0, 2, 1,18,-1,18, 3, 2, 4, 6,-3, 7,-1, 5, 1, 2, 3, 8 }, // 37 + { 1, 1, 1,17,-2, 2,-3, 6, 3, 5, 1, 2, 7, 6, 8,-2, 4, 1 }, // 38 + { 0, 1,17,-1, 5, 1, 4, 3, 6, 2,-2,18, 3, 2, 4, 5, 8,-1 }, // 39 + { 0, 2,18,18,17, 2, 3,-2, 5,18, 2, 4, 7, 8, 6,17, 3, 5 }, // 40 + { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 41 + { 1, 2, 1,-1, 3, 2,18, 7,-2, 5, 2, 6, 4, 3,-1,18, 8, 7 }, // 42 + { 0, 2,18,17, 3,18, 2, 5, 4, 3, 6, 2, 7, 8,18, 3, 4, 5 }, // 43 + { 1, 1, 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 }, // 44 + { 0, 2,18,18, 3,-3,18, 2, 6, 5, 3, 7,18, 4,-2, 8, 2, 3 }, // 45 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 46 + { 1, 1,17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 }, // 47 + { 1, 1, 3, 6, 5, 5, 1, 3, 7, 4, 2, 6, 4,18, 3, 7, 5, 6 }, // 48 + { 0, 1,18,18,18, 2, 4,-1,18, 8,-1, 2, 3, 4, 6,-2, 1, 7 }, // 49 + { 1, 1,18,-2,17,18, 2, 6, 3,-2, 5, 4, 7, 1,-3, 8, 2, 6 }, // 50 + { 0, 1,17,18,18, 4, 2, 7, 3, 6,-2,18, 8, 4, 5, 2, 7,17 }, // 51 + { 1, 1,18,18, 5, 4, 6, 4, 1, 5, 4, 3, 2, 5, 6, 1, 4, 5 }, // 52 + { 0, 1,18,18,-2,18, 2,-3, 3, 8, 5,18, 6, 4, 3,-1, 7, 2 }, // 53 + { 1, 1,18, 2,-2,-3,18, 5, 2, 3,-2, 4, 6, 1,-3, 2, 7, 8 }, // 54 + { 0, 1,18, 3, 5, 8, 2, 6, 7, 3, 1, 5, 2,-1, 8, 6, 7, 4 }, // 55 + { 1, 1, 4, 3, 8, 1, 5, 6, 2, 5, 8,-2, 2, 7, 3,18, 5, 4 }, // 56 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 57 + { 1, 1,17, 3,18,18, 7, 2, 4,18, 6, 2, 3,-1, 8, 5,18,-3 }, // 58 + { 0, 1, 3,17,18, 2,18, 6, 7,-3,18, 2, 5, 6, 3, 8, 7,-1 }, // 59 + { 1, 1,18,18, 2,18,18, 2,-1, 7, 3,18, 5, 2, 6, 4,-1,18 }, // 60 + { 0, 3,18, 3, 4, 1, 5, 2,18, 4, 2, 3,18, 7, 6, 1, 2, 4 }, // 61 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 62 + { 1, 1,17, 1,18, 2, 3, 6, 4, 5, 7,18, 3, 8, 2, 4,-2,17 }, // 63 + { 1, 2,18,17, 2, 3, 5,18, 6,-2, 7, 3, 2, 4,18, 8,-1, 5 }, // 64 + { 0, 2, 1,18,-1,18, 3, 2, 4, 6,-3, 7,-1, 5, 1, 2, 3, 8 }, // 65 + { 1, 1, 1,18,-1, 8, 2, 6, 3,-2, 1, 2, 5, 4,-3, 8, 6, 3 }, // 66 + { 0, 1,18,18, 2,18, 2,18, 7, 6,18, 2,-2, 3, 5, 4,18, 8 }, // 67 + { 1, 2,18,17, 2, 3,18,-1, 2, 3, 6,18, 5, 4, 3, 7, 2, 8 }, // 68 + { 1, 2,18,18, 3,-2, 4,18, 5, 7, 6, 2, 4,-3, 8, 5,18, 3 }, // 69 + { 1, 1,17,-2,18,18, 2, 5, 3, 8, 2,-1, 6, 1, 3, 4, 7, 5 }, // 70 + { 1, 1, 3,17,18, 5, 7, 2, 4, 6, 1, 8,-1, 3, 7, 4, 1, 2 }, // 71 + { 0, 2, 1,-2, 2,18, 3, 5, 2, 4, 7,-1, 2, 3, 5,18,-2, 4 }, // 72 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 73 + { 1, 1, 1, 2,-2, 6,18,-3, 2, 7, 3,-2, 5, 6, 1, 8, 2, 4 }, // 74 + { 0, 1,18,18,18, 3,-2, 6,18, 2, 4, 3, 5, 8, 7, 6, 2,-2 }, // 75 + { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 76 + { 0, 1, 3,17,18, 2, 5,18, 6, 7, 5,-2, 2, 4,18, 3, 6, 8 }, // 77 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 78 + { 0, 2,17,-1,18, 2, 4,-1, 8, 3,18, 7,-3, 4, 5, 1, 2,-2 }, // 79 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 8, 6, 4, 5, 7,-1 }, // 80 + { 1, 1,18,18, 3, 6, 4, 8,-2, 2, 5, 3, 7,18, 6, 8, 4, 2 }, // 81 + { 1, 1,17,18,18,-2, 5, 2, 3, 1, 4,-1, 8, 6, 5, 3, 2,18 }, // 82 + { 1, 1,17,17, 1, 2, 4, 5, 2, 6,-1, 3, 1, 1,-2, 4, 2, 7 }, // 83 + { 1, 1,17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 }, // 84 + { 0, 1,18,17,-2,-3, 1, 2, 3, 2, 5, 4, 7,-3, 6,-2, 2, 1 }, // 85 + { 1, 1, 1, 3, 5,18, 1, 2, 7, 3, 6, 2, 5, 8,-1, 1, 4, 7 }, // 86 + { 1, 1,17, 3, 6, 8, 1, 4, 5, 3,-2, 7, 2, 8, 5, 6,18, 3 }, // 87 + { 1, 1,17,18, 2, 4, 8,-2, 3, 1, 5, 6, 7, 1, 2, 3, 4, 7 }, // 88 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 89 + { 1, 1, 3, 1, 8,18, 5, 2, 3,18, 6, 7,-2, 4, 3, 2, 8,18 }, // 90 + { 0, 1,18,17, 2,18, 3, 4,-1,18, 7, 6, 2, 8, 4,18,18, 5 }, // 91 + { 0, 1,18,18, 2,18,18, 2, 7,-2, 6, 5, 4, 3,18, 3, 2,17 }, // 92 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 93 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 94 + { 1, 1,17, 8,18, 3, 2, 1, 5, 4, 6,-1, 3,-3, 8,18, 7, 2 }, // 95 + { 1, 2,18,17,18, 2, 3, 5,-2,18, 6,-1, 2, 3, 7, 4, 8,17 }, // 96 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 8, 6, 4, 5, 7,-1 }, // 97 + { 1, 2,18,18,-2,17, 2,18, 3, 4,18, 8, 7,-1, 2, 4, 5,17 }, // 98 + { 0, 2,17,-3,17, 3, 2,-2,18, 8, 4,-3, 2,18, 5, 3,-2, 6 }, // 99 + { 0, 1,18,18, 2,18,18, 2, 7,-2, 6, 5, 4, 3,18, 3, 2,17 }, // 100 + { 0, 2, 1,18,-1, 3, 5, 2,-3,18, 7, 3,-1, 6, 4, 2,17, 5 }, // 101 + { 1, 1,17,-2,17, 2,-3, 1, 5,-1, 4, 6, 3, 2, 8, 7,-2, 5 }, // 102 + { 1, 1, 1,18, 1, 3, 5, 8, 6, 2, 3,-1, 7, 1, 4, 8, 5,-3 }, // 103 + { 0, 2, 3,18,18, 2,18,-2, 6, 5, 7, 2, 4,18, 3, 6,-3, 5 }, // 104 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 105 + { 1, 1, 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 }, // 106 + { 0, 4,18, 2,17, 3,18,-2, 2, 6,18, 2, 7, 3, 5, 4, 8,18 }, // 107 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 108 + { 0, 1,18,18, 2, 3, 6, 3, 5,-2, 2, 4,18, 3,-2,-1, 6, 7 }, // 109 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 110 + { 1, 1,17, 1, 2, 5, 3,-2, 1, 4, 3, 7, 6,-3, 2, 1, 1, 2 }, // 111 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 112 + { 1, 1,18,18,-2,18,-2, 2, 3, 6,18, 4,-1, 2, 3, 8, 1, 4 }, // 113 + { 1, 1,17,-2,17, 2,-3, 1, 5,-1, 4, 6, 3, 2, 8, 7,-2, 5 }, // 114 + { 0, 1,17,17,18, 3, 2,18,18, 6, 8, 2,-2, 3, 5, 4,17,18 }, // 115 + { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 116 + { 1, 1, 1, 3,-3,18,18, 6, 5,18, 2,-1, 3, 8, 7,-3, 4,17 }, // 117 + { 1, 1,18, 1, 2, 1, 3, 8, 7, 4, 1, 5, 2,-1,-3,18, 6, 2 }, // 118 + { 0, 1,18, 3, 5, 2, 6, 8,18, 5, 7, 2, 3,-1, 6, 7, 8, 5 }, // 119 + { 0, 2,18, 3,-2, 7, 8, 2, 5, 4,-3, 8, 3, 2,18, 5, 4, 6 }, // 120 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 121 + { 1, 3, 1, 1, 2, 5, 2, 7, 4, 3,-1,18,-2, 8, 2, 1, 6, 7 }, // 122 + { 0, 1, 3,17,18, 5, 2, 6, 7,18, 4, 5, 3, 6,18, 2, 7, 8 }, // 123 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 124 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 125 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 126 + { 0, 1, 1,18, 1, 2, 3, 5, 1, 2, 6, 7, 4, 3, 8, 1,17, 5 }, // 127 + { 1, 2,17,-1,18,-2, 2, 3, 5,18, 2, 4, 6, 7, 3,-1, 5, 8 }, // 128 + { 1, 1,18,18,-3,18,-2, 2, 3,-2,18, 6, 4, 5, 8, 3,17,-3 }, // 129 + { 1, 1,18, 7, 6, 5, 5, 3, 1, 4, 2, 7, 3, 4,-3, 6,18, 8 }, // 130 + { 0, 2,18,18, 2, 3, 5,18, 2, 4, 3, 6,18, 7, 8,-1, 5, 2 }, // 131 + { 0, 1,18,17,-1, 2,18, 3, 2,18, 4, 3,18, 2, 6, 5, 8,17 }, // 132 + { 0, 2,18,17, 2, 3,18, 5,-1, 6, 7, 8, 2, 3, 4, 5,18, 6 }, // 133 + { 1, 2,18,-3,18, 2, 3,-2,-3, 5,18, 7, 6, 2, 4, 3, 8,-2 }, // 134 + { 1, 1,17,18,18,-2, 2, 3, 5, 4, 8,18,-1, 5, 3, 6,-2, 7 }, // 135 + { 1, 2,18,17, 2,-2,18, 3,-1, 4,18, 2, 7, 5, 3, 8, 6, 4 }, // 136 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 137 + { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 138 + { 0, 2,18,18, 3, 3,-2, 2, 5,18, 6, 3,-1, 4, 7,-1, 1, 2 }, // 139 + { 0, 1,-2, 1,18, 2,-2, 5, 7,18, 3, 2, 6, 2,-1, 4,-2,17 }, // 140 + { 0, 2,18,18,18, 2, 3,-2,18, 5, 4, 2, 6, 8, 3,-2, 4,18 }, // 141 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 142 + { 1, 1,17,18,-1, 3, 2, 5, 1, 3, 2, 8, 4, 7, 6, 2,-1, 5 }, // 143 + { 1, 1,17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 }, // 144 + { 0, 1,18,18,-2,18, 2, 3, 4, 5, 6,18, 8, 2, 3, 7,-2, 4 }, // 145 + { 0, 1,18,-2,18,18,-3,-2, 2, 3, 5, 8, 1, 2, 6, 4, 7,-1 }, // 146 + { 0, 1,18,17, 2,18, 3,-2, 2, 7, 6, 4,18, 3, 8, 7, 4, 2 }, // 147 + { 1, 1,17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 }, // 148 + { 1, 1,18,17,18, 2, 5, 3,-2,18, 6, 2, 3, 4, 8, 7, 5,-1 }, // 149 + { 0, 1, 2,-1,18,-1, 2, 4,-3,18, 5, 3, 6,18, 2, 4, 7, 8 }, // 150 + { 1, 1,17,18, 8, 3, 6, 4,-1, 5, 2, 7, 3, 8, 6, 5,18, 4 }, // 151 + { 0, 2,18, 3,-2, 7, 8, 2, 5, 4,-3, 8, 3, 2,18, 5, 4, 6 }, // 152 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 153 + { 1, 1, 1,18,-1, 8, 2, 6, 3,-2, 1, 2, 5, 4,-3, 8, 6, 3 }, // 154 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 155 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 156 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 157 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 158 + { 0, 1,17,18,18, 4, 2, 7, 3, 6,-2,18, 8, 4, 5, 2, 7,17 }, // 159 + { 1, 2,18,-1,18, 3,-2,18, 2, 5, 3, 6, 7, 2,-1,18, 8, 4 }, // 160 + { 1, 2, 1,18,-2, 4,18, 2, 3, 6,-1, 7, 5,-2,18, 8, 2, 4 }, // 161 + { 1, 2, 1,18,-3, 2, 3,18,-1, 5, 6, 2, 8, 3, 4, 1,-2, 7 }, // 162 + { 0, 1, 1,17,-1,18, 3, 2, 5, 4, 6, 7, 8, 3, 4, 2, 1,-2 }, // 163 + { 1, 1,18,17,18, 4, 3, 5, 1, 2, 6, 3, 4, 7, 1, 8, 5, 2 }, // 164 + { 0, 1,18,-2, 7, 1, 3, 2,-3, 4, 6,-2, 7, 8, 1, 5, 4, 3 }, // 165 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 166 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 167 + { 0, 2,18,18,18,-2, 2, 5, 3, 7,18, 2, 4,-3, 5, 6, 3, 8 }, // 168 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 169 + { 0, 3, 3,18,-1, 5, 2, 7,18, 6, 5, 2, 4, 3,-1, 7,18, 6 }, // 170 + { 0, 2,18,18,18, 4, 3, 2, 6, 4, 8,18, 5, 3, 2, 7,-2, 6 }, // 171 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 172 + { 0, 2,18,18,18, 2, 3,-2,18, 5, 4, 2, 6, 8, 3,-2, 4,18 }, // 173 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 174 + { 1, 1,17, 8,18, 3, 2, 1, 5, 4, 6,-1, 3,-3, 8,18, 7, 2 }, // 175 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 176 + { 0, 1,-1,18,18,18, 2, 4, 6,-2, 2, 8, 3, 4,18, 7,-1, 6 }, // 177 + { 0, 1,18, 1,-2, 2, 4, 1, 3,-1, 2, 5, 7, 1, 6, 8,-2,17 }, // 178 + { 0, 1,17,17,18, 2, 5, 4,18, 3, 8, 7, 4, 6, 8, 1, 5, 2 }, // 179 + { 1, 2,18,18, 5, 4, 6, 3, 4,18, 8, 4,-1, 7, 5, 3, 6, 2 }, // 180 + { 0, 1,18,18,-3,18, 3, 6, 2, 5, 7,18, 3, 8,-1, 4, 5, 2 }, // 181 + { 1, 1,18, 2,-2,-3,18, 5, 2,-2, 4, 3, 6,18, 8,-1, 2, 7 }, // 182 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 183 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 184 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 185 + { 1, 1,17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 }, // 186 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 187 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 188 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 189 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 190 + { 0, 1,17,18, 3,18, 2, 5, 4, 7,-3, 6, 3, 2,18, 4, 7, 3 }, // 191 + { 1, 1, 1, 7, 4, 5, 3, 4, 5, 1, 3, 6, 3, 2, 4, 8,-2, 7 }, // 192 + { 0, 1, 1,18,-1,-2,18, 3, 2,-1, 6, 7, 4, 5, 3,18, 2,-3 }, // 193 + { 1, 1,18,18,-1, 3, 6,18, 5, 4, 8, 2, 3, 6,18, 7, 4,-2 }, // 194 + { 0, 2,18,18, 2, 6,18, 2,18, 5, 3,18, 2, 4, 7, 8, 3,18 }, // 195 + { 1, 1, 3,18,18, 5,18, 6, 2, 4, 7,-2,18, 5, 8, 6, 3, 2 }, // 196 + { 0, 1,18,-2, 7, 1, 3, 2,-3, 4, 6,-2, 7, 8, 1, 5, 4, 3 }, // 197 + { 1, 1,18,-2,18, 2, 5,18, 3,-2, 4, 7, 2,-1, 8, 6, 5, 1 }, // 198 + { 1, 1,17,17, 5,18, 4, 1, 2, 8, 6, 4,-2, 3, 5,-1, 1, 8 }, // 199 + { 0, 2, 1, 2,17, 3, 7,18, 2,-1, 4, 5,18, 2, 7, 3, 6, 8 }, // 200 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 201 + { 1, 1, 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 }, // 202 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 203 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 204 + { 0, 2,18,18,18, 2,-2, 3, 6, 4, 8,18, 2, 5, 7, 4, 3, 6 }, // 205 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 206 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 207 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 208 + { 1, 1,18, 1, 8, 3, 5, 6, 4,-1, 8, 3, 7,18, 2, 5, 8, 4 }, // 209 + { 1, 1,17,18, 5, 2, 4, 3, 1, 6,-2, 1, 3, 2, 4, 5,-1,17 }, // 210 + { 1, 1,18,17, 2,18, 3,-3, 7, 2, 6, 4, 3, 5,18, 8, 2,-2 }, // 211 + { 1, 1,18,17,18, 4, 3, 5,-1,18, 2, 7, 8, 4, 6, 3,18, 5 }, // 212 + { 0, 1,18,17,18,-2, 2,-3, 3, 4, 8, 5, 2,18, 6, 3, 7,-2 }, // 213 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 214 + { 1, 1,17,18, 8, 3, 4, 6,18, 5,-2, 3, 8, 5, 2, 4, 7, 6 }, // 215 + { 0, 1,18,-2, 3, 5, 1, 7, 3, 2, 6,-3, 4, 1, 5, 8, 3,-2 }, // 216 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 217 + { 1, 1, 3,17,18, 5,-1,18, 2, 6, 7,18, 5, 3,-3,-1, 6, 2 }, // 218 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 219 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 220 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 221 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 222 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 223 + { 1, 3,18,17,-2, 3,-1,18, 2, 5, 3, 7, 6, 2, 4, 8,18, 5 }, // 224 + { 0, 1,18,-1,18, 2,18, 3, 5,18, 2, 8,18, 5, 4,-1, 6, 2 }, // 225 + { 1, 2,18,-2,18,18, 2, 3, 4,-3, 2, 5,18, 7, 4, 3, 8, 6 }, // 226 + { 0, 2,17,-1,18, 2,-1, 1, 7, 3, 8, 5,-2, 4, 1, 2,-3, 6 }, // 227 + { 0, 1,18,17, 2,18, 2,18, 6, 7, 4, 3,18, 5, 2,-2,17, 8 }, // 228 + { 0, 3,18,17, 2, 3,-3,-1,18, 2, 4, 5,18, 7, 3, 2,-3, 6 }, // 229 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 230 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 231 + { 0, 2, 3,18,18,18, 2, 6, 5,18, 7, 2, 4, 6,18, 5, 3, 8 }, // 232 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 233 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 234 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 235 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 236 + { 0, 1,18,18, 3, 6, 3,-2, 2,18, 5,-1, 7, 3, 4,-2, 2, 6 }, // 237 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 238 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 239 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 240 + { 1, 1,18,17,18,18,-2, 2, 3,-3,18, 6, 4, 2,-2, 8, 3, 7 }, // 241 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 242 + { 0, 1,18,18,18, 4, 2, 7, 8,18, 3, 2,-2, 4, 7, 6,17, 5 }, // 243 + { 1, 1,18,18,-1,-2, 8, 3,18, 6, 3, 5, 8, 2, 4, 7, 1, 6 }, // 244 + { 1, 1, 1,-3, 3,18,18, 2,-1, 3, 6, 5,18, 4, 7,-2, 8, 3 }, // 245 + { 1, 1, 1,18, 4, 2, 5,18, 1, 3,-1, 6, 1, 4, 8, 2, 5, 1 }, // 246 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 247 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 248 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 249 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 250 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 251 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 252 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 253 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 254 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 255 +}; + +#define NUM_FAST_SPECS (sizeof (fast_specs) / sizeof (fast_specs [0])) +#define NUM_DEFAULT_SPECS (sizeof (default_specs) / sizeof (default_specs [0])) +#define NUM_HIGH_SPECS (sizeof (high_specs) / sizeof (high_specs [0])) +#define NUM_VERY_HIGH_SPECS (sizeof (very_high_specs) / sizeof (very_high_specs [0])) diff --git a/Frameworks/WavPack/Files/decorr_utils.c b/Frameworks/WavPack/Files/decorr_utils.c new file mode 100644 index 000000000..12aef1cd8 --- /dev/null +++ b/Frameworks/WavPack/Files/decorr_utils.c @@ -0,0 +1,204 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// decorr_utils.c + +// This module contains the functions that process metadata blocks that are +// specific to the decorrelator. These would be called any time a WavPack +// block was parsed. These are in a module separate from the actual unpack +// decorrelation code (unpack.c) so that if an application just wants to get +// information from WavPack files (rather than actually decoding audio) then +// less code needs to be linked. + +#include +#include + +#include "wavpack_local.h" + +///////////////////////////// executable code //////////////////////////////// + +// Read decorrelation terms from specified metadata block into the +// decorr_passes array. The terms range from -3 to 8, plus 17 & 18; +// other values are reserved and generate errors for now. The delta +// ranges from 0 to 7 with all values valid. Note that the terms are +// stored in the opposite order in the decorr_passes array compared +// to packing. + +int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int termcnt = wpmd->byte_length; + unsigned char *byteptr = wpmd->data; + struct decorr_pass *dpp; + + if (termcnt > MAX_NTERMS) + return FALSE; + + wps->num_terms = termcnt; + + for (dpp = wps->decorr_passes + termcnt - 1; termcnt--; dpp--) { + dpp->term = (int)(*byteptr & 0x1f) - 5; + dpp->delta = (*byteptr++ >> 5) & 0x7; + + if (!dpp->term || dpp->term < -3 || (dpp->term > MAX_TERM && dpp->term < 17) || dpp->term > 18 || + ((wps->wphdr.flags & MONO_DATA) && dpp->term < 0)) + return FALSE; + } + + return TRUE; +} + +// Read decorrelation weights from specified metadata block into the +// decorr_passes array. The weights range +/-1024, but are rounded and +// truncated to fit in signed chars for metadata storage. Weights are +// separate for the two channels and are specified from the "last" term +// (first during encode). Unspecified weights are set to zero. + +int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int termcnt = wpmd->byte_length, tcount; + char *byteptr = wpmd->data; + struct decorr_pass *dpp; + + if (!(wps->wphdr.flags & MONO_DATA)) + termcnt /= 2; + + if (termcnt > wps->num_terms) + return FALSE; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + dpp->weight_A = dpp->weight_B = 0; + + while (--dpp >= wps->decorr_passes && termcnt--) { + dpp->weight_A = restore_weight (*byteptr++); + + if (!(wps->wphdr.flags & MONO_DATA)) + dpp->weight_B = restore_weight (*byteptr++); + } + + return TRUE; +} + +// Read decorrelation samples from specified metadata block into the +// decorr_passes array. The samples are signed 32-bit values, but are +// converted to signed log2 values for storage in metadata. Values are +// stored for both channels and are specified from the "last" term +// (first during encode) with unspecified samples set to zero. The +// number of samples stored varies with the actual term value, so +// those must obviously come first in the metadata. + +int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) +{ + unsigned char *byteptr = wpmd->data; + unsigned char *endptr = byteptr + wpmd->byte_length; + struct decorr_pass *dpp; + int tcount; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + CLEAR (dpp->samples_A); + CLEAR (dpp->samples_B); + } + + if (wps->wphdr.version == 0x402 && (wps->wphdr.flags & HYBRID_FLAG)) { + if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) + return FALSE; + + wps->dc.error [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->dc.error [1] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + } + } + + while (dpp-- > wps->decorr_passes && byteptr < endptr) + if (dpp->term > MAX_TERM) { + if (byteptr + (wps->wphdr.flags & MONO_DATA ? 4 : 8) > endptr) + return FALSE; + + dpp->samples_A [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_A [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + + if (!(wps->wphdr.flags & MONO_DATA)) { + dpp->samples_B [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_B [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + } + else if (dpp->term < 0) { + if (byteptr + 4 > endptr) + return FALSE; + + dpp->samples_A [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_B [0] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + else { + int m = 0, cnt = dpp->term; + + while (cnt--) { + if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) + return FALSE; + + dpp->samples_A [m] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + dpp->samples_B [m] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + } + + m++; + } + } + + return byteptr == endptr; +} + +// Read the shaping weights from specified metadata block into the +// WavpackStream structure. Note that there must be two values (even +// for mono streams) and that the values are stored in the same +// manner as decorrelation weights. These would normally be read from +// the "correction" file and are used for lossless reconstruction of +// hybrid data. + +int read_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + if (wpmd->byte_length == 2) { + char *byteptr = wpmd->data; + + wps->dc.shaping_acc [0] = (int32_t) restore_weight (*byteptr++) << 16; + wps->dc.shaping_acc [1] = (int32_t) restore_weight (*byteptr++) << 16; + return TRUE; + } + else if (wpmd->byte_length >= (wps->wphdr.flags & MONO_DATA ? 4 : 8)) { + unsigned char *byteptr = wpmd->data; + + wps->dc.error [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + wps->dc.shaping_acc [0] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->dc.error [1] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + wps->dc.shaping_acc [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + + if (wpmd->byte_length == (wps->wphdr.flags & MONO_DATA ? 6 : 12)) { + wps->dc.shaping_delta [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + + if (!(wps->wphdr.flags & MONO_DATA)) + wps->dc.shaping_delta [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8))); + } + + return TRUE; + } + + return FALSE; +} diff --git a/Frameworks/WavPack/Files/entropy_utils.c b/Frameworks/WavPack/Files/entropy_utils.c new file mode 100644 index 000000000..2a21cc69d --- /dev/null +++ b/Frameworks/WavPack/Files/entropy_utils.c @@ -0,0 +1,378 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// entropy_utils.c + +// This module contains the functions that process metadata blocks that are +// specific to the entropy decoder; these would be called any time a WavPack +// block was parsed. Additionally, it contains tables and functions that are +// common to both entropy coding and decoding. These are in a module separate +// from the actual entropy encoder (write_words.c) and decoder (read_words.c) +// so that if applications that just do a subset of the full WavPack reading +// and writing can link with a subset of the library. + +#include +#include + +#include "wavpack_local.h" + +///////////////////////////// local table storage //////////////////////////// + +const uint32_t bitset [] = { + 1L << 0, 1L << 1, 1L << 2, 1L << 3, + 1L << 4, 1L << 5, 1L << 6, 1L << 7, + 1L << 8, 1L << 9, 1L << 10, 1L << 11, + 1L << 12, 1L << 13, 1L << 14, 1L << 15, + 1L << 16, 1L << 17, 1L << 18, 1L << 19, + 1L << 20, 1L << 21, 1L << 22, 1L << 23, + 1L << 24, 1L << 25, 1L << 26, 1L << 27, + 1L << 28, 1L << 29, 1L << 30, 1L << 31 +}; + +const uint32_t bitmask [] = { + (1L << 0) - 1, (1L << 1) - 1, (1L << 2) - 1, (1L << 3) - 1, + (1L << 4) - 1, (1L << 5) - 1, (1L << 6) - 1, (1L << 7) - 1, + (1L << 8) - 1, (1L << 9) - 1, (1L << 10) - 1, (1L << 11) - 1, + (1L << 12) - 1, (1L << 13) - 1, (1L << 14) - 1, (1L << 15) - 1, + (1L << 16) - 1, (1L << 17) - 1, (1L << 18) - 1, (1L << 19) - 1, + (1L << 20) - 1, (1L << 21) - 1, (1L << 22) - 1, (1L << 23) - 1, + (1L << 24) - 1, (1L << 25) - 1, (1L << 26) - 1, (1L << 27) - 1, + (1L << 28) - 1, (1L << 29) - 1, (1L << 30) - 1, 0x7fffffff +}; + +const char nbits_table [] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 15 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 16 - 31 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 32 - 47 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 48 - 63 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 64 - 79 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 80 - 95 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 96 - 111 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 112 - 127 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 128 - 143 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 144 - 159 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 160 - 175 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 176 - 191 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 192 - 207 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 208 - 223 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 224 - 239 + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 // 240 - 255 +}; + +static const unsigned char log2_table [] = { + 0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15, + 0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, + 0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51, + 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, + 0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75, + 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, + 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2, + 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0, + 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce, + 0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb, + 0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7, + 0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4, + 0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff +}; + +static const unsigned char exp2_table [] = { + 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16, + 0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d, + 0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, + 0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, + 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, + 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, + 0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, + 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, + 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4, + 0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9, + 0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff +}; + +///////////////////////////// executable code //////////////////////////////// + +// Read the median log2 values from the 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) +{ + unsigned char *byteptr = wpmd->data; + + if (wpmd->byte_length != ((wps->wphdr.flags & MONO_DATA) ? 6 : 12)) + return FALSE; + + wps->w.c [0].median [0] = wp_exp2s (byteptr [0] + (byteptr [1] << 8)); + wps->w.c [0].median [1] = wp_exp2s (byteptr [2] + (byteptr [3] << 8)); + wps->w.c [0].median [2] = wp_exp2s (byteptr [4] + (byteptr [5] << 8)); + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->w.c [1].median [0] = wp_exp2s (byteptr [6] + (byteptr [7] << 8)); + wps->w.c [1].median [1] = wp_exp2s (byteptr [8] + (byteptr [9] << 8)); + wps->w.c [1].median [2] = wp_exp2s (byteptr [10] + (byteptr [11] << 8)); + } + + return TRUE; +} + +// Read the hybrid related values from the 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) +{ + unsigned char *byteptr = wpmd->data; + unsigned char *endptr = byteptr + wpmd->byte_length; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) + return FALSE; + + wps->w.c [0].slow_level = wp_exp2s (byteptr [0] + (byteptr [1] << 8)); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->w.c [1].slow_level = wp_exp2s (byteptr [0] + (byteptr [1] << 8)); + byteptr += 2; + } + } + + if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) + return FALSE; + + wps->w.bitrate_acc [0] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16; + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->w.bitrate_acc [1] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16; + byteptr += 2; + } + + if (byteptr < endptr) { + if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) + return FALSE; + + wps->w.bitrate_delta [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->w.bitrate_delta [1] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + } + + if (byteptr < endptr) + return FALSE; + } + else + wps->w.bitrate_delta [0] = wps->w.bitrate_delta [1] = 0; + + return TRUE; +} + +// This function is called during both encoding and decoding of hybrid data to +// update the "error_limit" variable which determines the maximum sample error +// allowed in the main bitstream. In the HYBRID_BITRATE mode (which is the only +// currently implemented) this is calculated from the slow_level values and the +// bitrate accumulators. Note that the bitrate accumulators can be changing. + +void update_error_limit (WavpackStream *wps) +{ + int bitrate_0 = (wps->w.bitrate_acc [0] += wps->w.bitrate_delta [0]) >> 16; + + if (wps->wphdr.flags & MONO_DATA) { + if (wps->wphdr.flags & HYBRID_BITRATE) { + int slow_log_0 = (wps->w.c [0].slow_level + SLO) >> SLS; + + if (slow_log_0 - bitrate_0 > -0x100) + wps->w.c [0].error_limit = wp_exp2s (slow_log_0 - bitrate_0 + 0x100); + else + wps->w.c [0].error_limit = 0; + } + else + wps->w.c [0].error_limit = wp_exp2s (bitrate_0); + } + else { + int bitrate_1 = (wps->w.bitrate_acc [1] += wps->w.bitrate_delta [1]) >> 16; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + int slow_log_0 = (wps->w.c [0].slow_level + SLO) >> SLS; + int slow_log_1 = (wps->w.c [1].slow_level + SLO) >> SLS; + + if (wps->wphdr.flags & HYBRID_BALANCE) { + int balance = (slow_log_1 - slow_log_0 + bitrate_1 + 1) >> 1; + + if (balance > bitrate_0) { + bitrate_1 = bitrate_0 * 2; + bitrate_0 = 0; + } + else if (-balance > bitrate_0) { + bitrate_0 = bitrate_0 * 2; + bitrate_1 = 0; + } + else { + bitrate_1 = bitrate_0 + balance; + bitrate_0 = bitrate_0 - balance; + } + } + + if (slow_log_0 - bitrate_0 > -0x100) + wps->w.c [0].error_limit = wp_exp2s (slow_log_0 - bitrate_0 + 0x100); + else + wps->w.c [0].error_limit = 0; + + if (slow_log_1 - bitrate_1 > -0x100) + wps->w.c [1].error_limit = wp_exp2s (slow_log_1 - bitrate_1 + 0x100); + else + wps->w.c [1].error_limit = 0; + } + else { + wps->w.c [0].error_limit = wp_exp2s (bitrate_0); + wps->w.c [1].error_limit = wp_exp2s (bitrate_1); + } + } +} + +// The concept of a base 2 logarithm is used in many parts of WavPack. It is +// a way of sufficiently accurately representing 32-bit signed and unsigned +// values storing only 16 bits (actually fewer). It is also used in the hybrid +// mode for quickly comparing the relative magnitude of large values (i.e. +// division) and providing smooth exponentials using only addition. + +// These are not strict logarithms in that they become linear around zero and +// can therefore represent both zero and negative values. They have 8 bits +// of precision and in "roundtrip" conversions the total error never exceeds 1 +// part in 225 except for the cases of +/-115 and +/-195 (which error by 1). + + +// This function returns the log2 for the specified 32-bit unsigned value. +// The maximum value allowed is about 0xff800000 and returns 8447. + +int FASTCALL wp_log2 (uint32_t avalue) +{ + int dbits; + + if ((avalue += avalue >> 9) < (1 << 8)) { + dbits = nbits_table [avalue]; + return (dbits << 8) + log2_table [(avalue << (9 - dbits)) & 0xff]; + } + else { + if (avalue < (1L << 16)) + dbits = nbits_table [avalue >> 8] + 8; + else if (avalue < (1L << 24)) + dbits = nbits_table [avalue >> 16] + 16; + else + dbits = nbits_table [avalue >> 24] + 24; + + return (dbits << 8) + log2_table [(avalue >> (dbits - 9)) & 0xff]; + } +} + +// This function scans a buffer of longs and accumulates the total log2 value +// of all the samples. This is useful for determining maximum compression +// because the bitstream storage required for entropy coding is proportional +// to the base 2 log of the samples. On some platforms there is an assembly +// version of this. + +#if !defined(OPT_ASM_X86) && !defined(OPT_ASM_X64) + +uint32_t log2buffer (int32_t *samples, uint32_t num_samples, int limit) +{ + uint32_t result = 0, avalue; + int dbits; + + while (num_samples--) { + avalue = abs (*samples++); + + if ((avalue += avalue >> 9) < (1 << 8)) { + dbits = nbits_table [avalue]; + result += (dbits << 8) + log2_table [(avalue << (9 - dbits)) & 0xff]; + } + else { + if (avalue < (1L << 16)) + dbits = nbits_table [avalue >> 8] + 8; + else if (avalue < (1L << 24)) + dbits = nbits_table [avalue >> 16] + 16; + else + dbits = nbits_table [avalue >> 24] + 24; + + result += dbits = (dbits << 8) + log2_table [(avalue >> (dbits - 9)) & 0xff]; + + if (limit && dbits >= limit) + return (uint32_t) -1; + } + } + + return result; +} + +#endif + +// This function returns the log2 for the specified 32-bit signed value. +// All input values are valid and the return values are in the range of +// +/- 8192. + +int wp_log2s (int32_t value) +{ + return (value < 0) ? -wp_log2 (-value) : wp_log2 (value); +} + +// This function returns the original integer represented by the supplied +// logarithm (at least within the provided accuracy). The log is signed, +// but since a full 32-bit value is returned this can be used for unsigned +// conversions as well (i.e. the input range is -8192 to +8447). + +int32_t wp_exp2s (int log) +{ + uint32_t value; + + if (log < 0) + return -wp_exp2s (-log); + + value = exp2_table [log & 0xff] | 0x100; + + if ((log >>= 8) <= 9) + return value >> (9 - log); + else + return value << (log - 9); +} + +// These two functions convert internal weights (which are normally +/-1024) +// to and from an 8-bit signed character version for storage in metadata. The +// weights are clipped here in the case that they are outside that range. + +signed char store_weight (int weight) +{ + if (weight > 1024) + weight = 1024; + else if (weight < -1024) + weight = -1024; + + if (weight > 0) + weight -= (weight + 64) >> 7; + + return (weight + 4) >> 3; +} + +int restore_weight (signed char weight) +{ + int result; + + if ((result = (int) weight << 3) > 0) + result += (result + 64) >> 7; + + return result; +} diff --git a/Frameworks/WavPack/Files/extra1.c b/Frameworks/WavPack/Files/extra1.c index 23d89711e..b8d1dc966 100644 --- a/Frameworks/WavPack/Files/extra1.c +++ b/Frameworks/WavPack/Files/extra1.c @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // +// Copyright (c) 1998 - 2013 Conifer Software. // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// @@ -10,28 +10,41 @@ // This module handles the "extra" mode for mono files. -#include "wavpack_local.h" - #include #include #include #include -//#define USE_OVERHEAD -#define LOG_LIMIT 6912 -//#define EXTRA_DUMP +#include "wavpack_local.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); +// This flag causes this module to take into account the size of the header +// (which grows with more decorrelation passes) when making decisions about +// adding additional passes (as opposed to just considering the resulting +// magnitude of the residuals). With small blocks this seems to work correctly, +// but with longer blocks it seems to actually hurt compression (for reasons I +// cannot explain), so it's disabled by default + +//#define USE_OVERHEAD + +// If the log2 value of any sample in a buffer being scanned exceeds this value, +// we abandon that configuration. This prevents us from going down paths that +// are wildly unstable. + +#define LOG_LIMIT 6912 + +//#define EXTRA_DUMP // dump generated filter data error_line() + +#ifdef OPT_ASM_X86 + #define PACK_DECORR_MONO_PASS_CONT pack_decorr_mono_pass_cont_x86 +#elif defined(OPT_ASM_X64) && (defined (_WIN64) || defined(__CYGWIN__) || defined(__MINGW64__)) + #define PACK_DECORR_MONO_PASS_CONT pack_decorr_mono_pass_cont_x64win +#elif defined(OPT_ASM_X64) + #define PACK_DECORR_MONO_PASS_CONT pack_decorr_mono_pass_cont_x64 #endif -//////////////////////////////// local tables /////////////////////////////// +#ifdef PACK_DECORR_MONO_PASS_CONT + void PACK_DECORR_MONO_PASS_CONT (int32_t *out_buffer, int32_t *in_buffer, struct decorr_pass *dpp, int32_t sample_count); +#endif typedef struct { int32_t *sampleptrs [MAX_NTERMS+2]; @@ -42,13 +55,22 @@ typedef struct { static void decorr_mono_pass (int32_t *in_samples, int32_t *out_samples, uint32_t num_samples, struct decorr_pass *dpp, int dir) { + int32_t cont_samples = 0; int m = 0, i; +#ifdef PACK_DECORR_MONO_PASS_CONT + if (num_samples > 16 && dir > 0) { + int32_t pre_samples = (dpp->term > MAX_TERM) ? 2 : dpp->term; + cont_samples = num_samples - pre_samples; + num_samples = pre_samples; + } +#endif + dpp->sum_A = 0; if (dir < 0) { - out_samples += (num_samples - 1); - in_samples += (num_samples - 1); + out_samples += (num_samples + cont_samples - 1); + in_samples += (num_samples + cont_samples - 1); dir = -1; } else @@ -57,7 +79,7 @@ static void decorr_mono_pass (int32_t *in_samples, int32_t *out_samples, uint32_ 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])); + dpp->samples_A [i] = wp_exp2s (wp_log2s (dpp->samples_A [i])); if (dpp->term > MAX_TERM) { while (num_samples--) { @@ -108,6 +130,11 @@ static void decorr_mono_pass (int32_t *in_samples, int32_t *out_samples, uint32_ m = (m + 1) & (MAX_TERM - 1); } } + +#ifdef PACK_DECORR_MONO_PASS_CONT + if (cont_samples) + PACK_DECORR_MONO_PASS_CONT (out_samples, in_samples, dpp, cont_samples); +#endif } static void reverse_mono_decorr (struct decorr_pass *dpp) @@ -224,7 +251,7 @@ static void recurse_mono (WavpackContext *wpc, WavpackExtraInfo *info, int depth 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); + bits = LOG2BUFFER (outsamples, wps->wphdr.block_samples, info->log_limit); if (bits != (uint32_t) -1) bits += log2overhead (info->dps [0].term, depth + 1); @@ -289,7 +316,7 @@ static void delta_mono (WavpackContext *wpc, WavpackExtraInfo *info) 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); + bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples, info->log_limit); if (bits != (uint32_t) -1) bits += log2overhead (wps->decorr_passes [0].term, i); @@ -314,7 +341,7 @@ static void delta_mono (WavpackContext *wpc, WavpackExtraInfo *info) 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); + bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples, info->log_limit); if (bits != (uint32_t) -1) bits += log2overhead (wps->decorr_passes [0].term, i); @@ -358,7 +385,7 @@ static void sort_mono (WavpackContext *wpc, WavpackExtraInfo *info) 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); + bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples, info->log_limit); if (bits != (uint32_t) -1) bits += log2overhead (wps->decorr_passes [0].term, i); @@ -412,13 +439,13 @@ static void analyze_mono (WavpackContext *wpc, int32_t *samples, int do_samples) for (i = 0; i < info.nterms && info.dps [i].term; ++i) decorr_mono_pass (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps + i, 1); - info.best_bits = log2buffer (info.sampleptrs [info.nterms], wps->wphdr.block_samples, 0) * 1; + info.best_bits = LOG2BUFFER (info.sampleptrs [info.nterms], wps->wphdr.block_samples, 0) * 1; info.best_bits += log2overhead (info.dps [0].term, i); memcpy (info.sampleptrs [info.nterms + 1], info.sampleptrs [i], wps->wphdr.block_samples * 4); if (wpc->config.extra_flags & EXTRA_BRANCHES) recurse_mono (wpc, &info, 0, (int) floor (wps->delta_decay + 0.5), - log2buffer (info.sampleptrs [0], wps->wphdr.block_samples, 0)); + LOG2BUFFER (info.sampleptrs [0], wps->wphdr.block_samples, 0)); if (wpc->config.extra_flags & EXTRA_SORT_FIRST) sort_mono (wpc, &info); @@ -500,6 +527,12 @@ void execute_mono (WavpackContext *wpc, int32_t *samples, int no_history, int do uint32_t best_size = (uint32_t) -1, size; int log_limit, pi, i; +#ifdef SKIP_DECORRELATION + CLEAR (wps->decorr_passes); + wps->num_terms = 0; + return; +#endif + for (i = 0; i < num_samples; ++i) if (samples [i]) break; @@ -571,7 +604,7 @@ void execute_mono (WavpackContext *wpc, int32_t *samples, int no_history, int do } wpds = &wps->decorr_specs [c]; - nterms = (int) strlen ((const char *)wpds->terms); + nterms = (int) strlen ((char *) wpds->terms); while (1) { memcpy (temp_buffer [0], noisy_buffer ? noisy_buffer : samples, buf_size); @@ -598,7 +631,7 @@ void execute_mono (WavpackContext *wpc, int32_t *samples, int no_history, int do decorr_mono_pass (temp_buffer [j&1], temp_buffer [~j&1], num_samples, &temp_decorr_pass, 1); } - size = log2buffer (temp_buffer [j&1], num_samples, log_limit); + size = LOG2BUFFER (temp_buffer [j&1], num_samples, log_limit); if (size == (uint32_t) -1 && nterms) nterms >>= 1; diff --git a/Frameworks/WavPack/Files/extra2.c b/Frameworks/WavPack/Files/extra2.c index 56a8adf70..ba50234a3 100644 --- a/Frameworks/WavPack/Files/extra2.c +++ b/Frameworks/WavPack/Files/extra2.c @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // +// Copyright (c) 1998 - 2013 Conifer Software. // // MMX optimizations (c) 2006 Joachim Henke // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // @@ -11,325 +11,74 @@ // This module handles the "extra" mode for stereo files. -#include "wavpack_local.h" - #include #include #include #include -//#define USE_OVERHEAD -#define LOG_LIMIT 6912 -//#define EXTRA_DUMP +#include "wavpack_local.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); +// This flag causes this module to take into account the size of the header +// (which grows with more decorrelation passes) when making decisions about +// adding additional passes (as opposed to just considering the resulting +// magnitude of the residuals). With small blocks this seems to work correctly, +// but with longer blocks it seems to actually hurt compression (for reasons I +// cannot explain), so it's disabled by default + +//#define USE_OVERHEAD + +// If the log2 value of any sample in a buffer being scanned exceeds this value, +// we abandon that configuration. This prevents us from going down paths that +// are wildly unstable. + +#define LOG_LIMIT 6912 + +//#define EXTRA_DUMP // dump generated filter data to error_line() + +#ifdef OPT_ASM_X86 + #define PACK_DECORR_STEREO_PASS_CONT pack_decorr_stereo_pass_cont_x86 + #define PACK_DECORR_STEREO_PASS_CONT_REV pack_decorr_stereo_pass_cont_rev_x86 + #define PACK_DECORR_STEREO_PASS_CONT_AVAILABLE pack_cpu_has_feature_x86(CPU_FEATURE_MMX) +#elif defined(OPT_ASM_X64) && (defined (_WIN64) || defined(__CYGWIN__) || defined(__MINGW64__)) + #define PACK_DECORR_STEREO_PASS_CONT pack_decorr_stereo_pass_cont_x64win + #define PACK_DECORR_STEREO_PASS_CONT_REV pack_decorr_stereo_pass_cont_rev_x64win + #define PACK_DECORR_STEREO_PASS_CONT_AVAILABLE 1 +#elif defined(OPT_ASM_X64) + #define PACK_DECORR_STEREO_PASS_CONT pack_decorr_stereo_pass_cont_x64 + #define PACK_DECORR_STEREO_PASS_CONT_REV pack_decorr_stereo_pass_cont_rev_x64 + #define PACK_DECORR_STEREO_PASS_CONT_AVAILABLE 1 #endif -//////////////////////////////// local tables /////////////////////////////// +#ifdef PACK_DECORR_STEREO_PASS_CONT + void PACK_DECORR_STEREO_PASS_CONT (struct decorr_pass *dpp, int32_t *in_buffer, int32_t *out_buffer, int32_t sample_count); + void PACK_DECORR_STEREO_PASS_CONT_REV (struct decorr_pass *dpp, int32_t *in_buffer, int32_t *out_buffer, int32_t sample_count); +#endif typedef struct { int32_t *sampleptrs [MAX_NTERMS+2]; struct decorr_pass dps [MAX_NTERMS]; - int nterms, log_limit, gt16bit; + int nterms, log_limit; uint32_t best_bits; } WavpackExtraInfo; -#ifdef OPT_MMX - -static void decorr_stereo_pass (int32_t *in_samples, int32_t *out_samples, int32_t num_samples, struct decorr_pass *dpp, int dir) -{ - const __m64 - delta = _mm_set1_pi32 (dpp->delta), - fill = _mm_set1_pi32 (0x7bff), - mask = _mm_set1_pi32 (0x7fff), - round = _mm_set1_pi32 (512), - zero = _mm_set1_pi32 (0); - __m64 - sum_AB = zero, - weight_AB = _mm_set_pi32 (restore_weight (store_weight (dpp->weight_B)), restore_weight (store_weight (dpp->weight_A))), - left_right, sam_AB, tmp0, tmp1, samples_AB [MAX_TERM]; - int k, m = 0; - - if (dir < 0) { - out_samples += (num_samples - 1) * 2; - in_samples += (num_samples - 1) * 2; - dir = -2; - } - else - dir = 2; - - for (k = 0; k < MAX_TERM; ++k) { - ((int32_t *) samples_AB) [k * 2] = exp2s (log2s (dpp->samples_A [k])); - ((int32_t *) samples_AB) [k * 2 + 1] = exp2s (log2s (dpp->samples_B [k])); - } - - if (dpp->term > 0) { - if (dpp->term == 17) { - while (num_samples--) { - left_right = *(__m64 *) in_samples; - tmp0 = samples_AB [0]; - sam_AB = _m_paddd (tmp0, tmp0); - sam_AB = _m_psubd (sam_AB, samples_AB [1]); - samples_AB [0] = left_right; - samples_AB [1] = tmp0; - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) out_samples = left_right; - - tmp0 = _m_pxor (sam_AB, left_right); - tmp0 = _m_psradi (tmp0, 31); - tmp1 = _m_pxor (delta, tmp0); - tmp1 = _m_psubd (tmp1, tmp0); - sam_AB = _m_pcmpeqd (sam_AB, zero); - tmp0 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, sam_AB); - tmp0 = _m_pandn (tmp0, tmp1); - weight_AB = _m_paddd (weight_AB, tmp0); - - sum_AB = _m_paddd (sum_AB, weight_AB); - - in_samples += dir; - out_samples += dir; - } - } - else if (dpp->term == 18) { - while (num_samples--) { - left_right = *(__m64 *) in_samples; - tmp0 = samples_AB [0]; - sam_AB = _m_psubd (tmp0, samples_AB [1]); - sam_AB = _m_psradi (sam_AB, 1); - sam_AB = _m_paddd (sam_AB, tmp0); - samples_AB [0] = left_right; - samples_AB [1] = tmp0; - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) out_samples = left_right; - - tmp0 = _m_pxor (sam_AB, left_right); - tmp0 = _m_psradi (tmp0, 31); - tmp1 = _m_pxor (delta, tmp0); - tmp1 = _m_psubd (tmp1, tmp0); - sam_AB = _m_pcmpeqd (sam_AB, zero); - tmp0 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, sam_AB); - tmp0 = _m_pandn (tmp0, tmp1); - weight_AB = _m_paddd (weight_AB, tmp0); - - sum_AB = _m_paddd (sum_AB, weight_AB); - - in_samples += dir; - out_samples += dir; - } - } - else { - k = dpp->term & (MAX_TERM - 1); - while (num_samples--) { - left_right = *(__m64 *) in_samples; - sam_AB = samples_AB [m]; - samples_AB [k] = left_right; - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) out_samples = left_right; - - tmp0 = _m_pxor (sam_AB, left_right); - tmp0 = _m_psradi (tmp0, 31); - tmp1 = _m_pxor (delta, tmp0); - tmp1 = _m_psubd (tmp1, tmp0); - sam_AB = _m_pcmpeqd (sam_AB, zero); - tmp0 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, sam_AB); - tmp0 = _m_pandn (tmp0, tmp1); - weight_AB = _m_paddd (weight_AB, tmp0); - - sum_AB = _m_paddd (sum_AB, weight_AB); - - in_samples += dir; - out_samples += dir; - k = (k + 1) & (MAX_TERM - 1); - m = (m + 1) & (MAX_TERM - 1); - } - } - } - else { - if (dpp->term == -1) { - while (num_samples--) { - left_right = *(__m64 *) in_samples; - sam_AB = samples_AB [0]; - samples_AB [0] = _m_punpckhdq (left_right, sam_AB); - sam_AB = _m_punpckldq (sam_AB, left_right); - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) out_samples = left_right; - - tmp0 = _m_pcmpeqd (sam_AB, zero); - tmp1 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, tmp1); - tmp0 = _m_pandn (tmp0, delta); - sam_AB = _m_pxor (sam_AB, left_right); - sam_AB = _m_psradi (sam_AB, 31); - tmp1 = _m_psubd (fill, sam_AB); - weight_AB = _m_pxor (weight_AB, sam_AB); - weight_AB = _m_paddd (weight_AB, tmp1); - weight_AB = _m_paddsw (weight_AB, tmp0); - weight_AB = _m_psubd (weight_AB, tmp1); - weight_AB = _m_pxor (weight_AB, sam_AB); - - sum_AB = _m_paddd (sum_AB, weight_AB); - - in_samples += dir; - out_samples += dir; - } - } - else if (dpp->term == -2) { - while (num_samples--) { - left_right = *(__m64 *) in_samples; - sam_AB = samples_AB [0]; - samples_AB [0] = _m_punpckldq (sam_AB, left_right); - sam_AB = _m_punpckhdq (left_right, sam_AB); - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) out_samples = left_right; - - tmp0 = _m_pcmpeqd (sam_AB, zero); - tmp1 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, tmp1); - tmp0 = _m_pandn (tmp0, delta); - sam_AB = _m_pxor (sam_AB, left_right); - sam_AB = _m_psradi (sam_AB, 31); - tmp1 = _m_psubd (fill, sam_AB); - weight_AB = _m_pxor (weight_AB, sam_AB); - weight_AB = _m_paddd (weight_AB, tmp1); - weight_AB = _m_paddsw (weight_AB, tmp0); - weight_AB = _m_psubd (weight_AB, tmp1); - weight_AB = _m_pxor (weight_AB, sam_AB); - - sum_AB = _m_paddd (sum_AB, weight_AB); - - in_samples += dir; - out_samples += dir; - } - } - else if (dpp->term == -3) { - while (num_samples--) { - left_right = *(__m64 *) in_samples; - sam_AB = samples_AB [0]; - tmp0 = _m_punpckhdq (left_right, left_right); - samples_AB [0] = _m_punpckldq (tmp0, left_right); - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) out_samples = left_right; - - tmp0 = _m_pcmpeqd (sam_AB, zero); - tmp1 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, tmp1); - tmp0 = _m_pandn (tmp0, delta); - sam_AB = _m_pxor (sam_AB, left_right); - sam_AB = _m_psradi (sam_AB, 31); - tmp1 = _m_psubd (fill, sam_AB); - weight_AB = _m_pxor (weight_AB, sam_AB); - weight_AB = _m_paddd (weight_AB, tmp1); - weight_AB = _m_paddsw (weight_AB, tmp0); - weight_AB = _m_psubd (weight_AB, tmp1); - weight_AB = _m_pxor (weight_AB, sam_AB); - - sum_AB = _m_paddd (sum_AB, weight_AB); - - in_samples += dir; - out_samples += dir; - } - } - } - dpp->sum_A = ((int32_t *) &sum_AB) [0]; - dpp->sum_B = ((int32_t *) &sum_AB) [1]; - dpp->weight_A = ((int32_t *) &weight_AB) [0]; - dpp->weight_B = ((int32_t *) &weight_AB) [1]; - - for (k = 0; k < MAX_TERM; ++k) { - dpp->samples_A [k] = ((int32_t *) samples_AB) [m * 2]; - dpp->samples_B [k] = ((int32_t *) samples_AB) [m * 2 + 1]; - m = (m + 1) & (MAX_TERM - 1); - } - _mm_empty (); -} - -#else - static void decorr_stereo_pass (int32_t *in_samples, int32_t *out_samples, int32_t num_samples, struct decorr_pass *dpp, int dir) { + int32_t cont_samples = 0; int m = 0, i; +#ifdef PACK_DECORR_STEREO_PASS_CONT + if (num_samples > 16 && PACK_DECORR_STEREO_PASS_CONT_AVAILABLE) { + int32_t pre_samples = (dpp->term < 0 || dpp->term > MAX_TERM) ? 2 : dpp->term; + cont_samples = num_samples - pre_samples; + num_samples = pre_samples; + } +#endif + dpp->sum_A = dpp->sum_B = 0; if (dir < 0) { - out_samples += (num_samples - 1) * 2; - in_samples += (num_samples - 1) * 2; + out_samples += (num_samples + cont_samples - 1) * 2; + in_samples += (num_samples + cont_samples - 1) * 2; dir = -2; } else @@ -339,8 +88,8 @@ static void decorr_stereo_pass (int32_t *in_samples, int32_t *out_samples, int32 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])); + dpp->samples_A [i] = wp_exp2s (wp_log2s (dpp->samples_A [i])); + dpp->samples_B [i] = wp_exp2s (wp_log2s (dpp->samples_B [i])); } switch (dpp->term) { @@ -511,184 +260,15 @@ static void decorr_stereo_pass (int32_t *in_samples, int32_t *out_samples, int32 break; } -} +#ifdef PACK_DECORR_STEREO_PASS_CONT + if (cont_samples) { + if (dir < 0) + PACK_DECORR_STEREO_PASS_CONT_REV (dpp, in_samples, out_samples, cont_samples); + else + PACK_DECORR_STEREO_PASS_CONT (dpp, in_samples, out_samples, cont_samples); + } #endif - -static void decorr_stereo_pass_quick (int32_t *in_samples, int32_t *out_samples, int32_t num_samples, struct decorr_pass *dpp, int dir) -{ - int m = 0, i; - - 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])); - } - - switch (dpp->term) { - - case 2: - while (num_samples--) { - int32_t sam, tmp; - - sam = dpp->samples_A [0]; - dpp->samples_A [0] = dpp->samples_A [1]; - out_samples [0] = tmp = (dpp->samples_A [1] = in_samples [0]) - apply_weight_i (dpp->weight_A, sam); - update_weight (dpp->weight_A, dpp->delta, sam, tmp); - - sam = dpp->samples_B [0]; - dpp->samples_B [0] = dpp->samples_B [1]; - out_samples [1] = tmp = (dpp->samples_B [1] = in_samples [1]) - apply_weight_i (dpp->weight_B, sam); - update_weight (dpp->weight_B, dpp->delta, sam, tmp); - - in_samples += dir; - out_samples += dir; - } - - break; - - case 17: - while (num_samples--) { - int32_t sam, tmp; - - sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_A [1] = dpp->samples_A [0]; - out_samples [0] = tmp = (dpp->samples_A [0] = in_samples [0]) - apply_weight_i (dpp->weight_A, sam); - update_weight (dpp->weight_A, dpp->delta, sam, tmp); - - sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - dpp->samples_B [1] = dpp->samples_B [0]; - out_samples [1] = tmp = (dpp->samples_B [0] = in_samples [1]) - apply_weight_i (dpp->weight_B, sam); - update_weight (dpp->weight_B, dpp->delta, sam, tmp); - - in_samples += dir; - out_samples += dir; - } - - break; - - case 18: - while (num_samples--) { - int32_t sam, tmp; - - sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); - dpp->samples_A [1] = dpp->samples_A [0]; - out_samples [0] = tmp = (dpp->samples_A [0] = in_samples [0]) - apply_weight_i (dpp->weight_A, sam); - update_weight (dpp->weight_A, dpp->delta, sam, tmp); - - sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); - dpp->samples_B [1] = dpp->samples_B [0]; - out_samples [1] = tmp = (dpp->samples_B [0] = in_samples [1]) - apply_weight_i (dpp->weight_B, sam); - update_weight (dpp->weight_B, dpp->delta, sam, tmp); - - in_samples += dir; - out_samples += dir; - } - - break; - - default: { - int k = dpp->term & (MAX_TERM - 1); - - while (num_samples--) { - int32_t sam, tmp; - - sam = dpp->samples_A [m]; - out_samples [0] = tmp = (dpp->samples_A [k] = in_samples [0]) - apply_weight_i (dpp->weight_A, sam); - update_weight (dpp->weight_A, dpp->delta, sam, tmp); - - sam = dpp->samples_B [m]; - out_samples [1] = tmp = (dpp->samples_B [k] = in_samples [1]) - apply_weight_i (dpp->weight_B, sam); - update_weight (dpp->weight_B, dpp->delta, sam, tmp); - - in_samples += dir; - out_samples += dir; - m = (m + 1) & (MAX_TERM - 1); - k = (k + 1) & (MAX_TERM - 1); - } - - if (m) { - int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; - int k; - - memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); - memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); - - for (k = 0; k < MAX_TERM; k++) { - dpp->samples_A [k] = temp_A [m]; - dpp->samples_B [k] = temp_B [m]; - m = (m + 1) & (MAX_TERM - 1); - } - } - - break; - } - - case -1: - while (num_samples--) { - int32_t sam_A, sam_B, tmp; - - sam_A = dpp->samples_A [0]; - out_samples [0] = tmp = (sam_B = in_samples [0]) - apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); - - out_samples [1] = tmp = (dpp->samples_A [0] = in_samples [1]) - apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); - - in_samples += dir; - out_samples += dir; - } - - break; - - case -2: - while (num_samples--) { - int32_t sam_A, sam_B, tmp; - - sam_B = dpp->samples_B [0]; - out_samples [1] = tmp = (sam_A = in_samples [1]) - apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); - - out_samples [0] = tmp = (dpp->samples_B [0] = in_samples [0]) - apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); - - in_samples += dir; - out_samples += dir; - } - - break; - - case -3: - while (num_samples--) { - int32_t sam_A, sam_B, tmp; - - sam_A = dpp->samples_A [0]; - sam_B = dpp->samples_B [0]; - - dpp->samples_A [0] = tmp = in_samples [1]; - out_samples [1] = tmp -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); - - dpp->samples_B [0] = tmp = in_samples [0]; - out_samples [0] = tmp -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); - - in_samples += dir; - out_samples += dir; - } - - break; - } } static void reverse_decorr (struct decorr_pass *dpp) @@ -788,10 +368,7 @@ static void decorr_stereo_buffer (WavpackExtraInfo *info, int32_t *samples, int3 // if (memcmp (dppi, &dp, sizeof (dp))) // error_line ("decorr_passes don't match, delta = %d", delta); - if (info->gt16bit) - decorr_stereo_pass (samples, outsamples, num_samples, &dp, 1); - else - decorr_stereo_pass_quick (samples, outsamples, num_samples, &dp, 1); + decorr_stereo_pass (samples, outsamples, num_samples, &dp, 1); } static int log2overhead (int first_term, int num_terms) @@ -837,7 +414,7 @@ static void recurse_stereo (WavpackContext *wpc, WavpackExtraInfo *info, int dep info->dps [depth].term = term; info->dps [depth].delta = delta; decorr_stereo_buffer (info, samples, outsamples, wps->wphdr.block_samples, depth); - bits = log2buffer (outsamples, wps->wphdr.block_samples * 2, info->log_limit); + bits = LOG2BUFFER (outsamples, wps->wphdr.block_samples * 2, info->log_limit); if (bits != (uint32_t) -1) bits += log2overhead (info->dps [0].term, depth + 1); @@ -903,7 +480,7 @@ static void delta_stereo (WavpackContext *wpc, WavpackExtraInfo *info) decorr_stereo_buffer (info, info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, i); } - bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); + bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); if (bits != (uint32_t) -1) bits += log2overhead (wps->decorr_passes [0].term, i); @@ -928,7 +505,7 @@ static void delta_stereo (WavpackContext *wpc, WavpackExtraInfo *info) decorr_stereo_buffer (info, info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, i); } - bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); + bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); if (bits != (uint32_t) -1) bits += log2overhead (wps->decorr_passes [0].term, i); @@ -972,7 +549,7 @@ static void sort_stereo (WavpackContext *wpc, WavpackExtraInfo *info) for (i = ri; i < info->nterms && wps->decorr_passes [i].term; ++i) decorr_stereo_buffer (info, info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, i); - bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); + bits = LOG2BUFFER (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); if (bits != (uint32_t) -1) bits += log2overhead (wps->decorr_passes [0].term, i); @@ -1001,8 +578,6 @@ static void analyze_stereo (WavpackContext *wpc, int32_t *samples, int do_sample WavpackExtraInfo info; int i; - info.gt16bit = ((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) >= 16; - #ifdef LOG_LIMIT info.log_limit = (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) + 4) * 256; @@ -1026,18 +601,15 @@ static void analyze_stereo (WavpackContext *wpc, int32_t *samples, int do_sample memcpy (info.sampleptrs [0], samples, wps->wphdr.block_samples * 8); for (i = 0; i < info.nterms && info.dps [i].term; ++i) - if (info.gt16bit) - decorr_stereo_pass (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps + i, 1); - else - decorr_stereo_pass_quick (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps + i, 1); + decorr_stereo_pass (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps + i, 1); - info.best_bits = log2buffer (info.sampleptrs [info.nterms], wps->wphdr.block_samples * 2, 0) * 1; + info.best_bits = LOG2BUFFER (info.sampleptrs [info.nterms], wps->wphdr.block_samples * 2, 0) * 1; info.best_bits += log2overhead (info.dps [0].term, i); memcpy (info.sampleptrs [info.nterms + 1], info.sampleptrs [i], wps->wphdr.block_samples * 8); if (wpc->config.extra_flags & EXTRA_BRANCHES) recurse_stereo (wpc, &info, 0, (int) floor (wps->delta_decay + 0.5), - log2buffer (info.sampleptrs [0], wps->wphdr.block_samples * 2, 0)); + LOG2BUFFER (info.sampleptrs [0], wps->wphdr.block_samples * 2, 0)); if (wpc->config.extra_flags & EXTRA_SORT_FIRST) sort_stereo (wpc, &info); @@ -1137,6 +709,12 @@ void execute_stereo (WavpackContext *wpc, int32_t *samples, int no_history, int uint32_t best_size = (uint32_t) -1, size; int log_limit, force_js = 0, force_ts = 0, pi, i; +#ifdef SKIP_DECORRELATION + CLEAR (wps->decorr_passes); + wps->num_terms = 0; + return; +#endif + for (i = 0; i < num_samples * 2; ++i) if (samples [i]) break; @@ -1216,7 +794,7 @@ void execute_stereo (WavpackContext *wpc, int32_t *samples, int no_history, int } wpds = &wps->decorr_specs [c]; - nterms = (int) strlen ((const char *)wpds->terms); + nterms = (int) strlen ((char *) wpds->terms); while (1) { if (force_js || (wpds->joint_stereo && !force_ts)) { @@ -1258,14 +836,10 @@ void execute_stereo (WavpackContext *wpc, int32_t *samples, int no_history, int reverse_decorr (&temp_decorr_pass); memcpy (save_decorr_passes + j, &temp_decorr_pass, sizeof (struct decorr_pass)); - - if (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) >= 16) - decorr_stereo_pass (temp_buffer [j&1], temp_buffer [~j&1], num_samples, &temp_decorr_pass, 1); - else - decorr_stereo_pass_quick (temp_buffer [j&1], temp_buffer [~j&1], num_samples, &temp_decorr_pass, 1); + decorr_stereo_pass (temp_buffer [j&1], temp_buffer [~j&1], num_samples, &temp_decorr_pass, 1); } - size = log2buffer (temp_buffer [j&1], num_samples * 2, log_limit); + size = LOG2BUFFER (temp_buffer [j&1], num_samples * 2, log_limit); if (size == (uint32_t) -1 && nterms) nterms >>= 1; diff --git a/Frameworks/WavPack/Files/float.c b/Frameworks/WavPack/Files/float.c deleted file mode 100644 index a01cfb376..000000000 --- a/Frameworks/WavPack/Files/float.c +++ /dev/null @@ -1,371 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// float.c - -#include "wavpack_local.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 - -#ifndef NO_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 = (int32_t)(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; - int32_t count, value, shift_count; - int max_exp = 0; - f32 *dp; - - wps->float_shift = wps->float_flags = 0; - - for (dp = values, count = num_values; count--; dp++) { - crc = crc * 27 + get_mantissa (*dp) * 9 + get_exponent (*dp) * 3 + get_sign (*dp); - - if (get_exponent (*dp) > max_exp && get_exponent (*dp) < 255) - max_exp = get_exponent (*dp); - } - - wps->crc_x = crc; - - for (dp = values, count = num_values; count--; dp++) { - if (get_exponent (*dp) == 255) { - wps->float_flags |= FLOAT_EXCEPTIONS; - value = 0x1000000; - shift_count = 0; - } - else if (get_exponent (*dp)) { - shift_count = max_exp - get_exponent (*dp); - value = 0x800000 + get_mantissa (*dp); - } - else { - shift_count = max_exp ? max_exp - 1 : 0; - value = get_mantissa (*dp); - -// if (get_mantissa (*dp)) -// denormals++; - } - - if (shift_count < 25) - value >>= shift_count; - else - value = 0; - - if (!value) { - if (get_exponent (*dp) || get_mantissa (*dp)) - ++false_zeros; - else if (get_sign (*dp)) - ++neg_zeros; - } - else if (shift_count) { - int32_t mask = (1 << shift_count) - 1; - - if (!(get_mantissa (*dp) & mask)) - shifted_zeros++; - else if ((get_mantissa (*dp) & mask) == mask) - shifted_ones++; - else - shifted_both++; - } - - ordata |= value; - * (int32_t *) dp = (get_sign (*dp)) ? -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 (get_exponent (*dp) == 255) { - if (get_mantissa (*dp)) { - putbit_1 (&wps->wvxbits); - putbits (get_mantissa (*dp), 23, &wps->wvxbits); - } - else { - putbit_0 (&wps->wvxbits); - } - - value = 0x1000000; - shift_count = 0; - } - else if (get_exponent (*dp)) { - shift_count = max_exp - get_exponent (*dp); - value = 0x800000 + get_mantissa (*dp); - } - else { - shift_count = max_exp ? max_exp - 1 : 0; - value = get_mantissa (*dp); - } - - if (shift_count < 25) - value >>= shift_count; - else - value = 0; - - if (!value) { - if (wps->float_flags & FLOAT_ZEROS_SENT) { - if (get_exponent (*dp) || get_mantissa (*dp)) { - putbit_1 (&wps->wvxbits); - putbits (get_mantissa (*dp), 23, &wps->wvxbits); - - if (max_exp >= 25) { - putbits (get_exponent (*dp), 8, &wps->wvxbits); - } - - putbit (get_sign (*dp), &wps->wvxbits); - } - else { - putbit_0 (&wps->wvxbits); - - if (wps->float_flags & FLOAT_NEG_ZEROS) - putbit (get_sign (*dp), &wps->wvxbits); - } - } - } - else if (shift_count) { - if (wps->float_flags & FLOAT_SHIFT_SENT) { - int32_t data = get_mantissa (*dp) & ((1 << shift_count) - 1); - putbits (data, shift_count, &wps->wvxbits); - } - else if (wps->float_flags & FLOAT_SHIFT_SAME) { - putbit (get_mantissa (*dp) & 1, &wps->wvxbits); - } - } - } -} - -#endif - -#if !defined(NO_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 - -#ifndef NO_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; - uint32_t temp; - - if (*values == 0) { - if (wps->float_flags & FLOAT_ZEROS_SENT) { - if (getbit (&wps->wvxbits)) { - getbits (&temp, 23, &wps->wvxbits); - set_mantissa (outval, temp); - - if (exp >= 25) { - getbits (&temp, 8, &wps->wvxbits); - set_exponent (outval, temp); - } - - set_sign (outval, getbit (&wps->wvxbits)); - } - else if (wps->float_flags & FLOAT_NEG_ZEROS) - set_sign (outval, getbit (&wps->wvxbits)); - } - } - else { - *values <<= wps->float_shift; - - if (*values < 0) { - *values = -*values; - set_sign (outval, 1); - } - - if (*values == 0x1000000) { - if (getbit (&wps->wvxbits)) { - getbits (&temp, 23, &wps->wvxbits); - set_mantissa (outval, temp); - } - - set_exponent (outval, 255); - } - else { - if (exp) - while (!(*values & 0x800000) && --exp) { - shift_count++; - *values <<= 1; - } - - if (shift_count) { - if ((wps->float_flags & FLOAT_SHIFT_ONES) || - ((wps->float_flags & FLOAT_SHIFT_SAME) && getbit (&wps->wvxbits))) - *values |= ((1 << shift_count) - 1); - else if (wps->float_flags & FLOAT_SHIFT_SENT) { - getbits (&temp, shift_count, &wps->wvxbits); - *values |= temp & ((1 << shift_count) - 1); - } - } - - set_mantissa (outval, *values); - set_exponent (outval, exp); - } - } - - crc = crc * 27 + get_mantissa (outval) * 9 + get_exponent (outval) * 3 + get_sign (outval); - * (f32 *) values++ = outval; - } - - wps->crc_x = crc; -} - -static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values) -{ - while (num_values--) { - int shift_count = 0, exp = wps->float_max_exp; - f32 outval = 0; - - if (*values) { - *values <<= wps->float_shift; - - if (*values < 0) { - *values = -*values; - set_sign (outval, 1); - } - - if (*values >= 0x1000000) { - while (*values & 0xf000000) { - *values >>= 1; - ++exp; - } - } - else if (exp) { - while (!(*values & 0x800000) && --exp) { - shift_count++; - *values <<= 1; - } - - if (shift_count && (wps->float_flags & FLOAT_SHIFT_ONES)) - *values |= ((1 << shift_count) - 1); - } - - set_mantissa (outval, *values); - set_exponent (outval, exp); - } - - * (f32 *) values++ = outval; - } -} - -#endif - -void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp) -{ - f32 *fvalues = (f32 *) values; - int exp; - - if (!delta_exp) - return; - - while (num_values--) { - if ((exp = get_exponent (*fvalues)) == 0 || exp + delta_exp <= 0) - *fvalues = 0; - else if (exp == 255 || (exp += delta_exp) >= 255) { - set_exponent (*fvalues, 255); - set_mantissa (*fvalues, 0); - } - else - set_exponent (*fvalues, exp); - - fvalues++; - } -} diff --git a/Frameworks/WavPack/Files/md5.c b/Frameworks/WavPack/Files/md5.c index 31433f216..0571ff595 100644 --- a/Frameworks/WavPack/Files/md5.c +++ b/Frameworks/WavPack/Files/md5.c @@ -121,6 +121,7 @@ void MD5Update(ctx, buf, len) void MD5Final(digest, ctx) unsigned char digest[16]; struct MD5Context *ctx; { + uint32 *ptr32 = (uint32 *) ctx->in; unsigned count; unsigned char *p; @@ -140,7 +141,7 @@ void MD5Final(digest, ctx) /* 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); + MD5Transform(ctx->buf, ptr32); /* Now fill the next block with 56 bytes */ memset(ctx->in, 0, 56); @@ -151,10 +152,10 @@ void MD5Final(digest, ctx) byteReverse(ctx->in, 14); /* Append length in bits and transform */ - ((uint32 *) ctx->in)[14] = ctx->bits[0]; - ((uint32 *) ctx->in)[15] = ctx->bits[1]; + ptr32 [14] = ctx->bits[0]; + ptr32 [15] = ctx->bits[1]; - MD5Transform(ctx->buf, (uint32 *) ctx->in); + MD5Transform(ctx->buf, ptr32); byteReverse((unsigned char *) ctx->buf, 4); memcpy(digest, ctx->buf, 16); memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ diff --git a/Frameworks/WavPack/Files/metadata.c b/Frameworks/WavPack/Files/metadata.c deleted file mode 100644 index 0fd8a49de..000000000 --- a/Frameworks/WavPack/Files/metadata.c +++ /dev/null @@ -1,313 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// metadata.c - -// This module handles the metadata structure introduced in WavPack 4.0 - -#include "wavpack_local.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(NO_UNPACK) || defined(INFO_ONLY) - -int read_metadata_buff (WavpackMetadata *wpmd, unsigned char *blockbuff, unsigned char **buffptr) -{ - WavpackHeader *wphdr = (WavpackHeader *) blockbuff; - unsigned char *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 - -#ifndef NO_PACK - -int copy_metadata (WavpackMetadata *wpmd, unsigned char *buffer_start, unsigned char *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, unsigned char id) -{ - WavpackMetadata *mdp; - unsigned char *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) -{ - unsigned char 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/Frameworks/WavPack/Files/open_filename.c b/Frameworks/WavPack/Files/open_filename.c new file mode 100644 index 000000000..4787fdca6 --- /dev/null +++ b/Frameworks/WavPack/Files/open_filename.c @@ -0,0 +1,296 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// open_filename.c + +// This module provides all the code required to open an existing WavPack +// file, by filename, for reading. It does not contain the actual code to +// unpack audio data and this was done so that programs that just want to +// query WavPack files for information (like, for example, taggers) don't +// need to link in a lot of unnecessary code. +// +// To allow opening files by filename, this code provides an interface +// between the reader callback mechanism that WavPack uses internally and +// the standard fstream C library. Note that in applications that do not +// require opening files by filename, this module can be omitted (which +// might make building easier). +// +// For Unicode support on Windows, a flag has been added (OPEN_FILE_UTF8) +// that forces the filename string to be assumed UTF-8 and converted to +// a widechar string suitable for _wfopen(). Without this flag we revert +// to the previous behavior of simply calling fopen() and hoping that the +// local character set works. This is ignored on non-Windows platforms +// (which is okay because they are probably UTF-8 anyway). + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include +#endif + +#include +#include + +#include "wavpack_local.h" + +#include +#include + +#if (defined(__GNUC__) || defined(__sun)) && !defined(_WIN32) +#include +#endif + +#ifdef __OS2__ +#include +#endif + +#ifdef _WIN32 +#define fileno _fileno +static FILE *fopen_utf8 (const char *filename_utf8, const char *mode_utf8); +#endif + +static int32_t read_bytes (void *id, void *data, int32_t bcount) +{ + return (int32_t) fread (data, 1, bcount, (FILE*) id); +} + +static int64_t get_pos (void *id) +{ +#ifdef _WIN32 + return _ftelli64 ((FILE*) id); +#else + return ftell ((FILE*) id); +#endif +} + +static int set_pos_abs (void *id, int64_t pos) +{ +#ifdef _WIN32 + return _fseeki64 (id, pos, SEEK_SET); +#else + return fseek (id, pos, SEEK_SET); +#endif +} + +static int set_pos_rel (void *id, int64_t delta, int mode) +{ +#ifdef _WIN32 + return _fseeki64 (id, delta, mode); +#else + return fseek (id, delta, mode); +#endif +} + +static int push_back_byte (void *id, int c) +{ + return ungetc (c, id); +} + +#ifdef _WIN32 + +static int64_t get_length (void *id) +{ + LARGE_INTEGER Size; + HANDLE fHandle; + + if (id == NULL) + return 0; + + fHandle = (HANDLE)_get_osfhandle(_fileno((FILE*) id)); + if (fHandle == INVALID_HANDLE_VALUE) + return 0; + + Size.u.LowPart = GetFileSize(fHandle, &Size.u.HighPart); + + if (Size.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) + return 0; + + return (int64_t)Size.QuadPart; +} + +#else + +static int64_t get_length (void *id) +{ + FILE *file = id; + struct stat statbuf; + + if (!file || fstat (fileno (file), &statbuf) || !(statbuf.st_mode & S_IFREG)) + return 0; + + return statbuf.st_size; +} + +#endif + +static int can_seek (void *id) +{ + FILE *file = id; + struct stat statbuf; + + return file && !fstat (fileno (file), &statbuf) && (statbuf.st_mode & S_IFREG); +} + +static int32_t write_bytes (void *id, void *data, int32_t bcount) +{ + return (int32_t) fwrite (data, 1, bcount, (FILE*) id); +} + +#ifdef _WIN32 + +static int truncate_here (void *id) +{ + FILE *file = id; + int64_t curr_pos = _ftelli64 (file); + + return _chsize_s (fileno (file), curr_pos); +} + +#else + +static int truncate_here (void *id) +{ + FILE *file = id; + off_t curr_pos = ftell (file); + + return ftruncate (fileno (file), curr_pos); +} + +#endif + +static int close_stream (void *id) +{ + return fclose ((FILE*) id); +} + +// int32_t (*read_bytes)(void *id, void *data, int32_t bcount); +// int32_t (*write_bytes)(void *id, void *data, int32_t bcount); +// int64_t (*get_pos)(void *id); // new signature for large files +// int (*set_pos_abs)(void *id, int64_t pos); // new signature for large files +// int (*set_pos_rel)(void *id, int64_t delta, int mode); // new signature for large files +// int (*push_back_byte)(void *id, int c); +// int64_t (*get_length)(void *id); // new signature for large files +// int (*can_seek)(void *id); +// int (*truncate_here)(void *id); // new function to truncate file at current position +// int (*close)(void *id); // new function to close file + +static WavpackStreamReader64 freader = { + read_bytes, write_bytes, get_pos, set_pos_abs, set_pos_rel, + push_back_byte, get_length, can_seek, truncate_here, close_stream +}; + +// This function attempts to open the specified WavPack file for reading. If +// this fails for any reason then an appropriate message is copied to "error" +// (which must accept 80 characters) and NULL is returned, otherwise a +// pointer to a WavpackContext structure is returned (which is used to call +// all other functions in this module). A filename beginning with "-" is +// assumed to be stdin. The "flags" argument has the following bit mask +// values to specify details of the open operation: + +// OPEN_WVC: attempt to open/read "correction" file +// OPEN_TAGS: attempt to read ID3v1 / APEv2 tags (requires seekable file) +// OPEN_WRAPPER: make audio wrapper available (i.e. RIFF) to caller +// OPEN_2CH_MAX: open only first stream of multichannel file (usually L/R) +// OPEN_NORMALIZE: normalize floating point data to +/- 1.0 (w/ offset exp) +// OPEN_STREAMING: blindly unpacks blocks w/o regard to header file position +// OPEN_EDIT_TAGS: allow editing of tags (file must be writable) +// OPEN_FILE_UTF8: assume infilename is UTF-8 encoded (Windows only) + +// Version 4.2 of the WavPack library adds the OPEN_STREAMING flag. This is +// essentially a "raw" mode where the library will simply decode any blocks +// fed it through the reader callback, regardless of where those blocks came +// from in a stream. The only requirement is that complete WavPack blocks are +// fed to the decoder (and this may require multiple blocks in multichannel +// mode) and that complete blocks are decoded (even if all samples are not +// actually required). All the blocks must contain the same number of channels +// and bit resolution, and the correction data must be either present or not. +// All other parameters may change from block to block (like lossy/lossless). +// Obviously, in this mode any seeking must be performed by the application +// (and again, decoding must start at the beginning of the block containing +// the seek sample). + +WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset) +{ + char *file_mode = (flags & OPEN_EDIT_TAGS) ? "r+b" : "rb"; + FILE *(*fopen_func)(const char *, const char *) = fopen; + FILE *wv_id, *wvc_id; + +#ifdef _WIN32 + if (flags & OPEN_FILE_UTF8) + fopen_func = fopen_utf8; +#endif + + if (*infilename == '-') { + wv_id = stdin; +#if defined(_WIN32) + _setmode (fileno (stdin), O_BINARY); +#endif +#if defined(__OS2__) + setmode (fileno (stdin), O_BINARY); +#endif + } + else if ((wv_id = fopen_func (infilename, file_mode)) == NULL) { + if (error) strcpy (error, (flags & OPEN_EDIT_TAGS) ? "can't open file for editing" : "can't open file"); + return NULL; + } + + if (wv_id != stdin && (flags & OPEN_WVC)) { + char *in2filename = malloc (strlen (infilename) + 10); + + strcpy (in2filename, infilename); + strcat (in2filename, "c"); + wvc_id = fopen_func (in2filename, "rb"); + free (in2filename); + } + else + wvc_id = NULL; + + return WavpackOpenFileInputEx64 (&freader, wv_id, wvc_id, error, flags, norm_offset); +} + +#ifdef _WIN32 + +// The following code Copyright (c) 2004-2012 LoRd_MuldeR +// (see cli/win32_unicode_support.c for full license) + +static wchar_t *utf8_to_utf16(const char *input) +{ + wchar_t *Buffer; + int BuffSize = 0, Result = 0; + + BuffSize = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0); + Buffer = (wchar_t*) malloc(sizeof(wchar_t) * BuffSize); + if(Buffer) + { + Result = MultiByteToWideChar(CP_UTF8, 0, input, -1, Buffer, BuffSize); + } + + return ((Result > 0) && (Result <= BuffSize)) ? Buffer : NULL; +} + + +static FILE *fopen_utf8(const char *filename_utf8, const char *mode_utf8) +{ + FILE *ret = NULL; + wchar_t *filename_utf16 = utf8_to_utf16(filename_utf8); + wchar_t *mode_utf16 = utf8_to_utf16(mode_utf8); + + if(filename_utf16 && mode_utf16) + { + ret = _wfopen(filename_utf16, mode_utf16); + } + + if(filename_utf16) free(filename_utf16); + if(mode_utf16) free(mode_utf16); + + return ret; +} + +#endif + + diff --git a/Frameworks/WavPack/Files/open_legacy.c b/Frameworks/WavPack/Files/open_legacy.c new file mode 100644 index 000000000..b12ca77e0 --- /dev/null +++ b/Frameworks/WavPack/Files/open_legacy.c @@ -0,0 +1,120 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2016 David Bryant. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// open_legacy.c + +// This code provides an interface between the new reader callback mechanism that +// WavPack uses internally and the old reader callback functions that did not +// provide large file support. + +#include +#include + +#include "wavpack_local.h" + +typedef struct { + WavpackStreamReader *reader; + void *id; +} WavpackReaderTranslator; + +static int32_t trans_read_bytes (void *id, void *data, int32_t bcount) +{ + WavpackReaderTranslator *trans = id; + return trans->reader->read_bytes (trans->id, data, bcount); +} + +static int32_t trans_write_bytes (void *id, void *data, int32_t bcount) +{ + WavpackReaderTranslator *trans = id; + return trans->reader->write_bytes (trans->id, data, bcount); +} + +static int64_t trans_get_pos (void *id) +{ + WavpackReaderTranslator *trans = id; + return trans->reader->get_pos (trans->id); +} + +static int trans_set_pos_abs (void *id, int64_t pos) +{ + WavpackReaderTranslator *trans = id; + return trans->reader->set_pos_abs (trans->id, (uint32_t) pos); +} + +static int trans_set_pos_rel (void *id, int64_t delta, int mode) +{ + WavpackReaderTranslator *trans = id; + return trans->reader->set_pos_rel (trans->id, (int32_t) delta, mode); +} + +static int trans_push_back_byte (void *id, int c) +{ + WavpackReaderTranslator *trans = id; + return trans->reader->push_back_byte (trans->id, c); +} + +static int64_t trans_get_length (void *id) +{ + WavpackReaderTranslator *trans = id; + return trans->reader->get_length (trans->id); +} + +static int trans_can_seek (void *id) +{ + WavpackReaderTranslator *trans = id; + return trans->reader->can_seek (trans->id); +} + +static int trans_close_stream (void *id) +{ + free (id); + return 0; +} + +// int32_t (*read_bytes)(void *id, void *data, int32_t bcount); +// int32_t (*write_bytes)(void *id, void *data, int32_t bcount); +// int64_t (*get_pos)(void *id); // new signature for large files +// int (*set_pos_abs)(void *id, int64_t pos); // new signature for large files +// int (*set_pos_rel)(void *id, int64_t delta, int mode); // new signature for large files +// int (*push_back_byte)(void *id, int c); +// int64_t (*get_length)(void *id); // new signature for large files +// int (*can_seek)(void *id); +// int (*truncate_here)(void *id); // new function to truncate file at current position +// int (*close)(void *id); // new function to close file + +static WavpackStreamReader64 trans_reader = { + trans_read_bytes, trans_write_bytes, trans_get_pos, trans_set_pos_abs, trans_set_pos_rel, + trans_push_back_byte, trans_get_length, trans_can_seek, NULL, trans_close_stream +}; + +// This function is identical to 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) +{ + WavpackReaderTranslator *trans_wv = NULL, *trans_wvc = NULL; + + if (wv_id) { + trans_wv = malloc (sizeof (WavpackReaderTranslator)); + trans_wv->reader = reader; + trans_wv->id = wv_id; + } + + if (wvc_id) { + trans_wvc = malloc (sizeof (WavpackReaderTranslator)); + trans_wvc->reader = reader; + trans_wvc->id = wvc_id; + } + + return WavpackOpenFileInputEx64 (&trans_reader, trans_wv, trans_wvc, error, flags, norm_offset); +} diff --git a/Frameworks/WavPack/Files/open_utils.c b/Frameworks/WavPack/Files/open_utils.c new file mode 100644 index 000000000..a94460949 --- /dev/null +++ b/Frameworks/WavPack/Files/open_utils.c @@ -0,0 +1,1117 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2016 David Bryant. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// open_utils.c + +// This module provides all the code required to open an existing WavPack file +// for reading by using a reader callback mechanism (NOT a filename). This +// includes the code required to find and parse WavPack blocks, process any +// included metadata, and queue up the bitstreams containing the encoded audio +// data. It does not the actual code to unpack audio data and this was done so +// that programs that just want to query WavPack files for information (like, +// for example, taggers) don't need to link in a lot of unnecessary code. + +#include +#include + +#include "wavpack_local.h" + +// 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. + +static int seek_eof_information (WavpackContext *wpc, int64_t *final_index, int get_wrapper); + +WavpackContext *WavpackOpenFileInputEx64 (WavpackStreamReader64 *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset) +{ + WavpackContext *wpc = malloc (sizeof (WavpackContext)); + WavpackStream *wps; + int num_blocks = 0; + unsigned char first_byte; + uint32_t bcount; + + if (!wpc) { + if (error) 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 = -1; + wpc->norm_offset = norm_offset; + wpc->max_streams = OLD_MAX_STREAMS; // use this until overwritten with actual number + wpc->open_flags = flags; + + wpc->filelen = wpc->reader->get_length (wpc->wv_in); + +#ifndef NO_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); + + if ((flags & OPEN_EDIT_TAGS) && !editable_tag (&wpc->m_tag)) { + if (error) strcpy (error, "can't edit tags located at the beginning of files!"); + return WavpackCloseFile (wpc); + } + } +#endif + +#ifndef VER4_ONLY + if (wpc->reader->read_bytes (wpc->wv_in, &first_byte, 1) != 1) { + if (error) 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 = malloc ((wpc->num_streams = 1) * sizeof (wpc->streams [0])); + if (!wpc->streams) { + if (error) strcpy (error, "can't allocate memory"); + return WavpackCloseFile (wpc); + } + + wpc->streams [0] = wps = malloc (sizeof (WavpackStream)); + if (!wps) { + if (error) strcpy (error, "can't allocate memory"); + return WavpackCloseFile (wpc); + } + 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 || + (!wps->wphdr.block_samples && num_blocks++ > 16)) { + if (error) strcpy (error, "not compatible with this version of WavPack file!"); + return WavpackCloseFile (wpc); + } + + wpc->filepos += bcount; + wps->blockbuff = malloc (wps->wphdr.ckSize + 8); + if (!wps->blockbuff) { + if (error) strcpy (error, "can't allocate memory"); + return WavpackCloseFile (wpc); + } + 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) { + if (error) strcpy (error, "can't read all of WavPack file!"); + return WavpackCloseFile (wpc); + } + + wps->init_done = FALSE; + + if (wps->wphdr.block_samples && !(flags & OPEN_STREAMING)) { + if (GET_BLOCK_INDEX (wps->wphdr) || GET_TOTAL_SAMPLES (wps->wphdr) == -1) { + wpc->initial_index = GET_BLOCK_INDEX (wps->wphdr); + SET_BLOCK_INDEX (wps->wphdr, 0); + + if (wpc->reader->can_seek (wpc->wv_in)) { + int64_t final_index = -1; + + seek_eof_information (wpc, &final_index, FALSE); + + if (final_index != -1) + wpc->total_samples = final_index - wpc->initial_index; + } + } + else + wpc->total_samples = GET_TOTAL_SAMPLES (wps->wphdr); + } + + if (wpc->wvc_in && wps->wphdr.block_samples && (wps->wphdr.flags & HYBRID_FLAG)) { + unsigned char ch; + + if (wpc->reader->read_bytes (wpc->wvc_in, &ch, 1) == 1) { + wpc->reader->push_back_byte (wpc->wvc_in, ch); + wpc->file2len = wpc->reader->get_length (wpc->wvc_in); + wpc->wvc_flag = TRUE; + } + } + + if (wpc->wvc_flag && !read_wvc_block (wpc)) { + if (error) strcpy (error, "not compatible with this version of correction file!"); + return WavpackCloseFile (wpc); + } + + if (!wps->init_done && !unpack_init (wpc)) { + if (error) strcpy (error, wpc->error_message [0] ? wpc->error_message : + "not compatible with this version of WavPack file!"); + + return WavpackCloseFile (wpc); + } + + wps->init_done = TRUE; + } + + wpc->config.flags &= ~0xff; + wpc->config.flags |= wps->wphdr.flags & 0xff; + + 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; + + if (wps->wphdr.flags & DSD_FLAG) { + if (flags & OPEN_DSD_NATIVE) { + wpc->config.bytes_per_sample = 1; + wpc->config.bits_per_sample = 8; + } + else if (flags & OPEN_DSD_AS_PCM) { + wpc->decimation_context = decimate_dsd_init (wpc->reduced_channels ? + wpc->reduced_channels : wpc->config.num_channels); + + wpc->config.bytes_per_sample = 3; + wpc->config.bits_per_sample = 24; + } + else { + if (error) strcpy (error, "not configured to handle DSD WavPack files!"); + return WavpackCloseFile (wpc); + } + } + else { + 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->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]; + } + + return wpc; +} + +// This function returns the major version number of the WavPack program +// (or library) that created the open file. Currently, this can be 1 to 5. +// Minor versions are not recorded in WavPack files. + +int WavpackGetVersion (WavpackContext *wpc) +{ + if (wpc) { +#ifndef VER4_ONLY + if (wpc->stream3) + return get_version3 (wpc); +#endif + return wpc->version_five ? 5 : 4; + } + + return 0; +} + +// Return the file format specified in the call to WavpackSetFileInformation() +// when the file was created. For all files created prior to WavPack 5.0 this +// will 0 (WP_FORMAT_WAV). + +unsigned char WavpackGetFileFormat (WavpackContext *wpc) +{ + return wpc->file_format; +} + +// Return a string representing the recommended file extension for the open +// WavPack file. For all files created prior to WavPack 5.0 this will be "wav", +// even for raw files with no RIFF into. This string is specified in the +// call to WavpackSetFileInformation() when the file was created. + +char *WavpackGetFileExtension (WavpackContext *wpc) +{ + if (wpc && wpc->file_extension [0]) + return wpc->file_extension; + else + return "wav"; +} + +// 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. + +static int read_metadata_buff (WavpackMetadata *wpmd, unsigned char *blockbuff, unsigned char **buffptr); +static int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd); +static void bs_open_read (Bitstream *bs, void *buffer_start, void *buffer_end); + +int unpack_init (WavpackContext *wpc) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + unsigned char *blockptr, *block2ptr; + WavpackMetadata wpmd; + + wps->num_terms = 0; + wps->mute_error = FALSE; + wps->crc = wps->crc_x = 0xffffffff; + wps->dsd.ready = 0; + CLEAR (wps->wvbits); + CLEAR (wps->wvcbits); + CLEAR (wps->wvxbits); + CLEAR (wps->decorr_passes); + CLEAR (wps->dc); + CLEAR (wps->w); + + if (!(wps->wphdr.flags & MONO_FLAG) && wpc->config.num_channels && wps->wphdr.block_samples && + (wpc->reduced_channels == 1 || wpc->config.num_channels == 1)) { + wps->mute_error = TRUE; + return FALSE; + } + + if ((wps->wphdr.flags & UNKNOWN_FLAGS) || (wps->wphdr.flags & MONO_DATA) == MONO_DATA) { + wps->mute_error = TRUE; + return FALSE; + } + + blockptr = wps->blockbuff + sizeof (WavpackHeader); + + while (read_metadata_buff (&wpmd, wps->blockbuff, &blockptr)) + if (!process_metadata (wpc, &wpmd)) { + wps->mute_error = TRUE; + return FALSE; + } + + if (wps->wphdr.block_samples && wpc->wvc_flag && wps->block2buff) { + block2ptr = wps->block2buff + sizeof (WavpackHeader); + + while (read_metadata_buff (&wpmd, wps->block2buff, &block2ptr)) + if (!process_metadata (wpc, &wpmd)) { + wps->mute_error = TRUE; + return FALSE; + } + } + + if (wps->wphdr.block_samples && ((wps->wphdr.flags & DSD_FLAG) ? !wps->dsd.ready : !bs_is_open (&wps->wvbits))) { + if (bs_is_open (&wps->wvcbits)) + strcpy (wpc->error_message, "can't unpack correction files alone!"); + + wps->mute_error = TRUE; + 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; + } + + if (wps->wphdr.block_samples) + wps->sample_index = GET_BLOCK_INDEX (wps->wphdr); + + return TRUE; +} + +//////////////////////////////// matadata handlers /////////////////////////////// + +// These functions handle specific metadata types and are called directly +// during WavPack block parsing by process_metadata() at the bottom. + +// This function initialzes the main bitstream for audio samples, which must +// be in the "wv" file. + +static int init_wv_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + if (!wpmd->byte_length || (wpmd->byte_length & 1)) + return FALSE; + + bs_open_read (&wps->wvbits, wpmd->data, (unsigned 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. + +static int init_wvc_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + if (!wpmd->byte_length || (wpmd->byte_length & 1)) + return FALSE; + + bs_open_read (&wps->wvcbits, wpmd->data, (unsigned 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. + +static int init_wvx_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + unsigned char *cp = wpmd->data; + + if (wpmd->byte_length <= 4 || (wpmd->byte_length & 1)) + return FALSE; + + 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, (unsigned char *) wpmd->data + wpmd->byte_length); + return TRUE; +} + +// 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. + +static 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; +} + +static 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; +} + +// 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. + +static int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length, shift = 0, mask_bits; + unsigned char *byteptr = wpmd->data; + uint32_t mask = 0; + + if (!bytecnt || bytecnt > 7) + return FALSE; + + if (!wpc->config.num_channels) { + + // if bytecnt is 6 or 7 we are using new configuration with "unlimited" streams + + if (bytecnt >= 6) { + wpc->config.num_channels = (byteptr [0] | ((byteptr [2] & 0xf) << 8)) + 1; + wpc->max_streams = (byteptr [1] | ((byteptr [2] & 0xf0) << 4)) + 1; + + if (wpc->config.num_channels < wpc->max_streams) + return FALSE; + + byteptr += 3; + mask = *byteptr++; + mask |= (uint32_t) *byteptr++ << 8; + mask |= (uint32_t) *byteptr++ << 16; + + if (bytecnt == 7) // this was introduced in 5.0 + mask |= (uint32_t) *byteptr << 24; + } + else { + wpc->config.num_channels = *byteptr++; + + while (--bytecnt) { + mask |= (uint32_t) *byteptr++ << shift; + shift += 8; + } + } + + if (wpc->config.num_channels > wpc->max_streams * 2) + return FALSE; + + wpc->config.channel_mask = mask; + + for (mask_bits = 0; mask; mask >>= 1) + if ((mask & 1) && ++mask_bits > wpc->config.num_channels) + return FALSE; + } + + return TRUE; +} + +// Read configuration information from metadata. + +static int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + unsigned char *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; + bytecnt -= 3; + + if (bytecnt && (wpc->config.flags & CONFIG_EXTRA_MODE)) { + wpc->config.xmode = *byteptr++; + bytecnt--; + } + + // we used an extra config byte here for the 5.0.0 alpha, so still + // honor it now (but this has been replaced with NEW_CONFIG) + + if (bytecnt) { + wpc->config.qmode = (wpc->config.qmode & ~0xff) | *byteptr; + wpc->version_five = 1; + } + } + + return TRUE; +} + +// Read "new" configuration information from metadata. + +static int read_new_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + unsigned char *byteptr = wpmd->data; + + wpc->version_five = 1; // just having this block signals version 5.0 + + wpc->file_format = wpc->config.qmode = wpc->channel_layout = 0; + + if (wpc->channel_reordering) { + free (wpc->channel_reordering); + wpc->channel_reordering = NULL; + } + + // if there's any data, the first two bytes are file_format and qmode flags + + if (bytecnt) { + wpc->file_format = *byteptr++; + wpc->config.qmode = (wpc->config.qmode & ~0xff) | *byteptr++; + bytecnt -= 2; + + // another byte indicates a channel layout + + if (bytecnt) { + int nchans, i; + + wpc->channel_layout = (int32_t) *byteptr++ << 16; + bytecnt--; + + // another byte means we have a channel count for the layout and maybe a reordering + + if (bytecnt) { + wpc->channel_layout += nchans = *byteptr++; + bytecnt--; + + // any more means there's a reordering string + + if (bytecnt) { + if (bytecnt > nchans) + return FALSE; + + wpc->channel_reordering = malloc (nchans); + + // note that redundant reordering info is not stored, so we fill in the rest + + if (wpc->channel_reordering) { + for (i = 0; i < nchans; ++i) + if (bytecnt) { + wpc->channel_reordering [i] = *byteptr++; + bytecnt--; + } + else + wpc->channel_reordering [i] = i; + } + } + } + else + wpc->channel_layout += wpc->config.num_channels; + } + } + + return TRUE; +} + +// Read non-standard sampling rate from metadata. + +static int read_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + unsigned char *byteptr = wpmd->data; + + if (bytecnt == 3 || bytecnt == 4) { + wpc->config.sample_rate = (int32_t) *byteptr++; + wpc->config.sample_rate |= (int32_t) *byteptr++ << 8; + wpc->config.sample_rate |= (int32_t) *byteptr++ << 16; + + // for sampling rates > 16777215 (non-audio probably, or ...) + + if (bytecnt == 4) + wpc->config.sample_rate |= (int32_t) (*byteptr & 0x7f) << 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. + +static int read_wrapper_data (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + if ((wpc->open_flags & OPEN_WRAPPER) && wpc->wrapper_bytes < MAX_WRAPPER_BYTES && wpmd->byte_length) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + wpmd->byte_length); + if (!wpc->wrapper_data) + return FALSE; + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, wpmd->data, wpmd->byte_length); + wpc->wrapper_bytes += wpmd->byte_length; + } + + return TRUE; +} + +static int read_metadata_buff (WavpackMetadata *wpmd, unsigned char *blockbuff, unsigned char **buffptr) +{ + WavpackHeader *wphdr = (WavpackHeader *) blockbuff; + unsigned char *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) { + if (!wpmd->byte_length) // odd size and zero length makes no sense + return FALSE; + 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; +} + +static 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_NEW_CONFIG_BLOCK: + return read_new_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_DSD_BLOCK: + return init_dsd_block (wpc, wpmd); + + case ID_ALT_HEADER: case ID_ALT_TRAILER: + if (!(wpc->open_flags & OPEN_ALT_TYPES)) + return TRUE; + + case ID_RIFF_HEADER: case ID_RIFF_TRAILER: + return read_wrapper_data (wpc, wpmd); + + case ID_ALT_MD5_CHECKSUM: + if (!(wpc->open_flags & OPEN_ALT_TYPES)) + return TRUE; + + 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; + + case ID_ALT_EXTENSION: + if (wpmd->byte_length && wpmd->byte_length < sizeof (wpc->file_extension)) { + memcpy (wpc->file_extension, wpmd->data, wpmd->byte_length); + wpc->file_extension [wpmd->byte_length] = 0; + } + + default: + return (wpmd->id & ID_OPTIONAL_DATA) ? TRUE : FALSE; + } +} + +//////////////////////////////// bitstream management /////////////////////////////// + +// Open the specified BitStream and associate with the specified buffer. + +static void bs_read (Bitstream *bs); + +static void bs_open_read (Bitstream *bs, void *buffer_start, void *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; + 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 < sizeof (*(bs->ptr)) * 8) + bs->ptr++; + + bytes_read = (uint32_t)(bs->ptr - bs->buf) * sizeof (*(bs->ptr)); + + if (!(bytes_read & 1)) + ++bytes_read; + + CLEAR (*bs); + return bytes_read; +} + +// Normally the trailing wrapper will not be available when a WavPack file is first +// opened for reading because it is stored in the final block of the file. This +// function forces a seek to the end of the file to pick up any trailing wrapper +// stored there (then use WavPackGetWrapper**() to obtain). This can obviously only +// be used for seekable files (not pipes) and is not available for pre-4.0 WavPack +// files. + +void WavpackSeekTrailingWrapper (WavpackContext *wpc) +{ + if ((wpc->open_flags & OPEN_WRAPPER) && + wpc->reader->can_seek (wpc->wv_in) && !wpc->stream3) + seek_eof_information (wpc, NULL, TRUE); +} + +// 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. + +int WavpackGetMD5Sum (WavpackContext *wpc, unsigned char data [16]) +{ + if (wpc->config.flags & CONFIG_MD5_CHECKSUM) { + if (!wpc->config.md5_read && wpc->reader->can_seek (wpc->wv_in)) + seek_eof_information (wpc, NULL, FALSE); + + if (wpc->config.md5_read) { + memcpy (data, wpc->config.md5_checksum, 16); + return TRUE; + } + } + + return FALSE; +} + +// 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. + +uint32_t read_next_header (WavpackStreamReader64 *reader, void *id, WavpackHeader *wphdr) +{ + unsigned char buffer [sizeof (*wphdr)], *sp = buffer + sizeof (*wphdr), *ep = sp; + uint32_t bytes_skipped = 0; + int bleft; + + while (1) { + if (sp < ep) { + bleft = (int)(ep - sp); + memmove (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 [2] || sp [1] || *sp >= 24) && sp [5] == 4 && + sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff) && sp [18] < 3 && !sp [19]) { + memcpy (wphdr, buffer, sizeof (*wphdr)); + WavpackLittleEndianToNative (wphdr, WavpackHeaderFormat); + return bytes_skipped; + } + + while (sp < ep && *sp != 'w') + sp++; + + if ((bytes_skipped += (uint32_t)(sp - buffer)) > 1024 * 1024) + return -1; + } +} + +// Compare the regular wv file block header to a potential matching wvc +// file block header and return action code based on analysis: +// +// 0 = use wvc block (assuming rest of block is readable) +// 1 = bad match; try to read next wvc block +// -1 = bad match; ignore wvc file for this block and backup fp (if +// possible) and try to use this block next time + +static int match_wvc_header (WavpackHeader *wv_hdr, WavpackHeader *wvc_hdr) +{ + if (GET_BLOCK_INDEX (*wv_hdr) == GET_BLOCK_INDEX (*wvc_hdr) && + wv_hdr->block_samples == wvc_hdr->block_samples) { + int wvi = 0, wvci = 0; + + if (wv_hdr->flags == wvc_hdr->flags) + return 0; + + if (wv_hdr->flags & INITIAL_BLOCK) + wvi -= 1; + + if (wv_hdr->flags & FINAL_BLOCK) + wvi += 1; + + if (wvc_hdr->flags & INITIAL_BLOCK) + wvci -= 1; + + if (wvc_hdr->flags & FINAL_BLOCK) + wvci += 1; + + return (wvci - wvi < 0) ? 1 : -1; + } + + if (GET_BLOCK_INDEX (*wvc_hdr) > GET_BLOCK_INDEX (*wv_hdr)) + return 1; + else + return -1; +} + +// Read the wvc block that matches the regular wv block that has been +// read for the current stream. If an exact match is not found then +// we either keep reading or back up and (possibly) use the block +// later. The skip_wvc flag is set if not matching wvc block is found +// so that we can still decode using only the lossy version (although +// we flag this as an error). A return of FALSE indicates a serious +// error (not just that we missed one wvc block). + +int read_wvc_block (WavpackContext *wpc) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int64_t bcount, file2pos; + WavpackHeader wphdr; + int compare_result; + + while (1) { + file2pos = wpc->reader->get_pos (wpc->wvc_in); + bcount = read_next_header (wpc->reader, wpc->wvc_in, &wphdr); + + if (bcount == (uint32_t) -1) { + wps->wvc_skip = TRUE; + wpc->crc_errors++; + return FALSE; + } + + if (wpc->open_flags & OPEN_STREAMING) + SET_BLOCK_INDEX (wphdr, wps->sample_index = 0); + else + SET_BLOCK_INDEX (wphdr, GET_BLOCK_INDEX (wphdr) - wpc->initial_index); + + if (wphdr.flags & INITIAL_BLOCK) + wpc->file2pos = file2pos + bcount; + + compare_result = match_wvc_header (&wps->wphdr, &wphdr); + + if (!compare_result) { + wps->block2buff = malloc (wphdr.ckSize + 8); + if (!wps->block2buff) + return FALSE; + memcpy (wps->block2buff, &wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wphdr.ckSize - 24) != + wphdr.ckSize - 24 || (wphdr.flags & UNKNOWN_FLAGS)) { + free (wps->block2buff); + wps->block2buff = NULL; + wps->wvc_skip = TRUE; + wpc->crc_errors++; + return FALSE; + } + + wps->wvc_skip = FALSE; + memcpy (&wps->wphdr, &wphdr, 32); + return TRUE; + } + else if (compare_result == -1) { + wps->wvc_skip = TRUE; + wpc->reader->set_pos_rel (wpc->wvc_in, -32, SEEK_CUR); + wpc->crc_errors++; + return TRUE; + } + } +} + +// This function is used to seek to end of a file to obtain certain information +// that is stored there at the file creation time because it is not known at +// the start. This includes the MD5 sum and and trailing part of the file +// wrapper, and in some rare cases may include the total number of samples in +// the file (although we usually try to back up and write that at the front of +// the file). Note this function restores the file position to its original +// location (and obviously requires a seekable file). The normal return value +// is TRUE indicating no errors, although this does not actually mean that any +// information was retrieved. An error return of FALSE usually means the file +// terminated unexpectedly. Note that this could be used to get all three +// types of information in one go, but it's not actually used that way now. + +static int seek_eof_information (WavpackContext *wpc, int64_t *final_index, int get_wrapper) +{ + int64_t restore_pos, last_pos = -1; + WavpackStreamReader64 *reader = wpc->reader; + int alt_types = wpc->open_flags & OPEN_ALT_TYPES; + uint32_t blocks = 0, audio_blocks = 0; + void *id = wpc->wv_in; + WavpackHeader wphdr; + + restore_pos = reader->get_pos (id); // we restore file position when done + + // start 1MB from the end-of-file, or from the start if the file is not that big + + if (reader->get_length (id) > 1048576LL) + reader->set_pos_rel (id, -1048576, SEEK_END); + else + reader->set_pos_abs (id, 0); + + // Note that we go backward (without parsing inside blocks) until we find a block + // with audio (careful to not get stuck in a loop). Only then do we go forward + // parsing all blocks in their entirety. + + while (1) { + uint32_t bcount = read_next_header (reader, id, &wphdr); + int64_t current_pos = reader->get_pos (id); + + // if we just got to the same place as last time, we're stuck and need to give up + + if (current_pos == last_pos) { + reader->set_pos_abs (id, restore_pos); + return FALSE; + } + + last_pos = current_pos; + + // We enter here if we just read 1 MB without seeing any WavPack block headers. + // Since WavPack blocks are < 1 MB, that means we're in a big APE tag, or we got + // to the end-of-file. + + if (bcount == (uint32_t) -1) { + + // if we have not seen any blocks at all yet, back up almost 2 MB (or to the + // beginning of the file) and try again + + if (!blocks) { + if (current_pos > 2000000LL) + reader->set_pos_rel (id, -2000000, SEEK_CUR); + else + reader->set_pos_abs (id, 0); + + continue; + } + + // if we have seen WavPack blocks, then this means we've done all we can do here + + reader->set_pos_abs (id, restore_pos); + return TRUE; + } + + blocks++; + + // If the block has audio samples, calculate a final index, although this is not + // final since this may not be the last block with audio. On the other hand, if + // this block does not have audio, and we haven't seen one with audio, we have + // to go back some more. + + if (wphdr.block_samples) { + if (final_index) + *final_index = GET_BLOCK_INDEX (wphdr) + wphdr.block_samples; + + audio_blocks++; + } + else if (!audio_blocks) { + if (current_pos > 1048576LL) + reader->set_pos_rel (id, -1048576, SEEK_CUR); + else + reader->set_pos_abs (id, 0); + + continue; + } + + // at this point we have seen at least one block with audio, so we parse the + // entire block looking for MD5 metadata or (conditionally) trailing wrappers + + bcount = wphdr.ckSize - sizeof (WavpackHeader) + 8; + + while (bcount >= 2) { + unsigned char meta_id, c1, c2; + uint32_t meta_bc, meta_size; + + if (reader->read_bytes (id, &meta_id, 1) != 1 || + reader->read_bytes (id, &c1, 1) != 1) { + reader->set_pos_abs (id, restore_pos); + 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) { + reader->set_pos_abs (id, restore_pos); + return FALSE; + } + + meta_bc += ((uint32_t) c1 << 9) + ((uint32_t) c2 << 17); + bcount -= 2; + } + + meta_size = (meta_id & ID_ODD_SIZE) ? meta_bc - 1 : meta_bc; + meta_id &= ID_UNIQUE; + + if (get_wrapper && (meta_id == ID_RIFF_TRAILER || (alt_types && meta_id == ID_ALT_TRAILER)) && meta_bc) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + meta_bc); + + if (!wpc->wrapper_data) { + reader->set_pos_abs (id, restore_pos); + return FALSE; + } + + if (reader->read_bytes (id, wpc->wrapper_data + wpc->wrapper_bytes, meta_bc) == meta_bc) + wpc->wrapper_bytes += meta_size; + else { + reader->set_pos_abs (id, restore_pos); + return FALSE; + } + } + else if (meta_id == ID_MD5_CHECKSUM || (alt_types && meta_id == ID_ALT_MD5_CHECKSUM)) { + if (meta_bc == 16 && bcount >= 16) { + if (reader->read_bytes (id, wpc->config.md5_checksum, 16) == 16) + wpc->config.md5_read = TRUE; + else { + reader->set_pos_abs (id, restore_pos); + return FALSE; + } + } + else + reader->set_pos_rel (id, meta_bc, SEEK_CUR); + } + else + reader->set_pos_rel (id, meta_bc, SEEK_CUR); + + bcount -= meta_bc; + } + } +} diff --git a/Frameworks/WavPack/Files/pack.c b/Frameworks/WavPack/Files/pack.c index d1330ac75..04fbc135b 100644 --- a/Frameworks/WavPack/Files/pack.c +++ b/Frameworks/WavPack/Files/pack.c @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // +// Copyright (c) 1998 - 2013 Conifer Software. // // MMX optimizations (c) 2006 Joachim Henke // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // @@ -10,1074 +10,16 @@ // 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_local.h" +// the entropy encoding which is handled by the write_words.c module. For better +// efficiency, the conversion is isolated to tight loops that handle an entire +// buffer. #include -#include #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 - -//////////////////////////////// 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). - -static const WavpackDecorrSpec fast_specs [] = { - { 1, 2,18,17 }, // 0 - { 1, 1,17,17 }, // 1 - { 0, 2,18,17 }, // 2 - { 0, 1,17,17 }, // 3 - { 1, 3, 1,18 }, // 4 - { 1, 1,17, 1 }, // 5 - { 0, 1, 1,17 }, // 6 - { 0, 1,-2,17 }, // 7 - { 0, 2,-1,17 }, // 8 - { 1, 1,17, 2 }, // 9 - { 0, 3,18,18 }, // 10 - { 0, 1,17, 1 }, // 11 - { 1, 6, 1, 2 }, // 12 - { 1, 1,17, 3 }, // 13 - { 0, 1,-2, 3 }, // 14 - { 0, 1, 2,17 }, // 15 - { 0, 1,18,-2 }, // 16 - { 0, 1,-1,17 }, // 17 - { 0, 1,18,17 }, // 18 - { 0, 1,17, 2 }, // 19 - { 1, 2,18,-2 }, // 20 - { 1, 1, 1,17 }, // 21 - { 0, 3,18, 2 }, // 22 - { 0, 1,17,-2 }, // 23 - { 0, 1,18,-2 }, // 24 - { 1, 2,17,-3 }, // 25 - { 0, 1,18, 3 }, // 26 - { 0, 1,18,18 }, // 27 - { 1, 1, 1, 3 }, // 28 - { 1, 1,18, 3 }, // 29 - { 1, 1, 1, 3 }, // 30 - { 0, 2,18,17 }, // 31 - { 1, 1, 1,17 }, // 32 - { 1, 1,17, 3 }, // 33 - { 0, 3,18,17 }, // 34 - { 0, 1,18,18 }, // 35 - { 1, 1, 1, 3 }, // 36 - { 1, 1, 1,18 }, // 37 - { 0, 1,18,-2 }, // 38 - { 0, 2,18,17 }, // 39 - { 0, 1,-1,18 }, // 40 - { 1, 1,17, 3 }, // 41 - { 0, 1,17, 2 }, // 42 - { 0, 1,17, 3 }, // 43 - { 1, 1,18, 2 }, // 44 - { 1, 1,17,-2 }, // 45 - { 0, 1, 1,-2 }, // 46 - { 0, 2,18,17 }, // 47 - { 0, 1,17,-2 }, // 48 - { 1, 1,17,-2 }, // 49 - { 0, 1,18, 3 }, // 50 - { 0, 1, 2,17 }, // 51 - { 1, 2,18,-3 }, // 52 - { 1, 2, 1,18 }, // 53 - { 1, 2,18, 2 }, // 54 - { 0, 1,17,-1 }, // 55 - { 0, 1,17,-2 }, // 56 - { 1, 1,17,-2 }, // 57 - { 1, 1, 1, 3 }, // 58 - { 0, 1, 1,17 }, // 59 - { 1, 2,18,-2 }, // 60 - { 1, 2,17,-3 }, // 61 - { 0, 2,18,17 }, // 62 - { 0, 2,18,17 }, // 63 - { 1, 1,17, 2 }, // 64 - { 1, 2,18,18 }, // 65 - { 0, 1,17, 2 }, // 66 - { 0, 1,18,17 }, // 67 - { 1, 1, 1,17 }, // 68 - { 1, 1,17, 2 }, // 69 - { 0, 2,18,18 }, // 70 - { 0, 2,18,17 }, // 71 - { 1, 2,17,-3 }, // 72 - { 1, 6, 1, 2 }, // 73 - { 0, 3,17,17 }, // 74 - { 0, 1, 1,18 }, // 75 - { 0, 1, 1,-2 }, // 76 - { 1, 1,17, 2 }, // 77 - { 0, 2,18,17 }, // 78 - { 0, 2,18,17 }, // 79 - { 1, 1,18, 3 }, // 80 - { 1, 2,17,-3 }, // 81 - { 0, 1,17, 2 }, // 82 - { 0, 1,17, 3 }, // 83 - { 0, 1,18,-2 }, // 84 - { 1, 1,18,18 }, // 85 - { 1, 6, 1, 2 }, // 86 - { 0, 2,18,17 }, // 87 - { 0, 2,18,17 }, // 88 - { 0, 1,-1,17 }, // 89 - { 1, 1,18, 3 }, // 90 - { 0, 1,17,18 }, // 91 - { 1, 1,17, 3 }, // 92 - { 0, 1,18, 3 }, // 93 - { 0, 2,18,17 }, // 94 - { 0, 2,18,17 }, // 95 - { 1, 2,18, 2 }, // 96 - { 0, 1,-2, 3 }, // 97 - { 0, 4,18,-1 }, // 98 - { 0, 2,18,18 }, // 99 - { 0, 1,-2, 3 }, // 100 - { 1, 1,17,-2 }, // 101 - { 0, 1,17, 3 }, // 102 - { 0, 2,18,17 }, // 103 - { 0, 2,-1,18 }, // 104 - { 1, 1, 2,17 }, // 105 - { 0, 2,17,-2 }, // 106 - { 0, 1,17, 2 }, // 107 - { 1, 2,18,-3 }, // 108 - { 0, 1,17,-2 }, // 109 - { 0, 2,18,17 }, // 110 - { 0, 2,18,17 }, // 111 - { 1, 1,17,-2 }, // 112 - { 1, 2,17,-3 }, // 113 - { 1, 1, 1, 3 }, // 114 - { 1, 1, 2,17 }, // 115 - { 1, 2,18, 2 }, // 116 - { 1, 1, 2,17 }, // 117 - { 1, 1,18, 2 }, // 118 - { 0, 2,18,17 }, // 119 - { 0, 2,18,17 }, // 120 - { 0, 1,17,-2 }, // 121 - { 0, 2,18,17 }, // 122 - { 0, 2,17,-1 }, // 123 - { 0, 2,18,-2 }, // 124 - { 0, 2,18,17 }, // 125 - { 0, 2,18,17 }, // 126 - { 0, 2,18,17 }, // 127 - { 1, 1, 1, 3 }, // 128 - { 0, 2,-2,17 }, // 129 - { 0, 2,18,-2 }, // 130 - { 0, 2,17,-2 }, // 131 - { 1, 1, 2,17 }, // 132 - { 1, 1, 1, 3 }, // 133 - { 0, 1, 2,17 }, // 134 - { 0, 2,18,17 }, // 135 - { 0, 3,-1,17 }, // 136 - { 1, 1, 2,17 }, // 137 - { 0, 2,18,18 }, // 138 - { 0, 1,17, 2 }, // 139 - { 1, 4,18,-3 }, // 140 - { 1, 1,18, 1 }, // 141 - { 0, 2,18,17 }, // 142 - { 0, 2,18,17 }, // 143 - { 1, 2,18,-1 }, // 144 - { 0, 1,-1,18 }, // 145 - { 1, 6, 1, 2 }, // 146 - { 1, 1,17, 2 }, // 147 - { 1, 4,18, 3 }, // 148 - { 0, 1, 1,17 }, // 149 - { 0, 1,18, 2 }, // 150 - { 0, 2,18,17 }, // 151 - { 0, 2,18,17 }, // 152 - { 1, 2,17, 2 }, // 153 - { 0, 2,18,-2 }, // 154 - { 0, 1, 1,18 }, // 155 - { 1, 2,18,-3 }, // 156 - { 0, 2,18,17 }, // 157 - { 0, 2,18,17 }, // 158 - { 0, 2,18,17 }, // 159 - { 1, 2,18,18 }, // 160 - { 1, 3,17,17 }, // 161 - { 0, 1,-2,17 }, // 162 - { 0, 1,17,18 }, // 163 - { 0, 1,-1, 3 }, // 164 - { 1, 1, 2,17 }, // 165 - { 0, 2,18,-1 }, // 166 - { 0, 2,18,17 }, // 167 - { 0, 2,18,17 }, // 168 - { 1, 1,17,-2 }, // 169 - { 1, 2,17, 2 }, // 170 - { 1, 1,18, 3 }, // 171 - { 0, 1,18, 2 }, // 172 - { 1, 2,17,-3 }, // 173 - { 0, 2,18,17 }, // 174 - { 0, 2,18,17 }, // 175 - { 0, 1,-2,17 }, // 176 - { 0, 1,17,-1 }, // 177 - { 0, 1,18,-1 }, // 178 - { 0, 2,18,17 }, // 179 - { 1, 2,17,-3 }, // 180 - { 1, 1, 1,18 }, // 181 - { 1, 3,18, 2 }, // 182 - { 0, 2,18,17 }, // 183 - { 0, 2,18,17 }, // 184 - { 0, 2,18,17 }, // 185 - { 0, 2,18,17 }, // 186 - { 0, 3,18,18 }, // 187 - { 0, 1, 1,-2 }, // 188 - { 0, 2,18,17 }, // 189 - { 0, 2,18,17 }, // 190 - { 0, 2,18,17 }, // 191 - { 1, 2,17,-3 }, // 192 - { 1, 1,18,18 }, // 193 - { 0, 2,18, 2 }, // 194 - { 0, 1,17,18 }, // 195 - { 1, 2,18, 2 }, // 196 - { 1, 1,17,-2 }, // 197 - { 0, 2,17,-1 }, // 198 - { 0, 2,18,17 }, // 199 - { 0, 2,18,17 }, // 200 - { 0, 2,18,17 }, // 201 - { 0, 1, 1,-2 }, // 202 - { 0, 1,18, 1 }, // 203 - { 1, 2,18,-2 }, // 204 - { 0, 1,17, 2 }, // 205 - { 0, 2,18,17 }, // 206 - { 0, 2,18,17 }, // 207 - { 1, 1,17, 3 }, // 208 - { 0, 1,17,-1 }, // 209 - { 0, 1,18, 2 }, // 210 - { 1, 1,17, 3 }, // 211 - { 1, 1,17,-2 }, // 212 - { 0, 1,18,18 }, // 213 - { 0, 2,18,17 }, // 214 - { 0, 2,18,17 }, // 215 - { 0, 2,18,17 }, // 216 - { 0, 2,18,17 }, // 217 - { 0, 2,18,17 }, // 218 - { 1, 1,17,18 }, // 219 - { 0, 1,-2, 3 }, // 220 - { 0, 2,18,17 }, // 221 - { 0, 2,18,17 }, // 222 - { 0, 2,18,17 }, // 223 - { 1, 2,18,-3 }, // 224 - { 0, 2,18,17 }, // 225 - { 0, 3,18, 2 }, // 226 - { 0, 1, 1,18 }, // 227 - { 0, 2,18,17 }, // 228 - { 0, 1,17,-1 }, // 229 - { 0, 2,18,17 }, // 230 - { 0, 2,18,17 }, // 231 - { 0, 2,18,17 }, // 232 - { 0, 1,-2, 3 }, // 233 - { 0, 3,17,17 }, // 234 - { 0, 2,18,17 }, // 235 - { 0, 2,18,17 }, // 236 - { 1, 1,17, 2 }, // 237 - { 0, 2,18,17 }, // 238 - { 0, 2,18,17 }, // 239 - { 1, 1,17, 2 }, // 240 - { 0, 2,18,17 }, // 241 - { 0, 2,18,17 }, // 242 - { 0, 2,18,17 }, // 243 - { 0, 2,18, 2 }, // 244 - { 0, 2,18,17 }, // 245 - { 0, 2,18,17 }, // 246 - { 0, 2,18,17 }, // 247 - { 0, 2,18,17 }, // 248 - { 0, 2,18,17 }, // 249 - { 0, 2,18,17 }, // 250 - { 0, 2,18,17 }, // 251 - { 0, 2,18,17 }, // 252 - { 0, 2,18,17 }, // 253 - { 0, 2,18,17 }, // 254 - { 0, 2,18,17 }, // 255 -}; - -static const WavpackDecorrSpec default_specs [] = { - { 1, 2,18,18, 2,17, 3 }, // 0 - { 0, 2,18,17,-1, 3, 2 }, // 1 - { 1, 1,17,18,18,-2, 2 }, // 2 - { 0, 2,18,17, 3,-2,17 }, // 3 - { 1, 2,18,17, 2,17, 3 }, // 4 - { 0, 1,18,18,-1, 2,17 }, // 5 - { 0, 1,17,17,-2, 2, 3 }, // 6 - { 0, 1,18,-2,18, 2,17 }, // 7 - { 1, 2,18,18,-1, 2, 3 }, // 8 - { 0, 2,18,17, 3, 2, 5 }, // 9 - { 1, 1,18,17,18, 2, 5 }, // 10 - { 0, 1,17,17,-2, 2, 3 }, // 11 - { 0, 1,18,-2,18, 2, 5 }, // 12 - { 0, 1,17,-2,17, 2,-3 }, // 13 - { 1, 1,17,-2,17, 1, 2 }, // 14 - { 0, 1,17,17,-2, 2, 3 }, // 15 - { 1, 1,18, 3, 1, 5, 4 }, // 16 - { 1, 4,18,18, 2, 3,-2 }, // 17 - { 0, 1, 1,-1,-1, 2,17 }, // 18 - { 0, 2,18,17, 3, 2, 5 }, // 19 - { 0, 1,18,18,18, 2,17 }, // 20 - { 0, 1,18,17,-1, 2,18 }, // 21 - { 1, 1,17, 3, 2, 1, 7 }, // 22 - { 0, 2,18,-2,18, 2, 3 }, // 23 - { 1, 3,18,-3,18, 2, 3 }, // 24 - { 0, 3,18,17, 2, 3,17 }, // 25 - { 1, 1,17,17, 2, 1, 4 }, // 26 - { 0, 1,17,18,-2, 2,17 }, // 27 - { 1, 1,18,18, 3, 5, 2 }, // 28 - { 0, 1,17,17, 2,18, 4 }, // 29 - { 0, 1,18,17, 1, 4, 6 }, // 30 - { 1, 1, 3,17,18, 2,17 }, // 31 - { 1, 1,17, 3, 2, 1, 7 }, // 32 - { 0, 1,18,17,-1, 2, 3 }, // 33 - { 1, 1,17,17, 2, 1, 4 }, // 34 - { 1, 2,18,17,-1,17, 3 }, // 35 - { 1, 2,18,17, 2, 3,-1 }, // 36 - { 0, 2,18,18,-2, 2,17 }, // 37 - { 0, 1,17,17, 2,18, 4 }, // 38 - { 0, 5,-2,18,18,18, 2 }, // 39 - { 1, 1,18,18,-1, 6, 3 }, // 40 - { 0, 1,17,17,-2, 2, 3 }, // 41 - { 1, 1,18,17,18, 2,17 }, // 42 - { 0, 1,18,17, 4, 3, 1 }, // 43 - { 0, 1,-2,18, 2, 2,18 }, // 44 - { 1, 2,18,18,-2, 2,-1 }, // 45 - { 1, 1,17,17, 2, 1, 4 }, // 46 - { 0, 1,17,18,-2, 2,17 }, // 47 - { 1, 1,17, 3, 2, 1, 7 }, // 48 - { 1, 3,18,-3,18, 2, 3 }, // 49 - { 1, 2,18,18,-2, 2,-1 }, // 50 - { 1, 1,18,18, 3, 5, 2 }, // 51 - { 0, 2,18,18,-1, 2,17 }, // 52 - { 0, 1,18,-1,17,18, 2 }, // 53 - { 0, 1,17,-1, 2, 3, 6 }, // 54 - { 0, 1,18,-2,18, 2, 5 }, // 55 - { 1, 2,18,18,-2, 2,-1 }, // 56 - { 0, 3,18,18, 2, 3,17 }, // 57 - { 0, 1,17,17, 2,18, 4 }, // 58 - { 1, 1,17,-2,17, 1, 2 }, // 59 - { 0, 1,-1, 3, 5, 4, 7 }, // 60 - { 0, 3,18,18, 3, 2, 5 }, // 61 - { 0, 1,17,17, 2,18, 4 }, // 62 - { 0, 1,18,17,-2,18, 3 }, // 63 - { 0, 2,18,18,-2, 2,17 }, // 64 - { 0, 3,18,17,-2, 2, 3 }, // 65 - { 1, 1,18,18,-2, 2,17 }, // 66 - { 0, 1,18,17, 4, 3, 1 }, // 67 - { 1, 2, 3,18,17, 2,17 }, // 68 - { 1, 2,18,18, 2,-2,18 }, // 69 - { 1, 2,18,18,-1,18, 2 }, // 70 - { 0, 2,18,18,-2, 2,17 }, // 71 - { 1, 3,18,18, 2, 3,-2 }, // 72 - { 0, 3,18,18, 3, 2, 5 }, // 73 - { 0, 1,18,-2,18, 2, 5 }, // 74 - { 1, 1,17, 3, 2, 1, 7 }, // 75 - { 1, 3,18,18,-2, 2,18 }, // 76 - { 1, 1,17,18,18,-2, 2 }, // 77 - { 0, 1,18,-2,18, 2, 5 }, // 78 - { 0, 2,18,-2,18, 2, 3 }, // 79 - { 0, 1,-1, 3, 4, 5, 7 }, // 80 - { 1, 1,17,17, 2,-1, 7 }, // 81 - { 0, 1,18,-1,-1, 2,-2 }, // 82 - { 0, 2,18,17, 2, 3,17 }, // 83 - { 0, 1,18,17, 2,18, 2 }, // 84 - { 0, 2,18,17,-1, 2,17 }, // 85 - { 0, 1, 1,18, 3, 2, 5 }, // 86 - { 0, 2,18,-2, 4,18, 2 }, // 87 - { 1, 1,18, 3, 1, 5, 4 }, // 88 - { 0, 1,18,17,18, 2, 5 }, // 89 - { 1, 1,18, 3, 1, 5, 4 }, // 90 - { 0, 4,18,18,-2, 2,18 }, // 91 - { 1, 1,18,18, 3, 2, 5 }, // 92 - { 1, 1,17,17, 2, 1, 4 }, // 93 - { 0, 2,18,18,-2,18, 2 }, // 94 - { 0, 2,18,18,-2,18, 2 }, // 95 - { 1, 1,18,18, 2, 1, 3 }, // 96 - { 1, 1,17,17, 2, 1, 4 }, // 97 - { 1, 2,17,17, 2,18, 3 }, // 98 - { 0, 1,18,17, 1, 4, 6 }, // 99 - { 1, 2,18,18,-2, 2,-1 }, // 100 - { 0, 1,18,-2,18, 2, 5 }, // 101 - { 1, 1,17, 2,18, 2,17 }, // 102 - { 0, 2,18,18,-2,18, 2 }, // 103 - { 0, 1,18,18, 3, 6,-1 }, // 104 - { 0, 1,18,17, 2,18, 3 }, // 105 - { 0, 1,18,17,-2, 2,17 }, // 106 - { 1, 1, 3,17,18, 2,17 }, // 107 - { 1, 3,18,-3,18, 2, 3 }, // 108 - { 1, 3,18,18,-3,18, 2 }, // 109 - { 1, 1,18, 3, 1, 5, 4 }, // 110 - { 0, 1,17,-2,17, 2,-3 }, // 111 - { 1, 1,18,18, 3, 5, 2 }, // 112 - { 1, 2,18,18,-2, 2,-1 }, // 113 - { 0, 1,18,-1,-1, 2,-2 }, // 114 - { 1, 1,18, 3, 1, 5, 4 }, // 115 - { 0, 3,18,17,-1, 2,17 }, // 116 - { 1, 3,18,17, 2,18,-2 }, // 117 - { 0, 2,18,18,-2,18, 2 }, // 118 - { 1, 2,18,18,-2, 2,-1 }, // 119 - { 1, 1,18, 3, 1, 5, 4 }, // 120 - { 0, 4, 3,18,18, 2,17 }, // 121 - { 0, 2,18,18,-2,18, 2 }, // 122 - { 1, 1,18,17,-1,18, 2 }, // 123 - { 0, 2,18,18,-2,18, 2 }, // 124 - { 0, 2,18,18,-2,18, 2 }, // 125 - { 0, 2,18,18,-2,18, 2 }, // 126 - { 0, 2,18,18,-2,18, 2 }, // 127 - { 1, 1,18,18,18, 3, 2 }, // 128 - { 0, 1,17,-1, 2, 3, 6 }, // 129 - { 0, 1,17,-1, 2, 3, 6 }, // 130 - { 0, 2,18,17,-2, 3, 2 }, // 131 - { 1, 3,18,17, 2,-2,18 }, // 132 - { 0, 2,18,18, 2,17, 3 }, // 133 - { 0, 1,18,18, 2,18,-2 }, // 134 - { 0, 2,18,-2, 4,18, 2 }, // 135 - { 0, 1,-2,18, 2, 2,18 }, // 136 - { 0, 2,18,17, 3, 6, 2 }, // 137 - { 0, 1,18,17,18, 2, 5 }, // 138 - { 0, 3,18,18,-2, 3, 2 }, // 139 - { 1, 1,18,18, 2,18, 5 }, // 140 - { 0, 1,17,-1, 2, 3, 6 }, // 141 - { 1, 4,18,18, 2, 3,-2 }, // 142 - { 0, 2,18,17,18, 2,-2 }, // 143 - { 0, 1, 1,18, 3, 2, 5 }, // 144 - { 1, 4,18,-2,18, 2, 3 }, // 145 - { 1, 2,18, 2,18, 3,-2 }, // 146 - { 0, 2,18,18,18, 2, 4 }, // 147 - { 0, 2, 3,17,18, 2,17 }, // 148 - { 1, 1,18,-1,18, 2,17 }, // 149 - { 1, 2,17,17, 2,18, 3 }, // 150 - { 0, 2,18,17,-2, 3, 2 }, // 151 - { 0, 1, 1,-1,-1, 2,17 }, // 152 - { 0, 3, 3,18,18, 2,17 }, // 153 - { 0, 1,18,-1,17,18, 2 }, // 154 - { 0, 1,18,17, 2,18, 3 }, // 155 - { 0, 2,18,18,-2,18, 2 }, // 156 - { 0, 1,18,17, 2,18, 2 }, // 157 - { 0, 2,18,18,-2,18, 2 }, // 158 - { 0, 2,18,18,-2,18, 2 }, // 159 - { 1, 2,17,17, 2,18, 3 }, // 160 - { 0, 1,18,17,-2, 2, 3 }, // 161 - { 0, 1,18,-2,18, 2, 5 }, // 162 - { 1, 4,18,-2,18, 2, 3 }, // 163 - { 1, 3,18,17, 2, 3, 6 }, // 164 - { 0, 2,18,18, 2,17, 3 }, // 165 - { 0, 2,18,17, 2,18, 2 }, // 166 - { 0, 2,18,18,-2,18, 2 }, // 167 - { 1, 1,18,18, 3, 5, 2 }, // 168 - { 0, 2,18,18,-2, 2, 3 }, // 169 - { 1, 2,18,17, 2,17, 3 }, // 170 - { 0, 1,18,17, 2, 3,18 }, // 171 - { 0, 2,18,18,-2,18, 2 }, // 172 - { 1, 4,18,18, 2, 3,-2 }, // 173 - { 0, 1,17,-2,17, 2,-3 }, // 174 - { 0, 1,17,17, 2,18, 4 }, // 175 - { 1, 1,18,18,18, 2, 4 }, // 176 - { 1, 2,18, 2,18, 3,-2 }, // 177 - { 1, 1,18,18,-2, 2,17 }, // 178 - { 0, 2,18,18,-2,18, 2 }, // 179 - { 0, 2,18,18, 2,17, 3 }, // 180 - { 0, 2,18,18,18, 2, 4 }, // 181 - { 0, 2,18,18,-2,18, 2 }, // 182 - { 0, 2,18,17,-2, 3, 2 }, // 183 - { 0, 1, 1,-1,-1, 2,17 }, // 184 - { 1, 4,18,18, 2, 3,-2 }, // 185 - { 0, 2,18,18,-2,18, 2 }, // 186 - { 0, 1,18,-2,18, 3, 2 }, // 187 - { 0, 2,18,18,-2,18, 2 }, // 188 - { 0, 2,18,18,-2,18, 2 }, // 189 - { 0, 2,18,18,-2,18, 2 }, // 190 - { 0, 2,18,18,-2,18, 2 }, // 191 - { 0, 1,18,18,-2, 2,17 }, // 192 - { 0, 3,18,17, 2, 3,17 }, // 193 - { 1, 2,18,18, 2,-2,18 }, // 194 - { 0, 1,-1, 3, 5, 4, 7 }, // 195 - { 1, 1,18, 3, 1, 5, 4 }, // 196 - { 1, 1,18,18,-2,18, 3 }, // 197 - { 0, 2,18,17,18, 2,-2 }, // 198 - { 0, 2,18,18, 2,17, 3 }, // 199 - { 1, 2,18, 2,18, 3,-2 }, // 200 - { 1, 4,18,18, 2, 3,-2 }, // 201 - { 1, 3,18,17, 2, 3, 6 }, // 202 - { 0, 2,18,18,-2,18, 2 }, // 203 - { 1, 2,18,17,-2,-1,17 }, // 204 - { 0, 1,17,-1, 2, 3, 6 }, // 205 - { 0, 2,18,18,-2,18, 2 }, // 206 - { 0, 2,18,18,-2, 2, 3 }, // 207 - { 1, 1,18,18,18, 2, 5 }, // 208 - { 0, 1,17,17,-2, 2, 3 }, // 209 - { 0, 2,18,18,-2,18, 2 }, // 210 - { 0, 2,18,17, 3, 6, 2 }, // 211 - { 0, 2,18,17,18, 2, 3 }, // 212 - { 0, 3,18,17,-3,18, 2 }, // 213 - { 0, 1,18,18,18, 2, 3 }, // 214 - { 0, 1,18,-2,-3, 2, 6 }, // 215 - { 0, 2,18,18,-2,18, 2 }, // 216 - { 1, 1,18,17,18, 2, 5 }, // 217 - { 0, 2,18,18,-2,18, 2 }, // 218 - { 0, 2,18,18,-2,18, 2 }, // 219 - { 1, 1,18,17,18, 2, 5 }, // 220 - { 0, 2,18,18,-2,18, 2 }, // 221 - { 0, 2,18,18,-2,18, 2 }, // 222 - { 0, 2,18,18,-2,18, 2 }, // 223 - { 0, 1,18,18,18, 2, 3 }, // 224 - { 1, 1,17,-2,17, 1, 2 }, // 225 - { 1, 1,17,17, 2,-1, 7 }, // 226 - { 0, 1,18,17, 4, 3, 1 }, // 227 - { 1, 3,18,-3,18, 2, 3 }, // 228 - { 0, 1, 1,18, 3, 2, 5 }, // 229 - { 0, 2,18,18,-2,18, 2 }, // 230 - { 0, 2,18,18,-2,18, 2 }, // 231 - { 0, 1,18,18, 3, 6, 2 }, // 232 - { 0, 1,17,17, 2,18, 4 }, // 233 - { 0, 1,17,17, 2,18, 4 }, // 234 - { 0, 2,18,18,-2,18, 2 }, // 235 - { 0, 2,18,18,-2,18, 2 }, // 236 - { 0, 2,18,18,-2,18, 2 }, // 237 - { 1, 2,18,-2,18, 3, 2 }, // 238 - { 1, 1,17,-2,17, 1, 2 }, // 239 - { 1, 1,18,18, 3, 2, 5 }, // 240 - { 0, 1,18,18,-1, 2, 3 }, // 241 - { 0, 2,18,18,-2,18, 2 }, // 242 - { 0, 2,18,18,-2,18, 2 }, // 243 - { 0, 1,18,17,18, 2, 5 }, // 244 - { 0, 2,18,18,-2,18, 2 }, // 245 - { 0, 2,18,18,-2,18, 2 }, // 246 - { 0, 2,18,18,-2,18, 2 }, // 247 - { 0, 2,18,18,-2,18, 2 }, // 248 - { 0, 1, 3,18,18, 2,17 }, // 249 - { 0, 2,18,18,-2,18, 2 }, // 250 - { 0, 2,18,18,-2,18, 2 }, // 251 - { 0, 2,18,18,-2,18, 2 }, // 252 - { 0, 2,18,18,-2,18, 2 }, // 253 - { 0, 2,18,18,-2,18, 2 }, // 254 - { 0, 2,18,18,-2,18, 2 }, // 255 -}; - -static const WavpackDecorrSpec high_specs [] = { - { 1, 2,18,18,18,-2, 2, 3, 5,-1,17, 4 }, // 0 - { 0, 1,18,17,-2, 2,18, 3, 7, 2, 5, 4 }, // 1 - { 1, 2, 1,18, 3, 6,-2,18, 2, 3, 4, 5 }, // 2 - { 0, 2,18,18,-2, 2,18, 3, 6, 2,17, 4 }, // 3 - { 1, 2,18,18, 2,18, 3, 2,-1, 4,18, 5 }, // 4 - { 1, 1, 7, 6, 5, 3, 4, 2, 5, 4, 3, 7 }, // 5 - { 1, 1,17, 3,18, 7, 2, 6, 1, 4, 3, 5 }, // 6 - { 1, 1,-2,18,18,18, 3,-2, 6, 5, 2, 1 }, // 7 - { 1, 2,18,18,-1,18, 2, 3, 6,-2,17, 5 }, // 8 - { 0, 1,17,17,18, 3, 6, 4, 5, 2,18,-2 }, // 9 - { 1, 2, 1,18,-2, 3, 5, 2, 4,-1, 6, 1 }, // 10 - { 0, 2,18,18, 3, 6,18, 2, 4, 8, 5, 3 }, // 11 - { 0, 1,-2, 1,18, 2,-2, 7,18, 2,-1, 5 }, // 12 - { 1, 1, 4, 3, 8, 1, 5, 2, 5, 6, 2, 8 }, // 13 - { 1, 1,17,18, 2, 6, 3, 4,-1, 1, 8, 6 }, // 14 - { 0, 1,18,18, 3, 6, 3,-2, 2, 5,-1, 1 }, // 15 - { 0, 1,18,18,17,-1, 2,-2,18, 3, 4, 5 }, // 16 - { 1, 2,18,17, 2,-2,18, 3, 5, 7, 2, 4 }, // 17 - { 1, 2,18,18, 3, 6,-2,18, 2, 5, 8, 3 }, // 18 - { 0, 1,18,17, 2,18,18, 2, 6, 5,17, 7 }, // 19 - { 1, 2,18,17, 2,18, 3, 2, 6,18,-1, 4 }, // 20 - { 1, 1, 5, 3, 6, 5, 3, 4, 1, 2, 4, 7 }, // 21 - { 1, 1, 5, 3, 6, 5, 3, 4, 1, 2, 4, 7 }, // 22 - { 0, 1,-2,18,18,18,-2, 3, 2, 4, 6, 5 }, // 23 - { 1, 2,18,17,-3, 3,-1,18, 2, 3, 6, 5 }, // 24 - { 0, 1,17,18, 7, 3,-2, 7, 1, 2, 4, 5 }, // 25 - { 1, 1, 2,18,18,-2, 2, 4,-1,18, 3, 6 }, // 26 - { 0, 3, 1,18, 4, 3, 5, 2, 4,18, 2, 3 }, // 27 - { 0, 1,-2,18, 2,18, 3, 7,18, 2, 6,-2 }, // 28 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 29 - { 1, 1,18,18, 5, 4, 6, 4, 5, 1, 4, 3 }, // 30 - { 1, 1,18, 3, 6, 5, 7, 8, 2, 3, 1,-1 }, // 31 - { 1, 1,18,18,18, 2,-2, 3, 5,18, 2, 8 }, // 32 - { 0, 2,18,17,-2, 2, 3,18,-3, 5, 2, 7 }, // 33 - { 1, 1, 1, 1,-1, 8,17, 3,-2, 2, 6,17 }, // 34 - { 0, 2,18,18,17, 2,-2, 3, 2, 4,18, 5 }, // 35 - { 1, 1,17,18, 2,-1, 5, 7,18, 3, 4, 6 }, // 36 - { 1, 1, 5, 4, 5,17, 3, 6, 3, 4, 7, 2 }, // 37 - { 0, 1,17, 3, 1, 7, 4, 2, 5,-2,18, 6 }, // 38 - { 0, 1,17,18, 2,18, 4, 3, 5, 7,-3, 6 }, // 39 - { 1, 2,17,17,-3,-2, 2, 8,18,-1, 3, 5 }, // 40 - { 0, 1,17,17,18, 2, 3, 6,-2, 8, 1, 7 }, // 41 - { 1, 1, 1, 2, 6,-2,18, 2, 5,-3, 7,-2 }, // 42 - { 0, 1,18,18, 3,18, 6, 8,-2, 2, 3, 5 }, // 43 - { 0, 1,18,17, 2,18,-2, 3, 7, 6, 2, 4 }, // 44 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 45 - { 1, 1,18,18, 2,-1, 3, 6, 1, 3, 4, 8 }, // 46 - { 0, 1,18,18, 3, 6, 5, 3,-2, 2,18,-1 }, // 47 - { 0, 1,18,17,-3,18, 2, 4,-2, 3, 6,17 }, // 48 - { 1, 3, 1, 2,17, 3,18, 7,-1, 5, 2, 4 }, // 49 - { 1, 1,18, 3,18, 6, 8,18,-2, 5, 7, 2 }, // 50 - { 0, 1,17, 2,18, 6, 3, 2, 5, 4, 8, 1 }, // 51 - { 0, 1,18,17,-1, 2, 3,18,18, 2, 3,17 }, // 52 - { 1, 1,18, 7, 6, 5, 5, 3, 1, 4, 2, 4 }, // 53 - { 1, 1, 6,17, 3, 8, 1, 5, 7,-1, 2, 1 }, // 54 - { 1, 1,18,-2,18, 3,-2, 2, 7, 4, 6,18 }, // 55 - { 1, 3,18,-3,18, 2, 3,18,-1, 7, 2, 5 }, // 56 - { 0, 2,18,-2, 7, 1, 3, 2, 4, 6,-3, 7 }, // 57 - { 1, 1,18,-2, 2,-3,18,-2,17,-1, 4, 2 }, // 58 - { 0, 3,17,17, 2, 5, 3, 7,18, 6, 4, 2 }, // 59 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 60 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 61 - { 1, 1,18,17, 4, 6, 6, 4, 5, 3, 4, 1 }, // 62 - { 0, 1,18, 5, 3, 6, 2, 3, 8, 1, 3, 7 }, // 63 - { 1, 2,18,17,-2, 2,18, 3, 5, 7,-1, 2 }, // 64 - { 0, 1, 1,18,18, 3, 6,-1, 4, 8, 5, 2 }, // 65 - { 1, 1, 1, 5, 3, 4, 1, 1, 3, 5, 7, 3 }, // 66 - { 0, 1, 3,18,18, 2,18,18,-1, 2, 3,18 }, // 67 - { 1, 2,18,18,-1,18, 2, 3, 4, 6,18, 5 }, // 68 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 69 - { 1, 1,18, 3, 1, 4, 5, 2, 7, 1, 3, 6 }, // 70 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 71 - { 1, 2,18,18,-1,18, 2, 3, 5,-2, 6, 8 }, // 72 - { 1, 1,17,18, 4, 8, 3, 2, 5, 2, 7, 6 }, // 73 - { 1, 4, 1, 2, 5,18,-2, 2, 3, 7,-1, 4 }, // 74 - { 0, 2,18,17,-1, 3, 6,18, 2, 3, 7, 5 }, // 75 - { 0, 1,-2,18, 2,-3, 6,18, 4, 3,-2, 5 }, // 76 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 77 - { 0, 1,17,17, 6, 2, 4, 8, 3, 5,-1,17 }, // 78 - { 1, 1,18, 3,18, 6, 8,18,-2, 5, 7, 2 }, // 79 - { 1, 2,17,17,-3, 2,18,-2, 8, 3, 6,-1 }, // 80 - { 1, 1,18,-2,17,18, 2, 3,-2, 6, 5, 4 }, // 81 - { 1, 2,18,17,-1, 3,18, 2, 5, 3, 6,-3 }, // 82 - { 0, 1,18,17, 2,18, 7,18, 2, 4, 3,17 }, // 83 - { 1, 3,18,18, 5, 6, 4, 3, 4,18, 6, 5 }, // 84 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 85 - { 1, 1, 7, 6, 5, 3, 4, 2, 5, 4, 3, 7 }, // 86 - { 0, 1,-2,18,18,18, 3, 6, 4, 2, 5, 2 }, // 87 - { 0, 3,18,17,-3,18, 3, 2, 5,-1,17, 3 }, // 88 - { 1, 1,17,18, 7, 3, 1, 7, 4, 2, 6, 5 }, // 89 - { 1, 1,18, 2,-2,-1,18, 5, 3,-2, 1, 2 }, // 90 - { 0, 3,18,18,-1, 3, 2, 7, 5,18, 4, 3 }, // 91 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 92 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 93 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 94 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 95 - { 1, 1,17,18, 2,-2, 4, 8,18, 3, 6, 5 }, // 96 - { 0, 2,18,17, 3, 5,-2, 7, 2,18, 3,-1 }, // 97 - { 1, 1,18, 2,-2,-1,18, 5, 3,-2, 1, 2 }, // 98 - { 0, 2, 3,17,18,18, 2, 5, 7, 6,18, 3 }, // 99 - { 1, 1,17,18,18, 4, 3, 2,18, 7, 8,-1 }, // 100 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 101 - { 0, 1,17, 1, 2, 3, 5, 6, 1, 4, 8,17 }, // 102 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 103 - { 0, 2,18,17,-1,18,-3, 2, 8, 3, 6,17 }, // 104 - { 1, 1,17,17, 1, 2, 4, 5,-1, 2, 1, 6 }, // 105 - { 1, 1, 1, 2, 6,-2,18, 2,-3, 3,-2, 5 }, // 106 - { 0, 1,18, 3,18, 6,18, 5, 2, 4,-1, 8 }, // 107 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 108 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 109 - { 1, 1,18,18,-1, 2,18, 3, 6, 4,-2, 7 }, // 110 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 111 - { 0, 2,-1,18,18,18, 2,-2, 4, 7, 2, 3 }, // 112 - { 0, 3, 3,17,-2, 5, 2, 7,18, 6, 4, 5 }, // 113 - { 0, 1,17, 6,18, 3, 8, 4, 5, 3, 8,18 }, // 114 - { 0, 2,18, 2, 6, 2,18, 3, 2, 4, 5, 8 }, // 115 - { 0, 1, 3,18,18, 2,18,-1, 2,18, 2,17 }, // 116 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 117 - { 0, 1, 3, 6,17,-2, 5, 1, 2, 7, 4, 8 }, // 118 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 119 - { 1, 3, 3,18,17, 5, 6, 2, 7,-2, 8,18 }, // 120 - { 1, 1,18,-1, 3, 1, 7, 2,-1, 4, 6,17 }, // 121 - { 1, 1,18, 2,-2,-1,18, 5, 3,-2, 1, 2 }, // 122 - { 0, 2,18, 1, 2,18, 3, 6, 5, 2, 4, 8 }, // 123 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 124 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 125 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 126 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 127 - { 1, 1,17,-2, 2,18,18, 8, 5, 3, 2, 6 }, // 128 - { 0, 1,18,17, 2,18, 3, 2, 7,-2,18, 4 }, // 129 - { 1, 2, 1,18, 2, 3,-1, 5, 6, 4, 7,17 }, // 130 - { 0, 2,18,17, 3, 6,-2, 2, 3, 8, 5,17 }, // 131 - { 0, 2,18,18, 3, 2,18,-1, 2, 4, 3,17 }, // 132 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 133 - { 1, 2,17,-1,18, 2, 3,-2, 5,18, 2, 7 }, // 134 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 135 - { 1, 2,18,-3,18, 2, 3,-2,18, 5, 6,-3 }, // 136 - { 0, 2,18,17, 3, 5,-2, 7, 2,18, 3,-1 }, // 137 - { 1, 1, 1,18,-1, 2, 3, 1,-2, 8, 2, 5 }, // 138 - { 0, 1,18,18, 3, 6,18, 2, 3, 4, 8, 5 }, // 139 - { 0, 1,-2, 1,18, 2,-2, 5, 7,18, 2,-1 }, // 140 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 141 - { 1, 1,17,18,-1, 2, 8, 3, 4, 5, 1, 7 }, // 142 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 143 - { 0, 2,18,18,-1, 2,18, 3,-2, 5, 4, 2 }, // 144 - { 1, 1,18,17, 2,18, 3, 8, 5, 2, 7,17 }, // 145 - { 0, 1,18,18, 3,18, 6, 8,-2, 2, 3, 5 }, // 146 - { 0, 1,18,18, 2,18, 2, 6,18, 2,17, 7 }, // 147 - { 1, 3,18,17,18, 2, 8,18, 5,-1, 3, 6 }, // 148 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 149 - { 1, 1,18, 7, 6, 5, 5, 3, 1, 4, 2, 4 }, // 150 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 151 - { 1, 2,18,17,-1, 3, 6,18, 2, 5, 8, 3 }, // 152 - { 0, 1,17,18,18, 4, 7, 2, 3,-2,18, 5 }, // 153 - { 1, 2,18, 1, 2, 6, 2, 5,18, 2, 4, 8 }, // 154 - { 0, 4,18, 4, 1, 2, 3, 5, 4, 1, 2, 6 }, // 155 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 156 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 157 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 158 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 159 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 160 - { 0, 2,18,17, 2,-1,18, 3,-3, 5, 2, 4 }, // 161 - { 0, 1,17,17, 3, 6, 3, 5,-2, 2,18,-1 }, // 162 - { 0, 2,18,18, 3,-2,18, 2,-3, 5, 3, 6 }, // 163 - { 1, 1,17,17, 2, 4, 1, 3, 5, 2, 6,-3 }, // 164 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 165 - { 0, 1,17, 1, 3, 2, 7, 1, 6, 3, 4, 8 }, // 166 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 167 - { 0, 1,17,-1,18, 2, 1, 5, 3, 8,-1,-2 }, // 168 - { 1, 1,17,18,-1, 8, 2, 5, 3, 4, 1, 6 }, // 169 - { 1, 2, 1,18, 3,-1, 5, 1, 2, 4, 7, 6 }, // 170 - { 0, 1,18,18, 3, 6, 5, 3,-2, 2,18,-1 }, // 171 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 172 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 173 - { 0, 1, 1,18,-1, 3, 8, 5, 6, 1, 2, 3 }, // 174 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 175 - { 0, 2,18,18, 2, 3, 6,18,-1, 4, 2, 3 }, // 176 - { 1, 1, 1, 3, 5,18, 2, 6, 7, 2, 3, 1 }, // 177 - { 1, 1, 1, 3, 8,18, 5, 2, 7, 1, 3,-2 }, // 178 - { 0, 2,17, 2,18, 3, 6, 2, 4, 5, 8, 3 }, // 179 - { 0, 1,18,17, 2,18, 3, 2, 7,-2,18, 4 }, // 180 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 181 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 182 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 183 - { 1, 2,18,-3,18,-1, 3,-2, 5, 7, 1, 2 }, // 184 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 185 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 186 - { 0, 3,18,18, 2, 6,18, 5,18, 2, 3,17 }, // 187 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 188 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 189 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 190 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 191 - { 1, 3, 1,-1, 1, 3,-2, 2, 5, 7,-3,18 }, // 192 - { 1, 2,18, 7, 3,-3, 2, 8, 2, 5, 4,17 }, // 193 - { 1, 1, 1, 4, 5, 1, 3, 4, 6, 7, 8, 3 }, // 194 - { 0, 1,18,17, 2,18,-1, 2, 3,18, 2, 4 }, // 195 - { 0, 2,18,18,-2,18, 2, 3, 4, 7, 5,17 }, // 196 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 197 - { 1, 1,17,18, 2, 1, 3, 2, 5, 1, 2, 3 }, // 198 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 199 - { 0, 2,18,18,-1, 2, 3, 5, 8, 6, 1,-2 }, // 200 - { 0, 1,17,18, 8, 3, 4, 6, 5, 2, 8, 7 }, // 201 - { 1, 2, 1, 3,-2,18, 2, 5, 1, 7,-1,-2 }, // 202 - { 0, 3,18,17,-1, 3,18, 2, 3, 6, 4,17 }, // 203 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 204 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 205 - { 1, 2,18,18, 4,18, 6, 7, 8, 3,18, 2 }, // 206 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 207 - { 0, 2,17,-3,17, 2,-2, 8, 3,18, 4,-3 }, // 208 - { 1, 1,18,17, 3, 5, 6, 2, 8, 1, 3, 7 }, // 209 - { 0, 1,18,18, 3, 6, 5, 3,-2, 2,18,-1 }, // 210 - { 0, 3,18,18, 2, 6,18, 5,18, 2, 3,17 }, // 211 - { 1, 1,18,18, 5, 4, 6, 4, 5, 1, 4, 3 }, // 212 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 213 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 214 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 215 - { 0, 2, 3,17,18,-3, 2, 5,18, 6,-1, 7 }, // 216 - { 1, 1,17,18, 3, 2, 5,-1, 6, 8, 4, 7 }, // 217 - { 1, 1,18, 1,-2, 3, 2, 1, 7, 6, 3, 4 }, // 218 - { 0, 3, 1, 2,17, 3,18, 2, 7, 5, 4,-1 }, // 219 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 220 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 221 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 222 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 223 - { 1, 1,17,-2, 2,18,18, 8, 5, 3, 2, 6 }, // 224 - { 0, 2,18, 5,18, 2, 3, 7,-2, 1, 6, 8 }, // 225 - { 0, 1, 2,-1,18,-1, 2, 4,-3, 5,18, 3 }, // 226 - { 0, 1, 3,17,18, 5, 2,18, 7, 3, 6, 5 }, // 227 - { 1, 4, 1, 2, 5,18,-2, 2, 3, 7,-1, 4 }, // 228 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 229 - { 0, 1, 1,18, 2, 1, 3, 4, 1, 5, 2, 7 }, // 230 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 231 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 232 - { 0, 1,17,17,18, 2, 4, 5,18,-2, 6, 3 }, // 233 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 234 - { 0, 2,18,18,-1, 3, 5, 6, 8,18, 2, 3 }, // 235 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 236 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 237 - { 0, 1,18,18, 4, 6, 8,18, 7, 3, 2, 5 }, // 238 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 239 - { 0, 2,-1,18,18,18, 2, 4,-2, 2, 3, 6 }, // 240 - { 0, 2,18,-2, 7, 1, 3, 2, 4, 6,-3, 7 }, // 241 - { 1, 1,17,18, 8, 3, 4, 6,-2, 5, 3, 8 }, // 242 - { 0, 2,18, 1, 2, 6, 2, 8, 3,18, 5, 4 }, // 243 - { 1, 1, 3,18,18, 2,18, 2,18, 3, 2,18 }, // 244 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 245 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 246 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 247 - { 1, 1, 3,17,18, 5, 2, 6, 7, 1, 4, 8 }, // 248 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 249 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 250 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 251 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 252 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 253 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 254 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 255 -}; - -static const WavpackDecorrSpec very_high_specs [] = { - { 1, 2,18,18, 2, 3,-2,18, 2, 4, 7, 5, 3, 6, 8,-1,18, 2 }, // 0 - { 0, 1,18,18,-1,18, 2, 3, 4, 6, 5, 7,18,-3, 8, 2,-1, 3 }, // 1 - { 1, 2, 1,18,-2, 4,18, 2, 3, 6,-1, 7, 5,-2,18, 8, 2, 4 }, // 2 - { 0, 1,17,17, 2, 3, 4,18,-1, 5, 6, 7,18, 2, 8,17, 3,-2 }, // 3 - { 1, 1,18,18, 2,18, 3, 2,18, 4,-1, 3,18, 2, 6, 8,17, 5 }, // 4 - { 0, 2,18,17, 2, 3,-2, 5,18,-3, 2, 4, 7, 3, 6, 8, 5,17 }, // 5 - { 1, 1,18,-2, 2,-3,18, 5,-2,18, 2, 3, 6, 2,17, 4, 7,-1 }, // 6 - { 1, 1,17, 8,18, 3,-2, 2, 5, 4,18, 6, 3, 8, 7, 2, 5, 4 }, // 7 - { 0, 2,18,17,-2, 2,18, 3, 2, 5,-3, 4, 7,18, 3, 8, 6, 2 }, // 8 - { 1, 1, 3, 6, 5, 5, 1, 3, 7, 4, 2, 6, 4,18, 3, 7, 5, 6 }, // 9 - { 1, 2, 1,18, 3, 2,-2, 1, 5, 4, 6, 2, 7, 1, 8, 3,-1, 1 }, // 10 - { 0, 1,18,18, 2, 3, 6, 3, 5,-2, 2, 4,18, 3,-2,-1, 6, 7 }, // 11 - { 0, 1,-2,18, 2,18, 7, 2, 6,-2, 3, 4,18,18, 2,-3, 8, 5 }, // 12 - { 0, 2,18,18,18, 2, 4, 3,18, 5, 3, 6,-2, 2, 4,18, 8, 7 }, // 13 - { 0, 1,-2, 1,18, 2,-2,18,-1, 5, 7, 2, 3, 4,18, 2, 6, 2 }, // 14 - { 1, 1,17,18, 3, 2, 1, 7,-1, 2, 4, 3, 5, 6,-2,18, 7, 8 }, // 15 - { 1, 1,18,18, 2,18, 3, 4, 6,-2,18, 5, 8, 2, 3, 7, 4,-1 }, // 16 - { 0, 1,18,18,18,-1, 2, 3, 4, 6, 8,18, 3, 5, 2, 6, 7, 4 }, // 17 - { 1, 1,17,-2,18,18, 2, 5, 3, 8, 2,-1, 6, 1, 3, 4, 7, 5 }, // 18 - { 0, 1,17,17,18, 2, 3, 6,-2, 8, 1, 7, 5, 2, 3, 1, 4, 8 }, // 19 - { 1, 1,17,17, 3, 2, 7, 1, 4, 3, 6, 2, 5,-2, 8, 7,18, 6 }, // 20 - { 0, 1,18,17,-2, 2,18, 3,-3, 7, 6, 5, 2, 4,-1, 8, 3,17 }, // 21 - { 1, 1, 2,18,18,-2, 2, 4,-1, 5,18, 3, 8, 6, 2, 7,17, 4 }, // 22 - { 0, 1,17, 3, 6, 8, 5, 4, 3, 8, 1,18, 7, 2, 4, 5, 6, 3 }, // 23 - { 1, 2,17,18, 4, 8, 3, 2, 5, 7, 6, 8, 2, 7,-2,18, 3, 4 }, // 24 - { 1, 1, 6, 5, 5, 3, 4, 7, 3, 2, 4, 6, 3, 7, 1, 5, 2, 4 }, // 25 - { 1, 1, 1,18,-1, 2, 1, 3, 8,-2, 2, 5, 6, 3, 8, 7,18, 4 }, // 26 - { 0, 1, 1,17,-1,18, 3, 2, 5, 4, 6, 7, 8, 3, 4, 2, 1,-2 }, // 27 - { 0, 1,18, 2,18,18, 2,18, 6,-2,18, 7, 5, 4, 3, 2,18,-2 }, // 28 - { 0, 3, 1, 4,18, 3, 2, 4, 1, 5, 2, 3, 6,18, 8, 7, 2, 4 }, // 29 - { 0, 1,17,-2, 1,-3, 2,18, 3,-2, 4,18, 3, 6, 7,-3, 2, 8 }, // 30 - { 1, 1,17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 }, // 31 - { 1, 2,18,-1,17,18, 2, 3,-2,18, 5, 8, 2, 4, 3, 7, 6,-1 }, // 32 - { 1, 1,18,18,18,-2, 4, 2, 3,18, 5, 8, 2, 4, 6, 7,-2, 3 }, // 33 - { 1, 2,18,18,-2,18,-1, 3, 2, 5,18,-2, 7, 2, 3, 4, 6, 8 }, // 34 - { 0, 1,17,18,-1, 2, 4,18, 8, 3, 6, 5, 7,-3, 2, 4, 3,17 }, // 35 - { 1, 1,18,18,17, 2,-1,18, 3, 2,18, 6, 5, 4,18, 7, 2,-1 }, // 36 - { 0, 2, 1,18,-1,18, 3, 2, 4, 6,-3, 7,-1, 5, 1, 2, 3, 8 }, // 37 - { 1, 1, 1,17,-2, 2,-3, 6, 3, 5, 1, 2, 7, 6, 8,-2, 4, 1 }, // 38 - { 0, 1,17,-1, 5, 1, 4, 3, 6, 2,-2,18, 3, 2, 4, 5, 8,-1 }, // 39 - { 0, 2,18,18,17, 2, 3,-2, 5,18, 2, 4, 7, 8, 6,17, 3, 5 }, // 40 - { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 41 - { 1, 2, 1,-1, 3, 2,18, 7,-2, 5, 2, 6, 4, 3,-1,18, 8, 7 }, // 42 - { 0, 2,18,17, 3,18, 2, 5, 4, 3, 6, 2, 7, 8,18, 3, 4, 5 }, // 43 - { 1, 1, 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 }, // 44 - { 0, 2,18,18, 3,-3,18, 2, 6, 5, 3, 7,18, 4,-2, 8, 2, 3 }, // 45 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 46 - { 1, 1,17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 }, // 47 - { 1, 1, 3, 6, 5, 5, 1, 3, 7, 4, 2, 6, 4,18, 3, 7, 5, 6 }, // 48 - { 0, 1,18,18,18, 2, 4,-1,18, 8,-1, 2, 3, 4, 6,-2, 1, 7 }, // 49 - { 1, 1,18,-2,17,18, 2, 6, 3,-2, 5, 4, 7, 1,-3, 8, 2, 6 }, // 50 - { 0, 1,17,18,18, 4, 2, 7, 3, 6,-2,18, 8, 4, 5, 2, 7,17 }, // 51 - { 1, 1,18,18, 5, 4, 6, 4, 1, 5, 4, 3, 2, 5, 6, 1, 4, 5 }, // 52 - { 0, 1,18,18,-2,18, 2,-3, 3, 8, 5,18, 6, 4, 3,-1, 7, 2 }, // 53 - { 1, 1,18, 2,-2,-3,18, 5, 2, 3,-2, 4, 6, 1,-3, 2, 7, 8 }, // 54 - { 0, 1,18, 3, 5, 8, 2, 6, 7, 3, 1, 5, 2,-1, 8, 6, 7, 4 }, // 55 - { 1, 1, 4, 3, 8, 1, 5, 6, 2, 5, 8,-2, 2, 7, 3,18, 5, 4 }, // 56 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 57 - { 1, 1,17, 3,18,18, 7, 2, 4,18, 6, 2, 3,-1, 8, 5,18,-3 }, // 58 - { 0, 1, 3,17,18, 2,18, 6, 7,-3,18, 2, 5, 6, 3, 8, 7,-1 }, // 59 - { 1, 1,18,18, 2,18,18, 2,-1, 7, 3,18, 5, 2, 6, 4,-1,18 }, // 60 - { 0, 3,18, 3, 4, 1, 5, 2,18, 4, 2, 3,18, 7, 6, 1, 2, 4 }, // 61 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 62 - { 1, 1,17, 1,18, 2, 3, 6, 4, 5, 7,18, 3, 8, 2, 4,-2,17 }, // 63 - { 1, 2,18,17, 2, 3, 5,18, 6,-2, 7, 3, 2, 4,18, 8,-1, 5 }, // 64 - { 0, 2, 1,18,-1,18, 3, 2, 4, 6,-3, 7,-1, 5, 1, 2, 3, 8 }, // 65 - { 1, 1, 1,18,-1, 8, 2, 6, 3,-2, 1, 2, 5, 4,-3, 8, 6, 3 }, // 66 - { 0, 1,18,18, 2,18, 2,18, 7, 6,18, 2,-2, 3, 5, 4,18, 8 }, // 67 - { 1, 2,18,17, 2, 3,18,-1, 2, 3, 6,18, 5, 4, 3, 7, 2, 8 }, // 68 - { 1, 2,18,18, 3,-2, 4,18, 5, 7, 6, 2, 4,-3, 8, 5,18, 3 }, // 69 - { 1, 1,17,-2,18,18, 2, 5, 3, 8, 2,-1, 6, 1, 3, 4, 7, 5 }, // 70 - { 1, 1, 3,17,18, 5, 7, 2, 4, 6, 1, 8,-1, 3, 7, 4, 1, 2 }, // 71 - { 0, 2, 1,-2, 2,18, 3, 5, 2, 4, 7,-1, 2, 3, 5,18,-2, 4 }, // 72 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 73 - { 1, 1, 1, 2,-2, 6,18,-3, 2, 7, 3,-2, 5, 6, 1, 8, 2, 4 }, // 74 - { 0, 1,18,18,18, 3,-2, 6,18, 2, 4, 3, 5, 8, 7, 6, 2,-2 }, // 75 - { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 76 - { 0, 1, 3,17,18, 2, 5,18, 6, 7, 5,-2, 2, 4,18, 3, 6, 8 }, // 77 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 78 - { 0, 2,17,-1,18, 2, 4,-1, 8, 3,18, 7,-3, 4, 5, 1, 2,-2 }, // 79 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 8, 6, 4, 5, 7,-1 }, // 80 - { 1, 1,18,18, 3, 6, 4, 8,-2, 2, 5, 3, 7,18, 6, 8, 4, 2 }, // 81 - { 1, 1,17,18,18,-2, 5, 2, 3, 1, 4,-1, 8, 6, 5, 3, 2,18 }, // 82 - { 1, 1,17,17, 1, 2, 4, 5, 2, 6,-1, 3, 1, 1,-2, 4, 2, 7 }, // 83 - { 1, 1,17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 }, // 84 - { 0, 1,18,17,-2,-3, 1, 2, 3, 2, 5, 4, 7,-3, 6,-2, 2, 1 }, // 85 - { 1, 1, 1, 3, 5,18, 1, 2, 7, 3, 6, 2, 5, 8,-1, 1, 4, 7 }, // 86 - { 1, 1,17, 3, 6, 8, 1, 4, 5, 3,-2, 7, 2, 8, 5, 6,18, 3 }, // 87 - { 1, 1,17,18, 2, 4, 8,-2, 3, 1, 5, 6, 7, 1, 2, 3, 4, 7 }, // 88 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 89 - { 1, 1, 3, 1, 8,18, 5, 2, 3,18, 6, 7,-2, 4, 3, 2, 8,18 }, // 90 - { 0, 1,18,17, 2,18, 3, 4,-1,18, 7, 6, 2, 8, 4,18,18, 5 }, // 91 - { 0, 1,18,18, 2,18,18, 2, 7,-2, 6, 5, 4, 3,18, 3, 2,17 }, // 92 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 93 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 94 - { 1, 1,17, 8,18, 3, 2, 1, 5, 4, 6,-1, 3,-3, 8,18, 7, 2 }, // 95 - { 1, 2,18,17,18, 2, 3, 5,-2,18, 6,-1, 2, 3, 7, 4, 8,17 }, // 96 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 8, 6, 4, 5, 7,-1 }, // 97 - { 1, 2,18,18,-2,17, 2,18, 3, 4,18, 8, 7,-1, 2, 4, 5,17 }, // 98 - { 0, 2,17,-3,17, 3, 2,-2,18, 8, 4,-3, 2,18, 5, 3,-2, 6 }, // 99 - { 0, 1,18,18, 2,18,18, 2, 7,-2, 6, 5, 4, 3,18, 3, 2,17 }, // 100 - { 0, 2, 1,18,-1, 3, 5, 2,-3,18, 7, 3,-1, 6, 4, 2,17, 5 }, // 101 - { 1, 1,17,-2,17, 2,-3, 1, 5,-1, 4, 6, 3, 2, 8, 7,-2, 5 }, // 102 - { 1, 1, 1,18, 1, 3, 5, 8, 6, 2, 3,-1, 7, 1, 4, 8, 5,-3 }, // 103 - { 0, 2, 3,18,18, 2,18,-2, 6, 5, 7, 2, 4,18, 3, 6,-3, 5 }, // 104 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 105 - { 1, 1, 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 }, // 106 - { 0, 4,18, 2,17, 3,18,-2, 2, 6,18, 2, 7, 3, 5, 4, 8,18 }, // 107 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 108 - { 0, 1,18,18, 2, 3, 6, 3, 5,-2, 2, 4,18, 3,-2,-1, 6, 7 }, // 109 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 110 - { 1, 1,17, 1, 2, 5, 3,-2, 1, 4, 3, 7, 6,-3, 2, 1, 1, 2 }, // 111 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 112 - { 1, 1,18,18,-2,18,-2, 2, 3, 6,18, 4,-1, 2, 3, 8, 1, 4 }, // 113 - { 1, 1,17,-2,17, 2,-3, 1, 5,-1, 4, 6, 3, 2, 8, 7,-2, 5 }, // 114 - { 0, 1,17,17,18, 3, 2,18,18, 6, 8, 2,-2, 3, 5, 4,17,18 }, // 115 - { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 116 - { 1, 1, 1, 3,-3,18,18, 6, 5,18, 2,-1, 3, 8, 7,-3, 4,17 }, // 117 - { 1, 1,18, 1, 2, 1, 3, 8, 7, 4, 1, 5, 2,-1,-3,18, 6, 2 }, // 118 - { 0, 1,18, 3, 5, 2, 6, 8,18, 5, 7, 2, 3,-1, 6, 7, 8, 5 }, // 119 - { 0, 2,18, 3,-2, 7, 8, 2, 5, 4,-3, 8, 3, 2,18, 5, 4, 6 }, // 120 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 121 - { 1, 3, 1, 1, 2, 5, 2, 7, 4, 3,-1,18,-2, 8, 2, 1, 6, 7 }, // 122 - { 0, 1, 3,17,18, 5, 2, 6, 7,18, 4, 5, 3, 6,18, 2, 7, 8 }, // 123 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 124 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 125 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 126 - { 0, 1, 1,18, 1, 2, 3, 5, 1, 2, 6, 7, 4, 3, 8, 1,17, 5 }, // 127 - { 1, 2,17,-1,18,-2, 2, 3, 5,18, 2, 4, 6, 7, 3,-1, 5, 8 }, // 128 - { 1, 1,18,18,-3,18,-2, 2, 3,-2,18, 6, 4, 5, 8, 3,17,-3 }, // 129 - { 1, 1,18, 7, 6, 5, 5, 3, 1, 4, 2, 7, 3, 4,-3, 6,18, 8 }, // 130 - { 0, 2,18,18, 2, 3, 5,18, 2, 4, 3, 6,18, 7, 8,-1, 5, 2 }, // 131 - { 0, 1,18,17,-1, 2,18, 3, 2,18, 4, 3,18, 2, 6, 5, 8,17 }, // 132 - { 0, 2,18,17, 2, 3,18, 5,-1, 6, 7, 8, 2, 3, 4, 5,18, 6 }, // 133 - { 1, 2,18,-3,18, 2, 3,-2,-3, 5,18, 7, 6, 2, 4, 3, 8,-2 }, // 134 - { 1, 1,17,18,18,-2, 2, 3, 5, 4, 8,18,-1, 5, 3, 6,-2, 7 }, // 135 - { 1, 2,18,17, 2,-2,18, 3,-1, 4,18, 2, 7, 5, 3, 8, 6, 4 }, // 136 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 137 - { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 138 - { 0, 2,18,18, 3, 3,-2, 2, 5,18, 6, 3,-1, 4, 7,-1, 1, 2 }, // 139 - { 0, 1,-2, 1,18, 2,-2, 5, 7,18, 3, 2, 6, 2,-1, 4,-2,17 }, // 140 - { 0, 2,18,18,18, 2, 3,-2,18, 5, 4, 2, 6, 8, 3,-2, 4,18 }, // 141 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 142 - { 1, 1,17,18,-1, 3, 2, 5, 1, 3, 2, 8, 4, 7, 6, 2,-1, 5 }, // 143 - { 1, 1,17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 }, // 144 - { 0, 1,18,18,-2,18, 2, 3, 4, 5, 6,18, 8, 2, 3, 7,-2, 4 }, // 145 - { 0, 1,18,-2,18,18,-3,-2, 2, 3, 5, 8, 1, 2, 6, 4, 7,-1 }, // 146 - { 0, 1,18,17, 2,18, 3,-2, 2, 7, 6, 4,18, 3, 8, 7, 4, 2 }, // 147 - { 1, 1,17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 }, // 148 - { 1, 1,18,17,18, 2, 5, 3,-2,18, 6, 2, 3, 4, 8, 7, 5,-1 }, // 149 - { 0, 1, 2,-1,18,-1, 2, 4,-3,18, 5, 3, 6,18, 2, 4, 7, 8 }, // 150 - { 1, 1,17,18, 8, 3, 6, 4,-1, 5, 2, 7, 3, 8, 6, 5,18, 4 }, // 151 - { 0, 2,18, 3,-2, 7, 8, 2, 5, 4,-3, 8, 3, 2,18, 5, 4, 6 }, // 152 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 153 - { 1, 1, 1,18,-1, 8, 2, 6, 3,-2, 1, 2, 5, 4,-3, 8, 6, 3 }, // 154 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 155 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 156 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 157 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 158 - { 0, 1,17,18,18, 4, 2, 7, 3, 6,-2,18, 8, 4, 5, 2, 7,17 }, // 159 - { 1, 2,18,-1,18, 3,-2,18, 2, 5, 3, 6, 7, 2,-1,18, 8, 4 }, // 160 - { 1, 2, 1,18,-2, 4,18, 2, 3, 6,-1, 7, 5,-2,18, 8, 2, 4 }, // 161 - { 1, 2, 1,18,-3, 2, 3,18,-1, 5, 6, 2, 8, 3, 4, 1,-2, 7 }, // 162 - { 0, 1, 1,17,-1,18, 3, 2, 5, 4, 6, 7, 8, 3, 4, 2, 1,-2 }, // 163 - { 1, 1,18,17,18, 4, 3, 5, 1, 2, 6, 3, 4, 7, 1, 8, 5, 2 }, // 164 - { 0, 1,18,-2, 7, 1, 3, 2,-3, 4, 6,-2, 7, 8, 1, 5, 4, 3 }, // 165 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 166 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 167 - { 0, 2,18,18,18,-2, 2, 5, 3, 7,18, 2, 4,-3, 5, 6, 3, 8 }, // 168 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 169 - { 0, 3, 3,18,-1, 5, 2, 7,18, 6, 5, 2, 4, 3,-1, 7,18, 6 }, // 170 - { 0, 2,18,18,18, 4, 3, 2, 6, 4, 8,18, 5, 3, 2, 7,-2, 6 }, // 171 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 172 - { 0, 2,18,18,18, 2, 3,-2,18, 5, 4, 2, 6, 8, 3,-2, 4,18 }, // 173 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 174 - { 1, 1,17, 8,18, 3, 2, 1, 5, 4, 6,-1, 3,-3, 8,18, 7, 2 }, // 175 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 176 - { 0, 1,-1,18,18,18, 2, 4, 6,-2, 2, 8, 3, 4,18, 7,-1, 6 }, // 177 - { 0, 1,18, 1,-2, 2, 4, 1, 3,-1, 2, 5, 7, 1, 6, 8,-2,17 }, // 178 - { 0, 1,17,17,18, 2, 5, 4,18, 3, 8, 7, 4, 6, 8, 1, 5, 2 }, // 179 - { 1, 2,18,18, 5, 4, 6, 3, 4,18, 8, 4,-1, 7, 5, 3, 6, 2 }, // 180 - { 0, 1,18,18,-3,18, 3, 6, 2, 5, 7,18, 3, 8,-1, 4, 5, 2 }, // 181 - { 1, 1,18, 2,-2,-3,18, 5, 2,-2, 4, 3, 6,18, 8,-1, 2, 7 }, // 182 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 183 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 184 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 185 - { 1, 1,17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 }, // 186 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 187 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 188 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 189 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 190 - { 0, 1,17,18, 3,18, 2, 5, 4, 7,-3, 6, 3, 2,18, 4, 7, 3 }, // 191 - { 1, 1, 1, 7, 4, 5, 3, 4, 5, 1, 3, 6, 3, 2, 4, 8,-2, 7 }, // 192 - { 0, 1, 1,18,-1,-2,18, 3, 2,-1, 6, 7, 4, 5, 3,18, 2,-3 }, // 193 - { 1, 1,18,18,-1, 3, 6,18, 5, 4, 8, 2, 3, 6,18, 7, 4,-2 }, // 194 - { 0, 2,18,18, 2, 6,18, 2,18, 5, 3,18, 2, 4, 7, 8, 3,18 }, // 195 - { 1, 1, 3,18,18, 5,18, 6, 2, 4, 7,-2,18, 5, 8, 6, 3, 2 }, // 196 - { 0, 1,18,-2, 7, 1, 3, 2,-3, 4, 6,-2, 7, 8, 1, 5, 4, 3 }, // 197 - { 1, 1,18,-2,18, 2, 5,18, 3,-2, 4, 7, 2,-1, 8, 6, 5, 1 }, // 198 - { 1, 1,17,17, 5,18, 4, 1, 2, 8, 6, 4,-2, 3, 5,-1, 1, 8 }, // 199 - { 0, 2, 1, 2,17, 3, 7,18, 2,-1, 4, 5,18, 2, 7, 3, 6, 8 }, // 200 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 201 - { 1, 1, 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 }, // 202 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 203 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 204 - { 0, 2,18,18,18, 2,-2, 3, 6, 4, 8,18, 2, 5, 7, 4, 3, 6 }, // 205 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 206 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 207 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 208 - { 1, 1,18, 1, 8, 3, 5, 6, 4,-1, 8, 3, 7,18, 2, 5, 8, 4 }, // 209 - { 1, 1,17,18, 5, 2, 4, 3, 1, 6,-2, 1, 3, 2, 4, 5,-1,17 }, // 210 - { 1, 1,18,17, 2,18, 3,-3, 7, 2, 6, 4, 3, 5,18, 8, 2,-2 }, // 211 - { 1, 1,18,17,18, 4, 3, 5,-1,18, 2, 7, 8, 4, 6, 3,18, 5 }, // 212 - { 0, 1,18,17,18,-2, 2,-3, 3, 4, 8, 5, 2,18, 6, 3, 7,-2 }, // 213 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 214 - { 1, 1,17,18, 8, 3, 4, 6,18, 5,-2, 3, 8, 5, 2, 4, 7, 6 }, // 215 - { 0, 1,18,-2, 3, 5, 1, 7, 3, 2, 6,-3, 4, 1, 5, 8, 3,-2 }, // 216 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 217 - { 1, 1, 3,17,18, 5,-1,18, 2, 6, 7,18, 5, 3,-3,-1, 6, 2 }, // 218 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 219 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 220 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 221 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 222 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 223 - { 1, 3,18,17,-2, 3,-1,18, 2, 5, 3, 7, 6, 2, 4, 8,18, 5 }, // 224 - { 0, 1,18,-1,18, 2,18, 3, 5,18, 2, 8,18, 5, 4,-1, 6, 2 }, // 225 - { 1, 2,18,-2,18,18, 2, 3, 4,-3, 2, 5,18, 7, 4, 3, 8, 6 }, // 226 - { 0, 2,17,-1,18, 2,-1, 1, 7, 3, 8, 5,-2, 4, 1, 2,-3, 6 }, // 227 - { 0, 1,18,17, 2,18, 2,18, 6, 7, 4, 3,18, 5, 2,-2,17, 8 }, // 228 - { 0, 3,18,17, 2, 3,-3,-1,18, 2, 4, 5,18, 7, 3, 2,-3, 6 }, // 229 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 230 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 231 - { 0, 2, 3,18,18,18, 2, 6, 5,18, 7, 2, 4, 6,18, 5, 3, 8 }, // 232 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 233 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 234 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 235 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 236 - { 0, 1,18,18, 3, 6, 3,-2, 2,18, 5,-1, 7, 3, 4,-2, 2, 6 }, // 237 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 238 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 239 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 240 - { 1, 1,18,17,18,18,-2, 2, 3,-3,18, 6, 4, 2,-2, 8, 3, 7 }, // 241 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 242 - { 0, 1,18,18,18, 4, 2, 7, 8,18, 3, 2,-2, 4, 7, 6,17, 5 }, // 243 - { 1, 1,18,18,-1,-2, 8, 3,18, 6, 3, 5, 8, 2, 4, 7, 1, 6 }, // 244 - { 1, 1, 1,-3, 3,18,18, 2,-1, 3, 6, 5,18, 4, 7,-2, 8, 3 }, // 245 - { 1, 1, 1,18, 4, 2, 5,18, 1, 3,-1, 6, 1, 4, 8, 2, 5, 1 }, // 246 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 247 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 248 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 249 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 250 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 251 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 252 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 253 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 254 - { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 255 -}; - -#define NUM_FAST_SPECS (sizeof (fast_specs) / sizeof (fast_specs [0])) -#define NUM_DEFAULT_SPECS (sizeof (default_specs) / sizeof (default_specs [0])) -#define NUM_HIGH_SPECS (sizeof (high_specs) / sizeof (high_specs [0])) -#define NUM_VERY_HIGH_SPECS (sizeof (very_high_specs) / sizeof (very_high_specs [0])) +#include "wavpack_local.h" +#include "decorr_tables.h" // contains data, only include from this module! ///////////////////////////// executable code //////////////////////////////// @@ -1093,6 +35,10 @@ void pack_init (WavpackContext *wpc) CLEAR (wps->decorr_passes); CLEAR (wps->dc); +#ifdef SKIP_DECORRELATION + wpc->config.xmode = 0; +#endif + /* although we set the term and delta values here for clarity, they're * actually hardcoded in the analysis function for speed */ @@ -1103,7 +49,7 @@ void pack_init (WavpackContext *wpc) if (wpc->config.flags & CONFIG_AUTO_SHAPING) { if (wpc->config.flags & CONFIG_OPTIMIZE_WVC) - wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = -512L * 65536; + wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = -(512L << 16); else if (wpc->config.sample_rate >= 64000) wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = 1024L << 16; else @@ -1154,7 +100,7 @@ void pack_init (WavpackContext *wpc) // 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) +static void write_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) { int tcount = wps->num_terms; struct decorr_pass *dpp; @@ -1174,7 +120,7 @@ void write_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) // 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) +static void write_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) { struct decorr_pass *dpp = wps->decorr_passes; int tcount = wps->num_terms, i; @@ -1215,7 +161,7 @@ void write_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) // 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) +static void write_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) { int tcount = wps->num_terms, wcount = 1, temp; struct decorr_pass *dpp; @@ -1227,27 +173,27 @@ void write_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) 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])); + dpp->samples_A [0] = wp_exp2s (temp = wp_log2s (dpp->samples_A [0])); *byteptr++ = temp; *byteptr++ = temp >> 8; - dpp->samples_A [1] = exp2s (temp = log2s (dpp->samples_A [1])); + dpp->samples_A [1] = wp_exp2s (temp = wp_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])); + dpp->samples_B [0] = wp_exp2s (temp = wp_log2s (dpp->samples_B [0])); *byteptr++ = temp; *byteptr++ = temp >> 8; - dpp->samples_B [1] = exp2s (temp = log2s (dpp->samples_B [1])); + dpp->samples_B [1] = wp_exp2s (temp = wp_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])); + dpp->samples_A [0] = wp_exp2s (temp = wp_log2s (dpp->samples_A [0])); *byteptr++ = temp; *byteptr++ = temp >> 8; - dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0])); + dpp->samples_B [0] = wp_exp2s (temp = wp_log2s (dpp->samples_B [0])); *byteptr++ = temp; *byteptr++ = temp >> 8; } @@ -1255,12 +201,12 @@ void write_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) int m = 0, cnt = dpp->term; while (cnt--) { - dpp->samples_A [m] = exp2s (temp = log2s (dpp->samples_A [m])); + dpp->samples_A [m] = wp_exp2s (temp = wp_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])); + dpp->samples_B [m] = wp_exp2s (temp = wp_log2s (dpp->samples_B [m])); *byteptr++ = temp; *byteptr++ = temp >> 8; } @@ -1285,7 +231,7 @@ void write_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) // 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) +static void write_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd) { char *byteptr; int temp; @@ -1293,29 +239,29 @@ void write_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd) byteptr = wpmd->data = malloc (12); wpmd->id = ID_SHAPING_WEIGHTS; - wps->dc.error [0] = exp2s (temp = log2s (wps->dc.error [0])); + wps->dc.error [0] = wp_exp2s (temp = wp_log2s (wps->dc.error [0])); *byteptr++ = temp; *byteptr++ = temp >> 8; - wps->dc.shaping_acc [0] = exp2s (temp = log2s (wps->dc.shaping_acc [0])); + wps->dc.shaping_acc [0] = wp_exp2s (temp = wp_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])); + wps->dc.error [1] = wp_exp2s (temp = wp_log2s (wps->dc.error [1])); *byteptr++ = temp; *byteptr++ = temp >> 8; - wps->dc.shaping_acc [1] = exp2s (temp = log2s (wps->dc.shaping_acc [1])); + wps->dc.shaping_acc [1] = wp_exp2s (temp = wp_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])); + wps->dc.shaping_delta [0] = wp_exp2s (temp = wp_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])); + wps->dc.shaping_delta [1] = wp_exp2s (temp = wp_log2s (wps->dc.shaping_delta [1])); *byteptr++ = temp; *byteptr++ = temp >> 8; } @@ -1329,7 +275,7 @@ void write_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd) // 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) +static void write_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) { char *byteptr; @@ -1342,29 +288,43 @@ void write_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data); } +static 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 = (int32_t)(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) +static void write_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) { uint32_t mask = wpc->config.channel_mask; - char *byteptr; + char *byteptr = wpmd->data = malloc (8); - if (wpc->num_streams > OLD_MAX_STREAMS) { - byteptr = wpmd->data = malloc (6); - wpmd->id = ID_CHANNEL_INFO; - *byteptr++ = wpc->config.num_channels - 1; - *byteptr++ = wpc->num_streams - 1; + wpmd->id = ID_CHANNEL_INFO; + + if (wpc->num_streams > OLD_MAX_STREAMS) { // if > 8 streams, use 6 or 7 bytes (breaks old decoders + *byteptr++ = wpc->config.num_channels - 1; // that could only handle 8 streams) and allow (in theory) + *byteptr++ = wpc->num_streams - 1; // up to 4096 channels *byteptr++ = (((wpc->num_streams - 1) >> 4) & 0xf0) | (((wpc->config.num_channels - 1) >> 8) & 0xf); *byteptr++ = mask; *byteptr++ = (mask >> 8); *byteptr++ = (mask >> 16); + + if (mask & 0xff000000) // this will break versions < 5.0, but is RF64-specific + *byteptr++ = (mask >> 24); } - else { - byteptr = wpmd->data = malloc (4); - wpmd->id = ID_CHANNEL_INFO; + else { // otherwise use only 1 to 5 bytes *byteptr++ = wpc->config.num_channels; while (mask) { @@ -1382,11 +342,11 @@ void write_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) // 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) +static void write_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) { char *byteptr; - byteptr = wpmd->data = malloc (4); + byteptr = wpmd->data = malloc (8); wpmd->id = ID_CONFIG_BLOCK; *byteptr++ = (char) (wpc->config.flags >> 8); *byteptr++ = (char) (wpc->config.flags >> 16); @@ -1395,16 +355,64 @@ void write_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) if (wpc->config.flags & CONFIG_EXTRA_MODE) *byteptr++ = (char) wpc->config.xmode; + // for the 5.0.0 alpha, we wrote the qmode flags here, but this + // has been replaced with the new_config block + // *byteptr++ = (char) wpc->config.qmode; + wpmd->byte_length = (int32_t)(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. +// Allocate room for and copy the "new" configuration information into the +// specified metadata structure. This is all the stuff introduced with version +// 5.0 and includes the qmode flags (big-endian, etc.) and CAF extended +// channel layouts (including optional reordering). Even if there is no new +// configuration, we still send the empty metadata block to signal a 5.0 file. -void write_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd) +static void write_new_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + char *byteptr = wpmd->data = malloc (260); + wpmd->id = ID_NEW_CONFIG_BLOCK; + + if (wpc->file_format || wpc->config.qmode || wpc->channel_layout) { + *byteptr++ = (char) wpc->file_format; + *byteptr++ = (char) wpc->config.qmode; + + if (wpc->channel_layout) { + int nchans = wpc->channel_layout & 0xff; + + *byteptr++ = (char) ((wpc->channel_layout & 0xff0000) >> 16); + + if (wpc->channel_reordering || nchans != wpc->config.num_channels) + *byteptr++ = (char) nchans; + + if (wpc->channel_reordering) { + int i, num_to_send = 0; + + // to save space, don't send redundant reorder string bytes + + for (i = 0; i < nchans; ++i) + if (wpc->channel_reordering [i] != i) + num_to_send = i + 1; + + if (num_to_send) { + memcpy (byteptr, wpc->channel_reordering, num_to_send); + byteptr += num_to_send; + } + } + } + } + + wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data); +} + +// Allocate room for and copy the non-standard sampling rate into the specified +// metadata structure. We normally store the lower 3 bytes of the sampling rate, +// unless 4 bytes are required (introduced in version 5). Note that this would +// only be used when the sampling rate was not included in the table of 15 +// "standard" values. + +static void write_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd) { char *byteptr; @@ -1413,6 +421,12 @@ void write_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd) *byteptr++ = (char) (wpc->config.sample_rate); *byteptr++ = (char) (wpc->config.sample_rate >> 8); *byteptr++ = (char) (wpc->config.sample_rate >> 16); + + // handle 4-byte sampling rates for scientific applications, etc. + + if (wpc->config.sample_rate & 0x7f000000) + *byteptr++ = (char) (wpc->config.sample_rate >> 24) & 0x7f; + wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data); } @@ -1425,13 +439,13 @@ void write_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd) // "wps->blockend" points to the end of the available space. A return value of // FALSE indicates an error. -static void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error); -static void dynamic_noise_shaping (WavpackContext *wpc, int32_t *buffer, int shortening_allowed); 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 scan_redundancy (int32_t *values, int32_t num_values); static int pack_samples (WavpackContext *wpc, int32_t *buffer); +static void bs_open_write (Bitstream *bs, void *buffer_start, void *buffer_end); +static uint32_t bs_close_write (Bitstream *bs); int pack_block (WavpackContext *wpc, int32_t *buffer) { @@ -1459,7 +473,11 @@ int pack_block (WavpackContext *wpc, int32_t *buffer) } } - if (!(flags & MONO_FLAG) && wpc->stream_version >= 0x410) { + // This code scans stereo data to check whether it can be stored as mono data + // (i.e., all L/R samples identical). This used to be an option because + // decoders < 4.30 pre-dated this feature, but now it's standard. + + if (!(flags & MONO_FLAG)) { int32_t lor = 0, diff = 0; int32_t *sptr, *dptr, i; @@ -1634,133 +652,6 @@ int pack_block (WavpackContext *wpc, int32_t *buffer) return TRUE; } -static void dynamic_noise_shaping (WavpackContext *wpc, int32_t *buffer, int shortening_allowed) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - int32_t sample_count = wps->wphdr.block_samples; - struct decorr_pass *ap = &wps->analysis_pass; - uint32_t flags = wps->wphdr.flags; - int32_t *bptr, temp, sam; - short *swptr; - int sc; - - if (!wps->num_terms && sample_count > 8) { - if (flags & MONO_DATA) - for (bptr = buffer + sample_count - 3, sc = sample_count - 2; sc--;) { - sam = (3 * bptr [1] - bptr [2]) >> 1; - temp = *bptr-- - apply_weight (ap->weight_A, sam); - update_weight (ap->weight_A, 2, sam, temp); - } - else - for (bptr = buffer + (sample_count - 3) * 2 + 1, sc = sample_count - 2; sc--;) { - sam = (3 * bptr [2] - bptr [4]) >> 1; - temp = *bptr-- - apply_weight (ap->weight_B, sam); - update_weight (ap->weight_B, 2, sam, temp); - sam = (3 * bptr [2] - bptr [4]) >> 1; - temp = *bptr-- - apply_weight (ap->weight_A, sam); - update_weight (ap->weight_A, 2, sam, temp); - } - } - - if (sample_count > wps->dc.shaping_samples) { - sc = sample_count - wps->dc.shaping_samples; - swptr = wps->dc.shaping_data + wps->dc.shaping_samples; - bptr = buffer + wps->dc.shaping_samples * ((flags & MONO_DATA) ? 1 : 2); - - if (flags & MONO_DATA) - while (sc--) { - sam = (3 * ap->samples_A [0] - ap->samples_A [1]) >> 1; - temp = *bptr - apply_weight (ap->weight_A, sam); - update_weight (ap->weight_A, 2, sam, temp); - ap->samples_A [1] = ap->samples_A [0]; - ap->samples_A [0] = *bptr++; - *swptr++ = (ap->weight_A < 256) ? 1024 : 1536 - ap->weight_A * 2; - } - else - while (sc--) { - sam = (3 * ap->samples_A [0] - ap->samples_A [1]) >> 1; - temp = *bptr - apply_weight (ap->weight_A, sam); - update_weight (ap->weight_A, 2, sam, temp); - ap->samples_A [1] = ap->samples_A [0]; - ap->samples_A [0] = *bptr++; - - sam = (3 * ap->samples_B [0] - ap->samples_B [1]) >> 1; - temp = *bptr - apply_weight (ap->weight_B, sam); - update_weight (ap->weight_B, 2, sam, temp); - ap->samples_B [1] = ap->samples_B [0]; - ap->samples_B [0] = *bptr++; - - *swptr++ = (ap->weight_A + ap->weight_B < 512) ? 1024 : 1536 - ap->weight_A - ap->weight_B; - } - - wps->dc.shaping_samples = sample_count; - } - - if (wpc->wvc_flag) { - int max_allowed_error = 1000000 / wpc->ave_block_samples; - short max_error, trial_max_error; - double initial_y, final_y; - - if (max_allowed_error < 128) - max_allowed_error = 128; - - best_floating_line (wps->dc.shaping_data, sample_count, &initial_y, &final_y, &max_error); - - if (shortening_allowed && max_error > max_allowed_error) { - int min_samples = 0, max_samples = sample_count, trial_count; - double trial_initial_y, trial_final_y; - - while (1) { - trial_count = (min_samples + max_samples) / 2; - - best_floating_line (wps->dc.shaping_data, trial_count, &trial_initial_y, - &trial_final_y, &trial_max_error); - - if (trial_max_error < max_allowed_error) { - max_error = trial_max_error; - min_samples = trial_count; - initial_y = trial_initial_y; - final_y = trial_final_y; - } - else - max_samples = trial_count; - - if (min_samples > 10000 || max_samples - min_samples < 2) - break; - } - - sample_count = min_samples; - } - - if (initial_y < -512) initial_y = -512; - else if (initial_y > 1024) initial_y = 1024; - - if (final_y < -512) final_y = -512; - else if (final_y > 1024) final_y = 1024; -#if 0 - error_line ("%.2f sec, sample count = %5d, max error = %3d, range = %5d, %5d, actual = %5d, %5d", - (double) wps->sample_index / wpc->config.sample_rate, sample_count, max_error, - (int) floor (initial_y), (int) floor (final_y), - wps->dc.shaping_data [0], wps->dc.shaping_data [sample_count-1]); -#endif - if (sample_count != wps->wphdr.block_samples) - wps->wphdr.block_samples = sample_count; - - if (wpc->wvc_flag) { - wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = (int32_t) floor (initial_y * 65536.0 + 0.5); - - wps->dc.shaping_delta [0] = wps->dc.shaping_delta [1] = - (int32_t) floor ((final_y - initial_y) / (sample_count - 1) * 65536.0 + 0.5); - - wps->dc.shaping_array = NULL; - } - else - wps->dc.shaping_array = wps->dc.shaping_data; - } - else - wps->dc.shaping_array = wps->dc.shaping_data; -} - // 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 @@ -1957,6 +848,39 @@ static void send_int32_data (WavpackStream *wps, int32_t *values, int32_t num_va } } +void send_general_metadata (WavpackContext *wpc) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags; + WavpackMetadata 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 & 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); + } + + if (flags & INITIAL_BLOCK) { + write_new_config_info (wpc, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } +} + // 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 @@ -1968,20 +892,55 @@ static void send_int32_data (WavpackStream *wps, int32_t *values, int32_t num_va // 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_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +#ifdef OPT_ASM_X86 + #define DECORR_STEREO_PASS(a,b,c) do { \ + if (pack_cpu_has_feature_x86 (CPU_FEATURE_MMX)) \ + pack_decorr_stereo_pass_x86 (a, b, c); \ + else decorr_stereo_pass (a, b, c); } while (0) + #define DECORR_MONO_BUFFER pack_decorr_mono_buffer_x86 + #define SCAN_MAX_MAGNITUDE(a,b) \ + (pack_cpu_has_feature_x86 (CPU_FEATURE_MMX) ? \ + scan_max_magnitude_x86 (a, b) : \ + scan_max_magnitude (a, b)) +#elif defined(OPT_ASM_X64) && (defined (_WIN64) || defined(__CYGWIN__) || defined(__MINGW64__)) + #define DECORR_STEREO_PASS pack_decorr_stereo_pass_x64win + #define DECORR_MONO_BUFFER pack_decorr_mono_buffer_x64win + #define SCAN_MAX_MAGNITUDE scan_max_magnitude_x64win +#elif defined(OPT_ASM_X64) + #define DECORR_STEREO_PASS pack_decorr_stereo_pass_x64 + #define DECORR_MONO_BUFFER pack_decorr_mono_buffer_x64 + #define SCAN_MAX_MAGNITUDE scan_max_magnitude_x64 +#else + #define DECORR_STEREO_PASS decorr_stereo_pass + #define DECORR_MONO_BUFFER decorr_mono_buffer + #define SCAN_MAX_MAGNITUDE scan_max_magnitude +#endif + +uint32_t DECORR_MONO_BUFFER (int32_t *buffer, struct decorr_pass *decorr_passes, int32_t num_terms, int32_t sample_count); + +#ifdef OPT_ASM_X86 +void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +void pack_decorr_stereo_pass_x86 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +uint32_t scan_max_magnitude (int32_t *values, int32_t num_values); +uint32_t scan_max_magnitude_x86 (int32_t *values, int32_t num_values); +#else +void DECORR_STEREO_PASS (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +uint32_t SCAN_MAX_MAGNITUDE (int32_t *values, int32_t num_values); +#endif + +// This macro controls the "repack" function where a block of samples will be repacked with +// fewer terms if a single residual exceeds the specified magnitude threshold. + +#define REPACK_SAFE_NUM_TERMS 5 // 5 terms is always okay (and we truncate to this) static int pack_samples (WavpackContext *wpc, int32_t *buffer) { - WavpackStream *wps = wpc->streams [wpc->current_stream]; - uint32_t flags = wps->wphdr.flags, data_count, crc, crc2, i; - uint32_t sample_count = wps->wphdr.block_samples; - short *shaping_array = wps->dc.shaping_array; - int tcount, lossy = FALSE, m = 0; - double noise_acc = 0.0, noise; + WavpackStream *wps = wpc->streams [wpc->current_stream], saved_stream; + uint32_t flags = wps->wphdr.flags, repack_possible, data_count, crc, crc2, i; + uint32_t sample_count = wps->wphdr.block_samples, repack_mask; + int32_t *bptr, *saved_buffer = NULL; struct decorr_pass *dpp; WavpackMetadata wpmd; - int32_t *bptr; crc = crc2 = 0xffffffff; @@ -2036,794 +995,436 @@ static int pack_samples (WavpackContext *wpc, int32_t *buffer) if (!sample_count) return TRUE; - write_decorr_terms (wps, &wpmd); - copy_metadata (&wpmd, wps->blockbuff, wps->blockend); - free_metadata (&wpmd); + memcpy (&wps->wphdr, wps->blockbuff, sizeof (WavpackHeader)); + repack_possible = !wps->num_passes && wps->num_terms > REPACK_SAFE_NUM_TERMS; + repack_mask = (flags & MAG_MASK) >> MAG_LSB >= 16 ? 0xF0000000 : 0xFFF00000; + saved_stream = *wps; - 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 (repack_possible && !(flags & HYBRID_FLAG)) { + saved_buffer = malloc (sample_count * sizeof (int32_t) * (flags & MONO_DATA ? 1 : 2)); + memcpy (saved_buffer, buffer, sample_count * sizeof (int32_t) * (flags & MONO_DATA ? 1 : 2)); } - if (flags & HYBRID_FLAG) { - write_hybrid_profile (wps, &wpmd); + // This code is written as a loop, but in the overwhelming majority of cases it executes only once. + // If one of the higher modes is being used and a residual exceeds a certain threshold, then the + // block will be repacked using fewer decorrelation terms. Note that this has only been triggered + // by pathological audio samples designed to trigger it...in practice this might never happen. Note + // that this only applies to the "high" and "very high" modes and only when packing directly + // (i.e. without the "extra" modes that will have already checked magnitude). + + do { + short *shaping_array = wps->dc.shaping_array; + int tcount, lossy = FALSE, m = 0; + double noise_acc = 0.0, noise; + uint32_t max_magnitude = 0; + + write_decorr_terms (wps, &wpmd); copy_metadata (&wpmd, wps->blockbuff, wps->blockend); free_metadata (&wpmd); - } - if (flags & FLOAT_DATA) { - write_float_info (wps, &wpmd); + write_decorr_weights (wps, &wpmd); copy_metadata (&wpmd, wps->blockbuff, wps->blockend); free_metadata (&wpmd); - } - if (flags & INT32_DATA) { - write_int32_info (wps, &wpmd); + write_decorr_samples (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); + 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 & 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); + if (flags & FLOAT_DATA) { + write_float_info (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); free_metadata (&wpmd); } - bs_open_write (&wps->wvcbits, wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 12, wps->block2end); - } + if (flags & INT32_DATA) { + write_int32_info (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } - /////////////////////// handle lossless mono mode ///////////////////////// + send_general_metadata (wpc); + bs_open_write (&wps->wvbits, wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12, wps->blockend); - if (!(flags & HYBRID_FLAG) && (flags & MONO_DATA)) { - if (!wps->num_passes) + 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)) { + if (!wps->num_passes) { + max_magnitude = DECORR_MONO_BUFFER (buffer, wps->decorr_passes, wps->num_terms, sample_count); + m = sample_count & (MAX_TERM - 1); + } + + send_words_lossless (wps, buffer, sample_count); + } + + //////////////////// handle the lossless stereo mode ////////////////////// + + else if (!(flags & HYBRID_FLAG) && !(flags & MONO_DATA)) { + if (!wps->num_passes) { + if (flags & JOINT_STEREO) { + int32_t *eptr = buffer + (sample_count * 2); + + for (bptr = buffer; bptr < eptr; bptr += 2) + bptr [1] += ((bptr [0] -= bptr [1]) >> 1); + } + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) + DECORR_STEREO_PASS (dpp, buffer, sample_count); + + m = sample_count & (MAX_TERM - 1); + + if (repack_possible) + max_magnitude = SCAN_MAX_MAGNITUDE (buffer, sample_count * 2); + } + + send_words_lossless (wps, buffer, sample_count); + } + + /////////////////// 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 = *bptr; + int32_t code, temp; + int shaping_weight; - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { - int32_t sam; + crc2 += (crc2 << 1) + (code = *bptr++); + if (flags & HYBRID_SHAPE) { + if (shaping_array) + shaping_weight = *shaping_array++; + else + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + + temp = -apply_weight (shaping_weight, 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) - sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [2] = 2 * dpp->samples_A [0] - dpp->samples_A [1]; else - sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + 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])); + + max_magnitude |= (code < 0 ? ~code : code); + 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 << 1) + 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 << 1) + left + (right = *bptr++); + + if (flags & HYBRID_SHAPE) { + if (shaping_array) + shaping_weight = *shaping_array++; + else + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + + temp = -apply_weight (shaping_weight, 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); + + if (!shaping_array) + 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])); + } + + max_magnitude |= (left < 0 ? ~left : left) | (right < 0 ? ~right : right); + 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_A [0] = code; + 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 { - sam = dpp->samples_A [m]; - dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = code; + 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); } - code -= apply_weight (dpp->weight_A, sam); - update_weight (dpp->weight_A, dpp->delta, sam, code); - } + if (flags & JOINT_STEREO) + left += (right -= (left >> 1)); + wps->dc.error [0] += left; + wps->dc.error [1] += right; m = (m + 1) & (MAX_TERM - 1); - *bptr++ = code; - } - send_words_lossless (wps, buffer, sample_count); - } + if ((crc += (crc << 3) + (left << 1) + left + right) != crc2) + lossy = TRUE; - //////////////////// handle the lossless stereo mode ////////////////////// + if (wpc->config.flags & CONFIG_CALC_NOISE) { + noise = (double)(left - bptr [-2]) * (left - bptr [-2]); + noise += (double)(right - bptr [-1]) * (right - bptr [-1]); - else if (!(flags & HYBRID_FLAG) && !(flags & MONO_DATA)) { - int32_t *eptr = buffer + (sample_count * 2); + noise_acc += noise /= 2.0; + wps->dc.noise_ave = (wps->dc.noise_ave * 0.99) + (noise * 0.01); - if (!wps->num_passes) { - if (flags & JOINT_STEREO) - for (bptr = buffer; bptr < eptr; bptr += 2) - bptr [1] += ((bptr [0] -= bptr [1]) >> 1); - - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) - if (((flags & MAG_MASK) >> MAG_LSB) >= 16 || dpp->delta != 2) - decorr_stereo_pass (dpp, buffer, sample_count); - else - decorr_stereo_pass_id2 (dpp, buffer, sample_count); - } - - send_words_lossless (wps, buffer, sample_count); - } - - /////////////////// 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; - int shaping_weight; - - crc2 += (crc2 << 1) + (code = *bptr++); - - if (flags & HYBRID_SHAPE) { - if (shaping_array) - shaping_weight = *shaping_array++; - else - shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; - - temp = -apply_weight (shaping_weight, 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); + if (wps->dc.noise_ave > wps->dc.noise_max) + wps->dc.noise_max = wps->dc.noise_ave; } } - wps->dc.error [0] += code; - m = (m + 1) & (MAX_TERM - 1); + 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; - if ((crc += (crc << 1) + code) != crc2) - lossy = TRUE; + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); - 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 << 1) + left + (right = *bptr++); - - if (flags & HYBRID_SHAPE) { - if (shaping_array) - shaping_weight = *shaping_array++; - else - shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; - - temp = -apply_weight (shaping_weight, 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); - - if (!shaping_array) - 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]; + 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); } - 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); + if (wpc->config.flags & CONFIG_CALC_NOISE) + wps->dc.noise_sum += noise_acc; - 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); + flush_word (wps); + data_count = bs_close_write (&wps->wvbits); - 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 << 1) + left + 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) { - unsigned char *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) { if (data_count != (uint32_t) -1) { - unsigned char *cptr = wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 8; + unsigned char *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8; - *cptr++ = ID_WVC_BITSTREAM | ID_LARGE; + *cptr++ = ID_WV_BITSTREAM | ID_LARGE; *cptr++ = data_count >> 1; *cptr++ = data_count >> 9; *cptr++ = data_count >> 17; - ((WavpackHeader *) wps->block2buff)->ckSize += data_count + 4; + ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4; } else return FALSE; } - ((WavpackHeader *) wps->block2buff)->crc = crc2; - } - else if (lossy) - wpc->lossy_blocks = TRUE; + ((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) { + unsigned char *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; + + // we're done with the entire block, so now we check if our threshold for a "repack" was hit + + if (repack_possible && wps->num_terms > REPACK_SAFE_NUM_TERMS && (max_magnitude & repack_mask)) { + *wps = saved_stream; + wps->num_terms = REPACK_SAFE_NUM_TERMS; + memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader)); + + if (saved_buffer) + memcpy (buffer, saved_buffer, sample_count * sizeof (int32_t) * (flags & MONO_DATA ? 1 : 2)); + + if (flags & HYBRID_FLAG) + crc = crc2 = 0xffffffff; + } + else { + // if we actually did repack the block with fewer terms, we detect that here + // and clean up so that we return to the original term count...otherwise we just + // free the saved_buffer (if allocated) and break out of the loop + if (wps->num_terms != saved_stream.num_terms) { + int ti; + + for (ti = wps->num_terms; ti < saved_stream.num_terms; ++ti) { + wps->decorr_passes [ti].weight_A = wps->decorr_passes [ti].weight_B = 0; + CLEAR (wps->decorr_passes [ti].samples_A); + CLEAR (wps->decorr_passes [ti].samples_B); + } + + wps->num_terms = saved_stream.num_terms; + } + + if (saved_buffer) + free (saved_buffer); + + break; + } + + } while (1); wps->sample_index += sample_count; return TRUE; } -// Perform a pass of the stereo decorrelation as specified by the referenced -// dpp structure. This version is optimized for samples that can use the -// simple apply_weight macro (i.e. <= 16-bit audio) and for when the weight -// delta is 2 (which is the case with all the default, non -x modes). For -// cases that do not fit this model, the more general decorr_stereo_pass() -// is provided. Note that this function returns the dpp->samples_X[] values -// in the "normalized" positions for terms 1-8. +#if !defined(OPT_ASM_X64) -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); - int m, k; +// This is the "C" version of the stereo decorrelation pass function. There +// are assembly optimized versions of this that can be used if available. +// It performs a single pass of stereo decorrelation, in place, as specified +// by the decorr_pass structure. Note that this function does NOT return the +// dpp->samples_X[] values in the "normalized" positions for terms 1-8, so if +// the number of samples is not a multiple of MAX_TERM, these must be moved if +// they are to be used somewhere else. - switch (dpp->term) { - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam, tmp; - - sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_A [1] = dpp->samples_A [0]; - bptr [0] = tmp = (dpp->samples_A [0] = bptr [0]) - apply_weight_i (dpp->weight_A, sam); - update_weight_d2 (dpp->weight_A, dpp->delta, sam, tmp); - - sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - dpp->samples_B [1] = dpp->samples_B [0]; - bptr [1] = tmp = (dpp->samples_B [0] = bptr [1]) - apply_weight_i (dpp->weight_B, sam); - update_weight_d2 (dpp->weight_B, dpp->delta, sam, tmp); - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam, tmp; - - sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); - dpp->samples_A [1] = dpp->samples_A [0]; - bptr [0] = tmp = (dpp->samples_A [0] = bptr [0]) - apply_weight_i (dpp->weight_A, sam); - update_weight_d2 (dpp->weight_A, dpp->delta, sam, tmp); - - sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); - dpp->samples_B [1] = dpp->samples_B [0]; - bptr [1] = tmp = (dpp->samples_B [0] = bptr [1]) - apply_weight_i (dpp->weight_B, sam); - update_weight_d2 (dpp->weight_B, dpp->delta, sam, tmp); - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam, tmp; - - sam = dpp->samples_A [m]; - bptr [0] = tmp = (dpp->samples_A [k] = bptr [0]) - apply_weight_i (dpp->weight_A, sam); - update_weight_d2 (dpp->weight_A, dpp->delta, sam, tmp); - - sam = dpp->samples_B [m]; - bptr [1] = tmp = (dpp->samples_B [k] = bptr [1]) - apply_weight_i (dpp->weight_B, sam); - update_weight_d2 (dpp->weight_B, dpp->delta, sam, tmp); - - m = (m + 1) & (MAX_TERM - 1); - k = (k + 1) & (MAX_TERM - 1); - } - - if (m) { - int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; - - memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); - memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); - - for (k = 0; k < MAX_TERM; k++) { - dpp->samples_A [k] = temp_A [m]; - dpp->samples_B [k] = temp_B [m]; - m = (m + 1) & (MAX_TERM - 1); - } - } - - break; - - case -1: - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam_A, sam_B, tmp; - - sam_A = dpp->samples_A [0]; - bptr [0] = tmp = (sam_B = bptr [0]) - apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, tmp); - - bptr [1] = tmp = (dpp->samples_A [0] = bptr [1]) - apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, tmp); - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam_A, sam_B, tmp; - - sam_B = dpp->samples_B [0]; - bptr [1] = tmp = (sam_A = bptr [1]) - apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, tmp); - - bptr [0] = tmp = (dpp->samples_B [0] = bptr [0]) - apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, tmp); - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam_A, sam_B, tmp; - - sam_A = dpp->samples_A [0]; - sam_B = dpp->samples_B [0]; - - dpp->samples_A [0] = tmp = bptr [1]; - bptr [1] = tmp -= apply_weight_i (dpp->weight_B, sam_B); - update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, tmp); - - dpp->samples_B [0] = tmp = bptr [0]; - bptr [0] = tmp -= apply_weight_i (dpp->weight_A, sam_A); - update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, tmp); - } - - break; - } -} - -// Perform a pass of the stereo decorrelation as specified by the referenced -// dpp structure. This function is provided in both a regular C version and -// an MMX version (using intrinsics) written by Joachim Henke. The MMX version -// is significantly faster when the sample data requires the full-resolution -// apply_weight macro. However, when the data is lower resolution (<= 16-bit) -// then the difference is slight (or the MMX is even slower), so for these -// cases the simpler decorr_stereo_pass_id2() is used. Note that this function -// returns the dpp->samples_X[] values in the "normalized" positions for -// terms 1-8. - -#ifdef OPT_MMX - -static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - const __m64 - delta = _mm_set1_pi32 (dpp->delta), - fill = _mm_set1_pi32 (0x7bff), - mask = _mm_set1_pi32 (0x7fff), - round = _mm_set1_pi32 (512), - zero = _mm_set1_pi32 (0); - __m64 - weight_AB = _mm_set_pi32 (restore_weight (store_weight (dpp->weight_B)), restore_weight (store_weight (dpp->weight_A))), - left_right, sam_AB, tmp0, tmp1, samples_AB [MAX_TERM]; - int k, m = 0; - - for (k = 0; k < MAX_TERM; ++k) { - ((int32_t *) samples_AB) [k * 2] = exp2s (log2s (dpp->samples_A [k])); - ((int32_t *) samples_AB) [k * 2 + 1] = exp2s (log2s (dpp->samples_B [k])); - } - - if (dpp->term > 0) { - if (dpp->term == 17) { - while (sample_count--) { - left_right = *(__m64 *) buffer; - tmp0 = samples_AB [0]; - sam_AB = _m_paddd (tmp0, tmp0); - sam_AB = _m_psubd (sam_AB, samples_AB [1]); - samples_AB [0] = left_right; - samples_AB [1] = tmp0; - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) buffer = left_right; - - tmp0 = _m_pxor (sam_AB, left_right); - tmp0 = _m_psradi (tmp0, 31); - tmp1 = _m_pxor (delta, tmp0); - tmp1 = _m_psubd (tmp1, tmp0); - sam_AB = _m_pcmpeqd (sam_AB, zero); - tmp0 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, sam_AB); - tmp0 = _m_pandn (tmp0, tmp1); - weight_AB = _m_paddd (weight_AB, tmp0); - - buffer += 2; - } - } - else if (dpp->term == 18) { - while (sample_count--) { - left_right = *(__m64 *) buffer; - tmp0 = samples_AB [0]; - sam_AB = _m_psubd (tmp0, samples_AB [1]); - sam_AB = _m_psradi (sam_AB, 1); - sam_AB = _m_paddd (sam_AB, tmp0); - samples_AB [0] = left_right; - samples_AB [1] = tmp0; - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) buffer = left_right; - - tmp0 = _m_pxor (sam_AB, left_right); - tmp0 = _m_psradi (tmp0, 31); - tmp1 = _m_pxor (delta, tmp0); - tmp1 = _m_psubd (tmp1, tmp0); - sam_AB = _m_pcmpeqd (sam_AB, zero); - tmp0 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, sam_AB); - tmp0 = _m_pandn (tmp0, tmp1); - weight_AB = _m_paddd (weight_AB, tmp0); - - buffer += 2; - } - } - else { - k = dpp->term & (MAX_TERM - 1); - while (sample_count--) { - left_right = *(__m64 *) buffer; - sam_AB = samples_AB [m]; - samples_AB [k] = left_right; - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) buffer = left_right; - - tmp0 = _m_pxor (sam_AB, left_right); - tmp0 = _m_psradi (tmp0, 31); - tmp1 = _m_pxor (delta, tmp0); - tmp1 = _m_psubd (tmp1, tmp0); - sam_AB = _m_pcmpeqd (sam_AB, zero); - tmp0 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, sam_AB); - tmp0 = _m_pandn (tmp0, tmp1); - weight_AB = _m_paddd (weight_AB, tmp0); - - buffer += 2; - k = (k + 1) & (MAX_TERM - 1); - m = (m + 1) & (MAX_TERM - 1); - } - } - } - else { - if (dpp->term == -1) { - while (sample_count--) { - left_right = *(__m64 *) buffer; - sam_AB = samples_AB [0]; - samples_AB [0] = _m_punpckhdq (left_right, sam_AB); - sam_AB = _m_punpckldq (sam_AB, left_right); - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) buffer = left_right; - - tmp0 = _m_pcmpeqd (sam_AB, zero); - tmp1 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, tmp1); - tmp0 = _m_pandn (tmp0, delta); - sam_AB = _m_pxor (sam_AB, left_right); - sam_AB = _m_psradi (sam_AB, 31); - tmp1 = _m_psubd (fill, sam_AB); - weight_AB = _m_pxor (weight_AB, sam_AB); - weight_AB = _m_paddd (weight_AB, tmp1); - weight_AB = _m_paddsw (weight_AB, tmp0); - weight_AB = _m_psubd (weight_AB, tmp1); - weight_AB = _m_pxor (weight_AB, sam_AB); - - buffer += 2; - } - } - else if (dpp->term == -2) { - while (sample_count--) { - left_right = *(__m64 *) buffer; - sam_AB = samples_AB [0]; - samples_AB [0] = _m_punpckldq (sam_AB, left_right); - sam_AB = _m_punpckhdq (left_right, sam_AB); - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) buffer = left_right; - - tmp0 = _m_pcmpeqd (sam_AB, zero); - tmp1 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, tmp1); - tmp0 = _m_pandn (tmp0, delta); - sam_AB = _m_pxor (sam_AB, left_right); - sam_AB = _m_psradi (sam_AB, 31); - tmp1 = _m_psubd (fill, sam_AB); - weight_AB = _m_pxor (weight_AB, sam_AB); - weight_AB = _m_paddd (weight_AB, tmp1); - weight_AB = _m_paddsw (weight_AB, tmp0); - weight_AB = _m_psubd (weight_AB, tmp1); - weight_AB = _m_pxor (weight_AB, sam_AB); - - buffer += 2; - } - } - else if (dpp->term == -3) { - while (sample_count--) { - left_right = *(__m64 *) buffer; - sam_AB = samples_AB [0]; - tmp0 = _m_punpckhdq (left_right, left_right); - samples_AB [0] = _m_punpckldq (tmp0, left_right); - - tmp0 = _m_paddd (sam_AB, sam_AB); - tmp1 = _m_pand (sam_AB, mask); - tmp0 = _m_psrldi (tmp0, 16); - tmp1 = _m_pmaddwd (tmp1, weight_AB); - tmp0 = _m_pmaddwd (tmp0, weight_AB); - tmp1 = _m_paddd (tmp1, round); - tmp0 = _m_pslldi (tmp0, 5); - tmp1 = _m_psradi (tmp1, 10); - left_right = _m_psubd (left_right, tmp0); - left_right = _m_psubd (left_right, tmp1); - - *(__m64 *) buffer = left_right; - - tmp0 = _m_pcmpeqd (sam_AB, zero); - tmp1 = _m_pcmpeqd (left_right, zero); - tmp0 = _m_por (tmp0, tmp1); - tmp0 = _m_pandn (tmp0, delta); - sam_AB = _m_pxor (sam_AB, left_right); - sam_AB = _m_psradi (sam_AB, 31); - tmp1 = _m_psubd (fill, sam_AB); - weight_AB = _m_pxor (weight_AB, sam_AB); - weight_AB = _m_paddd (weight_AB, tmp1); - weight_AB = _m_paddsw (weight_AB, tmp0); - weight_AB = _m_psubd (weight_AB, tmp1); - weight_AB = _m_pxor (weight_AB, sam_AB); - - buffer += 2; - } - } - } - - dpp->weight_A = ((int32_t *) &weight_AB) [0]; - dpp->weight_B = ((int32_t *) &weight_AB) [1]; - - for (k = 0; k < MAX_TERM; ++k) { - dpp->samples_A [k] = ((int32_t *) samples_AB) [m * 2]; - dpp->samples_B [k] = ((int32_t *) samples_AB) [m * 2 + 1]; - m = (m + 1) & (MAX_TERM - 1); - } - - _mm_empty (); -} - -#else - -static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) { int32_t *bptr, *eptr = buffer + (sample_count * 2); int m, k; @@ -2879,19 +1480,6 @@ static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_ k = (k + 1) & (MAX_TERM - 1); } - if (m) { - int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; - - memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); - memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); - - for (k = 0; k < MAX_TERM; k++) { - dpp->samples_A [k] = temp_A [m]; - dpp->samples_B [k] = temp_B [m]; - m = (m + 1) & (MAX_TERM - 1); - } - } - break; case -1: @@ -2942,6 +1530,75 @@ static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_ } } +// This is the "C" version of the magnitude scanning function. There are +// assembly optimized versions of this that can be used if available. This +// function scans a buffer of signed 32-bit ints and returns the magnitude +// of the largest sample, with a power-of-two resolution. It might be more +// useful to return the actual maximum absolute value (and this function +// could do that without breaking anything), but that implementation would +// likely be slower. Instead, this simply returns the "or" of all the +// values "xor"d with their own sign. + +uint32_t scan_max_magnitude (int32_t *values, int32_t num_values) +{ + uint32_t magnitude = 0; + + while (num_values--) + magnitude |= (*values < 0) ? ~*values++ : *values++; + + return magnitude; +} + +#endif + +#if !defined(OPT_ASM_X86) && !defined(OPT_ASM_X64) + +// This is the "C" version of the mono decorrelation pass function. There +// are assembly optimized versions of this that are be used if available. +// It decorrelates a buffer of mono samples, in place, as specified by the array +// of decorr_pass structures. Note that this function does NOT return the +// dpp->samples_X[] values in the "normalized" positions for terms 1-8, so if +// the number of samples is not a multiple of MAX_TERM, these must be moved if +// they are to be used somewhere else. The magnitude of the output samples is +// accumulated and returned (see scan_max_magnitude() for more details). + +uint32_t decorr_mono_buffer (int32_t *buffer, struct decorr_pass *decorr_passes, int32_t num_terms, int32_t sample_count) +{ + uint32_t max_magnitude = 0; + struct decorr_pass *dpp; + int tcount, i; + + for (i = 0; i < sample_count; ++i) { + int32_t code = *buffer; + + for (tcount = num_terms, dpp = 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 [i & (MAX_TERM - 1)]; + dpp->samples_A [(i + dpp->term) & (MAX_TERM - 1)] = code; + } + + code -= apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, code); + } + + *buffer++ = code; + max_magnitude |= (code < 0) ? ~code : code; + } + + return max_magnitude; +} + #endif ////////////////////////////////////////////////////////////////////////////// @@ -2961,44 +1618,52 @@ double WavpackGetEncodedNoise (WavpackContext *wpc, double *peak) return wps->dc.noise_sum; } -// Given an array of integer data (in shorts), find the linear function that most closely -// represents it (based on minimum sum of absolute errors). This is returned as the double -// precision initial & final Y values of the best-fit line. The function can also optionally -// compute and return a maximum error value (as a short). Note that the ends of the resulting -// line may fall way outside the range of input values, so some sort of clipping may be -// needed. +// 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. -void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error) +static void bs_write (Bitstream *bs); + +static void bs_open_write (Bitstream *bs, void *buffer_start, void *buffer_end) { - double left_sum = 0.0, right_sum = 0.0, center_x = (num_values - 1) / 2.0, center_y, m; - int i; - - for (i = 0; i < num_values >> 1; ++i) { - right_sum += values [num_values - i - 1]; - left_sum += values [i]; - } - - if (num_values & 1) { - right_sum += values [num_values >> 1] * 0.5; - left_sum += values [num_values >> 1] * 0.5; - } - - center_y = (right_sum + left_sum) / num_values; - m = (right_sum - left_sum) / ((double) num_values * num_values) * 4.0; - - if (initial_y) - *initial_y = center_y - m * center_x; - - if (final_y) - *final_y = center_y + m * center_x; - - if (max_error) { - double max = 0.0; - - for (i = 0; i < num_values; ++i) - if (fabs (values [i] - (center_y + (i - center_x) * m)) > max) - max = fabs (values [i] - (center_y + (i - center_x) * m)); - - *max_error = (short) floor (max + 0.5); - } + 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. + +static uint32_t bs_close_write (Bitstream *bs) +{ + uint32_t bytes_written; + + if (bs->error) + return (uint32_t) -1; + + while (1) { + while (bs->bc) + putbit_1 (bs); + + bytes_written = (uint32_t)(bs->ptr - bs->buf) * sizeof (*(bs->ptr)); + + if (bytes_written & 1) { + putbit_1 (bs); + } + else + break; + }; + + CLEAR (*bs); + return bytes_written; } diff --git a/Frameworks/WavPack/Files/pack_dns.c b/Frameworks/WavPack/Files/pack_dns.c new file mode 100644 index 000000000..2c6f3c8f1 --- /dev/null +++ b/Frameworks/WavPack/Files/pack_dns.c @@ -0,0 +1,191 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// pack_dns.c + +// This module handles the implementation of "dynamic noise shaping" which is +// designed to move the spectrum of the quantization noise introduced by lossy +// compression up or down in frequency so that it is more likely to be masked +// by the source material. + +#include +#include +#include + +#include "wavpack_local.h" + +static void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error); + +void dynamic_noise_shaping (WavpackContext *wpc, int32_t *buffer, int shortening_allowed) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int32_t sample_count = wps->wphdr.block_samples; + struct decorr_pass *ap = &wps->analysis_pass; + uint32_t flags = wps->wphdr.flags; + int32_t *bptr, temp, sam; + short *swptr; + int sc; + + if (!wps->num_terms && sample_count > 8) { + if (flags & MONO_DATA) + for (bptr = buffer + sample_count - 3, sc = sample_count - 2; sc--;) { + sam = (3 * bptr [1] - bptr [2]) >> 1; + temp = *bptr-- - apply_weight (ap->weight_A, sam); + update_weight (ap->weight_A, 2, sam, temp); + } + else + for (bptr = buffer + (sample_count - 3) * 2 + 1, sc = sample_count - 2; sc--;) { + sam = (3 * bptr [2] - bptr [4]) >> 1; + temp = *bptr-- - apply_weight (ap->weight_B, sam); + update_weight (ap->weight_B, 2, sam, temp); + sam = (3 * bptr [2] - bptr [4]) >> 1; + temp = *bptr-- - apply_weight (ap->weight_A, sam); + update_weight (ap->weight_A, 2, sam, temp); + } + } + + if (sample_count > wps->dc.shaping_samples) { + sc = sample_count - wps->dc.shaping_samples; + swptr = wps->dc.shaping_data + wps->dc.shaping_samples; + bptr = buffer + wps->dc.shaping_samples * ((flags & MONO_DATA) ? 1 : 2); + + if (flags & MONO_DATA) + while (sc--) { + sam = (3 * ap->samples_A [0] - ap->samples_A [1]) >> 1; + temp = *bptr - apply_weight (ap->weight_A, sam); + update_weight (ap->weight_A, 2, sam, temp); + ap->samples_A [1] = ap->samples_A [0]; + ap->samples_A [0] = *bptr++; + *swptr++ = (ap->weight_A < 256) ? 1024 : 1536 - ap->weight_A * 2; + } + else + while (sc--) { + sam = (3 * ap->samples_A [0] - ap->samples_A [1]) >> 1; + temp = *bptr - apply_weight (ap->weight_A, sam); + update_weight (ap->weight_A, 2, sam, temp); + ap->samples_A [1] = ap->samples_A [0]; + ap->samples_A [0] = *bptr++; + + sam = (3 * ap->samples_B [0] - ap->samples_B [1]) >> 1; + temp = *bptr - apply_weight (ap->weight_B, sam); + update_weight (ap->weight_B, 2, sam, temp); + ap->samples_B [1] = ap->samples_B [0]; + ap->samples_B [0] = *bptr++; + + *swptr++ = (ap->weight_A + ap->weight_B < 512) ? 1024 : 1536 - ap->weight_A - ap->weight_B; + } + + wps->dc.shaping_samples = sample_count; + } + + if (wpc->wvc_flag) { + int max_allowed_error = 1000000 / wpc->ave_block_samples; + short max_error, trial_max_error; + double initial_y, final_y; + + if (max_allowed_error < 128) + max_allowed_error = 128; + + best_floating_line (wps->dc.shaping_data, sample_count, &initial_y, &final_y, &max_error); + + if (shortening_allowed && max_error > max_allowed_error) { + int min_samples = 0, max_samples = sample_count, trial_count; + double trial_initial_y, trial_final_y; + + while (1) { + trial_count = (min_samples + max_samples) / 2; + + best_floating_line (wps->dc.shaping_data, trial_count, &trial_initial_y, + &trial_final_y, &trial_max_error); + + if (trial_max_error < max_allowed_error) { + max_error = trial_max_error; + min_samples = trial_count; + initial_y = trial_initial_y; + final_y = trial_final_y; + } + else + max_samples = trial_count; + + if (min_samples > 10000 || max_samples - min_samples < 2) + break; + } + + sample_count = min_samples; + } + + if (initial_y < -512) initial_y = -512; + else if (initial_y > 1024) initial_y = 1024; + + if (final_y < -512) final_y = -512; + else if (final_y > 1024) final_y = 1024; +#if 0 + error_line ("%.2f sec, sample count = %5d, max error = %3d, range = %5d, %5d, actual = %5d, %5d", + (double) wps->sample_index / wpc->config.sample_rate, sample_count, max_error, + (int) floor (initial_y), (int) floor (final_y), + wps->dc.shaping_data [0], wps->dc.shaping_data [sample_count-1]); +#endif + if (sample_count != wps->wphdr.block_samples) + wps->wphdr.block_samples = sample_count; + + if (wpc->wvc_flag) { + wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = (int32_t) floor (initial_y * 65536.0 + 0.5); + + wps->dc.shaping_delta [0] = wps->dc.shaping_delta [1] = + (int32_t) floor ((final_y - initial_y) / (sample_count - 1) * 65536.0 + 0.5); + + wps->dc.shaping_array = NULL; + } + else + wps->dc.shaping_array = wps->dc.shaping_data; + } + else + wps->dc.shaping_array = wps->dc.shaping_data; +} + +// Given an array of integer data (in shorts), find the linear function that most closely +// represents it (based on minimum sum of absolute errors). This is returned as the double +// precision initial & final Y values of the best-fit line. The function can also optionally +// compute and return a maximum error value (as a short). Note that the ends of the resulting +// line may fall way outside the range of input values, so some sort of clipping may be +// needed. + +static void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error) +{ + double left_sum = 0.0, right_sum = 0.0, center_x = (num_values - 1) / 2.0, center_y, m; + int i; + + for (i = 0; i < num_values >> 1; ++i) { + right_sum += values [num_values - i - 1]; + left_sum += values [i]; + } + + if (num_values & 1) { + right_sum += values [num_values >> 1] * 0.5; + left_sum += values [num_values >> 1] * 0.5; + } + + center_y = (right_sum + left_sum) / num_values; + m = (right_sum - left_sum) / ((double) num_values * num_values) * 4.0; + + if (initial_y) + *initial_y = center_y - m * center_x; + + if (final_y) + *final_y = center_y + m * center_x; + + if (max_error) { + double max = 0.0; + + for (i = 0; i < num_values; ++i) + if (fabs (values [i] - (center_y + (i - center_x) * m)) > max) + max = fabs (values [i] - (center_y + (i - center_x) * m)); + + *max_error = (short) floor (max + 0.5); + } +} diff --git a/Frameworks/WavPack/Files/pack_dsd.c b/Frameworks/WavPack/Files/pack_dsd.c new file mode 100644 index 000000000..bfb7d8bfe --- /dev/null +++ b/Frameworks/WavPack/Files/pack_dsd.c @@ -0,0 +1,630 @@ +//////////////////////////////////////////////////////////////////////////// +// **** DSDPACK **** // +// Lossless DSD (Direct Stream Digital) Audio Compressor // +// Copyright (c) 2013 - 2016 David Bryant. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// pack_dsd.c + +// This module actually handles the compression of the DSD audio data. + +#include +#include +#include + +#include "wavpack_local.h" + +///////////////////////////// executable code //////////////////////////////// + +// This function initializes everything required to pack WavPack DSD bitstreams +// and must be called BEFORE any other function in this module. + +void pack_dsd_init (WavpackContext *wpc) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + wps->sample_index = 0; +} + +// Pack an entire block of samples (either mono or stereo) into a completed +// WavPack block. This function is actually a shell for pack_samples() and +// performs tasks like handling any shift required by the format, preprocessing +// of floating point data or integer data over 24 bits wide, and implementing +// the "extra" mode (via the extra?.c modules). It is assumed that there is +// sufficient space for the completed block at "wps->blockbuff" and that +// "wps->blockend" points to the end of the available space. A return value of +// FALSE indicates an error. + +// Pack an entire block of samples (either mono or stereo) into a completed +// WavPack block. It is assumed that there is sufficient space for the +// completed block at "wps->blockbuff" and that "wps->blockend" points to the +// end of the available space. A return value of FALSE indicates an error. +// Any unsent metadata is transmitted first, then required metadata for this +// block is sent, and finally the compressed integer data is sent. If a "wpx" +// stream is required for floating point data or large integer data, then this +// must be handled outside this function. To find out how much data was written +// the caller must look at the ckSize field of the written WavpackHeader, NOT +// the one in the WavpackStream. + +static int encode_buffer_high (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination); +static int encode_buffer_fast (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination); + +int pack_dsd_block (WavpackContext *wpc, int32_t *buffer) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags, mult = wpc->dsd_multiplier, data_count; + uint32_t sample_count = wps->wphdr.block_samples; + unsigned char *dsd_encoding, dsd_power = 0; + int32_t res; + + // This code scans stereo data to check whether it can be stored as mono data + // (i.e., all L/R samples identical). + + if (!(flags & MONO_FLAG)) { + int32_t *sptr, *dptr, i; + + for (sptr = buffer, i = 0; i < (int32_t) sample_count; sptr += 2, i++) + if ((sptr [0] ^ sptr [1]) & 0xff) + break; + + if (i == sample_count) { + wps->wphdr.flags = flags |= FALSE_STEREO; + dptr = buffer; + sptr = buffer; + + for (i = sample_count; i--; sptr++) + *dptr++ = *sptr++; + } + else + wps->wphdr.flags = flags &= ~FALSE_STEREO; + } + + wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; + memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader)); + + if (wpc->metacount) { + WavpackMetadata *wpmdp = wpc->metadata; + + while (wpc->metacount) { + copy_metadata (wpmdp, wps->blockbuff, wps->blockend); + wpc->metabytes -= wpmdp->byte_length; + free_metadata (wpmdp++); + wpc->metacount--; + } + + free (wpc->metadata); + wpc->metadata = NULL; + } + + if (!sample_count) + return TRUE; + + send_general_metadata (wpc); + memcpy (&wps->wphdr, wps->blockbuff, sizeof (WavpackHeader)); + + dsd_encoding = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12; + + while (mult >>= 1) + dsd_power++; + + *dsd_encoding++ = dsd_power; + + if (wpc->config.flags & CONFIG_HIGH_FLAG) { + int fast_res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding); + + res = encode_buffer_high (wps, buffer, sample_count, dsd_encoding); + + if ((fast_res != -1) && (res == -1 || res > fast_res)) + res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding); + } + else + res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding); + + if (res == -1) { + int num_samples = sample_count * ((flags & MONO_DATA) ? 1 : 2); + uint32_t crc = 0xffffffff; + + *dsd_encoding++ = 0; + + data_count = num_samples + 2; + + while (num_samples--) + crc += (crc << 1) + (*dsd_encoding++ = *buffer++); + + ((WavpackHeader *) wps->blockbuff)->crc = crc; + } + else + data_count = res + 1; + + if (data_count) { + unsigned char *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8; + + if (data_count & 1) { + cptr [data_count + 4] = 0; + *cptr++ = ID_DSD_BLOCK | ID_LARGE | ID_ODD_SIZE; + data_count++; + } + else + *cptr++ = ID_DSD_BLOCK | ID_LARGE; + + *cptr++ = data_count >> 1; + *cptr++ = data_count >> 9; + *cptr++ = data_count >> 17; + ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4; + } + + wps->sample_index += sample_count; + return TRUE; +} + +/*------------------------------------------------------------------------------------------------------------------------*/ + +// #define DSD_BYTE_READY(low,high) (((low) >> 24) == ((high) >> 24)) +// #define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) >> 24)) +#define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) & 0xff000000)) + +#define MAX_HISTORY_BITS 5 +#define MAX_PROBABILITY 0xa0 // set to 0xff to disable RLE encoding for probabilities table + +#if (MAX_PROBABILITY < 0xff) + +static int rle_encode (unsigned char *src, int bcount, unsigned char *destination) +{ + int max_rle_zeros = 0xff - MAX_PROBABILITY; + unsigned char *dp = destination; + int zcount = 0; + + while (bcount--) { + if (*src) { + while (zcount) { + *dp++ = MAX_PROBABILITY + (zcount > max_rle_zeros ? max_rle_zeros : zcount); + zcount -= (zcount > max_rle_zeros ? max_rle_zeros : zcount); + } + + *dp++ = *src++; + } + else { + zcount++; + src++; + } + } + + while (zcount) { + *dp++ = MAX_PROBABILITY + (zcount > max_rle_zeros ? max_rle_zeros : zcount); + zcount -= (zcount > max_rle_zeros ? max_rle_zeros : zcount); + } + + *dp++ = 0; + + return (int)(dp - destination); +} + +#endif + +static void calculate_probabilities (int hist [256], unsigned char probs [256], unsigned short prob_sums [256]) +{ + int divisor, min_value, max_value, sum_values; + int min_hits = 0x7fffffff, max_hits = 0, i; + + for (i = 0; i < 256; ++i) { + if (hist [i] < min_hits) min_hits = hist [i]; + if (hist [i] > max_hits) max_hits = hist [i]; + } + + if (max_hits == 0) { + memset (probs, 0, sizeof (*probs) * 256); + memset (prob_sums, 0, sizeof (*prob_sums) * 256); + return; + } + +// fprintf (stderr, "process_histogram(): hits = %d to %d\n", min_hits, max_hits); + + if (max_hits > MAX_PROBABILITY) + divisor = ((max_hits << 8) + (MAX_PROBABILITY >> 1)) / MAX_PROBABILITY; + else + divisor = 0; + + while (1) { + min_value = 0x7fffffff; max_value = 0; sum_values = 0; + + for (i = 0; i < 256; ++i) { + int value; + + if (hist [i]) { + if (divisor) { + if (!(value = ((hist [i] << 8) + (divisor >> 1)) / divisor)) + value = 1; + } + else + value = hist [i]; + + if (value < min_value) min_value = value; + if (value > max_value) max_value = value; + } + else + value = 0; + + prob_sums [i] = sum_values += value; + probs [i] = value; + } + + if (max_value > MAX_PROBABILITY) { + divisor++; + continue; + } + +#if 0 // this code reduces probability values when they are completely redundant (i.e., common divisor), but + // this doesn't really happen often enough to make it worthwhile + + if (min_value > 1) { + for (i = 0; i < 256; ++i) + if (probs [i] % min_value) + break; + + if (i == 256) { + for (i = 0; i < 256; ++i) { + prob_sums [i] /= min_value; + probs [i] /= min_value; + } + + // fprintf (stderr, "fixed min_value = %d, divisor = %d, probs_sum = %d\n", min_value, divisor, prob_sums [255]); + } + } +#endif + + break; + } +} + +static int encode_buffer_fast (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination) +{ + uint32_t flags = wps->wphdr.flags, crc = 0xffffffff; + unsigned int low = 0, high = 0xffffffff, mult; + unsigned short (*summed_probabilities) [256]; + unsigned char (*probabilities) [256]; + unsigned char *dp = destination, *ep; + int history_bins, bc, p0 = 0, p1 = 0; + int total_summed_probabilities = 0; + int (*histogram) [256]; + int32_t *bp = buffer; + char history_bits; + + if (!(flags & MONO_DATA)) + num_samples *= 2; + + if (num_samples < 280) + return -1; + else if (num_samples < 560) + history_bits = 0; + else if (num_samples < 1725) + history_bits = 1; + else if (num_samples < 5000) + history_bits = 2; + else if (num_samples < 14000) + history_bits = 3; + else if (num_samples < 28000) + history_bits = 4; + else if (num_samples < 76000) + history_bits = 5; + else if (num_samples < 130000) + history_bits = 6; + else if (num_samples < 300000) + history_bits = 7; + else + history_bits = 8; + + if (history_bits > MAX_HISTORY_BITS) + history_bits = MAX_HISTORY_BITS; + + history_bins = 1 << history_bits; + histogram = malloc (sizeof (*histogram) * history_bins); + memset (histogram, 0, sizeof (*histogram) * history_bins); + probabilities = malloc (sizeof (*probabilities) * history_bins); + summed_probabilities = malloc (sizeof (*summed_probabilities) * history_bins); + + bc = num_samples; + + if (flags & MONO_DATA) + while (bc--) { + crc += (crc << 1) + (*bp & 0xff); + histogram [p0] [*bp & 0xff]++; + p0 = *bp++ & (history_bins-1); + } + else + while (bc--) { + crc += (crc << 1) + (*bp & 0xff); + histogram [p0] [*bp & 0xff]++; + p0 = p1; + p1 = *bp++ & (history_bins-1); + } + + for (p0 = 0; p0 < history_bins; p0++) { + calculate_probabilities (histogram [p0], probabilities [p0], summed_probabilities [p0]); + total_summed_probabilities += summed_probabilities [p0] [255]; + } + + ((WavpackHeader *) wps->blockbuff)->crc = crc; + + // This code detects the case where the required value lookup tables grow silly big and cuts them back down. This would + // normally only happen with large blocks or poorly compressible data. The target is to guarantee that the total memory + // required for all three decode tables will be 2K bytes per history bin. + + while (total_summed_probabilities > history_bins * 1280) { + int max_sum = 0, sum_values = 0, largest_bin; + + for (p0 = 0; p0 < history_bins; ++p0) + if (summed_probabilities [p0] [255] > max_sum) { + max_sum = summed_probabilities [p0] [255]; + largest_bin = p0; + } + + total_summed_probabilities -= max_sum; + p0 = largest_bin; + + for (p1 = 0; p1 < 256; ++p1) + summed_probabilities [p0] [p1] = sum_values += probabilities [p0] [p1] = (probabilities [p0] [p1] + 1) >> 1; + + total_summed_probabilities += summed_probabilities [p0] [255]; + // fprintf (stderr, "processed bin 0x%02x, bin: %d --> %d, new sum = %d\n", + // p0, max_sum, summed_probabilities [p0] [255], total_summed_probabilities); + } + + free (histogram); + bp = buffer; + bc = num_samples; + *dp++ = 1; + *dp++ = history_bits; + *dp++ = MAX_PROBABILITY; + ep = destination + num_samples - 10; + +#if (MAX_PROBABILITY < 0xff) + dp += rle_encode ((unsigned char *) probabilities, sizeof (*probabilities) * history_bins, dp); +#else + memcpy (dp, probabilities, sizeof (*probabilities) * history_bins); + dp += sizeof (*probabilities) * history_bins; +#endif + + p0 = p1 = 0; + + while (dp < ep && bc--) { + + mult = (high - low) / summed_probabilities [p0] [255]; + + if (!mult) { + high = low; + + while (DSD_BYTE_READY (high, low)) { + *dp++ = high >> 24; + high = (high << 8) | 0xff; + low <<= 8; + } + + mult = (high - low) / summed_probabilities [p0] [255]; + } + + if (*bp & 0xff) + low += summed_probabilities [p0] [(*bp & 0xff)-1] * mult; + + high = low + probabilities [p0] [*bp & 0xff] * mult - 1; + + while (DSD_BYTE_READY (high, low)) { + *dp++ = high >> 24; + high = (high << 8) | 0xff; + low <<= 8; + } + + if (flags & MONO_DATA) + p0 = *bp++ & (history_bins-1); + else { + p0 = p1; + p1 = *bp++ & (history_bins-1); + } + } + + high = low; + + while (DSD_BYTE_READY (high, low)) { + *dp++ = high >> 24; + high = (high << 8) | 0xff; + low <<= 8; + } + + free (summed_probabilities); + free (probabilities); + + if (dp < ep) + return (int)(dp - destination); + else + return -1; +} + +/*------------------------------------------------------------------------------------------------------------------------*/ + +#define PTABLE_BITS 8 +#define PTABLE_BINS (1<> 8; c--;) + value += (DOWN - value) >> DECAY; + + for (i = 0; i < PTABLE_BINS/2; ++i) { + table [i] = value; + table [PTABLE_BINS-1-i] = 0x100ffff - value; + + if (value > 0x010000) { + rate += (rate * rate_s + 128) >> 8; + + for (c = (rate + 64) >> 7; c--;) + value += (DOWN - value) >> DECAY; + } + } +} + +static int normalize_ptable (int *ptable) +{ + int rate = 0, min_error, error_sum, i; + int ntable [PTABLE_BINS]; + + init_ptable (ntable, rate, RATE_S); + + for (min_error = i = 0; i < PTABLE_BINS; ++i) + min_error += abs (ptable [i] - ntable [i]) >> 8; + + while (1) { + init_ptable (ntable, ++rate, RATE_S); + + for (error_sum = i = 0; i < PTABLE_BINS; ++i) + error_sum += abs (ptable [i] - ntable [i]) >> 8; + + if (error_sum < min_error) + min_error = error_sum; + else + break; + } + + return rate - 1; +} + +static int encode_buffer_high (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination) +{ + uint32_t flags = wps->wphdr.flags, crc = 0xffffffff; + unsigned int high = 0xffffffff, low = 0; + unsigned char *dp = destination, *ep; + DSDfilters *sp; + int channel; + + if (!(flags & MONO_DATA)) + num_samples *= 2; + + if (num_samples < 280) + return -1; + + *dp++ = 2; + ep = destination + num_samples - 10; + + if (!wps->sample_index) { + if (!wps->dsd.ptable) + wps->dsd.ptable = malloc (PTABLE_BINS * sizeof (*wps->dsd.ptable)); + + init_ptable (wps->dsd.ptable, INITIAL_TERM, RATE_S); + + for (channel = 0; channel < 2; ++channel) { + sp = wps->dsd.filters + channel; + + sp->filter1 = sp->filter2 = sp->filter3 = sp->filter4 = sp->filter5 = VALUE_ONE / 2; + sp->filter6 = sp->factor = 0; + } + + *dp++ = INITIAL_TERM; + *dp++ = RATE_S; + } + else { + int rate = normalize_ptable (wps->dsd.ptable); + init_ptable (wps->dsd.ptable, rate, RATE_S); + *dp++ = rate; + *dp++ = RATE_S; + } + + for (channel = 0; channel < ((flags & MONO_DATA) ? 1 : 2); ++channel) { + sp = wps->dsd.filters + channel; + + *dp++ = (sp->filter1 + 32768) >> 16; + *dp++ = (sp->filter2 + 32768) >> 16; + *dp++ = (sp->filter3 + 32768) >> 16; + *dp++ = (sp->filter4 + 32768) >> 16; + *dp++ = (sp->filter5 + 32768) >> 16; + *dp++ = sp->factor; + *dp++ = sp->factor >> 8; + + sp->filter1 = ((sp->filter1 + 32768) >> 16) << 16; + sp->filter2 = ((sp->filter2 + 32768) >> 16) << 16; + sp->filter3 = ((sp->filter3 + 32768) >> 16) << 16; + sp->filter4 = ((sp->filter4 + 32768) >> 16) << 16; + sp->filter5 = ((sp->filter5 + 32768) >> 16) << 16; + sp->filter6 = 0; + sp->factor = (sp->factor << 16) >> 16; + } + + channel = 0; + + while (dp < ep && num_samples--) { + int byte = (*buffer++ & 0xff), bitcount = 8; + sp = wps->dsd.filters + channel; + + crc += (crc << 1) + byte; + + while (bitcount--) { + int value = sp->filter1 - sp->filter5 + sp->filter6 * (sp->factor >> 2); + int index = (value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK; + int *val = wps->dsd.ptable + index; + + value += sp->filter6 << 3; + + if (byte & 0x80) { + high = low + (((high - low) >> 24) ? ((high - low) >> 8) * (*val >> 16) : (((high - low) * (*val >> 16)) >> 8)); + *val += (UP - *val) >> DECAY; + sp->filter1 += (VALUE_ONE - sp->filter1) >> 6; + sp->filter2 += (VALUE_ONE - sp->filter2) >> 4; + + if ((value ^ (value - (sp->filter6 << 4))) < 0) + sp->factor -= (value >> 31) | 1; + } + else { + low += 1 + (((high - low) >> 24) ? ((high - low) >> 8) * (*val >> 16) : (((high - low) * (*val >> 16)) >> 8)); + *val += (DOWN - *val) >> DECAY; + sp->filter1 -= sp->filter1 >> 6; + sp->filter2 -= sp->filter2 >> 4; + + if ((value ^ (value - (sp->filter6 << 4))) < 0) + sp->factor += (value >> 31) | 1; + } + + while (DSD_BYTE_READY (high, low)) { + *dp++ = high >> 24; + high = (high << 8) | 0xff; + low <<= 8; + } + + sp->filter3 += (sp->filter2 - sp->filter3) >> 4; + sp->filter4 += (sp->filter3 - sp->filter4) >> 4; + sp->filter5 += value = (sp->filter4 - sp->filter5) >> 4; + sp->filter6 += (value - sp->filter6) >> 3; + byte <<= 1; + } + + if (!(flags & MONO_DATA)) + channel ^= 1; + } + + ((WavpackHeader *) wps->blockbuff)->crc = crc; + high = low; + + while (DSD_BYTE_READY (high, low)) { + *dp++ = high >> 24; + high = (high << 8) | 0xff; + low <<= 8; + } + + if (dp < ep) + return (int)(dp - destination); + else + return -1; +} diff --git a/Frameworks/WavPack/Files/pack_floats.c b/Frameworks/WavPack/Files/pack_floats.c new file mode 100644 index 000000000..90ab65655 --- /dev/null +++ b/Frameworks/WavPack/Files/pack_floats.c @@ -0,0 +1,270 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// pack_floats.c + +// This module deals with the compression of floating-point data. Note that no +// floating point math is involved here...the values are only processed with +// the macros that directly access the mantissa, exponent, and sign fields. +// That's why we use the f32 type instead of the built-in float type. + +#include + +#include "wavpack_local.h" + +//#define DISPLAY_DIAGNOSTICS + +// Scan the provided buffer of floating-point values and (1) convert the +// significant portion of the data to integers for compression using the +// regular WavPack algorithms (which only operate on integers) and (2) +// determine whether the data requires a second stream for lossless +// storage (which will usually be the case except when the floating-point +// data was originally integer data). The converted integers are returned +// "in-place" and a return value of TRUE indicates that a second stream +// is required. + +int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values) +{ + int32_t shifted_ones = 0, shifted_zeros = 0, shifted_both = 0; + int32_t false_zeros = 0, neg_zeros = 0; +#ifdef DISPLAY_DIAGNOSTICS + int32_t true_zeros = 0, denormals = 0, exceptions = 0; +#endif + uint32_t ordata = 0, crc = 0xffffffff; + int32_t count, value, shift_count; + int max_mag = 0, max_exp = 0; + f32 *dp; + + wps->float_shift = wps->float_flags = 0; + + // First loop goes through all the data and (1) calculates the CRC and (2) finds the + // max magnitude that does not have an exponent of 255 (reserved for +/-inf and NaN). + for (dp = values, count = num_values; count--; dp++) { + crc = crc * 27 + get_mantissa (*dp) * 9 + get_exponent (*dp) * 3 + get_sign (*dp); + + if (get_exponent (*dp) < 255 && get_magnitude (*dp) > max_mag) + max_mag = get_magnitude (*dp); + } + + wps->crc_x = crc; + + // round up the magnitude so that when we convert the floating-point values to integers, + // they will be (at most) just over 24-bits signed precision + if (get_exponent (max_mag)) + max_exp = get_exponent (max_mag + 0x7F0000); + + for (dp = values, count = num_values; count--; dp++) { + // Exponent of 255 is reserved for +/-inf (mantissa = 0) or NaN (mantissa != 0). + // we use a value one greater than 24-bits unsigned for this. + if (get_exponent (*dp) == 255) { +#ifdef DISPLAY_DIAGNOSTICS + exceptions++; +#endif + wps->float_flags |= FLOAT_EXCEPTIONS; + value = 0x1000000; + shift_count = 0; + } + // This is the regular case. We generate a 24-bit unsigned value with the implied + // '1' MSB set and calculate a shift that will make it line up with the biggest + // samples in this block (although that shift would obviously shift out real data). + else if (get_exponent (*dp)) { + shift_count = max_exp - get_exponent (*dp); + value = 0x800000 + get_mantissa (*dp); + } + // Zero exponent means either +/- zero (mantissa = 0) or denormals (mantissa != 0). + // shift_count is set so that denormals (without an implied '1') will line up with + // regular values (with their implied '1' added at bit 23). Trust me. We don't care + // about the shift with zero. + else { + shift_count = max_exp ? max_exp - 1 : 0; + value = get_mantissa (*dp); + +#ifdef DISPLAY_DIAGNOSTICS + if (get_mantissa (*dp)) + denormals++; +#endif + } + + if (shift_count < 25) + value >>= shift_count; // perform the shift if there could be anything left + else + value = 0; // else just zero the value + + // If we are going to encode an integer zero, then this might be a "false zero" which + // means that there are significant bits but they're completely shifted out, or a + // "negative zero" which is simply a floating point value that we have to encode + // (and converting it to a positive zero would be an error). + if (!value) { + if (get_exponent (*dp) || get_mantissa (*dp)) + ++false_zeros; + else if (get_sign (*dp)) + ++neg_zeros; +#ifdef DISPLAY_DIAGNOSTICS + else + ++true_zeros; +#endif + } + // If we are going to shift something (but not everything) out of our integer before + // encoding, then we generate a mask corresponding to the bits that will be shifted + // out and increment the counter for the 3 possible cases of (1) all zeros, (2) all + // ones, and (3) a mix of ones and zeros. + else if (shift_count) { + int32_t mask = (1 << shift_count) - 1; + + if (!(get_mantissa (*dp) & mask)) + shifted_zeros++; + else if ((get_mantissa (*dp) & mask) == mask) + shifted_ones++; + else + shifted_both++; + } + + // "or" all the integer values together, and store the final integer with applied sign + + ordata |= value; + * (int32_t *) dp = (get_sign (*dp)) ? -value : value; + } + + wps->float_max_exp = max_exp; // on decode, we use this to calculate actual exponent + + // Now, based on our various counts, we determine the scheme required to encode the bits + // shifted out. Usually these will simply have to be sent literally, but in some rare cases + // we can get away with always assuming ones shifted out, or assuming all the bits shifted + // out in each value are the same (which means we only have to send a single bit). + if (shifted_both) + wps->float_flags |= FLOAT_SHIFT_SENT; + else if (shifted_ones && !shifted_zeros) + wps->float_flags |= FLOAT_SHIFT_ONES; + else if (shifted_ones && shifted_zeros) + wps->float_flags |= FLOAT_SHIFT_SAME; + // Another case is that we only shift out zeros (or maybe nothing), and in that case we + // check to see if our data actually has less than 24 or 25 bits of resolution, which means + // that we reduce can the magnitude of the integers we are encoding (which saves all those + // bits). The number of bits of reduced resolution is stored in float_shift. + else if (ordata && !(ordata & 1)) { + while (!(ordata & 1)) { + wps->float_shift++; + ordata >>= 1; + } + + // here we shift out all those zeros in the integer data we will encode + for (dp = values, count = num_values; count--; dp++) + * (int32_t *) dp >>= wps->float_shift; + } + + // Here we calculate the actual magnitude used by our integer data, although this is just + // used for informational purposes during encode/decode to possibly use faster math. + + wps->wphdr.flags &= ~MAG_MASK; + + while (ordata) { + wps->wphdr.flags += 1 << MAG_LSB; + ordata >>= 1; + } + + // Finally, we have to set some flags that guide how we encode various types of "zeros". + // If none of these are set (which is the most common situation), then every integer + // zero in the decoded data will simply become a floating-point zero. + + if (false_zeros || neg_zeros) + wps->float_flags |= FLOAT_ZEROS_SENT; + + if (neg_zeros) + wps->float_flags |= FLOAT_NEG_ZEROS; + +#ifdef DISPLAY_DIAGNOSTICS + { + int32_t *ip, min = 0x7fffffff, max = 0x80000000; + for (ip = (int32_t *) values, count = num_values; count--; ip++) { + if (*ip < min) min = *ip; + if (*ip > max) max = *ip; + } + + fprintf (stderr, "integer range = %d to %d\n", min, max); + } + + fprintf (stderr, "samples = %d, max exp = %d, pre-shift = %d, denormals = %d, exceptions = %d, max_mag = %x\n", + num_values, max_exp, wps->float_shift, denormals, exceptions, max_mag); + fprintf (stderr, "shifted ones/zeros/both = %d/%d/%d, true/neg/false zeros = %d/%d/%d\n", + shifted_ones, shifted_zeros, shifted_both, true_zeros, neg_zeros, false_zeros); +#endif + + return wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME); +} + +// Given a buffer of float data, convert the data to integers (which is what the WavPack compression +// algorithms require) and write the other data required for lossless compression (which includes +// significant bits shifted out of the integers, plus information about +/- zeros and exceptions +// like NaN and +/- infinities) into the wvxbits stream (which is assumed to be opened). Note that +// for this work correctly, scan_float_data() must have been called on the original data to set +// the appropiate flags in float_flags and max_exp. + +void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values) +{ + int max_exp = wps->float_max_exp; + int32_t count, value, shift_count; + f32 *dp; + + for (dp = values, count = num_values; count--; dp++) { + if (get_exponent (*dp) == 255) { + if (get_mantissa (*dp)) { + putbit_1 (&wps->wvxbits); + putbits (get_mantissa (*dp), 23, &wps->wvxbits); + } + else { + putbit_0 (&wps->wvxbits); + } + + value = 0x1000000; + shift_count = 0; + } + else if (get_exponent (*dp)) { + shift_count = max_exp - get_exponent (*dp); + value = 0x800000 + get_mantissa (*dp); + } + else { + shift_count = max_exp ? max_exp - 1 : 0; + value = get_mantissa (*dp); + } + + if (shift_count < 25) + value >>= shift_count; + else + value = 0; + + if (!value) { + if (wps->float_flags & FLOAT_ZEROS_SENT) { + if (get_exponent (*dp) || get_mantissa (*dp)) { + putbit_1 (&wps->wvxbits); + putbits (get_mantissa (*dp), 23, &wps->wvxbits); + + if (max_exp >= 25) { + putbits (get_exponent (*dp), 8, &wps->wvxbits); + } + + putbit (get_sign (*dp), &wps->wvxbits); + } + else { + putbit_0 (&wps->wvxbits); + + if (wps->float_flags & FLOAT_NEG_ZEROS) + putbit (get_sign (*dp), &wps->wvxbits); + } + } + } + else if (shift_count) { + if (wps->float_flags & FLOAT_SHIFT_SENT) { + int32_t data = get_mantissa (*dp) & ((1 << shift_count) - 1); + putbits (data, shift_count, &wps->wvxbits); + } + else if (wps->float_flags & FLOAT_SHIFT_SAME) { + putbit (get_mantissa (*dp) & 1, &wps->wvxbits); + } + } + } +} diff --git a/Frameworks/WavPack/Files/pack_utils.c b/Frameworks/WavPack/Files/pack_utils.c new file mode 100644 index 000000000..0b4c0e060 --- /dev/null +++ b/Frameworks/WavPack/Files/pack_utils.c @@ -0,0 +1,1126 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// pack_utils.c + +// This module provides the high-level API for creating WavPack files from +// audio data. It manages the buffers used to deinterleave the data passed +// in from the application into the individual streams and it handles the +// generation of riff headers and the "fixup" on the first WavPack block +// header for the case where the number of samples was unknown (or wrong). +// The actual audio stream compression is handled in the pack.c module. + +#include +#include +#include + +#include "wavpack_local.h" + +///////////////////////////// executable code //////////////////////////////// + +// 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->stream_version = CUR_STREAM_VERS; + wpc->blockout = blockout; + wpc->wv_out = wv_id; + wpc->wvc_out = wvc_id; + return wpc; +} + +static int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, unsigned char id); + +// New for version 5.0, this function allows the application to store a file extension and a +// file_format identification. The extension would be used by the unpacker if the user had not +// specified the target filename, and specifically handles the case where the original file +// had the "wrong" extension for the file format (e.g., a Wave64 file having a "wav" extension) +// or an alternative (e.g., "bwf") or where the file format is not known. Specifying a file +// format besides the default WP_FORMAT_WAV will ensure that old decoders will not be able to +// see the non-wav wrapper provided with WavpackAddWrapper() (which they would end up putting +// on a file with a .wav extension). + +void WavpackSetFileInformation (WavpackContext *wpc, char *file_extension, unsigned char file_format) +{ + if (file_extension && strlen (file_extension) < sizeof (wpc->file_extension)) { + add_to_metadata (wpc, file_extension, (uint32_t) strlen (file_extension), ID_ALT_EXTENSION); + strcpy (wpc->file_extension, file_extension); + } + + wpc->file_format = file_format; +} + +// 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 +// o CONFIG_OPTIMIZE_MONO detect and optimize for mono files posing as +// stereo (uses a more recent stream format that +// is not compatible with decoders < 4.3) + +// 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 stereo_pairings [] = { + (1 << 0) | (1 << 1), // FL, FR + (1 << 4) | (1 << 5), // BL, BR + (1 << 6) | (1 << 7), // FLC, FRC + (1 << 9) | (1 << 10), // SL, SR + (1 << 12) | (1 << 14), // TFL, TFR + (1 << 15) | (1 << 17), // TBL, TBR + (1 << 29) | (1 << 30) // stereo mix L,R (RF64) +}; + +#define NUM_STEREO_PAIRINGS (sizeof (stereo_pairings) / sizeof (stereo_pairings [0])) + +int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples) +{ + if (total_samples == (uint32_t) -1) + return WavpackSetConfiguration64 (wpc, config, -1); + else + return WavpackSetConfiguration64 (wpc, config, total_samples); +} + +int WavpackSetConfiguration64 (WavpackContext *wpc, WavpackConfig *config, int64_t total_samples) +{ + uint32_t flags, bps = 0, shift = 0; + uint32_t chan_mask = config->channel_mask; + int num_chans = config->num_channels; + int i; + + if ((config->qmode & QMODE_DSD_AUDIO) && config->bytes_per_sample == 1 && config->bits_per_sample == 8) { + wpc->dsd_multiplier = 1; + flags = DSD_FLAG; + + for (i = 14; i >= 0; --i) + if (config->sample_rate % sample_rates [i] == 0) { + int divisor = config->sample_rate / sample_rates [i]; + + if (divisor && (divisor & (divisor - 1)) == 0) { + config->sample_rate /= divisor; + wpc->dsd_multiplier = divisor; + break; + } + } + + // with DSD, very few PCM options work (or make sense), so only allow those that do + config->flags &= (CONFIG_HIGH_FLAG | CONFIG_MD5_CHECKSUM | CONFIG_PAIR_UNDEF_CHANS); + config->float_norm_exp = config->xmode = 0; + } + else + flags = config->bytes_per_sample - 1; + + 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; + wpc->config.qmode = config->qmode; + + if (config->flags & CONFIG_VERY_HIGH_FLAG) + wpc->config.flags |= CONFIG_HIGH_FLAG; + + for (i = 0; i < 15; ++i) + if (wpc->config.sample_rate == sample_rates [i]) + break; + + flags |= i << SRATE_LSB; + flags |= shift << SHIFT_LSB; + + // all of this stuff only applies to PCM + + if (!(flags & DSD_FLAG)) { + 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; + + 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_CROSS_DECORR | CONFIG_OPTIMIZE_WVC)) + flags |= CROSS_DECORR; + + if (config->flags & CONFIG_BITRATE_KBPS) { + bps = (uint32_t) floor (config->bitrate * 256000.0 / config->sample_rate / config->num_channels + 0.5); + + if (bps > (64 << 8)) + bps = 64 << 8; + } + else + bps = (uint32_t) 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 = 0, mono_mask = 0; + int pos, chans = 0; + + wpc->streams = realloc (wpc->streams, (wpc->current_stream + 1) * sizeof (wpc->streams [0])); + wpc->streams [wpc->current_stream] = wps; + CLEAR (*wps); + + for (pos = 0; pos < 32; ++pos) + if (chan_mask & (1 << pos)) { + if (mono_mask) { + stereo_mask = mono_mask | (1 << pos); + break; + } + else + mono_mask = 1 << pos; + } + + if (num_chans > 1 && stereo_mask) { + for (i = 0; i < NUM_STEREO_PAIRINGS; ++i) + if (stereo_mask == stereo_pairings [i]) { + chan_mask &= ~stereo_mask; + chans = 2; + break; + } + + if (i == NUM_STEREO_PAIRINGS) { + chan_mask &= ~mono_mask; + chans = 1; + } + } + else if (mono_mask) { + chan_mask &= ~mono_mask; + chans = 1; + } + + if (!chans) { + if (config->flags & CONFIG_PAIR_UNDEF_CHANS) + chans = num_chans > 1 ? 2 : 1; + else + chans = 1; + } + + num_chans -= chans; + + if (num_chans && wpc->current_stream == NEW_MAX_STREAMS - 1) + break; + + memcpy (wps->wphdr.ckID, "wvpk", 4); + wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; + SET_TOTAL_SAMPLES (wps->wphdr, 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) + wpc->config.xmode = config->xmode ? config->xmode : 1; + + return TRUE; +} + +// This function allows setting the Core Audio File channel layout, many of which do not +// conform to the Microsoft ordering standard that Wavpack requires internally (at least for +// those channels present in the "channel mask"). In addition to the layout tag, this function +// allows a reordering string to be stored in the file to allow the unpacker to reorder the +// channels back to the specified layout (if it is aware of this feature and wants to restore +// the CAF order). The number of channels in the layout is specified in the lower nybble of +// the layout word, and if a reorder string is specified it must be that long. Note that all +// the reordering is actually done outside of this library, and that if reordering is done +// then the appropriate qmode bit must be set to ensure that any MD5 sum is stored with a new +// ID so that old decoders don't try to verify it (and to let the decoder know that a reorder +// might be required). + +int WavpackSetChannelLayout (WavpackContext *wpc, uint32_t layout_tag, const unsigned char *reorder) +{ + int nchans = layout_tag & 0xff; + + if ((layout_tag & 0xff00ff00) || nchans > wpc->config.num_channels) + return FALSE; + + wpc->channel_layout = layout_tag; + + if (wpc->channel_reordering) { + free (wpc->channel_reordering); + wpc->channel_reordering = NULL; + } + + if (nchans && reorder) { + int min_index = 256, i; + + for (i = 0; i < nchans; ++i) + if (reorder [i] < min_index) + min_index = reorder [i]; + + wpc->channel_reordering = malloc (nchans); + + if (wpc->channel_reordering) + for (i = 0; i < nchans; ++i) + wpc->channel_reordering [i] = reorder [i] - min_index; + } + + 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. + +static int write_metadata_block (WavpackContext *wpc); + +int WavpackPackInit (WavpackContext *wpc) +{ + if (wpc->metabytes > 16384) // 16384 bytes still leaves plenty of room for audio + write_metadata_block (wpc); // in this block (otherwise write a special one) + + 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; + + if (wpc->dsd_multiplier) { + if (wpc->config.flags & CONFIG_HIGH_FLAG) + wpc->block_samples = 22050; + else + wpc->block_samples = 44100; + + if (wpc->config.num_channels == 1) + wpc->block_samples *= 2; + } + + 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; + + if (wpc->config.block_samples) { + if ((wpc->config.flags & CONFIG_MERGE_BLOCKS) && + wpc->block_samples > (uint32_t) wpc->config.block_samples) { + wpc->block_boundary = wpc->config.block_samples; + wpc->block_samples /= wpc->config.block_samples; + wpc->block_samples *= wpc->config.block_samples; + } + else + wpc->block_samples = wpc->config.block_samples; + } + + wpc->ave_block_samples = wpc->block_samples; + wpc->max_samples = wpc->block_samples + (wpc->block_samples >> 1); + + for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++) { + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + wps->sample_buffer = malloc (wpc->max_samples * (wps->wphdr.flags & MONO_FLAG ? 4 : 8)); + + if (wps->wphdr.flags & DSD_FLAG) + pack_dsd_init (wpc); + else + 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, int64_t total_samples, void *outbuffer); + +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; + unsigned int samples_to_copy; + + if (!wpc->riff_header_added && !wpc->riff_header_created && !wpc->file_format) { + char riff_header [128]; + + if (!add_to_metadata (wpc, riff_header, create_riff_header (wpc, wpc->total_samples, riff_header), ID_RIFF_HEADER)) + 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->current_stream < wpc->num_streams; 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; + + // This code used to just copy the 32-bit samples regardless of the actual size with the + // assumption that the caller had properly sign-extended the values (if they were smaller + // than 32 bits). However, several people have discovered that if the data isn't properly + // sign extended then ugly things happen (e.g. CRC errors that show up only on decode). + // To prevent this, we now explicitly sign-extend samples smaller than 32-bit when we + // copy, and the performance hit from doing this is very small (generally < 1%). + + if (wps->wphdr.flags & MONO_FLAG) { + switch (wpc->config.bytes_per_sample) { + case 1: + while (cnt--) { + *dptr++ = (signed char) *sptr; + sptr += nch; + } + + break; + + case 2: + while (cnt--) { + *dptr++ = (int16_t) *sptr; + sptr += nch; + } + + break; + + case 3: + while (cnt--) { + *dptr++ = (*sptr << 8) >> 8; + sptr += nch; + } + + break; + + default: + while (cnt--) { + *dptr++ = *sptr; + sptr += nch; + } + } + + source_pointer++; + } + else { + switch (wpc->config.bytes_per_sample) { + case 1: + while (cnt--) { + *dptr++ = (signed char) sptr [0]; + *dptr++ = (signed char) sptr [1]; + sptr += nch; + } + + break; + + case 2: + while (cnt--) { + *dptr++ = (int16_t) sptr [0]; + *dptr++ = (int16_t) sptr [1]; + sptr += nch; + } + + break; + + case 3: + while (cnt--) { + *dptr++ = (sptr [0] << 8) >> 8; + *dptr++ = (sptr [1] << 8) >> 8; + sptr += nch; + } + + break; + + default: + 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) +{ + int64_t index = WavpackGetSampleIndex64 (wpc); + unsigned char meta_id; + + if (!index || index == -1) { + wpc->riff_header_added = TRUE; + meta_id = wpc->file_format ? ID_ALT_HEADER : ID_RIFF_HEADER; + } + else { + wpc->riff_trailer_bytes += bcount; + meta_id = wpc->file_format ? ID_ALT_TRAILER : 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. +// If any of the lower 8 bits of qmode are set, then this MD5 is stored with +// a metadata ID that old decoders do not recognize (because they would not +// interpret the qmode and would therefore fail the verification). + +int WavpackStoreMD5Sum (WavpackContext *wpc, unsigned char data [16]) +{ + return add_to_metadata (wpc, data, 16, (wpc->config.qmode & 0xff) ? ID_ALT_MD5_CHECKSUM : ID_MD5_CHECKSUM); +} + +#pragma pack(push,4) + +typedef struct { + char ckID [4]; + uint64_t chunkSize64; +} CS64Chunk; + +typedef struct { + uint64_t riffSize64, dataSize64, sampleCount64; + uint32_t tableLength; +} DS64Chunk; + +typedef struct { + char ckID [4]; + uint32_t ckSize; + char junk [28]; +} JunkChunk; + +#pragma pack(pop) + +#define DS64ChunkFormat "DDDL" + +static int create_riff_header (WavpackContext *wpc, int64_t total_samples, void *outbuffer) +{ + int do_rf64 = 0, write_junk = 1; + ChunkHeader ds64hdr, datahdr, fmthdr; + char *outptr = outbuffer; + RiffChunkHeader riffhdr; + DS64Chunk ds64_chunk; + JunkChunk junkchunk; + WaveHeader wavhdr; + + int64_t total_data_bytes, total_riff_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 == -1) + total_samples = 0x7ffff000 / (bytes_per_sample * num_channels); + + total_data_bytes = total_samples * bytes_per_sample * num_channels; + + if (total_data_bytes > 0xff000000) { + write_junk = 0; + do_rf64 = 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, do_rf64 ? "RF64" : "RIFF", sizeof (riffhdr.ckID)); + strncpy (riffhdr.formType, "WAVE", sizeof (riffhdr.formType)); + total_riff_bytes = sizeof (riffhdr) + wavhdrsize + sizeof (datahdr) + total_data_bytes + wpc->riff_trailer_bytes; + if (do_rf64) total_riff_bytes += sizeof (ds64hdr) + sizeof (ds64_chunk); + if (write_junk) total_riff_bytes += sizeof (junkchunk); + strncpy (fmthdr.ckID, "fmt ", sizeof (fmthdr.ckID)); + strncpy (datahdr.ckID, "data", sizeof (datahdr.ckID)); + fmthdr.ckSize = wavhdrsize; + + if (write_junk) { + CLEAR (junkchunk); + strncpy (junkchunk.ckID, "junk", sizeof (junkchunk.ckID)); + junkchunk.ckSize = sizeof (junkchunk) - 8; + WavpackNativeToLittleEndian (&junkchunk, ChunkHeaderFormat); + } + + if (do_rf64) { + strncpy (ds64hdr.ckID, "ds64", sizeof (ds64hdr.ckID)); + ds64hdr.ckSize = sizeof (ds64_chunk); + CLEAR (ds64_chunk); + ds64_chunk.riffSize64 = total_riff_bytes; + ds64_chunk.dataSize64 = total_data_bytes; + ds64_chunk.sampleCount64 = total_samples; + riffhdr.ckSize = (uint32_t) -1; + datahdr.ckSize = (uint32_t) -1; + WavpackNativeToLittleEndian (&ds64hdr, ChunkHeaderFormat); + WavpackNativeToLittleEndian (&ds64_chunk, DS64ChunkFormat); + } + else { + riffhdr.ckSize = (uint32_t) total_riff_bytes; + datahdr.ckSize = (uint32_t) total_data_bytes; + } + + WavpackNativeToLittleEndian (&riffhdr, ChunkHeaderFormat); + WavpackNativeToLittleEndian (&fmthdr, ChunkHeaderFormat); + WavpackNativeToLittleEndian (&wavhdr, WaveHeaderFormat); + WavpackNativeToLittleEndian (&datahdr, ChunkHeaderFormat); + + // write the RIFF chunks up to just before the data starts + + outptr = (char *) memcpy (outptr, &riffhdr, sizeof (riffhdr)) + sizeof (riffhdr); + + if (do_rf64) { + outptr = (char *) memcpy (outptr, &ds64hdr, sizeof (ds64hdr)) + sizeof (ds64hdr); + outptr = (char *) memcpy (outptr, &ds64_chunk, sizeof (ds64_chunk)) + sizeof (ds64_chunk); + } + + if (write_junk) + outptr = (char *) memcpy (outptr, &junkchunk, sizeof (junkchunk)) + sizeof (junkchunk); + + outptr = (char *) memcpy (outptr, &fmthdr, sizeof (fmthdr)) + sizeof (fmthdr); + outptr = (char *) memcpy (outptr, &wavhdr, wavhdrsize) + wavhdrsize; + outptr = (char *) memcpy (outptr, &datahdr, sizeof (datahdr)) + sizeof (datahdr); + + return (int)(outptr - (char *) outbuffer); +} + +static int pack_streams (WavpackContext *wpc, uint32_t block_samples) +{ + uint32_t max_blocksize, bcount; + unsigned char *outbuff, *outend, *out2buff, *out2end; + int result = TRUE; + + if ((wpc->config.flags & CONFIG_FLOAT_DATA) && !(wpc->config.flags & CONFIG_SKIP_WVX)) + max_blocksize = block_samples * 16 + 4096; + else + max_blocksize = block_samples * 10 + 4096; + + 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->current_stream < wpc->num_streams; 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); + + SET_BLOCK_INDEX (wps->wphdr, 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; + + if (flags & DSD_FLAG) + result = pack_dsd_block (wpc, wps->sample_buffer); + else + result = pack_block (wpc, wps->sample_buffer); + + wps->blockbuff = wps->block2buff = NULL; + + if (wps->wphdr.block_samples != block_samples) + block_samples = wps->wphdr.block_samples; + + if (!result) { + strcpy (wpc->error_message, "output buffer overflowed!"); + break; + } + + bcount = ((WavpackHeader *) outbuff)->ckSize + 8; + WavpackNativeToLittleEndian ((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; + WavpackNativeToLittleEndian ((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) + memmove (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->ave_block_samples = (wpc->ave_block_samples * 0x7 + block_samples + 0x4) >> 3; + 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; + + WavpackLittleEndianToNative (first_block, WavpackHeaderFormat); + SET_TOTAL_SAMPLES (* (WavpackHeader *) first_block, WavpackGetSampleIndex64 (wpc)); + + if (wpc->riff_header_created && WavpackGetWrapperLocation (first_block, &wrapper_size)) { + unsigned char riff_header [128]; + + if (wrapper_size == create_riff_header (wpc, WavpackGetSampleIndex64 (wpc), riff_header)) + memcpy (WavpackGetWrapperLocation (first_block, NULL), riff_header, wrapper_size); + } + + WavpackNativeToLittleEndian (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; + + WavpackLittleEndianToNative (first_block, WavpackHeaderFormat); + loc = find_metadata (first_block, ID_RIFF_HEADER, size); + + if (!loc) + loc = find_metadata (first_block, ID_ALT_HEADER, size); + + WavpackNativeToLittleEndian (first_block, WavpackHeaderFormat); + + return loc; +} + +static void *find_metadata (void *wavpack_block, int desired_id, uint32_t *size) +{ + WavpackHeader *wphdr = wavpack_block; + unsigned char *dp, meta_id, c1, c2; + int32_t bcount, meta_bc; + + if (strncmp (wphdr->ckID, "wvpk", 4)) + return NULL; + + bcount = wphdr->ckSize - sizeof (WavpackHeader) + 8; + dp = (unsigned char *)(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 ((bcount - meta_bc) >= 0) { + if (size) + *size = meta_bc - ((meta_id & ID_ODD_SIZE) ? 1 : 0); + + return dp; + } + else + return NULL; + } + + bcount -= meta_bc; + dp += meta_bc; + } + + return NULL; +} + +int copy_metadata (WavpackMetadata *wpmd, unsigned char *buffer_start, unsigned char *buffer_end) +{ + uint32_t mdsize = wpmd->byte_length + (wpmd->byte_length & 1); + WavpackHeader *wphdr = (WavpackHeader *) buffer_start; + + 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) { + memcpy (buffer_start + (wpmd->byte_length > 510 ? 4 : 2), wpmd->data, wpmd->byte_length); + + if (wpmd->byte_length & 1) // if size is odd, make sure pad byte is a zero + buffer_start [mdsize - 1] = 0; + } + + wphdr->ckSize += mdsize; + return TRUE; +} + +static int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, unsigned char id) +{ + WavpackMetadata *mdp; + unsigned char *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) +{ + unsigned char 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) + 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; +} + +static 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); + SET_TOTAL_SAMPLES (*wphdr, 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; + WavpackNativeToLittleEndian ((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; +} + +void free_metadata (WavpackMetadata *wpmd) +{ + if (wpmd->data) { + free (wpmd->data); + wpmd->data = NULL; + } +} diff --git a/Frameworks/WavPack/Files/read_words.c b/Frameworks/WavPack/Files/read_words.c new file mode 100644 index 000000000..62acac329 --- /dev/null +++ b/Frameworks/WavPack/Files/read_words.c @@ -0,0 +1,610 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// read_words.c + +// This module provides entropy word decoding functions using +// a variation on the Rice method. This was introduced in version 3.93 +// because it allows splitting the data into a "lossy" stream and a +// "correction" stream in a very efficient manner and is therefore ideal +// for the "hybrid" mode. For 4.0, the efficiency of this method was +// significantly improved by moving away from the normal Rice restriction of +// using powers of two for the modulus divisions and now the method can be +// used for both hybrid and pure lossless encoding. + +// Samples are divided by median probabilities at 5/7 (71.43%), 10/49 (20.41%), +// and 20/343 (5.83%). Each zone has 3.5 times fewer samples than the +// previous. Using standard Rice coding on this data would result in 1.4 +// bits per sample average (not counting sign bit). However, there is a +// very simple encoding that is over 99% efficient with this data and +// results in about 1.22 bits per sample. + +#include +#include + +#include "wavpack_local.h" + +#if defined (HAVE___BUILTIN_CTZ) || defined (_WIN64) +#define USE_CTZ_OPTIMIZATION // use ctz intrinsic (or Windows equivalent) to count trailing ones +#else +#define USE_NEXT8_OPTIMIZATION // optimization using a table to count trailing ones +#endif + +#define USE_BITMASK_TABLES // use tables instead of shifting for certain masking operations + +///////////////////////////// local table storage //////////////////////////// + +#ifdef USE_NEXT8_OPTIMIZATION +static const char ones_count_table [] = { + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, + 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 +}; +#endif + +///////////////////////////// executable code //////////////////////////////// + +static uint32_t __inline read_code (Bitstream *bs, uint32_t maxcode); + +// Read the next word from the bitstream "wvbits" and return the value. This +// function can be used for hybrid or lossless streams, but since an +// optimized version is available for lossless this function would normally +// be used for hybrid only. If a hybrid lossless stream is being read then +// the "correction" offset is written at the specified pointer. A return value +// of WORD_EOF indicates that the end of the bitstream was reached (all 1s) or +// some other error occurred. + +int32_t FASTCALL get_word (WavpackStream *wps, int chan, int32_t *correction) +{ + register struct entropy_data *c = wps->w.c + chan; + uint32_t ones_count, low, mid, high; + int32_t value; + int sign; + + if (!wps->wvbits.ptr) + return WORD_EOF; + + if (correction) + *correction = 0; + + if (!(wps->w.c [0].median [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.c [1].median [0] & ~1)) { + uint32_t mask; + int cbits; + + if (wps->w.zeros_acc) { + if (--wps->w.zeros_acc) { + c->slow_level -= (c->slow_level + SLO) >> SLS; + return 0; + } + } + else { + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + wps->w.zeros_acc = cbits; + else { + for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + wps->w.zeros_acc |= mask; + + wps->w.zeros_acc |= mask; + } + + if (wps->w.zeros_acc) { + c->slow_level -= (c->slow_level + SLO) >> SLS; + CLEAR (wps->w.c [0].median); + CLEAR (wps->w.c [1].median); + return 0; + } + } + } + + if (wps->w.holding_zero) + ones_count = wps->w.holding_zero = 0; + else { +#ifdef USE_CTZ_OPTIMIZATION + while (wps->wvbits.bc < LIMIT_ONES) { + if (++(wps->wvbits.ptr) == wps->wvbits.end) + wps->wvbits.wrap (&wps->wvbits); + + wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc; + wps->wvbits.bc += sizeof (*(wps->wvbits.ptr)) * 8; + } + +#ifdef _WIN32 + _BitScanForward (&ones_count, ~wps->wvbits.sr); +#else + ones_count = __builtin_ctz (~wps->wvbits.sr); +#endif + + if (ones_count >= LIMIT_ONES) { + wps->wvbits.bc -= ones_count; + wps->wvbits.sr >>= ones_count; + + for (; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count); + + if (ones_count == (LIMIT_ONES + 1)) + return WORD_EOF; + + if (ones_count == LIMIT_ONES) { + uint32_t mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + ones_count = cbits; + else { + for (mask = 1, ones_count = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + ones_count |= mask; + + ones_count |= mask; + } + + ones_count += LIMIT_ONES; + } + } + else { + wps->wvbits.bc -= ones_count + 1; + wps->wvbits.sr >>= ones_count + 1; + } +#elif defined (USE_NEXT8_OPTIMIZATION) + int next8; + + if (wps->wvbits.bc < 8) { + if (++(wps->wvbits.ptr) == wps->wvbits.end) + wps->wvbits.wrap (&wps->wvbits); + + next8 = (wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc) & 0xff; + wps->wvbits.bc += sizeof (*(wps->wvbits.ptr)) * 8; + } + else + next8 = wps->wvbits.sr & 0xff; + + if (next8 == 0xff) { + wps->wvbits.bc -= 8; + wps->wvbits.sr >>= 8; + + for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count); + + if (ones_count == (LIMIT_ONES + 1)) + return WORD_EOF; + + if (ones_count == LIMIT_ONES) { + uint32_t mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + ones_count = cbits; + else { + for (mask = 1, ones_count = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + ones_count |= mask; + + ones_count |= mask; + } + + ones_count += LIMIT_ONES; + } + } + else { + wps->wvbits.bc -= (ones_count = ones_count_table [next8]) + 1; + wps->wvbits.sr >>= ones_count + 1; + } +#else + for (ones_count = 0; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count); + + if (ones_count >= LIMIT_ONES) { + uint32_t mask; + int cbits; + + if (ones_count == (LIMIT_ONES + 1)) + return WORD_EOF; + + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + ones_count = cbits; + else { + for (mask = 1, ones_count = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + ones_count |= mask; + + ones_count |= mask; + } + + ones_count += LIMIT_ONES; + } +#endif + + if (wps->w.holding_one) { + wps->w.holding_one = ones_count & 1; + ones_count = (ones_count >> 1) + 1; + } + else { + wps->w.holding_one = ones_count & 1; + ones_count >>= 1; + } + + wps->w.holding_zero = ~wps->w.holding_one & 1; + } + + if ((wps->wphdr.flags & HYBRID_FLAG) && !chan) + update_error_limit (wps); + + if (ones_count == 0) { + low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (ones_count == 1) { + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (ones_count == 2) { + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } + } + } + + low &= 0x7fffffff; + high &= 0x7fffffff; + mid = (high + low + 1) >> 1; + + if (!c->error_limit) + mid = read_code (&wps->wvbits, high - low) + low; + else while (high - low > c->error_limit) { + if (getbit (&wps->wvbits)) + mid = (high + (low = mid) + 1) >> 1; + else + mid = ((high = mid - 1) + low + 1) >> 1; + } + + sign = getbit (&wps->wvbits); + + if (bs_is_open (&wps->wvcbits) && c->error_limit) { + value = read_code (&wps->wvcbits, high - low) + low; + + if (correction) + *correction = sign ? (mid - value) : (value - mid); + } + + if (wps->wphdr.flags & HYBRID_BITRATE) { + c->slow_level -= (c->slow_level + SLO) >> SLS; + c->slow_level += wp_log2 (mid); + } + + return sign ? ~mid : mid; +} + +// This is an optimized version of get_word() that is used for lossless only +// (error_limit == 0). Also, rather than obtaining a single sample, it can be +// used to obtain an entire buffer of either mono or stereo samples. + +int32_t get_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples) +{ + struct entropy_data *c = wps->w.c; + uint32_t ones_count, low, high; + Bitstream *bs = &wps->wvbits; + int32_t csamples; +#ifdef USE_NEXT8_OPTIMIZATION + int32_t next8; +#endif + + if (nsamples && !bs->ptr) { + memset (buffer, 0, (wps->wphdr.flags & MONO_DATA) ? nsamples * 4 : nsamples * 8); + return nsamples; + } + + if (!(wps->wphdr.flags & MONO_DATA)) + nsamples *= 2; + + for (csamples = 0; csamples < nsamples; ++csamples) { + if (!(wps->wphdr.flags & MONO_DATA)) + c = wps->w.c + (csamples & 1); + + if (wps->w.holding_zero) { + wps->w.holding_zero = 0; + low = read_code (bs, GET_MED (0) - 1); + DEC_MED0 (); + buffer [csamples] = (getbit (bs)) ? ~low : low; + + if (++csamples == nsamples) + break; + + if (!(wps->wphdr.flags & MONO_DATA)) + c = wps->w.c + (csamples & 1); + } + + if (wps->w.c [0].median [0] < 2 && !wps->w.holding_one && wps->w.c [1].median [0] < 2) { + uint32_t mask; + int cbits; + + if (wps->w.zeros_acc) { + if (--wps->w.zeros_acc) { + buffer [csamples] = 0; + continue; + } + } + else { + for (cbits = 0; cbits < 33 && getbit (bs); ++cbits); + + if (cbits == 33) + break; + + if (cbits < 2) + wps->w.zeros_acc = cbits; + else { + for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1) + if (getbit (bs)) + wps->w.zeros_acc |= mask; + + wps->w.zeros_acc |= mask; + } + + if (wps->w.zeros_acc) { + CLEAR (wps->w.c [0].median); + CLEAR (wps->w.c [1].median); + buffer [csamples] = 0; + continue; + } + } + } + +#ifdef USE_CTZ_OPTIMIZATION + while (bs->bc < LIMIT_ONES) { + if (++(bs->ptr) == bs->end) + bs->wrap (bs); + + bs->sr |= *(bs->ptr) << bs->bc; + bs->bc += sizeof (*(bs->ptr)) * 8; + } + +#ifdef _WIN32 + _BitScanForward (&ones_count, ~wps->wvbits.sr); +#else + ones_count = __builtin_ctz (~wps->wvbits.sr); +#endif + + if (ones_count >= LIMIT_ONES) { + bs->bc -= ones_count; + bs->sr >>= ones_count; + + for (; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count); + + if (ones_count == (LIMIT_ONES + 1)) + break; + + if (ones_count == LIMIT_ONES) { + uint32_t mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (bs); ++cbits); + + if (cbits == 33) + break; + + if (cbits < 2) + ones_count = cbits; + else { + for (mask = 1, ones_count = 0; --cbits; mask <<= 1) + if (getbit (bs)) + ones_count |= mask; + + ones_count |= mask; + } + + ones_count += LIMIT_ONES; + } + } + else { + bs->bc -= ones_count + 1; + bs->sr >>= ones_count + 1; + } +#elif defined (USE_NEXT8_OPTIMIZATION) + if (bs->bc < 8) { + if (++(bs->ptr) == bs->end) + bs->wrap (bs); + + next8 = (bs->sr |= *(bs->ptr) << bs->bc) & 0xff; + bs->bc += sizeof (*(bs->ptr)) * 8; + } + else + next8 = bs->sr & 0xff; + + if (next8 == 0xff) { + bs->bc -= 8; + bs->sr >>= 8; + + for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count); + + if (ones_count == (LIMIT_ONES + 1)) + break; + + if (ones_count == LIMIT_ONES) { + uint32_t mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (bs); ++cbits); + + if (cbits == 33) + break; + + if (cbits < 2) + ones_count = cbits; + else { + for (mask = 1, ones_count = 0; --cbits; mask <<= 1) + if (getbit (bs)) + ones_count |= mask; + + ones_count |= mask; + } + + ones_count += LIMIT_ONES; + } + } + else { + bs->bc -= (ones_count = ones_count_table [next8]) + 1; + bs->sr >>= ones_count + 1; + } +#else + for (ones_count = 0; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count); + + if (ones_count >= LIMIT_ONES) { + uint32_t mask; + int cbits; + + if (ones_count == (LIMIT_ONES + 1)) + break; + + for (cbits = 0; cbits < 33 && getbit (bs); ++cbits); + + if (cbits == 33) + break; + + if (cbits < 2) + ones_count = cbits; + else { + for (mask = 1, ones_count = 0; --cbits; mask <<= 1) + if (getbit (bs)) + ones_count |= mask; + + ones_count |= mask; + } + + ones_count += LIMIT_ONES; + } +#endif + + low = wps->w.holding_one; + wps->w.holding_one = ones_count & 1; + wps->w.holding_zero = ~ones_count & 1; + ones_count = (ones_count >> 1) + low; + + if (ones_count == 0) { + low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (ones_count == 1) { + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (ones_count == 2) { + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } + } + } + + low += read_code (bs, high - low); + buffer [csamples] = (getbit (bs)) ? ~low : low; + } + + return (wps->wphdr.flags & MONO_DATA) ? csamples : (csamples / 2); +} + +// Read a single unsigned value from the specified bitstream with a value +// from 0 to maxcode. If there are exactly a power of two number of possible +// codes then this will read a fixed number of bits; otherwise it reads the +// minimum number of bits and then determines whether another bit is needed +// to define the code. + +static uint32_t __inline read_code (Bitstream *bs, uint32_t maxcode) +{ + unsigned long local_sr; + uint32_t extras, code; + int bitcount; + + if (maxcode < 2) + return maxcode ? getbit (bs) : 0; + + bitcount = count_bits (maxcode); +#ifdef USE_BITMASK_TABLES + extras = bitset [bitcount] - maxcode - 1; +#else + extras = (1 << bitcount) - maxcode - 1; +#endif + + local_sr = bs->sr; + + while (bs->bc < bitcount) { + if (++(bs->ptr) == bs->end) + bs->wrap (bs); + + local_sr |= (long)*(bs->ptr) << bs->bc; + bs->bc += sizeof (*(bs->ptr)) * 8; + } + +#ifdef USE_BITMASK_TABLES + if ((code = local_sr & bitmask [bitcount - 1]) >= extras) +#else + if ((code = local_sr & ((1 << (bitcount - 1)) - 1)) >= extras) +#endif + code = (code << 1) - extras + ((local_sr >> (bitcount - 1)) & 1); + else + bitcount--; + + if (sizeof (local_sr) < 8 && bs->bc > sizeof (local_sr) * 8) { + bs->bc -= bitcount; + bs->sr = *(bs->ptr) >> (sizeof (*(bs->ptr)) * 8 - bs->bc); + } + else { + bs->bc -= bitcount; + bs->sr = local_sr >> bitcount; + } + + return code; +} diff --git a/Frameworks/WavPack/Files/tag_utils.c b/Frameworks/WavPack/Files/tag_utils.c new file mode 100644 index 000000000..5b87eda28 --- /dev/null +++ b/Frameworks/WavPack/Files/tag_utils.c @@ -0,0 +1,597 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// tag_utils.c + +// This module provides the high-level API for creating, reading and editing +// APEv2 tags on WavPack files. Read-only support is also provided for ID3v1 +// tags, but their use is not recommended. + +#include +#include + +#include "wavpack_local.h" + +#ifdef _WIN32 +#define stricmp(x,y) _stricmp(x,y) +#else +#define stricmp strcasecmp +#endif + +static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size, int type); +static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size); +static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size, int type); +static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size); +static int append_ape_tag_item (WavpackContext *wpc, const char *item, const char *value, int vsize, int type); +static int write_tag_blockout (WavpackContext *wpc); +static int write_tag_reader (WavpackContext *wpc); +static void tagcpy (char *dest, char *src, int tag_size); +static int tagdata (char *src, int tag_size); + +//////////////////// Global functions part of external API ///////////////////////// + +// Count and return the total number of tag items in the specified file. + +int WavpackGetNumTagItems (WavpackContext *wpc) +{ + int i = 0; + + while (WavpackGetTagItemIndexed (wpc, i, NULL, 0)) + ++i; + + return i; +} + +// Count and return the total number of binary tag items in the specified file. This applies +// only to APEv2 tags and was implemented as a separate function to avoid breaking the old API. + +int WavpackGetNumBinaryTagItems (WavpackContext *wpc) +{ + int i = 0; + + while (WavpackGetBinaryTagItemIndexed (wpc, i, NULL, 0)) + ++i; + + return i; +} + +// Attempt to get the specified item from the specified file's ID3v1 or APEv2 +// tag. The "size" parameter specifies the amount of space available at "value", +// if the desired item will not fit in this space then ellipses (...) will +// be appended and the string terminated. Only text data are supported. The +// actual length of the string is returned (or 0 if no matching value found). +// Note that with APEv2 tags the length might not be the same as the number of +// characters because UTF-8 encoding is used. Also, APEv2 tags can have multiple +// (NULL separated) strings for a single value (this is why the length is +// returned). If this function is called with a NULL "value" pointer (or a +// zero "length") then only the actual length of the value data is returned +// (not counting the terminating NULL). This can be used to determine the +// actual memory to be allocated beforehand. + +int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size) +{ + M_Tag *m_tag = &wpc->m_tag; + + if (value && size) + *value = 0; + + if (m_tag->ape_tag_hdr.ID [0] == 'A') + return get_ape_tag_item (m_tag, item, value, size, APE_TAG_TYPE_TEXT); + else if (m_tag->id3_tag.tag_id [0] == 'T') + return get_id3_tag_item (m_tag, item, value, size); + else + return 0; +} + +// Attempt to get the specified binary item from the specified file's APEv2 +// tag. The "size" parameter specifies the amount of space available at "value". +// If the desired item will not fit in this space then nothing will be copied +// and 0 will be returned, otherwise the actual size will be returned. If this +// function is called with a NULL "value" pointer (or a zero "length") then only +// the actual length of the value data is returned and can be used to determine +// the actual memory to be allocated beforehand. + +int WavpackGetBinaryTagItem (WavpackContext *wpc, const char *item, char *value, int size) +{ + M_Tag *m_tag = &wpc->m_tag; + + if (value && size) + *value = 0; + + if (m_tag->ape_tag_hdr.ID [0] == 'A') + return get_ape_tag_item (m_tag, item, value, size, APE_TAG_TYPE_BINARY); + else + return 0; +} + +// This function looks up the tag item name by index and is used when the +// application wants to access all the items in the file's ID3v1 or APEv2 tag. +// Note that this function accesses only the item's name; WavpackGetTagItem() +// still must be called to get the actual value. The "size" parameter specifies +// the amount of space available at "item", if the desired item will not fit in +// this space then ellipses (...) will be appended and the string terminated. +// The actual length of the string is returned (or 0 if no item exists for +// index). If this function is called with a NULL "value" pointer (or a +// zero "length") then only the actual length of the item name is returned +// (not counting the terminating NULL). This can be used to determine the +// actual memory to be allocated beforehand. For binary tag values use the +// otherwise identical WavpackGetBinaryTagItemIndexed (); + +int WavpackGetTagItemIndexed (WavpackContext *wpc, int index, char *item, int size) +{ + M_Tag *m_tag = &wpc->m_tag; + + if (item && size) + *item = 0; + + if (m_tag->ape_tag_hdr.ID [0] == 'A') + return get_ape_tag_item_indexed (m_tag, index, item, size, APE_TAG_TYPE_TEXT); + else if (m_tag->id3_tag.tag_id [0] == 'T') + return get_id3_tag_item_indexed (m_tag, index, item, size); + else + return 0; +} + +int WavpackGetBinaryTagItemIndexed (WavpackContext *wpc, int index, char *item, int size) +{ + M_Tag *m_tag = &wpc->m_tag; + + if (item && size) + *item = 0; + + if (m_tag->ape_tag_hdr.ID [0] == 'A') + return get_ape_tag_item_indexed (m_tag, index, item, size, APE_TAG_TYPE_BINARY); + else + return 0; +} + +// These two functions are used to append APEv2 tags to WavPack files; one is +// for text values (UTF-8 encoded) and the other is for binary values. If no tag +// has been started, then an empty one will be allocated first. When finished, +// use WavpackWriteTag() to write the completed tag to the file. The purpose of +// the passed size parameter is obvious for binary values, but might not be for +// text values. Keep in mind that APEv2 text values can have multiple values +// that are NULL separated, so the size is required to know the extent of the +// value (although the final terminating NULL is not included in the passed +// size). If the specified item already exists, it will be replaced with the +// new value. ID3v1 tags are not supported. + +int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize) +{ + while (WavpackDeleteTagItem (wpc, item)); + return append_ape_tag_item (wpc, item, value, vsize, APE_TAG_TYPE_TEXT); +} + +int WavpackAppendBinaryTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize) +{ + while (WavpackDeleteTagItem (wpc, item)); + return append_ape_tag_item (wpc, item, value, vsize, APE_TAG_TYPE_BINARY); +} + +// Delete the specified tag item from the APEv2 tag on the specified WavPack file +// (fields cannot be deleted from ID3v1 tags). A return value of TRUE indicates +// that the item was found and successfully deleted. + +int WavpackDeleteTagItem (WavpackContext *wpc, const char *item) +{ + M_Tag *m_tag = &wpc->m_tag; + + if (m_tag->ape_tag_hdr.ID [0] == 'A') { + unsigned char *p = m_tag->ape_tag_data; + unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr); + int i; + + for (i = 0; i < m_tag->ape_tag_hdr.item_count; ++i) { + int vsize, isize; + + vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 8; // skip flags because we don't need them + for (isize = 0; p[isize] && p + isize < q; ++isize); + + if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q) + break; + + if (isize && vsize && !stricmp (item, (char *) p)) { + unsigned char *d = p - 8; + + p += isize + vsize + 1; + + while (p < q) + *d++ = *p++; + + m_tag->ape_tag_hdr.length = (int32_t)(d - m_tag->ape_tag_data) + sizeof (APE_Tag_Hdr); + m_tag->ape_tag_hdr.item_count--; + return 1; + } + else + p += isize + vsize + 1; + } + } + + return 0; +} + +// Once a APEv2 tag has been created with WavpackAppendTag(), this function is +// used to write the completed tag to the end of the WavPack file. Note that +// this function uses the same "blockout" function that is used to write +// regular WavPack blocks, although that's where the similarity ends. It is also +// used to write tags that have been edited on existing files. + +int WavpackWriteTag (WavpackContext *wpc) +{ + if (wpc->blockout) // this is the case for creating fresh WavPack files + return write_tag_blockout (wpc); + else // otherwise we are editing existing tags (OPEN_EDIT_TAGS) + return write_tag_reader (wpc); +} + +////////////////////////// local static functions ///////////////////////////// + +static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size, int type) +{ + unsigned char *p = m_tag->ape_tag_data; + unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr); + int i; + + for (i = 0; i < m_tag->ape_tag_hdr.item_count && q - p > 8; ++i) { + int vsize, flags, isize; + + vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4; + flags = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4; + for (isize = 0; p[isize] && p + isize < q; ++isize); + + if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q) + break; + + if (isize && vsize && !stricmp (item, (char *) p) && ((flags & 6) >> 1) == type) { + + if (!value || !size) + return vsize; + + if (type == APE_TAG_TYPE_BINARY) { + if (vsize <= size) { + memcpy (value, p + isize + 1, vsize); + return vsize; + } + else + return 0; + } + else if (vsize < size) { + memcpy (value, p + isize + 1, vsize); + value [vsize] = 0; + return vsize; + } + else if (size >= 4) { + memcpy (value, p + isize + 1, size - 1); + value [size - 4] = value [size - 3] = value [size - 2] = '.'; + value [size - 1] = 0; + return size - 1; + } + else + return 0; + } + else + p += isize + vsize + 1; + } + + return 0; +} + +static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size) +{ + char lvalue [64]; + int len; + + lvalue [0] = 0; + + if (!stricmp (item, "title")) + tagcpy (lvalue, m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title)); + else if (!stricmp (item, "artist")) + tagcpy (lvalue, m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist)); + else if (!stricmp (item, "album")) + tagcpy (lvalue, m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album)); + else if (!stricmp (item, "year")) + tagcpy (lvalue, m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year)); + else if (!stricmp (item, "comment")) + tagcpy (lvalue, m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.comment)); + else if (!stricmp (item, "track") && m_tag->id3_tag.comment [29] && !m_tag->id3_tag.comment [28]) + sprintf (lvalue, "%d", m_tag->id3_tag.comment [29]); + else + return 0; + + len = (int) strlen (lvalue); + + if (!value || !size) + return len; + + if (len < size) { + strcpy (value, lvalue); + return len; + } + else if (size >= 4) { + strncpy (value, lvalue, size - 1); + value [size - 4] = value [size - 3] = value [size - 2] = '.'; + value [size - 1] = 0; + return size - 1; + } + else + return 0; +} + +static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size, int type) +{ + unsigned char *p = m_tag->ape_tag_data; + unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr); + int i; + + for (i = 0; i < m_tag->ape_tag_hdr.item_count && index >= 0 && q - p > 8; ++i) { + int vsize, flags, isize; + + vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4; + flags = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4; + for (isize = 0; p[isize] && p + isize < q; ++isize); + + if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q) + break; + + if (isize && vsize && ((flags & 6) >> 1) == type && !index--) { + + if (!item || !size) + return isize; + + if (isize < size) { + memcpy (item, p, isize); + item [isize] = 0; + return isize; + } + else if (size >= 4) { + memcpy (item, p, size - 1); + item [size - 4] = item [size - 3] = item [size - 2] = '.'; + item [size - 1] = 0; + return size - 1; + } + else + return 0; + } + else + p += isize + vsize + 1; + } + + return 0; +} + +static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size) +{ + char lvalue [16]; + int len; + + lvalue [0] = 0; + + if (tagdata (m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title)) && !index--) + strcpy (lvalue, "Title"); + else if (tagdata (m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist)) && !index--) + strcpy (lvalue, "Artist"); + else if (tagdata (m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album)) && !index--) + strcpy (lvalue, "Album"); + else if (tagdata (m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year)) && !index--) + strcpy (lvalue, "Year"); + else if (tagdata (m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.comment)) && !index--) + strcpy (lvalue, "Comment"); + else if (m_tag->id3_tag.comment [29] && !m_tag->id3_tag.comment [28] && !index--) + strcpy (lvalue, "Track"); + else + return 0; + + len = (int) strlen (lvalue); + + if (!item || !size) + return len; + + if (len < size) { + strcpy (item, lvalue); + return len; + } + else if (size >= 4) { + strncpy (item, lvalue, size - 1); + item [size - 4] = item [size - 3] = item [size - 2] = '.'; + item [size - 1] = 0; + return size - 1; + } + else + return 0; +} + +static int append_ape_tag_item (WavpackContext *wpc, const char *item, const char *value, int vsize, int type) +{ + M_Tag *m_tag = &wpc->m_tag; + int isize = (int) strlen (item); + + if (!m_tag->ape_tag_hdr.ID [0]) { + 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 = APE_TAG_CONTAINS_HEADER; // we will include header on tags we originate + } + + if (m_tag->ape_tag_hdr.ID [0] == 'A') { + int new_item_len = vsize + isize + 9, flags = type << 1; + unsigned char *p; + + if (m_tag->ape_tag_hdr.length + new_item_len > APE_TAG_MAX_LENGTH) { + strcpy (wpc->error_message, "APEv2 tag exceeds maximum allowed length!"); + return FALSE; + } + + m_tag->ape_tag_hdr.item_count++; + m_tag->ape_tag_hdr.length += new_item_len; + p = m_tag->ape_tag_data = realloc (m_tag->ape_tag_data, m_tag->ape_tag_hdr.length); + p += m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr) - new_item_len; + + *p++ = (unsigned char) vsize; + *p++ = (unsigned char) (vsize >> 8); + *p++ = (unsigned char) (vsize >> 16); + *p++ = (unsigned char) (vsize >> 24); + + *p++ = (unsigned char) flags; + *p++ = (unsigned char) (flags >> 8); + *p++ = (unsigned char) (flags >> 16); + *p++ = (unsigned char) (flags >> 24); + + strcpy ((char *) p, item); + p += isize + 1; + memcpy (p, value, vsize); + + return TRUE; + } + else + return FALSE; +} + +// Append the stored APEv2 tag to the file being created using the "blockout" function callback. + +static int write_tag_blockout (WavpackContext *wpc) +{ + M_Tag *m_tag = &wpc->m_tag; + int result = TRUE; + + if (m_tag->ape_tag_hdr.ID [0] == 'A' && m_tag->ape_tag_hdr.item_count) { + + // only write header if it's specified in the flags + + if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER) { + m_tag->ape_tag_hdr.flags |= APE_TAG_THIS_IS_HEADER; + WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + result = wpc->blockout (wpc->wv_out, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr)); + WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + } + + if (m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr)) + result = wpc->blockout (wpc->wv_out, m_tag->ape_tag_data, m_tag->ape_tag_hdr.length - sizeof (m_tag->ape_tag_hdr)); + + m_tag->ape_tag_hdr.flags &= ~APE_TAG_THIS_IS_HEADER; // this is NOT header + WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + result = wpc->blockout (wpc->wv_out, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr)); + WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + } + + if (!result) + strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); + + return result; +} + +// Write the [potentially] edited tag to the existing WavPack file using the reader callback functions. + +static int write_tag_reader (WavpackContext *wpc) +{ + M_Tag *m_tag = &wpc->m_tag; + int32_t tag_size = 0; + int result; + + // before we write an edited (or new) tag into an existing file, make sure it's safe and possible + + if (m_tag->tag_begins_file) { + strcpy (wpc->error_message, "can't edit tags located at the beginning of files!"); + return FALSE; + } + + if (!wpc->reader->can_seek (wpc->wv_in)) { + strcpy (wpc->error_message, "can't edit tags on pipes or unseekable files!"); + return FALSE; + } + + if (!(wpc->open_flags & OPEN_EDIT_TAGS)) { + strcpy (wpc->error_message, "can't edit tags without OPEN_EDIT_TAGS flag!"); + return FALSE; + } + + if (m_tag->ape_tag_hdr.ID [0] == 'A' && m_tag->ape_tag_hdr.item_count && + m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr)) + tag_size = m_tag->ape_tag_hdr.length; + + // only write header if it's specified in the flags + + if (tag_size && (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER)) + tag_size += sizeof (m_tag->ape_tag_hdr); + + result = !wpc->reader->set_pos_rel (wpc->wv_in, m_tag->tag_file_pos, SEEK_END); + + if (result && tag_size < -m_tag->tag_file_pos && !wpc->reader->truncate_here) { + int nullcnt = (int) (-m_tag->tag_file_pos - tag_size); + char zero [1] = { 0 }; + + while (nullcnt--) + wpc->reader->write_bytes (wpc->wv_in, &zero, 1); + } + + if (result && tag_size) { + if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER) { + m_tag->ape_tag_hdr.flags |= APE_TAG_THIS_IS_HEADER; + WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + result = (wpc->reader->write_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr)) == sizeof (m_tag->ape_tag_hdr)); + WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + } + + result = (wpc->reader->write_bytes (wpc->wv_in, m_tag->ape_tag_data, m_tag->ape_tag_hdr.length - sizeof (m_tag->ape_tag_hdr)) == sizeof (m_tag->ape_tag_hdr)); + m_tag->ape_tag_hdr.flags &= ~APE_TAG_THIS_IS_HEADER; // this is NOT header + WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + result = (wpc->reader->write_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr)) == sizeof (m_tag->ape_tag_hdr)); + WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + } + + if (result && tag_size < -m_tag->tag_file_pos && wpc->reader->truncate_here) + result = !wpc->reader->truncate_here (wpc->wv_in); + + if (!result) + strcpy (wpc->error_message, "can't write WavPack data, disk probably full!"); + + return result; +} + +// Copy the specified ID3v1 tag value (with specified field size) from the +// source pointer to the destination, eliminating leading spaces and trailing +// spaces and nulls. + +static void tagcpy (char *dest, char *src, int tag_size) +{ + char *s1 = src, *s2 = src + tag_size - 1; + + if (*s2 && !s2 [-1]) + s2--; + + while (s1 <= s2) + if (*s1 == ' ') + ++s1; + else if (!*s2 || *s2 == ' ') + --s2; + else + break; + + while (*s1 && s1 <= s2) + *dest++ = *s1++; + + *dest = 0; +} + +static int tagdata (char *src, int tag_size) +{ + char *s1 = src, *s2 = src + tag_size - 1; + + if (*s2 && !s2 [-1]) + s2--; + + while (s1 <= s2) + if (*s1 == ' ') + ++s1; + else if (!*s2 || *s2 == ' ') + --s2; + else + break; + + return (*s1 && s1 <= s2); +} diff --git a/Frameworks/WavPack/Files/tags.c b/Frameworks/WavPack/Files/tags.c index 56403ecba..ce768ce3f 100644 --- a/Frameworks/WavPack/Files/tags.c +++ b/Frameworks/WavPack/Files/tags.c @@ -1,247 +1,23 @@ //////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2009 Conifer Software. // +// Copyright (c) 1998 - 2013 Conifer Software. // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// // tags.c -// This module provides support for reading and writing metadata tags. +// This module provides support for reading metadata tags (either ID3v1 or +// APEv2) from WavPack files. No actual creation or manipulation of the tags +// is done in this module; this is just internal code to load the tags into +// memory. The high-level API functions are in the tag_utils.c module. #include #include #include "wavpack_local.h" -#ifdef WIN32 -#define stricmp(x,y) _stricmp(x,y) -#define fileno _fileno -#else -#define stricmp strcasecmp -#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 - -#ifndef NO_TAGS - -static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size, int type); -static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size); -static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size, int type); -static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size); -static int append_ape_tag_item (WavpackContext *wpc, const char *item, const char *value, int vsize, int type); -static int write_tag_blockout (WavpackContext *wpc); -static int write_tag_reader (WavpackContext *wpc); -static void tagcpy (char *dest, char *src, int tag_size); -static int tagdata (char *src, int tag_size); - -//////////////////// Global functions part of external API ///////////////////////// - -// Count and return the total number of tag items in the specified file. - -int WavpackGetNumTagItems (WavpackContext *wpc) -{ - int i = 0; - - while (WavpackGetTagItemIndexed (wpc, i, NULL, 0)) - ++i; - - return i; -} - -// Count and return the total number of binary tag items in the specified file. This applies -// only to APEv2 tags and was implemented as a separate function to avoid breaking the old API. - -int WavpackGetNumBinaryTagItems (WavpackContext *wpc) -{ - int i = 0; - - while (WavpackGetBinaryTagItemIndexed (wpc, i, NULL, 0)) - ++i; - - return i; -} - -// Attempt to get the specified item from the specified file's ID3v1 or APEv2 -// tag. The "size" parameter specifies the amount of space available at "value", -// if the desired item will not fit in this space then ellipses (...) will -// be appended and the string terminated. Only text data are supported. The -// actual length of the string is returned (or 0 if no matching value found). -// Note that with APEv2 tags the length might not be the same as the number of -// characters because UTF-8 encoding is used. Also, APEv2 tags can have multiple -// (NULL separated) strings for a single value (this is why the length is -// returned). If this function is called with a NULL "value" pointer (or a -// zero "length") then only the actual length of the value data is returned -// (not counting the terminating NULL). This can be used to determine the -// actual memory to be allocated beforehand. - -int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size) -{ - M_Tag *m_tag = &wpc->m_tag; - - if (value && size) - *value = 0; - - if (m_tag->ape_tag_hdr.ID [0] == 'A') - return get_ape_tag_item (m_tag, item, value, size, APE_TAG_TYPE_TEXT); - else if (m_tag->id3_tag.tag_id [0] == 'T') - return get_id3_tag_item (m_tag, item, value, size); - else - return 0; -} - -// Attempt to get the specified binary item from the specified file's APEv2 -// tag. The "size" parameter specifies the amount of space available at "value". -// If the desired item will not fit in this space then nothing will be copied -// and 0 will be returned, otherwise the actual size will be returned. If this -// function is called with a NULL "value" pointer (or a zero "length") then only -// the actual length of the value data is returned and can be used to determine -// the actual memory to be allocated beforehand. - -int WavpackGetBinaryTagItem (WavpackContext *wpc, const char *item, char *value, int size) -{ - M_Tag *m_tag = &wpc->m_tag; - - if (value && size) - *value = 0; - - if (m_tag->ape_tag_hdr.ID [0] == 'A') - return get_ape_tag_item (m_tag, item, value, size, APE_TAG_TYPE_BINARY); - else - return 0; -} - -// This function looks up the tag item name by index and is used when the -// application wants to access all the items in the file's ID3v1 or APEv2 tag. -// Note that this function accesses only the item's name; WavpackGetTagItem() -// still must be called to get the actual value. The "size" parameter specifies -// the amount of space available at "item", if the desired item will not fit in -// this space then ellipses (...) will be appended and the string terminated. -// The actual length of the string is returned (or 0 if no item exists for -// index). If this function is called with a NULL "value" pointer (or a -// zero "length") then only the actual length of the item name is returned -// (not counting the terminating NULL). This can be used to determine the -// actual memory to be allocated beforehand. For binary tag values use the -// otherwise identical WavpackGetBinaryTagItemIndexed (); - -int WavpackGetTagItemIndexed (WavpackContext *wpc, int index, char *item, int size) -{ - M_Tag *m_tag = &wpc->m_tag; - - if (item && size) - *item = 0; - - if (m_tag->ape_tag_hdr.ID [0] == 'A') - return get_ape_tag_item_indexed (m_tag, index, item, size, APE_TAG_TYPE_TEXT); - else if (m_tag->id3_tag.tag_id [0] == 'T') - return get_id3_tag_item_indexed (m_tag, index, item, size); - else - return 0; -} - -int WavpackGetBinaryTagItemIndexed (WavpackContext *wpc, int index, char *item, int size) -{ - M_Tag *m_tag = &wpc->m_tag; - - if (item && size) - *item = 0; - - if (m_tag->ape_tag_hdr.ID [0] == 'A') - return get_ape_tag_item_indexed (m_tag, index, item, size, APE_TAG_TYPE_BINARY); - else - return 0; -} - -// These two functions are used to append APEv2 tags to WavPack files; one is -// for text values (UTF-8 encoded) and the other is for binary values. If no tag -// has been started, then an empty one will be allocated first. When finished, -// use WavpackWriteTag() to write the completed tag to the file. The purpose of -// the passed size parameter is obvious for binary values, but might not be for -// text values. Keep in mind that APEv2 text values can have multiple values -// that are NULL separated, so the size is required to know the extent of the -// value (although the final terminating NULL is not included in the passed -// size). If the specified item already exists, it will be replaced with the -// new value. ID3v1 tags are not supported. - -int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize) -{ - while (WavpackDeleteTagItem (wpc, item)); - return append_ape_tag_item (wpc, item, value, vsize, APE_TAG_TYPE_TEXT); -} - -int WavpackAppendBinaryTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize) -{ - while (WavpackDeleteTagItem (wpc, item)); - return append_ape_tag_item (wpc, item, value, vsize, APE_TAG_TYPE_BINARY); -} - -// Delete the specified tag item from the APEv2 tag on the specified WavPack file -// (fields cannot be deleted from ID3v1 tags). A return value of TRUE indicates -// that the item was found and successfully deleted. - -int WavpackDeleteTagItem (WavpackContext *wpc, const char *item) -{ - M_Tag *m_tag = &wpc->m_tag; - - if (m_tag->ape_tag_hdr.ID [0] == 'A') { - unsigned char *p = m_tag->ape_tag_data; - unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr); - int i; - - for (i = 0; i < m_tag->ape_tag_hdr.item_count; ++i) { - int vsize, isize; - - vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 8; // skip flags because we don't need them - for (isize = 0; p[isize] && p + isize < q; ++isize); - - if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q) - break; - - if (isize && vsize && !stricmp (item, (char *) p)) { - unsigned char *d = p - 8; - - p += isize + vsize + 1; - - while (p < q) - *d++ = *p++; - - m_tag->ape_tag_hdr.length = (int32_t)(d - m_tag->ape_tag_data) + sizeof (APE_Tag_Hdr); - m_tag->ape_tag_hdr.item_count--; - return 1; - } - else - p += isize + vsize + 1; - } - } - - return 0; -} - -// Once a APEv2 tag has been created with WavpackAppendTag(), this function is -// used to write the completed tag to the end of the WavPack file. Note that -// this function uses the same "blockout" function that is used to write -// regular WavPack blocks, although that's where the similarity ends. It is also -// used to write tags that have been edited on existing files. - -int WavpackWriteTag (WavpackContext *wpc) -{ - if (wpc->blockout) // this is the case for creating fresh WavPack files - return write_tag_blockout (wpc); - else // otherwise we are editing existing tags (OPEN_EDIT_TAGS) - return write_tag_reader (wpc); -} - -//////// Utility functions provided to other modules (but not part of lib API) ///////// - // 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 @@ -278,7 +54,7 @@ int load_tag (WavpackContext *wpc) 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); + WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); if (m_tag->ape_tag_hdr.version == 2000 && m_tag->ape_tag_hdr.item_count && m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr) && @@ -315,7 +91,7 @@ int load_tag (WavpackContext *wpc) return FALSE; // something's wrong... } - little_endian_to_native (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); + WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); if (m_tag->ape_tag_hdr.version != 2000 || m_tag->ape_tag_hdr.item_count != ape_tag_items || m_tag->ape_tag_hdr.length != ape_tag_length) { @@ -401,366 +177,3 @@ void free_tag (M_Tag *m_tag) m_tag->ape_tag_data = NULL; } } - -////////////////////////// local static functions ///////////////////////////// - -static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size, int type) -{ - unsigned char *p = m_tag->ape_tag_data; - unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr); - int i; - - for (i = 0; i < m_tag->ape_tag_hdr.item_count && q - p > 8; ++i) { - int vsize, flags, isize; - - vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4; - flags = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4; - for (isize = 0; p[isize] && p + isize < q; ++isize); - - if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q) - break; - - if (isize && vsize && !stricmp (item, (char *) p) && ((flags & 6) >> 1) == type) { - - if (!value || !size) - return vsize; - - if (type == APE_TAG_TYPE_BINARY) { - if (vsize <= size) { - memcpy (value, p + isize + 1, vsize); - return vsize; - } - else - return 0; - } - else if (vsize < size) { - memcpy (value, p + isize + 1, vsize); - value [vsize] = 0; - return vsize; - } - else if (size >= 4) { - memcpy (value, p + isize + 1, size - 1); - value [size - 4] = value [size - 3] = value [size - 2] = '.'; - value [size - 1] = 0; - return size - 1; - } - else - return 0; - } - else - p += isize + vsize + 1; - } - - return 0; -} - -static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size) -{ - char lvalue [64]; - int len; - - lvalue [0] = 0; - - if (!stricmp (item, "title")) - tagcpy (lvalue, m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title)); - else if (!stricmp (item, "artist")) - tagcpy (lvalue, m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist)); - else if (!stricmp (item, "album")) - tagcpy (lvalue, m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album)); - else if (!stricmp (item, "year")) - tagcpy (lvalue, m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year)); - else if (!stricmp (item, "comment")) - tagcpy (lvalue, m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.comment)); - else if (!stricmp (item, "track") && m_tag->id3_tag.comment [29] && !m_tag->id3_tag.comment [28]) - sprintf (lvalue, "%d", m_tag->id3_tag.comment [29]); - else - return 0; - - len = (int) strlen (lvalue); - - if (!value || !size) - return len; - - if (len < size) { - strcpy (value, lvalue); - return len; - } - else if (size >= 4) { - strncpy (value, lvalue, size - 1); - value [size - 4] = value [size - 3] = value [size - 2] = '.'; - value [size - 1] = 0; - return size - 1; - } - else - return 0; -} - -static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size, int type) -{ - unsigned char *p = m_tag->ape_tag_data; - unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr); - int i; - - for (i = 0; i < m_tag->ape_tag_hdr.item_count && index >= 0 && q - p > 8; ++i) { - int vsize, flags, isize; - - vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4; - flags = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4; - for (isize = 0; p[isize] && p + isize < q; ++isize); - - if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q) - break; - - if (isize && vsize && ((flags & 6) >> 1) == type && !index--) { - - if (!item || !size) - return isize; - - if (isize < size) { - memcpy (item, p, isize); - item [isize] = 0; - return isize; - } - else if (size >= 4) { - memcpy (item, p, size - 1); - item [size - 4] = item [size - 3] = item [size - 2] = '.'; - item [size - 1] = 0; - return size - 1; - } - else - return 0; - } - else - p += isize + vsize + 1; - } - - return 0; -} - -static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size) -{ - char lvalue [16]; - int len; - - lvalue [0] = 0; - - if (tagdata (m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title)) && !index--) - strcpy (lvalue, "Title"); - else if (tagdata (m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist)) && !index--) - strcpy (lvalue, "Artist"); - else if (tagdata (m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album)) && !index--) - strcpy (lvalue, "Album"); - else if (tagdata (m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year)) && !index--) - strcpy (lvalue, "Year"); - else if (tagdata (m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.comment)) && !index--) - strcpy (lvalue, "Comment"); - else if (m_tag->id3_tag.comment [29] && !m_tag->id3_tag.comment [28] && !index--) - strcpy (lvalue, "Track"); - else - return 0; - - len = (int) strlen (lvalue); - - if (!item || !size) - return len; - - if (len < size) { - strcpy (item, lvalue); - return len; - } - else if (size >= 4) { - strncpy (item, lvalue, size - 1); - item [size - 4] = item [size - 3] = item [size - 2] = '.'; - item [size - 1] = 0; - return size - 1; - } - else - return 0; -} - -static int append_ape_tag_item (WavpackContext *wpc, const char *item, const char *value, int vsize, int type) -{ - M_Tag *m_tag = &wpc->m_tag; - int isize = (int) strlen (item); - - if (!m_tag->ape_tag_hdr.ID [0]) { - 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 = APE_TAG_CONTAINS_HEADER; // we will include header on tags we originate - } - - if (m_tag->ape_tag_hdr.ID [0] == 'A') { - int new_item_len = vsize + isize + 9, flags = type << 1; - unsigned char *p; - - if (m_tag->ape_tag_hdr.length + new_item_len > APE_TAG_MAX_LENGTH) { - strcpy (wpc->error_message, "APEv2 tag exceeds maximum allowed length!"); - return FALSE; - } - - m_tag->ape_tag_hdr.item_count++; - m_tag->ape_tag_hdr.length += new_item_len; - p = m_tag->ape_tag_data = realloc (m_tag->ape_tag_data, m_tag->ape_tag_hdr.length); - p += m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr) - new_item_len; - - *p++ = (unsigned char) vsize; - *p++ = (unsigned char) (vsize >> 8); - *p++ = (unsigned char) (vsize >> 16); - *p++ = (unsigned char) (vsize >> 24); - - *p++ = (unsigned char) flags; - *p++ = (unsigned char) (flags >> 8); - *p++ = (unsigned char) (flags >> 16); - *p++ = (unsigned char) (flags >> 24); - - strcpy ((char *) p, item); - p += isize + 1; - memcpy (p, value, vsize); - - return TRUE; - } - else - return FALSE; -} - -static int write_tag_blockout (WavpackContext *wpc) -{ - M_Tag *m_tag = &wpc->m_tag; - int result = TRUE; - - if (m_tag->ape_tag_hdr.ID [0] == 'A' && m_tag->ape_tag_hdr.item_count) { - - // only write header if it's specified in the flags - - if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER) { - m_tag->ape_tag_hdr.flags |= APE_TAG_THIS_IS_HEADER; - 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 &= ~APE_TAG_THIS_IS_HEADER; // this is NOT header - 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; - int32_t tag_size = 0; - int result; - - // before we write an edited (or new) tag into an existing file, make sure it's safe and possible - - if (m_tag->tag_begins_file) { - strcpy (wpc->error_message, "can't edit tags located at the beginning of files!"); - return FALSE; - } - - if (!wpc->reader->can_seek (wpc->wv_in)) { - strcpy (wpc->error_message, "can't edit tags on pipes or unseekable files!"); - return FALSE; - } - - if (!(wpc->open_flags & OPEN_EDIT_TAGS)) { - strcpy (wpc->error_message, "can't edit tags without OPEN_EDIT_TAGS flag!"); - return FALSE; - } - - if (m_tag->ape_tag_hdr.ID [0] == 'A' && m_tag->ape_tag_hdr.item_count && - m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr)) - tag_size = m_tag->ape_tag_hdr.length; - - // only write header if it's specified in the flags - - if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER) - tag_size += sizeof (m_tag->ape_tag_hdr); - - result = !wpc->reader->set_pos_rel (wpc->wv_in, m_tag->tag_file_pos, SEEK_END); - - if (result && tag_size < -m_tag->tag_file_pos) { - 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) { - if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER) { - m_tag->ape_tag_hdr.flags |= APE_TAG_THIS_IS_HEADER; - 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 &= ~APE_TAG_THIS_IS_HEADER; // this is NOT header - 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; -} - -// 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 - diff --git a/Frameworks/WavPack/Files/unpack.c b/Frameworks/WavPack/Files/unpack.c index 86e288fc1..4dace135f 100644 --- a/Frameworks/WavPack/Files/unpack.c +++ b/Frameworks/WavPack/Files/unpack.c @@ -1,468 +1,56 @@ //////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // +// Copyright (c) 1998 - 2013 Conifer Software. // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// // unpack.c -// This module actually handles the decompression of the audio data, except -// for the entropy decoding which is handled by the words? modules. For -// maximum efficiency, the conversion is isolated to tight loops that handle -// an entire buffer. +// This module actually handles the decompression of the audio data, except for +// the entropy decoding which is handled by the read_words.c module. For better +// efficiency, the conversion is isolated to tight loops that handle an entire +// buffer. + +#include +#include #include "wavpack_local.h" -#include -#include -#include -#include +#ifdef OPT_ASM_X86 + #define DECORR_STEREO_PASS_CONT unpack_decorr_stereo_pass_cont_x86 + #define DECORR_STEREO_PASS_CONT_AVAILABLE unpack_cpu_has_feature_x86(CPU_FEATURE_MMX) + #define DECORR_MONO_PASS_CONT unpack_decorr_mono_pass_cont_x86 +#elif defined(OPT_ASM_X64) && (defined (_WIN64) || defined(__CYGWIN__) || defined(__MINGW64__)) + #define DECORR_STEREO_PASS_CONT unpack_decorr_stereo_pass_cont_x64win + #define DECORR_STEREO_PASS_CONT_AVAILABLE 1 + #define DECORR_MONO_PASS_CONT unpack_decorr_mono_pass_cont_x64win +#elif defined(OPT_ASM_X64) + #define DECORR_STEREO_PASS_CONT unpack_decorr_stereo_pass_cont_x64 + #define DECORR_STEREO_PASS_CONT_AVAILABLE 1 + #define DECORR_MONO_PASS_CONT unpack_decorr_mono_pass_cont_x64 +#elif defined(OPT_ASM_ARM) + #define DECORR_STEREO_PASS_CONT unpack_decorr_stereo_pass_cont_armv7 + #define DECORR_STEREO_PASS_CONT_AVAILABLE 1 + #define DECORR_MONO_PASS_CONT unpack_decorr_mono_pass_cont_armv7 +#endif -// This flag provides faster decoding speed at the expense of more code. The -// improvement applies to 16-bit stereo lossless only. +#ifdef DECORR_STEREO_PASS_CONT +extern void DECORR_STEREO_PASS_CONT (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count, int32_t long_math); +extern void DECORR_MONO_PASS_CONT (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count, int32_t long_math); +#endif -#define FAST_DECODE +// This flag provides the functionality of terminating the decoding and muting +// the output when a lossy sample appears to be corrupt. This is automatic +// for lossless files because a corrupt sample is unambigious, but for lossy +// data it might be possible for this to falsely trigger (although I have never +// seen it). #define LOSSY_MUTE -#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]; - unsigned char *blockptr, *block2ptr; - WavpackMetadata wpmd; - - 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); - - if (!(wps->wphdr.flags & MONO_FLAG) && wpc->config.num_channels && wps->wphdr.block_samples && - (wpc->reduced_channels == 1 || wpc->config.num_channels == 1)) { - wps->mute_error = TRUE; - return FALSE; - } - - if ((wps->wphdr.flags & UNKNOWN_FLAGS) || (wps->wphdr.flags & MONO_DATA) == MONO_DATA) { - wps->mute_error = TRUE; - return FALSE; - } - - blockptr = wps->blockbuff + sizeof (WavpackHeader); - - while (read_metadata_buff (&wpmd, wps->blockbuff, &blockptr)) - if (!process_metadata (wpc, &wpmd)) { - wps->mute_error = TRUE; - return FALSE; - } - - if (wps->wphdr.block_samples && wpc->wvc_flag && wps->block2buff) { - block2ptr = wps->block2buff + sizeof (WavpackHeader); - - while (read_metadata_buff (&wpmd, wps->block2buff, &block2ptr)) - if (!process_metadata (wpc, &wpmd)) { - wps->mute_error = TRUE; - 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!"); - - wps->mute_error = TRUE; - 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; - } - - if (wps->wphdr.block_samples) - wps->sample_index = wps->wphdr.block_index; - - 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) -{ - if (!wpmd->byte_length) - return FALSE; - - bs_open_read (&wps->wvbits, wpmd->data, (unsigned 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) -{ - if (!wpmd->byte_length) - return FALSE; - - bs_open_read (&wps->wvcbits, wpmd->data, (unsigned 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) -{ - unsigned char *cp = wpmd->data; - - if (wpmd->byte_length <= 4) - return FALSE; - - 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, (unsigned 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; - unsigned char *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) -{ - unsigned char *byteptr = wpmd->data; - unsigned char *endptr = byteptr + wpmd->byte_length; - struct decorr_pass *dpp; - int tcount; - - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { - CLEAR (dpp->samples_A); - CLEAR (dpp->samples_B); - } - - if (wps->wphdr.version == 0x402 && (wps->wphdr.flags & HYBRID_FLAG)) { - if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) - return FALSE; - - wps->dc.error [0] = 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) { - if (byteptr + (wps->wphdr.flags & MONO_DATA ? 4 : 8) > endptr) - return FALSE; - - 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) { - if (byteptr + 4 > endptr) - return FALSE; - - 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--) { - if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) - return FALSE; - - 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)) { - unsigned char *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; - unsigned char *byteptr = wpmd->data; - uint32_t mask = 0; - - if (!bytecnt || bytecnt > 6) - return FALSE; - - if (!wpc->config.num_channels) { - - if (bytecnt == 6) { - wpc->config.num_channels = (byteptr [0] | ((byteptr [2] & 0xf) << 8)) + 1; - wpc->max_streams = (byteptr [1] | ((byteptr [2] & 0xf0) << 4)) + 1; - - if (wpc->config.num_channels < wpc->max_streams) - return FALSE; - - byteptr += 3; - mask = *byteptr++; - mask |= (uint32_t) *byteptr++ << 8; - mask |= (uint32_t) *byteptr << 16; - } - else { - wpc->config.num_channels = *byteptr++; - - while (--bytecnt) { - mask |= (uint32_t) *byteptr++ << shift; - shift += 8; - } - } - - if (wpc->config.num_channels > wpc->max_streams * 2) - return FALSE; - - 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; - unsigned char *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; - - if (bytecnt >= 4 && (wpc->config.flags & CONFIG_EXTRA_MODE)) - wpc->config.xmode = *byteptr; - } - - return TRUE; -} - -// Read non-standard sampling rate from metadata. - -int read_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd) -{ - int bytecnt = wpmd->byte_length; - unsigned char *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_bytes < MAX_WRAPPER_BYTES) { - 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; -} - -#ifndef NO_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 @@ -480,24 +68,26 @@ int read_wrapper_data (WavpackContext *wpc, WavpackMetadata *wpmd) // 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_1717 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); -static void decorr_stereo_pass_1718 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); -static void decorr_stereo_pass_1818 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); -static void decorr_stereo_pass_nn (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_mono_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); static void fixup_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count); int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count) { WavpackStream *wps = wpc->streams [wpc->current_stream]; uint32_t flags = wps->wphdr.flags, crc = wps->crc, i; - int32_t mute_limit = (int32_t)((1L << ((flags & MAG_MASK) >> MAG_LSB)) + 2); + 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; + // don't attempt to decode past the end of the block, but watch out for overflow! + + if (wps->sample_index + sample_count > GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples && + GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index < sample_count) + sample_count = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index); + + if (GET_BLOCK_INDEX (wps->wphdr) > wps->sample_index || wps->wphdr.block_samples < sample_count) + wps->mute_error = TRUE; if (wps->mute_error) { if (wpc->reduced_channels == 1 || wpc->config.num_channels == 1 || (flags & MONO_FLAG)) @@ -510,7 +100,7 @@ int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_co } if ((flags & HYBRID_FLAG) && !wps->block2buff) - mute_limit *= 2; + mute_limit = (mute_limit * 2) + 128; //////////////// handle lossless or hybrid lossy mono data ///////////////// @@ -529,39 +119,34 @@ int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_co else i = get_words_lossless (wps, buffer, sample_count); - for (bptr = buffer; bptr < eptr;) { - read_word = *bptr; - +#ifdef DECORR_MONO_PASS_CONT + if (sample_count < 16) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + decorr_mono_pass (dpp, buffer, sample_count); + else for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { - int32_t sam, temp; - int k; + int pre_samples = (dpp->term > MAX_TERM) ? 2 : dpp->term; - if (dpp->term > MAX_TERM) { - if (dpp->term & 1) - sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - else - sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); + decorr_mono_pass (dpp, buffer, pre_samples); - 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; + DECORR_MONO_PASS_CONT (dpp, buffer + pre_samples, sample_count - pre_samples, + ((flags & MAG_MASK) >> MAG_LSB) > 15); } +#else + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + decorr_mono_pass (dpp, buffer, sample_count); +#endif - if (labs (read_word) > mute_limit) { +#ifndef LOSSY_MUTE + if (!(flags & HYBRID_FLAG)) +#endif + for (bptr = buffer; bptr < eptr; ++bptr) { + if (labs (bptr [0]) > mute_limit) { i = (uint32_t)(bptr - buffer); break; } - m = (m + 1) & (MAX_TERM - 1); - crc += (crc << 1) + (*bptr++ = read_word); + crc = crc * 3 + bptr [0]; } } @@ -583,36 +168,27 @@ int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_co else i = get_words_lossless (wps, buffer, sample_count); -#ifdef FAST_DECODE - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - if (((flags & MAG_MASK) >> MAG_LSB) >= 16) +#ifdef DECORR_STEREO_PASS_CONT + if (sample_count < 16 || !DECORR_STEREO_PASS_CONT_AVAILABLE) { + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) decorr_stereo_pass (dpp, buffer, sample_count); - else if (tcount && dpp [0].term == 17 && dpp [1].term == 17) { - decorr_stereo_pass_1717 (dpp, buffer, sample_count); - tcount--; - dpp++; + + m = sample_count & (MAX_TERM - 1); + } + else + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int pre_samples = (dpp->term < 0 || dpp->term > MAX_TERM) ? 2 : dpp->term; + + decorr_stereo_pass (dpp, buffer, pre_samples); + + DECORR_STEREO_PASS_CONT (dpp, buffer + pre_samples * 2, sample_count - pre_samples, + ((flags & MAG_MASK) >> MAG_LSB) >= 16); } - else if (tcount && dpp [0].term == 17 && dpp [1].term == 18) { - decorr_stereo_pass_1718 (dpp, buffer, sample_count); - tcount--; - dpp++; - } - else if (tcount && dpp [0].term == 18 && dpp [1].term == 18) { - decorr_stereo_pass_1818 (dpp, buffer, sample_count); - tcount--; - dpp++; - } - else if (tcount && dpp [0].term >= 1 && dpp [0].term <= 7 && - dpp [1].term >= 1 && dpp [1].term <= 7) { - decorr_stereo_pass_nn (dpp, buffer, sample_count); - tcount--; - dpp++; - } - else - decorr_stereo_pass_i (dpp, buffer, sample_count); #else for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) decorr_stereo_pass (dpp, buffer, sample_count); + + m = sample_count & (MAX_TERM - 1); #endif if (flags & JOINT_STEREO) @@ -624,13 +200,14 @@ int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_co for (bptr = buffer; bptr < eptr; bptr += 2) crc += (crc << 3) + (bptr [0] << 1) + bptr [0] + bptr [1]; +#ifndef LOSSY_MUTE + if (!(flags & HYBRID_FLAG)) +#endif for (bptr = buffer; bptr < eptr; bptr += 16) if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { i = (uint32_t)(bptr - buffer) / 2; break; } - - m = sample_count & (MAX_TERM - 1); } /////////////////// handle hybrid lossless mono data //////////////////// @@ -686,10 +263,9 @@ int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_co crc += (crc << 1) + read_word; -#ifdef LOSSY_MUTE if (labs (read_word) > mute_limit) break; -#endif + *bptr++ = read_word; } @@ -858,10 +434,9 @@ int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_co right = right_c; } -#ifdef LOSSY_MUTE if (labs (left) > mute_limit || labs (right) > mute_limit) break; -#endif + crc += (crc << 3) + (left << 1) + left + right; *bptr++ = left; *bptr++ = right; @@ -917,6 +492,67 @@ int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_co return i; } +// General function to perform mono decorrelation pass on specified buffer +// (although since this is the reverse function it might technically be called +// "correlation" instead). This version handles all sample resolutions and +// weight deltas. The dpp->samples_X[] data is returned normalized for term +// values 1-8. + +static void decorr_mono_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t delta = dpp->delta, weight_A = dpp->weight_A; + int32_t *bptr, *eptr = buffer + sample_count, sam_A; + int m, k; + + switch (dpp->term) { + + case 17: + for (bptr = buffer; bptr < eptr; bptr++) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0]; + update_weight (weight_A, delta, sam_A, bptr [0]); + bptr [0] = dpp->samples_A [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr++) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0]; + update_weight (weight_A, delta, sam_A, bptr [0]); + bptr [0] = dpp->samples_A [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr++) { + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = apply_weight (weight_A, sam_A) + bptr [0]; + update_weight (weight_A, delta, sam_A, bptr [0]); + bptr [0] = dpp->samples_A [k]; + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + if (m) { + int32_t temp_samples [MAX_TERM]; + + memcpy (temp_samples, dpp->samples_A, sizeof (dpp->samples_A)); + + for (k = 0; k < MAX_TERM; k++, m++) + dpp->samples_A [k] = temp_samples [m & (MAX_TERM - 1)]; + } + + break; + } + + dpp->weight_A = weight_A; +} + // General function to perform stereo decorrelation pass on specified buffer // (although since this is the reverse function it might technically be called // "correlation" instead). This version handles all sample resolutions and @@ -1028,245 +664,6 @@ static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_ } } -#ifdef FAST_DECODE - -// This function is a specialized version of decorr_stereo_pass() that works -// only with lower resolution data (<= 16-bit), but is otherwise identical. - -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); - int m, k; - - switch (dpp->term) { - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam, tmp; - - sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_A [1] = dpp->samples_A [0]; - bptr [0] = dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam) + (tmp = bptr [0]); - update_weight (dpp->weight_A, dpp->delta, sam, tmp); - - sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - dpp->samples_B [1] = dpp->samples_B [0]; - bptr [1] = dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam) + (tmp = bptr [1]); - update_weight (dpp->weight_B, dpp->delta, sam, tmp); - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam, tmp; - - sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); - dpp->samples_A [1] = dpp->samples_A [0]; - bptr [0] = dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam) + (tmp = bptr [0]); - update_weight (dpp->weight_A, dpp->delta, sam, tmp); - - sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); - dpp->samples_B [1] = dpp->samples_B [0]; - bptr [1] = dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam) + (tmp = bptr [1]); - update_weight (dpp->weight_B, dpp->delta, sam, tmp); - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam; - - sam = dpp->samples_A [m]; - dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam) + bptr [0]; - update_weight (dpp->weight_A, dpp->delta, sam, bptr [0]); - bptr [0] = dpp->samples_A [k]; - - sam = dpp->samples_B [m]; - dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam) + bptr [1]; - update_weight (dpp->weight_B, dpp->delta, sam, bptr [1]); - bptr [1] = dpp->samples_B [k]; - - m = (m + 1) & (MAX_TERM - 1); - k = (k + 1) & (MAX_TERM - 1); - } - - break; - - case -1: - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam; - - sam = bptr [0] + apply_weight_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; - dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam); - update_weight_clip (dpp->weight_B, dpp->delta, sam, bptr [1]); - bptr [1] = dpp->samples_A [0]; - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam; - - sam = bptr [1] + apply_weight_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; - dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam); - update_weight_clip (dpp->weight_A, dpp->delta, sam, bptr [0]); - bptr [0] = dpp->samples_B [0]; - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam_A, sam_B; - - sam_A = bptr [0] + apply_weight_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; - } -} - -// These functions are specialized versions of decorr_stereo_pass() that work -// only with lower resolution data (<= 16-bit) and handle the equivalent of -// *two* decorrelation passes. By combining two passes we save a read and write -// of the sample data and some overhead dealing with buffer pointers and looping. -// -// The cases handled are: -// 17,17 -- standard "fast" mode before version 4.40 -// 17,18 -- standard "fast" mode starting with 4.40 -// 18,18 -- used in the default and higher modes -// [1-7],[1-7] -- common in "high" and "very high" modes - -static void decorr_stereo_pass_1718 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2); - - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam; - - sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam) + bptr [0]; - update_weight (dpp->weight_A, dpp->delta, sam, bptr [0]); - - sam = (dpp+1)->samples_A [0] + (((dpp+1)->samples_A [0] - (dpp+1)->samples_A [1]) >> 1); - (dpp+1)->samples_A [1] = (dpp+1)->samples_A [0]; - bptr [0] = (dpp+1)->samples_A [0] = apply_weight_i ((dpp+1)->weight_A, sam) + dpp->samples_A [0]; - update_weight ((dpp+1)->weight_A, (dpp+1)->delta, sam, dpp->samples_A [0]); - - sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam) + bptr [1]; - update_weight (dpp->weight_B, dpp->delta, sam, bptr [1]); - - sam = (dpp+1)->samples_B [0] + (((dpp+1)->samples_B [0] - (dpp+1)->samples_B [1]) >> 1); - (dpp+1)->samples_B [1] = (dpp+1)->samples_B [0]; - bptr [1] = (dpp+1)->samples_B [0] = apply_weight_i ((dpp+1)->weight_B, sam) + dpp->samples_B [0]; - update_weight ((dpp+1)->weight_B, (dpp+1)->delta, sam, dpp->samples_B [0]); - } -} - -static void decorr_stereo_pass_1717 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2); - - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam; - - sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam) + bptr [0]; - update_weight (dpp->weight_A, dpp->delta, sam, bptr [0]); - - sam = 2 * (dpp+1)->samples_A [0] - (dpp+1)->samples_A [1]; - (dpp+1)->samples_A [1] = (dpp+1)->samples_A [0]; - bptr [0] = (dpp+1)->samples_A [0] = apply_weight_i ((dpp+1)->weight_A, sam) + dpp->samples_A [0]; - update_weight ((dpp+1)->weight_A, (dpp+1)->delta, sam, dpp->samples_A [0]); - - sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam) + bptr [1]; - update_weight (dpp->weight_B, dpp->delta, sam, bptr [1]); - - sam = 2 * (dpp+1)->samples_B [0] - (dpp+1)->samples_B [1]; - (dpp+1)->samples_B [1] = (dpp+1)->samples_B [0]; - bptr [1] = (dpp+1)->samples_B [0] = apply_weight_i ((dpp+1)->weight_B, sam) + dpp->samples_B [0]; - update_weight ((dpp+1)->weight_B, (dpp+1)->delta, sam, dpp->samples_B [0]); - } -} - -static void decorr_stereo_pass_1818 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2); - - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t sam; - - sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam) + bptr [0]; - update_weight (dpp->weight_A, dpp->delta, sam, bptr [0]); - - sam = (dpp+1)->samples_A [0] + (((dpp+1)->samples_A [0] - (dpp+1)->samples_A [1]) >> 1); - (dpp+1)->samples_A [1] = (dpp+1)->samples_A [0]; - bptr [0] = (dpp+1)->samples_A [0] = apply_weight_i ((dpp+1)->weight_A, sam) + dpp->samples_A [0]; - update_weight ((dpp+1)->weight_A, (dpp+1)->delta, sam, dpp->samples_A [0]); - - sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam) + bptr [1]; - update_weight (dpp->weight_B, dpp->delta, sam, bptr [1]); - - sam = (dpp+1)->samples_B [0] + (((dpp+1)->samples_B [0] - (dpp+1)->samples_B [1]) >> 1); - (dpp+1)->samples_B [1] = (dpp+1)->samples_B [0]; - bptr [1] = (dpp+1)->samples_B [0] = apply_weight_i ((dpp+1)->weight_B, sam) + dpp->samples_B [0]; - update_weight ((dpp+1)->weight_B, (dpp+1)->delta, sam, dpp->samples_B [0]); - } -} - -static void decorr_stereo_pass_nn (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) -{ - int32_t *bptr, *eptr = buffer + (sample_count * 2); - int m, k, j; - - m = 0; - k = dpp->term & (MAX_TERM - 1); - j = (dpp+1)->term & (MAX_TERM - 1); - - for (bptr = buffer; bptr < eptr; bptr += 2) { - int32_t tmp; - - dpp->samples_A [k] = apply_weight_i (dpp->weight_A, dpp->samples_A [m]) + (tmp = bptr [0]); - update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [m], tmp); - - bptr [0] = (dpp+1)->samples_A [j] = apply_weight_i ((dpp+1)->weight_A, (dpp+1)->samples_A [m]) + (tmp = dpp->samples_A [k]); - update_weight ((dpp+1)->weight_A, (dpp+1)->delta, (dpp+1)->samples_A [m], tmp); - - dpp->samples_B [k] = apply_weight_i (dpp->weight_B, dpp->samples_B [m]) + (tmp = bptr [1]); - update_weight (dpp->weight_B, dpp->delta, dpp->samples_B [m], tmp); - - bptr [1] = (dpp+1)->samples_B [j] = apply_weight_i ((dpp+1)->weight_B, (dpp+1)->samples_B [m]) + (tmp = dpp->samples_B [k]); - update_weight ((dpp+1)->weight_B, (dpp+1)->delta, (dpp+1)->samples_B [m], tmp); - - m = (m + 1) & (MAX_TERM - 1); - k = (k + 1) & (MAX_TERM - 1); - j = (j + 1) & (MAX_TERM - 1); - } -} - -#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. @@ -1413,5 +810,3 @@ int check_crc_error (WavpackContext *wpc) return result; } - -#endif diff --git a/Frameworks/WavPack/Files/unpack3.c b/Frameworks/WavPack/Files/unpack3.c index d425f8f53..cc99a672c 100644 --- a/Frameworks/WavPack/Files/unpack3.c +++ b/Frameworks/WavPack/Files/unpack3.c @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // +// Copyright (c) 1998 - 2013 Conifer Software. // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// @@ -12,387 +12,22 @@ // 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. +// 3.97 source code. Note that this module does only the low-level sample +// unpacking; the actual opening of the file (and obtaining information +// from it) is handled in the unpack3_open.c module. #include -#include #include -#include #include "wavpack_local.h" #include "unpack3.h" #define ATTEMPT_ERROR_MUTING -#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); -#ifndef NO_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; - - CLEAR (wavhdr); - wpc->stream3 = wps = (WavpackStream3 *) malloc (sizeof (WavpackStream3)); - CLEAR (*wps); - - if (wpc->reader->read_bytes (wpc->wv_in, &RiffChunkHeader, sizeof (RiffChunkHeader)) != - sizeof (RiffChunkHeader)) { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - if (!strncmp (RiffChunkHeader.ckID, "RIFF", 4) && !strncmp (RiffChunkHeader.formType, "WAVE", 4)) { - - if (wpc->open_flags & OPEN_WRAPPER) { - wpc->wrapper_data = malloc (wpc->wrapper_bytes = sizeof (RiffChunkHeader)); - memcpy (wpc->wrapper_data, &RiffChunkHeader, sizeof (RiffChunkHeader)); - } - - // If the first chunk is a wave RIFF header, then read the various chunks - // until we get to the "data" chunk (and WavPack header should follow). If - // the first chunk is not a RIFF, then we assume a "raw" WavPack file and - // the WavPack header must be first. - - while (1) { - - if (wpc->reader->read_bytes (wpc->wv_in, &ChunkHeader, sizeof (ChunkHeader)) != - sizeof (ChunkHeader)) { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - else { - if (wpc->open_flags & OPEN_WRAPPER) { - wpc->wrapper_data = 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)) { - if (error) 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 (bytes_to_skip > 1024 * 1024) { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - if (wpc->open_flags & OPEN_WRAPPER) { - wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip); - wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip); - wpc->wrapper_bytes += bytes_to_skip; - } - else { - unsigned char *temp = malloc (bytes_to_skip); - wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); - free (temp); - } - } - } - else if (!strncmp (ChunkHeader.ckID, "data", 4)) - break; - else if ((ChunkHeader.ckSize + 1) & ~1L) { - uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1) & ~1L; - - if (bytes_to_skip > 1024 * 1024) { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - if (wpc->open_flags & OPEN_WRAPPER) { - wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip); - wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip); - wpc->wrapper_bytes += bytes_to_skip; - } - else { - unsigned char *temp = malloc (bytes_to_skip); - wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); - free (temp); - } - } - } - } - } - else { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - if (wavhdr.FormatTag != 1 || !wavhdr.NumChannels || wavhdr.NumChannels > 2 || - !wavhdr.SampleRate || wavhdr.BitsPerSample < 16 || wavhdr.BitsPerSample > 24 || - wavhdr.BlockAlign / wavhdr.NumChannels > 3 || wavhdr.BlockAlign % wavhdr.NumChannels || - wavhdr.BlockAlign / wavhdr.NumChannels < (wavhdr.BitsPerSample + 7) / 8) { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - wpc->total_samples = ChunkHeader.ckSize / wavhdr.NumChannels / - ((wavhdr.BitsPerSample > 16) ? 3 : 2); - - if (wpc->reader->read_bytes (wpc->wv_in, &wphdr, 10) != 10) { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - if (((char *) &wphdr) [8] == 2 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10, 2) != 2)) { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - else if (((char *) &wphdr) [8] == 3 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10, - sizeof (wphdr) - 10) != sizeof (wphdr) - 10)) { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - 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) { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - // Because I ran out of flag bits in the WavPack header, an amazingly ugly - // kludge was forced upon me! This code takes care of preparing the flags - // field for internal use and checking for unknown formats we can't decode - - if (wphdr.version == 3) { - - if (wphdr.flags & EXTREME_DECORR) { - - if ((wphdr.flags & NOT_STORED_FLAGS) || - ((wphdr.bits) && - (((wphdr.flags & NEW_HIGH_FLAG) && - (wphdr.flags & (FAST_FLAG | HIGH_FLAG))) || - (wphdr.flags & CROSS_DECORR)))) { - if (error) strcpy (error, "not a valid WavPack file!"); - return WavpackCloseFile (wpc); - } - - if (wphdr.flags & CANCEL_EXTREME) - wphdr.flags &= ~(EXTREME_DECORR | CANCEL_EXTREME); - } - else - wphdr.flags &= ~CROSS_DECORR; - } - - // check to see if we should look for a "correction" file, and if so try - // to open it for reading, then set WVC_FLAG accordingly - - if (wpc->wvc_in && wphdr.version == 3 && wphdr.bits && (wphdr.flags & NEW_HIGH_FLAG)) { - wpc->file2len = wpc->reader->get_length (wpc->wvc_in); - wphdr.flags |= WVC_FLAG; - wpc->wvc_flag = TRUE; - } - else - wphdr.flags &= ~WVC_FLAG; - - // check WavPack version to handle special requirements of versions - // before 3.0 that had smaller headers - - if (wphdr.version < 3) { - wphdr.total_samples = wpc->total_samples; - wphdr.flags = wavhdr.NumChannels == 1 ? MONO_FLAG : 0; - wphdr.shift = 16 - wavhdr.BitsPerSample; - - if (wphdr.version == 1) - wphdr.bits = 0; - } - - wpc->config.sample_rate = wavhdr.SampleRate; - wpc->config.num_channels = wavhdr.NumChannels; - wpc->config.channel_mask = 5 - wavhdr.NumChannels; - - if (wphdr.flags & MONO_FLAG) - wpc->config.flags |= CONFIG_MONO_FLAG; - - if (wphdr.flags & EXTREME_DECORR) - wpc->config.flags |= CONFIG_HIGH_FLAG; - - if (wphdr.bits) { - if (wphdr.flags & NEW_HIGH_FLAG) - wpc->config.flags |= CONFIG_HYBRID_FLAG; - else - wpc->config.flags |= CONFIG_LOSSY_MODE; - } - else if (!(wphdr.flags & HIGH_FLAG)) - wpc->config.flags |= CONFIG_FAST_FLAG; - - wpc->config.bytes_per_sample = (wphdr.flags & BYTES_3) ? 3 : 2; - wpc->config.bits_per_sample = wavhdr.BitsPerSample; - - memcpy (&wps->wphdr, &wphdr, sizeof (wphdr)); - wps->wvbits.bufsiz = wps->wvcbits.bufsiz = 1024 * 1024; - return wpc; -} - -// return currently decoded sample index - -uint32_t get_sample_index3 (WavpackContext *wpc) -{ - WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; - - return (wps) ? wps->sample_index : (uint32_t) -1; -} - -int get_version3 (WavpackContext *wpc) -{ - WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; - - return (wps) ? wps->wphdr.version : 0; -} - -void free_stream3 (WavpackContext *wpc) -{ - WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; - - if (wps) { -#ifndef NO_SEEKING - if (wps->unpack_data) - free (wps->unpack_data); -#endif - if (wps->wphdr.flags & WVC_FLAG) - 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 = (unsigned char *) 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; -} - -#ifndef NO_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. - -static void bs_restore3 (Bitstream3 *bs) -{ - uint32_t bytes_to_read = (uint32_t)(bs->end - bs->ptr - 1), bytes_read; - - bs->reader->set_pos_abs (bs->id, bs->fpos - bytes_to_read); - - if (bytes_to_read > 0) { - - bytes_read = bs->reader->read_bytes (bs->id, bs->ptr + 1, bytes_to_read); - - if (bytes_to_read != bytes_read) - bs->end = bs->ptr + 1 + bytes_read; - } -} - -#endif - -// 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 (uint32_t)(bs->end - bs->ptr); -} - -static unsigned char *bs_unused_data (Bitstream3 *bs) -{ - if (bs->bc < 8) { - bs->bc += 8; - bs->ptr++; - } - - return bs->ptr; -} - -#ifndef NO_UNPACK +static int bs_open_read3 (Bitstream3 *bs, WavpackStreamReader64 *reader, void *id); +static uint32_t bs_unused_bytes (Bitstream3 *bs); +static unsigned char *bs_unused_data (Bitstream3 *bs); +static void init_words3 (WavpackStream3 *wps); //////////////////////////////// local macros ///////////////////////////////// @@ -426,13 +61,13 @@ static const signed char extreme_terms [] = { 1,1,1,2,4,-1,1,2,3,6,-2,8,5,7,4,1, static const signed char default_terms [] = { 1,1,1,-1,2,1,-2 }; static const signed char simple_terms [] = { 1,1,1,1 }; +///////////////////////////// executable code //////////////////////////////// + // 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) +void unpack_init3 (WavpackStream3 *wps) { int flags = wps->wphdr.flags; struct decorr_pass *dpp; @@ -461,9 +96,6 @@ static void unpack_init3 (WavpackStream3 *wps) #ifndef NO_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. @@ -504,8 +136,7 @@ static int unpack_size (WavpackStream3 *wps) } if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - { + 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); @@ -574,8 +205,7 @@ static void *unpack_save (WavpackStream3 *wps, void *destin) } if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - { + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { if (dpp->term > 0) { int count = dpp->term; int index = wps->dc.m; @@ -610,175 +240,6 @@ static void *unpack_save (WavpackStream3 *wps, void *destin) 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; - unsigned char *temp_buf; - - unpack_init3 (wps); - temp_file = wps->wvbits.id; - temp_buf = wps->wvbits.buf; - RESTORE (wps->wvbits, source); - - if (keep_resources) { - wps->wvbits.id = temp_file; - wps->wvbits.ptr += temp_buf - wps->wvbits.buf; - wps->wvbits.end += temp_buf - wps->wvbits.buf; - wps->wvbits.buf = temp_buf; - } - - bs_restore3 (&wps->wvbits); - - if (flags & WVC_FLAG) { - temp_file = wps->wvcbits.id; - temp_buf = wps->wvcbits.buf; - RESTORE (wps->wvcbits, source); - - if (keep_resources) { - wps->wvcbits.id = temp_file; - wps->wvcbits.ptr += temp_buf - wps->wvcbits.buf; - wps->wvcbits.end += temp_buf - wps->wvcbits.buf; - wps->wvcbits.buf = temp_buf; - } - - bs_restore3 (&wps->wvcbits); - } - - if (wps->wphdr.version == 3) { - if (wps->wphdr.bits) { - RESTORE (wps->w4, source); - } - else { - RESTORE (wps->w1, source); - } - - RESTORE (wps->w3, source); - RESTORE (wps->dc.crc, source); - } - else - RESTORE (wps->w2, source); - - if (wps->wphdr.bits) { - RESTORE (wps->dc.error, source); - } - else { - RESTORE (wps->dc.sum_level, source); - RESTORE (wps->dc.left_level, source); - RESTORE (wps->dc.right_level, source); - RESTORE (wps->dc.diff_level, source); - } - - if (flags & OVER_20) { - RESTORE (wps->dc.last_extra_bits, source); - RESTORE (wps->dc.extra_bits_count, source); - } - - if (!(flags & EXTREME_DECORR)) { - RESTORE (wps->dc.sample, source); - RESTORE (wps->dc.weight, source); - } - - if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - { - if (dpp->term > 0) { - int count = dpp->term; - int index = wps->dc.m; - - RESTORE (dpp->weight_A, source); - - while (count--) { - RESTORE (dpp->samples_A [index], source); - index = (index + 1) & (MAX_TERM - 1); - } - - if (!(flags & MONO_FLAG)) { - count = dpp->term; - index = wps->dc.m; - - RESTORE (dpp->weight_B, source); - - while (count--) { - RESTORE (dpp->samples_B [index], source); - index = (index + 1) & (MAX_TERM - 1); - } - } - } - else { - RESTORE (dpp->weight_A, source); - RESTORE (dpp->weight_B, source); - RESTORE (dpp->samples_A [0], source); - RESTORE (dpp->samples_B [0], source); - } - } - - return source; -} - -// This 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 @@ -803,7 +264,7 @@ int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_c WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; int shift = wps->wphdr.shift, flags = wps->wphdr.flags, min_weight = 0, m = wps->dc.m, tcount; #ifndef NO_SEEKING - int points_index = wps->sample_index / ((wpc->total_samples >> 8) + 1); + int points_index = wps->sample_index / (((uint32_t) wpc->total_samples >> 8) + 1); #endif int32_t min_value, max_value, min_shifted, max_shifted; int32_t correction [2], crc = wps->dc.crc; @@ -826,7 +287,7 @@ int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_c #endif if (wps->sample_index + sample_count > wpc->total_samples) - sample_count = wpc->total_samples - wps->sample_index; + sample_count = (uint32_t) (wpc->total_samples - wps->sample_index); if (!sample_count) return 0; @@ -1107,10 +568,10 @@ int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_c diff = left - right; } - sum_level = (int32_t)(sum_level - (sum_level >> 8) + labs (sum >> 1)); - left_level = (int32_t)(left_level - (left_level >> 8) + labs (left)); - right_level = (int32_t)(right_level - (right_level >> 8) + labs (right)); - diff_level = (int32_t)(diff_level - (diff_level >> 8) + labs (diff)); + 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; @@ -1236,9 +697,9 @@ int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_c sum = right + left; } - sum_level = (int32_t)(sum_level - (sum_level >> 8) + labs (sum >> 1)); - left_level = (int32_t)(left_level - (left_level >> 8) + labs (left)); - right_level = (int32_t)(right_level - (right_level >> 8) + labs (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); 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; @@ -1721,7 +1182,7 @@ int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_c } while (1) { - bcount = wpc->reader->read_bytes (wpc->wv_in, temp, sizeof (temp)); + bcount = wpc->reader->read_bytes (wpc->wv_in, temp, 1024); if (!bcount) break; @@ -1739,7 +1200,7 @@ int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_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); + memmove (wpc->wrapper_data, wpc->wrapper_data + 16, wpc->wrapper_bytes - 16); wpc->wrapper_bytes -= 16; } else { @@ -1759,12 +1220,6 @@ int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_c 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. @@ -1781,18 +1236,6 @@ static void init_words3 (WavpackStream3 *wps) 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; @@ -1974,12 +1417,12 @@ static int32_t FASTCALL get_word2 (WavpackStream3 *wps, int chan) return 0L; if (wps->wphdr.bits) { - for (value = (int32_t)(1L << (dbits - 1)); --dbits; mask <<= 1) + for (value = 1L << (dbits - 1); --dbits; mask <<= 1) if (dbits < wps->wphdr.bits && getbit (&wps->wvbits)) value |= mask; } else - for (value = (int32_t)(1L << (dbits - 1)); --dbits; mask <<= 1) + for (value = 1L << (dbits - 1); --dbits; mask <<= 1) if (getbit (&wps->wvbits)) value |= mask; @@ -2039,7 +1482,7 @@ static int32_t FASTCALL get_word3 (WavpackStream3 *wps, int chan) } } -static int FASTCALL _log2 (uint32_t avalue); +static int FASTCALL wp3_log2 (uint32_t avalue); static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *correction) { @@ -2082,22 +1525,22 @@ static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *corre 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); + wps->w4.bits_acc [0] += wps->w4.bitrate + wp3_log2 (wps->w4.fast_level [0]) - wp3_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]); + slow_log_0 = wp3_log2 (wps->w4.slow_level [0]); + slow_log_1 = wp3_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); + wps->w4.bits_acc [0] += wps->w4.bitrate - balance + wp3_log2 (wps->w4.fast_level [0]) - slow_log_0 + (3 << 8); + wps->w4.bits_acc [1] += wps->w4.bitrate + balance + wp3_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; @@ -2140,7 +1583,7 @@ static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *corre } wps->w4.fast_level [chan] -= ((wps->w4.fast_level [chan] + 0x10) >> 5); - wps->w4.fast_level [chan] += (avalue = (int32_t) labs (mid)); + 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; @@ -2149,7 +1592,7 @@ static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *corre if (high != low) { uint32_t maxcode = high - low; int bitcount = count_bits (maxcode); - uint32_t extras = (uint32_t)((1L << bitcount) - maxcode - 1); + uint32_t extras = (1L << bitcount) - maxcode - 1; getbits (&avalue, bitcount - 1, &wps->wvcbits); avalue &= bitmask [bitcount - 1]; @@ -2177,7 +1620,7 @@ static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *corre // 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) +static int FASTCALL wp3_log2 (uint32_t avalue) { int dbits; @@ -2197,5 +1640,60 @@ static int FASTCALL _log2 (uint32_t avalue) } } -#endif +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, WavpackStreamReader64 *reader, void *id) +{ + bs->fpos = (bs->reader = reader)->get_pos (bs->id = id); + + if (!bs->buf) + bs->buf = (unsigned char *) 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; +} + +static uint32_t bs_unused_bytes (Bitstream3 *bs) +{ + if (bs->bc < 8) { + bs->bc += 8; + bs->ptr++; + } + + return (uint32_t)(bs->end - bs->ptr); +} + +static unsigned char *bs_unused_data (Bitstream3 *bs) +{ + if (bs->bc < 8) { + bs->bc += 8; + bs->ptr++; + } + + return bs->ptr; +} diff --git a/Frameworks/WavPack/Files/unpack3.h b/Frameworks/WavPack/Files/unpack3.h index cf3ca0e8d..ae351f839 100644 --- a/Frameworks/WavPack/Files/unpack3.h +++ b/Frameworks/WavPack/Files/unpack3.h @@ -12,9 +12,9 @@ // decoding old (versions 1, 2 & 3) WavPack files. typedef struct { - unsigned short FormatTag, NumChannels; + uint16_t FormatTag, NumChannels; uint32_t SampleRate, BytesPerSecond; - unsigned short BlockAlign, BitsPerSample; + uint16_t BlockAlign, BitsPerSample; } WaveHeader3; #define WaveHeader3Format "SSLLSS" @@ -22,9 +22,9 @@ typedef struct { 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 + int16_t version; + int16_t bits; // added for version 2.00 + int16_t flags, shift; // added for version 3.00 int32_t total_samples, crc, crc2; char extension [4], extra_bc, extras [3]; } WavpackHeader3; @@ -62,8 +62,9 @@ typedef struct { typedef struct bs3 { void (*wrap)(struct bs3 *bs); unsigned char *buf, *end, *ptr; - uint32_t bufsiz, fpos, sr; - WavpackStreamReader *reader; + uint32_t bufsiz, sr; + int64_t fpos; + WavpackStreamReader64 *reader; int error, bc; void *id; } Bitstream3; @@ -111,3 +112,8 @@ typedef struct { int bits_acc [2], bitrate; } w4; } WavpackStream3; + +#define SAVE(destin, item) { memcpy (destin, &item, sizeof (item)); destin = (char *) destin + sizeof (item); } +#define RESTORE(item, source) { memcpy (&item, source, sizeof (item)); source = (char *) source + sizeof (item); } + +void unpack_init3 (WavpackStream3 *wps); diff --git a/Frameworks/WavPack/Files/unpack3_open.c b/Frameworks/WavPack/Files/unpack3_open.c new file mode 100644 index 000000000..39f548e8c --- /dev/null +++ b/Frameworks/WavPack/Files/unpack3_open.c @@ -0,0 +1,285 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack3_open.c + +// This module provides an extension to the open_utils.c module for handling +// WavPack files prior to version 4.0, not including "raw" files. As these +// modes are all obsolete and are no longer written, this code will not be +// fully documented other than the global functions. However, full documenation +// is provided in the version 3.97 source code. Note that this module only +// provides the functionality of opening the files and obtaining information +// from them; the actual audio decoding is located in the unpack3.c module. + +#include +#include + +#include "wavpack_local.h" +#include "unpack3.h" + +#define ATTEMPT_ERROR_MUTING + +// This provides an extension to the WavpackOpenFileRead () function contained +// in the wputils.c module. It is assumed that an 'R' had been read as the +// first character of the file/stream (indicating a non-raw pre version 4.0 +// WavPack file) and had been pushed back onto the stream (or simply seeked +// back to). + +WavpackContext *open_file3 (WavpackContext *wpc, char *error) +{ + RiffChunkHeader RiffChunkHeader; + ChunkHeader ChunkHeader; + WavpackHeader3 wphdr; + WavpackStream3 *wps; + WaveHeader3 wavhdr; + + CLEAR (wavhdr); + wpc->stream3 = wps = (WavpackStream3 *) malloc (sizeof (WavpackStream3)); + CLEAR (*wps); + + if (wpc->reader->read_bytes (wpc->wv_in, &RiffChunkHeader, sizeof (RiffChunkHeader)) != + sizeof (RiffChunkHeader)) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (!strncmp (RiffChunkHeader.ckID, "RIFF", 4) && !strncmp (RiffChunkHeader.formType, "WAVE", 4)) { + + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = malloc (wpc->wrapper_bytes = sizeof (RiffChunkHeader)); + memcpy (wpc->wrapper_data, &RiffChunkHeader, sizeof (RiffChunkHeader)); + } + + // If the first chunk is a wave RIFF header, then read the various chunks + // until we get to the "data" chunk (and WavPack header should follow). If + // the first chunk is not a RIFF, then we assume a "raw" WavPack file and + // the WavPack header must be first. + + while (1) { + + if (wpc->reader->read_bytes (wpc->wv_in, &ChunkHeader, sizeof (ChunkHeader)) != + sizeof (ChunkHeader)) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + else { + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (ChunkHeader)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &ChunkHeader, sizeof (ChunkHeader)); + wpc->wrapper_bytes += sizeof (ChunkHeader); + } + + WavpackLittleEndianToNative (&ChunkHeader, ChunkHeaderFormat); + + if (!strncmp (ChunkHeader.ckID, "fmt ", 4)) { + + if (ChunkHeader.ckSize < sizeof (wavhdr) || + wpc->reader->read_bytes (wpc->wv_in, &wavhdr, sizeof (wavhdr)) != sizeof (wavhdr)) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + else if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (wavhdr)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &wavhdr, sizeof (wavhdr)); + wpc->wrapper_bytes += sizeof (wavhdr); + } + + WavpackLittleEndianToNative (&wavhdr, WaveHeader3Format); + + if (ChunkHeader.ckSize > sizeof (wavhdr)) { + uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1 - sizeof (wavhdr)) & ~1L; + + if (bytes_to_skip > 1024 * 1024) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip); + wpc->wrapper_bytes += bytes_to_skip; + } + else { + unsigned char *temp = malloc (bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); + free (temp); + } + } + } + else if (!strncmp (ChunkHeader.ckID, "data", 4)) + break; + else if ((ChunkHeader.ckSize + 1) & ~1L) { + uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1) & ~1L; + + if (bytes_to_skip > 1024 * 1024) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip); + wpc->wrapper_bytes += bytes_to_skip; + } + else { + unsigned char *temp = malloc (bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); + free (temp); + } + } + } + } + } + else { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wavhdr.FormatTag != 1 || !wavhdr.NumChannels || wavhdr.NumChannels > 2 || + !wavhdr.SampleRate || wavhdr.BitsPerSample < 16 || wavhdr.BitsPerSample > 24 || + wavhdr.BlockAlign / wavhdr.NumChannels > 3 || wavhdr.BlockAlign % wavhdr.NumChannels || + wavhdr.BlockAlign / wavhdr.NumChannels < (wavhdr.BitsPerSample + 7) / 8) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + wpc->total_samples = ChunkHeader.ckSize / wavhdr.NumChannels / + ((wavhdr.BitsPerSample > 16) ? 3 : 2); + + if (wpc->reader->read_bytes (wpc->wv_in, &wphdr, 10) != 10) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (((char *) &wphdr) [8] == 2 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10, 2) != 2)) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + else if (((char *) &wphdr) [8] == 3 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10, + sizeof (wphdr) - 10) != sizeof (wphdr) - 10)) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + WavpackLittleEndianToNative (&wphdr, WavpackHeader3Format); + + // make sure this is a version we know about + + if (strncmp (wphdr.ckID, "wvpk", 4) || wphdr.version < 1 || wphdr.version > 3) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + // Because I ran out of flag bits in the WavPack header, an amazingly ugly + // kludge was forced upon me! This code takes care of preparing the flags + // field for internal use and checking for unknown formats we can't decode + + if (wphdr.version == 3) { + + if (wphdr.flags & EXTREME_DECORR) { + + if ((wphdr.flags & NOT_STORED_FLAGS) || + ((wphdr.bits) && + (((wphdr.flags & NEW_HIGH_FLAG) && + (wphdr.flags & (FAST_FLAG | HIGH_FLAG))) || + (wphdr.flags & CROSS_DECORR)))) { + if (error) strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wphdr.flags & CANCEL_EXTREME) + wphdr.flags &= ~(EXTREME_DECORR | CANCEL_EXTREME); + } + else + wphdr.flags &= ~CROSS_DECORR; + } + + // check to see if we should look for a "correction" file, and if so try + // to open it for reading, then set WVC_FLAG accordingly + + if (wpc->wvc_in && wphdr.version == 3 && wphdr.bits && (wphdr.flags & NEW_HIGH_FLAG)) { + wpc->file2len = wpc->reader->get_length (wpc->wvc_in); + wphdr.flags |= WVC_FLAG; + wpc->wvc_flag = TRUE; + } + else + wphdr.flags &= ~WVC_FLAG; + + // check WavPack version to handle special requirements of versions + // before 3.0 that had smaller headers + + if (wphdr.version < 3) { + wphdr.total_samples = (int32_t) wpc->total_samples; + wphdr.flags = wavhdr.NumChannels == 1 ? MONO_FLAG : 0; + wphdr.shift = 16 - wavhdr.BitsPerSample; + + if (wphdr.version == 1) + wphdr.bits = 0; + } + + wpc->config.sample_rate = wavhdr.SampleRate; + wpc->config.num_channels = wavhdr.NumChannels; + wpc->config.channel_mask = 5 - wavhdr.NumChannels; + + if (wphdr.flags & MONO_FLAG) + wpc->config.flags |= CONFIG_MONO_FLAG; + + if (wphdr.flags & EXTREME_DECORR) + wpc->config.flags |= CONFIG_HIGH_FLAG; + + if (wphdr.bits) { + if (wphdr.flags & NEW_HIGH_FLAG) + wpc->config.flags |= CONFIG_HYBRID_FLAG; + else + wpc->config.flags |= CONFIG_LOSSY_MODE; + } + else if (!(wphdr.flags & HIGH_FLAG)) + wpc->config.flags |= CONFIG_FAST_FLAG; + + wpc->config.bytes_per_sample = (wphdr.flags & BYTES_3) ? 3 : 2; + wpc->config.bits_per_sample = wavhdr.BitsPerSample; + + memcpy (&wps->wphdr, &wphdr, sizeof (wphdr)); + wps->wvbits.bufsiz = wps->wvcbits.bufsiz = 1024 * 1024; + return wpc; +} + +// return currently decoded sample index + +uint32_t get_sample_index3 (WavpackContext *wpc) +{ + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + + return (wps) ? wps->sample_index : (uint32_t) -1; +} + +int get_version3 (WavpackContext *wpc) +{ + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + + return (wps) ? wps->wphdr.version : 0; +} + +void free_stream3 (WavpackContext *wpc) +{ + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + + if (wps) { +#ifndef NO_SEEKING + if (wps->unpack_data) + free (wps->unpack_data); +#endif + if ((wps->wphdr.flags & WVC_FLAG) && wps->wvcbits.buf) + free (wps->wvcbits.buf); + + if (wps->wvbits.buf) + free (wps->wvbits.buf); + + free (wps); + } +} diff --git a/Frameworks/WavPack/Files/unpack3_seek.c b/Frameworks/WavPack/Files/unpack3_seek.c new file mode 100644 index 000000000..ffe1ded0a --- /dev/null +++ b/Frameworks/WavPack/Files/unpack3_seek.c @@ -0,0 +1,210 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack3_seek.c + +// This module provides seeking support for WavPack files prior to version 4.0. + +#ifndef NO_SEEKING + +#include +#include + +#include "wavpack_local.h" +#include "unpack3.h" + +static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources); +static void bs_restore3 (Bitstream3 *bs); + +// This is an extension for WavpackSeekSample (). Note that because WavPack +// files created prior to version 4.0 are not inherently seekable, this +// function could take a long time if a forward seek is requested to an +// area that has not been played (or seeked through) yet. + +int seek_sample3 (WavpackContext *wpc, uint32_t desired_index) +{ + int points_index = desired_index / (((uint32_t) wpc->total_samples >> 8) + 1); + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + + if (desired_index >= wpc->total_samples) + return FALSE; + + while (points_index) + if (wps->index_points [points_index].saved && + wps->index_points [points_index].sample_index <= desired_index) + break; + else + points_index--; + + if (wps->index_points [points_index].saved) + if (wps->index_points [points_index].sample_index > wps->sample_index || + wps->sample_index > desired_index) { + wps->sample_index = wps->index_points [points_index].sample_index; + unpack_restore (wps, wps->unpack_data + points_index * wps->unpack_size, TRUE); + } + + if (desired_index > wps->sample_index) { + int32_t *buffer = (int32_t *) malloc (1024 * (wps->wphdr.flags & MONO_FLAG ? 4 : 8)); + uint32_t samples_to_skip = desired_index - wps->sample_index; + + while (1) { + if (samples_to_skip > 1024) { + if (unpack_samples3 (wpc, buffer, 1024) == 1024) + samples_to_skip -= 1024; + else + break; + } + else { + samples_to_skip -= unpack_samples3 (wpc, buffer, samples_to_skip); + break; + } + } + + free (buffer); + + if (samples_to_skip) + return FALSE; + } + + return TRUE; +} + +// This function restores the unpacking context from the specified pointer +// and returns the updated pointer. After this call, unpack_samples() will +// continue where it left off immediately before unpack_save() was called. +// If the WavPack files and bitstreams might have been closed and reopened, +// then the "keep_resources" flag should be set to avoid using the "old" +// resources that were originally saved (and are probably now invalid). + +static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources) +{ + int flags = wps->wphdr.flags, tcount; + struct decorr_pass *dpp; + FILE *temp_file; + unsigned char *temp_buf; + + unpack_init3 (wps); + temp_file = wps->wvbits.id; + temp_buf = wps->wvbits.buf; + RESTORE (wps->wvbits, source); + + if (keep_resources) { + wps->wvbits.id = temp_file; + wps->wvbits.ptr += temp_buf - wps->wvbits.buf; + wps->wvbits.end += temp_buf - wps->wvbits.buf; + wps->wvbits.buf = temp_buf; + } + + bs_restore3 (&wps->wvbits); + + if (flags & WVC_FLAG) { + temp_file = wps->wvcbits.id; + temp_buf = wps->wvcbits.buf; + RESTORE (wps->wvcbits, source); + + if (keep_resources) { + wps->wvcbits.id = temp_file; + wps->wvcbits.ptr += temp_buf - wps->wvcbits.buf; + wps->wvcbits.end += temp_buf - wps->wvcbits.buf; + wps->wvcbits.buf = temp_buf; + } + + bs_restore3 (&wps->wvcbits); + } + + if (wps->wphdr.version == 3) { + if (wps->wphdr.bits) { + RESTORE (wps->w4, source); + } + else { + RESTORE (wps->w1, source); + } + + RESTORE (wps->w3, source); + RESTORE (wps->dc.crc, source); + } + else + RESTORE (wps->w2, source); + + if (wps->wphdr.bits) { + RESTORE (wps->dc.error, source); + } + else { + RESTORE (wps->dc.sum_level, source); + RESTORE (wps->dc.left_level, source); + RESTORE (wps->dc.right_level, source); + RESTORE (wps->dc.diff_level, source); + } + + if (flags & OVER_20) { + RESTORE (wps->dc.last_extra_bits, source); + RESTORE (wps->dc.extra_bits_count, source); + } + + if (!(flags & EXTREME_DECORR)) { + RESTORE (wps->dc.sample, source); + RESTORE (wps->dc.weight, source); + } + + if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + if (dpp->term > 0) { + int count = dpp->term; + int index = wps->dc.m; + + RESTORE (dpp->weight_A, source); + + while (count--) { + RESTORE (dpp->samples_A [index], source); + index = (index + 1) & (MAX_TERM - 1); + } + + if (!(flags & MONO_FLAG)) { + count = dpp->term; + index = wps->dc.m; + + RESTORE (dpp->weight_B, source); + + while (count--) { + RESTORE (dpp->samples_B [index], source); + index = (index + 1) & (MAX_TERM - 1); + } + } + } + else { + RESTORE (dpp->weight_A, source); + RESTORE (dpp->weight_B, source); + RESTORE (dpp->samples_A [0], source); + RESTORE (dpp->samples_B [0], source); + } + } + + return source; +} + +// This function is called after a call to unpack_restore() has restored +// the BitStream structure to a previous state and causes any required data +// to be read from the file. This function is NOT supported for overlapped +// operation. + +static void bs_restore3 (Bitstream3 *bs) +{ + uint32_t bytes_to_read = (uint32_t)(bs->end - bs->ptr - 1), bytes_read; + + bs->reader->set_pos_abs (bs->id, bs->fpos - bytes_to_read); + + if (bytes_to_read > 0) { + + bytes_read = bs->reader->read_bytes (bs->id, bs->ptr + 1, bytes_to_read); + + if (bytes_to_read != bytes_read) + bs->end = bs->ptr + 1 + bytes_read; + } +} + +#endif diff --git a/Frameworks/WavPack/Files/unpack_dsd.c b/Frameworks/WavPack/Files/unpack_dsd.c new file mode 100644 index 000000000..0a33d96f1 --- /dev/null +++ b/Frameworks/WavPack/Files/unpack_dsd.c @@ -0,0 +1,539 @@ +//////////////////////////////////////////////////////////////////////////// +// **** DSDPACK **** // +// Lossless DSD (Direct Stream Digital) Audio Compressor // +// Copyright (c) 2013 - 2016 David Bryant. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack_dsd.c + +// This module actually handles the uncompression of the DSD audio data. + +#include +#include +#include + +#include "wavpack_local.h" + +///////////////////////////// executable code //////////////////////////////// + +// This function initialzes the main range-encoded data for DSD audio samples + +static int init_dsd_block_fast (WavpackStream *wps, WavpackMetadata *wpmd); +static int init_dsd_block_high (WavpackStream *wps, WavpackMetadata *wpmd); +static int decode_fast (WavpackStream *wps, int32_t *output, int sample_count); +static int decode_high (WavpackStream *wps, int32_t *output, int sample_count); + +int init_dsd_block (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + if (wpmd->byte_length < 2) + return FALSE; + + wps->dsd.byteptr = wpmd->data; + wps->dsd.endptr = wps->dsd.byteptr + wpmd->byte_length; + wpc->dsd_multiplier = 1 << *wps->dsd.byteptr++; + wps->dsd.mode = *wps->dsd.byteptr++; + + if (!wps->dsd.mode) { + if (wps->dsd.endptr - wps->dsd.byteptr != wps->wphdr.block_samples * (wps->wphdr.flags & MONO_DATA ? 1 : 2)) { + return FALSE; + } + + wps->dsd.ready = 1; + return TRUE; + } + + if (wps->dsd.mode == 1) + return init_dsd_block_fast (wps, wpmd); + else if (wps->dsd.mode == 2) + return init_dsd_block_high (wps, wpmd); + else + return FALSE; +} + +int32_t unpack_dsd_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags, crc = wps->crc; + + // don't attempt to decode past the end of the block, but watch out for overflow! + + if (wps->sample_index + sample_count > GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples && + GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index < sample_count) + sample_count = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index); + + if (GET_BLOCK_INDEX (wps->wphdr) > wps->sample_index || wps->wphdr.block_samples < sample_count) + wps->mute_error = TRUE; + + if (!wps->mute_error) { + if (!wps->dsd.mode) { + int total_samples = sample_count * ((flags & MONO_DATA) ? 1 : 2); + int32_t *bptr = buffer; + + if (wps->dsd.endptr - wps->dsd.byteptr < total_samples) + total_samples = (int)(wps->dsd.endptr - wps->dsd.byteptr); + + while (total_samples--) + wps->crc += (wps->crc << 1) + (*bptr++ = *wps->dsd.byteptr++); + } + else if (wps->dsd.mode == 1) { + if (!decode_fast (wps, buffer, sample_count)) + wps->mute_error = TRUE; + } + else if (!decode_high (wps, buffer, sample_count)) + wps->mute_error = TRUE; + } + + if (wps->mute_error) { + int samples_to_null; + if (wpc->reduced_channels == 1 || wpc->config.num_channels == 1 || (flags & MONO_FLAG)) + samples_to_null = sample_count; + else + samples_to_null = sample_count * 2; + + while (samples_to_null--) + *buffer++ = 0x55; + + wps->sample_index += sample_count; + return sample_count; + } + + if (flags & FALSE_STEREO) { + int32_t *dptr = buffer + sample_count * 2; + int32_t *sptr = buffer + sample_count; + int32_t c = sample_count; + + while (c--) { + *--dptr = *--sptr; + *--dptr = *sptr; + } + } + + wps->sample_index += sample_count; + + return sample_count; +} + +/*------------------------------------------------------------------------------------------------------------------------*/ + +// #define DSD_BYTE_READY(low,high) (((low) >> 24) == ((high) >> 24)) +// #define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) >> 24)) +#define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) & 0xff000000)) +#define MAX_HISTORY_BITS 5 + +static int init_dsd_block_fast (WavpackStream *wps, WavpackMetadata *wpmd) +{ + unsigned char history_bits, max_probability; + int total_summed_probabilities = 0, i; + + if (wps->dsd.byteptr == wps->dsd.endptr) + return FALSE; + + history_bits = *wps->dsd.byteptr++; + + if (wps->dsd.byteptr == wps->dsd.endptr || history_bits > MAX_HISTORY_BITS) + return FALSE; + + wps->dsd.history_bins = 1 << history_bits; + + wps->dsd.value_lookup = malloc (sizeof (*wps->dsd.value_lookup) * wps->dsd.history_bins); + memset (wps->dsd.value_lookup, 0, sizeof (*wps->dsd.value_lookup) * wps->dsd.history_bins); + wps->dsd.summed_probabilities = malloc (sizeof (*wps->dsd.summed_probabilities) * wps->dsd.history_bins); + wps->dsd.probabilities = malloc (sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins); + + max_probability = *wps->dsd.byteptr++; + + if (max_probability < 0xff) { + unsigned char *outptr = (unsigned char *) wps->dsd.probabilities; + unsigned char *outend = outptr + sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins; + + while (outptr < outend && wps->dsd.byteptr < wps->dsd.endptr) { + int code = *wps->dsd.byteptr++; + + if (code > max_probability) { + int zcount = code - max_probability; + + while (outptr < outend && zcount--) + *outptr++ = 0; + } + else if (code) + *outptr++ = code; + else + break; + } + + if (outptr < outend || (wps->dsd.byteptr < wps->dsd.endptr && *wps->dsd.byteptr++)) + return FALSE; + } + else if (wps->dsd.endptr - wps->dsd.byteptr > (int) sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins) { + memcpy (wps->dsd.probabilities, wps->dsd.byteptr, sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins); + wps->dsd.byteptr += sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins; + } + else + return FALSE; + + for (wps->dsd.p0 = 0; wps->dsd.p0 < wps->dsd.history_bins; ++wps->dsd.p0) { + int32_t sum_values; + unsigned char *vp; + + for (sum_values = i = 0; i < 256; ++i) + wps->dsd.summed_probabilities [wps->dsd.p0] [i] = sum_values += wps->dsd.probabilities [wps->dsd.p0] [i]; + + if (sum_values) { + total_summed_probabilities += sum_values; + vp = wps->dsd.value_lookup [wps->dsd.p0] = malloc (sum_values); + + for (i = 0; i < 256; i++) { + int c = wps->dsd.probabilities [wps->dsd.p0] [i]; + + while (c--) + *vp++ = i; + } + } + } + + if (wps->dsd.endptr - wps->dsd.byteptr < 4 || total_summed_probabilities > wps->dsd.history_bins * 1280) + return FALSE; + + for (i = 4; i--;) + wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++; + + wps->dsd.p0 = wps->dsd.p1 = 0; + wps->dsd.low = 0; wps->dsd.high = 0xffffffff; + wps->dsd.ready = 1; + + return TRUE; +} + +static int decode_fast (WavpackStream *wps, int32_t *output, int sample_count) +{ + int total_samples = sample_count; + + if (!(wps->wphdr.flags & MONO_DATA)) + total_samples *= 2; + + while (total_samples--) { + int mult, index, code, i; + + if (!wps->dsd.summed_probabilities [wps->dsd.p0] [255]) + return 0; + + mult = (wps->dsd.high - wps->dsd.low) / wps->dsd.summed_probabilities [wps->dsd.p0] [255]; + + if (!mult) { + if (wps->dsd.endptr - wps->dsd.byteptr >= 4) + for (i = 4; i--;) + wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++; + + wps->dsd.low = 0; + wps->dsd.high = 0xffffffff; + mult = wps->dsd.high / wps->dsd.summed_probabilities [wps->dsd.p0] [255]; + + if (!mult) + return 0; + } + + index = (wps->dsd.value - wps->dsd.low) / mult; + + if (index >= wps->dsd.summed_probabilities [wps->dsd.p0] [255]) + return 0; + + if ((*output++ = code = wps->dsd.value_lookup [wps->dsd.p0] [index])) + wps->dsd.low += wps->dsd.summed_probabilities [wps->dsd.p0] [code-1] * mult; + + wps->dsd.high = wps->dsd.low + wps->dsd.probabilities [wps->dsd.p0] [code] * mult - 1; + wps->crc += (wps->crc << 1) + code; + + if (wps->wphdr.flags & MONO_DATA) + wps->dsd.p0 = code & (wps->dsd.history_bins-1); + else { + wps->dsd.p0 = wps->dsd.p1; + wps->dsd.p1 = code & (wps->dsd.history_bins-1); + } + + while (DSD_BYTE_READY (wps->dsd.high, wps->dsd.low) && wps->dsd.byteptr < wps->dsd.endptr) { + wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++; + wps->dsd.high = (wps->dsd.high << 8) | 0xff; + wps->dsd.low <<= 8; + } + } + + return sample_count; +} + +/*------------------------------------------------------------------------------------------------------------------------*/ + +#define PTABLE_BITS 8 +#define PTABLE_BINS (1<> 8; c--;) + value += (DOWN - value) >> DECAY; + + for (i = 0; i < PTABLE_BINS/2; ++i) { + table [i] = value; + table [PTABLE_BINS-1-i] = 0x100ffff - value; + + if (value > 0x010000) { + rate += (rate * rate_s + 128) >> 8; + + for (c = (rate + 64) >> 7; c--;) + value += (DOWN - value) >> DECAY; + } + } +} + +static int init_dsd_block_high (WavpackStream *wps, WavpackMetadata *wpmd) +{ + uint32_t flags = wps->wphdr.flags; + int channel, rate_i, rate_s, i; + + if (wps->dsd.endptr - wps->dsd.byteptr < ((flags & MONO_DATA) ? 13 : 20)) + return FALSE; + + rate_i = *wps->dsd.byteptr++; + rate_s = *wps->dsd.byteptr++; + + if (rate_s != RATE_S) + return FALSE; + + wps->dsd.ptable = malloc (PTABLE_BINS * sizeof (*wps->dsd.ptable)); + init_ptable (wps->dsd.ptable, rate_i, rate_s); + + for (channel = 0; channel < ((flags & MONO_DATA) ? 1 : 2); ++channel) { + DSDfilters *sp = wps->dsd.filters + channel; + + sp->filter1 = *wps->dsd.byteptr++ << 16; + sp->filter2 = *wps->dsd.byteptr++ << 16; + sp->filter3 = *wps->dsd.byteptr++ << 16; + sp->filter4 = *wps->dsd.byteptr++ << 16; + sp->filter5 = *wps->dsd.byteptr++ << 16; + sp->filter6 = 0; + sp->factor = *wps->dsd.byteptr++ & 0xff; + sp->factor |= (*wps->dsd.byteptr++ << 8) & 0xff00; + sp->factor = (sp->factor << 16) >> 16; + } + + wps->dsd.high = 0xffffffff; + wps->dsd.low = 0x0; + + for (i = 4; i--;) + wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++; + + wps->dsd.ready = 1; + + return TRUE; +} + +static int decode_high (WavpackStream *wps, int32_t *output, int sample_count) +{ + int total_samples = sample_count, channel = 0; + + if (!(wps->wphdr.flags & MONO_DATA)) + total_samples *= 2; + + while (total_samples--) { + DSDfilters *sp = wps->dsd.filters + channel; + int byte = 0, bitcount = 8; + + while (bitcount--) { + int value = sp->filter1 - sp->filter5 + sp->filter6 * (sp->factor >> 2); + int index = (value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK; + unsigned int range = wps->dsd.high - wps->dsd.low, split; + int *val = wps->dsd.ptable + index; + + split = wps->dsd.low + ((range & 0xff000000) ? (range >> 8) * (*val >> 16) : ((range * (*val >> 16)) >> 8)); + value += sp->filter6 << 3; + + if (wps->dsd.value <= split) { + wps->dsd.high = split; + byte = (byte << 1) | 1; + *val += (UP - *val) >> DECAY; + sp->filter1 += (VALUE_ONE - sp->filter1) >> 6; + sp->filter2 += (VALUE_ONE - sp->filter2) >> 4; + + if ((value ^ (value - (sp->filter6 << 4))) < 0) + sp->factor -= (value >> 31) | 1; + } + else { + wps->dsd.low = split + 1; + byte <<= 1; + *val += (DOWN - *val) >> DECAY; + sp->filter1 -= sp->filter1 >> 6; + sp->filter2 -= sp->filter2 >> 4; + + if ((value ^ (value - (sp->filter6 << 4))) < 0) + sp->factor += (value >> 31) | 1; + } + + while (DSD_BYTE_READY (wps->dsd.high, wps->dsd.low) && wps->dsd.byteptr < wps->dsd.endptr) { + wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++; + wps->dsd.high = (wps->dsd.high << 8) | 0xff; + wps->dsd.low <<= 8; + } + + sp->filter3 += (sp->filter2 - sp->filter3) >> 4; + sp->filter4 += (sp->filter3 - sp->filter4) >> 4; + sp->filter5 += value = (sp->filter4 - sp->filter5) >> 4; + sp->filter6 += (value - sp->filter6) >> 3; + } + + wps->crc += (wps->crc << 1) + (*output++ = byte); + + if (!(wps->wphdr.flags & MONO_DATA)) + channel ^= 1; + } + + return sample_count; +} + +/*------------------------------------------------------------------------------------------------------------------------*/ + +// 80 term DSD decimation filter +// < 1 dB down at 20 kHz +// > 108 dB stopband attenuation + +static const int32_t decm_filter [] = { + 4, 17, 56, 147, 336, 693, 1320, 2359, + 4003, 6502, 10170, 15392, 22623, 32389, 45275, 61920, + 82994, 109174, 141119, 179431, 224621, 277068, 336983, 404373, + 479004, 560384, 647741, 740025, 835917, 933849, 1032042, 1128551, + 1221329, 1308290, 1387386, 1456680, 1514425, 1559128, 1589610, 1605059, + 1605059, 1589610, 1559128, 1514425, 1456680, 1387386, 1308290, 1221329, + 1128551, 1032042, 933849, 835917, 740025, 647741, 560384, 479004, + 404373, 336983, 277068, 224621, 179431, 141119, 109174, 82994, + 61920, 45275, 32389, 22623, 15392, 10170, 6502, 4003, + 2359, 1320, 693, 336, 147, 56, 17, 4, +}; + +#define NUM_FILTER_TERMS ((int)(sizeof (decm_filter) / sizeof (decm_filter [0]))) +#define HISTORY_BYTES ((NUM_FILTER_TERMS+7)/8) + +typedef struct { + unsigned char delay [HISTORY_BYTES]; +} DecimationChannel; + +typedef struct { + int32_t conv_tables [HISTORY_BYTES] [256]; + DecimationChannel *chans; + int num_channels; +} DecimationContext; + +void *decimate_dsd_init (int num_channels) +{ + DecimationContext *context = malloc (sizeof (DecimationContext)); + double filter_sum = 0, filter_scale; + int skipped_terms, i, j; + + if (!context) + return context; + + memset (context, 0, sizeof (*context)); + context->num_channels = num_channels; + context->chans = malloc (num_channels * sizeof (DecimationChannel)); + + if (!context->chans) { + free (context); + return NULL; + } + + for (i = 0; i < NUM_FILTER_TERMS; ++i) + filter_sum += decm_filter [i]; + + filter_scale = ((1 << 23) - 1) / filter_sum * 16.0; + // fprintf (stderr, "convolution, %d terms, %f sum, %f scale\n", NUM_FILTER_TERMS, filter_sum, filter_scale); + + for (skipped_terms = i = 0; i < NUM_FILTER_TERMS; ++i) { + int scaled_term = (int) floor (decm_filter [i] * filter_scale + 0.5); + + if (scaled_term) { + for (j = 0; j < 256; ++j) + if (j & (0x80 >> (i & 0x7))) + context->conv_tables [i >> 3] [j] += scaled_term; + else + context->conv_tables [i >> 3] [j] -= scaled_term; + } + else + skipped_terms++; + } + + // fprintf (stderr, "%d terms skipped\n", skipped_terms); + + decimate_dsd_reset (context); + + return context; +} + +void decimate_dsd_reset (void *decimate_context) +{ + DecimationContext *context = (DecimationContext *) decimate_context; + int chan = 0, i; + + if (!context) + return; + + for (chan = 0; chan < context->num_channels; ++chan) + for (i = 0; i < HISTORY_BYTES; ++i) + context->chans [chan].delay [i] = 0x55; +} + +void decimate_dsd_run (void *decimate_context, int32_t *samples, int num_samples) +{ + DecimationContext *context = (DecimationContext *) decimate_context; + int chan = 0; + + if (!context) + return; + + while (num_samples) { + DecimationChannel *sp = context->chans + chan; + int sum = 0; + + sum += context->conv_tables [0] [sp->delay [0] = sp->delay [1]]; + sum += context->conv_tables [1] [sp->delay [1] = sp->delay [2]]; + sum += context->conv_tables [2] [sp->delay [2] = sp->delay [3]]; + sum += context->conv_tables [3] [sp->delay [3] = sp->delay [4]]; + sum += context->conv_tables [4] [sp->delay [4] = sp->delay [5]]; + sum += context->conv_tables [5] [sp->delay [5] = sp->delay [6]]; + sum += context->conv_tables [6] [sp->delay [6] = sp->delay [7]]; + sum += context->conv_tables [7] [sp->delay [7] = sp->delay [8]]; + sum += context->conv_tables [8] [sp->delay [8] = sp->delay [9]]; + sum += context->conv_tables [9] [sp->delay [9] = *samples]; + *samples++ = sum >> 4; + + if (++chan == context->num_channels) { + num_samples--; + chan = 0; + } + } +} + +void decimate_dsd_destroy (void *decimate_context) +{ + DecimationContext *context = (DecimationContext *) decimate_context; + + if (!context) + return; + + if (context->chans) + free (context->chans); + + free (context); +} diff --git a/Frameworks/WavPack/Files/unpack_floats.c b/Frameworks/WavPack/Files/unpack_floats.c new file mode 100644 index 000000000..cc045ddc5 --- /dev/null +++ b/Frameworks/WavPack/Files/unpack_floats.c @@ -0,0 +1,134 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack_floats.c + +// This module deals with the restoration of floating-point data. Note that no +// floating point math is involved here...the values are only processed with +// the macros that directly access the mantissa, exponent, and sign fields. +// That's why we use the f32 type instead of the built-in float type. + +#include + +#include "wavpack_local.h" + +static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values); + +void float_values (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + uint32_t crc = wps->crc_x; + + if (!bs_is_open (&wps->wvxbits)) { + float_values_nowvx (wps, values, num_values); + return; + } + + while (num_values--) { + int shift_count = 0, exp = wps->float_max_exp; + f32 outval = 0; + uint32_t temp; + + if (*values == 0) { + if (wps->float_flags & FLOAT_ZEROS_SENT) { + if (getbit (&wps->wvxbits)) { + getbits (&temp, 23, &wps->wvxbits); + set_mantissa (outval, temp); + + if (exp >= 25) { + getbits (&temp, 8, &wps->wvxbits); + set_exponent (outval, temp); + } + + set_sign (outval, getbit (&wps->wvxbits)); + } + else if (wps->float_flags & FLOAT_NEG_ZEROS) + set_sign (outval, getbit (&wps->wvxbits)); + } + } + else { + *values <<= wps->float_shift; + + if (*values < 0) { + *values = -*values; + set_sign (outval, 1); + } + + if (*values == 0x1000000) { + if (getbit (&wps->wvxbits)) { + getbits (&temp, 23, &wps->wvxbits); + set_mantissa (outval, temp); + } + + set_exponent (outval, 255); + } + else { + if (exp) + while (!(*values & 0x800000) && --exp) { + shift_count++; + *values <<= 1; + } + + if (shift_count) { + if ((wps->float_flags & FLOAT_SHIFT_ONES) || + ((wps->float_flags & FLOAT_SHIFT_SAME) && getbit (&wps->wvxbits))) + *values |= ((1 << shift_count) - 1); + else if (wps->float_flags & FLOAT_SHIFT_SENT) { + getbits (&temp, shift_count, &wps->wvxbits); + *values |= temp & ((1 << shift_count) - 1); + } + } + + set_mantissa (outval, *values); + set_exponent (outval, exp); + } + } + + crc = crc * 27 + get_mantissa (outval) * 9 + get_exponent (outval) * 3 + get_sign (outval); + * (f32 *) values++ = outval; + } + + wps->crc_x = crc; +} + +static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + while (num_values--) { + int shift_count = 0, exp = wps->float_max_exp; + f32 outval = 0; + + if (*values) { + *values <<= wps->float_shift; + + if (*values < 0) { + *values = -*values; + set_sign (outval, 1); + } + + if (*values >= 0x1000000) { + while (*values & 0xf000000) { + *values >>= 1; + ++exp; + } + } + else if (exp) { + while (!(*values & 0x800000) && --exp) { + shift_count++; + *values <<= 1; + } + + if (shift_count && (wps->float_flags & FLOAT_SHIFT_ONES)) + *values |= ((1 << shift_count) - 1); + } + + set_mantissa (outval, *values); + set_exponent (outval, exp); + } + + * (f32 *) values++ = outval; + } +} diff --git a/Frameworks/WavPack/Files/unpack_seek.c b/Frameworks/WavPack/Files/unpack_seek.c new file mode 100644 index 000000000..d8694c8cf --- /dev/null +++ b/Frameworks/WavPack/Files/unpack_seek.c @@ -0,0 +1,325 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack_seek.c + +// This module provides the high-level API for unpacking audio data from +// a specific sample index (i.e., seeking). + +#ifndef NO_SEEKING + +#include +#include + +#include "wavpack_local.h" + +///////////////////////////// executable code //////////////////////////////// + +static int64_t find_sample (WavpackContext *wpc, void *infile, int64_t header_pos, int64_t sample); + +// Seek to the 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. After a +// FALSE return the file should not be accessed again (other than to close +// it); this is a fatal error. + +int WavpackSeekSample (WavpackContext *wpc, uint32_t sample) +{ + return WavpackSeekSample64 (wpc, sample); +} + +int WavpackSeekSample64 (WavpackContext *wpc, int64_t sample) +{ + WavpackStream *wps = wpc->streams ? wpc->streams [wpc->current_stream = 0] : NULL; + uint32_t bcount, samples_to_skip; + int32_t *buffer; + + if (wpc->total_samples == -1 || sample >= wpc->total_samples || + !wpc->reader->can_seek (wpc->wv_in) || (wpc->open_flags & OPEN_STREAMING) || + (wpc->wvc_flag && !wpc->reader->can_seek (wpc->wvc_in))) + return FALSE; + +#ifndef VER4_ONLY + if (wpc->stream3) + return seek_sample3 (wpc, (uint32_t) sample); +#endif + + if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || sample < GET_BLOCK_INDEX (wps->wphdr) || + sample >= GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples) { + + free_streams (wpc); + wpc->filepos = find_sample (wpc, wpc->wv_in, wpc->filepos, sample); + + if (wpc->filepos == -1) + return FALSE; + + if (wpc->wvc_flag) { + wpc->file2pos = find_sample (wpc, wpc->wvc_in, 0, sample); + + if (wpc->file2pos == -1) + return FALSE; + } + } + + if (!wps->blockbuff) { + wpc->reader->set_pos_abs (wpc->wv_in, wpc->filepos); + wpc->reader->read_bytes (wpc->wv_in, &wps->wphdr, sizeof (WavpackHeader)); + WavpackLittleEndianToNative (&wps->wphdr, WavpackHeaderFormat); + SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index); + 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; + } + + wps->init_done = FALSE; + + if (wpc->wvc_flag) { + wpc->reader->set_pos_abs (wpc->wvc_in, wpc->file2pos); + wpc->reader->read_bytes (wpc->wvc_in, &wps->wphdr, sizeof (WavpackHeader)); + WavpackLittleEndianToNative (&wps->wphdr, WavpackHeaderFormat); + SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index); + 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 (!wps->init_done && !unpack_init (wpc)) { + free_streams (wpc); + return FALSE; + } + + wps->init_done = TRUE; + } + + while (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) { + if (++wpc->current_stream == wpc->num_streams) { + + if (wpc->num_streams == wpc->max_streams) { + free_streams (wpc); + return FALSE; + } + + wpc->streams = realloc (wpc->streams, (wpc->num_streams + 1) * sizeof (wpc->streams [0])); + 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) { + free_streams (wpc); + return FALSE; + } + + 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) { + free_streams (wpc); + return FALSE; + } + + wps->init_done = FALSE; + + if (wpc->wvc_flag && !read_wvc_block (wpc)) { + free_streams (wpc); + return FALSE; + } + + if (!wps->init_done && !unpack_init (wpc)) { + free_streams (wpc); + return FALSE; + } + + wps->init_done = TRUE; + } + else + wps = wpc->streams [wpc->current_stream]; + } + + if (sample < wps->sample_index) { + for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++) + if (!unpack_init (wpc)) + return FALSE; + else + wpc->streams [wpc->current_stream]->init_done = TRUE; + } + + samples_to_skip = (uint32_t) (sample - wps->sample_index); + + if (samples_to_skip > 131072) { + free_streams (wpc); + return FALSE; + } + + if (samples_to_skip) { + buffer = malloc (samples_to_skip * 8); + + for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++) + if (wpc->streams [wpc->current_stream]->wphdr.flags & DSD_FLAG) + unpack_dsd_samples (wpc, buffer, samples_to_skip); + else + unpack_samples (wpc, buffer, samples_to_skip); + + free (buffer); + } + + wpc->current_stream = 0; + + if (wpc->decimation_context) + decimate_dsd_reset (wpc->decimation_context); + + return TRUE; +} + +// Find a valid WavPack header, searching either from the current file position +// (or from the specified position if not -1) and store it (endian corrected) +// at the specified pointer. The return value is the exact file position of the +// header, although we may have actually read past it. Because this function +// is used for seeking to a specific audio sample, it only considers blocks +// that contain audio samples for the initial stream to be valid. + +#define BUFSIZE 4096 + +static int64_t find_header (WavpackStreamReader64 *reader, void *id, int64_t filepos, WavpackHeader *wphdr) +{ + unsigned char *buffer = malloc (BUFSIZE), *sp = buffer, *ep = buffer; + + if (filepos != (uint32_t) -1 && reader->set_pos_abs (id, filepos)) { + free (buffer); + return -1; + } + + while (1) { + int bleft; + + if (sp < ep) { + bleft = (int)(ep - sp); + memcpy (buffer, sp, bleft); + ep -= (sp - buffer); + sp = buffer; + } + else { + if (sp > ep) + if (reader->set_pos_rel (id, (int32_t)(sp - ep), SEEK_CUR)) { + free (buffer); + return -1; + } + + sp = ep = buffer; + bleft = 0; + } + + ep += reader->read_bytes (id, ep, BUFSIZE - bleft); + + if (ep - sp < 32) { + free (buffer); + return -1; + } + + while (sp + 32 <= ep) + if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' && + !(*++sp & 1) && sp [2] < 16 && !sp [3] && (sp [2] || sp [1] || *sp >= 24) && sp [5] == 4 && + sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff) && sp [18] < 3 && !sp [19]) { + memcpy (wphdr, sp - 4, sizeof (*wphdr)); + WavpackLittleEndianToNative (wphdr, WavpackHeaderFormat); + + if (wphdr->block_samples && (wphdr->flags & INITIAL_BLOCK)) { + free (buffer); + return reader->get_pos (id) - (ep - sp + 4); + } + + if (wphdr->ckSize > 1024) + sp += wphdr->ckSize - 1024; + } + } +} + +// Find the WavPack block that contains the specified sample. If "header_pos" +// is zero, then no information is assumed except the total number of samples +// in the file and its size in bytes. If "header_pos" is non-zero then we +// assume that it is the file position of the valid header image contained in +// the first stream and we can limit our search to either the portion above +// or below that point. If a .wvc file is being used, then this must be called +// for that file also. + +static int64_t find_sample (WavpackContext *wpc, void *infile, int64_t header_pos, int64_t sample) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int64_t file_pos1 = 0, file_pos2 = wpc->reader->get_length (infile); + int64_t sample_pos1 = 0, sample_pos2 = wpc->total_samples; + double ratio = 0.96; + int file_skip = 0; + + if (sample >= wpc->total_samples) + return -1; + + if (header_pos && wps->wphdr.block_samples) { + if (GET_BLOCK_INDEX (wps->wphdr) > sample) { + sample_pos2 = GET_BLOCK_INDEX (wps->wphdr); + file_pos2 = header_pos; + } + else if (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples <= sample) { + sample_pos1 = GET_BLOCK_INDEX (wps->wphdr); + file_pos1 = header_pos; + } + else + return header_pos; + } + + while (1) { + double bytes_per_sample; + int64_t seek_pos; + + bytes_per_sample = (double) file_pos2 - file_pos1; + bytes_per_sample /= sample_pos2 - sample_pos1; + seek_pos = file_pos1 + (file_skip ? 32 : 0); + seek_pos += (int64_t)(bytes_per_sample * (sample - sample_pos1) * ratio); + seek_pos = find_header (wpc->reader, infile, seek_pos, &wps->wphdr); + + if (seek_pos != (int64_t) -1) + SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index); + + if (seek_pos == (int64_t) -1 || seek_pos >= file_pos2) { + if (ratio > 0.0) { + if ((ratio -= 0.24) < 0.0) + ratio = 0.0; + } + else + return -1; + } + else if (GET_BLOCK_INDEX (wps->wphdr) > sample) { + sample_pos2 = GET_BLOCK_INDEX (wps->wphdr); + file_pos2 = seek_pos; + } + else if (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples <= sample) { + + if (seek_pos == file_pos1) + file_skip = 1; + else { + sample_pos1 = GET_BLOCK_INDEX (wps->wphdr); + file_pos1 = seek_pos; + } + } + else + return seek_pos; + } +} + +#endif + diff --git a/Frameworks/WavPack/Files/unpack_utils.c b/Frameworks/WavPack/Files/unpack_utils.c new file mode 100644 index 000000000..fb9e93cc3 --- /dev/null +++ b/Frameworks/WavPack/Files/unpack_utils.c @@ -0,0 +1,384 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack_utils.c + +// This module provides the high-level API for unpacking audio data from +// WavPack files. It manages the buffers used to interleave the data passed +// back to the application from the individual streams. The actual audio +// stream decompression is handled in the unpack.c module. + +#include +#include + +#include "wavpack_local.h" + +///////////////////////////// executable code //////////////////////////////// + +// Unpack the specified number of samples from the current file position. +// Note that "samples" here refers to "complete" samples, which would be +// 2 longs for stereo files or even more for multichannel files, so the +// required memory at "buffer" is 4 * samples * num_channels bytes. The +// audio data is returned right-justified in 32-bit longs in the endian +// mode native to the executing processor. So, if the original data was +// 16-bit, then the values returned would be +/-32k. Floating point data +// can also be returned if the source was floating point data (and this +// can be optionally normalized to +/-1.0 by using the appropriate flag +// in the call to WavpackOpenFileInput ()). The actual number of samples +// unpacked is returned, which should be equal to the number requested unless +// the end of fle is encountered or an error occurs. After all samples have +// been unpacked then 0 will be returned. + +uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples) +{ + WavpackStream *wps = wpc->streams ? wpc->streams [wpc->current_stream = 0] : NULL; + int num_channels = wpc->config.num_channels, file_done = FALSE; + uint32_t bcount, samples_unpacked = 0, samples_to_unpack; + int32_t *bptr = buffer; + +#ifndef VER4_ONLY + if (wpc->stream3) + return unpack_samples3 (wpc, buffer, samples); +#endif + + while (samples) { + + // if the current block has no audio, or it's not the first block of a multichannel + // sequence, or the sample we're on is past the last sample in this block...we need + // to free up the streams and read the next block + + if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || + wps->sample_index >= GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples) { + + int64_t nexthdrpos; + + if (wpc->wrapper_bytes >= MAX_WRAPPER_BYTES) + break; + + free_streams (wpc); + nexthdrpos = wpc->reader->get_pos (wpc->wv_in); + bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) + break; + + wpc->filepos = nexthdrpos + bcount; + + if (wpc->open_flags & OPEN_STREAMING) + SET_BLOCK_INDEX (wps->wphdr, wps->sample_index = 0); + else + SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index); + + // allocate the memory for the entire raw block and read it in + + wps->blockbuff = malloc (wps->wphdr.ckSize + 8); + + if (!wps->blockbuff) + break; + + memcpy (wps->blockbuff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + strcpy (wpc->error_message, "can't read all of last block!"); + wps->wphdr.block_samples = 0; + wps->wphdr.ckSize = 24; + break; + } + + wps->init_done = FALSE; // we have not yet called unpack_init() for this block + + // if this block has audio, but not the sample index we were expecting, flag an error + + if (wps->wphdr.block_samples && wps->sample_index != GET_BLOCK_INDEX (wps->wphdr)) + wpc->crc_errors++; + + // if this block has audio, and we're in hybrid lossless mode, read the matching wvc block + + if (wps->wphdr.block_samples && wpc->wvc_flag) + read_wvc_block (wpc); + + // if the block does NOT have any audio, call unpack_init() to process non-audio stuff + + if (!wps->wphdr.block_samples) { + if (!wps->init_done && !unpack_init (wpc)) + wpc->crc_errors++; + + wps->init_done = TRUE; + } + } + + // if the current block has no audio, or it's not the first block of a multichannel + // sequence, or the sample we're on is past the last sample in this block...we need + // to loop back and read the next block + + if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || + wps->sample_index >= GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples) + continue; + + // There seems to be some missing data, like a block was corrupted or something. + // If it's not too much data, just fill in with silence here and loop back. + + if (wps->sample_index < GET_BLOCK_INDEX (wps->wphdr)) { + int32_t zvalue = (wps->wphdr.flags & DSD_FLAG) ? 0x55 : 0; + + samples_to_unpack = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) - wps->sample_index); + + if (!samples_to_unpack || samples_to_unpack > 262144) { + strcpy (wpc->error_message, "discontinuity found, aborting file!"); + wps->wphdr.block_samples = 0; + wps->wphdr.ckSize = 24; + break; + } + + if (samples_to_unpack > samples) + samples_to_unpack = samples; + + wps->sample_index += samples_to_unpack; + samples_unpacked += samples_to_unpack; + samples -= samples_to_unpack; + + samples_to_unpack *= (wpc->reduced_channels ? wpc->reduced_channels : num_channels); + + while (samples_to_unpack--) + *bptr++ = zvalue; + + continue; + } + + // calculate number of samples to process from this block, then initialize the decoder for + // this block if we haven't already + + samples_to_unpack = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index); + + if (samples_to_unpack > samples) + samples_to_unpack = samples; + + if (!wps->init_done && !unpack_init (wpc)) + wpc->crc_errors++; + + wps->init_done = TRUE; + + // if this block is not the final block of a multichannel sequence (and we're not truncating + // to stereo), then enter this conditional block...otherwise we just unpack the samples directly + + if (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) { + int32_t *temp_buffer = malloc (samples_to_unpack * 8), *src, *dst; + int offset = 0; // offset to next channel in sequence (0 to num_channels - 1) + uint32_t samcnt; + + // since we are getting samples from multiple bocks in a multichannel sequence, we must + // allocate a temporary buffer to unpack to so that we can re-interleave the samples + + if (!temp_buffer) + break; + + // loop through all the streams... + + while (1) { + + // if the stream has not been allocated and corresponding block read, do that here... + + if (wpc->current_stream == wpc->num_streams) { + wpc->streams = realloc (wpc->streams, (wpc->num_streams + 1) * sizeof (wpc->streams [0])); + + if (!wpc->streams) + break; + + wps = wpc->streams [wpc->num_streams++] = malloc (sizeof (WavpackStream)); + + if (!wps) + break; + + CLEAR (*wps); + bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); + + if (bcount == (uint32_t) -1) { + wpc->streams [0]->wphdr.block_samples = 0; + wpc->streams [0]->wphdr.ckSize = 24; + file_done = TRUE; + break; + } + + if (wpc->open_flags & OPEN_STREAMING) + SET_BLOCK_INDEX (wps->wphdr, wps->sample_index = 0); + else + SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index); + + wps->blockbuff = malloc (wps->wphdr.ckSize + 8); + + if (!wps->blockbuff) + break; + + memcpy (wps->blockbuff, &wps->wphdr, 32); + + if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) != + wps->wphdr.ckSize - 24) { + wpc->streams [0]->wphdr.block_samples = 0; + wpc->streams [0]->wphdr.ckSize = 24; + file_done = TRUE; + break; + } + + // if this block has audio, and we're in hybrid lossless mode, read the matching wvc block + + if (wpc->wvc_flag) + read_wvc_block (wpc); + + // initialize the unpacker for this block + + if (!unpack_init (wpc)) + wpc->crc_errors++; + + wps->init_done = TRUE; + } + else + wps = wpc->streams [wpc->current_stream]; + + // unpack the correct number of samples (either mono or stereo) into the temp buffer + + if (wps->wphdr.flags & DSD_FLAG) + unpack_dsd_samples (wpc, src = temp_buffer, samples_to_unpack); + else + unpack_samples (wpc, src = temp_buffer, samples_to_unpack); + + samcnt = samples_to_unpack; + dst = bptr + offset; + + // if the block is mono, copy the samples from the single channel into the destination + // using num_channels as the stride + + if (wps->wphdr.flags & MONO_FLAG) { + while (samcnt--) { + dst [0] = *src++; + dst += num_channels; + } + + offset++; + } + + // if the block is stereo, and we don't have room for two more channels, just copy one + // and flag an error + + else if (offset == num_channels - 1) { + while (samcnt--) { + dst [0] = src [0]; + dst += num_channels; + src += 2; + } + + wpc->crc_errors++; + offset++; + } + + // otherwise copy the stereo samples into the destination + + else { + while (samcnt--) { + dst [0] = *src++; + dst [1] = *src++; + dst += num_channels; + } + + offset += 2; + } + + // check several clues that we're done with this set of blocks and exit if we are; else do next stream + + if ((wps->wphdr.flags & FINAL_BLOCK) || wpc->current_stream == wpc->max_streams - 1 || offset == num_channels) + break; + else + wpc->current_stream++; + } + + // if we didn't get all the channels we expected, mute the buffer and flag an error + + if (offset != num_channels) { + if (wps->wphdr.flags & DSD_FLAG) { + int samples_to_zero = samples_to_unpack * num_channels; + int32_t *zptr = bptr; + + while (samples_to_zero--) + *zptr++ = 0x55; + } + else + memset (bptr, 0, samples_to_unpack * num_channels * 4); + + wpc->crc_errors++; + } + + // go back to the first stream (we're going to leave them all loaded for now because they might have more samples) + // and free the temp buffer + + wps = wpc->streams [wpc->current_stream = 0]; + free (temp_buffer); + } + // catch the error situation where we have only one channel but run into a stereo block + // (this avoids overwriting the caller's buffer) + else if (!(wps->wphdr.flags & MONO_FLAG) && (num_channels == 1 || wpc->reduced_channels == 1)) { + memset (bptr, 0, samples_to_unpack * sizeof (*bptr)); + wps->sample_index += samples_to_unpack; + wpc->crc_errors++; + } + else if (wps->wphdr.flags & DSD_FLAG) + unpack_dsd_samples (wpc, bptr, samples_to_unpack); + else + unpack_samples (wpc, bptr, samples_to_unpack); + + if (file_done) { + strcpy (wpc->error_message, "can't read all of last block!"); + break; + } + + if (wpc->reduced_channels) + bptr += samples_to_unpack * wpc->reduced_channels; + else + bptr += samples_to_unpack * num_channels; + + samples_unpacked += samples_to_unpack; + samples -= samples_to_unpack; + + // if we just finished a block, check for a calculated crc error + // (and back up the streams a little if possible in case we passed a header) + + if (wps->sample_index == GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples) { + if (check_crc_error (wpc)) { + int32_t *zptr = bptr, zvalue = (wps->wphdr.flags & DSD_FLAG) ? 0x55 : 0; + uint32_t samples_to_zero = wps->wphdr.block_samples; + + if (samples_to_zero > samples_to_unpack) + samples_to_zero = samples_to_unpack; + + samples_to_zero *= (wpc->reduced_channels ? wpc->reduced_channels : num_channels); + + while (samples_to_zero--) + *--zptr = zvalue; + + if (wps->blockbuff && wpc->reader->can_seek (wpc->wv_in)) { + int32_t rseek = ((WavpackHeader *) wps->blockbuff)->ckSize / 3; + wpc->reader->set_pos_rel (wpc->wv_in, (rseek > 16384) ? -16384 : -rseek, SEEK_CUR); + } + + if (wpc->wvc_flag && wps->block2buff && wpc->reader->can_seek (wpc->wvc_in)) { + int32_t rseek = ((WavpackHeader *) wps->block2buff)->ckSize / 3; + wpc->reader->set_pos_rel (wpc->wvc_in, (rseek > 16384) ? -16384 : -rseek, SEEK_CUR); + } + + wpc->crc_errors++; + } + } + + if (wpc->total_samples != -1 && wps->sample_index == wpc->total_samples) + break; + } + + if (wpc->decimation_context) + decimate_dsd_run (wpc->decimation_context, buffer, samples_unpacked); + + return samples_unpacked; +} diff --git a/Frameworks/WavPack/Files/utils.c b/Frameworks/WavPack/Files/utils.c index ae00b2095..a89dfe4c3 100644 --- a/Frameworks/WavPack/Files/utils.c +++ b/Frameworks/WavPack/Files/utils.c @@ -11,7 +11,7 @@ // This module provides general purpose utilities for the WavPack command-line // utilities and the self-extraction module. -#if defined(WIN32) +#if defined(_WIN32) #define WIN32_LEAN_AND_MEAN #include #include @@ -31,16 +31,19 @@ #include "wavpack.h" #include "utils.h" -#ifdef WIN32 -#define fileno _fileno -#define stat64 __stat64 -#define fstat64 _fstat64 +#ifdef _WIN32 +#include "win32_unicode_support.h" +#define fprintf fprintf_utf8 +#define fputs fputs_utf8 +#define remove(f) unlink_utf8(f) #endif -#ifdef WIN32 +#ifdef _WIN32 int copy_timestamp (const char *src_filename, const char *dst_filename) { + wchar_t *src_filename_utf16 = utf8_to_utf16(src_filename); + wchar_t *dst_filename_utf16 = utf8_to_utf16(dst_filename); FILETIME last_modified; HANDLE src, dst; int res = TRUE; @@ -48,10 +51,13 @@ int copy_timestamp (const char *src_filename, const char *dst_filename) if (*src_filename == '-' || *dst_filename == '-') return res; - src = CreateFile (src_filename, GENERIC_READ, FILE_SHARE_READ, NULL, + if (!src_filename_utf16 || !dst_filename_utf16) + return FALSE; + + src = CreateFileW (src_filename_utf16, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); - dst = CreateFile (dst_filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, + dst = CreateFileW (dst_filename_utf16, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (src == INVALID_HANDLE_VALUE || dst == INVALID_HANDLE_VALUE || @@ -65,6 +71,9 @@ int copy_timestamp (const char *src_filename, const char *dst_filename) if (dst != INVALID_HANDLE_VALUE) CloseHandle (dst); + free (src_filename_utf16); + free (dst_filename_utf16); + return res; } @@ -101,28 +110,22 @@ int copy_timestamp(const char *src_filename, const char *dst_filename) ////////////////////////////////////////////////////////////////////////////// // 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. // +// then NULL is returned. Extensions with more than 4 letters don't count. // ////////////////////////////////////////////////////////////////////////////// -#if defined(WIN32) - -static int is_second_byte (char *filespec, char *pos); +#if defined(_WIN32) 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) + if (strlen (cp+1) && strlen (cp+1) <= 4) return cp; else return NULL; @@ -144,7 +147,7 @@ char *filespec_ext (char *filespec) return NULL; if (*cp == '.') { - if (strlen (cp) > 1 && strlen (cp) <= 4) + if (strlen (cp+1) && strlen (cp+1) <= 4) return cp; else return NULL; @@ -165,7 +168,7 @@ char *filespec_ext (char *filespec) // returned. // ////////////////////////////////////////////////////////////////////////////// -#if (defined(__GNUC__) || defined(__sun)) && !defined(WIN32) +#if (defined(__GNUC__) || defined(__sun)) && !defined(_WIN32) char *filespec_path (char *filespec) { @@ -203,8 +206,8 @@ char *filespec_path (char *filespec) char *filespec_path (char *filespec) { char *cp = filespec + strlen (filespec); - LANGID langid = GetSystemDefaultLangID (); - struct _finddata_t finddata; + struct _wfinddata_t wfinddata; + wchar_t *filespec_utf16; intptr_t file; if (cp == filespec || filespec_wild (filespec)) @@ -212,23 +215,28 @@ char *filespec_path (char *filespec) --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)) != (intptr_t) -1 && - (finddata.attrib & _A_SUBDIR)) { + filespec_utf16 = utf8_to_utf16(filespec); + + if (!filespec_utf16) + return NULL; + + if ((file = _wfindfirst (filespec_utf16, &wfinddata)) != (intptr_t) -1 && + (wfinddata.attrib & _A_SUBDIR)) { _findclose (file); + free (filespec_utf16); return strcat (filespec, "\\"); } - if (file != -1L) - _findclose(file); + if (file != -1L) + _findclose(file); + + free (filespec_utf16); return NULL; } @@ -249,16 +257,13 @@ char *filespec_wild (char *filespec) // a pointer to the actual filename, or NULL if no filename can be found. // ////////////////////////////////////////////////////////////////////////////// -#if defined(WIN32) +#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; @@ -288,27 +293,6 @@ char *filespec_name (char *filespec) #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) -{ - unsigned char *cp = pos; - - while (cp > filespec && ((cp [-1] >= 0x81 && cp [-1] <= 0x9f) || - (cp [-1] >= 0xe0 && cp [-1] <= 0xfc))) - cp--; - - return (int)((unsigned char *)pos - 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 // @@ -325,7 +309,7 @@ char yna (void) waiting_input = 1; while (1) { -#if defined(WIN32) +#if defined(_WIN32) key = _getch (); #else key = fgetc(stdin); @@ -341,31 +325,39 @@ char yna (void) else if (key == '\r' || key == '\n') { if (choice) { fprintf (stderr, "\r\n"); + fflush (stderr); break; } - else + else { fprintf (stderr, "%c", 7); + fflush (stderr); + } } else if (key == 'Y' || key == 'y') { -#ifdef WIN32 +#ifdef _WIN32 fprintf (stderr, "%c\b", key); + fflush (stderr); #endif choice = 'y'; } else if (key == 'N' || key == 'n') { -#ifdef WIN32 +#ifdef _WIN32 fprintf (stderr, "%c\b", key); + fflush (stderr); #endif choice = 'n'; } else if (key == 'A' || key == 'a') { -#ifdef WIN32 +#ifdef _WIN32 fprintf (stderr, "%c\b", key); + fflush (stderr); #endif choice = 'a'; } - else + else { fprintf (stderr, "%c", 7); + fflush (stderr); + } } waiting_input = 0; @@ -382,7 +374,7 @@ char yna (void) extern int debug_logging_mode; -#ifdef WIN32 +#ifdef _WIN32 int get_app_path (char *app_path) { @@ -495,36 +487,10 @@ void error_line (char *error, ...) #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) +#if defined(_WIN32) static int break_flag; BOOL WINAPI ctrl_handler (DWORD ctrl) @@ -581,14 +547,17 @@ 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; + if (hConIn && GetConsoleScreenBufferInfo (hConIn, &coninfo) && + (coninfo.dwCursorPosition.X || coninfo.dwCursorPosition.Y)) { + unsigned char spaces = coninfo.dwSize.X - coninfo.dwCursorPosition.X; - while (spaces--) - fputc (' ', stderr); + while (spaces--) + fputc (' ', stderr); } else - fputc ('\n', stderr); + fprintf (stderr, " \n"); + + fflush (stderr); } #else ////////////////////////////////////////////////////////////////////////////// @@ -598,7 +567,8 @@ void finish_line (void) void finish_line (void) { - fprintf (stderr, " \n"); + fprintf (stderr, " \n"); + fflush (stderr); } ////////////////////////////////////////////////////////////////////////////// @@ -678,7 +648,7 @@ int DoWriteFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToWrite, ui return !ferror (hFile); } -#ifdef WIN32 +#ifdef _WIN32 int64_t DoGetFileSize (FILE *hFile) { @@ -700,6 +670,21 @@ int64_t DoGetFileSize (FILE *hFile) return (int64_t)Size.QuadPart; } +int64_t DoGetFilePosition (FILE *hFile) +{ + return _ftelli64 (hFile); +} + +int DoSetFilePositionAbsolute (FILE *hFile, int64_t pos) +{ + return _fseeki64 (hFile, pos, SEEK_SET); +} + +int DoSetFilePositionRelative (FILE *hFile, int64_t pos, int mode) +{ + return _fseeki64 (hFile, pos, mode); +} + #else int64_t DoGetFileSize (FILE *hFile) @@ -712,23 +697,23 @@ int64_t DoGetFileSize (FILE *hFile) return (int64_t) statbuf.st_size; } -#endif - -uint32_t DoGetFilePosition (FILE *hFile) +int64_t DoGetFilePosition (FILE *hFile) { - return (uint32_t) ftell (hFile); + return ftell (hFile); } -int DoSetFilePositionAbsolute (FILE *hFile, uint32_t pos) +int DoSetFilePositionAbsolute (FILE *hFile, int64_t pos) { return fseek (hFile, pos, SEEK_SET); } -int DoSetFilePositionRelative (FILE *hFile, int32_t pos, int mode) +int DoSetFilePositionRelative (FILE *hFile, int64_t pos, int mode) { return fseek (hFile, pos, mode); } +#endif + // if ungetc() is not available, a seek of -1 is fine also because we do not // change the byte read. @@ -746,7 +731,7 @@ int DoTruncateFile (FILE *hFile) { if (hFile) { fflush (hFile); -#if defined(WIN32) +#if defined(_WIN32) return !_chsize (_fileno (hFile), 0); #else return !ftruncate(fileno (hFile), 0); @@ -766,7 +751,7 @@ int DoDeleteFile (char *filename) // displaying progress of batch operations with the console window minimized. // ///////////////////////////////////////////////////////////////////////////////// -#ifdef WIN32 +#ifdef _WIN32 void DoSetConsoleTitle (char *text) { @@ -778,6 +763,7 @@ void DoSetConsoleTitle (char *text) void DoSetConsoleTitle (char *text) { fprintf (stderr, "\033]0;%s\007", text); + fflush (stderr); } #endif diff --git a/Frameworks/WavPack/Files/utils.h b/Frameworks/WavPack/Files/utils.h index 7d60cee4f..6a06ed786 100644 --- a/Frameworks/WavPack/Files/utils.h +++ b/Frameworks/WavPack/Files/utils.h @@ -21,14 +21,14 @@ #endif #endif -#if defined(WIN32) +#if defined(_WIN32) #undef VERSION_OS #ifdef _WIN64 #define VERSION_OS "Win64" #else #define VERSION_OS "Win32" #endif -#define PACKAGE_VERSION "4.70.0" +#define PACKAGE_VERSION "5.0.0-alpha4" #endif #define FALSE 0 @@ -47,9 +47,9 @@ char yna (void); int DoReadFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead, uint32_t *lpNumberOfBytesRead); int DoWriteFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToWrite, uint32_t *lpNumberOfBytesWritten); int64_t DoGetFileSize (FILE *hFile); -uint32_t DoGetFilePosition (FILE *hFile); -int DoSetFilePositionAbsolute (FILE *hFile, uint32_t pos); -int DoSetFilePositionRelative (FILE *hFile, int32_t pos, int mode); +int64_t DoGetFilePosition (FILE *hFile); +int DoSetFilePositionAbsolute (FILE *hFile, int64_t pos); +int DoSetFilePositionRelative (FILE *hFile, int64_t pos, int mode); int DoUngetc (int c, FILE *hFile); int DoCloseHandle (FILE *hFile); int DoTruncateFile (FILE *hFile); diff --git a/Frameworks/WavPack/Files/wavpack.c b/Frameworks/WavPack/Files/wavpack.c deleted file mode 100644 index 982eb3ebb..000000000 --- a/Frameworks/WavPack/Files/wavpack.c +++ /dev/null @@ -1,3224 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2013 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// wavpack.c - -// This is the main module for the WavPack command-line compressor. - -#if defined(WIN32) -#define WIN32_LEAN_AND_MEAN -#include -#include -#else -#if defined(__OS2__) -#define INCL_DOSPROCESS -#include -#include -#endif -#include -#include -#include -#include -#endif - -#include -#include -#include -#include -#include -#include - -#include "wavpack.h" -#include "utils.h" -#include "md5.h" - -#if defined (__GNUC__) && !defined(WIN32) -#include -#include -#include -#else -#include -#endif - -#ifdef WIN32 -#define stricmp(x,y) _stricmp(x,y) -#define strdup(x) _strdup(x) -#define fileno _fileno -#else -#define stricmp strcasecmp -#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\n" -" Copyright (c) 1998 - 2013 Conifer Software. All Rights Reserved.\n\n"; - -static const char *usage = -#if defined (WIN32) -" Usage: WAVPACK [-options] infile[.wav]|infile.wv|- [outfile[.wv]|outpath|-]\n" -" (default is lossless; infile may contain wildcards: ?,*)\n\n" -#else -" Usage: WAVPACK [-options] infile[.wav]|infile.wv|- [...] [-o outfile[.wv]|outpath|-]\n" -" (default is lossless; multiple input files allowed)\n\n" -#endif -" Options: -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" -" -f = fast mode (fast, but some compromise in compression ratio)\n" -" -h = high quality (better compression ratio, but slower)\n" -" -v = verify output file integrity after write (no pipes)\n" -" -x = extra encode processing (no decoding speed penalty)\n" -" --help = complete help\n\n" -" Web: Visit www.wavpack.com for latest version and info\n"; - -static const char *help = -#if defined (WIN32) -" Usage:\n" -" WAVPACK [-options] infile[.wav]|infile.wv|- [outfile[.wv]|outpath|-]\n\n" -" The default operation is lossless. Wildcard characters (*,?) may be included\n" -" in the input file and they may be either WAV or WAVPACK (.wv) files (or raw\n" -" PCM if --raw-pcm is included). When transcoding, all tags are copied.\n\n" -#else -" Usage:\n" -" WAVPACK [-options] infile[.wav]|infile.wv|- [...] [-o outfile[.wv]|outpath|-]\n\n" -" The default operation is lossless. Multiple input files may be specified,\n" -" and they may be either WAV or WAVPACK (.wv) files (or raw PCM if --raw-pcm\n" -" is included). When transcoding, all tags are copied.\n\n" -#endif -" Options:\n" -" -a Adobe Audition (CoolEdit) mode for 32-bit floats\n" -" --allow-huge-tags allow tag data up to 16 MB (embedding > 1 MB is not\n" -" recommended for portable devices and may not work\n" -" with some programs including WavPack pre-4.70)\n" -" -bn enable hybrid compression\n" -" n = 2.0 to 23.9 bits/sample, or\n" -" n = 24-9600 kbits/second (kbps)\n" -" add -c to create correction file (.wvc)\n" -" --blocksize=n specify block size in samples (max = 131072 and\n" -" min = 16 with --merge-blocks, otherwise 128)\n" -" -c hybrid lossless mode (use with -b to create\n" -" correction file (.wvc) in hybrid mode)\n" -" -cc maximum hybrid lossless compression (but degrades\n" -" decode speed and may result in lower quality)\n" -" --channel-order= specify (comma separated) channel order if not\n" -" Microsoft standard (which is FL,FR,FC,LFE,BL,BR,\n" -" LC,FRC,BC,SL,SR,TC,TFL,TFC,TFR,TBL,TBC,TBR);\n" -" specify '...' to indicate that channels are not\n" -" assigned to specific speakers, or terminate list\n" -" with '...' to indicate that any channels beyond\n" -" those specified are unassigned\n" -" -d delete source file if successful (use with caution!)\n" -#if defined (WIN32) -" -e create self-extracting executable with .exe\n" -" extension, requires wvself.exe in path\n" -#endif -" -f fast mode (faster encode and decode, but some\n" -" compromise in compression ratio)\n" -" -h high quality (better compression ratio, but slower\n" -" encode and decode than default mode)\n" -" -hh very high quality (best compression, but slowest\n" -" and NOT recommended for portable hardware use)\n" -" --help this extended help display\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) || defined (__OS2__) -" -l run at lower priority for smoother multitasking\n" -#endif -" -m compute & store MD5 signature of raw audio data\n" -" --merge-blocks merge consecutive blocks with equal redundancy\n" -" (used with --blocksize option and is useful for\n" -" files generated by the lossyWAV program or\n" -" decoded HDCD files)\n" -" -n calculate average and peak quantization noise\n" -" (for hybrid mode only, reference fullscale sine)\n" -" --no-utf8-convert don't recode passed tags from local encoding to\n" -" UTF-8, assume they are in UTF-8 already.\n" -#if !defined (WIN32) -" -o FILENAME | PATH specify output filename or path\n" -#endif -" --optimize-mono optimization for stereo files that are really mono\n" -" (result may be incompatible with older decoders)\n" -" -p practical float storage (also affects 32-bit\n" -" integers, no longer technically lossless)\n" -" --pair-unassigned-chans encode unassigned channels into stereo pairs\n" -" -q quiet (keep console output to a minimum)\n" -" -r generate a new RIFF wav header (removes any\n" -" extra chunk info from existing header)\n" -" --raw-pcm input data is raw pcm (44100 Hz, 16-bit, 2-ch)\n" -" --raw-pcm=sr,bps,ch input data is raw pcm with specified sample rate,\n" -" sample bit depth, and number of channels\n" -" (specify 32f for 32-bit floating point data)\n" -" -sn override default noise shaping where n is a float\n" -" value between -1.0 and 1.0; negative values move noise\n" -" lower in freq, positive values move noise higher\n" -" in freq, use '0' for no shaping (white noise)\n" -" -t copy input file's time stamp to output file(s)\n" -" --use-dns force use of dynamic noise shaping (hybrid mode only)\n" -" -v verify output file integrity after write (no pipes)\n" -" --version write the version to stdout\n" -" -w \"Field=Value\" write specified text metadata to APEv2 tag\n" -" -w \"Field=@file.ext\" write specified text metadata from file to APEv2\n" -" tag, normally used for embedded cuesheets and logs\n" -" (field names \"Cuesheet\" and \"Log\")\n" -" --write-binary-tag \"Field=@file.ext\"\n" -" write the specified binary metadata file to APEv2\n" -" tag, normally used for cover art with the specified\n" -" field name \"Cover Art (Front)\"\n" -" -x[n] extra encode processing (optional n = 1 to 6, 1=default)\n" -" -x1 to -x3 to choose best of predefined filters\n" -" -x4 to -x6 to generate custom filters (very slow!)\n" -" -y yes to all warnings (use with caution!)\n" -" -z don't set console title to indicate progress\n\n" -" Web:\n" -" Visit www.wavpack.com for latest version and complete information\n"; - -static const char *speakers [] = { - "FL", "FR", "FC", "LFE", "BL", "BR", "FLC", "FRC", "BC", - "SL", "SR", "TC", "TFL", "TFC", "TFR", "TBL", "TBC", "TBR" -}; - -#define NUM_SPEAKERS (sizeof (speakers) / sizeof (speakers [0])) - -// 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, copy_time, quiet_mode, verify_mode, delete_source, store_floats_as_ints, - adobe_mode, ignore_length, new_riff_header, raw_pcm, no_utf8_convert, no_console_title, allow_huge_tags; - -static int num_channels_order; -static unsigned char channel_order [18], channel_order_undefined; -static uint32_t channel_order_mask; -static double encode_time_percent; - -// These two statics are used to keep track of tags that the user specifies on the -// command line. The "num_tag_strings" and "tag_strings" fields in the WavpackConfig -// structure are no longer used for anything (they should not have been there in -// the first place). - -static int num_tag_items, total_tag_size; - -static struct tag_item { - char *item, *value, *ext; - int vsize, binary; -} *tag_items; - -#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, unsigned char *new_order, unsigned char *md5_digest_source); -static int repack_file (char *infilename, char *outfilename, char *out2filename, const WavpackConfig *config); -static int repack_audio (WavpackContext *wpc, WavpackContext *infile, unsigned char *md5_digest_source); -static int verify_audio (char *infilename, unsigned char *md5_digest_source); -static void display_progress (double file_progress); -static void TextToUTF8 (void *string, int len); - -#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; -{ -#ifdef __EMX__ /* OS/2 */ - _wildcard (&argc, &argv); -#endif - int 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 (**++argv == '-' && (*argv)[1] == '-' && (*argv)[2]) { - char *long_option = *argv + 2, *long_param = long_option; - - while (*long_param) - if (*long_param++ == '=') - break; - - if (!strcmp (long_option, "help")) { // --help - printf ("%s", help); - return 1; - } - else if (!strcmp (long_option, "version")) { // --version - printf ("wavpack %s\n", PACKAGE_VERSION); - printf ("libwavpack %s\n", WavpackGetLibraryVersionString ()); - return 1; - } - else if (!strcmp (long_option, "optimize-mono")) // --optimize-mono - config.flags |= CONFIG_OPTIMIZE_MONO; - else if (!strcmp (long_option, "dns")) { // --dns - error_line ("warning: --dns deprecated, use --use-dns"); - ++error_count; - } - else if (!strcmp (long_option, "use-dns")) // --use-dns - config.flags |= CONFIG_DYNAMIC_SHAPING; - else if (!strcmp (long_option, "merge-blocks")) // --merge-blocks - config.flags |= CONFIG_MERGE_BLOCKS; - else if (!strcmp (long_option, "pair-unassigned-chans")) // --pair-unassigned-chans - config.flags |= CONFIG_PAIR_UNDEF_CHANS; - else if (!strcmp (long_option, "no-utf8-convert")) // --no-utf8-convert - no_utf8_convert = 1; - else if (!strcmp (long_option, "allow-huge-tags")) // --allow-huge-tags - allow_huge_tags = 1; - else if (!strcmp (long_option, "store-floats-as-ints")) // --store-floats-as-ints - store_floats_as_ints = 1; - else if (!strcmp (long_option, "write-binary-tag")) // --write-binary-tag - tag_next_arg = 2; - else if (!strncmp (long_option, "raw-pcm", 7)) { // --raw-pcm - int params [] = { 44100, 16, 2 }; - int pi, fp = 0; - - for (pi = 0; *long_param && pi < 3; ++pi) { - if (isdigit (*long_param)) - params [pi] = (int) strtol (long_param, &long_param, 10); - - if ((*long_param == 'f' || *long_param == 'F') && pi == 1) { - long_param++; - fp = 1; - } - - if (*long_param == ',') - long_param++; - else - break; - } - - if (*long_param) { - error_line ("syntax error in raw PCM specification!"); - ++error_count; - } - else if (params [0] < 1 || params [0] > 192000 || - params [1] < 1 || params [1] > 32 || (fp && params [1] != 32) || - params [2] < 1 || params [2] > 256) { - error_line ("argument range error in raw PCM specification!"); - ++error_count; - } - else { - config.sample_rate = params [0]; - config.bits_per_sample = params [1]; - config.bytes_per_sample = (params [1] + 7) / 8; - config.num_channels = params [2]; - - if (config.num_channels <= 2) - config.channel_mask = 0x5 - config.num_channels; - else if (config.num_channels <= 18) - config.channel_mask = (1 << config.num_channels) - 1; - else - config.channel_mask = 0x3ffff; - - config.float_norm_exp = fp ? 127 : 0; - raw_pcm = 1; - } - } - else if (!strncmp (long_option, "blocksize", 9)) { // --blocksize - config.block_samples = (int) strtol (long_param, NULL, 10); - - if (config.block_samples < 16 || config.block_samples > 131072) { - error_line ("invalid blocksize!"); - ++error_count; - } - } - else if (!strncmp (long_option, "channel-order", 13)) { // --channel-order - char name [6], channel_error = 0; - uint32_t mask = 0; - int chan, ci, si; - - for (chan = 0; chan < sizeof (channel_order); ++chan) { - - if (!*long_param) - break; - - if (*long_param == '.') { - if (*++long_param == '.' && *++long_param == '.' && !*++long_param) - channel_order_undefined = 1; - else - channel_error = 1; - - break; - } - - for (ci = 0; isalpha (*long_param) && ci < sizeof (name) - 1; ci++) - name [ci] = *long_param++; - - if (!ci) { - channel_error = 1; - break; - } - - name [ci] = 0; - - for (si = 0; si < NUM_SPEAKERS; ++si) - if (!stricmp (name, speakers [si])) { - if (mask & (1L << si)) - channel_error = 1; - - channel_order [chan] = si; - mask |= (1L << si); - break; - } - - if (channel_error || si == NUM_SPEAKERS) { - error_line ("unknown or repeated channel spec: %s!", name); - channel_error = 1; - break; - } - - if (*long_param && *long_param++ != ',') { - channel_error = 1; - break; - } - } - - if (channel_error) { - error_line ("syntax error in channel order specification!"); - ++error_count; - } - else if (*long_param) { - error_line ("too many channels specified!"); - ++error_count; - } - else { - channel_order_mask = mask; - num_channels_order = chan; - } - } - else { - error_line ("unknown option: %s !", long_option); - ++error_count; - } - } -#if defined (WIN32) - else if ((**argv == '-' || **argv == '/') && (*argv)[1]) -#else - 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 = (int) 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': - 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': - adobe_mode = 1; - break; -#if defined (WIN32) - case 'E': case 'e': - config.flags |= CONFIG_CREATE_EXE; - break; -#endif -#if defined (WIN32) - case 'L': case 'l': - SetPriorityClass (GetCurrentProcess(), IDLE_PRIORITY_CLASS); - break; -#elif defined (__OS2__) - case 'L': case 'l': - DosSetPriority (0, PRTYC_IDLETIME, 0, 0); - break; -#endif -#if defined (WIN32) - case 'O': case 'o': // ignore -o in Windows to be Linux compatible - break; -#else - case 'O': case 'o': - output_spec = 1; - break; -#endif - case 'T': case 't': - copy_time = 1; - break; - - case 'P': case 'p': - config.flags |= CONFIG_SKIP_WVX; - break; - - case 'Q': case 'q': - quiet_mode = 1; - break; - - case 'Z': case 'z': - no_console_title = 1; - break; - - case 'M': case 'm': - config.flags |= CONFIG_MD5_CHECKSUM; - break; - - case 'I': case 'i': - ignore_length = 1; - break; - - case 'R': case 'r': - new_riff_header = 1; - break; - - case 'V': case 'v': - verify_mode = 1; - break; - - case 'B': case 'b': - config.flags |= CONFIG_HYBRID_FLAG; - config.bitrate = (float) 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 = (float) 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': - if (++tag_next_arg == 2) { - error_line ("warning: -ww deprecated, use --write-binary-tag"); - ++error_count; - } - - break; - - default: - error_line ("illegal option: %c !", **argv); - ++error_count; - } - else if (tag_next_arg) { - char *cp = strchr (*argv, '='); - - if (cp && cp > *argv) { - int i = num_tag_items; - - tag_items = realloc (tag_items, ++num_tag_items * sizeof (*tag_items)); - tag_items [i].item = malloc (cp - *argv + 1); - memcpy (tag_items [i].item, *argv, cp - *argv); - tag_items [i].item [cp - *argv] = 0; - tag_items [i].vsize = (int) strlen (cp + 1); - tag_items [i].value = malloc (tag_items [i].vsize + 1); - strcpy (tag_items [i].value, cp + 1); - tag_items [i].binary = (tag_next_arg == 2); - tag_items [i].ext = NULL; - } - else { - error_line ("error in tag spec: %s !", *argv); - ++error_count; - } - - tag_next_arg = 0; - } -#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], raw_pcm ? ".raw" : ".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], raw_pcm ? ".raw" : ".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 (ignore_length && outfilename && *outfilename == '-') { - error_line ("can't ignore length in header when using stdout!"); - ++error_count; - } - - if (verify_mode && outfilename && *outfilename == '-') { - error_line ("can't verify output file 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; - } - if (config.flags & CONFIG_MERGE_BLOCKS) { - error_line ("--merge-blocks option is for lossless mode only!"); - ++error_count; - } - if ((config.flags & CONFIG_SHAPE_OVERRIDE) && (config.flags & CONFIG_DYNAMIC_SHAPING)) { - error_line ("-s and --use-dns options are mutually exclusive!"); - ++error_count; - } - } - else { - if (config.flags & (CONFIG_CALC_NOISE | CONFIG_SHAPE_OVERRIDE | CONFIG_CREATE_WVC | CONFIG_DYNAMIC_SHAPING)) { - error_line ("-c, -n, -s, and --use-dns options are for hybrid mode (-b) only!"); - ++error_count; - } - } - - if (config.flags & CONFIG_MERGE_BLOCKS) { - if (!config.block_samples) { - error_line ("--merge-blocks only makes sense when --blocksize is specified!"); - ++error_count; - } - } - else if (config.block_samples && config.block_samples < 128) { - error_line ("minimum blocksize is 128 when --merge-blocks is not specified!"); - ++error_count; - } - - if (!quiet_mode && !error_count) - fprintf (stderr, sign_on, VERSION_OS, WavpackGetLibraryVersionString ()); - - // Loop through any tag specification strings and check for file access, convert text - // strings to UTF-8, and otherwise prepare for writing to APE tags. This is done here - // rather than after encoding so that any errors can be reported to the user now. - - for (i = 0; i < num_tag_items; ++i) { - if (*tag_items [i].value == '@') { - char *fn = tag_items [i].value + 1, *new_value = NULL; - FILE *file = wild_fopen (fn, "rb"); - - // if the file is not found, try using any input and output directories that the - // user may have specified on the command line - - if (!file && num_files && filespec_name (matches [0]) && *matches [0] != '-') { - char *temp = malloc (strlen (matches [0]) + PATH_MAX); - - strcpy (temp, matches [0]); - strcpy (filespec_name (temp), fn); - file = wild_fopen (temp, "rb"); - free (temp); - } - - if (!file && outfilename && filespec_name (outfilename) && *outfilename != '-') { - char *temp = malloc (strlen (outfilename) + PATH_MAX); - - strcpy (temp, outfilename); - strcpy (filespec_name (temp), fn); - file = wild_fopen (temp, "rb"); - free (temp); - } - - if (file) { - uint32_t bcount; - - tag_items [i].vsize = (int) DoGetFileSize (file); - - if (filespec_ext (fn)) - tag_items [i].ext = strdup (filespec_ext (fn)); - - if (tag_items [i].vsize < 1048576 * (allow_huge_tags ? 16 : 1)) { - new_value = malloc (tag_items [i].vsize + 2); - memset (new_value, 0, tag_items [i].vsize + 2); - - if (!DoReadFile (file, new_value, tag_items [i].vsize, &bcount) || - bcount != tag_items [i].vsize) { - free (new_value); - new_value = NULL; - } - } - - DoCloseHandle (file); - } - - if (!new_value) { - error_line ("error in tag spec: %s !", tag_items [i].value); - ++error_count; - } - else { - free (tag_items [i].value); - tag_items [i].value = new_value; - } - } - else if (tag_items [i].binary) { - error_line ("binary tags must be from files: %s !", tag_items [i].value); - ++error_count; - } - - if (tag_items [i].binary) { - int isize = (int) strlen (tag_items [i].item); - int esize = tag_items [i].ext ? (int) strlen (tag_items [i].ext) : 0; - - tag_items [i].value = realloc (tag_items [i].value, isize + esize + 1 + tag_items [i].vsize); - memmove (tag_items [i].value + isize + esize + 1, tag_items [i].value, tag_items [i].vsize); - strcpy (tag_items [i].value, tag_items [i].item); - - if (tag_items [i].ext) - strcat (tag_items [i].value, tag_items [i].ext); - - tag_items [i].vsize += isize + esize + 1; - } - else if (tag_items [i].vsize) { - tag_items [i].value = realloc (tag_items [i].value, tag_items [i].vsize * 2 + 1); - - if (!no_utf8_convert) - TextToUTF8 (tag_items [i].value, (int) tag_items [i].vsize * 2 + 1); - - tag_items [i].vsize = (int) strlen (tag_items [i].value); - } - - if ((total_tag_size += tag_items [i].vsize) > 1048576 * (allow_huge_tags ? 16 : 1)) { - error_line ("total APEv2 tag size exceeds %d MB !", allow_huge_tags ? 16 : 1); - ++error_count; - break; - } - } - - if (error_count) { - fprintf (stderr, "\ntype 'wavpack' for short help or 'wavpack --help' for full help\n"); - return 1; - } - - if (!num_files) { - printf ("%s", usage); - 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 = (uint32_t) DoGetFileSize (wvselfx_file); - - if (wvselfx_size && wvselfx_size != 26624 && wvselfx_size != 30720 && 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"); - intptr_t file; - int di; - - for (di = file_index; di < num_files - 1; di++) - matches [di] = matches [di + 1]; - - file_index--; - num_files--; - - if ((file = _findfirst (infilename, &_finddata_t)) != (intptr_t) -1) { - 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 (file, &_finddata_t) == 0); - - _findclose (file); - } - - 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; - - // calculate an estimate for the percentage of the time that will be used for the encoding (as opposed - // to the optional verification step) based on the "extra" mode processing; this is only used for - // displaying the progress and so is not very critical - - if (verify_mode) { - if (config.flags & CONFIG_EXTRA_MODE) { - if (config.xmode) - encode_time_percent = 100.0 * (1.0 - (1.0 / ((1 << config.xmode) + 1))); - else - encode_time_percent = 66.7; - } - else - encode_time_percent = 50.0; - } - else - encode_time_percent = 100.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; - - // 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 && !quiet_mode) - fprintf (stderr, "\n%s:\n", matches [file_index]); - - if (filespec_ext (matches [file_index]) && !stricmp (filespec_ext (matches [file_index]), ".wv")) - result = repack_file (matches [file_index], outfilename, out2filename, &config); - else - result = pack_file (matches [file_index], outfilename, out2filename, &config); - - 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; - } - - 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 (!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 - - if (!no_console_title) - DoSetConsoleTitle ("WavPack Completed"); - - 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; - intptr_t file; - - if (!filespec_wild (filename) || !filespec_name (filename)) - return fopen (filename, mode); - - if ((file = _findfirst (filename, &_finddata_t)) != (intptr_t) -1) { - 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 (file, &_finddata_t) == 0); - - _findclose (file); - } - - if (matchname) { - res = fopen (matchname, mode); - free (matchname); - } - - return res; -} - -#else - -static FILE *wild_fopen (char *filename, const char *mode) -{ - char *matchname = NULL; - struct stat statbuf; - FILE *res = NULL; - glob_t globbuf; - int i; - - glob (filename, 0, NULL, &globbuf); - - for (i = 0; i < globbuf.gl_pathc; ++i) { - if (stat (globbuf.gl_pathv [i], &statbuf) == -1 || S_ISDIR (statbuf.st_mode)) - continue; - - if (matchname) { - free (matchname); - matchname = NULL; - break; - } - else { - matchname = malloc (strlen (globbuf.gl_pathv [i]) + 10); - strcpy (matchname, globbuf.gl_pathv [i]); - } - } - - globfree (&globbuf); - - if (matchname) { - res = fopen (matchname, mode); - free (matchname); - } - - return res; -} - -#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 int pack_file (char *infilename, char *outfilename, char *out2filename, const WavpackConfig *config) -{ - char *outfilename_temp, *out2filename_temp, dummy; - int use_tempfiles = (out2filename != NULL); - uint32_t total_samples = 0, bcount; - WavpackConfig loc_config = *config; - RiffChunkHeader riff_chunk_header; - unsigned char *new_channel_order = NULL; - unsigned char md5_digest [16]; - write_id wv_file, wvc_file; - ChunkHeader chunk_header; - WaveHeader WaveHeader; - WavpackContext *wpc; - int64_t infilesize; - double dtime; - FILE *infile; - int result; - -#if defined(WIN32) - struct _timeb time1, time2; -#else - struct timeval time1, time2; - struct timezone timez; -#endif - - CLEAR (WaveHeader); - - 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 -#if defined(__OS2__) - 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; - } - - infilesize = DoGetFileSize (infile); - - if (raw_pcm) { - if (infilesize) { - int sample_size = loc_config.bytes_per_sample * loc_config.num_channels; - - total_samples = (int) (infilesize / sample_size); - - if (infilesize % sample_size) - error_line ("warning: raw pcm infile length does not divide evenly, %d bytes will be discarded", - infilesize % sample_size); - } - else - total_samples = -1; - } - else if (infilesize >= 4294967296LL && !ignore_length) { - error_line ("can't handle .WAV files larger than 4 GB (non-standard)!"); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - // check both output files for overwrite warning required - - // note that for a file to be considered "overwritable", it must both be openable for reading - // and have at least 1 readable byte - this prevents us getting stuck on "nul" (Windows) - - if (*outfilename != '-' && (wv_file.file = fopen (outfilename, "rb")) != NULL) { - size_t res = fread (&dummy, 1, 1, wv_file.file); - - DoCloseHandle (wv_file.file); - - if (res == 1) { - use_tempfiles = 1; - - if (!overwrite_all) { - fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (outfilename)); - - if (!no_console_title) - DoSetConsoleTitle ("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) { - size_t res = fread (&dummy, 1, 1, wvc_file.file); - - DoCloseHandle (wvc_file.file); - - if (res == 1) { - fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (out2filename)); - - if (!no_console_title) - DoSetConsoleTitle ("overwrite?"); - - switch (yna ()) { - - case 'n': - DoCloseHandle (infile); - WavpackCloseFile (wpc); - return SOFT_ERROR; - - case 'a': - overwrite_all = 1; - } - } - } - - // if we are using temp files, either because the output filename already exists or we are creating a - // "correction" file, search for and generate the corresponding names here - - if (use_tempfiles) { - FILE *testfile; - int count = 0; - - outfilename_temp = malloc (strlen (outfilename) + 16); - - if (out2filename) - out2filename_temp = malloc (strlen (outfilename) + 16); - - while (1) { - strcpy (outfilename_temp, outfilename); - - if (filespec_ext (outfilename_temp)) { - if (count++) - sprintf (filespec_ext (outfilename_temp), ".tmp%d", count-1); - else - strcpy (filespec_ext (outfilename_temp), ".tmp"); - - strcat (outfilename_temp, filespec_ext (outfilename)); - } - else { - if (count++) - sprintf (outfilename_temp + strlen (outfilename_temp), ".tmp%d", count-1); - else - strcat (outfilename_temp, ".tmp"); - } - - testfile = fopen (outfilename_temp, "rb"); - - if (testfile) { - int res = (int) fread (&dummy, 1, 1, testfile); - - fclose (testfile); - - if (res == 1) - continue; - } - - if (out2filename) { - strcpy (out2filename_temp, outfilename_temp); - strcat (out2filename_temp, "c"); - - testfile = fopen (out2filename_temp, "rb"); - - if (testfile) { - int res = (int) fread (&dummy, 1, 1, testfile); - - fclose (testfile); - - if (res == 1) - continue; - } - } - - break; - } - } - -#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 -#if defined(__OS2__) - setmode (fileno (stdout), O_BINARY); -#endif - } - else if ((wv_file.file = fopen (use_tempfiles ? outfilename_temp : outfilename, "w+b")) == NULL) { - error_line ("can't create file %s!", use_tempfiles ? outfilename_temp : outfilename); - DoCloseHandle (infile); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - if (!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 (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } -#endif - - // if not in "raw" mode, read (and copy to output) initial RIFF form header - - if (!raw_pcm) { - 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 (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - else if (!new_riff_header && - !WavpackAddWrapper (wpc, &riff_chunk_header, sizeof (RiffChunkHeader))) { - error_line ("%s", WavpackGetErrorMessage (wpc)); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : 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 (!raw_pcm) { - - 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 (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - else if (!new_riff_header && - !WavpackAddWrapper (wpc, &chunk_header, sizeof (ChunkHeader))) { - error_line ("%s", WavpackGetErrorMessage (wpc)); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - WavpackLittleEndianToNative (&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 (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - else if (!new_riff_header && - !WavpackAddWrapper (wpc, &WaveHeader, chunk_header.ckSize)) { - error_line ("%s", WavpackGetErrorMessage (wpc)); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - WavpackLittleEndianToNative (&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) - adobe_mode = 1; - - format = (WaveHeader.FormatTag == 0xfffe && chunk_header.ckSize == 40) ? - WaveHeader.SubFormat : WaveHeader.FormatTag; - - loc_config.bits_per_sample = (chunk_header.ckSize == 40 && WaveHeader.ValidBitsPerSample) ? - WaveHeader.ValidBitsPerSample : WaveHeader.BitsPerSample; - - if (format != 1 && format != 3) - supported = FALSE; - - if (format == 3 && loc_config.bits_per_sample != 32 && !store_floats_as_ints) - supported = FALSE; - - if (!WaveHeader.NumChannels || WaveHeader.NumChannels > 256 || - WaveHeader.BlockAlign / WaveHeader.NumChannels < (loc_config.bits_per_sample + 7) / 8 || - WaveHeader.BlockAlign / WaveHeader.NumChannels > 4 || - WaveHeader.BlockAlign % WaveHeader.NumChannels) - 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 (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - if (chunk_header.ckSize < 40) { - if (WaveHeader.NumChannels <= 2) - loc_config.channel_mask = 0x5 - WaveHeader.NumChannels; - else if (WaveHeader.NumChannels <= 18) - loc_config.channel_mask = (1 << WaveHeader.NumChannels) - 1; - else - loc_config.channel_mask = 0x3ffff; - } - else if (WaveHeader.ChannelMask && (num_channels_order || channel_order_undefined)) { - error_line ("this WAV file already has channel order information!"); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - else - loc_config.channel_mask = WaveHeader.ChannelMask; - - if (format == 3 && !store_floats_as_ints) - loc_config.float_norm_exp = 127; - else if (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 - - if (!WaveHeader.NumChannels) { // make sure we saw a "fmt" chunk... - error_line ("%s is not a valid .WAV file!", infilename); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - if (infilesize && !ignore_length && infilesize - chunk_header.ckSize > 16777216) { - error_line ("this .WAV file has over 16 MB of extra RIFF data, probably is corrupt!"); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - total_samples = chunk_header.ckSize / WaveHeader.BlockAlign; - - if (!total_samples && !ignore_length) { - error_line ("this .WAV file has no audio samples, probably is corrupt!"); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - loc_config.bytes_per_sample = WaveHeader.BlockAlign / WaveHeader.NumChannels; - loc_config.num_channels = WaveHeader.NumChannels; - loc_config.sample_rate = WaveHeader.SampleRate; - 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 || - (!new_riff_header && - !WavpackAddWrapper (wpc, buff, bytes_to_copy))) { - error_line ("%s", WavpackGetErrorMessage (wpc)); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - free (buff); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - free (buff); - } - } - - if (num_channels_order || channel_order_undefined) { - int i, j; - - if (loc_config.num_channels < num_channels_order || - (loc_config.num_channels > num_channels_order && !channel_order_undefined)) { - error_line ("file does not have %d channel(s)!", num_channels_order); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - loc_config.channel_mask = channel_order_mask; - - if (num_channels_order) { - new_channel_order = malloc (loc_config.num_channels); - - for (i = 0; i < loc_config.num_channels; ++i) - new_channel_order [i] = i; - - memcpy (new_channel_order, channel_order, num_channels_order); - - for (i = 0; i < num_channels_order;) { - for (j = 0; j < num_channels_order; ++j) - if (new_channel_order [j] == i) { - i++; - break; - } - - if (j == num_channels_order) - for (j = 0; j < num_channels_order; ++j) - if (new_channel_order [j] > i) - new_channel_order [j]--; - } - } - } - - if (!WavpackSetConfiguration (wpc, &loc_config, total_samples)) { - error_line ("%s", WavpackGetErrorMessage (wpc)); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - // if we are creating a "correction" file, open it now for writing - - if (out2filename) { - if ((wvc_file.file = fopen (use_tempfiles ? out2filename_temp : out2filename, "w+b")) == NULL) { - error_line ("can't create correction file!"); - DoCloseHandle (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - } - - // pack the audio portion of the file now; calculate md5 if we're writing it to the file or verify mode is active - - result = pack_audio (wpc, infile, new_channel_order, ((loc_config.flags & CONFIG_MD5_CHECKSUM) || verify_mode) ? md5_digest : NULL); - - if (new_channel_order) - free (new_channel_order); - - // write the md5 sum if the user asked for it to be included - - if (result == NO_ERROR && (loc_config.flags & CONFIG_MD5_CHECKSUM)) - WavpackStoreMD5Sum (wpc, md5_digest); - - // 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 && !ignore_length && !raw_pcm) { - unsigned char buff [16]; - - while (DoReadFile (infile, buff, sizeof (buff), &bcount) && bcount) - if (!new_riff_header && - !WavpackAddWrapper (wpc, buff, bcount)) { - error_line ("%s", WavpackGetErrorMessage (wpc)); - 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", WavpackGetErrorMessage (wpc)); - 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 && num_tag_items) { - int i, res = TRUE; - - for (i = 0; i < num_tag_items && res; ++i) - if (tag_items [i].vsize) { - if (tag_items [i].binary) - res = WavpackAppendBinaryTagItem (wpc, tag_items [i].item, tag_items [i].value, tag_items [i].vsize); - else - res = WavpackAppendTagItem (wpc, tag_items [i].item, tag_items [i].value, tag_items [i].vsize); - } - - if (!res || !WavpackWriteTag (wpc)) { - error_line ("%s", WavpackGetErrorMessage (wpc)); - 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 or inputting raw pcm data. - - if (result == NO_ERROR && WavpackGetNumSamples (wpc) != WavpackGetSampleIndex (wpc)) { - if (raw_pcm || 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)) { - unsigned char *wrapper_location = WavpackGetWrapperLocation (block_buff, NULL); - unsigned char *chunk_header = malloc (sizeof (ChunkHeader)); - uint32_t data_size = WavpackGetSampleIndex (wpc) * WavpackGetNumChannels (wpc) * - WavpackGetBytesPerSample (wpc); - - memcpy (chunk_header, wrapper_location, sizeof (ChunkHeader)); - - if (!strncmp ((char *) chunk_header, "RIFF", 4)) { - ((ChunkHeader *)chunk_header)->ckSize = wrapper_size + data_size - 8; - WavpackNativeToLittleEndian (chunk_header, ChunkHeaderFormat); - } - - memcpy (wrapper_location, chunk_header, sizeof (ChunkHeader)); - memcpy (chunk_header, wrapper_location + wrapper_size - sizeof (ChunkHeader), sizeof (ChunkHeader)); - - if (!strncmp ((char *) chunk_header, "data", 4)) { - ((ChunkHeader *)chunk_header)->ckSize = data_size; - WavpackNativeToLittleEndian (chunk_header, ChunkHeaderFormat); - } - - memcpy (wrapper_location + wrapper_size - sizeof (ChunkHeader), chunk_header, sizeof (ChunkHeader)); - free (chunk_header); - } - - 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); - } - } - else { - error_line ("couldn't read all samples, file may be corrupt!!"); - result = SOFT_ERROR; - } - } - - // at this point we're completely 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 have been no errors up to now, and verify mode is enabled, do that now; only pass in the md5 if this - // was a lossless operation (either explicitly or because a high lossy bitrate resulted in lossless) - - if (result == NO_ERROR && verify_mode) - result = verify_audio (use_tempfiles ? outfilename_temp : outfilename, !WavpackLossyBlocks (wpc) ? md5_digest : NULL); - - // if there were any errors, delete the output files, close the context, and return the error - - if (result != NO_ERROR) { - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - - if (out2filename) - DoDeleteFile (use_tempfiles ? out2filename_temp : out2filename); - - WavpackCloseFile (wpc); - return result; - } - - // if we were writing to a temp file because the target file already existed, - // do the rename / overwrite now (and if that fails, return the error) - - if (use_tempfiles) { -#if defined(WIN32) - FILE *temp; - - if (remove (outfilename) && (temp = fopen (outfilename, "rb"))) { - error_line ("can not remove file %s, result saved in %s!", outfilename, outfilename_temp); - result = SOFT_ERROR; - fclose (temp); - } - else -#endif - if (rename (outfilename_temp, outfilename)) { - error_line ("can not rename temp file %s to %s!", outfilename_temp, outfilename); - result = SOFT_ERROR; - } - - if (out2filename) { -#if defined(WIN32) - FILE *temp; - - if (remove (out2filename) && (temp = fopen (out2filename, "rb"))) { - error_line ("can not remove file %s, result saved in %s!", out2filename, out2filename_temp); - result = SOFT_ERROR; - fclose (temp); - } - else -#endif - if (rename (out2filename_temp, out2filename)) { - error_line ("can not rename temp file %s to %s!", out2filename_temp, out2filename); - result = SOFT_ERROR; - } - } - - free (outfilename_temp); - if (out2filename) free (out2filename_temp); - - if (result != NO_ERROR) { - WavpackCloseFile (wpc); - return result; - } - } - - if (result == NO_ERROR && copy_time) - if (!copy_timestamp (infilename, outfilename) || - (out2filename && !copy_timestamp (infilename, out2filename))) - error_line ("failure copying time stamp!"); - - // delete source file if that option is enabled - - if (result == NO_ERROR && delete_source) { - int res = DoDeleteFile (infilename); - - if (!quiet_mode || !res) - error_line ("%s source file %s", res ? - "deleted" : "can't delete", infilename); - } - - // 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) && WavpackGetEncodedNoise (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 = WavpackGetEncodedNoise (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 (!quiet_mode) { - char *file, *fext, *oper, *cmode, cratio [16] = ""; - - if (loc_config.flags & CONFIG_MD5_CHECKSUM) { - char md5_string [] = "original md5 signature: 00000000000000000000000000000000"; - int i; - - for (i = 0; i < 16; ++i) - sprintf (md5_string + 24 + (i * 2), "%02x", md5_digest [i]); - - error_line (md5_string); - } - - if (outfilename && *outfilename != '-') { - file = FN_FIT (outfilename); - fext = wvc_file.bytes_written ? " (+.wvc)" : ""; - oper = verify_mode ? "created (and verified)" : "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. - -static void reorder_channels (void *data, unsigned char *new_order, int num_chans, - int num_samples, int bytes_per_sample); - -#define INPUT_SAMPLES 65536 - -static int pack_audio (WavpackContext *wpc, FILE *infile, unsigned char *new_order, unsigned char *md5_digest_source) -{ - uint32_t samples_remaining, input_samples = INPUT_SAMPLES, samples_read = 0; - double progress = -1.0; - int bytes_per_sample; - int32_t *sample_buffer; - unsigned char *input_buffer; - MD5_CTX md5_context; - - // don't use an absurd amount of memory just because we have an absurd number of channels - - while (input_samples * sizeof (int32_t) * WavpackGetNumChannels (wpc) > 2048*1024) - input_samples >>= 1; - - if (md5_digest_source) - 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; - unsigned int sample_count; - - if (raw_pcm || 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 (new_order) - reorder_channels (input_buffer, new_order, WavpackGetNumChannels (wpc), - sample_count, WavpackGetBytesPerSample (wpc)); - - if (md5_digest_source) - MD5Update (&md5_context, input_buffer, sample_count * bytes_per_sample); - - if (!sample_count) - break; - - if (sample_count) { - unsigned int cnt = sample_count * WavpackGetNumChannels (wpc); - unsigned char *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", WavpackGetErrorMessage (wpc)); - free (sample_buffer); - free (input_buffer); - return HARD_ERROR; - } - - if (check_break ()) { -#if defined(WIN32) - fprintf (stderr, "^C\n"); -#else - fprintf (stderr, "\n"); -#endif - free (sample_buffer); - free (input_buffer); - return SOFT_ERROR; - } - - if (WavpackGetProgress (wpc) != -1.0 && - progress != floor (WavpackGetProgress (wpc) * encode_time_percent + 0.5)) { - int nobs = progress == -1.0; - - progress = floor (WavpackGetProgress (wpc) * encode_time_percent + 0.5); - display_progress (progress / 100.0); - - if (!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", WavpackGetErrorMessage (wpc)); - return HARD_ERROR; - } - - if (md5_digest_source) - MD5Final (md5_digest_source, &md5_context); - - return NO_ERROR; -} - -// This function transcodes a single WavPack file "infilename" and stores the resulting -// WavPack file 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. Note that lossy to lossless transcoding -// is not allowed (no technical reason, it's just dumb, and could result in files that -// fail their MD5 verification test). - -static int repack_file (char *infilename, char *outfilename, char *out2filename, const WavpackConfig *config) -{ - int output_lossless = !(config->flags & CONFIG_HYBRID_FLAG) || (config->flags & CONFIG_CREATE_WVC); - int use_tempfiles = (out2filename != NULL), input_mode; - unsigned char md5_verify [16], md5_display [16]; - char *outfilename_temp, *out2filename_temp; - uint32_t total_samples = 0/*, bcount*/; - WavpackConfig loc_config = *config; - WavpackContext *infile, *outfile; - write_id wv_file, wvc_file; - char error [80]; - double dtime; - int result; - -#if defined(WIN32) - struct _timeb time1, time2; -#else - struct timeval time1, time2; - struct timezone timez; -#endif - - // use library to open input WavPack file - - infile = WavpackOpenFileInput (infilename, error, OPEN_WVC | OPEN_TAGS | OPEN_WRAPPER, 0); - - if (!infile) { - error_line (error); - return SOFT_ERROR; - } - - input_mode = WavpackGetMode (infile); - - if (!(input_mode & MODE_LOSSLESS) && output_lossless) { - error_line ("can't transcode lossy file %s to lossless...not allowed!", infilename); - WavpackCloseFile (infile); - return SOFT_ERROR; - } - - total_samples = WavpackGetNumSamples (infile); - - if (total_samples == (uint32_t) -1) { - error_line ("can't transcode file %s of unknown length!", infilename); - WavpackCloseFile (infile); - return SOFT_ERROR; - } - - // open an output context - - CLEAR (wv_file); - CLEAR (wvc_file); - outfile = WavpackOpenFileOutput (write_block, &wv_file, out2filename ? &wvc_file : NULL); - - // check both output files for overwrite warning required - - if (*outfilename != '-' && (wv_file.file = fopen (outfilename, "rb")) != NULL) { - DoCloseHandle (wv_file.file); - use_tempfiles = 1; - - if (!overwrite_all) { - if (output_lossless) - fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (outfilename)); - else - fprintf (stderr, "overwrite %s with lossy transcode (yes/no/all)? ", FN_FIT (outfilename)); - - if (!no_console_title) - DoSetConsoleTitle ("overwrite?"); - - switch (yna ()) { - case 'n': - WavpackCloseFile (infile); - WavpackCloseFile (outfile); - 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)); - - if (!no_console_title) - DoSetConsoleTitle ("overwrite?"); - - switch (yna ()) { - - case 'n': - WavpackCloseFile (infile); - WavpackCloseFile (outfile); - return SOFT_ERROR; - - case 'a': - overwrite_all = 1; - } - } - - // if we are using temp files, either because the output filename already exists or we are creating a - // "correction" file, search for and generate the corresponding names here - - if (use_tempfiles) { - FILE *testfile; - int count = 0; - - outfilename_temp = malloc (strlen (outfilename) + 16); - - if (out2filename) - out2filename_temp = malloc (strlen (outfilename) + 16); - - while (1) { - strcpy (outfilename_temp, outfilename); - - if (filespec_ext (outfilename_temp)) { - if (count++) - sprintf (filespec_ext (outfilename_temp), ".tmp%d", count-1); - else - strcpy (filespec_ext (outfilename_temp), ".tmp"); - - strcat (outfilename_temp, filespec_ext (outfilename)); - } - else { - if (count++) - sprintf (outfilename_temp + strlen (outfilename_temp), ".tmp%d", count-1); - else - strcat (outfilename_temp, ".tmp"); - } - - testfile = fopen (outfilename_temp, "rb"); - - if (testfile) { - fclose (testfile); - continue; - } - - if (out2filename) { - strcpy (out2filename_temp, outfilename_temp); - strcat (out2filename_temp, "c"); - - testfile = fopen (out2filename_temp, "rb"); - - if (testfile) { - fclose (testfile); - continue; - } - } - - break; - } - } - -#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 -#if defined(__OS2__) - setmode (fileno (stdout), O_BINARY); -#endif - } - else if ((wv_file.file = fopen (use_tempfiles ? outfilename_temp : outfilename, "w+b")) == NULL) { - error_line ("can't create file %s!", use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (infile); - WavpackCloseFile (outfile); - return SOFT_ERROR; - } - - if (!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!"); - WavpackCloseFile (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (outfile); - return SOFT_ERROR; - } -#endif - - // unless we've been specifically told not to, copy RIFF header - - if (!new_riff_header && WavpackGetWrapperBytes (infile)) { - if (!WavpackAddWrapper (outfile, WavpackGetWrapperData (infile), WavpackGetWrapperBytes (infile))) { - error_line ("%s", WavpackGetErrorMessage (outfile)); - WavpackCloseFile (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (outfile); - return SOFT_ERROR; - } - - WavpackFreeWrapper (infile); - } - - loc_config.bytes_per_sample = WavpackGetBytesPerSample (infile); - loc_config.bits_per_sample = WavpackGetBitsPerSample (infile); - loc_config.channel_mask = WavpackGetChannelMask (infile); - loc_config.num_channels = WavpackGetNumChannels (infile); - loc_config.sample_rate = WavpackGetSampleRate (infile); - - if (input_mode & MODE_FLOAT) - loc_config.float_norm_exp = WavpackGetFloatNormExp (infile); - - if (input_mode & MODE_MD5) - loc_config.flags |= CONFIG_MD5_CHECKSUM; - - if (!WavpackSetConfiguration (outfile, &loc_config, total_samples)) { - error_line ("%s", WavpackGetErrorMessage (outfile)); - WavpackCloseFile (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (outfile); - return SOFT_ERROR; - } - - // if we are creating a "correction" file, open it now for writing - - if (out2filename) { - if ((wvc_file.file = fopen (use_tempfiles ? out2filename_temp : out2filename, "w+b")) == NULL) { - error_line ("can't create correction file!"); - WavpackCloseFile (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (outfile); - return SOFT_ERROR; - } - } - - // pack the audio portion of the file now; calculate md5 if we're writing it to the file or verify mode is active - - result = repack_audio (outfile, infile, md5_verify); - - // before anything else, make sure the source file was read without errors - - if (result == NO_ERROR) { - if (WavpackGetNumErrors (infile)) { - error_line ("missing data or crc errors detected in %d block(s)!", WavpackGetNumErrors (infile)); - result = SOFT_ERROR; - } - - if (WavpackGetNumSamples (outfile) != total_samples) { - error_line ("incorrect number of samples read from source file!"); - result = SOFT_ERROR; - } - - if (input_mode & MODE_LOSSLESS) { - unsigned char md5_source [16]; - - if (WavpackGetMD5Sum (infile, md5_source) && memcmp (md5_source, md5_verify, sizeof (md5_source))) { - error_line ("MD5 signature in source should match, but does not!"); - result = SOFT_ERROR; - } - } - } - - // copy the md5 sum if present in source; if there's not one there and the user asked to add it, - // store the one we just calculated - - if (result == NO_ERROR) { - if (WavpackGetMD5Sum (infile, md5_display)) { - if (input_mode & MODE_LOSSLESS) - memcpy (md5_verify, md5_display, sizeof (md5_verify)); - - WavpackStoreMD5Sum (outfile, md5_display); - } - else if (loc_config.flags & CONFIG_MD5_CHECKSUM) { - memcpy (md5_display, md5_verify, sizeof (md5_display)); - WavpackStoreMD5Sum (outfile, md5_verify); - } - } - - // unless we've been specifically told not to, copy RIFF trailer - - if (result == NO_ERROR && !new_riff_header && WavpackGetWrapperBytes (infile)) { - if (!WavpackAddWrapper (outfile, WavpackGetWrapperData (infile), WavpackGetWrapperBytes (infile))) { - error_line ("%s", WavpackGetErrorMessage (outfile)); - WavpackCloseFile (infile); - DoCloseHandle (wv_file.file); - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - WavpackCloseFile (outfile); - return SOFT_ERROR; - } - - WavpackFreeWrapper (infile); - } - - // we're now done with any WavPack blocks, so flush any remaining data - - if (result == NO_ERROR && !WavpackFlushSamples (outfile)) { - error_line ("%s", WavpackGetErrorMessage (outfile)); - 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 && ((input_mode & MODE_VALID_TAG) || num_tag_items)) { - int num_binary_items = WavpackGetNumBinaryTagItems (infile); - int num_items = WavpackGetNumTagItems (infile), i; - int item_len, value_len; - char *item, *value; - int res = TRUE; - - for (i = 0; i < num_items && res; ++i) { - item_len = WavpackGetTagItemIndexed (infile, i, NULL, 0); - item = malloc (item_len + 1); - WavpackGetTagItemIndexed (infile, i, item, item_len + 1); - value_len = WavpackGetTagItem (infile, item, NULL, 0); - value = malloc (value_len * 2 + 1); - WavpackGetTagItem (infile, item, value, value_len + 1); - res = WavpackAppendTagItem (outfile, item, value, value_len); - free (value); - free (item); - } - - for (i = 0; i < num_binary_items && res; ++i) { - item_len = WavpackGetBinaryTagItemIndexed (infile, i, NULL, 0); - item = malloc (item_len + 1); - WavpackGetBinaryTagItemIndexed (infile, i, item, item_len + 1); - value_len = WavpackGetBinaryTagItem (infile, item, NULL, 0); - value = malloc (value_len); - value_len = WavpackGetBinaryTagItem (infile, item, value, value_len); - res = WavpackAppendBinaryTagItem (outfile, item, value, value_len); - free (value); - free (item); - } - - for (i = 0; i < num_tag_items && res; ++i) - if (tag_items [i].vsize) { - if (tag_items [i].binary) - res = WavpackAppendBinaryTagItem (outfile, tag_items [i].item, tag_items [i].value, tag_items [i].vsize); - else - res = WavpackAppendTagItem (outfile, tag_items [i].item, tag_items [i].value, tag_items [i].vsize); - } - else - WavpackDeleteTagItem (outfile, tag_items [i].item); - - if (!res || !WavpackWriteTag (outfile)) { - error_line ("%s", WavpackGetErrorMessage (outfile)); - result = HARD_ERROR; - } - } - - WavpackCloseFile (infile); // we're now done with input file, so close - - // at this point we're completely 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 have been no errors up to now, and verify mode is enabled, do that now; only pass in the md5 if this - // was a lossless operation (either explicitly or because a high lossy bitrate resulted in lossless) - - if (result == NO_ERROR && verify_mode) - result = verify_audio (use_tempfiles ? outfilename_temp : outfilename, !WavpackLossyBlocks (outfile) ? md5_verify : NULL); - - // if there were any errors, delete the output files, close the context, and return the error - - if (result != NO_ERROR) { - DoDeleteFile (use_tempfiles ? outfilename_temp : outfilename); - - if (out2filename) - DoDeleteFile (use_tempfiles ? out2filename_temp : out2filename); - - WavpackCloseFile (outfile); - return result; - } - - if (result == NO_ERROR && copy_time) - if (!copy_timestamp (infilename, use_tempfiles ? outfilename_temp : outfilename) || - (out2filename && !copy_timestamp (infilename, use_tempfiles ? out2filename_temp : out2filename))) - error_line ("failure copying time stamp!"); - - // delete source file(s) if that option is enabled (this is done before temp file rename to make sure - // we don't delete the file(s) we just created) - - if (result == NO_ERROR && delete_source) { - int res; - - if (stricmp (infilename, outfilename)) { - res = DoDeleteFile (infilename); - - if (!quiet_mode || !res) - error_line ("%s source file %s", res ? - "deleted" : "can't delete", infilename); - } - - if (input_mode & MODE_WVC) { - char in2filename [PATH_MAX]; - - strcpy (in2filename, infilename); - strcat (in2filename, "c"); - - if (!out2filename || stricmp (in2filename, out2filename)) { - res = DoDeleteFile (in2filename); - - if (!quiet_mode || !res) - error_line ("%s source file %s", res ? - "deleted" : "can't delete", in2filename); - } - } - } - - // if we were writing to a temp file because the target file already existed, - // do the rename / overwrite now (and if that fails, return the error) - - if (use_tempfiles) { -#if defined(WIN32) - FILE *temp; - - if (remove (outfilename) && (temp = fopen (outfilename, "rb"))) { - error_line ("can not remove file %s, result saved in %s!", outfilename, outfilename_temp); - result = SOFT_ERROR; - fclose (temp); - } - else -#endif - if (rename (outfilename_temp, outfilename)) { - error_line ("can not rename temp file %s to %s!", outfilename_temp, outfilename); - result = SOFT_ERROR; - } - - if (out2filename) { -#if defined(WIN32) - FILE *temp; - - if (remove (out2filename) && (temp = fopen (out2filename, "rb"))) { - error_line ("can not remove file %s, result saved in %s!", out2filename, out2filename_temp); - result = SOFT_ERROR; - fclose (temp); - } - else -#endif - if (rename (out2filename_temp, out2filename)) { - error_line ("can not rename temp file %s to %s!", out2filename_temp, out2filename); - result = SOFT_ERROR; - } - } - - free (outfilename_temp); - if (out2filename) free (out2filename_temp); - - if (result != NO_ERROR) { - WavpackCloseFile (outfile); - return result; - } - } - - // 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) && WavpackGetEncodedNoise (outfile, NULL) > 0.0) { - int full_scale_bits = WavpackGetBitsPerSample (outfile); - 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 = WavpackGetEncodedNoise (outfile, &peak); - - error_line ("ave noise = %.2f dB, peak noise = %.2f dB", - log10 (sum / WavpackGetNumSamples (outfile) / full_scale_rms) * 10, - log10 (peak / full_scale_rms) * 10); - } - - if (!quiet_mode) { - char *file, *fext, *oper, *cmode, cratio [16] = ""; - - if (config->flags & CONFIG_MD5_CHECKSUM) { - char md5_string [] = "original md5 signature: 00000000000000000000000000000000"; - int i; - - for (i = 0; i < 16; ++i) - sprintf (md5_string + 24 + (i * 2), "%02x", md5_display [i]); - - error_line (md5_string); - } - - if (outfilename && *outfilename != '-') { - file = FN_FIT (outfilename); - fext = wvc_file.bytes_written ? " (+.wvc)" : ""; - oper = verify_mode ? "created (and verified)" : "created"; - } - else { - file = (*infilename == '-') ? "stdin" : FN_FIT (infilename); - fext = ""; - oper = "packed"; - } - - if (WavpackLossyBlocks (outfile)) { - cmode = "lossy"; - - if (WavpackGetAverageBitrate (outfile, TRUE) != 0.0) - sprintf (cratio, ", %d kbps", (int) (WavpackGetAverageBitrate (outfile, TRUE) / 1000.0)); - } - else { - cmode = "lossless"; - - if (WavpackGetRatio (outfile) != 0.0) - sprintf (cratio, ", %.2f%%", 100.0 - WavpackGetRatio (outfile) * 100.0); - } - - error_line ("%s %s%s in %.2f secs (%s%s)", oper, file, fext, dtime, cmode, cratio); - } - - WavpackCloseFile (outfile); - return NO_ERROR; -} - -// This function handles the actual audio data transcoding. It assumes that the -// input file is positioned at the beginning of the audio data and that the -// WavPack configuration has been set. If the "md5_digest_source" pointer is not -// NULL, then a MD5 sum is calculated on the audio data during the transcoding -// and stored there at the completion. Note that the md5 requires a conversion -// to the native data format (endianness and bytes per sample) that is not -// required overwise. - -static unsigned char *format_samples (int bps, unsigned char *dst, int32_t *src, uint32_t samcnt); - -static int repack_audio (WavpackContext *outfile, WavpackContext *infile, unsigned char *md5_digest_source) -{ - int bps = WavpackGetBytesPerSample (infile), num_channels = WavpackGetNumChannels (infile); - uint32_t input_samples = INPUT_SAMPLES/*, samples_read = 0*/; - unsigned char *format_buffer; - int32_t *sample_buffer; - double progress = -1.0; - MD5_CTX md5_context; - - // don't use an absurd amount of memory just because we have an absurd number of channels - - while (input_samples * sizeof (int32_t) * WavpackGetNumChannels (outfile) > 2048*1024) - input_samples >>= 1; - - if (md5_digest_source) { - format_buffer = malloc (input_samples * bps * WavpackGetNumChannels (outfile)); - MD5Init (&md5_context); - } - - WavpackPackInit (outfile); - sample_buffer = malloc (input_samples * sizeof (int32_t) * WavpackGetNumChannels (outfile)); - - while (1) { - unsigned int sample_count = WavpackUnpackSamples (infile, sample_buffer, input_samples); - - if (!sample_count) - break; - - if (md5_digest_source) { - format_samples (bps, format_buffer, sample_buffer, sample_count * num_channels); - MD5Update (&md5_context, format_buffer, bps * sample_count * num_channels); - } - - if (!WavpackPackSamples (outfile, sample_buffer, sample_count)) { - error_line ("%s", WavpackGetErrorMessage (outfile)); - free (sample_buffer); - return HARD_ERROR; - } - - if (check_break ()) { -#if defined(WIN32) - fprintf (stderr, "^C\n"); -#else - fprintf (stderr, "\n"); -#endif - free (sample_buffer); - return SOFT_ERROR; - } - - if (WavpackGetProgress (outfile) != -1.0 && - progress != floor (WavpackGetProgress (outfile) * encode_time_percent + 0.5)) { - int nobs = progress == -1.0; - - progress = floor (WavpackGetProgress (outfile) * encode_time_percent + 0.5); - display_progress (progress / 100.0); - - if (!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); - - if (!WavpackFlushSamples (outfile)) { - error_line ("%s", WavpackGetErrorMessage (outfile)); - return HARD_ERROR; - } - - if (md5_digest_source) { - MD5Final (md5_digest_source, &md5_context); - free (format_buffer); - } - - return NO_ERROR; -} - -static void reorder_channels (void *data, unsigned char *order, int num_chans, - int num_samples, int bytes_per_sample) -{ - char *temp = malloc (num_chans * bytes_per_sample); - char *src = data; - - while (num_samples--) { - char *start = src; - int chan; - - for (chan = 0; chan < num_chans; ++chan) { - char *dst = temp + (order [chan] * bytes_per_sample); - int bc = bytes_per_sample; - - while (bc--) - *dst++ = *src++; - } - - memcpy (start, temp, num_chans * bytes_per_sample); - } - - free (temp); -} - -// Verify the specified WavPack input file. This function uses the library -// routines provided in wputils.c to do all unpacking. If an MD5 sum is provided -// by the caller, then this function will take care of reformatting the data -// (which is returned in native-endian longs) to the standard little-endian -// for a proper MD5 verification. Otherwise a lossy verification is assumed, -// and we only verify the exact number of samples and whether the decoding -// library detected CRC errors in any WavPack blocks. - -static int verify_audio (char *infilename, unsigned char *md5_digest_source) -{ - int bytes_per_sample, num_channels, wvc_mode, bps; - uint32_t total_unpacked_samples = 0; - unsigned char md5_digest_result [16]; - double progress = -1.0; - int result = NO_ERROR; - int32_t *temp_buffer; - MD5_CTX md5_context; - WavpackContext *wpc; - char error [80]; - - // use library to open WavPack file - - wpc = WavpackOpenFileInput (infilename, error, OPEN_WVC, 0); - - if (!wpc) { - error_line (error); - return SOFT_ERROR; - } - - if (md5_digest_source) - MD5Init (&md5_context); - - wvc_mode = WavpackGetMode (wpc) & MODE_WVC; - num_channels = WavpackGetNumChannels (wpc); - bps = WavpackGetBytesPerSample (wpc); - bytes_per_sample = num_channels * bps; - temp_buffer = malloc (4096L * num_channels * 4); - - while (result == NO_ERROR) { - uint32_t samples_unpacked; - - samples_unpacked = WavpackUnpackSamples (wpc, temp_buffer, 4096); - total_unpacked_samples += samples_unpacked; - - if (md5_digest_source && samples_unpacked) { - format_samples (bps, (unsigned char *) 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 ()) { -#if defined(WIN32) - fprintf (stderr, "^C\n"); -#else - fprintf (stderr, "\n"); -#endif - result = SOFT_ERROR; - break; - } - - if (WavpackGetProgress (wpc) != -1.0 && - progress != floor (WavpackGetProgress (wpc) * (100.0 - encode_time_percent) + encode_time_percent + 0.5)) { - - progress = floor (WavpackGetProgress (wpc) * (100.0 - encode_time_percent) + encode_time_percent + 0.5); - display_progress (progress / 100.0); - - if (!quiet_mode) - fprintf (stderr, "%s%3d%% done...", - "\b\b\b\b\b\b\b\b\b\b\b\b", (int) progress); - } - } - - free (temp_buffer); - - // If we have been provided an MD5 sum, then the assumption is that we are doing lossless compression (either explicitly - // with lossless mode or having a high enough bitrate that the result is lossless) and we can use the MD5 sum as a pretty - // definitive verification. - - if (result == NO_ERROR && md5_digest_source) { - MD5Final (md5_digest_result, &md5_context); - - if (memcmp (md5_digest_result, md5_digest_source, 16)) { - char md5_string1 [] = "00000000000000000000000000000000"; - char md5_string2 [] = "00000000000000000000000000000000"; - int i; - - for (i = 0; i < 16; ++i) { - sprintf (md5_string1 + (i * 2), "%02x", md5_digest_source [i]); - sprintf (md5_string2 + (i * 2), "%02x", md5_digest_result [i]); - } - - error_line ("original md5: %s", md5_string1); - error_line ("verified md5: %s", md5_string2); - error_line ("MD5 signatures should match, but do not!"); - result = SOFT_ERROR; - } - } - - // If we have not been provided an MD5 sum, then the assumption is that we are doing lossy compression and cannot rely - // (obviously) on that for verification. For these cases we make sure that the number of samples generated was exactly - // correct and that the WavPack decoding library did not detect an error. There is a simple CRC on every WavPack block - // that should catch any random corruption, although it's possible that this might miss some decoder bug that occurs - // late in the decoding process (e.g., after the CRC). - - if (result == NO_ERROR) { - if (WavpackGetNumSamples (wpc) != (uint32_t) -1) { - if (total_unpacked_samples < WavpackGetNumSamples (wpc)) { - error_line ("file is missing %u samples!", - WavpackGetNumSamples (wpc) - total_unpacked_samples); - result = SOFT_ERROR; - } - else if (total_unpacked_samples > WavpackGetNumSamples (wpc)) { - error_line ("file has %u extra samples!", - total_unpacked_samples - WavpackGetNumSamples (wpc)); - result = SOFT_ERROR; - } - } - - if (WavpackGetNumErrors (wpc)) { - error_line ("missing data or crc errors detected in %d block(s)!", WavpackGetNumErrors (wpc)); - result = SOFT_ERROR; - } - } - - WavpackCloseFile (wpc); - return result; -} - -// Reformat samples from longs in processor's native endian mode to -// little-endian data with (possibly) less than 4 bytes / sample. - -static unsigned char *format_samples (int bps, unsigned char *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++ = (unsigned char) (temp = *src++); - *dst++ = (unsigned char) (temp >> 8); - } - - break; - - case 3: - while (samcnt--) { - *dst++ = (unsigned char) (temp = *src++); - *dst++ = (unsigned char) (temp >> 8); - *dst++ = (unsigned char) (temp >> 16); - } - - break; - - case 4: - while (samcnt--) { - *dst++ = (unsigned char) (temp = *src++); - *dst++ = (unsigned char) (temp >> 8); - *dst++ = (unsigned char) (temp >> 16); - *dst++ = (unsigned char) (temp >> 24); - } - - break; - } - - return dst; -} -#if defined(WIN32) - -// 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 wchar_t *Wide, unsigned char *pUTF8, int len) -{ - const wchar_t *pWide = Wide; - int outndx = 0; - - while (*pWide) { - if (*pWide < 0x80 && outndx + 1 < len) - pUTF8 [outndx++] = (unsigned char) *pWide++; - else if (*pWide < 0x800 && outndx + 2 < len) { - pUTF8 [outndx++] = (unsigned char) (0xc0 | ((*pWide >> 6) & 0x1f)); - pUTF8 [outndx++] = (unsigned char) (0x80 | (*pWide++ & 0x3f)); - } - else if (outndx + 3 < len) { - pUTF8 [outndx++] = (unsigned char) (0xe0 | ((*pWide >> 12) & 0xf)); - pUTF8 [outndx++] = (unsigned char) (0x80 | ((*pWide >> 6) & 0x3f)); - pUTF8 [outndx++] = (unsigned char) (0x80 | (*pWide++ & 0x3f)); - } - else - break; - } - - pUTF8 [outndx] = 0; - return (int)(pWide - Wide); -} - -// Convert a text 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 TextToUTF8 (void *string, int len) -{ - if (* (wchar_t *) string == 0xFEFF) { - wchar_t *temp = _wcsdup (string); - - WideCharToUTF8 (temp + 1, (unsigned char *) string, len); - free (temp); - } - else { - int max_chars = (int) strlen (string); - wchar_t *temp = (wchar_t *) malloc ((max_chars + 1) * 2); - - MultiByteToWideChar (CP_ACP, 0, string, -1, temp, max_chars + 1); - WideCharToUTF8 (temp, (unsigned char *) string, len); - free (temp); - } -} - -#else - -static void TextToUTF8 (void *string, int len) -{ - char *temp = malloc (len); - char *outp = temp; - char *inp = string; - size_t insize = 0; - size_t outsize = len - 1; - int err = 0; - char *old_locale; - iconv_t converter; - - memset(temp, 0, len); - old_locale = setlocale (LC_CTYPE, ""); - - if ((unsigned char) inp [0] == 0xFF && (unsigned char) inp [1] == 0xFE) { - uint16_t *utf16p = (uint16_t *) (inp += 2); - - while (*utf16p++) - insize += 2; - - converter = iconv_open ("UTF-8", "UTF-16LE"); - } - else { - insize = strlen (string); - converter = iconv_open ("UTF-8", ""); - } - - if (converter != (iconv_t) -1) { - err = (int) iconv (converter, &inp, &insize, &outp, &outsize); - iconv_close (converter); - } - else - err = -1; - - setlocale (LC_CTYPE, old_locale); - - if (err == -1) { - free(temp); - return; - } - - memmove (string, temp, len); - free (temp); -} - -#endif - -////////////////////////////////////////////////////////////////////////////// -// 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]; - - if (!no_console_title) { - file_progress = (file_index + file_progress) / num_files; - sprintf (title, "%d%% (WavPack)", (int) ((file_progress * 100.0) + 0.5)); - DoSetConsoleTitle (title); - } -} diff --git a/Frameworks/WavPack/Files/wavpack.h b/Frameworks/WavPack/Files/wavpack.h index fe66dcbc0..1165a465b 100644 --- a/Frameworks/WavPack/Files/wavpack.h +++ b/Frameworks/WavPack/Files/wavpack.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // +// Copyright (c) 1998 - 2016 David Bryant. // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// @@ -16,8 +16,7 @@ #include -#if defined(_WIN32) && !defined(__MINGW32__) -#include +#if defined(_MSC_VER) && _MSC_VER < 1600 typedef unsigned __int64 uint64_t; typedef unsigned __int32 uint32_t; typedef unsigned __int16 uint16_t; @@ -26,9 +25,8 @@ typedef __int64 int64_t; typedef __int32 int32_t; typedef __int16 int16_t; typedef __int8 int8_t; -typedef float float32_t; #else -#include +#include #endif // RIFF / wav header formats (these occur at the beginning of both wav files @@ -50,12 +48,12 @@ typedef struct { #define ChunkHeaderFormat "4L" typedef struct { - unsigned short FormatTag, NumChannels; + uint16_t FormatTag, NumChannels; uint32_t SampleRate, BytesPerSecond; - unsigned short BlockAlign, BitsPerSample; - unsigned short cbSize, ValidBitsPerSample; + uint16_t BlockAlign, BitsPerSample; + uint16_t cbSize, ValidBitsPerSample; int32_t ChannelMask; - unsigned short SubFormat; + uint16_t SubFormat; char GUID [14]; } WaveHeader; @@ -71,13 +69,43 @@ typedef struct { typedef struct { char ckID [4]; uint32_t ckSize; - short version; - unsigned char track_no, index_no; + int16_t version; + unsigned char block_index_u8; + unsigned char total_samples_u8; uint32_t total_samples, block_index, block_samples, flags, crc; } WavpackHeader; #define WavpackHeaderFormat "4LS2LLLLL" +// Macros to access the 40-bit block_index field + +#define GET_BLOCK_INDEX(hdr) ( (int64_t) (hdr).block_index + ((int64_t) (hdr).block_index_u8 << 32) ) + +#define SET_BLOCK_INDEX(hdr,value) do { \ + int64_t tmp = (value); \ + (hdr).block_index = (uint32_t) tmp; \ + (hdr).block_index_u8 = \ + (unsigned char) (tmp >> 32); \ +} while (0) + +// Macros to access the 40-bit total_samples field, which is complicated by the fact that +// all 1's in the lower 32 bits indicates "unknown" (regardless of upper 8 bits) + +#define GET_TOTAL_SAMPLES(hdr) ( ((hdr).total_samples == (uint32_t) -1) ? -1 : \ + (int64_t) (hdr).total_samples + ((int64_t) (hdr).total_samples_u8 << 32) - (hdr).total_samples_u8 ) + +#define SET_TOTAL_SAMPLES(hdr,value) do { \ + int64_t tmp = (value); \ + if (tmp < 0) \ + (hdr).total_samples = (uint32_t) -1; \ + else { \ + tmp += (tmp / 0xffffffffLL); \ + (hdr).total_samples = (uint32_t) tmp; \ + (hdr).total_samples_u8 = \ + (unsigned char) (tmp >> 32); \ + } \ +} while (0) + // or-values for WavpackHeader.flags #define BYTES_STORED 3 // 1-4 bytes/sample #define MONO_FLAG 4 // not stereo @@ -114,7 +142,6 @@ typedef struct { #define MIN_STREAM_VERS 0x402 // lowest stream version we'll decode #define MAX_STREAM_VERS 0x410 // highest stream version we'll decode or encode -#define CUR_STREAM_VERS 0x407 // stream version we are writing now // These are the mask bit definitions for the metadata chunk id byte (see format.txt) @@ -140,11 +167,14 @@ typedef struct { #define ID_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1) #define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2) -#define ID_REPLAY_GAIN (ID_OPTIONAL_DATA | 0x3) // never used (APEv2) -#define ID_CUESHEET (ID_OPTIONAL_DATA | 0x4) // never used (APEv2) +#define ID_ALT_HEADER (ID_OPTIONAL_DATA | 0x3) +#define ID_ALT_TRAILER (ID_OPTIONAL_DATA | 0x4) #define ID_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0x5) #define ID_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x6) #define ID_SAMPLE_RATE (ID_OPTIONAL_DATA | 0x7) +#define ID_ALT_EXTENSION (ID_OPTIONAL_DATA | 0x8) +#define ID_ALT_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x9) +#define ID_NEW_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0xa) ///////////////////////// WavPack Configuration /////////////////////////////// @@ -158,12 +188,13 @@ typedef struct { int qmode, flags, xmode, num_channels, float_norm_exp; int32_t block_samples, extra_flags, sample_rate, channel_mask; unsigned char md5_checksum [16], md5_read; - int num_tag_strings; - char **tag_strings; + int num_tag_strings; // this field is not used + char **tag_strings; // this field is not used } WavpackConfig; #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_FAST_FLAG 0x200 // fast mode #define CONFIG_HIGH_FLAG 0x800 // high quality mode @@ -183,6 +214,32 @@ typedef struct { #define CONFIG_PAIR_UNDEF_CHANS 0x20000000 // encode undefined channels in stereo pairs #define CONFIG_OPTIMIZE_MONO 0x80000000 // optimize for mono streams posing as stereo +// The lower 8 bits of qmode indicate the use of new features in version 5 that (presently) +// only apply to Core Audio Files (CAF) and DSD files, but could apply to other things too. +// These flags are stored in the file and can be retrieved by a decoder that is aware of +// them, but the individual bits are meaningless to the library. If ANY of these bits are +// set then the MD5 sum is written with a new ID so that old decoders will not see it +// (because these features will cause the MD5 sum to be different and fail). + +#define QMODE_BIG_ENDIAN 0x1 // big-endian data format (opposite of WAV format) +#define QMODE_SIGNED_BYTES 0x2 // 8-bit audio data is signed (opposite of WAV format) +#define QMODE_UNSIGNED_WORDS 0x4 // audio data (other than 8-bit) is unsigned (opposite of WAV format) +#define QMODE_REORDERED_CHANS 0x8 // source channels were not Microsoft order, so they were reordered +#define QMODE_DSD_LSB_FIRST 0x10 // DSD bytes, LSB first (most Sony .dsf files) +#define QMODE_DSD_MSB_FIRST 0x20 // DSD bytes, MSB first (Philips .dff files) +#define QMODE_DSD_IN_BLOCKS 0x40 // DSD data is blocked by channels (Sony .dsf only) +#define QMODE_DSD_AUDIO (QMODE_DSD_LSB_FIRST | QMODE_DSD_MSB_FIRST) + +// The rest of the qmode word is reserved for the private use of the command-line programs +// and are ignored by the library (and not stored either). They really should not be defined +// here, but I thought it would be a good idea to have all the definitions together. + +#define QMODE_ADOBE_MODE 0x100 // user specified Adobe mode +#define QMODE_NO_STORE_WRAPPER 0x200 // user specified to not store audio file wrapper (RIFF, CAFF, etc.) +#define QMODE_CHANS_UNASSIGNED 0x400 // user specified "..." in --channel-order option +#define QMODE_IGNORE_LENGTH 0x800 // user specified to ignore length in file header +#define QMODE_RAW_PCM 0x1000 // user specified raw PCM format (no header present) + ////////////// Callbacks used for reading & writing WavPack streams ////////// typedef struct { @@ -198,18 +255,35 @@ typedef struct { int32_t (*write_bytes)(void *id, void *data, int32_t bcount); } WavpackStreamReader; +// Extended version of structure for handling large files and added +// functionality for truncating and closing files + +typedef struct { + int32_t (*read_bytes)(void *id, void *data, int32_t bcount); + int32_t (*write_bytes)(void *id, void *data, int32_t bcount); + int64_t (*get_pos)(void *id); // new signature for large files + int (*set_pos_abs)(void *id, int64_t pos); // new signature for large files + int (*set_pos_rel)(void *id, int64_t delta, int mode); // new signature for large files + int (*push_back_byte)(void *id, int c); + int64_t (*get_length)(void *id); // new signature for large files + int (*can_seek)(void *id); + int (*truncate_here)(void *id); // new function to truncate file at current position + int (*close)(void *id); // new function to close file +} WavpackStreamReader64; + typedef int (*WavpackBlockOutput)(void *id, void *data, int32_t bcount); //////////////////////////// function prototypes ///////////////////////////// -// Note: See wputils.c sourcecode for descriptions for using these functions. - typedef void WavpackContext; #ifdef __cplusplus extern "C" { #endif +#define MAX_WAVPACK_SAMPLES ((1LL << 40) - 257) + +WavpackContext *WavpackOpenFileInputEx64 (WavpackStreamReader64 *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset); WavpackContext *WavpackOpenFileInputEx (WavpackStreamReader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset); WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset); @@ -221,6 +295,15 @@ WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int f #define OPEN_STREAMING 0x20 // "streaming" mode blindly unpacks blocks // w/o regard to header file position info #define OPEN_EDIT_TAGS 0x40 // allow editing of tags +#define OPEN_FILE_UTF8 0x80 // assume filenames are UTF-8 encoded, not ANSI (Windows only) + +// new for version 5 + +#define OPEN_DSD_NATIVE 0x100 // open DSD files as bitstreams + // (returned as 8-bit "samples" stored in 32-bit words) +#define OPEN_DSD_AS_PCM 0x200 // open DSD files as 24-bit PCM (decimated 8x) +#define OPEN_ALT_TYPES 0x400 // application is aware of alternate file types & qmode + // (just affects retrieving wrappers & MD5 checksums) int WavpackGetMode (WavpackContext *wpc); @@ -239,14 +322,20 @@ int WavpackGetMode (WavpackContext *wpc); #define MODE_XMODE 0x7000 // mask for extra level (1-6, 0=unknown) #define MODE_DNS 0x8000 +int WavpackGetQualifyMode (WavpackContext *wpc); char *WavpackGetErrorMessage (WavpackContext *wpc); int WavpackGetVersion (WavpackContext *wpc); +char *WavpackGetFileExtension (WavpackContext *wpc); +unsigned char WavpackGetFileFormat (WavpackContext *wpc); uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples); uint32_t WavpackGetNumSamples (WavpackContext *wpc); +int64_t WavpackGetNumSamples64 (WavpackContext *wpc); uint32_t WavpackGetSampleIndex (WavpackContext *wpc); +int64_t WavpackGetSampleIndex64 (WavpackContext *wpc); int WavpackGetNumErrors (WavpackContext *wpc); int WavpackLossyBlocks (WavpackContext *wpc); int WavpackSeekSample (WavpackContext *wpc, uint32_t sample); +int WavpackSeekSample64 (WavpackContext *wpc, int64_t sample); WavpackContext *WavpackCloseFile (WavpackContext *wpc); uint32_t WavpackGetSampleRate (WavpackContext *wpc); int WavpackGetBitsPerSample (WavpackContext *wpc); @@ -256,12 +345,14 @@ int WavpackGetChannelMask (WavpackContext *wpc); int WavpackGetReducedChannels (WavpackContext *wpc); int WavpackGetFloatNormExp (WavpackContext *wpc); int WavpackGetMD5Sum (WavpackContext *wpc, unsigned char data [16]); +uint32_t WavpackGetChannelLayout (WavpackContext *wpc, unsigned char *reorder); uint32_t WavpackGetWrapperBytes (WavpackContext *wpc); unsigned char *WavpackGetWrapperData (WavpackContext *wpc); void WavpackFreeWrapper (WavpackContext *wpc); void WavpackSeekTrailingWrapper (WavpackContext *wpc); double WavpackGetProgress (WavpackContext *wpc); uint32_t WavpackGetFileSize (WavpackContext *wpc); +int64_t WavpackGetFileSize64 (WavpackContext *wpc); double WavpackGetRatio (WavpackContext *wpc); double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc); double WavpackGetInstantBitrate (WavpackContext *wpc); @@ -277,7 +368,17 @@ int WavpackDeleteTagItem (WavpackContext *wpc, const char *item); int WavpackWriteTag (WavpackContext *wpc); WavpackContext *WavpackOpenFileOutput (WavpackBlockOutput blockout, void *wv_id, void *wvc_id); +void WavpackSetFileInformation (WavpackContext *wpc, char *file_extension, unsigned char file_format); + +#define WP_FORMAT_WAV 0 // Microsoft RIFF, including BWF and RF64 varients +#define WP_FORMAT_W64 1 // Sony Wave64 +#define WP_FORMAT_CAF 2 // Apple CoreAudio +#define WP_FORMAT_DFF 3 // Philips DSDIFF +#define WP_FORMAT_DSF 4 // Sony DSD Format + int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples); +int WavpackSetConfiguration64 (WavpackContext *wpc, WavpackConfig *config, int64_t total_samples); +int WavpackSetChannelLayout (WavpackContext *wpc, uint32_t layout_tag, const unsigned char *reorder); int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount); int WavpackStoreMD5Sum (WavpackContext *wpc, unsigned char data [16]); int WavpackPackInit (WavpackContext *wpc); @@ -291,6 +392,8 @@ void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp); void WavpackLittleEndianToNative (void *data, char *format); void WavpackNativeToLittleEndian (void *data, char *format); +void WavpackBigEndianToNative (void *data, char *format); +void WavpackNativeToBigEndian (void *data, char *format); uint32_t WavpackGetLibraryVersion (void); const char *WavpackGetLibraryVersionString (void); diff --git a/Frameworks/WavPack/Files/wavpack_local.h b/Frameworks/WavPack/Files/wavpack_local.h index 5c69108e1..84c5bfb86 100644 --- a/Frameworks/WavPack/Files/wavpack_local.h +++ b/Frameworks/WavPack/Files/wavpack_local.h @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////////// // **** WAVPACK **** // // Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // +// Copyright (c) 1998 - 2013 Conifer Software. // // All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// @@ -11,19 +11,16 @@ #ifndef WAVPACK_LOCAL_H #define WAVPACK_LOCAL_H -#ifndef __has_builtin -#define __has_builtin(x) 0 -#endif - -#if defined(WIN32) +#if defined(_WIN32) #define FASTCALL __fastcall #else #define FASTCALL #endif -#if defined(WIN32) || \ - (defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN)) -#define BITSTREAM_SHORTS // use "shorts" for reading/writing bitstreams +#if defined(_WIN32) || \ + (defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && (BYTE_ORDER == LITTLE_ENDIAN)) || \ + (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +#define BITSTREAM_SHORTS // use 16-bit "shorts" for reading/writing bitstreams (instead of chars) // (only works on little-endian machines) #endif @@ -31,7 +28,7 @@ // This header file contains all the definitions required by WavPack. -#if defined(_WIN32) && !defined(__MINGW32__) +#if defined(_MSC_VER) && _MSC_VER < 1600 #include typedef unsigned __int64 uint64_t; typedef unsigned __int32 uint32_t; @@ -41,14 +38,13 @@ typedef __int64 int64_t; typedef __int32 int32_t; typedef __int16 int16_t; typedef __int8 int8_t; -typedef float float32_t; #else -#include +#include #endif // Because the C99 specification states that "The order of allocation of -// bit-fields within a unit (high-order to low-order or low-order to -// high-order) is implementation-defined" (6.7.2.1), I decided to change +// bit-fields within a unit (high-order to low-order or low-order to +// high-order) is implementation-defined" (6.7.2.1), I decided to change // the representation of floating-point values from a structure of // bit-fields to a 32-bit integer with access macros. Note that the WavPack // library doesn't use any floating-point math to implement compression of @@ -58,6 +54,7 @@ typedef float float32_t; typedef int32_t f32; #define get_mantissa(f) ((f) & 0x7fffff) +#define get_magnitude(f) ((f) & 0x7fffffff) #define get_exponent(f) (((f) >> 23) & 0xff) #define get_sign(f) (((f) >> 31) & 0x1) @@ -92,7 +89,8 @@ typedef struct { #define APE_TAG_MAX_LENGTH (1024 * 1024 * 16) typedef struct { - int32_t tag_file_pos, tag_begins_file; + int64_t tag_file_pos; + int tag_begins_file; ID3_Tag id3_tag; APE_Tag_Hdr ape_tag_hdr; unsigned char *ape_tag_data; @@ -115,12 +113,12 @@ typedef struct { #define ChunkHeaderFormat "4L" typedef struct { - unsigned short FormatTag, NumChannels; + uint16_t FormatTag, NumChannels; uint32_t SampleRate, BytesPerSecond; - unsigned short BlockAlign, BitsPerSample; - unsigned short cbSize, ValidBitsPerSample; + uint16_t BlockAlign, BitsPerSample; + uint16_t cbSize, ValidBitsPerSample; int32_t ChannelMask; - unsigned short SubFormat; + uint16_t SubFormat; char GUID [14]; } WaveHeader; @@ -135,13 +133,43 @@ typedef struct { typedef struct { char ckID [4]; uint32_t ckSize; - short version; - unsigned char track_no, index_no; + int16_t version; + unsigned char block_index_u8; + unsigned char total_samples_u8; uint32_t total_samples, block_index, block_samples, flags, crc; } WavpackHeader; #define WavpackHeaderFormat "4LS2LLLLL" +// Macros to access the 40-bit block_index field + +#define GET_BLOCK_INDEX(hdr) ( (int64_t) (hdr).block_index + ((int64_t) (hdr).block_index_u8 << 32) ) + +#define SET_BLOCK_INDEX(hdr,value) do { \ + int64_t tmp = (value); \ + (hdr).block_index = (uint32_t) tmp; \ + (hdr).block_index_u8 = \ + (unsigned char) (tmp >> 32); \ +} while (0) + +// Macros to access the 40-bit total_samples field, which is complicated by the fact that +// all 1's in the lower 32 bits indicates "unknown" (regardless of upper 8 bits) + +#define GET_TOTAL_SAMPLES(hdr) ( ((hdr).total_samples == (uint32_t) -1) ? -1 : \ + (int64_t) (hdr).total_samples + ((int64_t) (hdr).total_samples_u8 << 32) - (hdr).total_samples_u8 ) + +#define SET_TOTAL_SAMPLES(hdr,value) do { \ + int64_t tmp = (value); \ + if (tmp < 0) \ + (hdr).total_samples = (uint32_t) -1; \ + else { \ + tmp += (tmp / 0xffffffffLL); \ + (hdr).total_samples = (uint32_t) tmp; \ + (hdr).total_samples_u8 = \ + (unsigned char) (tmp >> 32); \ + } \ +} while (0) + // or-values for "flags" #define BYTES_STORED 3 // 1-4 bytes/sample @@ -172,14 +200,16 @@ typedef struct { #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 DSD_FLAG 0x80000000 // block is DSD encoded (introduced in + // WavPack 5.0) + +#define UNKNOWN_FLAGS 0x00000000 // we no longer have any of these spares #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 or encode -#define CUR_STREAM_VERS 0x407 // stream version we are [normally] writing now +#define CUR_STREAM_VERS 0x410 // stream version we are writing now //////////////////////////// WavPack Metadata ///////////////////////////////// @@ -211,14 +241,18 @@ typedef struct { #define ID_WVC_BITSTREAM 0xb #define ID_WVX_BITSTREAM 0xc #define ID_CHANNEL_INFO 0xd +#define ID_DSD_BLOCK 0xe #define ID_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1) #define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2) -#define ID_REPLAY_GAIN (ID_OPTIONAL_DATA | 0x3) -#define ID_CUESHEET (ID_OPTIONAL_DATA | 0x4) +#define ID_ALT_HEADER (ID_OPTIONAL_DATA | 0x3) +#define ID_ALT_TRAILER (ID_OPTIONAL_DATA | 0x4) #define ID_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0x5) #define ID_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x6) #define ID_SAMPLE_RATE (ID_OPTIONAL_DATA | 0x7) +#define ID_ALT_EXTENSION (ID_OPTIONAL_DATA | 0x8) +#define ID_ALT_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x9) +#define ID_NEW_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0xa) ///////////////////////// WavPack Configuration /////////////////////////////// @@ -264,6 +298,8 @@ typedef struct { #define CONFIG_PAIR_UNDEF_CHANS 0x20000000 // encode undefined channels in stereo pairs #define CONFIG_OPTIMIZE_MONO 0x80000000 // optimize for mono streams posing as stereo +#define QMODE_DSD_AUDIO 0x30 // if either of these is set in qmode (version 5.0) + /* * These config flags were never actually used, or are no longer used, or are * used for something else now. They may be used in the future for what they @@ -305,7 +341,7 @@ typedef struct { typedef struct bs { #ifdef BITSTREAM_SHORTS - unsigned short *buf, *end, *ptr; + uint16_t *buf, *end, *ptr; #else unsigned char *buf, *end, *ptr; #endif @@ -320,8 +356,10 @@ typedef struct bs { #define MAX_NTERMS 16 #define MAX_TERM 8 +// Note that this structure is directly accessed in assembly files, so modify with care + struct decorr_pass { - int term, delta, weight_A, weight_B; + int32_t term, delta, weight_A, weight_B; int32_t samples_A [MAX_TERM], samples_B [MAX_TERM]; int32_t aweight_A, aweight_B; int32_t sum_A, sum_B; @@ -342,6 +380,10 @@ struct words_data { struct entropy_data c [2]; }; +typedef struct { + int32_t filter1, filter2, filter3, filter4, filter5, filter6, factor; +} DSDfilters; + typedef struct { WavpackHeader wphdr; struct words_data w; @@ -350,9 +392,10 @@ typedef struct { unsigned char *block2buff, *block2end; int32_t *sample_buffer; + int64_t sample_index; int bits, num_terms, mute_error, joint_stereo, false_stereo, shift; int num_decorrs, num_passes, best_decorr, mask_decorr; - uint32_t sample_index, crc, crc_x, crc_wvx; + uint32_t crc, crc_x, crc_wvx; Bitstream wvbits, wvcbits, wvxbits; int init_done, wvc_skip; float delta_decay; @@ -363,12 +406,22 @@ typedef struct { struct { int32_t shaping_acc [2], shaping_delta [2], error [2]; double noise_sum, noise_ave, noise_max; - short *shaping_data, *shaping_array; + int16_t *shaping_data, *shaping_array; int32_t shaping_samples; } dc; struct decorr_pass decorr_passes [MAX_NTERMS], analysis_pass; const WavpackDecorrSpec *decorr_specs; + + struct { + unsigned char *byteptr, *endptr, (*probabilities) [256], **value_lookup, mode, ready; + int history_bins, p0, p1; + int16_t (*summed_probabilities) [256]; + uint32_t low, high, value; + DSDfilters filters [2]; + int32_t *ptable; + } dsd; + } WavpackStream; // flags for float_flags: @@ -399,6 +452,22 @@ typedef struct { int32_t (*write_bytes)(void *id, void *data, int32_t bcount); } WavpackStreamReader; +// Extended version of structure for handling large files and added +// functionality for truncating and closing files + +typedef struct { + int32_t (*read_bytes)(void *id, void *data, int32_t bcount); + int32_t (*write_bytes)(void *id, void *data, int32_t bcount); + int64_t (*get_pos)(void *id); // new signature for large files + int (*set_pos_abs)(void *id, int64_t pos); // new signature for large files + int (*set_pos_rel)(void *id, int64_t delta, int mode); // new signature for large files + int (*push_back_byte)(void *id, int c); + int64_t (*get_length)(void *id); // new signature for large files + int (*can_seek)(void *id); + int (*truncate_here)(void *id); // new function to truncate file at current position + int (*close)(void *id); // new function to close file +} WavpackStreamReader64; + typedef int (*WavpackBlockOutput)(void *id, void *data, int32_t bcount); typedef struct { @@ -414,12 +483,13 @@ typedef struct { WavpackBlockOutput blockout; void *wv_out, *wvc_out; - WavpackStreamReader *reader; + WavpackStreamReader64 *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; - uint32_t block_samples, ave_block_samples, block_boundary, max_samples, acc_samples, initial_index, riff_trailer_bytes; + int64_t filelen, file2len, filepos, file2pos, total_samples, initial_index; + uint32_t crc_errors, first_flags; + int wvc_flag, open_flags, norm_offset, reduced_channels, lossy_blocks, version_five; + uint32_t block_samples, ave_block_samples, block_boundary, max_samples, acc_samples, riff_trailer_bytes; int riff_header_added, riff_header_created; M_Tag m_tag; @@ -427,6 +497,12 @@ typedef struct { WavpackStream **streams; void *stream3; + // these items were added in 5.0 to support alternate file types (especially CAF & DSD) + unsigned char file_format, *channel_reordering; + uint32_t channel_layout, dsd_multiplier; + void *decimation_context; + char file_extension [8]; + char error_message [80]; } WavpackContext; @@ -434,6 +510,11 @@ typedef struct { #define CLEAR(destin) memset (&destin, 0, sizeof (destin)); +//////////////////////////////// decorrelation ////////////////////////////// +// modules: pack.c, unpack.c, unpack_floats.c, extra1.c, extra2.c + +// #define SKIP_DECORRELATION // experimental switch to disable all decorrelation on encode + // These macros implement the weight application and update operations // that are at the heart of the decorrelation loops. Note that there are // sometimes two and even three versions of each macro. Theses should be @@ -449,15 +530,17 @@ typedef struct { #if 1 // PERFCOND - apply decorrelation weight when 32-bit overflow is possible #define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \ (((sample & ~0xffff) >> 9) * weight) + 1) >> 1) +#elif 1 +#define apply_weight_f(weight, sample) ((int32_t)((weight * (int64_t) sample + 512) >> 10)) #else #define apply_weight_f(weight, sample) ((int32_t)floor(((double) weight * sample + 512.0) / 1024.0)) #endif -#if 1 // PERFCOND - universal version that checks input magnitude (or simply uses 64-bit ints) -#define apply_weight(weight, sample) (sample != (short) sample ? \ +#if 1 // PERFCOND - universal version that checks input magnitude or always uses long version +#define apply_weight(weight, sample) (sample != (int16_t) sample ? \ apply_weight_f (weight, sample) : apply_weight_i (weight, sample)) #else -#define apply_weight(weight, sample) ((int32_t)((weight * (int64_t) sample + 512) >> 10)) +#define apply_weight(weight, sample) (apply_weight_f (weight, sample)) #endif #if 1 // PERFCOND @@ -488,22 +571,59 @@ typedef struct { weight = (weight ^ s) - s; \ } -// bits.c +void pack_init (WavpackContext *wpc); +int pack_block (WavpackContext *wpc, int32_t *buffer); +void send_general_metadata (WavpackContext *wpc); +void free_metadata (WavpackMetadata *wpmd); +int copy_metadata (WavpackMetadata *wpmd, unsigned char *buffer_start, unsigned char *buffer_end); +double WavpackGetEncodedNoise (WavpackContext *wpc, double *peak); +int unpack_init (WavpackContext *wpc); +int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd); +int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd); +int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd); +int read_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd); +int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count); +int check_crc_error (WavpackContext *wpc); +int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values); +void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values); +void float_values (WavpackStream *wps, int32_t *values, int32_t num_values); +void dynamic_noise_shaping (WavpackContext *wpc, int32_t *buffer, int shortening_allowed); +void execute_stereo (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples); +void execute_mono (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples); -void bs_open_read (Bitstream *bs, void *buffer_start, void *buffer_end); -void bs_open_write (Bitstream *bs, void *buffer_start, void *buffer_end); -uint32_t bs_close_read (Bitstream *bs); -uint32_t bs_close_write (Bitstream *bs); +////////////////////////// DSD related (including decimation) ////////////////////////// +// modules: pack_dsd.c unpack_dsd.c -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); +void pack_dsd_init (WavpackContext *wpc); +int pack_dsd_block (WavpackContext *wpc, int32_t *buffer); +int init_dsd_block (WavpackContext *wpc, WavpackMetadata *wpmd); +int32_t unpack_dsd_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count); + +void *decimate_dsd_init (int num_channels); +void decimate_dsd_reset (void *decimate_context); +void decimate_dsd_run (void *decimate_context, int32_t *samples, int num_samples); +void decimate_dsd_destroy (void *decimate_context); + +///////////////////////////////// CPU feature detection //////////////////////////////// + +int unpack_cpu_has_feature_x86 (int findex), pack_cpu_has_feature_x86 (int findex); + +#define CPU_FEATURE_MMX 23 + +///////////////////////////// pre-4.0 version decoding //////////////////////////// +// modules: unpack3.c, unpack3_open.c, unpack3_seek.c + +WavpackContext *open_file3 (WavpackContext *wpc, char *error); +int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count); +int seek_sample3 (WavpackContext *wpc, uint32_t desired_index); +uint32_t get_sample_index3 (WavpackContext *wpc); +void free_stream3 (WavpackContext *wpc); +int get_version3 (WavpackContext *wpc); + +////////////////////////////// bitstream macros & functions ///////////////////////////// #define bs_is_open(bs) ((bs)->ptr != NULL) +uint32_t bs_close_read (Bitstream *bs); #define getbit(bs) ( \ (((bs)->bc) ? \ @@ -564,56 +684,51 @@ int DoCloseHandle (FILE *hFile), DoTruncateFile (FILE *hFile); } while ((bs)->bc >= sizeof (*((bs)->ptr)) * 8); \ } while (0) -void little_endian_to_native (void *data, char *format); -void native_to_little_endian (void *data, char *format); +///////////////////////////// entropy encoder / decoder //////////////////////////// +// modules: entropy_utils.c, read_words.c, write_words.c -// pack.c +// these control the time constant "slow_level" which is used for hybrid mode +// that controls bitrate as a function of residual level (HYBRID_BITRATE). +#define SLS 8 +#define SLO ((1 << (SLS - 1))) -void pack_init (WavpackContext *wpc); -int pack_block (WavpackContext *wpc, int32_t *buffer); -double WavpackGetEncodedNoise (WavpackContext *wpc, double *peak); +#define LIMIT_ONES 16 // maximum consecutive 1s sent for "div" data -// unpack.c +// 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 -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); +// this macro retrieves the specified median breakpoint (without frac; min = 1) +#define GET_MED(med) (((c->median [med]) >> 4) + 1) -// unpack3.c +// 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. -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); +#define INC_MED0() (c->median [0] += ((c->median [0] + DIV0) / DIV0) * 5) +#define DEC_MED0() (c->median [0] -= ((c->median [0] + (DIV0-2)) / DIV0) * 2) +#define INC_MED1() (c->median [1] += ((c->median [1] + DIV1) / DIV1) * 5) +#define DEC_MED1() (c->median [1] -= ((c->median [1] + (DIV1-2)) / DIV1) * 2) +#define INC_MED2() (c->median [2] += ((c->median [2] + DIV2) / DIV2) * 5) +#define DEC_MED2() (c->median [2] -= ((c->median [2] + (DIV2-2)) / DIV2) * 2) -// metadata.c stuff - -int read_metadata_buff (WavpackMetadata *wpmd, unsigned char *blockbuff, unsigned char **buffptr); -int write_metadata_block (WavpackContext *wpc); -int copy_metadata (WavpackMetadata *wpmd, unsigned char *buffer_start, unsigned char *buffer_end); -int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, unsigned char id); -int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd); -void free_metadata (WavpackMetadata *wpmd); - -// words.c stuff +#ifdef HAVE___BUILTIN_CLZ +#define count_bits(av) ((av) ? 32 - __builtin_clz (av) : 0) +#elif defined (_WIN64) +static __inline int count_bits (uint32_t av) { unsigned long res; return _BitScanReverse (&res, av) ? (int)(res + 1) : 0; } +#else +#define count_bits(av) ( \ + (av) < (1 << 8) ? nbits_table [av] : \ + ( \ + (av) < (1L << 16) ? nbits_table [(av) >> 8] + 8 : \ + ((av) < (1L << 24) ? nbits_table [(av) >> 16] + 16 : nbits_table [(av) >> 24] + 24) \ + ) \ +) +#endif void init_words (WavpackStream *wps); -void 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); @@ -625,34 +740,39 @@ int32_t get_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsample void flush_word (WavpackStream *wps); int32_t nosend_word (WavpackStream *wps, int32_t value, int chan); void scan_word (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir); +void update_error_limit (WavpackStream *wps); -int log2s (int32_t value); -int32_t exp2s (int log); -uint32_t log2buffer (int32_t *samples, uint32_t num_samples, int limit); +extern const uint32_t bitset [32]; +extern const uint32_t bitmask [32]; +extern const char nbits_table [256]; + +int wp_log2s (int32_t value); +int32_t wp_exp2s (int log); +int FASTCALL wp_log2 (uint32_t avalue); + +#ifdef OPT_ASM_X86 +#define LOG2BUFFER log2buffer_x86 +#elif defined(OPT_ASM_X64) && (defined (_WIN64) || defined(__CYGWIN__) || defined(__MINGW64__)) +#define LOG2BUFFER log2buffer_x64win +#elif defined(OPT_ASM_X64) +#define LOG2BUFFER log2buffer_x64 +#else +#define LOG2BUFFER log2buffer +#endif + +uint32_t LOG2BUFFER (int32_t *samples, uint32_t num_samples, int limit); signed char store_weight (int weight); int restore_weight (signed char weight); #define WORD_EOF ((int32_t)(1L << 31)) -// 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 WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp); -// extra?.c - -// void analyze_stereo (WavpackContext *wpc, int32_t *samples); -// void analyze_mono (WavpackContext *wpc, int32_t *samples); -void execute_stereo (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples); -void execute_mono (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples); - -// wputils.c +/////////////////////////// high-level unpacking API and support //////////////////////////// +// modules: open_utils.c, unpack_utils.c, unpack_seek.c, unpack_floats.c +WavpackContext *WavpackOpenFileInputEx64 (WavpackStreamReader64 *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset); WavpackContext *WavpackOpenFileInputEx (WavpackStreamReader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset); WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset); @@ -664,6 +784,15 @@ WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int f #define OPEN_STREAMING 0x20 // "streaming" mode blindly unpacks blocks // w/o regard to header file position info #define OPEN_EDIT_TAGS 0x40 // allow editing of tags +#define OPEN_FILE_UTF8 0x80 // assume filenames are UTF-8 encoded, not ANSI (Windows only) + +// new for version 5 + +#define OPEN_DSD_NATIVE 0x100 // open DSD files as bitstreams + // (returned as 8-bit "samples" stored in 32-bit words) +#define OPEN_DSD_AS_PCM 0x200 // open DSD files as 24-bit PCM (decimated 8x) +#define OPEN_ALT_TYPES 0x400 // application is aware of alternate file types & qmode + // (just affects retrieving wrappers & MD5 checksums) int WavpackGetMode (WavpackContext *wpc); @@ -682,15 +811,37 @@ int WavpackGetMode (WavpackContext *wpc); #define MODE_XMODE 0x7000 // mask for extra level (1-6, 0=unknown) #define MODE_DNS 0x8000 -char *WavpackGetErrorMessage (WavpackContext *wpc); +int WavpackGetQualifyMode (WavpackContext *wpc); 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); +int WavpackSeekSample64 (WavpackContext *wpc, int64_t sample); +int WavpackGetMD5Sum (WavpackContext *wpc, unsigned char data [16]); + +uint32_t read_next_header (WavpackStreamReader64 *reader, void *id, WavpackHeader *wphdr); +int read_wvc_block (WavpackContext *wpc); + +/////////////////////////// high-level packing API and support //////////////////////////// +// modules: pack_utils.c, pack_floats.c + +WavpackContext *WavpackOpenFileOutput (WavpackBlockOutput blockout, void *wv_id, void *wvc_id); +int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples); +int WavpackSetConfiguration64 (WavpackContext *wpc, WavpackConfig *config, int64_t total_samples); +int WavpackPackInit (WavpackContext *wpc); +int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount); +int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count); +int WavpackFlushSamples (WavpackContext *wpc); +int WavpackStoreMD5Sum (WavpackContext *wpc, unsigned char data [16]); +void WavpackSeekTrailingWrapper (WavpackContext *wpc); +void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block); +void *WavpackGetWrapperLocation (void *first_block, uint32_t *size); + +/////////////////////////////////// common utilities //////////////////////////////////// +// module: common_utils.c + +extern const uint32_t sample_rates [16]; +uint32_t WavpackGetLibraryVersion (void); +const char *WavpackGetLibraryVersionString (void); uint32_t WavpackGetSampleRate (WavpackContext *wpc); int WavpackGetBitsPerSample (WavpackContext *wpc); int WavpackGetBytesPerSample (WavpackContext *wpc); @@ -698,34 +849,32 @@ int WavpackGetNumChannels (WavpackContext *wpc); int WavpackGetChannelMask (WavpackContext *wpc); int WavpackGetReducedChannels (WavpackContext *wpc); int WavpackGetFloatNormExp (WavpackContext *wpc); -int WavpackGetMD5Sum (WavpackContext *wpc, unsigned char data [16]); +uint32_t WavpackGetNumSamples (WavpackContext *wpc); +int64_t WavpackGetNumSamples64 (WavpackContext *wpc); +uint32_t WavpackGetSampleIndex (WavpackContext *wpc); +int64_t WavpackGetSampleIndex64 (WavpackContext *wpc); +char *WavpackGetErrorMessage (WavpackContext *wpc); +int WavpackGetNumErrors (WavpackContext *wpc); +int WavpackLossyBlocks (WavpackContext *wpc); uint32_t WavpackGetWrapperBytes (WavpackContext *wpc); unsigned char *WavpackGetWrapperData (WavpackContext *wpc); void WavpackFreeWrapper (WavpackContext *wpc); -void WavpackSeekTrailingWrapper (WavpackContext *wpc); double WavpackGetProgress (WavpackContext *wpc); uint32_t WavpackGetFileSize (WavpackContext *wpc); +int64_t WavpackGetFileSize64 (WavpackContext *wpc); double WavpackGetRatio (WavpackContext *wpc); double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc); double WavpackGetInstantBitrate (WavpackContext *wpc); - -WavpackContext *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, unsigned char 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); - +WavpackContext *WavpackCloseFile (WavpackContext *wpc); void WavpackLittleEndianToNative (void *data, char *format); void WavpackNativeToLittleEndian (void *data, char *format); +void WavpackBigEndianToNative (void *data, char *format); +void WavpackNativeToBigEndian (void *data, char *format); -uint32_t WavpackGetLibraryVersion (void); -const char *WavpackGetLibraryVersionString (void); +void free_streams (WavpackContext *wpc); -// tags.c +/////////////////////////////////// tag utilities //////////////////////////////////// +// modules: tags.c, tag_utils.c int WavpackGetNumTagItems (WavpackContext *wpc); int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size); @@ -742,58 +891,5 @@ void free_tag (M_Tag *m_tag); int valid_tag (M_Tag *m_tag); int editable_tag (M_Tag *m_tag); -///////////////////////////// SIMD helper macros ///////////////////////////// - -#ifdef OPT_MMX - -#if defined (__GNUC__) && !defined (__INTEL_COMPILER) -//directly map to gcc's native builtins for faster code - -#if __GNUC__ < 4 -typedef int __di __attribute__ ((__mode__ (__DI__))); -typedef int __m64 __attribute__ ((__mode__ (__V2SI__))); -typedef int __v4hi __attribute__ ((__mode__ (__V4HI__))); -#define _m_paddsw(m1, m2) (__m64) __builtin_ia32_paddsw ((__v4hi) m1, (__v4hi) m2) -#define _m_pand(m1, m2) (__m64) __builtin_ia32_pand ((__di) m1, (__di) m2) -#define _m_pandn(m1, m2) (__m64) __builtin_ia32_pandn ((__di) m1, (__di) m2) -#define _m_pmaddwd(m1, m2) __builtin_ia32_pmaddwd ((__v4hi) m1, (__v4hi) m2) -#define _m_por(m1, m2) (__m64) __builtin_ia32_por ((__di) m1, (__di) m2) -#define _m_pxor(m1, m2) (__m64) __builtin_ia32_pxor ((__di) m1, (__di) m2) -#else -typedef int __m64 __attribute__ ((__vector_size__ (8))); -typedef short __m64_16 __attribute__ ((__vector_size__ (8))); -#define _m_paddsw(m1, m2) (__m64) __builtin_ia32_paddsw ((__m64_16) m1, (__m64_16) m2) -#define _m_pand(m1, m2) __builtin_ia32_pand (m1, m2) -#define _m_pandn(m1, m2) __builtin_ia32_pandn (m1, m2) -#define _m_pmaddwd(m1, m2) __builtin_ia32_pmaddwd ((__m64_16) m1, (__m64_16) m2) -#define _m_por(m1, m2) __builtin_ia32_por (m1, m2) -#define _m_pxor(m1, m2) __builtin_ia32_pxor (m1, m2) #endif -#define _m_paddd(m1, m2) __builtin_ia32_paddd (m1, m2) -#define _m_pcmpeqd(m1, m2) __builtin_ia32_pcmpeqd (m1, m2) - -#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4 || __has_builtin(__builtin_ia32_pslldi) -# define _m_pslldi(m1, m2) __builtin_ia32_pslldi ((__m64)m1, m2) -# define _m_psradi(m1, m2) __builtin_ia32_psradi ((__m64)m1, m2) -# define _m_psrldi(m1, m2) __builtin_ia32_psrldi ((__m64)m1, m2) -#else -# define _m_pslldi(m1, m2) __builtin_ia32_pslld (m1, m2) -# define _m_psradi(m1, m2) __builtin_ia32_psrad (m1, m2) -# define _m_psrldi(m1, m2) __builtin_ia32_psrld (m1, m2) -#endif - -#define _m_psubd(m1, m2) __builtin_ia32_psubd (m1, m2) -#define _m_punpckhdq(m1, m2) __builtin_ia32_punpckhdq (m1, m2) -#define _m_punpckldq(m1, m2) __builtin_ia32_punpckldq (m1, m2) -#define _mm_empty() __builtin_ia32_emms () -#define _mm_set_pi32(m1, m2) { m2, m1 } -#define _mm_set1_pi32(m) { m, m } - -#else -#include -#endif - -#endif //OPT_MMX - -#endif diff --git a/Frameworks/WavPack/Files/wavpack_version.h b/Frameworks/WavPack/Files/wavpack_version.h index ed6e241dd..388358e2f 100644 --- a/Frameworks/WavPack/Files/wavpack_version.h +++ b/Frameworks/WavPack/Files/wavpack_version.h @@ -11,9 +11,9 @@ #ifndef WAVPACK_VERSION_H #define WAVPACK_VERSION_H -#define LIBWAVPACK_MAJOR 4 -#define LIBWAVPACK_MINOR 70 +#define LIBWAVPACK_MAJOR 5 +#define LIBWAVPACK_MINOR 0 #define LIBWAVPACK_MICRO 0 -#define LIBWAVPACK_VERSION_STRING "4.70.0" +#define LIBWAVPACK_VERSION_STRING "5.0.0-alpha4" #endif diff --git a/Frameworks/WavPack/Files/words.c b/Frameworks/WavPack/Files/words.c deleted file mode 100644 index 0fc9a3684..000000000 --- a/Frameworks/WavPack/Files/words.c +++ /dev/null @@ -1,1525 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// 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_local.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 - -//////////////////////////////// local macros ///////////////////////////////// - -#define USE_NEXT8_OPTIMIZATION // we normally want this, but code is easier to understand without it - -#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) (((c->median [med]) >> 4) + 1) - -// These macros update the specified median breakpoints. Note that the median -// is incremented when the sample is higher than the median, else decremented. -// They are designed so that the median will never drop below 1 and the value -// is essentially stationary if there are 2 increments for every 5 decrements. - -#define INC_MED0() (c->median [0] += ((c->median [0] + DIV0) / DIV0) * 5) -#define DEC_MED0() (c->median [0] -= ((c->median [0] + (DIV0-2)) / DIV0) * 2) -#define INC_MED1() (c->median [1] += ((c->median [1] + DIV1) / DIV1) * 5) -#define DEC_MED1() (c->median [1] -= ((c->median [1] + (DIV1-2)) / DIV1) * 2) -#define INC_MED2() (c->median [2] += ((c->median [2] + DIV2) / DIV2) * 5) -#define DEC_MED2() (c->median [2] -= ((c->median [2] + (DIV2-2)) / DIV2) * 2) - -#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 unsigned char log2_table [] = { - 0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15, - 0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a, - 0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e, - 0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51, - 0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, - 0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75, - 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, - 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, - 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, - 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2, - 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0, - 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce, - 0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb, - 0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7, - 0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4, - 0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff -}; - -static const unsigned char exp2_table [] = { - 0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b, - 0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16, - 0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d, - 0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b, - 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, - 0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, - 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a, - 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, - 0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, - 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, - 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4, - 0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9, - 0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff -}; - -#ifdef USE_NEXT8_OPTIMIZATION -static const char ones_count_table [] = { - 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, - 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6, - 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, - 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7, - 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, - 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6, - 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5, - 0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8 -}; -#endif - -///////////////////////////// executable code //////////////////////////////// - -static 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. - -#ifndef NO_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) { - if (wps->wphdr.flags & FALSE_STEREO) - bitrate_0 = (wps->bits * 2 - 512) < 568 ? 0 : (wps->bits * 2 - 512) - 568; - else - bitrate_0 = wps->bits < 568 ? 0 : wps->bits - 568; - - if (!(wps->wphdr.flags & MONO_DATA)) { - - if (wps->wphdr.flags & HYBRID_BALANCE) - bitrate_1 = (wps->wphdr.flags & JOINT_STEREO) ? 256 : 0; - else { - bitrate_1 = bitrate_0; - - if (wps->wphdr.flags & JOINT_STEREO) { - if (bitrate_0 < 128) { - bitrate_1 += bitrate_0; - bitrate_0 = 0; - } - else { - bitrate_0 -= 128; - bitrate_1 += 128; - } - } - } - } - else - bitrate_1 = 0; - } - else - bitrate_0 = bitrate_1 = 0; - - wps->w.bitrate_acc [0] = (int32_t) bitrate_0 << 16; - wps->w.bitrate_acc [1] = (int32_t) bitrate_1 << 16; -} - -// Allocates the correct space in the metadata structure and writes the -// current median values to it. Values are converted from 32-bit unsigned -// to our internal 16-bit 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) -{ - unsigned char *byteptr; - int temp; - - byteptr = wpmd->data = malloc (12); - wpmd->id = ID_ENTROPY_VARS; - - *byteptr++ = temp = mylog2 (wps->w.c [0].median [0]); - *byteptr++ = temp >> 8; - *byteptr++ = temp = mylog2 (wps->w.c [0].median [1]); - *byteptr++ = temp >> 8; - *byteptr++ = temp = mylog2 (wps->w.c [0].median [2]); - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_DATA)) { - *byteptr++ = temp = mylog2 (wps->w.c [1].median [0]); - *byteptr++ = temp >> 8; - *byteptr++ = temp = mylog2 (wps->w.c [1].median [1]); - *byteptr++ = temp >> 8; - *byteptr++ = temp = mylog2 (wps->w.c [1].median [2]); - *byteptr++ = temp >> 8; - } - - wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data); - read_entropy_vars (wps, wpmd); -} - -// Allocates enough space in the metadata structure and writes the current -// high word of the bitrate accumulator and the slow_level values to it. The -// slow_level values are converted from 32-bit unsigned to our internal 16-bit -// 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) -{ - unsigned char *byteptr; - int temp; - - word_set_bitrate (wps); - byteptr = wpmd->data = malloc (512); - wpmd->id = ID_HYBRID_PROFILE; - - if (wps->wphdr.flags & HYBRID_BITRATE) { - *byteptr++ = temp = log2s (wps->w.c [0].slow_level); - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_DATA)) { - *byteptr++ = temp = log2s (wps->w.c [1].slow_level); - *byteptr++ = temp >> 8; - } - } - - *byteptr++ = temp = wps->w.bitrate_acc [0] >> 16; - *byteptr++ = temp >> 8; - - if (!(wps->wphdr.flags & MONO_DATA)) { - *byteptr++ = temp = wps->w.bitrate_acc [1] >> 16; - *byteptr++ = temp >> 8; - } - - if (wps->w.bitrate_delta [0] | wps->w.bitrate_delta [1]) { - *byteptr++ = temp = 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 = (int32_t)(byteptr - (unsigned char *) 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) -{ - unsigned char *byteptr = wpmd->data; - - if (wpmd->byte_length != ((wps->wphdr.flags & MONO_DATA) ? 6 : 12)) - return FALSE; - - wps->w.c [0].median [0] = exp2s (byteptr [0] + (byteptr [1] << 8)); - wps->w.c [0].median [1] = exp2s (byteptr [2] + (byteptr [3] << 8)); - wps->w.c [0].median [2] = exp2s (byteptr [4] + (byteptr [5] << 8)); - - if (!(wps->wphdr.flags & MONO_DATA)) { - wps->w.c [1].median [0] = exp2s (byteptr [6] + (byteptr [7] << 8)); - wps->w.c [1].median [1] = exp2s (byteptr [8] + (byteptr [9] << 8)); - wps->w.c [1].median [2] = 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) -{ - unsigned char *byteptr = wpmd->data; - unsigned char *endptr = byteptr + wpmd->byte_length; - - if (wps->wphdr.flags & HYBRID_BITRATE) { - if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) - return FALSE; - - wps->w.c [0].slow_level = exp2s (byteptr [0] + (byteptr [1] << 8)); - byteptr += 2; - - if (!(wps->wphdr.flags & MONO_DATA)) { - wps->w.c [1].slow_level = exp2s (byteptr [0] + (byteptr [1] << 8)); - byteptr += 2; - } - } - - if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) - return FALSE; - - wps->w.bitrate_acc [0] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16; - byteptr += 2; - - if (!(wps->wphdr.flags & MONO_DATA)) { - wps->w.bitrate_acc [1] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16; - byteptr += 2; - } - - if (byteptr < endptr) { - if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) - return FALSE; - - wps->w.bitrate_delta [0] = 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.c [0].slow_level + SLO) >> SLS; - - if (slow_log_0 - bitrate_0 > -0x100) - wps->w.c [0].error_limit = exp2s (slow_log_0 - bitrate_0 + 0x100); - else - wps->w.c [0].error_limit = 0; - } - else - wps->w.c [0].error_limit = exp2s (bitrate_0); - } - else { - int bitrate_1 = (wps->w.bitrate_acc [1] += wps->w.bitrate_delta [1]) >> 16; - - if (wps->wphdr.flags & HYBRID_BITRATE) { - int slow_log_0 = (wps->w.c [0].slow_level + SLO) >> SLS; - int slow_log_1 = (wps->w.c [1].slow_level + SLO) >> SLS; - - if (wps->wphdr.flags & HYBRID_BALANCE) { - int balance = (slow_log_1 - slow_log_0 + bitrate_1 + 1) >> 1; - - if (balance > bitrate_0) { - bitrate_1 = bitrate_0 * 2; - bitrate_0 = 0; - } - else if (-balance > bitrate_0) { - bitrate_0 = bitrate_0 * 2; - bitrate_1 = 0; - } - else { - bitrate_1 = bitrate_0 + balance; - bitrate_0 = bitrate_0 - balance; - } - } - - if (slow_log_0 - bitrate_0 > -0x100) - wps->w.c [0].error_limit = exp2s (slow_log_0 - bitrate_0 + 0x100); - else - wps->w.c [0].error_limit = 0; - - if (slow_log_1 - bitrate_1 > -0x100) - wps->w.c [1].error_limit = exp2s (slow_log_1 - bitrate_1 + 0x100); - else - wps->w.c [1].error_limit = 0; - } - else { - wps->w.c [0].error_limit = exp2s (bitrate_0); - wps->w.c [1].error_limit = exp2s (bitrate_1); - } - } -} - -#ifndef NO_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) -{ - struct entropy_data *c = wps->w.c + chan; - uint32_t ones_count, low, mid, high; - int sign = (value < 0) ? 1 : 0; - - if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) { - if (wps->w.zeros_acc) { - if (value) - flush_word (wps); - else { - c->slow_level -= (c->slow_level + SLO) >> SLS; - wps->w.zeros_acc++; - return 0; - } - } - else if (value) - putbit_0 (&wps->wvbits); - else { - c->slow_level -= (c->slow_level + SLO) >> SLS; - CLEAR (wps->w.c [0].median); - CLEAR (wps->w.c [1].median); - wps->w.zeros_acc = 1; - return 0; - } - } - - if (sign) - value = ~value; - - if ((wps->wphdr.flags & HYBRID_FLAG) && !chan) - update_error_limit (wps); - - if (value < (int32_t) GET_MED (0)) { - ones_count = low = 0; - high = GET_MED (0) - 1; - DEC_MED0 (); - } - else { - low = GET_MED (0); - INC_MED0 (); - - if (value - low < GET_MED (1)) { - ones_count = 1; - high = low + GET_MED (1) - 1; - DEC_MED1 (); - } - else { - low += GET_MED (1); - INC_MED1 (); - - if (value - low < GET_MED (2)) { - ones_count = 2; - high = low + GET_MED (2) - 1; - DEC_MED2 (); - } - else { - ones_count = 2 + (value - low) / GET_MED (2); - low += (ones_count - 2) * GET_MED (2); - high = low + GET_MED (2) - 1; - INC_MED2 (); - } - } - } - - mid = (high + low + 1) >> 1; - - if (wps->w.holding_zero) { - if (ones_count) - wps->w.holding_one++; - - flush_word (wps); - - if (ones_count) { - wps->w.holding_zero = 1; - ones_count--; - } - else - wps->w.holding_zero = 0; - } - else - wps->w.holding_zero = 1; - - wps->w.holding_one = ones_count * 2; - - if (!c->error_limit) { - if (high != low) { - uint32_t maxcode = high - low, code = value - low; - int bitcount = count_bits (maxcode); - uint32_t extras = bitset [bitcount] - maxcode - 1; - - if (code < extras) { - wps->w.pend_data |= code << wps->w.pend_count; - wps->w.pend_count += bitcount - 1; - } - else { - wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count; - wps->w.pend_count += bitcount - 1; - wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++; - } - } - - mid = value; - } - else - while (high - low > c->error_limit) - if (value < (int32_t) mid) { - mid = ((high = mid - 1) + low + 1) >> 1; - wps->w.pend_count++; - } - else { - mid = (high + (low = mid) + 1) >> 1; - wps->w.pend_data |= bitset [wps->w.pend_count++]; - } - - wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++); - - if (!wps->w.holding_zero) - flush_word (wps); - - if (bs_is_open (&wps->wvcbits) && c->error_limit) { - uint32_t code = value - low, maxcode = high - low; - int bitcount = count_bits (maxcode); - uint32_t extras = bitset [bitcount] - maxcode - 1; - - if (bitcount) { - if (code < extras) - putbits (code, bitcount - 1, &wps->wvcbits); - else { - putbits ((code + extras) >> 1, bitcount - 1, &wps->wvcbits); - putbit ((code + extras) & 1, &wps->wvcbits); - } - } - } - - if (wps->wphdr.flags & HYBRID_BITRATE) { - c->slow_level -= (c->slow_level + SLO) >> SLS; - c->slow_level += mylog2 (mid); - } - - return sign ? ~mid : mid; -} - -// This function is an optimized version of send_word() that only handles -// lossless (error_limit == 0) and sends an entire buffer of either mono or -// stereo data rather than a single sample. Unlike the generalized -// send_word(), it does not return values because it always encodes -// the exact value passed. - -void send_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples) -{ - struct entropy_data *c = wps->w.c; - int32_t value, csamples; - - if (!(wps->wphdr.flags & MONO_DATA)) - nsamples *= 2; - - for (csamples = 0; csamples < nsamples; ++csamples) { - int sign = ((value = *buffer++) < 0) ? 1 : 0; - uint32_t ones_count, low, high; - - if (!(wps->wphdr.flags & MONO_DATA)) - c = wps->w.c + (csamples & 1); - - if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) { - if (wps->w.zeros_acc) { - if (value) - flush_word (wps); - else { - wps->w.zeros_acc++; - continue; - } - } - else if (value) - putbit_0 (&wps->wvbits); - else { - CLEAR (wps->w.c [0].median); - CLEAR (wps->w.c [1].median); - wps->w.zeros_acc = 1; - continue; - } - } - - if (sign) - value = ~value; - - if (value < (int32_t) GET_MED (0)) { - ones_count = low = 0; - high = GET_MED (0) - 1; - DEC_MED0 (); - } - else { - low = GET_MED (0); - INC_MED0 (); - - if (value - low < GET_MED (1)) { - ones_count = 1; - high = low + GET_MED (1) - 1; - DEC_MED1 (); - } - else { - low += GET_MED (1); - INC_MED1 (); - - if (value - low < GET_MED (2)) { - ones_count = 2; - high = low + GET_MED (2) - 1; - DEC_MED2 (); - } - else { - ones_count = 2 + (value - low) / GET_MED (2); - low += (ones_count - 2) * GET_MED (2); - high = low + GET_MED (2) - 1; - INC_MED2 (); - } - } - } - - if (wps->w.holding_zero) { - if (ones_count) - wps->w.holding_one++; - - flush_word (wps); - - if (ones_count) { - wps->w.holding_zero = 1; - ones_count--; - } - else - wps->w.holding_zero = 0; - } - else - wps->w.holding_zero = 1; - - wps->w.holding_one = ones_count * 2; - - if (high != low) { - uint32_t maxcode = high - low, code = value - low; - int bitcount = count_bits (maxcode); - uint32_t extras = bitset [bitcount] - maxcode - 1; - - if (code < extras) { - wps->w.pend_data |= code << wps->w.pend_count; - wps->w.pend_count += bitcount - 1; - } - else { - wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count; - wps->w.pend_count += bitcount - 1; - wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++; - } - } - - wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++); - - if (!wps->w.holding_zero) - flush_word (wps); - } -} - -// Used by send_word() and send_word_lossless() to actually send most the -// accumulated data onto the bitstream. This is also called directly from -// clients when all words have been sent. - -void flush_word (WavpackStream *wps) -{ - if (wps->w.zeros_acc) { - int cbits = count_bits (wps->w.zeros_acc); - - while (cbits--) - putbit_1 (&wps->wvbits); - - putbit_0 (&wps->wvbits); - - while (wps->w.zeros_acc > 1) { - putbit (wps->w.zeros_acc & 1, &wps->wvbits); - wps->w.zeros_acc >>= 1; - } - - wps->w.zeros_acc = 0; - } - - if (wps->w.holding_one) { -#ifdef LIMIT_ONES - if (wps->w.holding_one >= LIMIT_ONES) { - int cbits; - - putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, &wps->wvbits); - wps->w.holding_one -= LIMIT_ONES; - cbits = count_bits (wps->w.holding_one); - - while (cbits--) - putbit_1 (&wps->wvbits); - - putbit_0 (&wps->wvbits); - - while (wps->w.holding_one > 1) { - putbit (wps->w.holding_one & 1, &wps->wvbits); - wps->w.holding_one >>= 1; - } - - wps->w.holding_zero = 0; - } - else - putbits (bitmask [wps->w.holding_one], wps->w.holding_one, &wps->wvbits); - - wps->w.holding_one = 0; -#else - do { - putbit_1 (&wps->wvbits); - } while (--wps->w.holding_one); -#endif - } - - if (wps->w.holding_zero) { - putbit_0 (&wps->wvbits); - wps->w.holding_zero = 0; - } - - if (wps->w.pend_count) { - putbits (wps->w.pend_data, wps->w.pend_count, &wps->wvbits); - wps->w.pend_data = wps->w.pend_count = 0; - } -} - -// This function is similar to send_word() except that no data is actually -// written to any stream, but it does return the value that would have been -// sent to a hybrid stream. It is used to determine beforehand how much noise -// will be added to samples. - -int32_t nosend_word (WavpackStream *wps, int32_t value, int chan) -{ - struct entropy_data *c = wps->w.c + chan; - uint32_t ones_count, low, mid, high; - int sign = (value < 0) ? 1 : 0; - - if (sign) - value = ~value; - - if ((wps->wphdr.flags & HYBRID_FLAG) && !chan) - update_error_limit (wps); - - if (value < (int32_t) GET_MED (0)) { - low = 0; - high = GET_MED (0) - 1; - DEC_MED0 (); - } - else { - low = GET_MED (0); - INC_MED0 (); - - if (value - low < GET_MED (1)) { - high = low + GET_MED (1) - 1; - DEC_MED1 (); - } - else { - low += GET_MED (1); - INC_MED1 (); - - if (value - low < GET_MED (2)) { - high = low + GET_MED (2) - 1; - DEC_MED2 (); - } - else { - ones_count = 2 + (value - low) / GET_MED (2); - low += (ones_count - 2) * GET_MED (2); - high = low + GET_MED (2) - 1; - INC_MED2 (); - } - } - } - - mid = (high + low + 1) >> 1; - - if (!c->error_limit) - mid = value; - else - while (high - low > c->error_limit) - if (value < (int32_t) mid) - mid = ((high = mid - 1) + low + 1) >> 1; - else - mid = (high + (low = mid) + 1) >> 1; - - c->slow_level -= (c->slow_level + SLO) >> SLS; - c->slow_level += 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; - struct entropy_data *c = wps->w.c; - int chan; - - init_words (wps); - - 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 = (uint32_t) labs (samples [chan = 0]); - - if (flags & HYBRID_BITRATE) { - wps->w.c [0].slow_level -= (wps->w.c [0].slow_level + SLO) >> SLS; - wps->w.c [0].slow_level += 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 = (uint32_t) labs (samples [chan = 1]); - c++; - - if (wps->wphdr.flags & HYBRID_BITRATE) { - wps->w.c [1].slow_level -= (wps->w.c [1].slow_level + SLO) >> SLS; - wps->w.c [1].slow_level += 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 (); - } - } - } - - c--; - } - - samples += dir; - } -} - -#endif - -#ifndef NO_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) -{ - register struct entropy_data *c = wps->w.c + chan; - uint32_t ones_count, low, mid, high; - int next8, sign; - int32_t value; - - if (correction) - *correction = 0; - - if (!(wps->w.c [0].median [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.c [1].median [0] & ~1)) { - uint32_t mask; - int cbits; - - if (wps->w.zeros_acc) { - if (--wps->w.zeros_acc) { - c->slow_level -= (c->slow_level + SLO) >> SLS; - return 0; - } - } - else { - for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); - - if (cbits == 33) - return WORD_EOF; - - if (cbits < 2) - wps->w.zeros_acc = cbits; - else { - for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1) - if (getbit (&wps->wvbits)) - wps->w.zeros_acc |= mask; - - wps->w.zeros_acc |= mask; - } - - if (wps->w.zeros_acc) { - c->slow_level -= (c->slow_level + SLO) >> SLS; - CLEAR (wps->w.c [0].median); - CLEAR (wps->w.c [1].median); - return 0; - } - } - } - - if (wps->w.holding_zero) - ones_count = wps->w.holding_zero = 0; - else { -#ifdef USE_NEXT8_OPTIMIZATION - if (wps->wvbits.bc < 8) { - if (++(wps->wvbits.ptr) == wps->wvbits.end) - wps->wvbits.wrap (&wps->wvbits); - - next8 = (wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc) & 0xff; - wps->wvbits.bc += sizeof (*(wps->wvbits.ptr)) * 8; - } - else - next8 = wps->wvbits.sr & 0xff; - - if (next8 == 0xff) { - wps->wvbits.bc -= 8; - wps->wvbits.sr >>= 8; - - for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count); - - if (ones_count == (LIMIT_ONES + 1)) - return WORD_EOF; - - if (ones_count == LIMIT_ONES) { - uint32_t mask; - int cbits; - - for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); - - if (cbits == 33) - return WORD_EOF; - - if (cbits < 2) - ones_count = cbits; - else { - for (mask = 1, ones_count = 0; --cbits; mask <<= 1) - if (getbit (&wps->wvbits)) - ones_count |= mask; - - ones_count |= mask; - } - - ones_count += LIMIT_ONES; - } - } - else { - wps->wvbits.bc -= (ones_count = ones_count_table [next8]) + 1; - wps->wvbits.sr >>= ones_count + 1; - } -#else - for (ones_count = 0; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count); - - if (ones_count >= LIMIT_ONES) { - uint32_t mask; - int cbits; - - if (ones_count == (LIMIT_ONES + 1)) - return WORD_EOF; - - for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); - - if (cbits == 33) - return WORD_EOF; - - if (cbits < 2) - ones_count = cbits; - else { - for (mask = 1, ones_count = 0; --cbits; mask <<= 1) - if (getbit (&wps->wvbits)) - ones_count |= mask; - - ones_count |= mask; - } - - ones_count += LIMIT_ONES; - } -#endif - - if (wps->w.holding_one) { - wps->w.holding_one = ones_count & 1; - ones_count = (ones_count >> 1) + 1; - } - else { - wps->w.holding_one = ones_count & 1; - ones_count >>= 1; - } - - wps->w.holding_zero = ~wps->w.holding_one & 1; - } - - if ((wps->wphdr.flags & HYBRID_FLAG) && !chan) - update_error_limit (wps); - - if (ones_count == 0) { - low = 0; - high = GET_MED (0) - 1; - DEC_MED0 (); - } - else { - low = GET_MED (0); - INC_MED0 (); - - if (ones_count == 1) { - high = low + GET_MED (1) - 1; - DEC_MED1 (); - } - else { - low += GET_MED (1); - INC_MED1 (); - - if (ones_count == 2) { - high = low + GET_MED (2) - 1; - DEC_MED2 (); - } - else { - low += (ones_count - 2) * GET_MED (2); - high = low + GET_MED (2) - 1; - INC_MED2 (); - } - } - } - - low &= 0x7fffffff; - high &= 0x7fffffff; - mid = (high + low + 1) >> 1; - - if (!c->error_limit) - mid = read_code (&wps->wvbits, high - low) + low; - else while (high - low > c->error_limit) { - if (getbit (&wps->wvbits)) - mid = (high + (low = mid) + 1) >> 1; - else - mid = ((high = mid - 1) + low + 1) >> 1; - } - - sign = getbit (&wps->wvbits); - - if (bs_is_open (&wps->wvcbits) && c->error_limit) { - value = read_code (&wps->wvcbits, high - low) + low; - - if (correction) - *correction = sign ? (mid - value) : (value - mid); - } - - if (wps->wphdr.flags & HYBRID_BITRATE) { - c->slow_level -= (c->slow_level + SLO) >> SLS; - c->slow_level += mylog2 (mid); - } - - return sign ? ~mid : mid; -} - -// This is an optimized version of get_word() that is used for lossless only -// (error_limit == 0). Also, rather than obtaining a single sample, it can be -// used to obtain an entire buffer of either mono or stereo samples. - -int32_t get_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples) -{ - struct entropy_data *c = wps->w.c; - uint32_t ones_count, low, high; - Bitstream *bs = &wps->wvbits; - int32_t csamples; - - if (!(wps->wphdr.flags & MONO_DATA)) - nsamples *= 2; - - for (csamples = 0; csamples < nsamples; ++csamples) { - if (!(wps->wphdr.flags & MONO_DATA)) - c = wps->w.c + (csamples & 1); - - if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && !wps->w.holding_one && wps->w.c [1].median [0] < 2) { - uint32_t mask; - int cbits; - - if (wps->w.zeros_acc) { - if (--wps->w.zeros_acc) { - *buffer++ = 0; - continue; - } - } - else { - for (cbits = 0; cbits < 33 && getbit (bs); ++cbits); - - if (cbits == 33) - break; - - if (cbits < 2) - wps->w.zeros_acc = cbits; - else { - for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1) - if (getbit (bs)) - wps->w.zeros_acc |= mask; - - wps->w.zeros_acc |= mask; - } - - if (wps->w.zeros_acc) { - CLEAR (wps->w.c [0].median); - CLEAR (wps->w.c [1].median); - *buffer++ = 0; - continue; - } - } - } - - if (wps->w.holding_zero) - ones_count = wps->w.holding_zero = 0; - else { -#ifdef USE_NEXT8_OPTIMIZATION - int next8; - - if (bs->bc < 8) { - if (++(bs->ptr) == bs->end) - bs->wrap (bs); - - next8 = (bs->sr |= *(bs->ptr) << bs->bc) & 0xff; - bs->bc += sizeof (*(bs->ptr)) * 8; - } - else - next8 = bs->sr & 0xff; - - if (next8 == 0xff) { - bs->bc -= 8; - bs->sr >>= 8; - - for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count); - - if (ones_count == (LIMIT_ONES + 1)) - break; - - if (ones_count == LIMIT_ONES) { - uint32_t mask; - int cbits; - - for (cbits = 0; cbits < 33 && getbit (bs); ++cbits); - - if (cbits == 33) - break; - - if (cbits < 2) - ones_count = cbits; - else { - for (mask = 1, ones_count = 0; --cbits; mask <<= 1) - if (getbit (bs)) - ones_count |= mask; - - ones_count |= mask; - } - - ones_count += LIMIT_ONES; - } - } - else { - bs->bc -= (ones_count = ones_count_table [next8]) + 1; - bs->sr >>= ones_count + 1; - } -#else - for (ones_count = 0; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count); - - if (ones_count >= LIMIT_ONES) { - uint32_t mask; - int cbits; - - if (ones_count == (LIMIT_ONES + 1)) - break; - - for (cbits = 0; cbits < 33 && getbit (bs); ++cbits); - - if (cbits == 33) - break; - - if (cbits < 2) - ones_count = cbits; - else { - for (mask = 1, ones_count = 0; --cbits; mask <<= 1) - if (getbit (bs)) - ones_count |= mask; - - ones_count |= mask; - } - - ones_count += LIMIT_ONES; - } -#endif - 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 (bs, high - low); - *buffer++ = (getbit (bs)) ? ~low : low; - } - - return (wps->wphdr.flags & MONO_DATA) ? csamples : (csamples / 2); -} - -// Read a single unsigned value from the specified bitstream with a value -// from 0 to maxcode. If there are exactly a power of two number of possible -// codes then this will read a fixed number of bits; otherwise it reads the -// minimum number of bits and then determines whether another bit is needed -// to define the code. - -static uint32_t FASTCALL read_code (Bitstream *bs, uint32_t maxcode) -{ - uint32_t extras, code; - int bitcount; - - if (maxcode < 2) - return maxcode ? getbit (bs) : 0; - - bitcount = count_bits (maxcode); - extras = bitset [bitcount] - maxcode - 1; - - while (bs->bc < bitcount) { - if (++(bs->ptr) == bs->end) - bs->wrap (bs); - - bs->sr |= *(bs->ptr) << bs->bc; - bs->bc += sizeof (*(bs->ptr)) * 8; - } - - if ((code = bs->sr & bitmask [bitcount - 1]) >= extras) - code = (code << 1) - extras + ((bs->sr >> (bitcount - 1)) & 1); - else - bitcount--; - - if (bs->bc > 32) { - bs->bc -= bitcount; - bs->sr = *(bs->ptr) >> (sizeof (*(bs->ptr)) * 8 - bs->bc); - } - else { - bs->sr >>= bitcount; - bs->bc -= bitcount; - } - - 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/Frameworks/WavPack/Files/wputils.c b/Frameworks/WavPack/Files/wputils.c deleted file mode 100644 index 5d30f1e2d..000000000 --- a/Frameworks/WavPack/Files/wputils.c +++ /dev/null @@ -1,2350 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2006 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// 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 - -#if defined (WIN32) || defined (__OS2__) -#include -#endif - -#ifndef LIBWAVPACK_VERSION_STRING -#include "wavpack_version.h" -#endif - -#include "wavpack_local.h" - -#ifdef WIN32 -#define stricmp(x,y) _stricmp(x,y) -#define fileno _fileno -#else -#define stricmp strcasecmp -#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 //////////////////////////// - -static const uint32_t sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050, - 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 }; - -///////////////////////////// executable code //////////////////////////////// - -#if !defined(NO_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); -static int read_wvc_block (WavpackContext *wpc); - -// This code provides an interface between the reader callback mechanism that -// WavPack uses internally and the standard fstream C library. - -#ifndef NO_USE_FSTREAMS - -static int32_t read_bytes (void *id, void *data, int32_t bcount) -{ - return (int32_t) 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 (int32_t) 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 -#if defined(__OS2__) - setmode (fileno (stdin), O_BINARY); -#endif - } - else if ((wv_id = fopen (infilename, file_mode)) == NULL) { - if (error) strcpy (error, (flags & OPEN_EDIT_TAGS) ? "can't open file for editing" : "can't open file"); - return NULL; - } - - if (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; - int num_blocks = 0; - unsigned char first_byte; - uint32_t bcount; - - if (!wpc) { - if (error) 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->max_streams = OLD_MAX_STREAMS; // use this until overwritten with actual number - wpc->open_flags = flags; - - wpc->filelen = wpc->reader->get_length (wpc->wv_in); - -#ifndef NO_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); - - if ((flags & OPEN_EDIT_TAGS) && !editable_tag (&wpc->m_tag)) { - if (error) strcpy (error, "can't edit tags located at the beginning of files!"); - return WavpackCloseFile (wpc); - } - } -#endif - -#ifndef VER4_ONLY - if (wpc->reader->read_bytes (wpc->wv_in, &first_byte, 1) != 1) { - if (error) 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 = malloc ((wpc->num_streams = 1) * sizeof (wpc->streams [0])); - wpc->streams [0] = wps = malloc (sizeof (WavpackStream)); - 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 || - (!wps->wphdr.block_samples && num_blocks++ > 16)) { - if (error) 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) { - if (error) strcpy (error, "can't read all of WavPack file!"); - return WavpackCloseFile (wpc); - } - - wps->init_done = FALSE; - - if (wps->wphdr.block_samples && !(flags & OPEN_STREAMING)) { - if (wps->wphdr.block_index || wps->wphdr.total_samples == (uint32_t) -1) { - wpc->initial_index = wps->wphdr.block_index; - wps->wphdr.block_index = 0; - - if (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 - wpc->initial_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 && !read_wvc_block (wpc)) { - if (error) strcpy (error, "not compatible with this version of correction file!"); - return WavpackCloseFile (wpc); - } - - if (!wps->init_done && !unpack_init (wpc)) { - if (error) strcpy (error, wpc->error_message [0] ? wpc->error_message : - "not compatible with this version of WavPack file!"); - - return WavpackCloseFile (wpc); - } - - wps->init_done = TRUE; - } - - 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->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 -// MODE_VERY_HIGH: file was created in the "very high" mode (or in -// the "high" mode prior to 4.4) -// MODE_MD5: file contains an MD5 checksum -// MODE_XMODE: level used for extra mode (1-6, 0=unknown) -// MODE_DNS: dynamic noise shaping - -int WavpackGetMode (WavpackContext *wpc) -{ - int mode = 0; - - if (wpc) { - if (wpc->config.flags & CONFIG_HYBRID_FLAG) - mode |= MODE_HYBRID; - else if (!(wpc->config.flags & CONFIG_LOSSY_MODE)) - mode |= MODE_LOSSLESS; - - if (wpc->wvc_flag) - mode |= (MODE_LOSSLESS | MODE_WVC); - - if (wpc->lossy_blocks) - mode &= ~MODE_LOSSLESS; - - if (wpc->config.flags & CONFIG_FLOAT_DATA) - mode |= MODE_FLOAT; - - if (wpc->config.flags & (CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG)) { - mode |= MODE_HIGH; - - if ((wpc->config.flags & CONFIG_VERY_HIGH_FLAG) || - (wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.version < 0x405)) - mode |= MODE_VERY_HIGH; - } - - if (wpc->config.flags & CONFIG_FAST_FLAG) - mode |= MODE_FAST; - - if (wpc->config.flags & CONFIG_EXTRA_MODE) - mode |= (MODE_EXTRA | (wpc->config.xmode << 12)); - - if (wpc->config.flags & CONFIG_CREATE_EXE) - mode |= MODE_SFX; - - if (wpc->config.flags & CONFIG_MD5_CHECKSUM) - mode |= MODE_MD5; - - if ((wpc->config.flags & CONFIG_HYBRID_FLAG) && (wpc->config.flags & CONFIG_DYNAMIC_SHAPING) && - wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.version >= 0x407) - mode |= MODE_DNS; - -#ifndef NO_TAGS - if (valid_tag (&wpc->m_tag)) { - mode |= MODE_VALID_TAG; - - if (valid_tag (&wpc->m_tag) == 'A') - mode |= MODE_APETAG; - } -#endif - } - - 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) { -#ifndef VER4_ONLY - if (wpc->stream3) - return get_version3 (wpc); -#endif - return 4; - } - - return 0; -} - -#endif - -// This function returns a pointer to a string describing the last error -// generated by WavPack. - -char *WavpackGetErrorMessage (WavpackContext *wpc) -{ - return wpc->error_message; -} - -#ifndef NO_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->streams [wpc->current_stream = 0] : NULL; - uint32_t bcount, samples_unpacked = 0, samples_to_unpack; - int num_channels = wpc->config.num_channels; - int file_done = FALSE; - -#ifndef VER4_ONLY - 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) { - - uint32_t nexthdrpos; - - if (wpc->wrapper_bytes >= MAX_WRAPPER_BYTES) - break; - - free_streams (wpc); - nexthdrpos = wpc->reader->get_pos (wpc->wv_in); - bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr); - - if (bcount == (uint32_t) -1) - break; - - wpc->filepos = nexthdrpos; - - if (wpc->open_flags & OPEN_STREAMING) - wps->wphdr.block_index = wps->sample_index = 0; - else - wps->wphdr.block_index -= wpc->initial_index; - - 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 last block!"); - wps->wphdr.block_samples = 0; - wps->wphdr.ckSize = 24; - break; - } - - wps->init_done = FALSE; - - if (wps->wphdr.block_samples && wps->sample_index != wps->wphdr.block_index) - wpc->crc_errors++; - - if (wps->wphdr.block_samples && wpc->wvc_flag) - read_wvc_block (wpc); - - if (!wps->wphdr.block_samples) { - if (!wps->init_done && !unpack_init (wpc)) - wpc->crc_errors++; - - wps->init_done = TRUE; - } - } - - 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 > 262144) { - strcpy (wpc->error_message, "discontinuity found, aborting file!"); - wps->wphdr.block_samples = 0; - wps->wphdr.ckSize = 24; - break; - } - - if (samples_to_unpack > samples) - samples_to_unpack = samples; - - wps->sample_index += samples_to_unpack; - samples_unpacked += samples_to_unpack; - samples -= samples_to_unpack; - - 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 (!wps->init_done && !unpack_init (wpc)) - wpc->crc_errors++; - - wps->init_done = TRUE; - - 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) { - wpc->streams = realloc (wpc->streams, (wpc->num_streams + 1) * sizeof (wpc->streams [0])); - 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) { - wpc->streams [0]->wphdr.block_samples = 0; - wpc->streams [0]->wphdr.ckSize = 24; - file_done = TRUE; - break; - } - - if (wpc->open_flags & OPEN_STREAMING) - wps->wphdr.block_index = wps->sample_index = 0; - else - wps->wphdr.block_index -= wpc->initial_index; - - 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) { - wpc->streams [0]->wphdr.block_samples = 0; - wpc->streams [0]->wphdr.ckSize = 24; - file_done = TRUE; - break; - } - - wps->init_done = FALSE; - - if (wpc->wvc_flag) - read_wvc_block (wpc); - - if (!wps->init_done && !unpack_init (wpc)) - wpc->crc_errors++; - - wps->init_done = TRUE; - } - 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 if (offset == num_channels - 1) { - while (samcnt--) { - dst [0] = src [0]; - dst += num_channels; - src += 2; - } - - wpc->crc_errors++; - offset++; - } - else { - while (samcnt--) { - dst [0] = *src++; - dst [1] = *src++; - dst += num_channels; - } - - offset += 2; - } - - if ((wps->wphdr.flags & FINAL_BLOCK) || wpc->current_stream == wpc->max_streams - 1 || offset == num_channels) - break; - else - wpc->current_stream++; - } - - wps = wpc->streams [wpc->current_stream = 0]; - free (temp_buffer); - } - else - unpack_samples (wpc, buffer, samples_to_unpack); - - if (file_done) { - strcpy (wpc->error_message, "can't read all of last block!"); - break; - } - - 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 (wpc->total_samples != (uint32_t) -1 && wps->sample_index == wpc->total_samples) - break; - } - - return samples_unpacked; -} - -#ifndef NO_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. After a -// FALSE return the file should not be accessed again (other than to close -// it); this is a fatal error. - -int WavpackSeekSample (WavpackContext *wpc, uint32_t sample) -{ - WavpackStream *wps = wpc->streams ? wpc->streams [wpc->current_stream = 0] : NULL; - 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; - -#ifndef VER4_ONLY - 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->wphdr.block_index -= wpc->initial_index; - 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; - } - - wps->init_done = FALSE; - - if (wpc->wvc_flag) { - wpc->reader->set_pos_abs (wpc->wvc_in, wpc->file2pos); - wpc->reader->read_bytes (wpc->wvc_in, &wps->wphdr, sizeof (WavpackHeader)); - little_endian_to_native (&wps->wphdr, WavpackHeaderFormat); - wps->wphdr.block_index -= wpc->initial_index; - 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 (!wps->init_done && !unpack_init (wpc)) { - free_streams (wpc); - return FALSE; - } - - wps->init_done = TRUE; - } - - while (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) { - if (++wpc->current_stream == wpc->num_streams) { - - if (wpc->num_streams == wpc->max_streams) { - free_streams (wpc); - return FALSE; - } - - wpc->streams = realloc (wpc->streams, (wpc->num_streams + 1) * sizeof (wpc->streams [0])); - 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) { - free_streams (wpc); - return FALSE; - } - - 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) { - free_streams (wpc); - return FALSE; - } - - wps->init_done = FALSE; - - if (wpc->wvc_flag && !read_wvc_block (wpc)) { - free_streams (wpc); - return FALSE; - } - - if (!wps->init_done && !unpack_init (wpc)) { - free_streams (wpc); - return FALSE; - } - - wps->init_done = TRUE; - } - else - wps = wpc->streams [wpc->current_stream]; - } - - if (sample < wps->sample_index) { - for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++) - if (!unpack_init (wpc)) - return FALSE; - else - wpc->streams [wpc->current_stream]->init_done = TRUE; - } - - samples_to_skip = sample - wps->sample_index; - - if (samples_to_skip > 131072) { - free_streams (wpc); - return FALSE; - } - - 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 - -#endif - -#ifndef NO_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 -// o CONFIG_OPTIMIZE_MONO detect and optimize for mono files posing as -// stereo (uses a more recent stream format that -// is not compatible with decoders < 4.3) - -// 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. - -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->flags & CONFIG_VERY_HIGH_FLAG) - wpc->config.flags |= CONFIG_HIGH_FLAG; - - 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 = (uint32_t) floor (config->bitrate * 256000.0 / config->sample_rate / config->num_channels + 0.5); - - if (bps > (64 << 8)) - bps = 64 << 8; - } - else - bps = (uint32_t) 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 = (config->flags & CONFIG_OPTIMIZE_MONO) ? MAX_STREAM_VERS : 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 = 0; - - wpc->streams = realloc (wpc->streams, (wpc->current_stream + 1) * sizeof (wpc->streams [0])); - 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 (!chans) { - if (config->flags & CONFIG_PAIR_UNDEF_CHANS) - chans = num_chans > 1 ? 2 : 1; - else - chans = 1; - } - - num_chans -= chans; - - if (num_chans && wpc->current_stream == NEW_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) - wpc->config.xmode = config->xmode ? config->xmode : 1; - - 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 > 16384) // 16384 bytes still leaves plenty of room for audio - write_metadata_block (wpc); // in this block (otherwise write a special one) - - 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; - - if (wpc->config.block_samples) { - if ((wpc->config.flags & CONFIG_MERGE_BLOCKS) && - wpc->block_samples > (uint32_t) wpc->config.block_samples) { - wpc->block_boundary = wpc->config.block_samples; - wpc->block_samples /= wpc->config.block_samples; - wpc->block_samples *= wpc->config.block_samples; - } - else - wpc->block_samples = wpc->config.block_samples; - } - - wpc->ave_block_samples = wpc->block_samples; - wpc->max_samples = wpc->block_samples + (wpc->block_samples >> 1); - - for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; 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; - unsigned int 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->current_stream < wpc->num_streams; 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); - unsigned char meta_id; - - if (!index || index == (uint32_t) -1) { - wpc->riff_header_added = TRUE; - meta_id = ID_RIFF_HEADER; - } - else { - wpc->riff_trailer_bytes += bcount; - 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, unsigned char 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_samples = 0x7ffff000 / (bytes_per_sample * num_channels); - - total_data_bytes = total_samples * bytes_per_sample * num_channels; - - 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)); - riffhdr.ckSize = sizeof (riffhdr) + wavhdrsize + sizeof (datahdr) + 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, bcount; - unsigned char *outbuff, *outend, *out2buff, *out2end; - int result = TRUE; - - if ((wpc->config.flags & CONFIG_FLOAT_DATA) && !(wpc->config.flags & CONFIG_SKIP_WVX)) - max_blocksize = block_samples * 16 + 4096; - else - max_blocksize = block_samples * 10 + 4096; - - 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->current_stream < wpc->num_streams; 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 (wps->wphdr.block_samples != block_samples) - block_samples = wps->wphdr.block_samples; - - 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) - memmove (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->ave_block_samples = (wpc->ave_block_samples * 0x7 + block_samples + 0x4) >> 3; - 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); - - /* note that since the RIFF wrapper will not necessarily be properly aligned, - we copy it into a newly allocated buffer before modifying it */ - - if (wpc->riff_header_created) { - if (WavpackGetWrapperLocation (first_block, &wrapper_size)) { - uint32_t data_size = WavpackGetSampleIndex (wpc) * WavpackGetNumChannels (wpc) * WavpackGetBytesPerSample (wpc); - RiffChunkHeader *riffhdr; - ChunkHeader *datahdr; - void *wrapper_buff; - - riffhdr = wrapper_buff = malloc (wrapper_size); - memcpy (wrapper_buff, WavpackGetWrapperLocation (first_block, NULL), wrapper_size); - datahdr = (ChunkHeader *)((char *) riffhdr + wrapper_size - sizeof (ChunkHeader)); - - if (!strncmp (riffhdr->ckID, "RIFF", 4)) { - little_endian_to_native (riffhdr, ChunkHeaderFormat); - riffhdr->ckSize = wrapper_size + data_size - 8 + wpc->riff_trailer_bytes; - 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); - } - - memcpy (WavpackGetWrapperLocation (first_block, NULL), wrapper_buff, wrapper_size); - free (wrapper_buff); - } - } - - 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; - unsigned char *dp, meta_id, c1, c2; - int32_t bcount, meta_bc; - - if (strncmp (wphdr->ckID, "wvpk", 4)) - return NULL; - - bcount = wphdr->ckSize - sizeof (WavpackHeader) + 8; - dp = (unsigned char *)(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 ((bcount - meta_bc) >= 0) { - if (size) - *size = meta_bc - ((meta_id & ID_ODD_SIZE) ? 1 : 0); - - return dp; - } - else - return NULL; - } - - bcount -= meta_bc; - dp += meta_bc; - } - - return NULL; -} - -#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) { -#if !defined(VER4_ONLY) && !defined(NO_UNPACK) - if (wpc->stream3) - return get_sample_index3 (wpc); - else if (wpc->streams && wpc->streams [0]) - return wpc->streams [0]->sample_index; -#else - if (wpc->streams && wpc->streams [0]) - return wpc->streams [0]->sample_index; -#endif - } - - return (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 >= 0.1 && input_size >= 1.0) - return input_size * 8.0 / output_time; - } - - return 0.0; -} - -#ifndef NO_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 && wpc->stream3) - return WavpackGetAverageBitrate (wpc, TRUE); - - if (wpc && wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.block_samples) { - double output_time = (double) wpc->streams [0]->wphdr.block_samples / 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) -{ - if (wpc->streams) { - free_streams (wpc); - - if (wpc->streams [0]) - free (wpc->streams [0]); - - free (wpc->streams); - } - -#if !defined(VER4_ONLY) && !defined(NO_UNPACK) - if (wpc->stream3) - free_stream3 (wpc); -#endif - -#if !defined(NO_UNPACK) || defined(INFO_ONLY) - if (wpc->close_files) { -#ifndef NO_USE_FSTREAMS - if (wpc->wv_in != NULL) - fclose (wpc->wv_in); - - if (wpc->wvc_in != NULL) - fclose (wpc->wvc_in); -#endif - } - - WavpackFreeWrapper (wpc); -#endif - -#ifndef NO_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; -} - -// Returns the standard Microsoft channel mask for the specified WavPack -// file. A value of zero indicates that there is no speaker assignment -// information. - -int WavpackGetChannelMask (WavpackContext *wpc) -{ - return wpc ? wpc->config.channel_mask : 0; -} - -// Return the normalization value for floating point data (valid only -// if floating point data is present). A value of 127 indicates that -// the floating point range is +/- 1.0. Higher values indicate a -// larger floating point range. - -int WavpackGetFloatNormExp (WavpackContext *wpc) -{ - return wpc->config.float_norm_exp; -} - -// Returns the actual number of valid bits per sample contained in the -// original file, which may or may not be a multiple of 8. Floating data -// always has 32 bits, integers may be from 1 to 32 bits each. When this -// value is not a multiple of 8, then the "extra" bits are located in the -// LSBs of the results. That is, values are right justified when unpacked -// into ints, but are left justified in the number of bytes used by the -// original data. - -int WavpackGetBitsPerSample (WavpackContext *wpc) -{ - return wpc ? wpc->config.bits_per_sample : 16; -} - -// Returns the number of bytes used for each sample (1 to 4) in the original -// file. This is required information for the user of this module because the -// audio data is returned in the LOWER bytes of the long buffer and must be -// left-shifted 8, 16, or 24 bits if normalized longs are required. - -int WavpackGetBytesPerSample (WavpackContext *wpc) -{ - return wpc ? wpc->config.bytes_per_sample : 2; -} - -#if !defined(NO_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; -} - -unsigned char *WavpackGetWrapperData (WavpackContext *wpc) -{ - return wpc ? wpc->wrapper_data : NULL; -} - -void WavpackFreeWrapper (WavpackContext *wpc) -{ - if (wpc && wpc->wrapper_data) { - free (wpc->wrapper_data); - wpc->wrapper_data = NULL; - wpc->wrapper_bytes = 0; - } -} - -// Normally the trailing wrapper will not be available when a WavPack file is first -// opened for reading because it is stored in the final block of the file. This -// function forces a seek to the end of the file to pick up any trailing wrapper -// stored there (then use WavPackGetWrapper**() to obtain). This can obviously only -// be used for seekable files (not pipes) and is not available for pre-4.0 WavPack -// files. - -static void seek_riff_trailer (WavpackContext *wpc); - -void WavpackSeekTrailingWrapper (WavpackContext *wpc) -{ - if ((wpc->open_flags & OPEN_WRAPPER) && - wpc->reader->can_seek (wpc->wv_in) && !wpc->stream3) { - uint32_t pos_save = wpc->reader->get_pos (wpc->wv_in); - - seek_riff_trailer (wpc); - wpc->reader->set_pos_abs (wpc->wv_in, pos_save); - } -} - -// 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, unsigned char data [16]); - -int WavpackGetMD5Sum (WavpackContext *wpc, unsigned char 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 (wpc->streams [si]->dc.shaping_data) { - free (wpc->streams [si]->dc.shaping_data); - wpc->streams [si]->dc.shaping_data = NULL; - } - - if (si) { - wpc->num_streams--; - free (wpc->streams [si]); - wpc->streams [si] = NULL; - } - } - - wpc->current_stream = 0; -} - -#if !defined(NO_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) -{ - unsigned char buffer [sizeof (*wphdr)], *sp = buffer + sizeof (*wphdr), *ep = sp; - uint32_t bytes_skipped = 0; - int bleft; - - while (1) { - if (sp < ep) { - bleft = (int)(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 [2] || sp [1] || *sp >= 24) && sp [5] == 4 && - sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff) && sp [18] < 3 && !sp [19]) { - memcpy (wphdr, buffer, sizeof (*wphdr)); - little_endian_to_native (wphdr, WavpackHeaderFormat); - return bytes_skipped; - } - - while (sp < ep && *sp != 'w') - sp++; - - if ((bytes_skipped += (uint32_t)(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; - unsigned char *tempbuff; - - if (reader->get_length (id) > 1200000L) - reader->set_pos_rel (id, -1048576L, SEEK_END); - else - reader->set_pos_abs (id, 0); - - while (1) { - bcount = read_next_header (reader, id, &wphdr); - - if (bcount == (uint32_t) -1) - return result; - - tempbuff = malloc (wphdr.ckSize + 8); - memcpy (tempbuff, &wphdr, 32); - - if (reader->read_bytes (id, tempbuff + 32, wphdr.ckSize - 24) != wphdr.ckSize - 24) { - free (tempbuff); - return result; - } - - free (tempbuff); - - if (wphdr.block_samples && (wphdr.flags & FINAL_BLOCK)) - result = wphdr.block_index + wphdr.block_samples; - } -} - -static int seek_md5 (WavpackStreamReader *reader, void *id, unsigned char data [16]) -{ - unsigned char 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; - } - } -} - -static void seek_riff_trailer (WavpackContext *wpc) -{ - WavpackStreamReader *reader = wpc->reader; - void *id = wpc->wv_in; - unsigned char 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; - - 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; - - 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; - - meta_bc += ((uint32_t) c1 << 9) + ((uint32_t) c2 << 17); - bcount -= 2; - } - - if ((meta_id & ID_UNIQUE) == ID_RIFF_TRAILER) { - wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + meta_bc); - - if (reader->read_bytes (id, wpc->wrapper_data + wpc->wrapper_bytes, meta_bc) == meta_bc) - wpc->wrapper_bytes += meta_bc; - else - return; - } - else - reader->set_pos_rel (id, meta_bc, SEEK_CUR); - - bcount -= meta_bc; - } - } -} - -// Compare the regular wv file block header to a potential matching wvc -// file block header and return action code based on analysis: -// -// 0 = use wvc block (assuming rest of block is readable) -// 1 = bad match; try to read next wvc block -// -1 = bad match; ignore wvc file for this block and backup fp (if -// possible) and try to use this block next time - -static int match_wvc_header (WavpackHeader *wv_hdr, WavpackHeader *wvc_hdr) -{ - if (wv_hdr->block_index == wvc_hdr->block_index && - wv_hdr->block_samples == wvc_hdr->block_samples) { - int wvi = 0, wvci = 0; - - if (wv_hdr->flags == wvc_hdr->flags) - return 0; - - if (wv_hdr->flags & INITIAL_BLOCK) - wvi -= 1; - - if (wv_hdr->flags & FINAL_BLOCK) - wvi += 1; - - if (wvc_hdr->flags & INITIAL_BLOCK) - wvci -= 1; - - if (wvc_hdr->flags & FINAL_BLOCK) - wvci += 1; - - return (wvci - wvi < 0) ? 1 : -1; - } - - if ((int32_t)(wvc_hdr->block_index - wv_hdr->block_index) < 0) - return 1; - else - return -1; -} - -// Read the wvc block that matches the regular wv block that has been -// read for the current stream. If an exact match is not found then -// we either keep reading or back up and (possibly) use the block -// later. The skip_wvc flag is set if not matching wvc block is found -// so that we can still decode using only the lossy version (although -// we flag this as an error). A return of FALSE indicates a serious -// error (not just that we missed one wvc block). - -static int read_wvc_block (WavpackContext *wpc) -{ - WavpackStream *wps = wpc->streams [wpc->current_stream]; - uint32_t bcount, file2pos; - WavpackHeader wphdr; - int compare_result; - - while (1) { - file2pos = wpc->reader->get_pos (wpc->wvc_in); - bcount = read_next_header (wpc->reader, wpc->wvc_in, &wphdr); - - if (bcount == (uint32_t) -1) { - wps->wvc_skip = TRUE; - wpc->crc_errors++; - return FALSE; - } - - if (wpc->open_flags & OPEN_STREAMING) - wphdr.block_index = wps->sample_index = 0; - else - wphdr.block_index -= wpc->initial_index; - - if (wphdr.flags & INITIAL_BLOCK) - wpc->file2pos = file2pos + bcount; - - compare_result = match_wvc_header (&wps->wphdr, &wphdr); - - if (!compare_result) { - wps->block2buff = malloc (wphdr.ckSize + 8); - memcpy (wps->block2buff, &wphdr, 32); - - if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wphdr.ckSize - 24) != - wphdr.ckSize - 24 || (wphdr.flags & UNKNOWN_FLAGS)) { - free (wps->block2buff); - wps->block2buff = NULL; - wps->wvc_skip = TRUE; - wpc->crc_errors++; - return FALSE; - } - - wps->wvc_skip = FALSE; - memcpy (&wps->wphdr, &wphdr, 32); - return TRUE; - } - else if (compare_result == -1) { - wps->wvc_skip = TRUE; - wpc->reader->set_pos_rel (wpc->wvc_in, -32, SEEK_CUR); - wpc->crc_errors++; - return TRUE; - } - } -} - -#ifndef NO_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) -{ - unsigned 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 = (int)(ep - sp); - memcpy (buffer, sp, bleft); - ep -= (sp - buffer); - sp = buffer; - } - else { - if (sp > ep) - if (reader->set_pos_rel (id, (int32_t)(sp - ep), SEEK_CUR)) { - free (buffer); - return -1; - } - - sp = ep = buffer; - bleft = 0; - } - - ep += reader->read_bytes (id, ep, BUFSIZE - bleft); - - if (ep - sp < 32) { - free (buffer); - return -1; - } - - while (sp + 32 <= ep) - if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' && - !(*++sp & 1) && sp [2] < 16 && !sp [3] && (sp [2] || sp [1] || *sp >= 24) && sp [5] == 4 && - sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff) && sp [18] < 3 && !sp [19]) { - memcpy (wphdr, sp - 4, sizeof (*wphdr)); - little_endian_to_native (wphdr, WavpackHeaderFormat); - - if (wphdr->block_samples && (wphdr->flags & INITIAL_BLOCK)) { - free (buffer); - return (uint32_t) (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) - wps->wphdr.block_index -= wpc->initial_index; - - 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 - -#endif - -void WavpackLittleEndianToNative (void *data, char *format) -{ - little_endian_to_native (data, format); -} - -void WavpackNativeToLittleEndian (void *data, char *format) -{ - native_to_little_endian (data, format); -} - -uint32_t WavpackGetLibraryVersion (void) -{ - return (LIBWAVPACK_MAJOR<<16) - |(LIBWAVPACK_MINOR<<8) - |(LIBWAVPACK_MICRO<<0); -} - -const char *WavpackGetLibraryVersionString (void) -{ - return LIBWAVPACK_VERSION_STRING; -} - diff --git a/Frameworks/WavPack/Files/write_words.c b/Frameworks/WavPack/Files/write_words.c new file mode 100644 index 000000000..69345ffc8 --- /dev/null +++ b/Frameworks/WavPack/Files/write_words.c @@ -0,0 +1,674 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2013 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// write_words.c + +// This module provides entropy word encoding functions using +// a variation on the Rice method. This was introduced in version 3.93 +// because it allows splitting the data into a "lossy" stream and a +// "correction" stream in a very efficient manner and is therefore ideal +// for the "hybrid" mode. For 4.0, the efficiency of this method was +// significantly improved by moving away from the normal Rice restriction of +// using powers of two for the modulus divisions and now the method can be +// used for both hybrid and pure lossless encoding. + +// Samples are divided by median probabilities at 5/7 (71.43%), 10/49 (20.41%), +// and 20/343 (5.83%). Each zone has 3.5 times fewer samples than the +// previous. Using standard Rice coding on this data would result in 1.4 +// bits per sample average (not counting sign bit). However, there is a +// very simple encoding that is over 99% efficient with this data and +// results in about 1.22 bits per sample. + +#include +#include + +#include "wavpack_local.h" + +///////////////////////////// executable code //////////////////////////////// + +// Initialize entropy encoder for the specified stream. In lossless mode there +// are no parameters to select; in hybrid mode the bitrate mode and value need +// be initialized. + +static void word_set_bitrate (WavpackStream *wps); + +void init_words (WavpackStream *wps) +{ + CLEAR (wps->w); + + if (wps->wphdr.flags & HYBRID_FLAG) + word_set_bitrate (wps); +} + +// Set up parameters for hybrid mode based on header flags and "bits" field. +// This is currently only set up for the HYBRID_BITRATE mode in which the +// allowed error varies with the residual level (from "slow_level"). The +// simpler mode (which is not used yet) has the error level directly +// controlled from the metadata. + +static void word_set_bitrate (WavpackStream *wps) +{ + int bitrate_0, bitrate_1; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + if (wps->wphdr.flags & FALSE_STEREO) + bitrate_0 = (wps->bits * 2 - 512) < 568 ? 0 : (wps->bits * 2 - 512) - 568; + else + bitrate_0 = wps->bits < 568 ? 0 : wps->bits - 568; + + if (!(wps->wphdr.flags & MONO_DATA)) { + + if (wps->wphdr.flags & HYBRID_BALANCE) + bitrate_1 = (wps->wphdr.flags & JOINT_STEREO) ? 256 : 0; + else { + bitrate_1 = bitrate_0; + + if (wps->wphdr.flags & JOINT_STEREO) { + if (bitrate_0 < 128) { + bitrate_1 += bitrate_0; + bitrate_0 = 0; + } + else { + bitrate_0 -= 128; + bitrate_1 += 128; + } + } + } + } + else + bitrate_1 = 0; + } + else + bitrate_0 = bitrate_1 = 0; + + wps->w.bitrate_acc [0] = (int32_t) bitrate_0 << 16; + wps->w.bitrate_acc [1] = (int32_t) bitrate_1 << 16; +} + +// Allocates the correct space in the metadata structure and writes the +// current median values to it. Values are converted from 32-bit unsigned +// to our internal 16-bit wp_log2 values, and read_entropy_vars () is called +// to read the values back because we must compensate for the loss through +// the log function. + +void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd) +{ + unsigned char *byteptr; + int temp; + + byteptr = wpmd->data = malloc (12); + wpmd->id = ID_ENTROPY_VARS; + + *byteptr++ = temp = wp_log2 (wps->w.c [0].median [0]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = wp_log2 (wps->w.c [0].median [1]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = wp_log2 (wps->w.c [0].median [2]); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + *byteptr++ = temp = wp_log2 (wps->w.c [1].median [0]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = wp_log2 (wps->w.c [1].median [1]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = wp_log2 (wps->w.c [1].median [2]); + *byteptr++ = temp >> 8; + } + + wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data); + read_entropy_vars (wps, wpmd); +} + +// Allocates enough space in the metadata structure and writes the current +// high word of the bitrate accumulator and the slow_level values to it. The +// slow_level values are converted from 32-bit unsigned to our internal 16-bit +// wp_log2 values. Afterward, read_entropy_vars () is called to read the values +// back because we must compensate for the loss through the log function and +// the truncation of the bitrate. + +void write_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd) +{ + unsigned char *byteptr; + int temp; + + word_set_bitrate (wps); + byteptr = wpmd->data = malloc (512); + wpmd->id = ID_HYBRID_PROFILE; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + *byteptr++ = temp = wp_log2s (wps->w.c [0].slow_level); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + *byteptr++ = temp = wp_log2s (wps->w.c [1].slow_level); + *byteptr++ = temp >> 8; + } + } + + *byteptr++ = temp = wps->w.bitrate_acc [0] >> 16; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + *byteptr++ = temp = wps->w.bitrate_acc [1] >> 16; + *byteptr++ = temp >> 8; + } + + if (wps->w.bitrate_delta [0] | wps->w.bitrate_delta [1]) { + *byteptr++ = temp = wp_log2s (wps->w.bitrate_delta [0]); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + *byteptr++ = temp = wp_log2s (wps->w.bitrate_delta [1]); + *byteptr++ = temp >> 8; + } + } + + wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data); + read_hybrid_profile (wps, wpmd); +} + +// This function writes the specified word to the open bitstream "wvbits" and, +// if the bitstream "wvcbits" is open, writes any correction data there. This +// function will work for either lossless or hybrid but because a version +// optimized for lossless exits below, it would normally be used for the hybrid +// mode only. The return value is the actual value stored to the stream (even +// if a correction file is being created) and is used as feedback to the +// predictor. + +int32_t FASTCALL send_word (WavpackStream *wps, int32_t value, int chan) +{ + struct entropy_data *c = wps->w.c + chan; + uint32_t ones_count, low, mid, high; + int sign = (value < 0) ? 1 : 0; + + if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) { + if (wps->w.zeros_acc) { + if (value) + flush_word (wps); + else { + c->slow_level -= (c->slow_level + SLO) >> SLS; + wps->w.zeros_acc++; + return 0; + } + } + else if (value) + putbit_0 (&wps->wvbits); + else { + c->slow_level -= (c->slow_level + SLO) >> SLS; + CLEAR (wps->w.c [0].median); + CLEAR (wps->w.c [1].median); + wps->w.zeros_acc = 1; + return 0; + } + } + + if (sign) + value = ~value; + + if ((wps->wphdr.flags & HYBRID_FLAG) && !chan) + update_error_limit (wps); + + if (value < (int32_t) GET_MED (0)) { + ones_count = low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (value - low < GET_MED (1)) { + ones_count = 1; + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + ones_count = 2; + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + ones_count = 2 + (value - low) / GET_MED (2); + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } + } + } + + mid = (high + low + 1) >> 1; + + if (wps->w.holding_zero) { + if (ones_count) + wps->w.holding_one++; + + flush_word (wps); + + if (ones_count) { + wps->w.holding_zero = 1; + ones_count--; + } + else + wps->w.holding_zero = 0; + } + else + wps->w.holding_zero = 1; + + wps->w.holding_one = ones_count * 2; + + if (!c->error_limit) { + if (high != low) { + uint32_t maxcode = high - low, code = value - low; + int bitcount = count_bits (maxcode); + uint32_t extras = bitset [bitcount] - maxcode - 1; + + if (code < extras) { + wps->w.pend_data |= code << wps->w.pend_count; + wps->w.pend_count += bitcount - 1; + } + else { + wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count; + wps->w.pend_count += bitcount - 1; + wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++; + } + } + + mid = value; + } + else + while (high - low > c->error_limit) + if (value < (int32_t) mid) { + mid = ((high = mid - 1) + low + 1) >> 1; + wps->w.pend_count++; + } + else { + mid = (high + (low = mid) + 1) >> 1; + wps->w.pend_data |= bitset [wps->w.pend_count++]; + } + + wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++); + + if (!wps->w.holding_zero) + flush_word (wps); + + if (bs_is_open (&wps->wvcbits) && c->error_limit) { + uint32_t code = value - low, maxcode = high - low; + int bitcount = count_bits (maxcode); + uint32_t extras = bitset [bitcount] - maxcode - 1; + + if (bitcount) { + if (code < extras) + putbits (code, bitcount - 1, &wps->wvcbits); + else { + putbits ((code + extras) >> 1, bitcount - 1, &wps->wvcbits); + putbit ((code + extras) & 1, &wps->wvcbits); + } + } + } + + if (wps->wphdr.flags & HYBRID_BITRATE) { + c->slow_level -= (c->slow_level + SLO) >> SLS; + c->slow_level += wp_log2 (mid); + } + + return sign ? ~mid : mid; +} + +// This function is an optimized version of send_word() that only handles +// lossless (error_limit == 0) and sends an entire buffer of either mono or +// stereo data rather than a single sample. Unlike the generalized +// send_word(), it does not return values because it always encodes +// the exact value passed. + +void send_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples) +{ + struct entropy_data *c = wps->w.c; + int32_t value, csamples; + + if (!(wps->wphdr.flags & MONO_DATA)) + nsamples *= 2; + + for (csamples = 0; csamples < nsamples; ++csamples) { + int sign = ((value = *buffer++) < 0) ? 1 : 0; + uint32_t ones_count, low, high; + + if (!(wps->wphdr.flags & MONO_DATA)) + c = wps->w.c + (csamples & 1); + + if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) { + if (wps->w.zeros_acc) { + if (value) + flush_word (wps); + else { + wps->w.zeros_acc++; + continue; + } + } + else if (value) + putbit_0 (&wps->wvbits); + else { + CLEAR (wps->w.c [0].median); + CLEAR (wps->w.c [1].median); + wps->w.zeros_acc = 1; + continue; + } + } + + if (sign) + value = ~value; + + if (value < (int32_t) GET_MED (0)) { + ones_count = low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (value - low < GET_MED (1)) { + ones_count = 1; + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + ones_count = 2; + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + ones_count = 2 + (value - low) / GET_MED (2); + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } + } + } + + if (wps->w.holding_zero) { + if (ones_count) + wps->w.holding_one++; + + flush_word (wps); + + if (ones_count) { + wps->w.holding_zero = 1; + ones_count--; + } + else + wps->w.holding_zero = 0; + } + else + wps->w.holding_zero = 1; + + wps->w.holding_one = ones_count * 2; + + if (high != low) { + uint32_t maxcode = high - low, code = value - low; + int bitcount = count_bits (maxcode); + uint32_t extras = bitset [bitcount] - maxcode - 1; + + if (code < extras) { + wps->w.pend_data |= code << wps->w.pend_count; + wps->w.pend_count += bitcount - 1; + } + else { + wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count; + wps->w.pend_count += bitcount - 1; + wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++; + } + } + + wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++); + + if (!wps->w.holding_zero) + flush_word (wps); + } +} + +// Used by send_word() and send_word_lossless() to actually send most the +// accumulated data onto the bitstream. This is also called directly from +// clients when all words have been sent. + +void flush_word (WavpackStream *wps) +{ + if (wps->w.zeros_acc) { + int cbits = count_bits (wps->w.zeros_acc); + + while (cbits--) + putbit_1 (&wps->wvbits); + + putbit_0 (&wps->wvbits); + + while (wps->w.zeros_acc > 1) { + putbit (wps->w.zeros_acc & 1, &wps->wvbits); + wps->w.zeros_acc >>= 1; + } + + wps->w.zeros_acc = 0; + } + + if (wps->w.holding_one) { +#ifdef LIMIT_ONES + if (wps->w.holding_one >= LIMIT_ONES) { + int cbits; + + putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, &wps->wvbits); + wps->w.holding_one -= LIMIT_ONES; + cbits = count_bits (wps->w.holding_one); + + while (cbits--) + putbit_1 (&wps->wvbits); + + putbit_0 (&wps->wvbits); + + while (wps->w.holding_one > 1) { + putbit (wps->w.holding_one & 1, &wps->wvbits); + wps->w.holding_one >>= 1; + } + + wps->w.holding_zero = 0; + } + else + putbits (bitmask [wps->w.holding_one], wps->w.holding_one, &wps->wvbits); + + wps->w.holding_one = 0; +#else + do { + putbit_1 (&wps->wvbits); + } while (--wps->w.holding_one); +#endif + } + + if (wps->w.holding_zero) { + putbit_0 (&wps->wvbits); + wps->w.holding_zero = 0; + } + + if (wps->w.pend_count) { + putbits (wps->w.pend_data, wps->w.pend_count, &wps->wvbits); + wps->w.pend_data = wps->w.pend_count = 0; + } +} + +// This function is similar to send_word() except that no data is actually +// written to any stream, but it does return the value that would have been +// sent to a hybrid stream. It is used to determine beforehand how much noise +// will be added to samples. + +int32_t nosend_word (WavpackStream *wps, int32_t value, int chan) +{ + struct entropy_data *c = wps->w.c + chan; + uint32_t ones_count, low, mid, high; + int sign = (value < 0) ? 1 : 0; + + if (sign) + value = ~value; + + if ((wps->wphdr.flags & HYBRID_FLAG) && !chan) + update_error_limit (wps); + + if (value < (int32_t) GET_MED (0)) { + low = 0; + high = GET_MED (0) - 1; + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (value - low < GET_MED (1)) { + high = low + GET_MED (1) - 1; + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + high = low + GET_MED (2) - 1; + DEC_MED2 (); + } + else { + ones_count = 2 + (value - low) / GET_MED (2); + low += (ones_count - 2) * GET_MED (2); + high = low + GET_MED (2) - 1; + INC_MED2 (); + } + } + } + + mid = (high + low + 1) >> 1; + + if (!c->error_limit) + mid = value; + else + while (high - low > c->error_limit) + if (value < (int32_t) mid) + mid = ((high = mid - 1) + low + 1) >> 1; + else + mid = (high + (low = mid) + 1) >> 1; + + c->slow_level -= (c->slow_level + SLO) >> SLS; + c->slow_level += wp_log2 (mid); + + return sign ? ~mid : mid; +} + +// This function is used to scan some number of samples to set the variables +// "slow_level" and the "median" array. In pure 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; + struct entropy_data *c = wps->w.c; + int chan; + + init_words (wps); + + if (flags & MONO_DATA) { + if (dir < 0) { + samples += (num_samples - 1); + dir = -1; + } + else + dir = 1; + } + else { + if (dir < 0) { + samples += (num_samples - 1) * 2; + dir = -2; + } + else + dir = 2; + } + + while (num_samples--) { + + value = labs (samples [chan = 0]); + + if (flags & HYBRID_BITRATE) { + wps->w.c [0].slow_level -= (wps->w.c [0].slow_level + SLO) >> SLS; + wps->w.c [0].slow_level += wp_log2 (value); + } + + if (value < GET_MED (0)) { + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (value - low < GET_MED (1)) { + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + DEC_MED2 (); + } + else { + INC_MED2 (); + } + } + } + + if (!(flags & MONO_DATA)) { + value = labs (samples [chan = 1]); + c++; + + if (wps->wphdr.flags & HYBRID_BITRATE) { + wps->w.c [1].slow_level -= (wps->w.c [1].slow_level + SLO) >> SLS; + wps->w.c [1].slow_level += wp_log2 (value); + } + + if (value < GET_MED (0)) { + DEC_MED0 (); + } + else { + low = GET_MED (0); + INC_MED0 (); + + if (value - low < GET_MED (1)) { + DEC_MED1 (); + } + else { + low += GET_MED (1); + INC_MED1 (); + + if (value - low < GET_MED (2)) { + DEC_MED2 (); + } + else { + INC_MED2 (); + } + } + } + + c--; + } + + samples += dir; + } +} + diff --git a/Frameworks/WavPack/Files/wvunpack.c b/Frameworks/WavPack/Files/wvunpack.c deleted file mode 100644 index 424514f0b..000000000 --- a/Frameworks/WavPack/Files/wvunpack.c +++ /dev/null @@ -1,2062 +0,0 @@ -//////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2013 Conifer Software. // -// All Rights Reserved. // -// Distributed under the BSD Software License (see license.txt) // -//////////////////////////////////////////////////////////////////////////// - -// wvunpack.c - -// This is the main module for the WavPack command-line decompressor. - -#if defined(WIN32) -#define WIN32_LEAN_AND_MEAN -#include -#include -#else -#if defined(__OS2__) -#define INCL_DOSPROCESS -#include -#include -#endif -#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 -#include - -#include "wavpack.h" -#include "utils.h" -#include "md5.h" - -#ifdef WIN32 -#define strdup(x) _strdup(x) -#define fileno _fileno -#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" -" WVUNPACK Hybrid Lossless Audio Decompressor %s Version %s\n" -" Copyright (c) 1998 - 2013 Conifer Software. All Rights Reserved.\n\n"; - -static const char *usage = -#if defined (WIN32) -" Usage: WVUNPACK [-options] infile[.wv]|- [outfile[.wav]|outpath|-]\n" -" (infile may contain wildcards: ?,*)\n\n" -#else -" Usage: WVUNPACK [-options] infile[.wv]|- [...] [-o outfile[.wav]|outpath|-]\n" -#endif -" (multiple input files are allowed)\n\n" -" Options: -b = blindly decode all stream blocks & ignore length info\n" -" -c = extract cuesheet only to stdout (no audio decode)\n" -" (note: equivalent to -x \"cuesheet\")\n" -" -cc = extract cuesheet file (.cue) in addition to audio file\n" -" (note: equivalent to -xx \"cuesheet=%a.cue\")\n" -" -d = delete source file if successful (use with caution!)\n" -" -f = file info to stdout in machine-parsable format\n" -" --help = this help display\n" -" -i = ignore .wvc file (forces hybrid lossy decompression)\n" -#if defined (WIN32) || defined (__OS2__) -" -l = run at low priority (for smoother multitasking)\n" -#endif -" -m = calculate and display MD5 signature; verify if lossless\n" -" -n = no audio decoding (use with -xx to extract tags only)\n" -" --no-utf8-convert = leave tag items in UTF-8 on extract or display\n" -#if !defined (WIN32) -" -o FILENAME | PATH = specify output filename or path\n" -#endif -" -q = quiet (keep console output to a minimum)\n" -" -r = force raw audio decode (results in .raw extension)\n" -" -s = display summary information only to stdout (no audio decode)\n" -" -ss = display super summary (including tags) to stdout (no decode)\n" -" --skip=[sample|hh:mm:ss.ss] = start decoding at specified sample/time\n" -" -t = copy input file's time stamp to output file(s)\n" -" --until=[+|-][sample|hh:mm:ss.ss] = stop decoding at specified sample/time\n" -" (specifying a '+' causes sample/time to be relative to '--skip' point;\n" -" specifying a '-' causes sample/time to be relative to end of file)\n" -" -v = verify source data only (no output file created)\n" -" --version = write the version to stdout\n" -" -w = regenerate .wav header (ignore RIFF data in file)\n" -" -x \"Field\" = extract specified tag field only to stdout (no audio decode)\n" -" -xx \"Field[=file]\" = extract specified tag field to file, optional\n" -" filename specification can inlude following replacement codes:\n" -" %a = audio output filename\n" -" %t = tag field name (note: comes from data for binary tags)\n" -" %e = extension from binary tag source file, or 'txt' for text tag\n" -" -y = yes to overwrite warning (use with caution!)\n" -" -z = don't set console title to indicate progress\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, delete_source, raw_decode, no_utf8_convert, no_audio_decode, file_info, - summary, ignore_wvc, quiet_mode, calc_md5, copy_time, blind_decode, wav_decode, no_console_title; - -static int num_files, file_index, outbuf_k; - -static struct sample_time_index { - int value_is_time, value_is_relative, value_is_valid; - double value; -} skip, until; - -static char *tag_extract_stdout; // extract single tag to stdout -static char **tag_extractions; // extract multiple tags to named files -static int num_tag_extractions; - -/////////////////////////// local function declarations /////////////////////// - -static void add_tag_extraction_to_list (char *spec); -static void parse_sample_time_index (struct sample_time_index *dst, char *src); -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; -{ -#ifdef __EMX__ /* OS/2 */ - _wildcard (&argc, &argv); -#endif - int verify_only = 0, error_count = 0, add_extension = 0, output_spec = 0, c_count = 0, x_count = 0; - char outpath, **matches = NULL, *outfilename = NULL; - int result; - -#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 (**++argv == '-' && (*argv)[1] == '-' && (*argv)[2]) { - char *long_option = *argv + 2, *long_param = long_option; - - while (*long_param) - if (*long_param++ == '=') - break; - - if (!strcmp (long_option, "help")) { // --help - printf ("%s", usage); - return 1; - } - else if (!strcmp (long_option, "version")) { // --version - printf ("wvunpack %s\n", PACKAGE_VERSION); - printf ("libwavpack %s\n", WavpackGetLibraryVersionString ()); - return 1; - } - else if (!strcmp (long_option, "no-utf8-convert")) // --no-utf8-convert - no_utf8_convert = 1; - else if (!strncmp (long_option, "skip", 4)) { // --skip - parse_sample_time_index (&skip, long_param); - - if (!skip.value_is_valid || skip.value_is_relative) { - error_line ("invalid --skip parameter!"); - ++error_count; - } - } - else if (!strncmp (long_option, "until", 5)) { // --until - parse_sample_time_index (&until, long_param); - - if (!until.value_is_valid) { - error_line ("invalid --until parameter!"); - ++error_count; - } - } - else { - error_line ("unknown option: %s !", long_option); - ++error_count; - } - } -#if defined (WIN32) - else if ((**argv == '-' || **argv == '/') && (*argv)[1]) -#else - else if ((**argv == '-') && (*argv)[1]) -#endif - while (*++*argv) - switch (**argv) { - case 'Y': case 'y': - overwrite_all = 1; - break; - - case 'C': case 'c': - if (++c_count == 2) { - add_tag_extraction_to_list ("cuesheet=%a.cue"); - c_count = 0; - } - - break; - - case 'D': case 'd': - delete_source = 1; - break; - -#if defined (WIN32) - case 'L': case 'l': - SetPriorityClass (GetCurrentProcess(), IDLE_PRIORITY_CLASS); - break; -#elif defined (__OS2__) - case 'L': case 'l': - DosSetPriority (0, PRTYC_IDLETIME, 0, 0); - break; -#endif -#if defined (WIN32) - case 'O': case 'o': // ignore -o in Windows to be Linux compatible - 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 'F': case 'f': - file_info = quiet_mode = no_audio_decode = 1; - break; - - case 'S': case 's': - no_audio_decode = 1; - ++summary; - break; - - case 'K': case 'k': - outbuf_k = strtol (++*argv, argv, 10); - - if (outbuf_k < 1 || outbuf_k > 16384) // range-check for reasonable values - outbuf_k = 0; - - --*argv; - break; - - case 'M': case 'm': - calc_md5 = 1; - break; - - case 'B': case 'b': - blind_decode = 1; - break; - - case 'N': case 'n': - no_audio_decode = 1; - break; - - case 'R': case 'r': - raw_decode = 1; - break; - - case 'W': case 'w': - wav_decode = 1; - break; - - case 'Q': case 'q': - quiet_mode = 1; - break; - - case 'Z': case 'z': - no_console_title = 1; - break; - - case 'X': case 'x': - if (++x_count == 3) { - error_line ("illegal option: %s !", *argv); - ++error_count; - x_count = 0; - } - - break; - - case 'I': case 'i': - ignore_wvc = 1; - break; - - default: - error_line ("illegal option: %c !", **argv); - ++error_count; - } - else { - if (x_count) { - if (x_count == 1) { - if (tag_extract_stdout) { - error_line ("can't extract more than 1 tag item to stdout at a time!"); - ++error_count; - } - else { - tag_extract_stdout = *argv; - no_audio_decode = 1; - } - } - else if (x_count == 2) - add_tag_extraction_to_list (*argv); - - x_count = 0; - } -#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], ".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 - 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 (delete_source && (verify_only || skip.value_is_valid || until.value_is_valid)) { - error_line ("can't delete in verify mode or when --skip or --until are used!"); - delete_source = 0; - } - - if (raw_decode && wav_decode) { - error_line ("-r (raw decode) and -w (wav header) modes are incompatible!"); - ++error_count; - } - - if (verify_only && outfilename) { - error_line ("outfile specification and verify mode are incompatible!"); - ++error_count; - } - - if (c_count == 1) { - if (tag_extract_stdout) { - error_line ("can't extract more than 1 tag item to stdout at a time!"); - error_count++; - } - else { - tag_extract_stdout = "cuesheet"; - no_audio_decode = 1; - } - } - - if ((summary || tag_extract_stdout) && (num_tag_extractions || outfilename || verify_only || delete_source || wav_decode || raw_decode)) { - error_line ("can't display summary information or extract a tag to stdout and do anything else!"); - ++error_count; - } - - if ((tag_extract_stdout || num_tag_extractions) && outfilename && *outfilename == '-') { - error_line ("can't extract tags when unpacking audio to stdout!"); - ++error_count; - } - - if (!quiet_mode && !error_count) - fprintf (stderr, sign_on, VERSION_OS, WavpackGetLibraryVersionString ()); - - 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"); - intptr_t file; - int di; - - for (di = file_index; di < num_files - 1; di++) - matches [di] = matches [di + 1]; - - file_index--; - num_files--; - - if ((file = _findfirst (infilename, &_finddata_t)) != (intptr_t) -1) { - 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 (file, &_finddata_t) == 0); - - _findclose (file); - } - - 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 && !quiet_mode) - 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 - - if (!no_console_title) - DoSetConsoleTitle ("WvUnpack Completed"); - - return error_count ? 1 : 0; -} - -// Parse the parameter of the --skip and --until commands, which are of the form: -// [+|-] [samples | hh:mm:ss.ss] -// The value is returned in a double (in the "dst" struct) as either samples or -// seconds (if a time is specified). If sample, the value must be an integer. - -static void parse_sample_time_index (struct sample_time_index *dst, char *src) -{ - int colons = 0; - double temp; - - memset (dst, 0, sizeof (*dst)); - - if (*src == '+' || *src == '-') - dst->value_is_relative = (*src++ == '+') ? 1 : -1; - - while (*src) - if (*src == ':') { - if (++colons == 3) - return; - - src++; - dst->value_is_time = 1; - dst->value *= 60.0; - continue; - } - else if (*src == '.' || isdigit (*src)) { - temp = strtod (src, &src); - - if (temp < 0.0 || (dst->value_is_time && temp >= 60.0) || - (!dst->value_is_time && temp != floor (temp))) - return; - - dst->value += temp; - } - else - return; - - dst->value_is_valid = 1; -} - - -// Open specified file for writing, with overwrite check. If the specified file already exists (and the user has -// agreed to overwrite) then open a temp file instead and store a pointer to that filename at "tempfilename" (otherwise -// the pointer is set to NULL). The caller will be required to perform the rename (and free the pointer) once the file -// is completely written and closed. Note that for a file to be considered "overwritable", it must both be openable for -// reading and have at least 1 readable byte - this prevents us getting stuck on "nul" (Windows). - -static FILE *open_output_file (char *filename, char **tempfilename) -{ - FILE *retval, *testfile; - char dummy; - - *tempfilename = NULL; - - if (*filename == '-') { -#if defined(WIN32) - _setmode (fileno (stdout), O_BINARY); -#endif -#if defined(__OS2__) - setmode (fileno (stdout), O_BINARY); -#endif - return stdout; - } - - testfile = fopen (filename, "rb"); - - if (testfile) { - size_t res = fread (&dummy, 1, 1, testfile); - - fclose (testfile); - - if (res == 1) { - int count = 0; - - if (!overwrite_all) { - fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (filename)); - - if (!no_console_title) - DoSetConsoleTitle ("overwrite?"); - - switch (yna ()) { - case 'n': - return NULL; - - case 'a': - overwrite_all = 1; - } - } - - *tempfilename = malloc (strlen (filename) + 16); - - while (1) { - strcpy (*tempfilename, filename); - - if (filespec_ext (*tempfilename)) { - if (count++) - sprintf (filespec_ext (*tempfilename), ".tmp%d", count-1); - else - strcpy (filespec_ext (*tempfilename), ".tmp"); - - strcat (*tempfilename, filespec_ext (filename)); - } - else { - if (count++) - sprintf (*tempfilename + strlen (*tempfilename), ".tmp%d", count-1); - else - strcat (*tempfilename, ".tmp"); - } - - testfile = fopen (*tempfilename, "rb"); - - if (!testfile) - break; - - res = fread (&dummy, 1, 1, testfile); - fclose (testfile); - - if (res != 1) - break; - } - } - } - - retval = fopen (*tempfilename ? *tempfilename : filename, "w+b"); - - if (retval == NULL) - error_line ("can't create file %s!", *tempfilename ? *tempfilename : filename); - - return retval; -} - -// 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 int do_tag_extractions (WavpackContext *wpc, char *outfilename); -static unsigned char *format_samples (int bps, unsigned char *dst, int32_t *src, uint32_t samcnt); -static void dump_summary (WavpackContext *wpc, char *name, FILE *dst); -static int write_riff_header (FILE *outfile, WavpackContext *wpc, uint32_t total_samples); -static int dump_tag_item_to_file (WavpackContext *wpc, const char *tag_item, FILE *dst, char *fn); -static void dump_file_info (WavpackContext *wpc, char *name, FILE *dst); - -static int unpack_file (char *infilename, char *outfilename) -{ - int result = NO_ERROR, md5_diff = FALSE, created_riff_header = FALSE; - int open_flags = 0, bytes_per_sample, num_channels, wvc_mode, bps; - uint32_t output_buffer_size = 0, bcount, total_unpacked_samples = 0; - uint32_t skip_sample_index = 0, until_samples_total = 0; - unsigned char *output_buffer = NULL, *output_pointer = NULL; - double dtime, progress = -1.0; - char *outfilename_temp; - 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 && !blind_decode && !wav_decode && - !skip.value_is_valid && !until.value_is_valid) || summary > 1) - open_flags |= OPEN_WRAPPER; - - if (blind_decode) - open_flags |= OPEN_STREAMING; - - if (!ignore_wvc) - open_flags |= OPEN_WVC; - - if (summary > 1 || num_tag_extractions || tag_extract_stdout) - 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 (skip.value_is_valid) { - if (skip.value_is_time) - skip_sample_index = (uint32_t) (skip.value * WavpackGetSampleRate (wpc)); - else - skip_sample_index = (uint32_t) skip.value; - - if (skip_sample_index && !WavpackSeekSample (wpc, skip_sample_index)) { - error_line ("can't seek to specified --skip point!"); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - if (WavpackGetNumSamples (wpc) != (uint32_t) -1) - until_samples_total = WavpackGetNumSamples (wpc) - skip_sample_index; - } - - if (until.value_is_valid) { - if (until.value_is_time) - until.value *= WavpackGetSampleRate (wpc); - - if (until.value_is_relative == -1) { - if (WavpackGetNumSamples (wpc) == (uint32_t) -1) { - error_line ("can't use negative relative --until command with files of unknown length!"); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - - if ((uint32_t) until.value + skip_sample_index < WavpackGetNumSamples (wpc)) - until_samples_total = WavpackGetNumSamples (wpc) - (uint32_t) until.value - skip_sample_index; - else - until_samples_total = 0; - } - else { - if (until.value_is_relative == 1) - until_samples_total = (uint32_t) until.value; - else if ((uint32_t) until.value > skip_sample_index) - until_samples_total = (uint32_t) until.value - skip_sample_index; - else - until_samples_total = 0; - - if (WavpackGetNumSamples (wpc) != (uint32_t) -1 && - skip_sample_index + until_samples_total > WavpackGetNumSamples (wpc)) - until_samples_total = WavpackGetNumSamples (wpc) - skip_sample_index; - } - - if (!until_samples_total) { - error_line ("--until command results in no samples to decode!"); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - } - - if (file_info) - dump_file_info (wpc, infilename, stdout); - else if (summary) - dump_summary (wpc, infilename, stdout); - else if (tag_extract_stdout) { - if (!dump_tag_item_to_file (wpc, tag_extract_stdout, stdout, NULL)) { - error_line ("tag \"%s\" not found!", tag_extract_stdout); - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - } - else if (num_tag_extractions && outfilename && *outfilename != '-' && filespec_name (outfilename)) { - result = do_tag_extractions (wpc, outfilename); - - if (result != NO_ERROR) { - WavpackCloseFile (wpc); - return result; - } - } - - if (no_audio_decode) { - WavpackCloseFile (wpc); - return NO_ERROR; - } - - if (outfilename) { - if ((outfile = open_output_file (outfilename, &outfilename_temp)) == NULL) { - WavpackCloseFile (wpc); - return SOFT_ERROR; - } - else if (*outfilename == '-') { - if (!quiet_mode) - fprintf (stderr, "unpacking %s%s to stdout,", *infilename == '-' ? - "stdin" : FN_FIT (infilename), wvc_mode ? " (+.wvc)" : ""); - } - else if (!quiet_mode) - fprintf (stderr, "restoring %s,", FN_FIT (outfilename)); - - if (outbuf_k) - output_buffer_size = outbuf_k * 1024; - else - output_buffer_size = 1024 * 256; - - output_pointer = output_buffer = malloc (output_buffer_size); - - if (!output_buffer) { - error_line ("can't allocate buffer for decoding!"); - WavpackCloseFile (wpc); - return HARD_ERROR; - } - } - 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 (outfile && !raw_decode) { - if (until_samples_total) { - if (!write_riff_header (outfile, wpc, until_samples_total)) { - DoTruncateFile (outfile); - result = HARD_ERROR; - } - else - created_riff_header = TRUE; - } - else if (WavpackGetWrapperBytes (wpc)) { - if (!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); - } - else if (!write_riff_header (outfile, wpc, WavpackGetNumSamples (wpc))) { - DoTruncateFile (outfile); - result = HARD_ERROR; - } - else - created_riff_header = TRUE; - } - - 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 - (uint32_t)(output_pointer - output_buffer)) / bytes_per_sample; - - if (samples_to_unpack > 4096) - samples_to_unpack = 4096; - } - else - samples_to_unpack = 4096; - - if (until_samples_total && samples_to_unpack > until_samples_total - total_unpacked_samples) - samples_to_unpack = until_samples_total - total_unpacked_samples; - - 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)) < (uint32_t) bytes_per_sample) { - if (!DoWriteFile (outfile, output_buffer, (uint32_t)(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, (unsigned char *) 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 ()) { -#if defined(WIN32) - fprintf (stderr, "^C\n"); -#else - fprintf (stderr, "\n"); -#endif - 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); - } - } - - if (output_buffer) - free (output_buffer); - - if (!check_break () && calc_md5) { - char md5_string1 [] = "00000000000000000000000000000000"; - char md5_string2 [] = "00000000000000000000000000000000"; - unsigned char 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); - } - - while (!created_riff_header && 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); - WavpackUnpackSamples (wpc, temp_buffer, 1); // perhaps there's more RIFF info... - } - - free (temp_buffer); - - if (result == NO_ERROR && outfile && created_riff_header && - (WavpackGetNumSamples (wpc) == (uint32_t) -1 || - (until_samples_total ? until_samples_total : WavpackGetNumSamples (wpc)) != total_unpacked_samples)) { - if (*outfilename == '-' || DoSetFilePositionAbsolute (outfile, 0)) - error_line ("can't update RIFF header with actual size"); - else if (!write_riff_header (outfile, wpc, total_unpacked_samples)) { - DoTruncateFile (outfile); - result = HARD_ERROR; - } - } - - // if we are not just in verify only mode, flush the output stream and if it's a real file (not stdout) - // close it and make sure it's not zero length (which means we got an error somewhere) - - if (outfile) { - fflush (outfile); - - if (*outfilename != '-') { - int64_t outfile_length = DoGetFileSize (outfile); - - if (!DoCloseHandle (outfile)) { - error_line ("can't close file %s!", FN_FIT (outfilename)); - result = SOFT_ERROR; - } - - if (!outfile_length) - DoDeleteFile (outfilename_temp ? outfilename_temp : outfilename); - } - } - - // if we were writing to a temp file because the target file already existed, - // do the rename / overwrite now (and if that fails, flag the error) - -#if defined(WIN32) - if (result == NO_ERROR && outfilename && outfilename_temp) { - if (remove (outfilename)) { - error_line ("can not remove file %s, result saved in %s!", outfilename, outfilename_temp); - result = SOFT_ERROR; - } - else if (rename (outfilename_temp, outfilename)) { - error_line ("can not rename temp file %s to %s!", outfilename_temp, outfilename); - result = SOFT_ERROR; - } - } -#else - if (result == NO_ERROR && outfilename && outfilename_temp && rename (outfilename_temp, outfilename)) { - error_line ("can not rename temp file %s to %s!", outfilename_temp, outfilename); - result = SOFT_ERROR; - } -#endif - - if (outfilename && outfilename_temp) free (outfilename_temp); - - if (result == NO_ERROR && copy_time && outfilename && - !copy_timestamp (infilename, outfilename)) - error_line ("failure copying time stamp!"); - - if (result == NO_ERROR) { - if (!until_samples_total && WavpackGetNumSamples (wpc) != (uint32_t) -1) { - if (total_unpacked_samples < WavpackGetNumSamples (wpc)) { - error_line ("file is missing %u samples!", - WavpackGetNumSamples (wpc) - total_unpacked_samples); - result = SOFT_ERROR; - } - else if (total_unpacked_samples > WavpackGetNumSamples (wpc)) { - error_line ("file has %u extra samples!", - total_unpacked_samples - WavpackGetNumSamples (wpc)); - result = SOFT_ERROR; - } - } - - if (WavpackGetNumErrors (wpc)) { - error_line ("missing data or crc errors detected in %d block(s)!", WavpackGetNumErrors (wpc)); - result = SOFT_ERROR; - } - } - - if (result == NO_ERROR && md5_diff && (WavpackGetMode (wpc) & MODE_LOSSLESS) && !until_samples_total) { - 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) { - int res = DoDeleteFile (infilename); - - if (!quiet_mode || !res) - error_line ("%s source file %s", res ? - "deleted" : "can't delete", infilename); - - if (wvc_mode) { - char in2filename [PATH_MAX]; - - strcpy (in2filename, infilename); - strcat (in2filename, "c"); - res = DoDeleteFile (in2filename); - - if (!quiet_mode || !res) - error_line ("%s source file %s", res ? - "deleted" : "can't delete", in2filename); - } - } - - return result; -} - -static void add_tag_extraction_to_list (char *spec) -{ - tag_extractions = realloc (tag_extractions, (num_tag_extractions + 1) * sizeof (*tag_extractions)); - tag_extractions [num_tag_extractions] = malloc (strlen (spec) + 10); - strcpy (tag_extractions [num_tag_extractions], spec); - num_tag_extractions++; -} - -static int do_tag_extractions (WavpackContext *wpc, char *outfilename) -{ - int result = NO_ERROR, i; - FILE *outfile; - - for (i = 0; result == NO_ERROR && i < num_tag_extractions; ++i) { - char *extraction_spec = strdup (tag_extractions [i]); - char *output_spec = strchr (extraction_spec, '='); - char tag_filename [256]; - - if (output_spec && output_spec > extraction_spec && strlen (output_spec) > 1) - *output_spec++ = 0; - - if (dump_tag_item_to_file (wpc, extraction_spec, NULL, tag_filename)) { - int max_length = (int) strlen (outfilename) + (int) strlen (tag_filename) + 10; - char *full_filename; - - if (output_spec) - max_length += (int) strlen (output_spec) + 256; - - full_filename = malloc (max_length * 2 + 1); - strcpy (full_filename, outfilename); - - if (output_spec) { - char *dst = filespec_name (full_filename); - - while (*output_spec && dst - full_filename < max_length) { - if (*output_spec == '%') { - switch (*++output_spec) { - case 'a': // audio filename - strcpy (dst, filespec_name (outfilename)); - - if (filespec_ext (dst)) // get rid of any extension - dst = filespec_ext (dst); - else - dst += strlen (dst); - - output_spec++; - break; - - case 't': // tag field name - strcpy (dst, tag_filename); - - if (filespec_ext (dst)) // get rid of any extension - dst = filespec_ext (dst); - else - dst += strlen (dst); - - output_spec++; - break; - - case 'e': // default extension - if (filespec_ext (tag_filename)) { - strcpy (dst, filespec_ext (tag_filename) + 1); - dst += strlen (dst); - } - - output_spec++; - break; - - default: - *dst++ = '%'; - } - } - else - *dst++ = *output_spec++; - } - - *dst = 0; - } - else - strcpy (filespec_name (full_filename), tag_filename); - - if (!overwrite_all && (outfile = fopen (full_filename, "r")) != NULL) { - DoCloseHandle (outfile); - fprintf (stderr, "overwrite %s (yes/no/all)? ", FN_FIT (full_filename)); - - if (!no_console_title) - DoSetConsoleTitle ("overwrite?"); - - switch (yna ()) { - - case 'n': - *full_filename = 0; - break; - - case 'a': - overwrite_all = 1; - } - } - - // open output file for writing - - if (*full_filename) { - if ((outfile = fopen (full_filename, "w")) == NULL) { - error_line ("can't create file %s!", FN_FIT (full_filename)); - result = SOFT_ERROR; - } - else { - dump_tag_item_to_file (wpc, extraction_spec, outfile, NULL); - - if (!DoCloseHandle (outfile)) { - error_line ("can't close file %s!", FN_FIT (full_filename)); - result = SOFT_ERROR; - } - else if (!quiet_mode) - error_line ("extracted tag \"%s\" to file %s", extraction_spec, FN_FIT (full_filename)); - } - } - - free (full_filename); - } - - free (extraction_spec); - } - - return result; -} - -// Reformat samples from longs in processor's native endian mode to -// little-endian data with (possibly) less than 4 bytes / sample. - -static unsigned char *format_samples (int bps, unsigned char *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++ = (unsigned char) (temp = *src++); - *dst++ = (unsigned char) (temp >> 8); - } - - break; - - case 3: - while (samcnt--) { - *dst++ = (unsigned char) (temp = *src++); - *dst++ = (unsigned char) (temp >> 8); - *dst++ = (unsigned char) (temp >> 16); - } - - break; - - case 4: - while (samcnt--) { - *dst++ = (unsigned char) (temp = *src++); - *dst++ = (unsigned char) (temp >> 8); - *dst++ = (unsigned char) (temp >> 16); - *dst++ = (unsigned char) (temp >> 24); - } - - break; - } - - return dst; -} - -static int write_riff_header (FILE *outfile, WavpackContext *wpc, uint32_t total_samples) -{ - RiffChunkHeader riffhdr; - ChunkHeader datahdr, fmthdr; - WaveHeader wavhdr; - uint32_t bcount; - - uint32_t total_data_bytes; - int num_channels = WavpackGetNumChannels (wpc); - int32_t channel_mask = WavpackGetChannelMask (wpc); - int32_t sample_rate = WavpackGetSampleRate (wpc); - int bytes_per_sample = WavpackGetBytesPerSample (wpc); - int bits_per_sample = WavpackGetBitsPerSample (wpc); - int format = WavpackGetFloatNormExp (wpc) ? 3 : 1; - int wavhdrsize = 16; - - if (format == 3 && WavpackGetFloatNormExp (wpc) != 127) { - error_line ("can't create valid RIFF wav header for non-normalized floating data!"); - return FALSE; - } - - if (total_samples == (uint32_t) -1) - total_samples = 0x7ffff000 / (bytes_per_sample * num_channels); - - total_data_bytes = total_samples * bytes_per_sample * num_channels; - - 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)); - riffhdr.ckSize = sizeof (riffhdr) + wavhdrsize + sizeof (datahdr) + 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 - - WavpackNativeToLittleEndian (&riffhdr, ChunkHeaderFormat); - WavpackNativeToLittleEndian (&fmthdr, ChunkHeaderFormat); - WavpackNativeToLittleEndian (&wavhdr, WaveHeaderFormat); - WavpackNativeToLittleEndian (&datahdr, ChunkHeaderFormat); - - if (!DoWriteFile (outfile, &riffhdr, sizeof (riffhdr), &bcount) || bcount != sizeof (riffhdr) || - !DoWriteFile (outfile, &fmthdr, sizeof (fmthdr), &bcount) || bcount != sizeof (fmthdr) || - !DoWriteFile (outfile, &wavhdr, wavhdrsize, &bcount) || bcount != wavhdrsize || - !DoWriteFile (outfile, &datahdr, sizeof (datahdr), &bcount) || bcount != sizeof (datahdr)) { - error_line ("can't write .WAV data, disk probably full!"); - return FALSE; - } - - return TRUE; -} - -static void dump_UTF8_string (char *string, FILE *dst); -static void UTF8ToAnsi (char *string, int len); -static const char *speakers [] = { - "FL", "FR", "FC", "LFE", "BL", "BR", "FLC", "FRC", "BC", - "SL", "SR", "TC", "TFL", "TFC", "TFR", "TBL", "TBC", "TBR" -}; - -static void dump_summary (WavpackContext *wpc, char *name, FILE *dst) -{ - uint32_t channel_mask = (uint32_t) WavpackGetChannelMask (wpc); - int num_channels = WavpackGetNumChannels (wpc); - unsigned char md5_sum [16]; - char 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: %u bytes\n", WavpackGetFileSize (wpc)); - } - - fprintf (dst, "source: %d-bit %s at %u Hz\n", WavpackGetBitsPerSample (wpc), - (WavpackGetMode (wpc) & MODE_FLOAT) ? "floats" : "ints", - WavpackGetSampleRate (wpc)); - - if (!channel_mask) - strcpy (modes, "unassigned speakers"); - else if (num_channels == 1 && channel_mask == 0x4) - strcpy (modes, "mono"); - else if (num_channels == 2 && channel_mask == 0x3) - strcpy (modes, "stereo"); - else { - int cc = num_channels, si = 0; - uint32_t cm = channel_mask; - - modes [0] = 0; - - while (cc && cm) { - if (cm & 1) { - strcat (modes, speakers [si]); - if (--cc) - strcat (modes, ","); - } - cm >>= 1; - si++; - } - - if (cc) - strcat (modes, "..."); - } - - fprintf (dst, "channels: %d (%s)\n", num_channels, modes); - - 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 -= (int)(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_VERY_HIGH) - strcat (modes, ", very high"); - else if (WavpackGetMode (wpc) & MODE_HIGH) - strcat (modes, ", high"); - - if (WavpackGetMode (wpc) & MODE_EXTRA) { - strcat (modes, ", extra"); - - if (WavpackGetMode (wpc) & MODE_XMODE) { - char xmode[3] = "-0"; - - xmode [1] = ((WavpackGetMode (wpc) & MODE_XMODE) >> 12) + '0'; - strcat (modes, xmode); - } - } - - if (WavpackGetMode (wpc) & MODE_SFX) - strcat (modes, ", sfx"); - - if (WavpackGetMode (wpc) & MODE_DNS) - strcat (modes, ", dns"); - - 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 (summary > 1) { - uint32_t header_bytes = WavpackGetWrapperBytes (wpc), trailer_bytes, i; - unsigned char *header_data = WavpackGetWrapperData (wpc); - char header_name [5]; - - strcpy (header_name, "????"); - - for (i = 0; i < 4 && i < header_bytes; ++i) - if (header_data [i] >= 0x20 && header_data [i] <= 0x7f) - header_name [i] = header_data [i]; - - WavpackFreeWrapper (wpc); - WavpackSeekTrailingWrapper (wpc); - trailer_bytes = WavpackGetWrapperBytes (wpc); - - if (header_bytes && trailer_bytes) - fprintf (dst, "file wrapper: %d + %d bytes (%s)\n", - header_bytes, trailer_bytes, header_name); - else if (header_bytes) - fprintf (dst, "file wrapper: %d byte %s header\n", - header_bytes, header_name); - else if (trailer_bytes) - fprintf (dst, "file wrapper: %d byte trailer only\n", - trailer_bytes); - else - fprintf (dst, "file wrapper: none (raw audio)\n"); - } - - if (WavpackGetMode (wpc) & MODE_VALID_TAG) { - int ape_tag = WavpackGetMode (wpc) & MODE_APETAG; - int num_binary_items = WavpackGetNumBinaryTagItems (wpc); - int num_items = WavpackGetNumTagItems (wpc), i; - char *spaces = " "; - - fprintf (dst, "\n%s tag items: %d\n", ape_tag ? "APEv2" : "ID3v1", num_items + num_binary_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); - - fprintf (dst, "%s:%s", item, strlen (item) < strlen (spaces) ? spaces + strlen (item) : " "); - - if (ape_tag) { - for (j = 0; j < value_len; ++j) - if (!value [j]) - value [j] = '\\'; - - if (strchr (value, '\n')) - fprintf (dst, "%d-byte multi-line text string\n", value_len); - else { - dump_UTF8_string (value, dst); - fprintf (dst, "\n"); - } - } - else - fprintf (dst, "%s\n", value); - - free (value); - free (item); - } - - for (i = 0; i < num_binary_items; ++i) { - int item_len, value_len; - char *item, fname [256]; - - item_len = WavpackGetBinaryTagItemIndexed (wpc, i, NULL, 0); - item = malloc (item_len + 1); - WavpackGetBinaryTagItemIndexed (wpc, i, item, item_len + 1); - value_len = dump_tag_item_to_file (wpc, item, NULL, fname); - fprintf (dst, "%s:%s", item, strlen (item) < strlen (spaces) ? spaces + strlen (item) : " "); - - if (filespec_ext (fname)) - fprintf (dst, "%d-byte binary item (%s)\n", value_len, filespec_ext (fname)+1); - else - fprintf (dst, "%d-byte binary item\n", value_len); - -#if 0 // debug binary tag reading - { - char md5_string [] = "00000000000000000000000000000000"; - unsigned char md5_result [16]; - MD5_CTX md5_context; - char *value; - int i, j; - - MD5Init (&md5_context); - value_len = WavpackGetBinaryTagItem (wpc, item, NULL, 0); - value = malloc (value_len); - value_len = WavpackGetBinaryTagItem (wpc, item, value, value_len); - - for (i = 0; i < value_len; ++i) - if (!value [i]) { - MD5Update (&md5_context, (unsigned char *) value + i + 1, value_len - i - 1); - MD5Final (md5_result, &md5_context); - for (j = 0; j < 16; ++j) - sprintf (md5_string + (j * 2), "%02x", md5_result [j]); - fprintf (dst, " %d byte string >>%s<<\n", i, value); - fprintf (dst, " %d bytes binary data >>%s<<\n", value_len - i - 1, md5_string); - break; - } - - if (i == value_len) - fprintf (dst, " no NULL found in binary value (or value not readable)\n"); - - free (value); - } -#endif - free (item); - } - } -} - -// Dump a summary of the file information in a machine-parsable format to the specified file (usually stdout). -// The items are separated by semi-colons and the line is newline terminated, like in this example: -// -// 44100;16;int;2;0x3;9878400;023066a6345773674c0755ee6be54d87;4;0x18a2;Track01.wv -// -// The fields are, in order: -// -// 1. sampling rate -// 2. bit-depth (1-32) -// 3. format ("int" or "float") -// 4. number of channels -// 5. channel mask (in hex because it's a mask, always prefixed with "0x") -// 6. number of samples (missing if unknown) -// 7. md5sum (technically is hex, but not prefixed with "0x", might be missing) -// 8. encoder version (basically this will always be 4, but there are some old files out there, could be 5 one day) -// 9. encoding mode (in hex because it's a bitfield, always prefixed with "0x") -// 10. filename (if available) - -static void dump_file_info (WavpackContext *wpc, char *name, FILE *dst) -{ - unsigned char md5_sum [16]; - char str [80]; - - sprintf (str, "%d;%d;%s;%d;0x%x;", WavpackGetSampleRate (wpc), WavpackGetBitsPerSample (wpc), - (WavpackGetMode (wpc) & MODE_FLOAT) ? "float" : "int", WavpackGetNumChannels (wpc), WavpackGetChannelMask (wpc)); - - if (WavpackGetNumSamples (wpc) != (uint32_t) -1) - sprintf (str + strlen (str), "%u;", WavpackGetNumSamples (wpc)); - else - strcat (str, ";"); - - 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]); - - sprintf (str + strlen (str), "%s;", md5_string); - } - else - strcat (str, ";"); - - sprintf (str + strlen (str), "%d;0x%x", WavpackGetVersion (wpc), WavpackGetMode (wpc)); - - if (name && *name != '-') - fprintf (dst, "%s;%s\n", str, name); - else - fprintf (dst, "%s;\n", str); -} - -// Dump the specified tag field to the specified stream. Both text and binary tags may be written, -// and in Windows the appropriate file mode will be set. If the tag is not found then 0 is returned, -// otherwise the length of the data is returned, and this is true even when the file pointer is NULL -// so this can be used to determine if the tag exists before further processing. -// -// The "fname" parameter can optionally be set to a character array that will accept the suggested -// filename. This is formed by the tag item name with the extension ".txt" for text fields; for -// binary fields this is supplied by convention as a NULL terminated string at the beginning of the -// data, so this is returned. The string should have 256 characters available. - -static int dump_tag_item_to_file (WavpackContext *wpc, const char *tag_item, FILE *dst, char *fname) -{ - if (WavpackGetMode (wpc) & MODE_VALID_TAG) { - if (WavpackGetTagItem (wpc, tag_item, NULL, 0)) { - int value_len = WavpackGetTagItem (wpc, tag_item, NULL, 0); - char *value; - - if (fname) { - strcpy (fname, tag_item); - strcat (fname, ".txt"); - } - - if (!value_len || !dst) - return value_len; - -#if defined(WIN32) - _setmode (fileno (dst), O_TEXT); -#endif -#if defined(__OS2__) - setmode (fileno (dst), O_TEXT); -#endif - value = malloc (value_len * 2 + 1); - WavpackGetTagItem (wpc, tag_item, value, value_len + 1); - dump_UTF8_string (value, dst); - free (value); - return value_len; - } - else if (WavpackGetBinaryTagItem (wpc, tag_item, NULL, 0)) { - int value_len = WavpackGetBinaryTagItem (wpc, tag_item, NULL, 0), res = 0, i; - uint32_t bcount = 0; - char *value; - - value = malloc (value_len); - WavpackGetBinaryTagItem (wpc, tag_item, value, value_len); - - for (i = 0; i < value_len; ++i) - if (!value [i]) { - - if (dst) { -#if defined(WIN32) - _setmode (fileno (dst), O_BINARY); -#endif -#if defined(__OS2__) - setmode (fileno (dst), O_BINARY); -#endif - res = DoWriteFile (dst, (unsigned char *) value + i + 1, value_len - i - 1, &bcount); - } - - if (fname) { - if (i < 256) - strcpy (fname, value); - else { - strcpy (fname, tag_item); - strcat (fname, ".bin"); - } - } - - break; - } - - free (value); - - if (i == value_len) - return 0; - - if (dst && (!res || bcount != value_len - i - 1)) - return 0; - - return value_len - i - 1; - } - else - return 0; - } - else - return 0; -} - -// Dump the specified null-terminated, possibly multi-line, UTF-8 string to -// the specified stream. To make sure that this works correctly on both -// Windows and Linux, all CR characters ('\r') are removed from the stream -// and it is assumed that the output FILE will be in "text" mode (on Windows). -// Lines are processed and transmitted one at a time. - -static void dump_UTF8_string (char *string, FILE *dst) -{ - while (*string) { - char *p = string, *temp; - int len = 0; - - while (*p) { - if (*p != '\r') - ++len; - - if (*p++ == '\n') - break; - } - - if (!len) - return; - - p = temp = malloc (len * 2 + 1); - - while (*string) { - if (*string != '\r') - *p++ = *string; - - if (*string++ == '\n') - break; - } - - *p = 0; - - if (!no_utf8_convert) - UTF8ToAnsi (temp, len * 2); - - fputs (temp, dst); - free (temp); - } -} - -#if defined (WIN32) - -// 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; -} - -#endif - -// 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 void UTF8ToAnsi (char *string, int len) -{ - int max_chars = (int) 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_ACP, 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; - iconv_t converter; - - memset(temp, 0, len); - old_locale = setlocale (LC_CTYPE, ""); - converter = iconv_open ("", "UTF-8"); - - if (converter != (iconv_t) -1) { - err = iconv (converter, &inp, &insize, &outp, &outsize); - iconv_close (converter); - } - else - err = -1; - - 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]; - - if (!no_console_title) { - file_progress = (file_index + file_progress) / num_files; - sprintf (title, "%d%% (WvUnpack)", (int) ((file_progress * 100.0) + 0.5)); - DoSetConsoleTitle (title); - } -} diff --git a/Frameworks/WavPack/WavPack.xcodeproj/project.pbxproj b/Frameworks/WavPack/WavPack.xcodeproj/project.pbxproj index 9bcc6ad11..8723178bb 100644 --- a/Frameworks/WavPack/WavPack.xcodeproj/project.pbxproj +++ b/Frameworks/WavPack/WavPack.xcodeproj/project.pbxproj @@ -7,32 +7,66 @@ objects = { /* Begin PBXBuildFile section */ + 8310BA351D7377850055CEC5 /* common_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA281D7377850055CEC5 /* common_utils.c */; }; + 8310BA361D7377850055CEC5 /* decorr_tables.h in Headers */ = {isa = PBXBuildFile; fileRef = 8310BA291D7377850055CEC5 /* decorr_tables.h */; }; + 8310BA371D7377850055CEC5 /* decorr_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2A1D7377850055CEC5 /* decorr_utils.c */; }; + 8310BA381D7377850055CEC5 /* entropy_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2B1D7377850055CEC5 /* entropy_utils.c */; }; + 8310BA391D7377850055CEC5 /* open_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2C1D7377850055CEC5 /* open_utils.c */; }; + 8310BA3A1D7377850055CEC5 /* read_words.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2D1D7377850055CEC5 /* read_words.c */; }; + 8310BA3B1D7377850055CEC5 /* tag_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2E1D7377850055CEC5 /* tag_utils.c */; }; + 8310BA3C1D7377850055CEC5 /* unpack_dsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA2F1D7377850055CEC5 /* unpack_dsd.c */; }; + 8310BA3D1D7377850055CEC5 /* unpack_floats.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA301D7377850055CEC5 /* unpack_floats.c */; }; + 8310BA3E1D7377850055CEC5 /* unpack_seek.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA311D7377850055CEC5 /* unpack_seek.c */; }; + 8310BA3F1D7377850055CEC5 /* unpack_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA321D7377850055CEC5 /* unpack_utils.c */; }; + 8310BA401D7377850055CEC5 /* unpack3_open.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA331D7377850055CEC5 /* unpack3_open.c */; }; + 8310BA411D7377850055CEC5 /* unpack3_seek.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA341D7377850055CEC5 /* unpack3_seek.c */; }; + 8310BA431D7377B80055CEC5 /* write_words.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA421D7377B80055CEC5 /* write_words.c */; }; + 8310BA4A1D7377DC0055CEC5 /* open_filename.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA441D7377DC0055CEC5 /* open_filename.c */; }; + 8310BA4B1D7377DC0055CEC5 /* open_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA451D7377DC0055CEC5 /* open_legacy.c */; }; + 8310BA4C1D7377DC0055CEC5 /* pack_dns.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA461D7377DC0055CEC5 /* pack_dns.c */; }; + 8310BA4D1D7377DC0055CEC5 /* pack_dsd.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA471D7377DC0055CEC5 /* pack_dsd.c */; }; + 8310BA4E1D7377DC0055CEC5 /* pack_floats.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA481D7377DC0055CEC5 /* pack_floats.c */; }; + 8310BA4F1D7377DC0055CEC5 /* pack_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8310BA491D7377DC0055CEC5 /* pack_utils.c */; }; 83DD1DD017FA038A00249519 /* utils.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DD1DCD17FA038A00249519 /* utils.h */; settings = {ATTRIBUTES = (Public, ); }; }; 83DD1DD117FA038A00249519 /* wavpack_local.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DD1DCE17FA038A00249519 /* wavpack_local.h */; }; 83DD1DD217FA038A00249519 /* wavpack_version.h in Headers */ = {isa = PBXBuildFile; fileRef = 83DD1DCF17FA038A00249519 /* wavpack_version.h */; }; 83DD1DD417FA03F900249519 /* tags.c in Sources */ = {isa = PBXBuildFile; fileRef = 83DD1DD317FA03F900249519 /* tags.c */; }; - 83DD1DD517FA04E100249519 /* wavpack.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574C109F31BD50080F1EE /* wavpack.c */; }; 8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; }; 8E7574B309F31BB90080F1EE /* md5.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E7574AF09F31BB90080F1EE /* md5.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8E7574B409F31BB90080F1EE /* unpack3.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E7574B009F31BB90080F1EE /* unpack3.h */; settings = {ATTRIBUTES = (Public, ); }; }; 8E7574B509F31BB90080F1EE /* wavpack.h in Headers */ = {isa = PBXBuildFile; fileRef = 8E7574B109F31BB90080F1EE /* wavpack.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 8E7574C509F31BD50080F1EE /* bits.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574B709F31BD50080F1EE /* bits.c */; }; 8E7574C609F31BD50080F1EE /* extra1.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574B809F31BD50080F1EE /* extra1.c */; }; 8E7574C709F31BD50080F1EE /* extra2.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574B909F31BD50080F1EE /* extra2.c */; }; - 8E7574C809F31BD50080F1EE /* float.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BA09F31BD50080F1EE /* float.c */; }; 8E7574C909F31BD50080F1EE /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BB09F31BD50080F1EE /* md5.c */; }; - 8E7574CA09F31BD50080F1EE /* metadata.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BC09F31BD50080F1EE /* metadata.c */; }; 8E7574CB09F31BD50080F1EE /* pack.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BD09F31BD50080F1EE /* pack.c */; }; 8E7574CC09F31BD50080F1EE /* unpack.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BE09F31BD50080F1EE /* unpack.c */; }; 8E7574CD09F31BD50080F1EE /* unpack3.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574BF09F31BD50080F1EE /* unpack3.c */; }; 8E7574CE09F31BD50080F1EE /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574C009F31BD50080F1EE /* utils.c */; }; - 8E7574D009F31BD50080F1EE /* words.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574C209F31BD50080F1EE /* words.c */; }; - 8E7574D109F31BD50080F1EE /* wputils.c in Sources */ = {isa = PBXBuildFile; fileRef = 8E7574C309F31BD50080F1EE /* wputils.c */; }; 8E7574F509F31C7D0080F1EE /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E7574F409F31C7D0080F1EE /* libiconv.dylib */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 8310BA281D7377850055CEC5 /* common_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = common_utils.c; path = Files/common_utils.c; sourceTree = ""; }; + 8310BA291D7377850055CEC5 /* decorr_tables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = decorr_tables.h; path = Files/decorr_tables.h; sourceTree = ""; }; + 8310BA2A1D7377850055CEC5 /* decorr_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = decorr_utils.c; path = Files/decorr_utils.c; sourceTree = ""; }; + 8310BA2B1D7377850055CEC5 /* entropy_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = entropy_utils.c; path = Files/entropy_utils.c; sourceTree = ""; }; + 8310BA2C1D7377850055CEC5 /* open_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = open_utils.c; path = Files/open_utils.c; sourceTree = ""; }; + 8310BA2D1D7377850055CEC5 /* read_words.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = read_words.c; path = Files/read_words.c; sourceTree = ""; }; + 8310BA2E1D7377850055CEC5 /* tag_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tag_utils.c; path = Files/tag_utils.c; sourceTree = ""; }; + 8310BA2F1D7377850055CEC5 /* unpack_dsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_dsd.c; path = Files/unpack_dsd.c; sourceTree = ""; }; + 8310BA301D7377850055CEC5 /* unpack_floats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_floats.c; path = Files/unpack_floats.c; sourceTree = ""; }; + 8310BA311D7377850055CEC5 /* unpack_seek.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_seek.c; path = Files/unpack_seek.c; sourceTree = ""; }; + 8310BA321D7377850055CEC5 /* unpack_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_utils.c; path = Files/unpack_utils.c; sourceTree = ""; }; + 8310BA331D7377850055CEC5 /* unpack3_open.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack3_open.c; path = Files/unpack3_open.c; sourceTree = ""; }; + 8310BA341D7377850055CEC5 /* unpack3_seek.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack3_seek.c; path = Files/unpack3_seek.c; sourceTree = ""; }; + 8310BA421D7377B80055CEC5 /* write_words.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = write_words.c; path = Files/write_words.c; sourceTree = ""; }; + 8310BA441D7377DC0055CEC5 /* open_filename.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = open_filename.c; path = Files/open_filename.c; sourceTree = ""; }; + 8310BA451D7377DC0055CEC5 /* open_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = open_legacy.c; path = Files/open_legacy.c; sourceTree = ""; }; + 8310BA461D7377DC0055CEC5 /* pack_dns.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_dns.c; path = Files/pack_dns.c; sourceTree = ""; }; + 8310BA471D7377DC0055CEC5 /* pack_dsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_dsd.c; path = Files/pack_dsd.c; sourceTree = ""; }; + 8310BA481D7377DC0055CEC5 /* pack_floats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_floats.c; path = Files/pack_floats.c; sourceTree = ""; }; + 8310BA491D7377DC0055CEC5 /* pack_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_utils.c; path = Files/pack_utils.c; sourceTree = ""; }; 833F683A1CDBCAB200AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = ""; }; 83DD1DCD17FA038A00249519 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = utils.h; path = Files/utils.h; sourceTree = ""; }; 83DD1DCE17FA038A00249519 /* wavpack_local.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wavpack_local.h; path = Files/wavpack_local.h; sourceTree = ""; }; @@ -43,20 +77,13 @@ 8E7574AF09F31BB90080F1EE /* md5.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = md5.h; path = Files/md5.h; sourceTree = ""; }; 8E7574B009F31BB90080F1EE /* unpack3.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = unpack3.h; path = Files/unpack3.h; sourceTree = ""; }; 8E7574B109F31BB90080F1EE /* wavpack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = wavpack.h; path = Files/wavpack.h; sourceTree = ""; }; - 8E7574B709F31BD50080F1EE /* bits.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bits.c; path = Files/bits.c; sourceTree = ""; }; 8E7574B809F31BD50080F1EE /* extra1.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = extra1.c; path = Files/extra1.c; sourceTree = ""; }; 8E7574B909F31BD50080F1EE /* extra2.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = extra2.c; path = Files/extra2.c; sourceTree = ""; }; - 8E7574BA09F31BD50080F1EE /* float.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = float.c; path = Files/float.c; sourceTree = ""; }; 8E7574BB09F31BD50080F1EE /* md5.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = md5.c; path = Files/md5.c; sourceTree = ""; }; - 8E7574BC09F31BD50080F1EE /* metadata.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = metadata.c; path = Files/metadata.c; sourceTree = ""; }; 8E7574BD09F31BD50080F1EE /* pack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = pack.c; path = Files/pack.c; sourceTree = ""; }; 8E7574BE09F31BD50080F1EE /* unpack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = unpack.c; path = Files/unpack.c; sourceTree = ""; }; 8E7574BF09F31BD50080F1EE /* unpack3.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = unpack3.c; path = Files/unpack3.c; sourceTree = ""; }; 8E7574C009F31BD50080F1EE /* utils.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = utils.c; path = Files/utils.c; sourceTree = ""; }; - 8E7574C109F31BD50080F1EE /* wavpack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wavpack.c; path = Files/wavpack.c; sourceTree = ""; }; - 8E7574C209F31BD50080F1EE /* words.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = words.c; path = Files/words.c; sourceTree = ""; }; - 8E7574C309F31BD50080F1EE /* wputils.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wputils.c; path = Files/wputils.c; sourceTree = ""; }; - 8E7574C409F31BD50080F1EE /* wvunpack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wvunpack.c; path = Files/wvunpack.c; sourceTree = ""; }; 8E7574F409F31C7D0080F1EE /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = /usr/lib/libiconv.dylib; sourceTree = ""; }; /* End PBXFileReference section */ @@ -128,21 +155,33 @@ 8E7574A809F31B940080F1EE /* Source */ = { isa = PBXGroup; children = ( + 8310BA441D7377DC0055CEC5 /* open_filename.c */, + 8310BA451D7377DC0055CEC5 /* open_legacy.c */, + 8310BA461D7377DC0055CEC5 /* pack_dns.c */, + 8310BA471D7377DC0055CEC5 /* pack_dsd.c */, + 8310BA481D7377DC0055CEC5 /* pack_floats.c */, + 8310BA491D7377DC0055CEC5 /* pack_utils.c */, + 8310BA421D7377B80055CEC5 /* write_words.c */, + 8310BA281D7377850055CEC5 /* common_utils.c */, + 8310BA2A1D7377850055CEC5 /* decorr_utils.c */, + 8310BA2B1D7377850055CEC5 /* entropy_utils.c */, + 8310BA2C1D7377850055CEC5 /* open_utils.c */, + 8310BA2D1D7377850055CEC5 /* read_words.c */, + 8310BA2E1D7377850055CEC5 /* tag_utils.c */, + 8310BA2F1D7377850055CEC5 /* unpack_dsd.c */, + 8310BA301D7377850055CEC5 /* unpack_floats.c */, + 8310BA311D7377850055CEC5 /* unpack_seek.c */, + 8310BA321D7377850055CEC5 /* unpack_utils.c */, + 8310BA331D7377850055CEC5 /* unpack3_open.c */, + 8310BA341D7377850055CEC5 /* unpack3_seek.c */, 83DD1DD317FA03F900249519 /* tags.c */, - 8E7574B709F31BD50080F1EE /* bits.c */, 8E7574B809F31BD50080F1EE /* extra1.c */, 8E7574B909F31BD50080F1EE /* extra2.c */, - 8E7574BA09F31BD50080F1EE /* float.c */, 8E7574BB09F31BD50080F1EE /* md5.c */, - 8E7574BC09F31BD50080F1EE /* metadata.c */, 8E7574BD09F31BD50080F1EE /* pack.c */, 8E7574BE09F31BD50080F1EE /* unpack.c */, 8E7574BF09F31BD50080F1EE /* unpack3.c */, 8E7574C009F31BD50080F1EE /* utils.c */, - 8E7574C109F31BD50080F1EE /* wavpack.c */, - 8E7574C209F31BD50080F1EE /* words.c */, - 8E7574C309F31BD50080F1EE /* wputils.c */, - 8E7574C409F31BD50080F1EE /* wvunpack.c */, ); name = Source; sourceTree = ""; @@ -150,6 +189,7 @@ 8E7574A909F31B9A0080F1EE /* Headers */ = { isa = PBXGroup; children = ( + 8310BA291D7377850055CEC5 /* decorr_tables.h */, 83DD1DCD17FA038A00249519 /* utils.h */, 83DD1DCE17FA038A00249519 /* wavpack_local.h */, 83DD1DCF17FA038A00249519 /* wavpack_version.h */, @@ -172,6 +212,7 @@ 8E7574B409F31BB90080F1EE /* unpack3.h in Headers */, 83DD1DD017FA038A00249519 /* utils.h in Headers */, 83DD1DD217FA038A00249519 /* wavpack_version.h in Headers */, + 8310BA361D7377850055CEC5 /* decorr_tables.h in Headers */, 8E7574B509F31BB90080F1EE /* wavpack.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -240,20 +281,33 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 83DD1DD517FA04E100249519 /* wavpack.c in Sources */, + 8310BA4A1D7377DC0055CEC5 /* open_filename.c in Sources */, + 8310BA4B1D7377DC0055CEC5 /* open_legacy.c in Sources */, + 8310BA4C1D7377DC0055CEC5 /* pack_dns.c in Sources */, + 8310BA4D1D7377DC0055CEC5 /* pack_dsd.c in Sources */, + 8310BA4E1D7377DC0055CEC5 /* pack_floats.c in Sources */, + 8310BA4F1D7377DC0055CEC5 /* pack_utils.c in Sources */, + 8310BA431D7377B80055CEC5 /* write_words.c in Sources */, + 8310BA351D7377850055CEC5 /* common_utils.c in Sources */, + 8310BA371D7377850055CEC5 /* decorr_utils.c in Sources */, + 8310BA381D7377850055CEC5 /* entropy_utils.c in Sources */, + 8310BA391D7377850055CEC5 /* open_utils.c in Sources */, + 8310BA3A1D7377850055CEC5 /* read_words.c in Sources */, + 8310BA3B1D7377850055CEC5 /* tag_utils.c in Sources */, + 8310BA3C1D7377850055CEC5 /* unpack_dsd.c in Sources */, + 8310BA3D1D7377850055CEC5 /* unpack_floats.c in Sources */, + 8310BA3E1D7377850055CEC5 /* unpack_seek.c in Sources */, + 8310BA3F1D7377850055CEC5 /* unpack_utils.c in Sources */, + 8310BA401D7377850055CEC5 /* unpack3_open.c in Sources */, + 8310BA411D7377850055CEC5 /* unpack3_seek.c in Sources */, 83DD1DD417FA03F900249519 /* tags.c in Sources */, - 8E7574C509F31BD50080F1EE /* bits.c in Sources */, 8E7574C609F31BD50080F1EE /* extra1.c in Sources */, 8E7574C709F31BD50080F1EE /* extra2.c in Sources */, - 8E7574C809F31BD50080F1EE /* float.c in Sources */, 8E7574C909F31BD50080F1EE /* md5.c in Sources */, - 8E7574CA09F31BD50080F1EE /* metadata.c in Sources */, 8E7574CB09F31BD50080F1EE /* pack.c in Sources */, 8E7574CC09F31BD50080F1EE /* unpack.c in Sources */, 8E7574CD09F31BD50080F1EE /* unpack3.c in Sources */, 8E7574CE09F31BD50080F1EE /* utils.c in Sources */, - 8E7574D009F31BD50080F1EE /* words.c in Sources */, - 8E7574D109F31BD50080F1EE /* wputils.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Plugins/WavPack/WavPackDecoder.h b/Plugins/WavPack/WavPackDecoder.h index 331e3a507..55b17a55a 100644 --- a/Plugins/WavPack/WavPackDecoder.h +++ b/Plugins/WavPack/WavPackDecoder.h @@ -22,6 +22,7 @@ int bitsPerSample; int channels; + BOOL floatingPoint; int bitrate; float frequency; long totalFrames; diff --git a/Plugins/WavPack/WavPackDecoder.m b/Plugins/WavPack/WavPackDecoder.m index d43ef217c..3a9c832dd 100644 --- a/Plugins/WavPack/WavPackDecoder.m +++ b/Plugins/WavPack/WavPackDecoder.m @@ -110,6 +110,8 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) reader.get_length = GetLengthProc; reader.can_seek = CanSeekProc; reader.write_bytes = WriteBytesProc; + + open_flags |= OPEN_DSD_AS_PCM | OPEN_ALT_TYPES; //No corrections file (WVC) support at the moment. wpc = WavpackOpenFileInputEx(&reader, (__bridge void *)(self), NULL, error, open_flags, 0); @@ -126,6 +128,8 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) totalFrames = WavpackGetNumSamples(wpc); bitrate = (int)(WavpackGetAverageBitrate(wpc, TRUE)/1000.0); + + floatingPoint = MODE_FLOAT & WavpackGetMode(wpc) && 127 == WavpackGetFloatNormExp(wpc); [self willChangeValueForKey:@"properties"]; [self didChangeValueForKey:@"properties"]; @@ -169,21 +173,6 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) // Wavpack uses "complete" samples (one sample across all channels), i.e. a Core Audio frame samplesRead = WavpackUnpackSamples(wpc, inputBuffer, frames/channels); - // Handle floating point files - // Perform hard clipping and convert to integers - if(MODE_FLOAT & WavpackGetMode(wpc) && 127 == WavpackGetFloatNormExp(wpc)) { - float f; - alias32 = inputBuffer; - for(sample = 0; sample < samplesRead * channels; ++sample) { - f = * ((float *) alias32); - - if(f > 1.0) { f = 1.0; } - if(f < -1.0) { f = -1.0; } - - *alias32++ = (int32_t) (f * 2147483647.0); - } - } - switch(bitsPerSample) { case 8: // No need for byte swapping @@ -263,6 +252,7 @@ int32_t WriteBytesProc(void *ds, void *data, int32_t bcount) [NSNumber numberWithInt:bitsPerSample],@"bitsPerSample", [NSNumber numberWithInt:bitrate],@"bitrate", [NSNumber numberWithFloat:frequency],@"sampleRate", + [NSNumber numberWithBool:floatingPoint],@"floatingPoint", [NSNumber numberWithDouble:totalFrames],@"totalFrames", [NSNumber numberWithBool:[source seekable]], @"seekable", @"little",@"endian",