Initial import of libwavpack

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@6056 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Christian Gmeiner 2005-02-25 17:05:30 +00:00
parent 234489a449
commit e449d88b3e
12 changed files with 2190 additions and 0 deletions

View file

@ -0,0 +1,25 @@
Copyright (c) 1998 - 2004 Conifer Software
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Conifer Software nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,52 @@
////////////////////////////////////////////////////////////////////////////
// **** WAVPACK **** //
// Hybrid Lossless Wavefile Compressor //
// Copyright (c) 1998 - 2004 Conifer Software. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
This package contains a tiny version of the WavPack 4.0 decoder that might
be used in a "resource limited" CPU environment or form the basis for a
hardware decoding implementation. It is packaged with a demo command-line
program that accepts a WavPack audio file on stdin and outputs a RIFF wav
file to stdout. The program is standard C, and a win32 executable is
included which was compiled under MS Visual C++ 6.0 using this command:
cl /O1 /DWIN32 wvfilter.c wputils.c unpack.c float.c metadata.c words.c bits.c
WavPack data is read with a stream reading callback. No direct seeking is
provided for, but it is possible to start decoding anywhere in a WavPack
stream. In this case, WavPack will be able to provide the sample-accurate
position when it synchs with the data and begins decoding.
For demonstration purposes this uses a single static copy of the
WavpackContext structure, so obviously it cannot be used for more than one
file at a time. Also, this decoder will not handle "correction" files, plays
only the first two channels of multi-channel files, and is limited in
resolution in some large integer or floating point files (but always
provides at least 24 bits of resolution). It also will not accept WavPack
files from before version 4.0.
To make this code viable on the greatest number of hardware platforms, the
following are true:
speed is about 4x realtime on an AMD K6 300 MHz
("high" mode 16/44 stereo; normal mode is about twice that fast)
no floating-point math required; just 32b * 32b = 32b int multiply
large data areas are static and less than 4K total
executable code and tables are less than 32K
no malloc / free usage
To maintain compatibility on various platforms, the following conventions
are used:
a "short" must be 16-bits
a "long" must be 32-bits
an "int" must be at least 16-bits, but may be larger
a "char" must default to signed
Questions or comments should be directed to david@wavpack.com

View file

@ -0,0 +1,15 @@
Library: wavpack - Release 4.1 - September 14, 2004
Imported: 2005-02-25 by Christian Gmeiner
This directory contains a "tiny" decoder version of wavpack for version 4.x.
LICENSING INFORMATION
wavpack is released under the BSD License as described
in the LICENSE file in this directory.
IMPORT DETAILS
Excluded is wvfilter.c, because it is only a test programm.

View file

@ -0,0 +1,6 @@
bits.c
float.c
metadata.c
unpack.c
words.c
wputils.c

View file

@ -0,0 +1,140 @@
////////////////////////////////////////////////////////////////////////////
// **** WAVPACK **** //
// Hybrid Lossless Wavefile Compressor //
// Copyright (c) 1998 - 2004 Conifer Software. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
// bits.c
// This module provides utilities to support the BitStream structure which is
// used to read and write all WavPack audio data streams. It also contains a
// wrapper for the stream I/O functions and a set of functions dealing with
// endian-ness, both for enhancing portability. Finally, a debug wrapper for
// the malloc() system is provided.
#include "wavpack.h"
#include <string.h>
#include <ctype.h>
////////////////////////// Bitstream functions ////////////////////////////////
// Open the specified BitStream and associate with the specified buffer.
static void bs_read (Bitstream *bs);
void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end, read_stream file, ulong file_bytes)
{
CLEAR (*bs);
bs->buf = buffer_start;
bs->end = buffer_end;
if (file) {
bs->ptr = bs->end - 1;
bs->file_bytes = file_bytes;
bs->file = file;
}
else
bs->ptr = bs->buf - 1;
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)
{
if (bs->file && bs->file_bytes) {
ulong bytes_read, bytes_to_read = bs->end - bs->buf;
if (bytes_to_read > bs->file_bytes)
bytes_to_read = bs->file_bytes;
bytes_read = bs->file (bs->buf, bytes_to_read);
if (bytes_read) {
bs->end = bs->buf + bytes_read;
bs->file_bytes -= bytes_read;
}
else {
memset (bs->buf, -1, bs->end - bs->buf);
bs->error = 1;
}
}
else
bs->error = 1;
if (bs->error)
memset (bs->buf, -1, bs->end - bs->buf);
bs->ptr = bs->buf;
}
/////////////////////// Endian Correction Routines ////////////////////////////
void little_endian_to_native (void *data, char *format)
{
uchar *cp = (uchar *) data;
long temp;
while (*format) {
switch (*format) {
case 'L':
temp = cp [0] + ((long) cp [1] << 8) + ((long) cp [2] << 16) + ((long) cp [3] << 24);
* (long *) cp = temp;
cp += 4;
break;
case 'S':
temp = cp [0] + (cp [1] << 8);
* (short *) cp = (short) temp;
cp += 2;
break;
default:
if (isdigit (*format))
cp += *format - '0';
break;
}
format++;
}
}
void native_to_little_endian (void *data, char *format)
{
uchar *cp = (uchar *) data;
long temp;
while (*format) {
switch (*format) {
case 'L':
temp = * (long *) cp;
*cp++ = (uchar) temp;
*cp++ = (uchar) (temp >> 8);
*cp++ = (uchar) (temp >> 16);
*cp++ = (uchar) (temp >> 24);
break;
case 'S':
temp = * (short *) cp;
*cp++ = (uchar) temp;
*cp++ = (uchar) (temp >> 8);
break;
default:
if (isdigit (*format))
cp += *format - '0';
break;
}
format++;
}
}

View file

@ -0,0 +1,83 @@
////////////////////////////////////////////////////////////////////////////
// **** WAVPACK **** //
// Hybrid Lossless Wavefile Compressor //
// Copyright (c) 1998 - 2004 Conifer Software. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
// float.c
#include "wavpack.h"
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;
}
void float_values (WavpackStream *wps, long *values, long num_values)
{
while (num_values--) {
int shift_count = 0, exp = wps->float_max_exp;
f32 outval = { 0, 0, 0 };
if (*values) {
*values <<= wps->float_shift;
if (*values < 0) {
*values = -*values;
outval.sign = 1;
}
if (*values == 0x1000000)
outval.exponent = 255;
else {
if (exp)
while (!(*values & 0x800000) && --exp) {
shift_count++;
*values <<= 1;
}
if (shift_count && (wps->float_flags & FLOAT_SHIFT_ONES))
*values |= ((1 << shift_count) - 1);
outval.mantissa = *values;
outval.exponent = exp;
}
}
* (f32 *) values++ = outval;
}
}
void float_normalize (long *values, long num_values, int delta_exp)
{
f32 *fvalues = (f32 *) values, fzero = { 0, 0, 0 };
int exp;
if (!delta_exp)
return;
while (num_values--) {
if ((exp = fvalues->exponent) == 0 || exp + delta_exp <= 0)
*fvalues = fzero;
else if (exp == 255 || (exp += delta_exp) >= 255) {
fvalues->exponent = 255;
fvalues->mantissa = 0;
}
else
fvalues->exponent = exp;
fvalues++;
}
}

View file

@ -0,0 +1 @@
cl /O1 /DWIN32 wvfilter.c wputils.c unpack.c float.c metadata.c words.c bits.c

View file

@ -0,0 +1,105 @@
////////////////////////////////////////////////////////////////////////////
// **** WAVPACK **** //
// Hybrid Lossless Wavefile Compressor //
// Copyright (c) 1998 - 2003 Conifer Software. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
// metadata.c
// This module handles the metadata structure introduced in WavPack 4.0
#include "wavpack.h"
int read_metadata_buff (WavpackContext *wpc, WavpackMetadata *wpmd)
{
uchar tchar;
if (!wpc->infile (&wpmd->id, 1) || !wpc->infile (&tchar, 1))
return FALSE;
wpmd->byte_length = tchar << 1;
if (wpmd->id & ID_LARGE) {
wpmd->id &= ~ID_LARGE;
if (!wpc->infile (&tchar, 1))
return FALSE;
wpmd->byte_length += (long) tchar << 9;
if (!wpc->infile (&tchar, 1))
return FALSE;
wpmd->byte_length += (long) tchar << 17;
}
if (wpmd->id & ID_ODD_SIZE) {
wpmd->id &= ~ID_ODD_SIZE;
wpmd->byte_length--;
}
if (wpmd->byte_length && wpmd->byte_length <= sizeof (wpc->read_buffer)) {
ulong bytes_to_read = wpmd->byte_length + (wpmd->byte_length & 1);
if (wpc->infile (wpc->read_buffer, bytes_to_read) != (long) bytes_to_read) {
wpmd->data = NULL;
return FALSE;
}
wpmd->data = wpc->read_buffer;
}
else
wpmd->data = NULL;
return TRUE;
}
int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd)
{
WavpackStream *wps = &wpc->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_FLOAT_INFO:
return read_float_info (wps, wpmd);
case ID_INT32_INFO:
return read_int32_info (wps, wpmd);
case ID_CHANNEL_INFO:
return read_channel_info (wpc, wpmd);
case ID_CONFIG_BLOCK:
return read_config_info (wpc, wpmd);
case ID_WV_BITSTREAM:
return init_wv_bitstream (wpc, wpmd);
case ID_SHAPING_WEIGHTS:
case ID_WVC_BITSTREAM:
case ID_WVX_BITSTREAM:
return TRUE;
default:
return (wpmd->id & ID_OPTIONAL_DATA) ? TRUE : FALSE;
}
}

View file

@ -0,0 +1,576 @@
////////////////////////////////////////////////////////////////////////////
// **** WAVPACK **** //
// Hybrid Lossless Wavefile Compressor //
// Copyright (c) 1998 - 2004 Conifer Software. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
// unpack.c
// This module actually handles the decompression of the audio data, except
// for the entropy decoding which is handled by the words.c module. For
// maximum efficiency, the conversion is isolated to tight loops that handle
// an entire buffer.
#include "wavpack.h"
#include <string.h>
#include <math.h>
#define LOSSY_MUTE
//////////////////////////////// local macros /////////////////////////////////
#define apply_weight_i(weight, sample) ((weight * sample + 512) >> 10)
#define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \
(((sample & ~0xffff) >> 9) * weight) + 1) >> 1)
#define apply_weight(weight, sample) (sample != (short) sample ? \
apply_weight_f (weight, sample) : apply_weight_i (weight, sample))
#define update_weight(weight, delta, source, result) \
if (source && result) weight -= ((((source ^ result) >> 30) & 2) - 1) * delta;
#define update_weight_clip(weight, delta, source, result) \
if (source && result && ((source ^ result) < 0 ? (weight -= delta) < -1024 : (weight += delta) > 1024)) \
weight = weight < 0 ? -1024 : 1024;
///////////////////////////// executable code ////////////////////////////////
// This function initializes everything required to unpack a WavPack block
// and must be called before unpack_samples() is called to obtain audio data.
// It is assumed that the WavpackHeader has been read into the wps->wphdr
// (in the current WavpackStream). This is where all the metadata blocks are
// scanned up to the one containing the audio bitstream.
int unpack_init (WavpackContext *wpc)
{
WavpackStream *wps = &wpc->stream;
WavpackMetadata wpmd;
if (wps->wphdr.block_samples && wps->wphdr.block_index != (ulong) -1)
wps->sample_index = wps->wphdr.block_index;
wps->mute_error = FALSE;
wps->crc = 0xffffffff;
CLEAR (wps->wvbits);
CLEAR (wps->decorr_passes);
CLEAR (wps->w);
while (read_metadata_buff (wpc, &wpmd)) {
if (!process_metadata (wpc, &wpmd)) {
strcpy (wpc->error_message, "invalid metadata!");
return FALSE;
}
if (wpmd.id == ID_WV_BITSTREAM)
break;
}
if (wps->wphdr.block_samples && !bs_is_open (&wps->wvbits)) {
strcpy (wpc->error_message, "invalid WavPack file!");
return FALSE;
}
if (wps->wphdr.block_samples) {
if ((wps->wphdr.flags & INT32_DATA) && wps->int32_sent_bits)
wpc->lossy_blocks = TRUE;
if ((wps->wphdr.flags & FLOAT_DATA) &&
wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME))
wpc->lossy_blocks = TRUE;
}
return TRUE;
}
// This function initialzes the main bitstream for audio samples, which must
// be in the "wv" file.
int init_wv_bitstream (WavpackContext *wpc, WavpackMetadata *wpmd)
{
WavpackStream *wps = &wpc->stream;
if (wpmd->data)
bs_open_read (&wps->wvbits, wpmd->data, (char *) wpmd->data + wpmd->byte_length, NULL, 0);
else if (wpmd->byte_length)
bs_open_read (&wps->wvbits, wpc->read_buffer, wpc->read_buffer + sizeof (wpc->read_buffer),
wpc->infile, wpmd->byte_length + (wpmd->byte_length & 1));
return TRUE;
}
// Read decorrelation terms from specified metadata block into the
// decorr_passes array. The terms range from -3 to 8, plus 17 & 18;
// other values are reserved and generate errors for now. The delta
// ranges from 0 to 7 with all values valid. Note that the terms are
// stored in the opposite order in the decorr_passes array compared
// to packing.
int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd)
{
int termcnt = wpmd->byte_length;
uchar *byteptr = wpmd->data;
struct decorr_pass *dpp;
if (termcnt > MAX_NTERMS)
return FALSE;
wps->num_terms = termcnt;
for (dpp = wps->decorr_passes + termcnt - 1; termcnt--; dpp--) {
dpp->term = (int)(*byteptr & 0x1f) - 5;
dpp->delta = (*byteptr++ >> 5) & 0x7;
if (!dpp->term || dpp->term < -3 || (dpp->term > MAX_TERM && dpp->term < 17) || dpp->term > 18)
return FALSE;
}
return TRUE;
}
// Read decorrelation weights from specified metadata block into the
// decorr_passes array. The weights range +/-1024, but are rounded and
// truncated to fit in signed chars for metadata storage. Weights are
// separate for the two channels and are specified from the "last" term
// (first during encode). Unspecified weights are set to zero.
int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd)
{
int termcnt = wpmd->byte_length, tcount;
char *byteptr = wpmd->data;
struct decorr_pass *dpp;
if (!(wps->wphdr.flags & MONO_FLAG))
termcnt /= 2;
if (termcnt > wps->num_terms)
return FALSE;
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
dpp->weight_A = dpp->weight_B = 0;
while (--dpp >= wps->decorr_passes && termcnt--) {
dpp->weight_A = restore_weight (*byteptr++);
if (!(wps->wphdr.flags & MONO_FLAG))
dpp->weight_B = restore_weight (*byteptr++);
}
return TRUE;
}
// Read decorrelation samples from specified metadata block into the
// decorr_passes array. The samples are signed 32-bit values, but are
// converted to signed log2 values for storage in metadata. Values are
// stored for both channels and are specified from the "last" term
// (first during encode) with unspecified samples set to zero. The
// number of samples stored varies with the actual term value, so
// those must obviously come first in the metadata.
int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd)
{
uchar *byteptr = wpmd->data;
uchar *endptr = byteptr + wpmd->byte_length;
struct decorr_pass *dpp;
int tcount;
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
CLEAR (dpp->samples_A);
CLEAR (dpp->samples_B);
}
if (wps->wphdr.version == 0x402 && (wps->wphdr.flags & HYBRID_FLAG)) {
byteptr += 2;
if (!(wps->wphdr.flags & MONO_FLAG))
byteptr += 2;
}
while (dpp-- > wps->decorr_passes && byteptr < endptr)
if (dpp->term > MAX_TERM) {
dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8)));
dpp->samples_A [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8)));
byteptr += 4;
if (!(wps->wphdr.flags & MONO_FLAG)) {
dpp->samples_B [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8)));
dpp->samples_B [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8)));
byteptr += 4;
}
}
else if (dpp->term < 0) {
dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8)));
dpp->samples_B [0] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8)));
byteptr += 4;
}
else {
int m = 0, cnt = dpp->term;
while (cnt--) {
dpp->samples_A [m] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8)));
byteptr += 2;
if (!(wps->wphdr.flags & MONO_FLAG)) {
dpp->samples_B [m] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8)));
byteptr += 2;
}
m++;
}
}
return byteptr == endptr;
}
// Read the int32 data from the specified metadata into the specified stream.
// This data is used for integer data that has more than 24 bits of magnitude
// or, in some cases, used to eliminate redundant bits from any audio stream.
int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd)
{
int bytecnt = wpmd->byte_length;
char *byteptr = wpmd->data;
if (bytecnt != 4)
return FALSE;
wps->int32_sent_bits = *byteptr++;
wps->int32_zeros = *byteptr++;
wps->int32_ones = *byteptr++;
wps->int32_dups = *byteptr;
return TRUE;
}
// Read multichannel information from metadata. The first byte is the total
// number of channels and the following bytes represent the channel_mask
// as described for Microsoft WAVEFORMATEX.
int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd)
{
int bytecnt = wpmd->byte_length, shift = 0;
char *byteptr = wpmd->data;
ulong mask = 0;
if (!bytecnt || bytecnt > 5)
return FALSE;
wpc->config.num_channels = *byteptr++;
while (--bytecnt) {
mask |= (ulong) *byteptr++ << shift;
shift += 8;
}
wpc->config.channel_mask = mask;
return TRUE;
}
// Read configuration information from metadata.
int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd)
{
int bytecnt = wpmd->byte_length;
uchar *byteptr = wpmd->data;
if (bytecnt >= 3) {
wpc->config.flags &= 0xff;
wpc->config.flags |= (long) *byteptr++ << 8;
wpc->config.flags |= (long) *byteptr++ << 16;
wpc->config.flags |= (long) *byteptr << 24;
}
return TRUE;
}
// This monster actually unpacks the WavPack bitstream(s) into the specified
// buffer as 32-bit integers or floats (depending on orignal data). Lossy
// samples will be clipped to their original limits (i.e. 8-bit samples are
// clipped to -128/+127) but are still returned in longs. It is up to the
// caller to potentially reformat this for the final output including any
// multichannel distribution, block alignment or endian compensation. The
// function unpack_init() must have been called and the entire WavPack block
// must still be visible (although wps->blockbuff will not be accessed again).
// For maximum clarity, the function is broken up into segments that handle
// various modes. This makes for a few extra infrequent flag checks, but
// makes the code easier to follow because the nesting does not become so
// deep. For maximum efficiency, the conversion is isolated to tight loops
// that handle an entire buffer. The function returns the total number of
// samples unpacked, which can be less than the number requested if an error
// occurs or the end of the block is reached.
static void fixup_samples (WavpackStream *wps, long *buffer, ulong sample_count);
long unpack_samples (WavpackContext *wpc, long *buffer, ulong sample_count)
{
WavpackStream *wps = &wpc->stream;
ulong flags = wps->wphdr.flags, crc = wps->crc, i;
long mute_limit = (1L << ((flags & MAG_MASK) >> MAG_LSB)) + 2;
struct decorr_pass *dpp;
long read_word, *bptr;
int tcount, m = 0;
if (wps->sample_index + sample_count > wps->wphdr.block_index + wps->wphdr.block_samples)
sample_count = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index;
if (wps->mute_error) {
memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8));
wps->sample_index += sample_count;
return sample_count;
}
if (flags & HYBRID_FLAG)
mute_limit *= 2;
///////////////////// handle version 4 mono data /////////////////////////
if (flags & MONO_FLAG)
for (bptr = buffer, i = 0; i < sample_count; ++i) {
if ((read_word = get_word (wps, 0)) == WORD_EOF)
break;
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
long sam, temp;
int k;
if (dpp->term > MAX_TERM) {
if (dpp->term & 1)
sam = 2 * dpp->samples_A [0] - dpp->samples_A [1];
else
sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
dpp->samples_A [1] = dpp->samples_A [0];
k = 0;
}
else {
sam = dpp->samples_A [m];
k = (m + dpp->term) & (MAX_TERM - 1);
}
temp = apply_weight (dpp->weight_A, sam) + read_word;
update_weight (dpp->weight_A, dpp->delta, sam, read_word);
dpp->samples_A [k] = read_word = temp;
}
if (labs (read_word) > mute_limit)
break;
m = (m + 1) & (MAX_TERM - 1);
crc = crc * 3 + read_word;
*bptr++ = read_word;
}
//////////////////// handle version 4 stereo data ////////////////////////
else
for (bptr = buffer, i = 0; i < sample_count; ++i) {
long left, right, left2, right2;
if ((left = get_word (wps, 0)) == WORD_EOF ||
(right = get_word (wps, 1)) == WORD_EOF)
break;
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
if (dpp->term > 0) {
long sam_A, sam_B;
int k;
if (dpp->term > MAX_TERM) {
if (dpp->term & 1) {
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1];
}
else {
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1;
}
dpp->samples_A [1] = dpp->samples_A [0];
dpp->samples_B [1] = dpp->samples_B [0];
k = 0;
}
else {
sam_A = dpp->samples_A [m];
sam_B = dpp->samples_B [m];
k = (m + dpp->term) & (MAX_TERM - 1);
}
left2 = apply_weight (dpp->weight_A, sam_A) + left;
right2 = apply_weight (dpp->weight_B, sam_B) + right;
update_weight (dpp->weight_A, dpp->delta, sam_A, left);
update_weight (dpp->weight_B, dpp->delta, sam_B, right);
dpp->samples_A [k] = left = left2;
dpp->samples_B [k] = right = right2;
}
else if (dpp->term == -1) {
left2 = left + apply_weight (dpp->weight_A, dpp->samples_A [0]);
update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], left);
left = left2;
right2 = right + apply_weight (dpp->weight_B, left2);
update_weight_clip (dpp->weight_B, dpp->delta, left2, right);
dpp->samples_A [0] = right = right2;
}
else {
right2 = right + apply_weight (dpp->weight_B, dpp->samples_B [0]);
update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], right);
right = right2;
if (dpp->term == -3) {
right2 = dpp->samples_A [0];
dpp->samples_A [0] = right;
}
left2 = left + apply_weight (dpp->weight_A, right2);
update_weight_clip (dpp->weight_A, dpp->delta, right2, left);
dpp->samples_B [0] = left = left2;
}
m = (m + 1) & (MAX_TERM - 1);
if (flags & JOINT_STEREO)
left += (right -= (left >> 1));
if (labs (left) > mute_limit || labs (right) > mute_limit)
break;
crc = (crc * 3 + left) * 3 + right;
*bptr++ = left;
*bptr++ = right;
}
if (i != sample_count) {
memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8));
wps->mute_error = TRUE;
i = sample_count;
}
while (m--)
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
if (dpp->term > 0 && dpp->term <= MAX_TERM) {
long temp = dpp->samples_A [0];
memcpy (dpp->samples_A, dpp->samples_A + 1, sizeof (dpp->samples_A) - sizeof (dpp->samples_A [0]));
dpp->samples_A [MAX_TERM - 1] = temp;
temp = dpp->samples_B [0];
memcpy (dpp->samples_B, dpp->samples_B + 1, sizeof (dpp->samples_B) - sizeof (dpp->samples_B [0]));
dpp->samples_B [MAX_TERM - 1] = temp;
}
fixup_samples (wps, buffer, i);
if (flags & FLOAT_DATA)
float_normalize (buffer, (flags & MONO_FLAG) ? i : i * 2,
127 - wps->float_norm_exp + wpc->norm_offset);
wps->sample_index += i;
wps->crc = crc;
return i;
}
// This is a helper function for unpack_samples() that applies several final
// operations. First, if the data is 32-bit float data, then that conversion
// is done in the float.c module (whether lossy or lossless) and we return.
// Otherwise, if the extended integer data applies, then that operation is
// executed first. If the unpacked data is lossy (and not corrected) then
// it is clipped and shifted in a single operation. Otherwise, if it's
// lossless then the last step is to apply the final shift (if any).
static void fixup_samples (WavpackStream *wps, long *buffer, ulong sample_count)
{
ulong flags = wps->wphdr.flags;
int shift = (flags & SHIFT_MASK) >> SHIFT_LSB;
if (flags & FLOAT_DATA) {
float_values (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2);
return;
}
if (flags & INT32_DATA) {
ulong count = (flags & MONO_FLAG) ? sample_count : sample_count * 2;
int sent_bits = wps->int32_sent_bits, zeros = wps->int32_zeros;
int ones = wps->int32_ones, dups = wps->int32_dups;
// ulong mask = (1 << sent_bits) - 1;
long *dptr = buffer;
if (!(flags & HYBRID_FLAG) && !sent_bits && (zeros + ones + dups))
while (count--) {
if (zeros)
*dptr <<= zeros;
else if (ones)
*dptr = ((*dptr + 1) << ones) - 1;
else if (dups)
*dptr = ((*dptr + (*dptr & 1)) << dups) - (*dptr & 1);
dptr++;
}
else
shift += zeros + sent_bits + ones + dups;
}
if (flags & HYBRID_FLAG) {
long min_value, max_value, min_shifted, max_shifted;
switch (flags & BYTES_STORED) {
case 0:
min_shifted = (min_value = -128 >> shift) << shift;
max_shifted = (max_value = 127 >> shift) << shift;
break;
case 1:
min_shifted = (min_value = -32768 >> shift) << shift;
max_shifted = (max_value = 32767 >> shift) << shift;
break;
case 2:
min_shifted = (min_value = -8388608 >> shift) << shift;
max_shifted = (max_value = 8388607 >> shift) << shift;
break;
case 3:
min_shifted = (min_value = -(long)2147483648 >> shift) << shift;
max_shifted = (max_value = (long) 2147483647 >> shift) << shift;
break;
}
if (!(flags & MONO_FLAG))
sample_count *= 2;
while (sample_count--) {
if (*buffer < min_value)
*buffer++ = min_shifted;
else if (*buffer > max_value)
*buffer++ = max_shifted;
else
*buffer++ <<= shift;
}
}
else if (shift) {
if (!(flags & MONO_FLAG))
sample_count *= 2;
while (sample_count--)
*buffer++ <<= shift;
}
}
// This function checks the crc value(s) for an unpacked block, returning the
// number of actual crc errors detected for the block. The block must be
// completely unpacked before this test is valid. For losslessly unpacked
// blocks of float or extended integer data the extended crc is also checked.
// Note that WavPack's crc is not a CCITT approved polynomial algorithm, but
// is a much simpler method that is virtually as robust for real world data.
int check_crc_error (WavpackContext *wpc)
{
WavpackStream *wps = &wpc->stream;
int result = 0;
if (wps->crc != wps->wphdr.crc)
++result;
return result;
}

View file

@ -0,0 +1,330 @@
////////////////////////////////////////////////////////////////////////////
// **** WAVPACK **** //
// Hybrid Lossless Wavefile Compressor //
// Copyright (c) 1998 - 2004 Conifer Software. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
// wavpack.h
#include <sys/types.h>
// This header file contains all the definitions required by WavPack.
typedef unsigned char uchar;
#if !defined(__GNUC__) || defined(WIN32)
typedef unsigned short ushort;
typedef unsigned long ulong;
typedef unsigned int uint;
#elif defined(__APPLE__)
typedef unsigned long ulong;
#endif
// This structure is used to access the individual fields of 32-bit ieee
// floating point numbers. This will not be compatible with compilers that
// allocate bit fields from the most significant bits, although I'm not sure
// how common that is.
typedef struct {
unsigned mantissa : 23;
unsigned exponent : 8;
unsigned sign : 1;
} f32;
#include <stdio.h>
#define FALSE 0
#define TRUE 1
////////////////////////////// WavPack Header /////////////////////////////////
// Note that this is the ONLY structure that is written to (or read from)
// WavPack 4.0 files, and is the preamble to every block in both the .wv
// and .wvc files.
typedef struct {
char ckID [4];
ulong ckSize;
short version;
uchar track_no, index_no;
ulong total_samples, block_index, block_samples, flags, crc;
} WavpackHeader;
#define WavpackHeaderFormat "4LS2LLLLL"
// or-values for "flags"
#define BYTES_STORED 3 // 1-4 bytes/sample
#define MONO_FLAG 4 // not stereo
#define HYBRID_FLAG 8 // hybrid mode
#define JOINT_STEREO 0x10 // joint stereo
#define CROSS_DECORR 0x20 // no-delay cross decorrelation
#define HYBRID_SHAPE 0x40 // noise shape (hybrid mode only)
#define FLOAT_DATA 0x80 // ieee 32-bit floating point data
#define INT32_DATA 0x100 // special extended int handling
#define HYBRID_BITRATE 0x200 // bitrate noise (hybrid mode only)
#define HYBRID_BALANCE 0x400 // balance noise (hybrid stereo mode only)
#define INITIAL_BLOCK 0x800 // initial block of multichannel segment
#define FINAL_BLOCK 0x1000 // final block of multichannel segment
#define SHIFT_LSB 13
#define SHIFT_MASK (0x1fL << SHIFT_LSB)
#define MAG_LSB 18
#define MAG_MASK (0x1fL << MAG_LSB)
#define SRATE_LSB 23
#define SRATE_MASK (0xfL << SRATE_LSB)
#define IGNORED_FLAGS 0x18000000 // reserved, but ignore if encountered
#define NEW_SHAPING 0x20000000 // use IIR filter for negative shaping
#define UNKNOWN_FLAGS 0xC0000000 // also reserved, but refuse decode if
// encountered
//////////////////////////// WavPack Metadata /////////////////////////////////
// This is an internal representation of metadata.
typedef struct {
long byte_length;
void *data;
uchar id;
} WavpackMetadata;
#define ID_OPTIONAL_DATA 0x20
#define ID_ODD_SIZE 0x40
#define ID_LARGE 0x80
#define ID_DUMMY 0x0
#define ID_ENCODER_INFO 0x1
#define ID_DECORR_TERMS 0x2
#define ID_DECORR_WEIGHTS 0x3
#define ID_DECORR_SAMPLES 0x4
#define ID_ENTROPY_VARS 0x5
#define ID_HYBRID_PROFILE 0x6
#define ID_SHAPING_WEIGHTS 0x7
#define ID_FLOAT_INFO 0x8
#define ID_INT32_INFO 0x9
#define ID_WV_BITSTREAM 0xa
#define ID_WVC_BITSTREAM 0xb
#define ID_WVX_BITSTREAM 0xc
#define ID_CHANNEL_INFO 0xd
#define ID_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1)
#define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2)
#define ID_REPLAY_GAIN (ID_OPTIONAL_DATA | 0x3)
#define ID_CUESHEET (ID_OPTIONAL_DATA | 0x4)
#define ID_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0x5)
#define ID_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x6)
///////////////////////// WavPack Configuration ///////////////////////////////
// This internal structure is used during encode to provide configuration to
// the encoding engine and during decoding to provide fle information back to
// the higher level functions. Not all fields are used in both modes.
typedef struct {
int bits_per_sample, bytes_per_sample;
int qmode, flags, xmode, num_channels, float_norm_exp;
long block_samples, extra_flags, sample_rate, channel_mask;
} WavpackConfig;
#define CONFIG_BYTES_STORED 3 // 1-4 bytes/sample
#define CONFIG_MONO_FLAG 4 // not stereo
#define CONFIG_HYBRID_FLAG 8 // hybrid mode
#define CONFIG_JOINT_STEREO 0x10 // joint stereo
#define CONFIG_CROSS_DECORR 0x20 // no-delay cross decorrelation
#define CONFIG_HYBRID_SHAPE 0x40 // noise shape (hybrid mode only)
#define CONFIG_FLOAT_DATA 0x80 // ieee 32-bit floating point data
#define CONFIG_ADOBE_MODE 0x100 // "adobe" mode for 32-bit floats
#define CONFIG_FAST_FLAG 0x200 // fast mode
#define CONFIG_VERY_FAST_FLAG 0x400 // double fast
#define CONFIG_HIGH_FLAG 0x800 // high quality mode
#define CONFIG_VERY_HIGH_FLAG 0x1000 // double high (not used yet)
#define CONFIG_BITRATE_KBPS 0x2000 // bitrate is kbps, not bits / sample
#define CONFIG_AUTO_SHAPING 0x4000 // automatic noise shaping
#define CONFIG_SHAPE_OVERRIDE 0x8000 // shaping mode specified
#define CONFIG_JOINT_OVERRIDE 0x10000 // joint-stereo mode specified
#define CONFIG_COPY_TIME 0x20000 // copy file-time from source
#define CONFIG_CREATE_EXE 0x40000 // create executable (not yet)
#define CONFIG_CREATE_WVC 0x80000 // create correction file
#define CONFIG_OPTIMIZE_WVC 0x100000 // maximize bybrid compression
#define CONFIG_QUALITY_MODE 0x200000 // psychoacoustic quality mode
#define CONFIG_RAW_FLAG 0x400000 // raw mode (not implemented yet)
#define CONFIG_CALC_NOISE 0x800000 // calc noise in hybrid mode
#define CONFIG_LOSSY_MODE 0x1000000 // obsolete (for information)
#define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode
#define CONFIG_SKIP_WVX 0x4000000 // no wvx stream w/ floats & big ints
#define CONFIG_MD5_CHECKSUM 0x8000000 // compute & store MD5 signature
#define CONFIG_QUIET_MODE 0x10000000 // don't report progress %
//////////////////////////////// WavPack Stream ///////////////////////////////
// This internal structure contains everything required to handle a WavPack
// "stream", which is defined as a stereo or mono stream of audio samples. For
// multichannel audio several of these would be required. Each stream contains
// pointers to hold a complete allocated block of WavPack data, although it's
// possible to decode WavPack blocks without buffering an entire block.
typedef long (*read_stream)(void *, long);
typedef struct bs {
uchar *buf, *end, *ptr;
void (*wrap)(struct bs *bs);
ulong file_bytes, sr;
int error, bc;
read_stream file;
} Bitstream;
#define MAX_NTERMS 16
#define MAX_TERM 8
struct decorr_pass {
short term, delta, weight_A, weight_B;
long samples_A [MAX_TERM], samples_B [MAX_TERM];
};
typedef struct {
WavpackHeader wphdr;
int num_terms, mute_error;
ulong sample_index, crc;
Bitstream wvbits;
uchar int32_sent_bits, int32_zeros, int32_ones, int32_dups;
uchar float_flags, float_shift, float_max_exp, float_norm_exp;
struct decorr_pass decorr_passes [MAX_NTERMS];
struct {
ulong bitrate_delta [2], bitrate_acc [2];
ulong median [3] [2], slow_level [2], error_limit [2];
ulong pend_data, holding_one, zeros_acc;
int holding_zero, pend_count;
} w;
} WavpackStream;
// flags for float_flags:
#define FLOAT_SHIFT_ONES 1 // bits left-shifted into float = '1'
#define FLOAT_SHIFT_SAME 2 // bits left-shifted into float are the same
#define FLOAT_SHIFT_SENT 4 // bits shifted into float are sent literally
#define FLOAT_ZEROS_SENT 8 // "zeros" are not all real zeros
#define FLOAT_NEG_ZEROS 0x10 // contains negative zeros
#define FLOAT_EXCEPTIONS 0x20 // contains exceptions (inf, nan, etc.)
/////////////////////////////// WavPack Context ///////////////////////////////
// This internal structure holds everything required to encode or decode WavPack
// files. It is recommended that direct access to this structure be minimized
// and the provided utilities used instead.
typedef struct {
WavpackConfig config;
WavpackStream stream;
uchar read_buffer [1024];
char error_message [80];
read_stream infile;
ulong total_samples, crc_errors, first_flags;
int open_flags, norm_offset, reduced_channels, lossy_blocks;
} WavpackContext;
//////////////////////// function prototypes and macros //////////////////////
#define CLEAR(destin) memset (&destin, 0, sizeof (destin));
// bits.c
void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end, read_stream file, ulong file_bytes);
#define bs_is_open(bs) ((bs)->ptr != NULL)
#define getbit(bs) ( \
(((bs)->bc) ? \
((bs)->bc--, (bs)->sr & 1) : \
(((++((bs)->ptr) != (bs)->end) ? (void) 0 : (bs)->wrap (bs)), (bs)->bc = 7, ((bs)->sr = *((bs)->ptr)) & 1) \
) ? \
((bs)->sr >>= 1, 1) : \
((bs)->sr >>= 1, 0) \
)
#define getbits(value, nbits, bs) { \
while ((nbits) > (bs)->bc) { \
if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \
(bs)->sr |= (long)*((bs)->ptr) << (bs)->bc; \
(bs)->bc += 8; \
} \
*(value) = (bs)->sr; \
(bs)->sr >>= (nbits); \
(bs)->bc -= (nbits); \
}
void little_endian_to_native (void *data, char *format);
void native_to_little_endian (void *data, char *format);
// unpack.c
int unpack_init (WavpackContext *wpc);
int init_wv_bitstream (WavpackContext *wpc, 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_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);
long unpack_samples (WavpackContext *wpc, long *buffer, ulong sample_count);
int check_crc_error (WavpackContext *wpc);
// metadata.c stuff
int read_metadata_buff (WavpackContext *wpc, WavpackMetadata *wpmd);
int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd);
// words.c stuff
int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd);
int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd);
long get_word (WavpackStream *wps, int chan);
long exp2s (int log);
int restore_weight (char weight);
#define WORD_EOF (1L << 31)
// float.c
int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd);
void float_values (WavpackStream *wps, long *values, long num_values);
void float_normalize (long *values, long num_values, int delta_exp);
// wputils.c
WavpackContext *WavpackOpenFileInput (read_stream infile, char *error);
int WavpackGetMode (WavpackContext *wpc);
#define MODE_WVC 0x1
#define MODE_LOSSLESS 0x2
#define MODE_HYBRID 0x4
#define MODE_FLOAT 0x8
#define MODE_VALID_TAG 0x10
#define MODE_HIGH 0x20
#define MODE_FAST 0x40
ulong WavpackUnpackSamples (WavpackContext *wpc, long *buffer, ulong samples);
ulong WavpackGetNumSamples (WavpackContext *wpc);
ulong WavpackGetSampleIndex (WavpackContext *wpc);
int WavpackGetNumErrors (WavpackContext *wpc);
int WavpackLossyBlocks (WavpackContext *wpc);
ulong WavpackGetSampleRate (WavpackContext *wpc);
int WavpackGetBitsPerSample (WavpackContext *wpc);
int WavpackGetBytesPerSample (WavpackContext *wpc);
int WavpackGetNumChannels (WavpackContext *wpc);
int WavpackGetReducedChannels (WavpackContext *wpc);

View file

@ -0,0 +1,503 @@
////////////////////////////////////////////////////////////////////////////
// **** WAVPACK **** //
// Hybrid Lossless Wavefile Compressor //
// Copyright (c) 1998 - 2004 Conifer Software. //
// All Rights Reserved. //
////////////////////////////////////////////////////////////////////////////
// words.c
// This module provides entropy word encoding and decoding functions using
// a variation on the Rice method. This was introduced in version 3.93
// because it allows splitting the data into a "lossy" stream and a
// "correction" stream in a very efficient manner and is therefore ideal
// for the "hybrid" mode. For 4.0, the efficiency of this method was
// significantly improved by moving away from the normal Rice restriction of
// using powers of two for the modulus divisions and now the method can be
// used for both hybrid and pure lossless encoding.
// Samples are divided by median probabilities at 5/7 (71.43%), 10/49 (20.41%),
// and 20/343 (5.83%). Each zone has 3.5 times fewer samples than the
// previous. Using standard Rice coding on this data would result in 1.4
// bits per sample average (not counting sign bit). However, there is a
// very simple encoding that is over 99% efficient with this data and
// results in about 1.22 bits per sample.
#include "wavpack.h"
#include <string.h>
//////////////////////////////// local macros /////////////////////////////////
#define LIMIT_ONES 16 // maximum consecutive 1s sent for "div" data
// these control the time constant "slow_level" which is used for hybrid mode
// that controls bitrate as a function of residual level (HYBRID_BITRATE).
#define SLS 8
#define SLO ((1 << (SLS - 1)))
// these control the time constant of the 3 median level breakpoints
#define DIV0 128 // 5/7 of samples
#define DIV1 64 // 10/49 of samples
#define DIV2 32 // 20/343 of samples
// this macro retrieves the specified median breakpoint (without frac; min = 1)
#define GET_MED(med) (((wps->w.median [med] [chan]) >> 4) + 1)
// These macros update the specified median breakpoints. Note that the median
// is incremented when the sample is higher than the median, else decremented.
// They are designed so that the median will never drop below 1 and the value
// is essentially stationary if there are 2 increments for every 5 decrements.
#define INC_MED0() (wps->w.median [0] [chan] += ((wps->w.median [0] [chan] + DIV0) / DIV0) * 5)
#define DEC_MED0() (wps->w.median [0] [chan] -= ((wps->w.median [0] [chan] + (DIV0-2)) / DIV0) * 2)
#define INC_MED1() (wps->w.median [1] [chan] += ((wps->w.median [1] [chan] + DIV1) / DIV1) * 5)
#define DEC_MED1() (wps->w.median [1] [chan] -= ((wps->w.median [1] [chan] + (DIV1-2)) / DIV1) * 2)
#define INC_MED2() (wps->w.median [2] [chan] += ((wps->w.median [2] [chan] + DIV2) / DIV2) * 5)
#define DEC_MED2() (wps->w.median [2] [chan] -= ((wps->w.median [2] [chan] + (DIV2-2)) / DIV2) * 2)
#define count_bits(av) ( \
(av) < (1 << 8) ? nbits_table [av] : \
( \
(av) < (1L << 16) ? nbits_table [(av) >> 8] + 8 : \
((av) < (1L << 24) ? nbits_table [(av) >> 16] + 16 : nbits_table [(av) >> 24] + 24) \
) \
)
///////////////////////////// local table storage ////////////////////////////
const char nbits_table [] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 15
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 16 - 31
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 32 - 47
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 48 - 63
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 64 - 79
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 80 - 95
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 96 - 111
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 112 - 127
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 128 - 143
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 144 - 159
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 160 - 175
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 176 - 191
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 192 - 207
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 208 - 223
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 224 - 239
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 // 240 - 255
};
static const uchar log2_table [] = {
0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15,
0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a,
0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e,
0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85,
0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2,
0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0,
0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce,
0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb,
0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7,
0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4,
0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff
};
static const uchar exp2_table [] = {
0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b,
0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16,
0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23,
0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d,
0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a,
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4,
0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9,
0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff
};
///////////////////////////// executable code ////////////////////////////////
static int log2 (unsigned long avalue);
// Read the median log2 values from the specifed metadata structure, convert
// them back to 32-bit unsigned values and store them. If length is not
// exactly correct then we flag and return an error.
int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd)
{
uchar *byteptr = wpmd->data;
if (wpmd->byte_length != ((wps->wphdr.flags & MONO_FLAG) ? 6 : 12))
return FALSE;
wps->w.median [0] [0] = exp2s (byteptr [0] + (byteptr [1] << 8));
wps->w.median [1] [0] = exp2s (byteptr [2] + (byteptr [3] << 8));
wps->w.median [2] [0] = exp2s (byteptr [4] + (byteptr [5] << 8));
if (!(wps->wphdr.flags & MONO_FLAG)) {
wps->w.median [0] [1] = exp2s (byteptr [6] + (byteptr [7] << 8));
wps->w.median [1] [1] = exp2s (byteptr [8] + (byteptr [9] << 8));
wps->w.median [2] [1] = exp2s (byteptr [10] + (byteptr [11] << 8));
}
return TRUE;
}
// Read the hybrid related values from the specifed metadata structure, convert
// them back to their internal formats and store them. The extended profile
// stuff is not implemented yet, so return an error if we get more data than
// we know what to do with.
int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd)
{
uchar *byteptr = wpmd->data;
uchar *endptr = byteptr + wpmd->byte_length;
if (wps->wphdr.flags & HYBRID_BITRATE) {
wps->w.slow_level [0] = exp2s (byteptr [0] + (byteptr [1] << 8));
byteptr += 2;
if (!(wps->wphdr.flags & MONO_FLAG)) {
wps->w.slow_level [1] = exp2s (byteptr [0] + (byteptr [1] << 8));
byteptr += 2;
}
}
wps->w.bitrate_acc [0] = (long)(byteptr [0] + (byteptr [1] << 8)) << 16;
byteptr += 2;
if (!(wps->wphdr.flags & MONO_FLAG)) {
wps->w.bitrate_acc [1] = (long)(byteptr [0] + (byteptr [1] << 8)) << 16;
byteptr += 2;
}
if (byteptr < endptr) {
wps->w.bitrate_delta [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8)));
byteptr += 2;
if (!(wps->wphdr.flags & MONO_FLAG)) {
wps->w.bitrate_delta [1] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8)));
byteptr += 2;
}
if (byteptr < endptr)
return FALSE;
}
else
wps->w.bitrate_delta [0] = wps->w.bitrate_delta [1] = 0;
return TRUE;
}
// This function is called during both encoding and decoding of hybrid data to
// update the "error_limit" variable which determines the maximum sample error
// allowed in the main bitstream. In the HYBRID_BITRATE mode (which is the only
// currently implemented) this is calculated from the slow_level values and the
// bitrate accumulators. Note that the bitrate accumulators can be changing.
static void update_error_limit (WavpackStream *wps)
{
int bitrate_0 = (wps->w.bitrate_acc [0] += wps->w.bitrate_delta [0]) >> 16;
if (wps->wphdr.flags & MONO_FLAG) {
if (wps->wphdr.flags & HYBRID_BITRATE) {
int slow_log_0 = (wps->w.slow_level [0] + SLO) >> SLS;
if (slow_log_0 - bitrate_0 > -0x100)
wps->w.error_limit [0] = exp2s (slow_log_0 - bitrate_0 + 0x100);
else
wps->w.error_limit [0] = 0;
}
else
wps->w.error_limit [0] = exp2s (bitrate_0);
}
else {
int bitrate_1 = (wps->w.bitrate_acc [1] += wps->w.bitrate_delta [1]) >> 16;
if (wps->wphdr.flags & HYBRID_BITRATE) {
int slow_log_0 = (wps->w.slow_level [0] + SLO) >> SLS;
int slow_log_1 = (wps->w.slow_level [1] + SLO) >> SLS;
if (wps->wphdr.flags & HYBRID_BALANCE) {
int balance = (slow_log_1 - slow_log_0 + bitrate_1 + 1) >> 1;
if (balance > bitrate_0) {
bitrate_1 = bitrate_0 * 2;
bitrate_0 = 0;
}
else if (-balance > bitrate_0) {
bitrate_0 = bitrate_0 * 2;
bitrate_1 = 0;
}
else {
bitrate_1 = bitrate_0 + balance;
bitrate_0 = bitrate_0 - balance;
}
}
if (slow_log_0 - bitrate_0 > -0x100)
wps->w.error_limit [0] = exp2s (slow_log_0 - bitrate_0 + 0x100);
else
wps->w.error_limit [0] = 0;
if (slow_log_1 - bitrate_1 > -0x100)
wps->w.error_limit [1] = exp2s (slow_log_1 - bitrate_1 + 0x100);
else
wps->w.error_limit [1] = 0;
}
else {
wps->w.error_limit [0] = exp2s (bitrate_0);
wps->w.error_limit [1] = exp2s (bitrate_1);
}
}
}
static ulong read_code (Bitstream *bs, ulong 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.
long get_word (WavpackStream *wps, int chan)
{
ulong ones_count, low, mid, high;
int sign;
if (wps->w.zeros_acc) {
if (--wps->w.zeros_acc) {
wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS;
return 0;
}
}
else if (!wps->w.holding_zero && !wps->w.holding_one && !(wps->w.median [0] [0] & ~1) && !(wps->w.median [0] [1] & ~1)) {
ulong mask;
int cbits;
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
if (cbits == 33)
return WORD_EOF;
if (cbits < 2)
wps->w.zeros_acc = cbits;
else {
for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1)
if (getbit (&wps->wvbits))
wps->w.zeros_acc |= mask;
wps->w.zeros_acc |= mask;
}
if (wps->w.zeros_acc) {
wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS;
CLEAR (wps->w.median);
return 0;
}
}
if (wps->w.holding_zero)
ones_count = wps->w.holding_zero = 0;
else {
#ifdef LIMIT_ONES
for (ones_count = 0; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count);
if (ones_count == (LIMIT_ONES + 1))
return WORD_EOF;
if (ones_count == LIMIT_ONES) {
ulong 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
for (ones_count = 0; getbit (&wps->wvbits); ++ones_count);
#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 ();
}
}
}
mid = (high + low + 1) >> 1;
if (!wps->w.error_limit [chan])
mid = read_code (&wps->wvbits, high - low) + low;
else while (high - low > wps->w.error_limit [chan]) {
if (getbit (&wps->wvbits))
mid = (high + (low = mid) + 1) >> 1;
else
mid = ((high = mid - 1) + low + 1) >> 1;
}
sign = getbit (&wps->wvbits);
if (wps->wphdr.flags & HYBRID_BITRATE) {
wps->w.slow_level [chan] -= (wps->w.slow_level [chan] + SLO) >> SLS;
wps->w.slow_level [chan] += log2 (mid);
}
return sign ? ~mid : mid;
}
// 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 ulong read_code (Bitstream *bs, ulong maxcode)
{
int bitcount = count_bits (maxcode);
ulong extras = (1L << bitcount) - maxcode - 1, code;
if (!bitcount)
return 0;
getbits (&code, bitcount - 1, bs);
code &= (1L << (bitcount - 1)) - 1;
if (code >= extras) {
code = (code << 1) - extras;
if (getbit (bs))
++code;
}
return code;
}
// The concept of a base 2 logarithm is used in many parts of WavPack. It is
// a way of sufficiently accurately representing 32-bit signed and unsigned
// values storing only 16 bits (actually fewer). It is also used in the hybrid
// mode for quickly comparing the relative magnitude of large values (i.e.
// division) and providing smooth exponentials using only addition.
// These are not strict logarithms in that they become linear around zero and
// can therefore represent both zero and negative values. They have 8 bits
// of precision and in "roundtrip" conversions the total error never exceeds 1
// part in 225 except for the cases of +/-115 and +/-195 (which error by 1).
// This function returns the log2 for the specified 32-bit unsigned value.
// The maximum value allowed is about 0xff800000 and returns 8447.
static int log2 (unsigned long 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 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).
long exp2s (int log)
{
ulong value;
if (log < 0)
return -exp2s (-log);
value = exp2_table [log & 0xff] | 0x100;
if ((log >>= 8) <= 9)
return value >> (9 - log);
else
return value << (log - 9);
}
// These two functions convert internal weights (which are normally +/-1024)
// to and from an 8-bit signed character version for storage in metadata. The
// weights are clipped here in the case that they are outside that range.
int restore_weight (char weight)
{
int result;
if ((result = (int) weight << 3) > 0)
result += (result + 64) >> 7;
return result;
}

View file

@ -0,0 +1,354 @@
////////////////////////////////////////////////////////////////////////////
// **** WAVPACK **** //
// Hybrid Lossless Wavefile Compressor //
// Copyright (c) 1998 - 2004 Conifer Software. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
// wputils.c
// This module provides a high-level interface for decoding WavPack 4.0 audio
// streams and files. WavPack data is read with a stream reading callback. No
// direct seeking is provided for, but it is possible to start decoding
// anywhere in a WavPack stream. In this case, WavPack will be able to provide
// the sample-accurate position when it synchs with the data and begins
// decoding.
#include "wavpack.h"
#include <string.h>
///////////////////////////// local table storage ////////////////////////////
const ulong sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050,
24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 };
///////////////////////////// executable code ////////////////////////////////
static ulong read_next_header (read_stream infile, WavpackHeader *wphdr);
// This function reads data from the specified stream in search of a valid
// WavPack 4.0 audio block. If this fails in 1 megabyte (or an invalid or
// unsupported WavPack block is encountered) then an appropriate message is
// copied to "error" and NULL is returned, otherwise a pointer to a
// WavpackContext structure is returned (which is used to call all other
// functions in this module). This can be initiated at the beginning of a
// WavPack file, or anywhere inside a WavPack file. To determine the exact
// position within the file use WavpackGetSampleIndex(). For demonstration
// purposes this uses a single static copy of the WavpackContext structure,
// so obviously it cannot be used for more than one file at a time. Also,
// this function will not handle "correction" files, plays only the first
// two channels of multi-channel files, and is limited in resolution in some
// large integer or floating point files (but always provides at least 24 bits
// of resolution).
static WavpackContext wpc;
WavpackContext *WavpackOpenFileInput (read_stream infile, char *error)
{
WavpackStream *wps = &wpc.stream;
ulong bcount;
CLEAR (wpc);
wpc.infile = infile;
wpc.total_samples = (ulong) -1;
wpc.norm_offset = 0;
wpc.open_flags = 0;
// open the source file for reading and store the size
while (!wps->wphdr.block_samples) {
bcount = read_next_header (wpc.infile, &wps->wphdr);
if (bcount == (ulong) -1) {
strcpy (error, "not compatible with this version of WavPack file!");
return NULL;
}
if ((wps->wphdr.flags & UNKNOWN_FLAGS) || wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) {
strcpy (error, "not compatible with this version of WavPack file!");
return NULL;
}
if (wps->wphdr.block_samples && wps->wphdr.total_samples != (ulong) -1)
wpc.total_samples = wps->wphdr.total_samples;
if (!unpack_init (&wpc)) {
strcpy (error, wpc.error_message [0] ? wpc.error_message :
"not compatible with this version of WavPack file!");
return NULL;
}
}
wpc.config.flags &= ~0xff;
wpc.config.flags |= wps->wphdr.flags & 0xff;
wpc.config.bytes_per_sample = (wps->wphdr.flags & BYTES_STORED) + 1;
wpc.config.float_norm_exp = wps->float_norm_exp;
wpc.config.bits_per_sample = (wpc.config.bytes_per_sample * 8) -
((wps->wphdr.flags & SHIFT_MASK) >> SHIFT_LSB);
if (!wpc.config.sample_rate) {
if (!wps || !wps->wphdr.block_samples || (wps->wphdr.flags & SRATE_MASK) == SRATE_MASK)
wpc.config.sample_rate = 44100;
else
wpc.config.sample_rate = sample_rates [(wps->wphdr.flags & SRATE_MASK) >> SRATE_LSB];
}
if (!wpc.config.num_channels) {
wpc.config.num_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2;
wpc.config.channel_mask = 0x5 - wpc.config.num_channels;
}
if (!(wps->wphdr.flags & FINAL_BLOCK))
wpc.reduced_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2;
return &wpc;
}
// This function obtains general information about an open file and returns
// a mask with the following bit values:
// MODE_LOSSLESS: file is lossless (pure lossless only)
// MODE_HYBRID: file is hybrid mode (lossy part only)
// MODE_FLOAT: audio data is 32-bit ieee floating point
// MODE_HIGH: file was created in "high" mode (information only)
// MODE_FAST: file was created in "fast" mode (information only)
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->lossy_blocks)
mode &= ~MODE_LOSSLESS;
if (wpc->config.flags & CONFIG_FLOAT_DATA)
mode |= MODE_FLOAT;
if (wpc->config.flags & CONFIG_HIGH_FLAG)
mode |= MODE_HIGH;
if (wpc->config.flags & CONFIG_FAST_FLAG)
mode |= MODE_FAST;
}
return mode;
}
// 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. 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 is normalized to +/-1.0). 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.
ulong WavpackUnpackSamples (WavpackContext *wpc, long *buffer, ulong samples)
{
WavpackStream *wps = &wpc->stream;
ulong bcount, samples_unpacked = 0, samples_to_unpack;
int num_channels = wpc->config.num_channels;
while (samples) {
if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) ||
wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples) {
bcount = read_next_header (wpc->infile, &wps->wphdr);
if (bcount == (ulong) -1)
break;
if (wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) {
strcpy (wpc->error_message, "not compatible with this version of WavPack file!");
break;
}
if (!wps->wphdr.block_samples || wps->sample_index == wps->wphdr.block_index)
if (!unpack_init (wpc))
break;
}
if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) ||
wps->sample_index >= wps->wphdr.block_index + wps->wphdr.block_samples)
continue;
if (wps->sample_index < wps->wphdr.block_index) {
samples_to_unpack = wps->wphdr.block_index - wps->sample_index;
if (samples_to_unpack > samples)
samples_to_unpack = samples;
wps->sample_index += samples_to_unpack;
samples_unpacked += samples_to_unpack;
samples -= samples_to_unpack;
if (wpc->reduced_channels)
samples_to_unpack *= wpc->reduced_channels;
else
samples_to_unpack *= num_channels;
while (samples_to_unpack--)
*buffer++ = 0;
continue;
}
samples_to_unpack = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index;
if (samples_to_unpack > samples)
samples_to_unpack = samples;
unpack_samples (wpc, buffer, samples_to_unpack);
if (wpc->reduced_channels)
buffer += samples_to_unpack * wpc->reduced_channels;
else
buffer += samples_to_unpack * num_channels;
samples_unpacked += samples_to_unpack;
samples -= samples_to_unpack;
if (wps->sample_index == wps->wphdr.block_index + wps->wphdr.block_samples) {
if (check_crc_error (wpc))
wpc->crc_errors++;
}
if (wps->sample_index == wpc->total_samples)
break;
}
return samples_unpacked;
}
// Get total number of samples contained in the WavPack file, or -1 if unknown
ulong WavpackGetNumSamples (WavpackContext *wpc)
{
return wpc ? wpc->total_samples : (ulong) -1;
}
// Get the current sample index position, or -1 if unknown
ulong WavpackGetSampleIndex (WavpackContext *wpc)
{
if (wpc)
return wpc->stream.sample_index;
return (ulong) -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;
}
// Returns the sample rate of the specified WavPack file
ulong WavpackGetSampleRate (WavpackContext *wpc)
{
return wpc ? wpc->config.sample_rate : 44100;
}
// Returns the number of channels of the specified WavPack file. Note that
// this is the actual number of channels contained in the file, but this
// version can only decode the first two.
int WavpackGetNumChannels (WavpackContext *wpc)
{
return wpc ? wpc->config.num_channels : 2;
}
// 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 longs, 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;
}
// 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 multi-channel file.
int WavpackGetReducedChannels (WavpackContext *wpc)
{
if (wpc)
return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels;
else
return 2;
}
// Read from current file position until a valid 32-byte WavPack 4.0 header is
// found and read into the specified pointer. The number of bytes skipped is
// returned. If no WavPack header is found within 1 meg, then a -1 is returned
// to indicate the error. No additional bytes are read past the header and it
// is returned in the processor's native endian mode. Seeking is not required.
static ulong read_next_header (read_stream infile, WavpackHeader *wphdr)
{
char buffer [sizeof (*wphdr)], *sp = buffer + sizeof (*wphdr), *ep = sp;
ulong bytes_skipped = 0;
int bleft;
while (1) {
if (sp < ep) {
bleft = ep - sp;
memcpy (buffer, sp, bleft);
}
else
bleft = 0;
if (infile (buffer + bleft, sizeof (*wphdr) - bleft) != (long) sizeof (*wphdr) - bleft)
return -1;
sp = buffer;
if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' &&
!(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 && sp [4] >= 2 && sp [4] <= 0xf) {
memcpy (wphdr, buffer, sizeof (*wphdr));
little_endian_to_native (wphdr, WavpackHeaderFormat);
return bytes_skipped;
}
while (sp < ep && *sp != 'w')
sp++;
if ((bytes_skipped += sp - buffer) > 1024 * 1024)
return -1;
}
}