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.
parent
de77fef181
commit
d298087dec
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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-fields within a unit (high-order to low-order or low-order to
|
||||
// high-order) is implementation-defined" (6.7.2.1), I decided to change
|
||||
// bit-fields within a unit (high-order to low-order or low-order to
|
||||
// high-order) is implementation-defined" (6.7.2.1), I decided to change
|
||||
// the representation of floating-point values from a structure of
|
||||
// bit-fields to a 32-bit integer with access macros. Note that the WavPack
|
||||
// library doesn't use any floating-point math to implement compression of
|
||||
|
@ -58,6 +54,7 @@ typedef float float32_t;
|
|||
typedef int32_t f32;
|
||||
|
||||
#define get_mantissa(f) ((f) & 0x7fffff)
|
||||
#define get_magnitude(f) ((f) & 0x7fffffff)
|
||||
#define get_exponent(f) (((f) >> 23) & 0xff)
|
||||
#define get_sign(f) (((f) >> 31) & 0x1)
|
||||
|
||||
|
@ -92,7 +89,8 @@ typedef struct {
|
|||
#define APE_TAG_MAX_LENGTH (1024 * 1024 * 16)
|
||||
|
||||
typedef struct {
|
||||
int32_t tag_file_pos, tag_begins_file;
|
||||
int64_t tag_file_pos;
|
||||
int tag_begins_file;
|
||||
ID3_Tag id3_tag;
|
||||
APE_Tag_Hdr ape_tag_hdr;
|
||||
unsigned char *ape_tag_data;
|
||||
|
@ -115,12 +113,12 @@ typedef struct {
|
|||
#define ChunkHeaderFormat "4L"
|
||||
|
||||
typedef struct {
|
||||
unsigned short FormatTag, NumChannels;
|
||||
uint16_t FormatTag, NumChannels;
|
||||
uint32_t SampleRate, BytesPerSecond;
|
||||
unsigned short BlockAlign, BitsPerSample;
|
||||
unsigned short cbSize, ValidBitsPerSample;
|
||||
uint16_t BlockAlign, BitsPerSample;
|
||||
uint16_t cbSize, ValidBitsPerSample;
|
||||
int32_t ChannelMask;
|
||||
unsigned short SubFormat;
|
||||
uint16_t SubFormat;
|
||||
char GUID [14];
|
||||
} WaveHeader;
|
||||
|
||||
|
@ -135,13 +133,43 @@ typedef struct {
|
|||
typedef struct {
|
||||
char ckID [4];
|
||||
uint32_t ckSize;
|
||||
short version;
|
||||
unsigned char track_no, index_no;
|
||||
int16_t version;
|
||||
unsigned char block_index_u8;
|
||||
unsigned char total_samples_u8;
|
||||
uint32_t total_samples, block_index, block_samples, flags, crc;
|
||||
} WavpackHeader;
|
||||
|
||||
#define WavpackHeaderFormat "4LS2LLLLL"
|
||||
|
||||
// Macros to access the 40-bit block_index field
|
||||
|
||||
#define GET_BLOCK_INDEX(hdr) ( (int64_t) (hdr).block_index + ((int64_t) (hdr).block_index_u8 << 32) )
|
||||
|
||||
#define SET_BLOCK_INDEX(hdr,value) do { \
|
||||
int64_t tmp = (value); \
|
||||
(hdr).block_index = (uint32_t) tmp; \
|
||||
(hdr).block_index_u8 = \
|
||||
(unsigned char) (tmp >> 32); \
|
||||
} while (0)
|
||||
|
||||
// Macros to access the 40-bit total_samples field, which is complicated by the fact that
|
||||
// all 1's in the lower 32 bits indicates "unknown" (regardless of upper 8 bits)
|
||||
|
||||
#define GET_TOTAL_SAMPLES(hdr) ( ((hdr).total_samples == (uint32_t) -1) ? -1 : \
|
||||
(int64_t) (hdr).total_samples + ((int64_t) (hdr).total_samples_u8 << 32) - (hdr).total_samples_u8 )
|
||||
|
||||
#define SET_TOTAL_SAMPLES(hdr,value) do { \
|
||||
int64_t tmp = (value); \
|
||||
if (tmp < 0) \
|
||||
(hdr).total_samples = (uint32_t) -1; \
|
||||
else { \
|
||||
tmp += (tmp / 0xffffffffLL); \
|
||||
(hdr).total_samples = (uint32_t) tmp; \
|
||||
(hdr).total_samples_u8 = \
|
||||
(unsigned char) (tmp >> 32); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// or-values for "flags"
|
||||
|
||||
#define BYTES_STORED 3 // 1-4 bytes/sample
|
||||
|
@ -172,14 +200,16 @@ typedef struct {
|
|||
|
||||
#define IGNORED_FLAGS 0x18000000 // reserved, but ignore if encountered
|
||||
#define NEW_SHAPING 0x20000000 // use IIR filter for negative shaping
|
||||
#define UNKNOWN_FLAGS 0x80000000 // also reserved, but refuse decode if
|
||||
// encountered
|
||||
#define DSD_FLAG 0x80000000 // block is DSD encoded (introduced in
|
||||
// WavPack 5.0)
|
||||
|
||||
#define UNKNOWN_FLAGS 0x00000000 // we no longer have any of these spares
|
||||
|
||||
#define MONO_DATA (MONO_FLAG | FALSE_STEREO)
|
||||
|
||||
#define MIN_STREAM_VERS 0x402 // lowest stream version we'll decode
|
||||
#define MAX_STREAM_VERS 0x410 // highest stream version we'll decode or encode
|
||||
#define CUR_STREAM_VERS 0x407 // stream version we are [normally] writing now
|
||||
#define CUR_STREAM_VERS 0x410 // stream version we are writing now
|
||||
|
||||
|
||||
//////////////////////////// WavPack Metadata /////////////////////////////////
|
||||
|
@ -211,14 +241,18 @@ typedef struct {
|
|||
#define ID_WVC_BITSTREAM 0xb
|
||||
#define ID_WVX_BITSTREAM 0xc
|
||||
#define ID_CHANNEL_INFO 0xd
|
||||
#define ID_DSD_BLOCK 0xe
|
||||
|
||||
#define ID_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1)
|
||||
#define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2)
|
||||
#define ID_REPLAY_GAIN (ID_OPTIONAL_DATA | 0x3)
|
||||
#define ID_CUESHEET (ID_OPTIONAL_DATA | 0x4)
|
||||
#define ID_ALT_HEADER (ID_OPTIONAL_DATA | 0x3)
|
||||
#define ID_ALT_TRAILER (ID_OPTIONAL_DATA | 0x4)
|
||||
#define ID_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0x5)
|
||||
#define ID_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x6)
|
||||
#define ID_SAMPLE_RATE (ID_OPTIONAL_DATA | 0x7)
|
||||
#define ID_ALT_EXTENSION (ID_OPTIONAL_DATA | 0x8)
|
||||
#define ID_ALT_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x9)
|
||||
#define ID_NEW_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0xa)
|
||||
|
||||
///////////////////////// WavPack Configuration ///////////////////////////////
|
||||
|
||||
|
@ -264,6 +298,8 @@ typedef struct {
|
|||
#define CONFIG_PAIR_UNDEF_CHANS 0x20000000 // encode undefined channels in stereo pairs
|
||||
#define CONFIG_OPTIMIZE_MONO 0x80000000 // optimize for mono streams posing as stereo
|
||||
|
||||
#define QMODE_DSD_AUDIO 0x30 // if either of these is set in qmode (version 5.0)
|
||||
|
||||
/*
|
||||
* These config flags were never actually used, or are no longer used, or are
|
||||
* used for something else now. They may be used in the future for what they
|
||||
|
@ -305,7 +341,7 @@ typedef struct {
|
|||
|
||||
typedef struct bs {
|
||||
#ifdef BITSTREAM_SHORTS
|
||||
unsigned short *buf, *end, *ptr;
|
||||
uint16_t *buf, *end, *ptr;
|
||||
#else
|
||||
unsigned char *buf, *end, *ptr;
|
||||
#endif
|
||||
|
@ -320,8 +356,10 @@ typedef struct bs {
|
|||
#define MAX_NTERMS 16
|
||||
#define MAX_TERM 8
|
||||
|
||||
// Note that this structure is directly accessed in assembly files, so modify with care
|
||||
|
||||
struct decorr_pass {
|
||||
int term, delta, weight_A, weight_B;
|
||||
int32_t term, delta, weight_A, weight_B;
|
||||
int32_t samples_A [MAX_TERM], samples_B [MAX_TERM];
|
||||
int32_t aweight_A, aweight_B;
|
||||
int32_t sum_A, sum_B;
|
||||
|
@ -342,6 +380,10 @@ struct words_data {
|
|||
struct entropy_data c [2];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
int32_t filter1, filter2, filter3, filter4, filter5, filter6, factor;
|
||||
} DSDfilters;
|
||||
|
||||
typedef struct {
|
||||
WavpackHeader wphdr;
|
||||
struct words_data w;
|
||||
|
@ -350,9 +392,10 @@ typedef struct {
|
|||
unsigned char *block2buff, *block2end;
|
||||
int32_t *sample_buffer;
|
||||
|
||||
int64_t sample_index;
|
||||
int bits, num_terms, mute_error, joint_stereo, false_stereo, shift;
|
||||
int num_decorrs, num_passes, best_decorr, mask_decorr;
|
||||
uint32_t sample_index, crc, crc_x, crc_wvx;
|
||||
uint32_t crc, crc_x, crc_wvx;
|
||||
Bitstream wvbits, wvcbits, wvxbits;
|
||||
int init_done, wvc_skip;
|
||||
float delta_decay;
|
||||
|
@ -363,12 +406,22 @@ typedef struct {
|
|||
struct {
|
||||
int32_t shaping_acc [2], shaping_delta [2], error [2];
|
||||
double noise_sum, noise_ave, noise_max;
|
||||
short *shaping_data, *shaping_array;
|
||||
int16_t *shaping_data, *shaping_array;
|
||||
int32_t shaping_samples;
|
||||
} dc;
|
||||
|
||||
struct decorr_pass decorr_passes [MAX_NTERMS], analysis_pass;
|
||||
const WavpackDecorrSpec *decorr_specs;
|
||||
|
||||
struct {
|
||||
unsigned char *byteptr, *endptr, (*probabilities) [256], **value_lookup, mode, ready;
|
||||
int history_bins, p0, p1;
|
||||
int16_t (*summed_probabilities) [256];
|
||||
uint32_t low, high, value;
|
||||
DSDfilters filters [2];
|
||||
int32_t *ptable;
|
||||
} dsd;
|
||||
|
||||
} WavpackStream;
|
||||
|
||||
// flags for float_flags:
|
||||
|
@ -399,6 +452,22 @@ typedef struct {
|
|||
int32_t (*write_bytes)(void *id, void *data, int32_t bcount);
|
||||
} WavpackStreamReader;
|
||||
|
||||
// Extended version of structure for handling large files and added
|
||||
// functionality for truncating and closing files
|
||||
|
||||
typedef struct {
|
||||
int32_t (*read_bytes)(void *id, void *data, int32_t bcount);
|
||||
int32_t (*write_bytes)(void *id, void *data, int32_t bcount);
|
||||
int64_t (*get_pos)(void *id); // new signature for large files
|
||||
int (*set_pos_abs)(void *id, int64_t pos); // new signature for large files
|
||||
int (*set_pos_rel)(void *id, int64_t delta, int mode); // new signature for large files
|
||||
int (*push_back_byte)(void *id, int c);
|
||||
int64_t (*get_length)(void *id); // new signature for large files
|
||||
int (*can_seek)(void *id);
|
||||
int (*truncate_here)(void *id); // new function to truncate file at current position
|
||||
int (*close)(void *id); // new function to close file
|
||||
} WavpackStreamReader64;
|
||||
|
||||
typedef int (*WavpackBlockOutput)(void *id, void *data, int32_t bcount);
|
||||
|
||||
typedef struct {
|
||||
|
@ -414,12 +483,13 @@ typedef struct {
|
|||
WavpackBlockOutput blockout;
|
||||
void *wv_out, *wvc_out;
|
||||
|
||||
WavpackStreamReader *reader;
|
||||
WavpackStreamReader64 *reader;
|
||||
void *wv_in, *wvc_in;
|
||||
|
||||
uint32_t filelen, file2len, filepos, file2pos, total_samples, crc_errors, first_flags;
|
||||
int wvc_flag, open_flags, norm_offset, reduced_channels, lossy_blocks, close_files;
|
||||
uint32_t block_samples, ave_block_samples, block_boundary, max_samples, acc_samples, initial_index, riff_trailer_bytes;
|
||||
int64_t filelen, file2len, filepos, file2pos, total_samples, initial_index;
|
||||
uint32_t crc_errors, first_flags;
|
||||
int wvc_flag, open_flags, norm_offset, reduced_channels, lossy_blocks, version_five;
|
||||
uint32_t block_samples, ave_block_samples, block_boundary, max_samples, acc_samples, riff_trailer_bytes;
|
||||
int riff_header_added, riff_header_created;
|
||||
M_Tag m_tag;
|
||||
|
||||
|
@ -427,6 +497,12 @@ typedef struct {
|
|||
WavpackStream **streams;
|
||||
void *stream3;
|
||||
|
||||
// these items were added in 5.0 to support alternate file types (especially CAF & DSD)
|
||||
unsigned char file_format, *channel_reordering;
|
||||
uint32_t channel_layout, dsd_multiplier;
|
||||
void *decimation_context;
|
||||
char file_extension [8];
|
||||
|
||||
char error_message [80];
|
||||
} WavpackContext;
|
||||
|
||||
|
@ -434,6 +510,11 @@ typedef struct {
|
|||
|
||||
#define CLEAR(destin) memset (&destin, 0, sizeof (destin));
|
||||
|
||||
//////////////////////////////// decorrelation //////////////////////////////
|
||||
// modules: pack.c, unpack.c, unpack_floats.c, extra1.c, extra2.c
|
||||
|
||||
// #define SKIP_DECORRELATION // experimental switch to disable all decorrelation on encode
|
||||
|
||||
// These macros implement the weight application and update operations
|
||||
// that are at the heart of the decorrelation loops. Note that there are
|
||||
// sometimes two and even three versions of each macro. Theses should be
|
||||
|
@ -449,15 +530,17 @@ typedef struct {
|
|||
#if 1 // PERFCOND - apply decorrelation weight when 32-bit overflow is possible
|
||||
#define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \
|
||||
(((sample & ~0xffff) >> 9) * weight) + 1) >> 1)
|
||||
#elif 1
|
||||
#define apply_weight_f(weight, sample) ((int32_t)((weight * (int64_t) sample + 512) >> 10))
|
||||
#else
|
||||
#define apply_weight_f(weight, sample) ((int32_t)floor(((double) weight * sample + 512.0) / 1024.0))
|
||||
#endif
|
||||
|
||||
#if 1 // PERFCOND - universal version that checks input magnitude (or simply uses 64-bit ints)
|
||||
#define apply_weight(weight, sample) (sample != (short) sample ? \
|
||||
#if 1 // PERFCOND - universal version that checks input magnitude or always uses long version
|
||||
#define apply_weight(weight, sample) (sample != (int16_t) sample ? \
|
||||
apply_weight_f (weight, sample) : apply_weight_i (weight, sample))
|
||||
#else
|
||||
#define apply_weight(weight, sample) ((int32_t)((weight * (int64_t) sample + 512) >> 10))
|
||||
#define apply_weight(weight, sample) (apply_weight_f (weight, sample))
|
||||
#endif
|
||||
|
||||
#if 1 // PERFCOND
|
||||
|
@ -488,22 +571,59 @@ typedef struct {
|
|||
weight = (weight ^ s) - s; \
|
||||
}
|
||||
|
||||
// bits.c
|
||||
void pack_init (WavpackContext *wpc);
|
||||
int pack_block (WavpackContext *wpc, int32_t *buffer);
|
||||
void send_general_metadata (WavpackContext *wpc);
|
||||
void free_metadata (WavpackMetadata *wpmd);
|
||||
int copy_metadata (WavpackMetadata *wpmd, unsigned char *buffer_start, unsigned char *buffer_end);
|
||||
double WavpackGetEncodedNoise (WavpackContext *wpc, double *peak);
|
||||
int unpack_init (WavpackContext *wpc);
|
||||
int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count);
|
||||
int check_crc_error (WavpackContext *wpc);
|
||||
int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values);
|
||||
void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values);
|
||||
void float_values (WavpackStream *wps, int32_t *values, int32_t num_values);
|
||||
void dynamic_noise_shaping (WavpackContext *wpc, int32_t *buffer, int shortening_allowed);
|
||||
void execute_stereo (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples);
|
||||
void execute_mono (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples);
|
||||
|
||||
void bs_open_read (Bitstream *bs, void *buffer_start, void *buffer_end);
|
||||
void bs_open_write (Bitstream *bs, void *buffer_start, void *buffer_end);
|
||||
uint32_t bs_close_read (Bitstream *bs);
|
||||
uint32_t bs_close_write (Bitstream *bs);
|
||||
////////////////////////// DSD related (including decimation) //////////////////////////
|
||||
// modules: pack_dsd.c unpack_dsd.c
|
||||
|
||||
int DoReadFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToRead, uint32_t *lpNumberOfBytesRead);
|
||||
int DoWriteFile (FILE *hFile, void *lpBuffer, uint32_t nNumberOfBytesToWrite, uint32_t *lpNumberOfBytesWritten);
|
||||
uint32_t DoGetFileSize (FILE *hFile), DoGetFilePosition (FILE *hFile);
|
||||
int DoSetFilePositionRelative (FILE *hFile, int32_t pos, int mode);
|
||||
int DoSetFilePositionAbsolute (FILE *hFile, uint32_t pos);
|
||||
int DoUngetc (int c, FILE *hFile), DoDeleteFile (char *filename);
|
||||
int DoCloseHandle (FILE *hFile), DoTruncateFile (FILE *hFile);
|
||||
void pack_dsd_init (WavpackContext *wpc);
|
||||
int pack_dsd_block (WavpackContext *wpc, int32_t *buffer);
|
||||
int init_dsd_block (WavpackContext *wpc, WavpackMetadata *wpmd);
|
||||
int32_t unpack_dsd_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count);
|
||||
|
||||
void *decimate_dsd_init (int num_channels);
|
||||
void decimate_dsd_reset (void *decimate_context);
|
||||
void decimate_dsd_run (void *decimate_context, int32_t *samples, int num_samples);
|
||||
void decimate_dsd_destroy (void *decimate_context);
|
||||
|
||||
///////////////////////////////// CPU feature detection ////////////////////////////////
|
||||
|
||||
int unpack_cpu_has_feature_x86 (int findex), pack_cpu_has_feature_x86 (int findex);
|
||||
|
||||
#define CPU_FEATURE_MMX 23
|
||||
|
||||
///////////////////////////// pre-4.0 version decoding ////////////////////////////
|
||||
// modules: unpack3.c, unpack3_open.c, unpack3_seek.c
|
||||
|
||||
WavpackContext *open_file3 (WavpackContext *wpc, char *error);
|
||||
int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count);
|
||||
int seek_sample3 (WavpackContext *wpc, uint32_t desired_index);
|
||||
uint32_t get_sample_index3 (WavpackContext *wpc);
|
||||
void free_stream3 (WavpackContext *wpc);
|
||||
int get_version3 (WavpackContext *wpc);
|
||||
|
||||
////////////////////////////// bitstream macros & functions /////////////////////////////
|
||||
|
||||
#define bs_is_open(bs) ((bs)->ptr != NULL)
|
||||
uint32_t bs_close_read (Bitstream *bs);
|
||||
|
||||
#define getbit(bs) ( \
|
||||
(((bs)->bc) ? \
|
||||
|
@ -564,56 +684,51 @@ int DoCloseHandle (FILE *hFile), DoTruncateFile (FILE *hFile);
|
|||
} while ((bs)->bc >= sizeof (*((bs)->ptr)) * 8); \
|
||||
} while (0)
|
||||
|
||||
void little_endian_to_native (void *data, char *format);
|
||||
void native_to_little_endian (void *data, char *format);
|
||||
///////////////////////////// entropy encoder / decoder ////////////////////////////
|
||||
// modules: entropy_utils.c, read_words.c, write_words.c
|
||||
|
||||
// pack.c
|
||||
// these control the time constant "slow_level" which is used for hybrid mode
|
||||
// that controls bitrate as a function of residual level (HYBRID_BITRATE).
|
||||
#define SLS 8
|
||||
#define SLO ((1 << (SLS - 1)))
|
||||
|
||||
void pack_init (WavpackContext *wpc);
|
||||
int pack_block (WavpackContext *wpc, int32_t *buffer);
|
||||
double WavpackGetEncodedNoise (WavpackContext *wpc, double *peak);
|
||||
#define LIMIT_ONES 16 // maximum consecutive 1s sent for "div" data
|
||||
|
||||
// unpack.c
|
||||
// these control the time constant of the 3 median level breakpoints
|
||||
#define DIV0 128 // 5/7 of samples
|
||||
#define DIV1 64 // 10/49 of samples
|
||||
#define DIV2 32 // 20/343 of samples
|
||||
|
||||
int unpack_init (WavpackContext *wpc);
|
||||
int init_wv_bitstream (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int init_wvc_bitstream (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int init_wvx_bitstream (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd);
|
||||
int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd);
|
||||
int read_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd);
|
||||
int read_wrapper_data (WavpackContext *wpc, WavpackMetadata *wpmd);
|
||||
int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count);
|
||||
int check_crc_error (WavpackContext *wpc);
|
||||
// this macro retrieves the specified median breakpoint (without frac; min = 1)
|
||||
#define GET_MED(med) (((c->median [med]) >> 4) + 1)
|
||||
|
||||
// unpack3.c
|
||||
// These macros update the specified median breakpoints. Note that the median
|
||||
// is incremented when the sample is higher than the median, else decremented.
|
||||
// They are designed so that the median will never drop below 1 and the value
|
||||
// is essentially stationary if there are 2 increments for every 5 decrements.
|
||||
|
||||
WavpackContext *open_file3 (WavpackContext *wpc, char *error);
|
||||
int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count);
|
||||
int seek_sample3 (WavpackContext *wpc, uint32_t desired_index);
|
||||
uint32_t get_sample_index3 (WavpackContext *wpc);
|
||||
void free_stream3 (WavpackContext *wpc);
|
||||
int get_version3 (WavpackContext *wpc);
|
||||
#define INC_MED0() (c->median [0] += ((c->median [0] + DIV0) / DIV0) * 5)
|
||||
#define DEC_MED0() (c->median [0] -= ((c->median [0] + (DIV0-2)) / DIV0) * 2)
|
||||
#define INC_MED1() (c->median [1] += ((c->median [1] + DIV1) / DIV1) * 5)
|
||||
#define DEC_MED1() (c->median [1] -= ((c->median [1] + (DIV1-2)) / DIV1) * 2)
|
||||
#define INC_MED2() (c->median [2] += ((c->median [2] + DIV2) / DIV2) * 5)
|
||||
#define DEC_MED2() (c->median [2] -= ((c->median [2] + (DIV2-2)) / DIV2) * 2)
|
||||
|
||||
// metadata.c stuff
|
||||
|
||||
int read_metadata_buff (WavpackMetadata *wpmd, unsigned char *blockbuff, unsigned char **buffptr);
|
||||
int write_metadata_block (WavpackContext *wpc);
|
||||
int copy_metadata (WavpackMetadata *wpmd, unsigned char *buffer_start, unsigned char *buffer_end);
|
||||
int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, unsigned char id);
|
||||
int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd);
|
||||
void free_metadata (WavpackMetadata *wpmd);
|
||||
|
||||
// words.c stuff
|
||||
#ifdef HAVE___BUILTIN_CLZ
|
||||
#define count_bits(av) ((av) ? 32 - __builtin_clz (av) : 0)
|
||||
#elif defined (_WIN64)
|
||||
static __inline int count_bits (uint32_t av) { unsigned long res; return _BitScanReverse (&res, av) ? (int)(res + 1) : 0; }
|
||||
#else
|
||||
#define count_bits(av) ( \
|
||||
(av) < (1 << 8) ? nbits_table [av] : \
|
||||
( \
|
||||
(av) < (1L << 16) ? nbits_table [(av) >> 8] + 8 : \
|
||||
((av) < (1L << 24) ? nbits_table [(av) >> 16] + 16 : nbits_table [(av) >> 24] + 24) \
|
||||
) \
|
||||
)
|
||||
#endif
|
||||
|
||||
void init_words (WavpackStream *wps);
|
||||
void word_set_bitrate (WavpackStream *wps);
|
||||
void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
void write_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
|
@ -625,34 +740,39 @@ int32_t get_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsample
|
|||
void flush_word (WavpackStream *wps);
|
||||
int32_t nosend_word (WavpackStream *wps, int32_t value, int chan);
|
||||
void scan_word (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir);
|
||||
void update_error_limit (WavpackStream *wps);
|
||||
|
||||
int log2s (int32_t value);
|
||||
int32_t exp2s (int log);
|
||||
uint32_t log2buffer (int32_t *samples, uint32_t num_samples, int limit);
|
||||
extern const uint32_t bitset [32];
|
||||
extern const uint32_t bitmask [32];
|
||||
extern const char nbits_table [256];
|
||||
|
||||
int wp_log2s (int32_t value);
|
||||
int32_t wp_exp2s (int log);
|
||||
int FASTCALL wp_log2 (uint32_t avalue);
|
||||
|
||||
#ifdef OPT_ASM_X86
|
||||
#define LOG2BUFFER log2buffer_x86
|
||||
#elif defined(OPT_ASM_X64) && (defined (_WIN64) || defined(__CYGWIN__) || defined(__MINGW64__))
|
||||
#define LOG2BUFFER log2buffer_x64win
|
||||
#elif defined(OPT_ASM_X64)
|
||||
#define LOG2BUFFER log2buffer_x64
|
||||
#else
|
||||
#define LOG2BUFFER log2buffer
|
||||
#endif
|
||||
|
||||
uint32_t LOG2BUFFER (int32_t *samples, uint32_t num_samples, int limit);
|
||||
|
||||
signed char store_weight (int weight);
|
||||
int restore_weight (signed char weight);
|
||||
|
||||
#define WORD_EOF ((int32_t)(1L << 31))
|
||||
|
||||
// float.c
|
||||
|
||||
void write_float_info (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values);
|
||||
void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values);
|
||||
int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
void float_values (WavpackStream *wps, int32_t *values, int32_t num_values);
|
||||
void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp);
|
||||
|
||||
// extra?.c
|
||||
|
||||
// void analyze_stereo (WavpackContext *wpc, int32_t *samples);
|
||||
// void analyze_mono (WavpackContext *wpc, int32_t *samples);
|
||||
void execute_stereo (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples);
|
||||
void execute_mono (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples);
|
||||
|
||||
// wputils.c
|
||||
/////////////////////////// high-level unpacking API and support ////////////////////////////
|
||||
// modules: open_utils.c, unpack_utils.c, unpack_seek.c, unpack_floats.c
|
||||
|
||||
WavpackContext *WavpackOpenFileInputEx64 (WavpackStreamReader64 *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset);
|
||||
WavpackContext *WavpackOpenFileInputEx (WavpackStreamReader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset);
|
||||
WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset);
|
||||
|
||||
|
@ -664,6 +784,15 @@ WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int f
|
|||
#define OPEN_STREAMING 0x20 // "streaming" mode blindly unpacks blocks
|
||||
// w/o regard to header file position info
|
||||
#define OPEN_EDIT_TAGS 0x40 // allow editing of tags
|
||||
#define OPEN_FILE_UTF8 0x80 // assume filenames are UTF-8 encoded, not ANSI (Windows only)
|
||||
|
||||
// new for version 5
|
||||
|
||||
#define OPEN_DSD_NATIVE 0x100 // open DSD files as bitstreams
|
||||
// (returned as 8-bit "samples" stored in 32-bit words)
|
||||
#define OPEN_DSD_AS_PCM 0x200 // open DSD files as 24-bit PCM (decimated 8x)
|
||||
#define OPEN_ALT_TYPES 0x400 // application is aware of alternate file types & qmode
|
||||
// (just affects retrieving wrappers & MD5 checksums)
|
||||
|
||||
int WavpackGetMode (WavpackContext *wpc);
|
||||
|
||||
|
@ -682,15 +811,37 @@ int WavpackGetMode (WavpackContext *wpc);
|
|||
#define MODE_XMODE 0x7000 // mask for extra level (1-6, 0=unknown)
|
||||
#define MODE_DNS 0x8000
|
||||
|
||||
char *WavpackGetErrorMessage (WavpackContext *wpc);
|
||||
int WavpackGetQualifyMode (WavpackContext *wpc);
|
||||
int WavpackGetVersion (WavpackContext *wpc);
|
||||
uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples);
|
||||
uint32_t WavpackGetNumSamples (WavpackContext *wpc);
|
||||
uint32_t WavpackGetSampleIndex (WavpackContext *wpc);
|
||||
int WavpackGetNumErrors (WavpackContext *wpc);
|
||||
int WavpackLossyBlocks (WavpackContext *wpc);
|
||||
int WavpackSeekSample (WavpackContext *wpc, uint32_t sample);
|
||||
WavpackContext *WavpackCloseFile (WavpackContext *wpc);
|
||||
int WavpackSeekSample64 (WavpackContext *wpc, int64_t sample);
|
||||
int WavpackGetMD5Sum (WavpackContext *wpc, unsigned char data [16]);
|
||||
|
||||
uint32_t read_next_header (WavpackStreamReader64 *reader, void *id, WavpackHeader *wphdr);
|
||||
int read_wvc_block (WavpackContext *wpc);
|
||||
|
||||
/////////////////////////// high-level packing API and support ////////////////////////////
|
||||
// modules: pack_utils.c, pack_floats.c
|
||||
|
||||
WavpackContext *WavpackOpenFileOutput (WavpackBlockOutput blockout, void *wv_id, void *wvc_id);
|
||||
int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples);
|
||||
int WavpackSetConfiguration64 (WavpackContext *wpc, WavpackConfig *config, int64_t total_samples);
|
||||
int WavpackPackInit (WavpackContext *wpc);
|
||||
int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount);
|
||||
int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count);
|
||||
int WavpackFlushSamples (WavpackContext *wpc);
|
||||
int WavpackStoreMD5Sum (WavpackContext *wpc, unsigned char data [16]);
|
||||
void WavpackSeekTrailingWrapper (WavpackContext *wpc);
|
||||
void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block);
|
||||
void *WavpackGetWrapperLocation (void *first_block, uint32_t *size);
|
||||
|
||||
/////////////////////////////////// common utilities ////////////////////////////////////
|
||||
// module: common_utils.c
|
||||
|
||||
extern const uint32_t sample_rates [16];
|
||||
uint32_t WavpackGetLibraryVersion (void);
|
||||
const char *WavpackGetLibraryVersionString (void);
|
||||
uint32_t WavpackGetSampleRate (WavpackContext *wpc);
|
||||
int WavpackGetBitsPerSample (WavpackContext *wpc);
|
||||
int WavpackGetBytesPerSample (WavpackContext *wpc);
|
||||
|
@ -698,34 +849,32 @@ int WavpackGetNumChannels (WavpackContext *wpc);
|
|||
int WavpackGetChannelMask (WavpackContext *wpc);
|
||||
int WavpackGetReducedChannels (WavpackContext *wpc);
|
||||
int WavpackGetFloatNormExp (WavpackContext *wpc);
|
||||
int WavpackGetMD5Sum (WavpackContext *wpc, unsigned char data [16]);
|
||||
uint32_t WavpackGetNumSamples (WavpackContext *wpc);
|
||||
int64_t WavpackGetNumSamples64 (WavpackContext *wpc);
|
||||
uint32_t WavpackGetSampleIndex (WavpackContext *wpc);
|
||||
int64_t WavpackGetSampleIndex64 (WavpackContext *wpc);
|
||||
char *WavpackGetErrorMessage (WavpackContext *wpc);
|
||||
int WavpackGetNumErrors (WavpackContext *wpc);
|
||||
int WavpackLossyBlocks (WavpackContext *wpc);
|
||||
uint32_t WavpackGetWrapperBytes (WavpackContext *wpc);
|
||||
unsigned char *WavpackGetWrapperData (WavpackContext *wpc);
|
||||
void WavpackFreeWrapper (WavpackContext *wpc);
|
||||
void WavpackSeekTrailingWrapper (WavpackContext *wpc);
|
||||
double WavpackGetProgress (WavpackContext *wpc);
|
||||
uint32_t WavpackGetFileSize (WavpackContext *wpc);
|
||||
int64_t WavpackGetFileSize64 (WavpackContext *wpc);
|
||||
double WavpackGetRatio (WavpackContext *wpc);
|
||||
double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc);
|
||||
double WavpackGetInstantBitrate (WavpackContext *wpc);
|
||||
|
||||
WavpackContext *WavpackOpenFileOutput (WavpackBlockOutput blockout, void *wv_id, void *wvc_id);
|
||||
int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples);
|
||||
int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount);
|
||||
int WavpackStoreMD5Sum (WavpackContext *wpc, unsigned char data [16]);
|
||||
int WavpackPackInit (WavpackContext *wpc);
|
||||
int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count);
|
||||
int WavpackFlushSamples (WavpackContext *wpc);
|
||||
void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block);
|
||||
void *WavpackGetWrapperLocation (void *first_block, uint32_t *size);
|
||||
|
||||
WavpackContext *WavpackCloseFile (WavpackContext *wpc);
|
||||
void WavpackLittleEndianToNative (void *data, char *format);
|
||||
void WavpackNativeToLittleEndian (void *data, char *format);
|
||||
void WavpackBigEndianToNative (void *data, char *format);
|
||||
void WavpackNativeToBigEndian (void *data, char *format);
|
||||
|
||||
uint32_t WavpackGetLibraryVersion (void);
|
||||
const char *WavpackGetLibraryVersionString (void);
|
||||
void free_streams (WavpackContext *wpc);
|
||||
|
||||
// tags.c
|
||||
/////////////////////////////////// tag utilities ////////////////////////////////////
|
||||
// modules: tags.c, tag_utils.c
|
||||
|
||||
int WavpackGetNumTagItems (WavpackContext *wpc);
|
||||
int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size);
|
||||
|
@ -742,58 +891,5 @@ void free_tag (M_Tag *m_tag);
|
|||
int valid_tag (M_Tag *m_tag);
|
||||
int editable_tag (M_Tag *m_tag);
|
||||
|
||||
///////////////////////////// SIMD helper macros /////////////////////////////
|
||||
|
||||
#ifdef OPT_MMX
|
||||
|
||||
#if defined (__GNUC__) && !defined (__INTEL_COMPILER)
|
||||
//directly map to gcc's native builtins for faster code
|
||||
|
||||
#if __GNUC__ < 4
|
||||
typedef int __di __attribute__ ((__mode__ (__DI__)));
|
||||
typedef int __m64 __attribute__ ((__mode__ (__V2SI__)));
|
||||
typedef int __v4hi __attribute__ ((__mode__ (__V4HI__)));
|
||||
#define _m_paddsw(m1, m2) (__m64) __builtin_ia32_paddsw ((__v4hi) m1, (__v4hi) m2)
|
||||
#define _m_pand(m1, m2) (__m64) __builtin_ia32_pand ((__di) m1, (__di) m2)
|
||||
#define _m_pandn(m1, m2) (__m64) __builtin_ia32_pandn ((__di) m1, (__di) m2)
|
||||
#define _m_pmaddwd(m1, m2) __builtin_ia32_pmaddwd ((__v4hi) m1, (__v4hi) m2)
|
||||
#define _m_por(m1, m2) (__m64) __builtin_ia32_por ((__di) m1, (__di) m2)
|
||||
#define _m_pxor(m1, m2) (__m64) __builtin_ia32_pxor ((__di) m1, (__di) m2)
|
||||
#else
|
||||
typedef int __m64 __attribute__ ((__vector_size__ (8)));
|
||||
typedef short __m64_16 __attribute__ ((__vector_size__ (8)));
|
||||
#define _m_paddsw(m1, m2) (__m64) __builtin_ia32_paddsw ((__m64_16) m1, (__m64_16) m2)
|
||||
#define _m_pand(m1, m2) __builtin_ia32_pand (m1, m2)
|
||||
#define _m_pandn(m1, m2) __builtin_ia32_pandn (m1, m2)
|
||||
#define _m_pmaddwd(m1, m2) __builtin_ia32_pmaddwd ((__m64_16) m1, (__m64_16) m2)
|
||||
#define _m_por(m1, m2) __builtin_ia32_por (m1, m2)
|
||||
#define _m_pxor(m1, m2) __builtin_ia32_pxor (m1, m2)
|
||||
#endif
|
||||
|
||||
#define _m_paddd(m1, m2) __builtin_ia32_paddd (m1, m2)
|
||||
#define _m_pcmpeqd(m1, m2) __builtin_ia32_pcmpeqd (m1, m2)
|
||||
|
||||
#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) || __GNUC__ > 4 || __has_builtin(__builtin_ia32_pslldi)
|
||||
# define _m_pslldi(m1, m2) __builtin_ia32_pslldi ((__m64)m1, m2)
|
||||
# define _m_psradi(m1, m2) __builtin_ia32_psradi ((__m64)m1, m2)
|
||||
# define _m_psrldi(m1, m2) __builtin_ia32_psrldi ((__m64)m1, m2)
|
||||
#else
|
||||
# define _m_pslldi(m1, m2) __builtin_ia32_pslld (m1, m2)
|
||||
# define _m_psradi(m1, m2) __builtin_ia32_psrad (m1, m2)
|
||||
# define _m_psrldi(m1, m2) __builtin_ia32_psrld (m1, m2)
|
||||
#endif
|
||||
|
||||
#define _m_psubd(m1, m2) __builtin_ia32_psubd (m1, m2)
|
||||
#define _m_punpckhdq(m1, m2) __builtin_ia32_punpckhdq (m1, m2)
|
||||
#define _m_punpckldq(m1, m2) __builtin_ia32_punpckldq (m1, m2)
|
||||
#define _mm_empty() __builtin_ia32_emms ()
|
||||
#define _mm_set_pi32(m1, m2) { m2, m1 }
|
||||
#define _mm_set1_pi32(m) { m, m }
|
||||
|
||||
#else
|
||||
#include <mmintrin.h>
|
||||
#endif
|
||||
|
||||
#endif //OPT_MMX
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
int bitsPerSample;
|
||||
int channels;
|
||||
BOOL floatingPoint;
|
||||
int bitrate;
|
||||
float frequency;
|
||||
long totalFrames;
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue