Updated WavPack to version 5.0.0 alpha 4, decode floating point sample data to actual floating point, and now support DSD decoded as PCM.

CQTexperiment
Christopher Snowhill 2016-08-28 13:03:54 -07:00
parent de77fef181
commit d298087dec
45 changed files with 11691 additions and 15012 deletions

View File

@ -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

View File

@ -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

View File

@ -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 <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#if defined(WIN32)
#include <io.h>
#else
#if defined(__OS2__)
#include <io.h>
#endif
#include <unistd.h>
#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

View File

@ -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 <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "wavpack_local.h"
#ifndef LIBWAVPACK_VERSION_STRING
#include "wavpack_version.h"
#endif
///////////////////////////// local table storage ////////////////////////////
const uint32_t sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 };
///////////////////////////// executable code ////////////////////////////////
// This function obtains general information about an open input file and
// returns a mask with the following bit values:
// MODE_WVC: a .wvc file has been found and will be used for lossless
// MODE_LOSSLESS: file is lossless (either pure or hybrid)
// MODE_HYBRID: file is hybrid mode (either lossy or lossless)
// MODE_FLOAT: audio data is 32-bit ieee floating point
// MODE_VALID_TAG: file 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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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 <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
///////////////////////////// executable code ////////////////////////////////
// Read decorrelation terms from specified metadata block into the
// decorr_passes array. The terms range from -3 to 8, plus 17 & 18;
// other values are reserved and generate errors for now. The delta
// ranges from 0 to 7 with all values valid. Note that the terms are
// stored in the opposite order in the decorr_passes array compared
// to packing.
int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd)
{
int termcnt = wpmd->byte_length;
unsigned char *byteptr = 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;
}

View File

@ -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 <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
///////////////////////////// local table storage ////////////////////////////
const uint32_t bitset [] = {
1L << 0, 1L << 1, 1L << 2, 1L << 3,
1L << 4, 1L << 5, 1L << 6, 1L << 7,
1L << 8, 1L << 9, 1L << 10, 1L << 11,
1L << 12, 1L << 13, 1L << 14, 1L << 15,
1L << 16, 1L << 17, 1L << 18, 1L << 19,
1L << 20, 1L << 21, 1L << 22, 1L << 23,
1L << 24, 1L << 25, 1L << 26, 1L << 27,
1L << 28, 1L << 29, 1L << 30, 1L << 31
};
const uint32_t bitmask [] = {
(1L << 0) - 1, (1L << 1) - 1, (1L << 2) - 1, (1L << 3) - 1,
(1L << 4) - 1, (1L << 5) - 1, (1L << 6) - 1, (1L << 7) - 1,
(1L << 8) - 1, (1L << 9) - 1, (1L << 10) - 1, (1L << 11) - 1,
(1L << 12) - 1, (1L << 13) - 1, (1L << 14) - 1, (1L << 15) - 1,
(1L << 16) - 1, (1L << 17) - 1, (1L << 18) - 1, (1L << 19) - 1,
(1L << 20) - 1, (1L << 21) - 1, (1L << 22) - 1, (1L << 23) - 1,
(1L << 24) - 1, (1L << 25) - 1, (1L << 26) - 1, (1L << 27) - 1,
(1L << 28) - 1, (1L << 29) - 1, (1L << 30) - 1, 0x7fffffff
};
const char nbits_table [] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 15
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 16 - 31
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 32 - 47
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 48 - 63
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 64 - 79
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 80 - 95
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 96 - 111
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 112 - 127
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 128 - 143
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 144 - 159
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 160 - 175
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 176 - 191
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 192 - 207
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 208 - 223
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 224 - 239
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 // 240 - 255
};
static const unsigned char log2_table [] = {
0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15,
0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a,
0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e,
0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85,
0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2,
0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0,
0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce,
0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb,
0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7,
0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4,
0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff
};
static const unsigned char exp2_table [] = {
0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b,
0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16,
0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23,
0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d,
0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a,
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4,
0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9,
0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff
};
///////////////////////////// executable code ////////////////////////////////
// Read the median log2 values from the 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;
}

View File

@ -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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
//#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;

View File

@ -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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
//#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;

View File

@ -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 <stdlib.h>
#ifdef DEBUG_ALLOC
#define malloc malloc_db
#define realloc realloc_db
#define free free_db
void *malloc_db (uint32_t size);
void *realloc_db (void *ptr, uint32_t size);
void free_db (void *ptr);
int32_t dump_alloc (void);
#endif
#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++;
}
}

View File

@ -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 */

View File

@ -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 <stdlib.h>
#include <string.h>
#ifdef DEBUG_ALLOC
#define malloc malloc_db
#define realloc realloc_db
#define free free_db
void *malloc_db (uint32_t size);
void *realloc_db (void *ptr, uint32_t size);
void free_db (void *ptr);
int32_t dump_alloc (void);
#endif
#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;
}
}

View File

@ -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 <windows.h>
#include <io.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
#include <fcntl.h>
#include <sys/stat.h>
#if (defined(__GNUC__) || defined(__sun)) && !defined(_WIN32)
#include <unistd.h>
#endif
#ifdef __OS2__
#include <io.h>
#endif
#ifdef _WIN32
#define fileno _fileno
static FILE *fopen_utf8 (const char *filename_utf8, const char *mode_utf8);
#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 <mulder2@gmx.de>
// (see cli/win32_unicode_support.c for full license)
static wchar_t *utf8_to_utf16(const char *input)
{
wchar_t *Buffer;
int BuffSize = 0, Result = 0;
BuffSize = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
Buffer = (wchar_t*) malloc(sizeof(wchar_t) * BuffSize);
if(Buffer)
{
Result = MultiByteToWideChar(CP_UTF8, 0, input, -1, Buffer, BuffSize);
}
return ((Result > 0) && (Result <= BuffSize)) ? Buffer : NULL;
}
static FILE *fopen_utf8(const char *filename_utf8, const char *mode_utf8)
{
FILE *ret = NULL;
wchar_t *filename_utf16 = utf8_to_utf16(filename_utf8);
wchar_t *mode_utf16 = utf8_to_utf16(mode_utf8);
if(filename_utf16 && mode_utf16)
{
ret = _wfopen(filename_utf16, mode_utf16);
}
if(filename_utf16) free(filename_utf16);
if(mode_utf16) free(mode_utf16);
return ret;
}
#endif

View File

@ -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 <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
typedef struct {
WavpackStreamReader *reader;
void *id;
} WavpackReaderTranslator;
static int32_t trans_read_bytes (void *id, void *data, int32_t bcount)
{
WavpackReaderTranslator *trans = 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);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 <stdlib.h>
#include <string.h>
#include <math.h>
#include "wavpack_local.h"
static void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error);
void dynamic_noise_shaping (WavpackContext *wpc, int32_t *buffer, int shortening_allowed)
{
WavpackStream *wps = wpc->streams [wpc->current_stream];
int32_t sample_count = wps->wphdr.block_samples;
struct decorr_pass *ap = &wps->analysis_pass;
uint32_t flags = wps->wphdr.flags;
int32_t *bptr, temp, sam;
short *swptr;
int sc;
if (!wps->num_terms && sample_count > 8) {
if (flags & MONO_DATA)
for (bptr = buffer + sample_count - 3, sc = sample_count - 2; sc--;) {
sam = (3 * bptr [1] - bptr [2]) >> 1;
temp = *bptr-- - apply_weight (ap->weight_A, sam);
update_weight (ap->weight_A, 2, sam, temp);
}
else
for (bptr = buffer + (sample_count - 3) * 2 + 1, sc = sample_count - 2; sc--;) {
sam = (3 * bptr [2] - bptr [4]) >> 1;
temp = *bptr-- - apply_weight (ap->weight_B, sam);
update_weight (ap->weight_B, 2, sam, temp);
sam = (3 * bptr [2] - bptr [4]) >> 1;
temp = *bptr-- - apply_weight (ap->weight_A, sam);
update_weight (ap->weight_A, 2, sam, temp);
}
}
if (sample_count > wps->dc.shaping_samples) {
sc = sample_count - wps->dc.shaping_samples;
swptr = wps->dc.shaping_data + wps->dc.shaping_samples;
bptr = buffer + wps->dc.shaping_samples * ((flags & MONO_DATA) ? 1 : 2);
if (flags & MONO_DATA)
while (sc--) {
sam = (3 * ap->samples_A [0] - ap->samples_A [1]) >> 1;
temp = *bptr - apply_weight (ap->weight_A, sam);
update_weight (ap->weight_A, 2, sam, temp);
ap->samples_A [1] = ap->samples_A [0];
ap->samples_A [0] = *bptr++;
*swptr++ = (ap->weight_A < 256) ? 1024 : 1536 - ap->weight_A * 2;
}
else
while (sc--) {
sam = (3 * ap->samples_A [0] - ap->samples_A [1]) >> 1;
temp = *bptr - apply_weight (ap->weight_A, sam);
update_weight (ap->weight_A, 2, sam, temp);
ap->samples_A [1] = ap->samples_A [0];
ap->samples_A [0] = *bptr++;
sam = (3 * ap->samples_B [0] - ap->samples_B [1]) >> 1;
temp = *bptr - apply_weight (ap->weight_B, sam);
update_weight (ap->weight_B, 2, sam, temp);
ap->samples_B [1] = ap->samples_B [0];
ap->samples_B [0] = *bptr++;
*swptr++ = (ap->weight_A + ap->weight_B < 512) ? 1024 : 1536 - ap->weight_A - ap->weight_B;
}
wps->dc.shaping_samples = sample_count;
}
if (wpc->wvc_flag) {
int max_allowed_error = 1000000 / wpc->ave_block_samples;
short max_error, trial_max_error;
double initial_y, final_y;
if (max_allowed_error < 128)
max_allowed_error = 128;
best_floating_line (wps->dc.shaping_data, sample_count, &initial_y, &final_y, &max_error);
if (shortening_allowed && max_error > max_allowed_error) {
int min_samples = 0, max_samples = sample_count, trial_count;
double trial_initial_y, trial_final_y;
while (1) {
trial_count = (min_samples + max_samples) / 2;
best_floating_line (wps->dc.shaping_data, trial_count, &trial_initial_y,
&trial_final_y, &trial_max_error);
if (trial_max_error < max_allowed_error) {
max_error = trial_max_error;
min_samples = trial_count;
initial_y = trial_initial_y;
final_y = trial_final_y;
}
else
max_samples = trial_count;
if (min_samples > 10000 || max_samples - min_samples < 2)
break;
}
sample_count = min_samples;
}
if (initial_y < -512) initial_y = -512;
else if (initial_y > 1024) initial_y = 1024;
if (final_y < -512) final_y = -512;
else if (final_y > 1024) final_y = 1024;
#if 0
error_line ("%.2f sec, sample count = %5d, max error = %3d, range = %5d, %5d, actual = %5d, %5d",
(double) wps->sample_index / wpc->config.sample_rate, sample_count, max_error,
(int) floor (initial_y), (int) floor (final_y),
wps->dc.shaping_data [0], wps->dc.shaping_data [sample_count-1]);
#endif
if (sample_count != wps->wphdr.block_samples)
wps->wphdr.block_samples = sample_count;
if (wpc->wvc_flag) {
wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = (int32_t) floor (initial_y * 65536.0 + 0.5);
wps->dc.shaping_delta [0] = wps->dc.shaping_delta [1] =
(int32_t) floor ((final_y - initial_y) / (sample_count - 1) * 65536.0 + 0.5);
wps->dc.shaping_array = NULL;
}
else
wps->dc.shaping_array = wps->dc.shaping_data;
}
else
wps->dc.shaping_array = wps->dc.shaping_data;
}
// Given an array of integer data (in shorts), find the linear function that most closely
// represents it (based on minimum sum of absolute errors). This is returned as the double
// precision initial & final Y values of the best-fit line. The function can also optionally
// compute and return a maximum error value (as a short). Note that the ends of the resulting
// line may fall way outside the range of input values, so some sort of clipping may be
// needed.
static void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error)
{
double left_sum = 0.0, right_sum = 0.0, center_x = (num_values - 1) / 2.0, center_y, m;
int i;
for (i = 0; i < num_values >> 1; ++i) {
right_sum += values [num_values - i - 1];
left_sum += values [i];
}
if (num_values & 1) {
right_sum += values [num_values >> 1] * 0.5;
left_sum += values [num_values >> 1] * 0.5;
}
center_y = (right_sum + left_sum) / num_values;
m = (right_sum - left_sum) / ((double) num_values * num_values) * 4.0;
if (initial_y)
*initial_y = center_y - m * center_x;
if (final_y)
*final_y = center_y + m * center_x;
if (max_error) {
double max = 0.0;
for (i = 0; i < num_values; ++i)
if (fabs (values [i] - (center_y + (i - center_x) * m)) > max)
max = fabs (values [i] - (center_y + (i - center_x) * m));
*max_error = (short) floor (max + 0.5);
}
}

View File

@ -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 <stdlib.h>
#include <string.h>
#include <math.h>
#include "wavpack_local.h"
///////////////////////////// executable code ////////////////////////////////
// This function initializes everything required to pack WavPack DSD bitstreams
// and must be called BEFORE any other function in this module.
void pack_dsd_init (WavpackContext *wpc)
{
WavpackStream *wps = wpc->streams [wpc->current_stream];
wps->sample_index = 0;
}
// Pack an entire block of samples (either mono or stereo) into a completed
// WavPack block. This function is actually a shell for pack_samples() and
// performs tasks like handling any shift required by the format, preprocessing
// of floating point data or integer data over 24 bits wide, and implementing
// the "extra" mode (via the extra?.c modules). It is assumed that there is
// sufficient space for the completed block at "wps->blockbuff" and that
// "wps->blockend" points to the end of the available space. A return value of
// FALSE indicates an error.
// Pack an entire block of samples (either mono or stereo) into a completed
// WavPack block. It is assumed that there is sufficient space for the
// completed block at "wps->blockbuff" and that "wps->blockend" points to the
// end of the available space. A return value of FALSE indicates an error.
// Any unsent metadata is transmitted first, then required metadata for this
// block is sent, and finally the compressed integer data is sent. If a "wpx"
// stream is required for floating point data or large integer data, then this
// must be handled outside this function. To find out how much data was written
// the caller must look at the ckSize field of the written WavpackHeader, NOT
// the one in the WavpackStream.
static int encode_buffer_high (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination);
static int encode_buffer_fast (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination);
int pack_dsd_block (WavpackContext *wpc, int32_t *buffer)
{
WavpackStream *wps = wpc->streams [wpc->current_stream];
uint32_t flags = wps->wphdr.flags, mult = wpc->dsd_multiplier, data_count;
uint32_t sample_count = wps->wphdr.block_samples;
unsigned char *dsd_encoding, dsd_power = 0;
int32_t res;
// This code scans stereo data to check whether it can be stored as mono data
// (i.e., all L/R samples identical).
if (!(flags & MONO_FLAG)) {
int32_t *sptr, *dptr, i;
for (sptr = buffer, i = 0; i < (int32_t) sample_count; sptr += 2, i++)
if ((sptr [0] ^ sptr [1]) & 0xff)
break;
if (i == sample_count) {
wps->wphdr.flags = flags |= FALSE_STEREO;
dptr = buffer;
sptr = buffer;
for (i = sample_count; i--; sptr++)
*dptr++ = *sptr++;
}
else
wps->wphdr.flags = flags &= ~FALSE_STEREO;
}
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader));
if (wpc->metacount) {
WavpackMetadata *wpmdp = wpc->metadata;
while (wpc->metacount) {
copy_metadata (wpmdp, wps->blockbuff, wps->blockend);
wpc->metabytes -= wpmdp->byte_length;
free_metadata (wpmdp++);
wpc->metacount--;
}
free (wpc->metadata);
wpc->metadata = NULL;
}
if (!sample_count)
return TRUE;
send_general_metadata (wpc);
memcpy (&wps->wphdr, wps->blockbuff, sizeof (WavpackHeader));
dsd_encoding = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12;
while (mult >>= 1)
dsd_power++;
*dsd_encoding++ = dsd_power;
if (wpc->config.flags & CONFIG_HIGH_FLAG) {
int fast_res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding);
res = encode_buffer_high (wps, buffer, sample_count, dsd_encoding);
if ((fast_res != -1) && (res == -1 || res > fast_res))
res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding);
}
else
res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding);
if (res == -1) {
int num_samples = sample_count * ((flags & MONO_DATA) ? 1 : 2);
uint32_t crc = 0xffffffff;
*dsd_encoding++ = 0;
data_count = num_samples + 2;
while (num_samples--)
crc += (crc << 1) + (*dsd_encoding++ = *buffer++);
((WavpackHeader *) wps->blockbuff)->crc = crc;
}
else
data_count = res + 1;
if (data_count) {
unsigned char *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8;
if (data_count & 1) {
cptr [data_count + 4] = 0;
*cptr++ = ID_DSD_BLOCK | ID_LARGE | ID_ODD_SIZE;
data_count++;
}
else
*cptr++ = ID_DSD_BLOCK | ID_LARGE;
*cptr++ = data_count >> 1;
*cptr++ = data_count >> 9;
*cptr++ = data_count >> 17;
((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4;
}
wps->sample_index += sample_count;
return TRUE;
}
/*------------------------------------------------------------------------------------------------------------------------*/
// #define DSD_BYTE_READY(low,high) (((low) >> 24) == ((high) >> 24))
// #define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) >> 24))
#define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) & 0xff000000))
#define MAX_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<<PTABLE_BITS)
#define PTABLE_MASK (PTABLE_BINS-1)
#define INITIAL_TERM (1536/PTABLE_BINS)
#define UP 0x010000fe
#define DOWN 0x00010000
#define DECAY 8
#define PRECISION 24
#define VALUE_ONE (1 << PRECISION)
#define PRECISION_USE 12
#define RATE_S 20
static void init_ptable (int *table, int rate_i, int rate_s)
{
int value = 0x808000, rate = rate_i << 8, c, i;
for (c = (rate + 128) >> 8; c--;)
value += (DOWN - value) >> DECAY;
for (i = 0; i < PTABLE_BINS/2; ++i) {
table [i] = value;
table [PTABLE_BINS-1-i] = 0x100ffff - value;
if (value > 0x010000) {
rate += (rate * rate_s + 128) >> 8;
for (c = (rate + 64) >> 7; c--;)
value += (DOWN - value) >> DECAY;
}
}
}
static int normalize_ptable (int *ptable)
{
int rate = 0, min_error, error_sum, i;
int ntable [PTABLE_BINS];
init_ptable (ntable, rate, RATE_S);
for (min_error = i = 0; i < PTABLE_BINS; ++i)
min_error += abs (ptable [i] - ntable [i]) >> 8;
while (1) {
init_ptable (ntable, ++rate, RATE_S);
for (error_sum = i = 0; i < PTABLE_BINS; ++i)
error_sum += abs (ptable [i] - ntable [i]) >> 8;
if (error_sum < min_error)
min_error = error_sum;
else
break;
}
return rate - 1;
}
static int encode_buffer_high (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination)
{
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;
}

View File

@ -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 <stdlib.h>
#include "wavpack_local.h"
//#define DISPLAY_DIAGNOSTICS
// Scan the provided buffer of floating-point values and (1) convert the
// significant portion of the data to integers for compression using the
// regular WavPack algorithms (which only operate on integers) and (2)
// determine whether the data requires a second stream for lossless
// storage (which will usually be the case except when the floating-point
// data was originally integer data). The converted integers are returned
// "in-place" and a return value of TRUE indicates that a second stream
// is required.
int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values)
{
int32_t shifted_ones = 0, shifted_zeros = 0, shifted_both = 0;
int32_t false_zeros = 0, neg_zeros = 0;
#ifdef DISPLAY_DIAGNOSTICS
int32_t true_zeros = 0, denormals = 0, exceptions = 0;
#endif
uint32_t ordata = 0, crc = 0xffffffff;
int32_t count, value, shift_count;
int max_mag = 0, max_exp = 0;
f32 *dp;
wps->float_shift = wps->float_flags = 0;
// First loop goes through all the data and (1) calculates the CRC and (2) finds the
// max magnitude that does not have an exponent of 255 (reserved for +/-inf and NaN).
for (dp = values, count = num_values; count--; dp++) {
crc = crc * 27 + get_mantissa (*dp) * 9 + get_exponent (*dp) * 3 + get_sign (*dp);
if (get_exponent (*dp) < 255 && get_magnitude (*dp) > max_mag)
max_mag = get_magnitude (*dp);
}
wps->crc_x = crc;
// round up the magnitude so that when we convert the floating-point values to integers,
// they will be (at most) just over 24-bits signed precision
if (get_exponent (max_mag))
max_exp = get_exponent (max_mag + 0x7F0000);
for (dp = values, count = num_values; count--; dp++) {
// Exponent of 255 is reserved for +/-inf (mantissa = 0) or NaN (mantissa != 0).
// we use a value one greater than 24-bits unsigned for this.
if (get_exponent (*dp) == 255) {
#ifdef DISPLAY_DIAGNOSTICS
exceptions++;
#endif
wps->float_flags |= FLOAT_EXCEPTIONS;
value = 0x1000000;
shift_count = 0;
}
// This is the regular case. We generate a 24-bit unsigned value with the implied
// '1' MSB set and calculate a shift that will make it line up with the biggest
// samples in this block (although that shift would obviously shift out real data).
else if (get_exponent (*dp)) {
shift_count = max_exp - get_exponent (*dp);
value = 0x800000 + get_mantissa (*dp);
}
// Zero exponent means either +/- zero (mantissa = 0) or denormals (mantissa != 0).
// shift_count is set so that denormals (without an implied '1') will line up with
// regular values (with their implied '1' added at bit 23). Trust me. We don't care
// about the shift with zero.
else {
shift_count = max_exp ? max_exp - 1 : 0;
value = get_mantissa (*dp);
#ifdef DISPLAY_DIAGNOSTICS
if (get_mantissa (*dp))
denormals++;
#endif
}
if (shift_count < 25)
value >>= shift_count; // perform the shift if there could be anything left
else
value = 0; // else just zero the value
// If we are going to encode an integer zero, then this might be a "false zero" which
// means that there are significant bits but they're completely shifted out, or a
// "negative zero" which is simply a floating point value that we have to encode
// (and converting it to a positive zero would be an error).
if (!value) {
if (get_exponent (*dp) || get_mantissa (*dp))
++false_zeros;
else if (get_sign (*dp))
++neg_zeros;
#ifdef DISPLAY_DIAGNOSTICS
else
++true_zeros;
#endif
}
// If we are going to shift something (but not everything) out of our integer before
// encoding, then we generate a mask corresponding to the bits that will be shifted
// out and increment the counter for the 3 possible cases of (1) all zeros, (2) all
// ones, and (3) a mix of ones and zeros.
else if (shift_count) {
int32_t mask = (1 << shift_count) - 1;
if (!(get_mantissa (*dp) & mask))
shifted_zeros++;
else if ((get_mantissa (*dp) & mask) == mask)
shifted_ones++;
else
shifted_both++;
}
// "or" all the integer values together, and store the final integer with applied sign
ordata |= value;
* (int32_t *) dp = (get_sign (*dp)) ? -value : value;
}
wps->float_max_exp = max_exp; // on decode, we use this to calculate actual exponent
// Now, based on our various counts, we determine the scheme required to encode the bits
// shifted out. Usually these will simply have to be sent literally, but in some rare cases
// we can get away with always assuming ones shifted out, or assuming all the bits shifted
// out in each value are the same (which means we only have to send a single bit).
if (shifted_both)
wps->float_flags |= FLOAT_SHIFT_SENT;
else if (shifted_ones && !shifted_zeros)
wps->float_flags |= FLOAT_SHIFT_ONES;
else if (shifted_ones && shifted_zeros)
wps->float_flags |= FLOAT_SHIFT_SAME;
// Another case is that we only shift out zeros (or maybe nothing), and in that case we
// check to see if our data actually has less than 24 or 25 bits of resolution, which means
// that we reduce can the magnitude of the integers we are encoding (which saves all those
// bits). The number of bits of reduced resolution is stored in float_shift.
else if (ordata && !(ordata & 1)) {
while (!(ordata & 1)) {
wps->float_shift++;
ordata >>= 1;
}
// here we shift out all those zeros in the integer data we will encode
for (dp = values, count = num_values; count--; dp++)
* (int32_t *) dp >>= wps->float_shift;
}
// Here we calculate the actual magnitude used by our integer data, although this is just
// used for informational purposes during encode/decode to possibly use faster math.
wps->wphdr.flags &= ~MAG_MASK;
while (ordata) {
wps->wphdr.flags += 1 << MAG_LSB;
ordata >>= 1;
}
// Finally, we have to set some flags that guide how we encode various types of "zeros".
// If none of these are set (which is the most common situation), then every integer
// zero in the decoded data will simply become a floating-point zero.
if (false_zeros || neg_zeros)
wps->float_flags |= FLOAT_ZEROS_SENT;
if (neg_zeros)
wps->float_flags |= FLOAT_NEG_ZEROS;
#ifdef DISPLAY_DIAGNOSTICS
{
int32_t *ip, min = 0x7fffffff, max = 0x80000000;
for (ip = (int32_t *) values, count = num_values; count--; ip++) {
if (*ip < min) min = *ip;
if (*ip > max) max = *ip;
}
fprintf (stderr, "integer range = %d to %d\n", min, max);
}
fprintf (stderr, "samples = %d, max exp = %d, pre-shift = %d, denormals = %d, exceptions = %d, max_mag = %x\n",
num_values, max_exp, wps->float_shift, denormals, exceptions, max_mag);
fprintf (stderr, "shifted ones/zeros/both = %d/%d/%d, true/neg/false zeros = %d/%d/%d\n",
shifted_ones, shifted_zeros, shifted_both, true_zeros, neg_zeros, false_zeros);
#endif
return wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME);
}
// Given a buffer of float data, convert the data to integers (which is what the WavPack compression
// algorithms require) and write the other data required for lossless compression (which includes
// significant bits shifted out of the integers, plus information about +/- zeros and exceptions
// like NaN and +/- infinities) into the wvxbits stream (which is assumed to be opened). Note that
// for this work correctly, scan_float_data() must have been called on the original data to set
// the 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);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
#if defined (HAVE___BUILTIN_CTZ) || defined (_WIN64)
#define USE_CTZ_OPTIMIZATION // use ctz intrinsic (or Windows equivalent) to count trailing ones
#else
#define USE_NEXT8_OPTIMIZATION // optimization using a table to count trailing ones
#endif
#define USE_BITMASK_TABLES // use tables instead of shifting for certain masking operations
///////////////////////////// local table storage ////////////////////////////
#ifdef USE_NEXT8_OPTIMIZATION
static const char ones_count_table [] = {
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8
};
#endif
///////////////////////////// executable code ////////////////////////////////
static uint32_t __inline read_code (Bitstream *bs, uint32_t maxcode);
// Read the next word from the bitstream "wvbits" and return the value. This
// function can be used for hybrid or lossless streams, but since an
// optimized version is available for lossless this function would normally
// be used for hybrid only. If a hybrid lossless stream is being read then
// the "correction" offset is written at the specified pointer. A return value
// of WORD_EOF indicates that the end of the bitstream was reached (all 1s) or
// some other error occurred.
int32_t FASTCALL get_word (WavpackStream *wps, int chan, int32_t *correction)
{
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;
}

View File

@ -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 <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
#ifdef _WIN32
#define stricmp(x,y) _stricmp(x,y)
#else
#define stricmp strcasecmp
#endif
static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size, int type);
static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size);
static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size, int type);
static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size);
static int append_ape_tag_item (WavpackContext *wpc, const char *item, const char *value, int vsize, int type);
static int write_tag_blockout (WavpackContext *wpc);
static int write_tag_reader (WavpackContext *wpc);
static void tagcpy (char *dest, char *src, int tag_size);
static int tagdata (char *src, int tag_size);
//////////////////// Global functions part of external API /////////////////////////
// Count and return the total number of tag items in the specified file.
int WavpackGetNumTagItems (WavpackContext *wpc)
{
int i = 0;
while (WavpackGetTagItemIndexed (wpc, i, NULL, 0))
++i;
return i;
}
// Count and return the total number of binary tag items in the specified file. This applies
// only to APEv2 tags and was implemented as a separate function to avoid breaking the old API.
int WavpackGetNumBinaryTagItems (WavpackContext *wpc)
{
int i = 0;
while (WavpackGetBinaryTagItemIndexed (wpc, i, NULL, 0))
++i;
return i;
}
// Attempt to get the specified item from the specified file's ID3v1 or APEv2
// tag. The "size" parameter specifies the amount of space available at "value",
// if the desired item will not fit in this space then ellipses (...) will
// be appended and the string terminated. Only text data are supported. The
// actual length of the string is returned (or 0 if no matching value found).
// Note that with APEv2 tags the length might not be the same as the number of
// characters because UTF-8 encoding is used. Also, APEv2 tags can have multiple
// (NULL separated) strings for a single value (this is why the length is
// returned). If this function is called with a NULL "value" pointer (or a
// zero "length") then only the actual length of the value data is returned
// (not counting the terminating NULL). This can be used to determine the
// actual memory to be allocated beforehand.
int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size)
{
M_Tag *m_tag = &wpc->m_tag;
if (value && size)
*value = 0;
if (m_tag->ape_tag_hdr.ID [0] == 'A')
return get_ape_tag_item (m_tag, item, value, size, APE_TAG_TYPE_TEXT);
else if (m_tag->id3_tag.tag_id [0] == 'T')
return get_id3_tag_item (m_tag, item, value, size);
else
return 0;
}
// Attempt to get the specified binary item from the specified file's APEv2
// tag. The "size" parameter specifies the amount of space available at "value".
// If the desired item will not fit in this space then nothing will be copied
// and 0 will be returned, otherwise the actual size will be returned. If this
// function is called with a NULL "value" pointer (or a zero "length") then only
// the actual length of the value data is returned and can be used to determine
// the actual memory to be allocated beforehand.
int WavpackGetBinaryTagItem (WavpackContext *wpc, const char *item, char *value, int size)
{
M_Tag *m_tag = &wpc->m_tag;
if (value && size)
*value = 0;
if (m_tag->ape_tag_hdr.ID [0] == 'A')
return get_ape_tag_item (m_tag, item, value, size, APE_TAG_TYPE_BINARY);
else
return 0;
}
// This function looks up the tag item name by index and is used when the
// application wants to access all the items in the file's ID3v1 or APEv2 tag.
// Note that this function accesses only the item's name; WavpackGetTagItem()
// still must be called to get the actual value. The "size" parameter specifies
// the amount of space available at "item", if the desired item will not fit in
// this space then ellipses (...) will be appended and the string terminated.
// The actual length of the string is returned (or 0 if no item exists for
// index). If this function is called with a NULL "value" pointer (or a
// zero "length") then only the actual length of the item name is returned
// (not counting the terminating NULL). This can be used to determine the
// actual memory to be allocated beforehand. For binary tag values use the
// otherwise identical WavpackGetBinaryTagItemIndexed ();
int WavpackGetTagItemIndexed (WavpackContext *wpc, int index, char *item, int size)
{
M_Tag *m_tag = &wpc->m_tag;
if (item && size)
*item = 0;
if (m_tag->ape_tag_hdr.ID [0] == 'A')
return get_ape_tag_item_indexed (m_tag, index, item, size, APE_TAG_TYPE_TEXT);
else if (m_tag->id3_tag.tag_id [0] == 'T')
return get_id3_tag_item_indexed (m_tag, index, item, size);
else
return 0;
}
int WavpackGetBinaryTagItemIndexed (WavpackContext *wpc, int index, char *item, int size)
{
M_Tag *m_tag = &wpc->m_tag;
if (item && size)
*item = 0;
if (m_tag->ape_tag_hdr.ID [0] == 'A')
return get_ape_tag_item_indexed (m_tag, index, item, size, APE_TAG_TYPE_BINARY);
else
return 0;
}
// These two functions are used to append APEv2 tags to WavPack files; one is
// for text values (UTF-8 encoded) and the other is for binary values. If no tag
// has been started, then an empty one will be allocated first. When finished,
// use WavpackWriteTag() to write the completed tag to the file. The purpose of
// the passed size parameter is obvious for binary values, but might not be for
// text values. Keep in mind that APEv2 text values can have multiple values
// that are NULL separated, so the size is required to know the extent of the
// value (although the final terminating NULL is not included in the passed
// size). If the specified item already exists, it will be replaced with the
// new value. ID3v1 tags are not supported.
int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize)
{
while (WavpackDeleteTagItem (wpc, item));
return append_ape_tag_item (wpc, item, value, vsize, APE_TAG_TYPE_TEXT);
}
int WavpackAppendBinaryTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize)
{
while (WavpackDeleteTagItem (wpc, item));
return append_ape_tag_item (wpc, item, value, vsize, APE_TAG_TYPE_BINARY);
}
// Delete the specified tag item from the APEv2 tag on the specified WavPack file
// (fields cannot be deleted from ID3v1 tags). A return value of TRUE indicates
// that the item was found and successfully deleted.
int WavpackDeleteTagItem (WavpackContext *wpc, const char *item)
{
M_Tag *m_tag = &wpc->m_tag;
if (m_tag->ape_tag_hdr.ID [0] == 'A') {
unsigned char *p = m_tag->ape_tag_data;
unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr);
int i;
for (i = 0; i < m_tag->ape_tag_hdr.item_count; ++i) {
int vsize, isize;
vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 8; // skip flags because we don't need them
for (isize = 0; p[isize] && p + isize < q; ++isize);
if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q)
break;
if (isize && vsize && !stricmp (item, (char *) p)) {
unsigned char *d = p - 8;
p += isize + vsize + 1;
while (p < q)
*d++ = *p++;
m_tag->ape_tag_hdr.length = (int32_t)(d - m_tag->ape_tag_data) + sizeof (APE_Tag_Hdr);
m_tag->ape_tag_hdr.item_count--;
return 1;
}
else
p += isize + vsize + 1;
}
}
return 0;
}
// Once a APEv2 tag has been created with WavpackAppendTag(), this function is
// used to write the completed tag to the end of the WavPack file. Note that
// this function uses the same "blockout" function that is used to write
// regular WavPack blocks, although that's where the similarity ends. It is also
// used to write tags that have been edited on existing files.
int WavpackWriteTag (WavpackContext *wpc)
{
if (wpc->blockout) // this is the case for creating fresh WavPack files
return write_tag_blockout (wpc);
else // otherwise we are editing existing tags (OPEN_EDIT_TAGS)
return write_tag_reader (wpc);
}
////////////////////////// local static functions /////////////////////////////
static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size, int type)
{
unsigned char *p = m_tag->ape_tag_data;
unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr);
int i;
for (i = 0; i < m_tag->ape_tag_hdr.item_count && q - p > 8; ++i) {
int vsize, flags, isize;
vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
flags = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
for (isize = 0; p[isize] && p + isize < q; ++isize);
if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q)
break;
if (isize && vsize && !stricmp (item, (char *) p) && ((flags & 6) >> 1) == type) {
if (!value || !size)
return vsize;
if (type == APE_TAG_TYPE_BINARY) {
if (vsize <= size) {
memcpy (value, p + isize + 1, vsize);
return vsize;
}
else
return 0;
}
else if (vsize < size) {
memcpy (value, p + isize + 1, vsize);
value [vsize] = 0;
return vsize;
}
else if (size >= 4) {
memcpy (value, p + isize + 1, size - 1);
value [size - 4] = value [size - 3] = value [size - 2] = '.';
value [size - 1] = 0;
return size - 1;
}
else
return 0;
}
else
p += isize + vsize + 1;
}
return 0;
}
static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size)
{
char lvalue [64];
int len;
lvalue [0] = 0;
if (!stricmp (item, "title"))
tagcpy (lvalue, m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title));
else if (!stricmp (item, "artist"))
tagcpy (lvalue, m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist));
else if (!stricmp (item, "album"))
tagcpy (lvalue, m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album));
else if (!stricmp (item, "year"))
tagcpy (lvalue, m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year));
else if (!stricmp (item, "comment"))
tagcpy (lvalue, m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.comment));
else if (!stricmp (item, "track") && m_tag->id3_tag.comment [29] && !m_tag->id3_tag.comment [28])
sprintf (lvalue, "%d", m_tag->id3_tag.comment [29]);
else
return 0;
len = (int) strlen (lvalue);
if (!value || !size)
return len;
if (len < size) {
strcpy (value, lvalue);
return len;
}
else if (size >= 4) {
strncpy (value, lvalue, size - 1);
value [size - 4] = value [size - 3] = value [size - 2] = '.';
value [size - 1] = 0;
return size - 1;
}
else
return 0;
}
static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size, int type)
{
unsigned char *p = m_tag->ape_tag_data;
unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr);
int i;
for (i = 0; i < m_tag->ape_tag_hdr.item_count && index >= 0 && q - p > 8; ++i) {
int vsize, flags, isize;
vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
flags = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
for (isize = 0; p[isize] && p + isize < q; ++isize);
if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q)
break;
if (isize && vsize && ((flags & 6) >> 1) == type && !index--) {
if (!item || !size)
return isize;
if (isize < size) {
memcpy (item, p, isize);
item [isize] = 0;
return isize;
}
else if (size >= 4) {
memcpy (item, p, size - 1);
item [size - 4] = item [size - 3] = item [size - 2] = '.';
item [size - 1] = 0;
return size - 1;
}
else
return 0;
}
else
p += isize + vsize + 1;
}
return 0;
}
static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size)
{
char lvalue [16];
int len;
lvalue [0] = 0;
if (tagdata (m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title)) && !index--)
strcpy (lvalue, "Title");
else if (tagdata (m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist)) && !index--)
strcpy (lvalue, "Artist");
else if (tagdata (m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album)) && !index--)
strcpy (lvalue, "Album");
else if (tagdata (m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year)) && !index--)
strcpy (lvalue, "Year");
else if (tagdata (m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.comment)) && !index--)
strcpy (lvalue, "Comment");
else if (m_tag->id3_tag.comment [29] && !m_tag->id3_tag.comment [28] && !index--)
strcpy (lvalue, "Track");
else
return 0;
len = (int) strlen (lvalue);
if (!item || !size)
return len;
if (len < size) {
strcpy (item, lvalue);
return len;
}
else if (size >= 4) {
strncpy (item, lvalue, size - 1);
item [size - 4] = item [size - 3] = item [size - 2] = '.';
item [size - 1] = 0;
return size - 1;
}
else
return 0;
}
static int append_ape_tag_item (WavpackContext *wpc, const char *item, const char *value, int vsize, int type)
{
M_Tag *m_tag = &wpc->m_tag;
int isize = (int) strlen (item);
if (!m_tag->ape_tag_hdr.ID [0]) {
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);
}

View File

@ -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 <stdlib.h>
#include <string.h>
#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

File diff suppressed because it is too large Load Diff

View File

@ -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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#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;
}

View File

@ -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);

View File

@ -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 <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
#include "unpack3.h"
#define ATTEMPT_ERROR_MUTING
// This provides an extension to the WavpackOpenFileRead () function contained
// in the wputils.c module. It is assumed that an 'R' had been read as the
// first character of the file/stream (indicating a non-raw pre version 4.0
// WavPack file) and had been pushed back onto the stream (or simply seeked
// back to).
WavpackContext *open_file3 (WavpackContext *wpc, char *error)
{
RiffChunkHeader RiffChunkHeader;
ChunkHeader ChunkHeader;
WavpackHeader3 wphdr;
WavpackStream3 *wps;
WaveHeader3 wavhdr;
CLEAR (wavhdr);
wpc->stream3 = wps = (WavpackStream3 *) malloc (sizeof (WavpackStream3));
CLEAR (*wps);
if (wpc->reader->read_bytes (wpc->wv_in, &RiffChunkHeader, sizeof (RiffChunkHeader)) !=
sizeof (RiffChunkHeader)) {
if (error) strcpy (error, "not a valid WavPack file!");
return WavpackCloseFile (wpc);
}
if (!strncmp (RiffChunkHeader.ckID, "RIFF", 4) && !strncmp (RiffChunkHeader.formType, "WAVE", 4)) {
if (wpc->open_flags & OPEN_WRAPPER) {
wpc->wrapper_data = 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);
}
}

View File

@ -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 <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
#include "unpack3.h"
static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources);
static void bs_restore3 (Bitstream3 *bs);
// This is an extension for WavpackSeekSample (). Note that because WavPack
// files created prior to version 4.0 are not inherently seekable, this
// function could take a long time if a forward seek is requested to an
// area that has not been played (or seeked through) yet.
int seek_sample3 (WavpackContext *wpc, uint32_t desired_index)
{
int points_index = desired_index / (((uint32_t) wpc->total_samples >> 8) + 1);
WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
if (desired_index >= wpc->total_samples)
return FALSE;
while (points_index)
if (wps->index_points [points_index].saved &&
wps->index_points [points_index].sample_index <= desired_index)
break;
else
points_index--;
if (wps->index_points [points_index].saved)
if (wps->index_points [points_index].sample_index > wps->sample_index ||
wps->sample_index > desired_index) {
wps->sample_index = wps->index_points [points_index].sample_index;
unpack_restore (wps, wps->unpack_data + points_index * wps->unpack_size, TRUE);
}
if (desired_index > wps->sample_index) {
int32_t *buffer = (int32_t *) malloc (1024 * (wps->wphdr.flags & MONO_FLAG ? 4 : 8));
uint32_t samples_to_skip = desired_index - wps->sample_index;
while (1) {
if (samples_to_skip > 1024) {
if (unpack_samples3 (wpc, buffer, 1024) == 1024)
samples_to_skip -= 1024;
else
break;
}
else {
samples_to_skip -= unpack_samples3 (wpc, buffer, samples_to_skip);
break;
}
}
free (buffer);
if (samples_to_skip)
return FALSE;
}
return TRUE;
}
// This function restores the unpacking context from the specified pointer
// and returns the updated pointer. After this call, unpack_samples() will
// continue where it left off immediately before unpack_save() was called.
// If the WavPack files and bitstreams might have been closed and reopened,
// then the "keep_resources" flag should be set to avoid using the "old"
// resources that were originally saved (and are probably now invalid).
static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources)
{
int flags = wps->wphdr.flags, tcount;
struct decorr_pass *dpp;
FILE *temp_file;
unsigned char *temp_buf;
unpack_init3 (wps);
temp_file = wps->wvbits.id;
temp_buf = wps->wvbits.buf;
RESTORE (wps->wvbits, source);
if (keep_resources) {
wps->wvbits.id = temp_file;
wps->wvbits.ptr += temp_buf - wps->wvbits.buf;
wps->wvbits.end += temp_buf - wps->wvbits.buf;
wps->wvbits.buf = temp_buf;
}
bs_restore3 (&wps->wvbits);
if (flags & WVC_FLAG) {
temp_file = wps->wvcbits.id;
temp_buf = wps->wvcbits.buf;
RESTORE (wps->wvcbits, source);
if (keep_resources) {
wps->wvcbits.id = temp_file;
wps->wvcbits.ptr += temp_buf - wps->wvcbits.buf;
wps->wvcbits.end += temp_buf - wps->wvcbits.buf;
wps->wvcbits.buf = temp_buf;
}
bs_restore3 (&wps->wvcbits);
}
if (wps->wphdr.version == 3) {
if (wps->wphdr.bits) {
RESTORE (wps->w4, source);
}
else {
RESTORE (wps->w1, source);
}
RESTORE (wps->w3, source);
RESTORE (wps->dc.crc, source);
}
else
RESTORE (wps->w2, source);
if (wps->wphdr.bits) {
RESTORE (wps->dc.error, source);
}
else {
RESTORE (wps->dc.sum_level, source);
RESTORE (wps->dc.left_level, source);
RESTORE (wps->dc.right_level, source);
RESTORE (wps->dc.diff_level, source);
}
if (flags & OVER_20) {
RESTORE (wps->dc.last_extra_bits, source);
RESTORE (wps->dc.extra_bits_count, source);
}
if (!(flags & EXTREME_DECORR)) {
RESTORE (wps->dc.sample, source);
RESTORE (wps->dc.weight, source);
}
if (flags & (HIGH_FLAG | NEW_HIGH_FLAG))
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
if (dpp->term > 0) {
int count = dpp->term;
int index = wps->dc.m;
RESTORE (dpp->weight_A, source);
while (count--) {
RESTORE (dpp->samples_A [index], source);
index = (index + 1) & (MAX_TERM - 1);
}
if (!(flags & MONO_FLAG)) {
count = dpp->term;
index = wps->dc.m;
RESTORE (dpp->weight_B, source);
while (count--) {
RESTORE (dpp->samples_B [index], source);
index = (index + 1) & (MAX_TERM - 1);
}
}
}
else {
RESTORE (dpp->weight_A, source);
RESTORE (dpp->weight_B, source);
RESTORE (dpp->samples_A [0], source);
RESTORE (dpp->samples_B [0], source);
}
}
return source;
}
// This function is called after a call to unpack_restore() has restored
// the BitStream structure to a previous state and causes any required data
// to be read from the file. This function is NOT supported for overlapped
// operation.
static void bs_restore3 (Bitstream3 *bs)
{
uint32_t bytes_to_read = (uint32_t)(bs->end - bs->ptr - 1), bytes_read;
bs->reader->set_pos_abs (bs->id, bs->fpos - bytes_to_read);
if (bytes_to_read > 0) {
bytes_read = bs->reader->read_bytes (bs->id, bs->ptr + 1, bytes_to_read);
if (bytes_to_read != bytes_read)
bs->end = bs->ptr + 1 + bytes_read;
}
}
#endif

View File

@ -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 <stdlib.h>
#include <string.h>
#include <math.h>
#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<<PTABLE_BITS)
#define PTABLE_MASK (PTABLE_BINS-1)
#define UP 0x010000fe
#define DOWN 0x00010000
#define DECAY 8
#define PRECISION 24
#define VALUE_ONE (1 << PRECISION)
#define PRECISION_USE 12
#define RATE_S 20
static void init_ptable (int *table, int rate_i, int rate_s)
{
int value = 0x808000, rate = rate_i << 8, c, i;
for (c = (rate + 128) >> 8; c--;)
value += (DOWN - value) >> DECAY;
for (i = 0; i < PTABLE_BINS/2; ++i) {
table [i] = value;
table [PTABLE_BINS-1-i] = 0x100ffff - value;
if (value > 0x010000) {
rate += (rate * rate_s + 128) >> 8;
for (c = (rate + 64) >> 7; c--;)
value += (DOWN - value) >> DECAY;
}
}
}
static int init_dsd_block_high (WavpackStream *wps, WavpackMetadata *wpmd)
{
uint32_t flags = wps->wphdr.flags;
int channel, rate_i, rate_s, i;
if (wps->dsd.endptr - wps->dsd.byteptr < ((flags & MONO_DATA) ? 13 : 20))
return FALSE;
rate_i = *wps->dsd.byteptr++;
rate_s = *wps->dsd.byteptr++;
if (rate_s != RATE_S)
return FALSE;
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);
}

View File

@ -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 <stdlib.h>
#include "wavpack_local.h"
static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values);
void float_values (WavpackStream *wps, int32_t *values, int32_t num_values)
{
uint32_t crc = wps->crc_x;
if (!bs_is_open (&wps->wvxbits)) {
float_values_nowvx (wps, values, num_values);
return;
}
while (num_values--) {
int shift_count = 0, exp = wps->float_max_exp;
f32 outval = 0;
uint32_t temp;
if (*values == 0) {
if (wps->float_flags & FLOAT_ZEROS_SENT) {
if (getbit (&wps->wvxbits)) {
getbits (&temp, 23, &wps->wvxbits);
set_mantissa (outval, temp);
if (exp >= 25) {
getbits (&temp, 8, &wps->wvxbits);
set_exponent (outval, temp);
}
set_sign (outval, getbit (&wps->wvxbits));
}
else if (wps->float_flags & FLOAT_NEG_ZEROS)
set_sign (outval, getbit (&wps->wvxbits));
}
}
else {
*values <<= wps->float_shift;
if (*values < 0) {
*values = -*values;
set_sign (outval, 1);
}
if (*values == 0x1000000) {
if (getbit (&wps->wvxbits)) {
getbits (&temp, 23, &wps->wvxbits);
set_mantissa (outval, temp);
}
set_exponent (outval, 255);
}
else {
if (exp)
while (!(*values & 0x800000) && --exp) {
shift_count++;
*values <<= 1;
}
if (shift_count) {
if ((wps->float_flags & FLOAT_SHIFT_ONES) ||
((wps->float_flags & FLOAT_SHIFT_SAME) && getbit (&wps->wvxbits)))
*values |= ((1 << shift_count) - 1);
else if (wps->float_flags & FLOAT_SHIFT_SENT) {
getbits (&temp, shift_count, &wps->wvxbits);
*values |= temp & ((1 << shift_count) - 1);
}
}
set_mantissa (outval, *values);
set_exponent (outval, exp);
}
}
crc = crc * 27 + get_mantissa (outval) * 9 + get_exponent (outval) * 3 + get_sign (outval);
* (f32 *) values++ = outval;
}
wps->crc_x = crc;
}
static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values)
{
while (num_values--) {
int shift_count = 0, exp = wps->float_max_exp;
f32 outval = 0;
if (*values) {
*values <<= wps->float_shift;
if (*values < 0) {
*values = -*values;
set_sign (outval, 1);
}
if (*values >= 0x1000000) {
while (*values & 0xf000000) {
*values >>= 1;
++exp;
}
}
else if (exp) {
while (!(*values & 0x800000) && --exp) {
shift_count++;
*values <<= 1;
}
if (shift_count && (wps->float_flags & FLOAT_SHIFT_ONES))
*values |= ((1 << shift_count) - 1);
}
set_mantissa (outval, *values);
set_exponent (outval, exp);
}
* (f32 *) values++ = outval;
}
}

View File

@ -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 <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
///////////////////////////// executable code ////////////////////////////////
static int64_t find_sample (WavpackContext *wpc, void *infile, int64_t header_pos, int64_t sample);
// Seek to the 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

View File

@ -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 <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
///////////////////////////// executable code ////////////////////////////////
// Unpack the specified number of samples from the current file position.
// Note that "samples" here refers to "complete" samples, which would be
// 2 longs for stereo files or even more for multichannel files, so the
// required memory at "buffer" is 4 * samples * num_channels bytes. The
// audio data is returned right-justified in 32-bit longs in the endian
// mode native to the executing processor. So, if the original data was
// 16-bit, then the values returned would be +/-32k. Floating point data
// can also be returned if the source was floating point data (and this
// can be optionally normalized to +/-1.0 by using the appropriate flag
// in the call to WavpackOpenFileInput ()). The actual number of samples
// unpacked is returned, which should be equal to the number requested unless
// the end of fle is encountered or an error occurs. After all samples have
// been unpacked then 0 will be returned.
uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples)
{
WavpackStream *wps = wpc->streams ? wpc->streams [wpc->current_stream = 0] : NULL;
int num_channels = wpc->config.num_channels, file_done = FALSE;
uint32_t bcount, samples_unpacked = 0, samples_to_unpack;
int32_t *bptr = buffer;
#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;
}

View File

@ -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 <windows.h>
#include <io.h>
@ -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

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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 <sys/types.h>
#if defined(_WIN32) && !defined(__MINGW32__)
#include <stdlib.h>
#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 <inttypes.h>
#include <stdint.h>
#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);

View File

@ -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 <stdlib.h>
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 <inttypes.h>
#include <stdint.h>
#endif
// Because the C99 specification states that "The order of allocation of
// bit-elds within a unit (high-order to low-order or low-order to
// high-order) is implementation-dened" (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 <mmintrin.h>
#endif
#endif //OPT_MMX
#endif

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
///////////////////////////// executable code ////////////////////////////////
// Initialize entropy encoder for the specified stream. In lossless mode there
// are no parameters to select; in hybrid mode the bitrate mode and value need
// be initialized.
static void word_set_bitrate (WavpackStream *wps);
void init_words (WavpackStream *wps)
{
CLEAR (wps->w);
if (wps->wphdr.flags & HYBRID_FLAG)
word_set_bitrate (wps);
}
// Set up parameters for hybrid mode based on header flags and "bits" field.
// This is currently only set up for the HYBRID_BITRATE mode in which the
// allowed error varies with the residual level (from "slow_level"). The
// simpler mode (which is not used yet) has the error level directly
// controlled from the metadata.
static void word_set_bitrate (WavpackStream *wps)
{
int bitrate_0, bitrate_1;
if (wps->wphdr.flags & HYBRID_BITRATE) {
if (wps->wphdr.flags & FALSE_STEREO)
bitrate_0 = (wps->bits * 2 - 512) < 568 ? 0 : (wps->bits * 2 - 512) - 568;
else
bitrate_0 = wps->bits < 568 ? 0 : wps->bits - 568;
if (!(wps->wphdr.flags & MONO_DATA)) {
if (wps->wphdr.flags & HYBRID_BALANCE)
bitrate_1 = (wps->wphdr.flags & JOINT_STEREO) ? 256 : 0;
else {
bitrate_1 = bitrate_0;
if (wps->wphdr.flags & JOINT_STEREO) {
if (bitrate_0 < 128) {
bitrate_1 += bitrate_0;
bitrate_0 = 0;
}
else {
bitrate_0 -= 128;
bitrate_1 += 128;
}
}
}
}
else
bitrate_1 = 0;
}
else
bitrate_0 = bitrate_1 = 0;
wps->w.bitrate_acc [0] = (int32_t) bitrate_0 << 16;
wps->w.bitrate_acc [1] = (int32_t) bitrate_1 << 16;
}
// Allocates the correct space in the metadata structure and writes the
// current median values to it. Values are converted from 32-bit unsigned
// to our internal 16-bit wp_log2 values, and read_entropy_vars () is called
// to read the values back because we must compensate for the loss through
// the log function.
void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd)
{
unsigned char *byteptr;
int temp;
byteptr = wpmd->data = malloc (12);
wpmd->id = ID_ENTROPY_VARS;
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [0]);
*byteptr++ = temp >> 8;
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [1]);
*byteptr++ = temp >> 8;
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [2]);
*byteptr++ = temp >> 8;
if (!(wps->wphdr.flags & MONO_DATA)) {
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [0]);
*byteptr++ = temp >> 8;
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [1]);
*byteptr++ = temp >> 8;
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [2]);
*byteptr++ = temp >> 8;
}
wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data);
read_entropy_vars (wps, wpmd);
}
// Allocates enough space in the metadata structure and writes the current
// high word of the bitrate accumulator and the slow_level values to it. The
// slow_level values are converted from 32-bit unsigned to our internal 16-bit
// wp_log2 values. Afterward, read_entropy_vars () is called to read the values
// back because we must compensate for the loss through the log function and
// the truncation of the bitrate.
void write_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd)
{
unsigned char *byteptr;
int temp;
word_set_bitrate (wps);
byteptr = wpmd->data = malloc (512);
wpmd->id = ID_HYBRID_PROFILE;
if (wps->wphdr.flags & HYBRID_BITRATE) {
*byteptr++ = temp = wp_log2s (wps->w.c [0].slow_level);
*byteptr++ = temp >> 8;
if (!(wps->wphdr.flags & MONO_DATA)) {
*byteptr++ = temp = wp_log2s (wps->w.c [1].slow_level);
*byteptr++ = temp >> 8;
}
}
*byteptr++ = temp = wps->w.bitrate_acc [0] >> 16;
*byteptr++ = temp >> 8;
if (!(wps->wphdr.flags & MONO_DATA)) {
*byteptr++ = temp = wps->w.bitrate_acc [1] >> 16;
*byteptr++ = temp >> 8;
}
if (wps->w.bitrate_delta [0] | wps->w.bitrate_delta [1]) {
*byteptr++ = temp = wp_log2s (wps->w.bitrate_delta [0]);
*byteptr++ = temp >> 8;
if (!(wps->wphdr.flags & MONO_DATA)) {
*byteptr++ = temp = wp_log2s (wps->w.bitrate_delta [1]);
*byteptr++ = temp >> 8;
}
}
wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data);
read_hybrid_profile (wps, wpmd);
}
// This function writes the specified word to the open bitstream "wvbits" and,
// if the bitstream "wvcbits" is open, writes any correction data there. This
// function will work for either lossless or hybrid but because a version
// optimized for lossless exits below, it would normally be used for the hybrid
// mode only. The return value is the actual value stored to the stream (even
// if a correction file is being created) and is used as feedback to the
// predictor.
int32_t FASTCALL send_word (WavpackStream *wps, int32_t value, int chan)
{
struct entropy_data *c = wps->w.c + chan;
uint32_t ones_count, low, mid, high;
int sign = (value < 0) ? 1 : 0;
if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) {
if (wps->w.zeros_acc) {
if (value)
flush_word (wps);
else {
c->slow_level -= (c->slow_level + SLO) >> SLS;
wps->w.zeros_acc++;
return 0;
}
}
else if (value)
putbit_0 (&wps->wvbits);
else {
c->slow_level -= (c->slow_level + SLO) >> SLS;
CLEAR (wps->w.c [0].median);
CLEAR (wps->w.c [1].median);
wps->w.zeros_acc = 1;
return 0;
}
}
if (sign)
value = ~value;
if ((wps->wphdr.flags & HYBRID_FLAG) && !chan)
update_error_limit (wps);
if (value < (int32_t) GET_MED (0)) {
ones_count = low = 0;
high = GET_MED (0) - 1;
DEC_MED0 ();
}
else {
low = GET_MED (0);
INC_MED0 ();
if (value - low < GET_MED (1)) {
ones_count = 1;
high = low + GET_MED (1) - 1;
DEC_MED1 ();
}
else {
low += GET_MED (1);
INC_MED1 ();
if (value - low < GET_MED (2)) {
ones_count = 2;
high = low + GET_MED (2) - 1;
DEC_MED2 ();
}
else {
ones_count = 2 + (value - low) / GET_MED (2);
low += (ones_count - 2) * GET_MED (2);
high = low + GET_MED (2) - 1;
INC_MED2 ();
}
}
}
mid = (high + low + 1) >> 1;
if (wps->w.holding_zero) {
if (ones_count)
wps->w.holding_one++;
flush_word (wps);
if (ones_count) {
wps->w.holding_zero = 1;
ones_count--;
}
else
wps->w.holding_zero = 0;
}
else
wps->w.holding_zero = 1;
wps->w.holding_one = ones_count * 2;
if (!c->error_limit) {
if (high != low) {
uint32_t maxcode = high - low, code = value - low;
int bitcount = count_bits (maxcode);
uint32_t extras = bitset [bitcount] - maxcode - 1;
if (code < extras) {
wps->w.pend_data |= code << wps->w.pend_count;
wps->w.pend_count += bitcount - 1;
}
else {
wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count;
wps->w.pend_count += bitcount - 1;
wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++;
}
}
mid = value;
}
else
while (high - low > c->error_limit)
if (value < (int32_t) mid) {
mid = ((high = mid - 1) + low + 1) >> 1;
wps->w.pend_count++;
}
else {
mid = (high + (low = mid) + 1) >> 1;
wps->w.pend_data |= bitset [wps->w.pend_count++];
}
wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++);
if (!wps->w.holding_zero)
flush_word (wps);
if (bs_is_open (&wps->wvcbits) && c->error_limit) {
uint32_t code = value - low, maxcode = high - low;
int bitcount = count_bits (maxcode);
uint32_t extras = bitset [bitcount] - maxcode - 1;
if (bitcount) {
if (code < extras)
putbits (code, bitcount - 1, &wps->wvcbits);
else {
putbits ((code + extras) >> 1, bitcount - 1, &wps->wvcbits);
putbit ((code + extras) & 1, &wps->wvcbits);
}
}
}
if (wps->wphdr.flags & HYBRID_BITRATE) {
c->slow_level -= (c->slow_level + SLO) >> SLS;
c->slow_level += wp_log2 (mid);
}
return sign ? ~mid : mid;
}
// This function is an optimized version of send_word() that only handles
// lossless (error_limit == 0) and sends an entire buffer of either mono or
// stereo data rather than a single sample. Unlike the generalized
// send_word(), it does not return values because it always encodes
// the exact value passed.
void send_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples)
{
struct entropy_data *c = wps->w.c;
int32_t value, csamples;
if (!(wps->wphdr.flags & MONO_DATA))
nsamples *= 2;
for (csamples = 0; csamples < nsamples; ++csamples) {
int sign = ((value = *buffer++) < 0) ? 1 : 0;
uint32_t ones_count, low, high;
if (!(wps->wphdr.flags & MONO_DATA))
c = wps->w.c + (csamples & 1);
if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) {
if (wps->w.zeros_acc) {
if (value)
flush_word (wps);
else {
wps->w.zeros_acc++;
continue;
}
}
else if (value)
putbit_0 (&wps->wvbits);
else {
CLEAR (wps->w.c [0].median);
CLEAR (wps->w.c [1].median);
wps->w.zeros_acc = 1;
continue;
}
}
if (sign)
value = ~value;
if (value < (int32_t) GET_MED (0)) {
ones_count = low = 0;
high = GET_MED (0) - 1;
DEC_MED0 ();
}
else {
low = GET_MED (0);
INC_MED0 ();
if (value - low < GET_MED (1)) {
ones_count = 1;
high = low + GET_MED (1) - 1;
DEC_MED1 ();
}
else {
low += GET_MED (1);
INC_MED1 ();
if (value - low < GET_MED (2)) {
ones_count = 2;
high = low + GET_MED (2) - 1;
DEC_MED2 ();
}
else {
ones_count = 2 + (value - low) / GET_MED (2);
low += (ones_count - 2) * GET_MED (2);
high = low + GET_MED (2) - 1;
INC_MED2 ();
}
}
}
if (wps->w.holding_zero) {
if (ones_count)
wps->w.holding_one++;
flush_word (wps);
if (ones_count) {
wps->w.holding_zero = 1;
ones_count--;
}
else
wps->w.holding_zero = 0;
}
else
wps->w.holding_zero = 1;
wps->w.holding_one = ones_count * 2;
if (high != low) {
uint32_t maxcode = high - low, code = value - low;
int bitcount = count_bits (maxcode);
uint32_t extras = bitset [bitcount] - maxcode - 1;
if (code < extras) {
wps->w.pend_data |= code << wps->w.pend_count;
wps->w.pend_count += bitcount - 1;
}
else {
wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count;
wps->w.pend_count += bitcount - 1;
wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++;
}
}
wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++);
if (!wps->w.holding_zero)
flush_word (wps);
}
}
// Used by send_word() and send_word_lossless() to actually send most the
// accumulated data onto the bitstream. This is also called directly from
// clients when all words have been sent.
void flush_word (WavpackStream *wps)
{
if (wps->w.zeros_acc) {
int cbits = count_bits (wps->w.zeros_acc);
while (cbits--)
putbit_1 (&wps->wvbits);
putbit_0 (&wps->wvbits);
while (wps->w.zeros_acc > 1) {
putbit (wps->w.zeros_acc & 1, &wps->wvbits);
wps->w.zeros_acc >>= 1;
}
wps->w.zeros_acc = 0;
}
if (wps->w.holding_one) {
#ifdef LIMIT_ONES
if (wps->w.holding_one >= LIMIT_ONES) {
int cbits;
putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, &wps->wvbits);
wps->w.holding_one -= LIMIT_ONES;
cbits = count_bits (wps->w.holding_one);
while (cbits--)
putbit_1 (&wps->wvbits);
putbit_0 (&wps->wvbits);
while (wps->w.holding_one > 1) {
putbit (wps->w.holding_one & 1, &wps->wvbits);
wps->w.holding_one >>= 1;
}
wps->w.holding_zero = 0;
}
else
putbits (bitmask [wps->w.holding_one], wps->w.holding_one, &wps->wvbits);
wps->w.holding_one = 0;
#else
do {
putbit_1 (&wps->wvbits);
} while (--wps->w.holding_one);
#endif
}
if (wps->w.holding_zero) {
putbit_0 (&wps->wvbits);
wps->w.holding_zero = 0;
}
if (wps->w.pend_count) {
putbits (wps->w.pend_data, wps->w.pend_count, &wps->wvbits);
wps->w.pend_data = wps->w.pend_count = 0;
}
}
// This function is similar to send_word() except that no data is actually
// written to any stream, but it does return the value that would have been
// sent to a hybrid stream. It is used to determine beforehand how much noise
// will be added to samples.
int32_t nosend_word (WavpackStream *wps, int32_t value, int chan)
{
struct entropy_data *c = wps->w.c + chan;
uint32_t ones_count, low, mid, high;
int sign = (value < 0) ? 1 : 0;
if (sign)
value = ~value;
if ((wps->wphdr.flags & HYBRID_FLAG) && !chan)
update_error_limit (wps);
if (value < (int32_t) GET_MED (0)) {
low = 0;
high = GET_MED (0) - 1;
DEC_MED0 ();
}
else {
low = GET_MED (0);
INC_MED0 ();
if (value - low < GET_MED (1)) {
high = low + GET_MED (1) - 1;
DEC_MED1 ();
}
else {
low += GET_MED (1);
INC_MED1 ();
if (value - low < GET_MED (2)) {
high = low + GET_MED (2) - 1;
DEC_MED2 ();
}
else {
ones_count = 2 + (value - low) / GET_MED (2);
low += (ones_count - 2) * GET_MED (2);
high = low + GET_MED (2) - 1;
INC_MED2 ();
}
}
}
mid = (high + low + 1) >> 1;
if (!c->error_limit)
mid = value;
else
while (high - low > c->error_limit)
if (value < (int32_t) mid)
mid = ((high = mid - 1) + low + 1) >> 1;
else
mid = (high + (low = mid) + 1) >> 1;
c->slow_level -= (c->slow_level + SLO) >> SLS;
c->slow_level += wp_log2 (mid);
return sign ? ~mid : mid;
}
// This function is used to scan some number of samples to set the variables
// "slow_level" and the "median" array. In pure 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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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 = "<group>"; };
8310BA281D7377850055CEC5 /* common_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = common_utils.c; path = Files/common_utils.c; sourceTree = "<group>"; };
8310BA291D7377850055CEC5 /* decorr_tables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = decorr_tables.h; path = Files/decorr_tables.h; sourceTree = "<group>"; };
8310BA2A1D7377850055CEC5 /* decorr_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = decorr_utils.c; path = Files/decorr_utils.c; sourceTree = "<group>"; };
8310BA2B1D7377850055CEC5 /* entropy_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = entropy_utils.c; path = Files/entropy_utils.c; sourceTree = "<group>"; };
8310BA2C1D7377850055CEC5 /* open_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = open_utils.c; path = Files/open_utils.c; sourceTree = "<group>"; };
8310BA2D1D7377850055CEC5 /* read_words.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = read_words.c; path = Files/read_words.c; sourceTree = "<group>"; };
8310BA2E1D7377850055CEC5 /* tag_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = tag_utils.c; path = Files/tag_utils.c; sourceTree = "<group>"; };
8310BA2F1D7377850055CEC5 /* unpack_dsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_dsd.c; path = Files/unpack_dsd.c; sourceTree = "<group>"; };
8310BA301D7377850055CEC5 /* unpack_floats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_floats.c; path = Files/unpack_floats.c; sourceTree = "<group>"; };
8310BA311D7377850055CEC5 /* unpack_seek.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_seek.c; path = Files/unpack_seek.c; sourceTree = "<group>"; };
8310BA321D7377850055CEC5 /* unpack_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack_utils.c; path = Files/unpack_utils.c; sourceTree = "<group>"; };
8310BA331D7377850055CEC5 /* unpack3_open.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack3_open.c; path = Files/unpack3_open.c; sourceTree = "<group>"; };
8310BA341D7377850055CEC5 /* unpack3_seek.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unpack3_seek.c; path = Files/unpack3_seek.c; sourceTree = "<group>"; };
8310BA421D7377B80055CEC5 /* write_words.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = write_words.c; path = Files/write_words.c; sourceTree = "<group>"; };
8310BA441D7377DC0055CEC5 /* open_filename.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = open_filename.c; path = Files/open_filename.c; sourceTree = "<group>"; };
8310BA451D7377DC0055CEC5 /* open_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = open_legacy.c; path = Files/open_legacy.c; sourceTree = "<group>"; };
8310BA461D7377DC0055CEC5 /* pack_dns.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_dns.c; path = Files/pack_dns.c; sourceTree = "<group>"; };
8310BA471D7377DC0055CEC5 /* pack_dsd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_dsd.c; path = Files/pack_dsd.c; sourceTree = "<group>"; };
8310BA481D7377DC0055CEC5 /* pack_floats.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_floats.c; path = Files/pack_floats.c; sourceTree = "<group>"; };
8310BA491D7377DC0055CEC5 /* pack_utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = pack_utils.c; path = Files/pack_utils.c; sourceTree = "<group>"; };
833F683A1CDBCAB200AFB9F0 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
83DD1DCD17FA038A00249519 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = utils.h; path = Files/utils.h; sourceTree = "<group>"; };
83DD1DCE17FA038A00249519 /* wavpack_local.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wavpack_local.h; path = Files/wavpack_local.h; sourceTree = "<group>"; };
@ -43,20 +77,13 @@
8E7574AF09F31BB90080F1EE /* md5.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = md5.h; path = Files/md5.h; sourceTree = "<group>"; };
8E7574B009F31BB90080F1EE /* unpack3.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = unpack3.h; path = Files/unpack3.h; sourceTree = "<group>"; };
8E7574B109F31BB90080F1EE /* wavpack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = wavpack.h; path = Files/wavpack.h; sourceTree = "<group>"; };
8E7574B709F31BD50080F1EE /* bits.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = bits.c; path = Files/bits.c; sourceTree = "<group>"; };
8E7574B809F31BD50080F1EE /* extra1.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = extra1.c; path = Files/extra1.c; sourceTree = "<group>"; };
8E7574B909F31BD50080F1EE /* extra2.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = extra2.c; path = Files/extra2.c; sourceTree = "<group>"; };
8E7574BA09F31BD50080F1EE /* float.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = float.c; path = Files/float.c; sourceTree = "<group>"; };
8E7574BB09F31BD50080F1EE /* md5.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = md5.c; path = Files/md5.c; sourceTree = "<group>"; };
8E7574BC09F31BD50080F1EE /* metadata.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = metadata.c; path = Files/metadata.c; sourceTree = "<group>"; };
8E7574BD09F31BD50080F1EE /* pack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = pack.c; path = Files/pack.c; sourceTree = "<group>"; };
8E7574BE09F31BD50080F1EE /* unpack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = unpack.c; path = Files/unpack.c; sourceTree = "<group>"; };
8E7574BF09F31BD50080F1EE /* unpack3.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = unpack3.c; path = Files/unpack3.c; sourceTree = "<group>"; };
8E7574C009F31BD50080F1EE /* utils.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = utils.c; path = Files/utils.c; sourceTree = "<group>"; };
8E7574C109F31BD50080F1EE /* wavpack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wavpack.c; path = Files/wavpack.c; sourceTree = "<group>"; };
8E7574C209F31BD50080F1EE /* words.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = words.c; path = Files/words.c; sourceTree = "<group>"; };
8E7574C309F31BD50080F1EE /* wputils.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wputils.c; path = Files/wputils.c; sourceTree = "<group>"; };
8E7574C409F31BD50080F1EE /* wvunpack.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = wvunpack.c; path = Files/wvunpack.c; sourceTree = "<group>"; };
8E7574F409F31C7D0080F1EE /* libiconv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libiconv.dylib; path = /usr/lib/libiconv.dylib; sourceTree = "<absolute>"; };
/* End PBXFileReference section */
@ -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 = "<group>";
@ -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;
};

View File

@ -22,6 +22,7 @@
int bitsPerSample;
int channels;
BOOL floatingPoint;
int bitrate;
float frequency;
long totalFrames;

View File

@ -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",