forked from len0rd/rockbox
Added lossless encoding to WavPack library. Also made a few changes to
decoding stuff in preparation for future optimization and eliminated all tabs. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7009 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
1d5f07b0a6
commit
dacbc16d5b
9 changed files with 2034 additions and 977 deletions
|
@ -2,6 +2,7 @@ bits.c
|
||||||
float.c
|
float.c
|
||||||
metadata.c
|
metadata.c
|
||||||
unpack.c
|
unpack.c
|
||||||
|
pack.c
|
||||||
words.c
|
words.c
|
||||||
wputils.c
|
wputils.c
|
||||||
#if CONFIG_CPU==MCF5249 && !defined(SIMULATOR)
|
#if CONFIG_CPU==MCF5249 && !defined(SIMULATOR)
|
||||||
|
|
|
@ -74,6 +74,45 @@ static void bs_read (Bitstream *bs)
|
||||||
bs->ptr = bs->buf;
|
bs->ptr = bs->buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open the specified BitStream using the specified buffer pointers. It is
|
||||||
|
// assumed that enough buffer space has been allocated for all data that will
|
||||||
|
// be written, otherwise an error will be generated.
|
||||||
|
|
||||||
|
static void bs_write (Bitstream *bs);
|
||||||
|
|
||||||
|
void bs_open_write (Bitstream *bs, uchar *buffer_start, uchar *buffer_end)
|
||||||
|
{
|
||||||
|
bs->error = bs->sr = bs->bc = 0;
|
||||||
|
bs->ptr = bs->buf = buffer_start;
|
||||||
|
bs->end = buffer_end;
|
||||||
|
bs->wrap = bs_write;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is only called from the putbit() and putbits() macros when
|
||||||
|
// the buffer is full, which is now flagged as an error.
|
||||||
|
|
||||||
|
static void bs_write (Bitstream *bs)
|
||||||
|
{
|
||||||
|
bs->ptr = bs->buf;
|
||||||
|
bs->error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function forces a flushing write of the specified BitStream, and
|
||||||
|
// returns the total number of bytes written into the buffer.
|
||||||
|
|
||||||
|
ulong bs_close_write (Bitstream *bs)
|
||||||
|
{
|
||||||
|
ulong bytes_written;
|
||||||
|
|
||||||
|
if (bs->error)
|
||||||
|
return (ulong) -1;
|
||||||
|
|
||||||
|
while (bs->bc || ((bs->ptr - bs->buf) & 1)) putbit_1 (bs);
|
||||||
|
bytes_written = bs->ptr - bs->buf;
|
||||||
|
CLEAR (*bs);
|
||||||
|
return bytes_written;
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////// Endian Correction Routines ////////////////////////////
|
/////////////////////// Endian Correction Routines ////////////////////////////
|
||||||
|
|
||||||
void little_endian_to_native (void *data, char *format)
|
void little_endian_to_native (void *data, char *format)
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include "wavpack.h"
|
#include "wavpack.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
int read_metadata_buff (WavpackContext *wpc, WavpackMetadata *wpmd)
|
int read_metadata_buff (WavpackContext *wpc, WavpackMetadata *wpmd)
|
||||||
{
|
{
|
||||||
uchar tchar;
|
uchar tchar;
|
||||||
|
@ -103,3 +105,47 @@ int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd)
|
||||||
return (wpmd->id & ID_OPTIONAL_DATA) ? TRUE : FALSE;
|
return (wpmd->id & ID_OPTIONAL_DATA) ? TRUE : FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int copy_metadata (WavpackMetadata *wpmd, uchar *buffer_start, uchar *buffer_end)
|
||||||
|
{
|
||||||
|
ulong 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_metadata (WavpackMetadata *wpmd)
|
||||||
|
{
|
||||||
|
wpmd->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
450
apps/codecs/libwavpack/pack.c
Normal file
450
apps/codecs/libwavpack/pack.c
Normal file
|
@ -0,0 +1,450 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// **** WAVPACK **** //
|
||||||
|
// Hybrid Lossless Wavefile Compressor //
|
||||||
|
// Copyright (c) 1998 - 2005 Conifer Software. //
|
||||||
|
// All Rights Reserved. //
|
||||||
|
// Distributed under the BSD Software License (see license.txt) //
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// pack.c
|
||||||
|
|
||||||
|
// This module actually handles the compression of the audio data, except for
|
||||||
|
// the entropy coding which is handled by the words? modules. For efficiency,
|
||||||
|
// the conversion is isolated to tight loops that handle an entire buffer.
|
||||||
|
|
||||||
|
#include "wavpack.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// This flag provides faster encoding speed at the expense of more code. The
|
||||||
|
// improvement applies to 16-bit stereo lossless only.
|
||||||
|
|
||||||
|
//////////////////////////////// local tables ///////////////////////////////
|
||||||
|
|
||||||
|
// These two tables specify the characteristics of the decorrelation filters.
|
||||||
|
// Each term represents one layer of the sequential filter, where positive
|
||||||
|
// values indicate the relative sample involved from the same channel (1=prev),
|
||||||
|
// 17 & 18 are special functions using the previous 2 samples, and negative
|
||||||
|
// values indicate cross channel decorrelation (in stereo only).
|
||||||
|
|
||||||
|
static const char default_terms [] = { 18,18,2,3,-2,0 };
|
||||||
|
static const char high_terms [] = { 18,18,2,3,-2,18,2,4,7,5,3,6,8,-1,18,2,0 };
|
||||||
|
static const char fast_terms [] = { 17,17,0 };
|
||||||
|
|
||||||
|
///////////////////////////// executable code ////////////////////////////////
|
||||||
|
|
||||||
|
// This function initializes everything required to pack WavPack bitstreams
|
||||||
|
// and must be called BEFORE any other function in this module.
|
||||||
|
|
||||||
|
void pack_init (WavpackContext *wpc)
|
||||||
|
{
|
||||||
|
WavpackStream *wps = &wpc->stream;
|
||||||
|
ulong flags = wps->wphdr.flags;
|
||||||
|
struct decorr_pass *dpp;
|
||||||
|
const char *term_string;
|
||||||
|
int ti;
|
||||||
|
|
||||||
|
wps->sample_index = 0;
|
||||||
|
CLEAR (wps->decorr_passes);
|
||||||
|
|
||||||
|
if (wpc->config.flags & CONFIG_HIGH_FLAG)
|
||||||
|
term_string = high_terms;
|
||||||
|
else if (wpc->config.flags & CONFIG_FAST_FLAG)
|
||||||
|
term_string = fast_terms;
|
||||||
|
else
|
||||||
|
term_string = default_terms;
|
||||||
|
|
||||||
|
for (dpp = wps->decorr_passes, ti = 0; term_string [ti]; ti++)
|
||||||
|
if (term_string [ti] >= 0 || (flags & CROSS_DECORR)) {
|
||||||
|
dpp->term = term_string [ti];
|
||||||
|
dpp++->delta = 2;
|
||||||
|
}
|
||||||
|
else if (!(flags & MONO_FLAG)) {
|
||||||
|
dpp->term = -3;
|
||||||
|
dpp++->delta = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
wps->num_terms = dpp - wps->decorr_passes;
|
||||||
|
init_words (wps);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate room for and copy the decorrelation terms from the decorr_passes
|
||||||
|
// array into the specified metadata structure. Both the actual term id and
|
||||||
|
// the delta are packed into single characters.
|
||||||
|
|
||||||
|
static void write_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||||
|
{
|
||||||
|
int tcount = wps->num_terms;
|
||||||
|
struct decorr_pass *dpp;
|
||||||
|
char *byteptr;
|
||||||
|
|
||||||
|
byteptr = wpmd->data = wpmd->temp_data;
|
||||||
|
wpmd->id = ID_DECORR_TERMS;
|
||||||
|
|
||||||
|
for (dpp = wps->decorr_passes; tcount--; ++dpp)
|
||||||
|
*byteptr++ = ((dpp->term + 5) & 0x1f) | ((dpp->delta << 5) & 0xe0);
|
||||||
|
|
||||||
|
wpmd->byte_length = byteptr - (char *) wpmd->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate room for and copy the decorrelation term weights from the
|
||||||
|
// decorr_passes array into the specified metadata structure. The weights
|
||||||
|
// range +/-1024, but are rounded and truncated to fit in signed chars for
|
||||||
|
// metadata storage. Weights are separate for the two channels
|
||||||
|
|
||||||
|
static void write_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||||
|
{
|
||||||
|
int tcount = wps->num_terms;
|
||||||
|
struct decorr_pass *dpp;
|
||||||
|
char *byteptr;
|
||||||
|
|
||||||
|
byteptr = wpmd->data = wpmd->temp_data;
|
||||||
|
wpmd->id = ID_DECORR_WEIGHTS;
|
||||||
|
|
||||||
|
for (dpp = wps->decorr_passes; tcount--; ++dpp) {
|
||||||
|
dpp->weight_A = restore_weight (*byteptr++ = store_weight (dpp->weight_A));
|
||||||
|
|
||||||
|
if (!(wps->wphdr.flags & MONO_FLAG))
|
||||||
|
dpp->weight_B = restore_weight (*byteptr++ = store_weight (dpp->weight_B));
|
||||||
|
}
|
||||||
|
|
||||||
|
wpmd->byte_length = byteptr - (char *) wpmd->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate room for and copy the decorrelation samples from the decorr_passes
|
||||||
|
// array into the specified metadata structure. The samples are signed 32-bit
|
||||||
|
// values, but are converted to signed log2 values for storage in metadata.
|
||||||
|
// Values are stored for both channels and are specified from the first term
|
||||||
|
// with unspecified samples set to zero. The number of samples stored varies
|
||||||
|
// with the actual term value, so those must obviously be specified before
|
||||||
|
// these in the metadata list. Any number of terms can have their samples
|
||||||
|
// specified from no terms to all the terms, however I have found that
|
||||||
|
// sending more than the first term's samples is a waste. The "wcount"
|
||||||
|
// variable can be set to the number of terms to have their samples stored.
|
||||||
|
|
||||||
|
static void write_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||||
|
{
|
||||||
|
int tcount = wps->num_terms, wcount = 1, temp;
|
||||||
|
struct decorr_pass *dpp;
|
||||||
|
uchar *byteptr;
|
||||||
|
|
||||||
|
byteptr = wpmd->data = wpmd->temp_data;
|
||||||
|
wpmd->id = ID_DECORR_SAMPLES;
|
||||||
|
|
||||||
|
for (dpp = wps->decorr_passes; tcount--; ++dpp)
|
||||||
|
if (wcount) {
|
||||||
|
if (dpp->term > MAX_TERM) {
|
||||||
|
dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0]));
|
||||||
|
*byteptr++ = temp;
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
dpp->samples_A [1] = exp2s (temp = log2s (dpp->samples_A [1]));
|
||||||
|
*byteptr++ = temp;
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
|
||||||
|
if (!(wps->wphdr.flags & MONO_FLAG)) {
|
||||||
|
dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0]));
|
||||||
|
*byteptr++ = temp;
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
dpp->samples_B [1] = exp2s (temp = log2s (dpp->samples_B [1]));
|
||||||
|
*byteptr++ = temp;
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dpp->term < 0) {
|
||||||
|
dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0]));
|
||||||
|
*byteptr++ = temp;
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0]));
|
||||||
|
*byteptr++ = temp;
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int m = 0, cnt = dpp->term;
|
||||||
|
|
||||||
|
while (cnt--) {
|
||||||
|
dpp->samples_A [m] = exp2s (temp = log2s (dpp->samples_A [m]));
|
||||||
|
*byteptr++ = temp;
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
|
||||||
|
if (!(wps->wphdr.flags & MONO_FLAG)) {
|
||||||
|
dpp->samples_B [m] = exp2s (temp = log2s (dpp->samples_B [m]));
|
||||||
|
*byteptr++ = temp;
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wcount--;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CLEAR (dpp->samples_A);
|
||||||
|
CLEAR (dpp->samples_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
wpmd->byte_length = byteptr - (uchar *) wpmd->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate room for and copy the configuration information into the specified
|
||||||
|
// metadata structure. Currently, we just store the upper 3 bytes of
|
||||||
|
// config.flags and only in the first block of audio data. Note that this is
|
||||||
|
// for informational purposes not required for playback or decoding (like
|
||||||
|
// whether high or fast mode was specified).
|
||||||
|
|
||||||
|
static void write_config_info (WavpackContext *wpc, WavpackMetadata *wpmd)
|
||||||
|
{
|
||||||
|
char *byteptr;
|
||||||
|
|
||||||
|
byteptr = wpmd->data = wpmd->temp_data;
|
||||||
|
wpmd->id = ID_CONFIG_BLOCK;
|
||||||
|
*byteptr++ = (char) (wpc->config.flags >> 8);
|
||||||
|
*byteptr++ = (char) (wpc->config.flags >> 16);
|
||||||
|
*byteptr++ = (char) (wpc->config.flags >> 24);
|
||||||
|
wpmd->byte_length = byteptr - (char *) wpmd->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pack an entire block of samples (either mono or stereo) into a completed
|
||||||
|
// WavPack block. This function is actually a shell for pack_samples() and
|
||||||
|
// performs tasks like handling any shift required by the format, preprocessing
|
||||||
|
// of floating point data or integer data over 24 bits wide, and implementing
|
||||||
|
// the "extra" mode (via the extra?.c modules). It is assumed that there is
|
||||||
|
// sufficient space for the completed block at "wps->blockbuff" and that
|
||||||
|
// "wps->blockend" points to the end of the available space. A return value of
|
||||||
|
// FALSE indicates an error.
|
||||||
|
|
||||||
|
static int pack_samples (WavpackContext *wpc, long *buffer);
|
||||||
|
|
||||||
|
int pack_block (WavpackContext *wpc, long *buffer)
|
||||||
|
{
|
||||||
|
WavpackStream *wps = &wpc->stream;
|
||||||
|
ulong flags = wps->wphdr.flags, sflags = wps->wphdr.flags;
|
||||||
|
ulong sample_count = wps->wphdr.block_samples;
|
||||||
|
|
||||||
|
if (flags & SHIFT_MASK) {
|
||||||
|
int shift = (flags & SHIFT_MASK) >> SHIFT_LSB;
|
||||||
|
int mag = (flags & MAG_MASK) >> MAG_LSB;
|
||||||
|
ulong cnt = sample_count;
|
||||||
|
long *ptr = buffer;
|
||||||
|
|
||||||
|
if (flags & MONO_FLAG)
|
||||||
|
while (cnt--)
|
||||||
|
*ptr++ >>= shift;
|
||||||
|
else
|
||||||
|
while (cnt--) {
|
||||||
|
*ptr++ >>= shift;
|
||||||
|
*ptr++ >>= shift;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mag -= shift) < 0)
|
||||||
|
flags &= ~MAG_MASK;
|
||||||
|
else
|
||||||
|
flags -= (1 << MAG_LSB) * shift;
|
||||||
|
|
||||||
|
wps->wphdr.flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pack_samples (wpc, buffer)) {
|
||||||
|
wps->wphdr.flags = sflags;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wps->wphdr.flags = sflags;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 pack_samples (WavpackContext *wpc, long *buffer)
|
||||||
|
{
|
||||||
|
WavpackStream *wps = &wpc->stream;
|
||||||
|
ulong sample_count = wps->wphdr.block_samples;
|
||||||
|
ulong flags = wps->wphdr.flags, data_count;
|
||||||
|
struct decorr_pass *dpp;
|
||||||
|
WavpackMetadata wpmd;
|
||||||
|
int tcount, m = 0;
|
||||||
|
ulong crc, i;
|
||||||
|
long *bptr;
|
||||||
|
|
||||||
|
crc = 0xffffffff;
|
||||||
|
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||||
|
memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader));
|
||||||
|
|
||||||
|
if (wpc->wrapper_bytes) {
|
||||||
|
wpmd.id = ID_RIFF_HEADER;
|
||||||
|
wpmd.byte_length = wpc->wrapper_bytes;
|
||||||
|
wpmd.data = wpc->wrapper_data;
|
||||||
|
copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
|
||||||
|
free_metadata (&wpmd);
|
||||||
|
wpc->wrapper_data = NULL;
|
||||||
|
wpc->wrapper_bytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sample_count)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
write_decorr_terms (wps, &wpmd);
|
||||||
|
copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
|
||||||
|
free_metadata (&wpmd);
|
||||||
|
|
||||||
|
write_decorr_weights (wps, &wpmd);
|
||||||
|
copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
|
||||||
|
free_metadata (&wpmd);
|
||||||
|
|
||||||
|
write_decorr_samples (wps, &wpmd);
|
||||||
|
copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
|
||||||
|
free_metadata (&wpmd);
|
||||||
|
|
||||||
|
write_entropy_vars (wps, &wpmd);
|
||||||
|
copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
|
||||||
|
free_metadata (&wpmd);
|
||||||
|
|
||||||
|
if ((flags & INITIAL_BLOCK) && !wps->sample_index) {
|
||||||
|
write_config_info (wpc, &wpmd);
|
||||||
|
copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
|
||||||
|
free_metadata (&wpmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
bs_open_write (&wps->wvbits, wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12, wps->blockend);
|
||||||
|
|
||||||
|
/////////////////////// handle lossless mono mode /////////////////////////
|
||||||
|
|
||||||
|
if (!(flags & HYBRID_FLAG) && (flags & MONO_FLAG))
|
||||||
|
for (bptr = buffer, i = 0; i < sample_count; ++i) {
|
||||||
|
long code;
|
||||||
|
|
||||||
|
crc = crc * 3 + (code = *bptr++);
|
||||||
|
|
||||||
|
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
|
||||||
|
long sam;
|
||||||
|
|
||||||
|
if (dpp->term > MAX_TERM) {
|
||||||
|
if (dpp->term & 1)
|
||||||
|
sam = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||||
|
else
|
||||||
|
sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||||
|
|
||||||
|
dpp->samples_A [1] = dpp->samples_A [0];
|
||||||
|
dpp->samples_A [0] = code;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sam = dpp->samples_A [m];
|
||||||
|
dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
code -= apply_weight_i (dpp->weight_A, sam);
|
||||||
|
update_weight (dpp->weight_A, 2, sam, code);
|
||||||
|
}
|
||||||
|
|
||||||
|
m = (m + 1) & (MAX_TERM - 1);
|
||||||
|
send_word_lossless (wps, code, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////// handle the lossless stereo mode //////////////////////
|
||||||
|
|
||||||
|
else if (!(flags & HYBRID_FLAG) && !(flags & MONO_FLAG))
|
||||||
|
for (bptr = buffer, i = 0; i < sample_count; ++i, bptr += 2) {
|
||||||
|
long left, right, sam_A, sam_B;
|
||||||
|
|
||||||
|
crc = crc * 3 + (left = bptr [0]);
|
||||||
|
crc = crc * 3 + (right = bptr [1]);
|
||||||
|
|
||||||
|
if (flags & JOINT_STEREO)
|
||||||
|
right += ((left -= right) >> 1);
|
||||||
|
|
||||||
|
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) {
|
||||||
|
if (dpp->term > 0) {
|
||||||
|
if (dpp->term > MAX_TERM) {
|
||||||
|
if (dpp->term & 1) {
|
||||||
|
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
|
||||||
|
sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
|
||||||
|
sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dpp->samples_A [1] = dpp->samples_A [0];
|
||||||
|
dpp->samples_B [1] = dpp->samples_B [0];
|
||||||
|
dpp->samples_A [0] = left;
|
||||||
|
dpp->samples_B [0] = right;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int k = (m + dpp->term) & (MAX_TERM - 1);
|
||||||
|
|
||||||
|
sam_A = dpp->samples_A [m];
|
||||||
|
sam_B = dpp->samples_B [m];
|
||||||
|
dpp->samples_A [k] = left;
|
||||||
|
dpp->samples_B [k] = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
left -= apply_weight_i (dpp->weight_A, sam_A);
|
||||||
|
right -= apply_weight_i (dpp->weight_B, sam_B);
|
||||||
|
update_weight (dpp->weight_A, 2, sam_A, left);
|
||||||
|
update_weight (dpp->weight_B, 2, sam_B, right);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sam_A = (dpp->term == -2) ? right : dpp->samples_A [0];
|
||||||
|
sam_B = (dpp->term == -1) ? left : dpp->samples_B [0];
|
||||||
|
dpp->samples_A [0] = right;
|
||||||
|
dpp->samples_B [0] = left;
|
||||||
|
left -= apply_weight_i (dpp->weight_A, sam_A);
|
||||||
|
right -= apply_weight_i (dpp->weight_B, sam_B);
|
||||||
|
update_weight_clip (dpp->weight_A, 2, sam_A, left);
|
||||||
|
update_weight_clip (dpp->weight_B, 2, sam_B, right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m = (m + 1) & (MAX_TERM - 1);
|
||||||
|
send_word_lossless (wps, left, 0);
|
||||||
|
send_word_lossless (wps, right, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m)
|
||||||
|
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
||||||
|
if (dpp->term > 0 && dpp->term <= MAX_TERM) {
|
||||||
|
long 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
flush_word (wps);
|
||||||
|
data_count = bs_close_write (&wps->wvbits);
|
||||||
|
|
||||||
|
if (data_count) {
|
||||||
|
if (data_count != (ulong) -1) {
|
||||||
|
uchar *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8;
|
||||||
|
|
||||||
|
*cptr++ = ID_WV_BITSTREAM | ID_LARGE;
|
||||||
|
*cptr++ = data_count >> 1;
|
||||||
|
*cptr++ = data_count >> 9;
|
||||||
|
*cptr++ = data_count >> 17;
|
||||||
|
((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
((WavpackHeader *) wps->blockbuff)->crc = crc;
|
||||||
|
|
||||||
|
wps->sample_index += sample_count;
|
||||||
|
return TRUE;
|
||||||
|
}
|
|
@ -15,46 +15,13 @@
|
||||||
|
|
||||||
#include "wavpack.h"
|
#include "wavpack.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
static void strcpy_loc (char *dst, char *src) { while (*src) *dst++ = *src++; *dst = 0; }
|
static void strcpy_loc (char *dst, char *src) { while ((*dst++ = *src++) != 0); }
|
||||||
|
|
||||||
#define LOSSY_MUTE
|
#define LOSSY_MUTE
|
||||||
|
|
||||||
//////////////////////////////// local macros /////////////////////////////////
|
|
||||||
|
|
||||||
// these macros implement the weight application and update operations
|
|
||||||
// that are at the heart of the decorrelation loops
|
|
||||||
|
|
||||||
#if 0 // PERFCOND
|
|
||||||
#define apply_weight_i(weight, sample) ((weight * sample + 512) >> 10)
|
|
||||||
#else
|
|
||||||
#define apply_weight_i(weight, sample) ((((weight * sample) >> 8) + 2) >> 2)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \
|
|
||||||
(((sample & ~0xffff) >> 9) * weight) + 1) >> 1)
|
|
||||||
|
|
||||||
#if 1 // PERFCOND
|
|
||||||
#define apply_weight(weight, sample) (sample != (short) sample ? \
|
|
||||||
apply_weight_f (weight, sample) : apply_weight_i (weight, sample))
|
|
||||||
#else
|
|
||||||
#define apply_weight(weight, sample) ((int32_t)((weight * (int64_t) sample + 512) >> 10))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if 0 // PERFCOND
|
|
||||||
#define update_weight(weight, delta, source, result) \
|
|
||||||
if (source && result) weight -= ((((source ^ result) >> 30) & 2) - 1) * delta;
|
|
||||||
#else
|
|
||||||
#define update_weight(weight, delta, source, result) \
|
|
||||||
if (source && result) (source ^ result) < 0 ? (weight -= delta) : (weight += delta);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define update_weight_clip(weight, delta, source, result) \
|
|
||||||
if (source && result && ((source ^ result) < 0 ? (weight -= delta) < -1024 : (weight += delta) > 1024)) \
|
|
||||||
weight = weight < 0 ? -1024 : 1024;
|
|
||||||
|
|
||||||
///////////////////////////// executable code ////////////////////////////////
|
///////////////////////////// executable code ////////////////////////////////
|
||||||
|
|
||||||
// This function initializes everything required to unpack a WavPack block
|
// This function initializes everything required to unpack a WavPack block
|
||||||
|
@ -354,7 +321,7 @@ long unpack_samples (WavpackContext *wpc, long *buffer, ulong sample_count)
|
||||||
|
|
||||||
if (flags & MONO_FLAG) {
|
if (flags & MONO_FLAG) {
|
||||||
eptr = buffer + sample_count;
|
eptr = buffer + sample_count;
|
||||||
i = get_words (wps, 1, sample_count, buffer);
|
i = get_words (buffer, sample_count, flags, &wps->w, &wps->wvbits);
|
||||||
|
|
||||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
||||||
decorr_mono_pass (dpp, buffer, sample_count);
|
decorr_mono_pass (dpp, buffer, sample_count);
|
||||||
|
@ -373,7 +340,7 @@ long unpack_samples (WavpackContext *wpc, long *buffer, ulong sample_count)
|
||||||
|
|
||||||
else {
|
else {
|
||||||
eptr = buffer + (sample_count * 2);
|
eptr = buffer + (sample_count * 2);
|
||||||
i = get_words (wps, 2, sample_count, buffer);
|
i = get_words (buffer, sample_count, flags, &wps->w, &wps->wvbits);
|
||||||
|
|
||||||
if (sample_count < 16)
|
if (sample_count < 16)
|
||||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
|
|
||||||
// This header file contains all the definitions required by WavPack.
|
// This header file contains all the definitions required by WavPack.
|
||||||
|
|
||||||
// not sure about them.. testing will bring more light into it..
|
|
||||||
typedef unsigned char uchar;
|
typedef unsigned char uchar;
|
||||||
typedef unsigned short ushort;
|
typedef unsigned short ushort;
|
||||||
typedef unsigned long ulong;
|
typedef unsigned long ulong;
|
||||||
|
@ -88,6 +87,7 @@ typedef struct {
|
||||||
// This is an internal representation of metadata.
|
// This is an internal representation of metadata.
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
uchar temp_data [64];
|
||||||
long byte_length;
|
long byte_length;
|
||||||
void *data;
|
void *data;
|
||||||
uchar id;
|
uchar id;
|
||||||
|
@ -127,8 +127,8 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int bits_per_sample, bytes_per_sample;
|
int bits_per_sample, bytes_per_sample;
|
||||||
int qmode, flags, xmode, num_channels, float_norm_exp;
|
int flags, num_channels, float_norm_exp;
|
||||||
long block_samples, extra_flags, sample_rate, channel_mask;
|
ulong sample_rate, channel_mask;
|
||||||
} WavpackConfig;
|
} WavpackConfig;
|
||||||
|
|
||||||
#define CONFIG_BYTES_STORED 3 // 1-4 bytes/sample
|
#define CONFIG_BYTES_STORED 3 // 1-4 bytes/sample
|
||||||
|
@ -191,22 +191,25 @@ struct entropy_data {
|
||||||
ulong median [3], slow_level, error_limit;
|
ulong median [3], slow_level, error_limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
struct words_data {
|
||||||
WavpackHeader wphdr;
|
|
||||||
Bitstream wvbits;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
ulong bitrate_delta [2], bitrate_acc [2];
|
ulong bitrate_delta [2], bitrate_acc [2];
|
||||||
ulong pend_data, holding_one, zeros_acc;
|
ulong pend_data, holding_one, zeros_acc;
|
||||||
int holding_zero, pend_count;
|
int holding_zero, pend_count;
|
||||||
struct entropy_data c [2];
|
struct entropy_data c [2];
|
||||||
} w;
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
WavpackHeader wphdr;
|
||||||
|
Bitstream wvbits;
|
||||||
|
|
||||||
|
struct words_data w;
|
||||||
|
|
||||||
int num_terms, mute_error;
|
int num_terms, mute_error;
|
||||||
ulong sample_index, crc;
|
ulong sample_index, crc;
|
||||||
|
|
||||||
uchar int32_sent_bits, int32_zeros, int32_ones, int32_dups;
|
uchar int32_sent_bits, int32_zeros, int32_ones, int32_dups;
|
||||||
uchar float_flags, float_shift, float_max_exp, float_norm_exp;
|
uchar float_flags, float_shift, float_max_exp, float_norm_exp;
|
||||||
|
uchar *blockbuff, *blockend;
|
||||||
|
|
||||||
struct decorr_pass decorr_passes [MAX_NTERMS];
|
struct decorr_pass decorr_passes [MAX_NTERMS];
|
||||||
|
|
||||||
|
@ -231,6 +234,13 @@ typedef struct {
|
||||||
WavpackStream stream;
|
WavpackStream stream;
|
||||||
WavpackConfig config;
|
WavpackConfig config;
|
||||||
|
|
||||||
|
WavpackMetadata *metadata;
|
||||||
|
ulong metabytes;
|
||||||
|
int metacount;
|
||||||
|
|
||||||
|
uchar *wrapper_data;
|
||||||
|
int wrapper_bytes;
|
||||||
|
|
||||||
uchar read_buffer [1024];
|
uchar read_buffer [1024];
|
||||||
char error_message [80];
|
char error_message [80];
|
||||||
|
|
||||||
|
@ -247,6 +257,8 @@ typedef struct {
|
||||||
// bits.c
|
// bits.c
|
||||||
|
|
||||||
void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end, read_stream file, ulong file_bytes);
|
void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end, read_stream file, ulong file_bytes);
|
||||||
|
void bs_open_write (Bitstream *bs, uchar *buffer_start, uchar *buffer_end);
|
||||||
|
ulong bs_close_write (Bitstream *bs);
|
||||||
|
|
||||||
#define bs_is_open(bs) ((bs)->ptr != NULL)
|
#define bs_is_open(bs) ((bs)->ptr != NULL)
|
||||||
|
|
||||||
|
@ -270,9 +282,71 @@ void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end, read_s
|
||||||
(bs)->bc -= (nbits); \
|
(bs)->bc -= (nbits); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define putbit(bit, bs) { if (bit) (bs)->sr |= (1 << (bs)->bc); \
|
||||||
|
if (++((bs)->bc) == 8) { \
|
||||||
|
*((bs)->ptr) = (bs)->sr; \
|
||||||
|
(bs)->sr = (bs)->bc = 0; \
|
||||||
|
if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#define putbit_0(bs) { \
|
||||||
|
if (++((bs)->bc) == 8) { \
|
||||||
|
*((bs)->ptr) = (bs)->sr; \
|
||||||
|
(bs)->sr = (bs)->bc = 0; \
|
||||||
|
if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#define putbit_1(bs) { (bs)->sr |= (1 << (bs)->bc); \
|
||||||
|
if (++((bs)->bc) == 8) { \
|
||||||
|
*((bs)->ptr) = (bs)->sr; \
|
||||||
|
(bs)->sr = (bs)->bc = 0; \
|
||||||
|
if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \
|
||||||
|
}}
|
||||||
|
|
||||||
|
#define putbits(value, nbits, bs) { \
|
||||||
|
(bs)->sr |= (long)(value) << (bs)->bc; \
|
||||||
|
if (((bs)->bc += (nbits)) >= 8) \
|
||||||
|
do { \
|
||||||
|
*((bs)->ptr) = (bs)->sr; \
|
||||||
|
(bs)->sr >>= 8; \
|
||||||
|
if (++((bs)->ptr) == (bs)->end) (bs)->wrap (bs); \
|
||||||
|
} while (((bs)->bc -= 8) >= 8); \
|
||||||
|
}
|
||||||
|
|
||||||
void little_endian_to_native (void *data, char *format);
|
void little_endian_to_native (void *data, char *format);
|
||||||
void native_to_little_endian (void *data, char *format);
|
void native_to_little_endian (void *data, char *format);
|
||||||
|
|
||||||
|
// these macros implement the weight application and update operations
|
||||||
|
// that are at the heart of the decorrelation loops
|
||||||
|
|
||||||
|
#if 0 // PERFCOND
|
||||||
|
#define apply_weight_i(weight, sample) ((weight * sample + 512) >> 10)
|
||||||
|
#else
|
||||||
|
#define apply_weight_i(weight, sample) ((((weight * sample) >> 8) + 2) >> 2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \
|
||||||
|
(((sample & ~0xffff) >> 9) * weight) + 1) >> 1)
|
||||||
|
|
||||||
|
#if 1 // PERFCOND
|
||||||
|
#define apply_weight(weight, sample) (sample != (short) sample ? \
|
||||||
|
apply_weight_f (weight, sample) : apply_weight_i (weight, sample))
|
||||||
|
#else
|
||||||
|
#define apply_weight(weight, sample) ((int32_t)((weight * (int64_t) sample + 512) >> 10))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0 // PERFCOND
|
||||||
|
#define update_weight(weight, delta, source, result) \
|
||||||
|
if (source && result) weight -= ((((source ^ result) >> 30) & 2) - 1) * delta;
|
||||||
|
#else
|
||||||
|
#define update_weight(weight, delta, source, result) \
|
||||||
|
if (source && result) (source ^ result) < 0 ? (weight -= delta) : (weight += delta);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define update_weight_clip(weight, delta, source, result) \
|
||||||
|
if (source && result && ((source ^ result) < 0 ? (weight -= delta) < -1024 : (weight += delta) > 1024)) \
|
||||||
|
weight = weight < 0 ? -1024 : 1024;
|
||||||
|
|
||||||
// unpack.c
|
// unpack.c
|
||||||
|
|
||||||
int unpack_init (WavpackContext *wpc);
|
int unpack_init (WavpackContext *wpc);
|
||||||
|
@ -287,17 +361,31 @@ int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd);
|
||||||
long unpack_samples (WavpackContext *wpc, long *buffer, ulong sample_count);
|
long unpack_samples (WavpackContext *wpc, long *buffer, ulong sample_count);
|
||||||
int check_crc_error (WavpackContext *wpc);
|
int check_crc_error (WavpackContext *wpc);
|
||||||
|
|
||||||
|
// pack.c
|
||||||
|
|
||||||
|
void pack_init (WavpackContext *wpc);
|
||||||
|
int pack_block (WavpackContext *wpc, long *buffer);
|
||||||
|
|
||||||
// metadata.c stuff
|
// metadata.c stuff
|
||||||
|
|
||||||
int read_metadata_buff (WavpackContext *wpc, WavpackMetadata *wpmd);
|
int read_metadata_buff (WavpackContext *wpc, WavpackMetadata *wpmd);
|
||||||
int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd);
|
int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd);
|
||||||
|
int copy_metadata (WavpackMetadata *wpmd, uchar *buffer_start, uchar *buffer_end);
|
||||||
|
void free_metadata (WavpackMetadata *wpmd);
|
||||||
|
|
||||||
// words.c stuff
|
// words.c stuff
|
||||||
|
|
||||||
|
void init_words (WavpackStream *wps);
|
||||||
int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd);
|
int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||||
|
void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||||
int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd);
|
int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||||
long get_words (WavpackStream *wps, int nchans, int nsamples, long *buffer);
|
long get_words (long *buffer, int nsamples, ulong flags,
|
||||||
|
struct words_data *w, Bitstream *bs);
|
||||||
|
void send_word_lossless (WavpackStream *wps, long value, int chan);
|
||||||
|
void flush_word (WavpackStream *wps);
|
||||||
|
int log2s (long value);
|
||||||
long exp2s (int log);
|
long exp2s (int log);
|
||||||
|
char store_weight (int weight);
|
||||||
int restore_weight (char weight);
|
int restore_weight (char weight);
|
||||||
|
|
||||||
#define WORD_EOF (1L << 31)
|
#define WORD_EOF (1L << 31)
|
||||||
|
@ -332,3 +420,10 @@ int WavpackGetBitsPerSample (WavpackContext *wpc);
|
||||||
int WavpackGetBytesPerSample (WavpackContext *wpc);
|
int WavpackGetBytesPerSample (WavpackContext *wpc);
|
||||||
int WavpackGetNumChannels (WavpackContext *wpc);
|
int WavpackGetNumChannels (WavpackContext *wpc);
|
||||||
int WavpackGetReducedChannels (WavpackContext *wpc);
|
int WavpackGetReducedChannels (WavpackContext *wpc);
|
||||||
|
WavpackContext *WavpackOpenFileOutput (void);
|
||||||
|
void WavpackSetOutputBuffer (WavpackContext *wpc, uchar *begin, uchar *end);
|
||||||
|
int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, ulong total_samples);
|
||||||
|
void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount);
|
||||||
|
ulong WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,28 @@
|
||||||
|
|
||||||
///////////////////////////// local table storage ////////////////////////////
|
///////////////////////////// local table storage ////////////////////////////
|
||||||
|
|
||||||
|
const ulong 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 ulong 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 [] = {
|
const char nbits_table [] = {
|
||||||
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 15
|
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
|
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 16 - 31
|
||||||
|
@ -136,6 +158,11 @@ static const char ones_count_table [] = {
|
||||||
|
|
||||||
///////////////////////////// executable code ////////////////////////////////
|
///////////////////////////// executable code ////////////////////////////////
|
||||||
|
|
||||||
|
void init_words (WavpackStream *wps)
|
||||||
|
{
|
||||||
|
CLEAR (wps->w);
|
||||||
|
}
|
||||||
|
|
||||||
static int mylog2 (unsigned long avalue);
|
static int mylog2 (unsigned long avalue);
|
||||||
|
|
||||||
// Read the median log2 values from the specifed metadata structure, convert
|
// Read the median log2 values from the specifed metadata structure, convert
|
||||||
|
@ -162,6 +189,40 @@ int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocates the correct space in the metadata structure and writes the
|
||||||
|
// current median values to it. Values are converted from 32-bit unsigned
|
||||||
|
// to our internal 16-bit mylog2 values, and read_entropy_vars () is called
|
||||||
|
// to read the values back because we must compensate for the loss through
|
||||||
|
// the log function.
|
||||||
|
|
||||||
|
void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||||
|
{
|
||||||
|
uchar *byteptr;
|
||||||
|
int temp;
|
||||||
|
|
||||||
|
byteptr = wpmd->data = wpmd->temp_data;
|
||||||
|
wpmd->id = ID_ENTROPY_VARS;
|
||||||
|
|
||||||
|
*byteptr++ = temp = mylog2 (wps->w.c [0].median [0]);
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
*byteptr++ = temp = mylog2 (wps->w.c [0].median [1]);
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
*byteptr++ = temp = mylog2 (wps->w.c [0].median [2]);
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
|
||||||
|
if (!(wps->wphdr.flags & MONO_FLAG)) {
|
||||||
|
*byteptr++ = temp = mylog2 (wps->w.c [1].median [0]);
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
*byteptr++ = temp = mylog2 (wps->w.c [1].median [1]);
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
*byteptr++ = temp = mylog2 (wps->w.c [1].median [2]);
|
||||||
|
*byteptr++ = temp >> 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpmd->byte_length = byteptr - (uchar *) wpmd->data;
|
||||||
|
read_entropy_vars (wps, wpmd);
|
||||||
|
}
|
||||||
|
|
||||||
// Read the hybrid related values from the specifed metadata structure, convert
|
// Read the hybrid related values from the specifed metadata structure, convert
|
||||||
// them back to their internal formats and store them. The extended profile
|
// 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
|
// stuff is not implemented yet, so return an error if we get more data than
|
||||||
|
@ -214,30 +275,30 @@ int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||||
// currently implemented) this is calculated from the slow_level values and the
|
// currently implemented) this is calculated from the slow_level values and the
|
||||||
// bitrate accumulators. Note that the bitrate accumulators can be changing.
|
// bitrate accumulators. Note that the bitrate accumulators can be changing.
|
||||||
|
|
||||||
static void update_error_limit (WavpackStream *wps)
|
void update_error_limit (struct words_data *w, ulong flags)
|
||||||
{
|
{
|
||||||
int bitrate_0 = (wps->w.bitrate_acc [0] += wps->w.bitrate_delta [0]) >> 16;
|
int bitrate_0 = (w->bitrate_acc [0] += w->bitrate_delta [0]) >> 16;
|
||||||
|
|
||||||
if (wps->wphdr.flags & MONO_FLAG) {
|
if (flags & MONO_FLAG) {
|
||||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
if (flags & HYBRID_BITRATE) {
|
||||||
int slow_log_0 = (wps->w.c [0].slow_level + SLO) >> SLS;
|
int slow_log_0 = (w->c [0].slow_level + SLO) >> SLS;
|
||||||
|
|
||||||
if (slow_log_0 - bitrate_0 > -0x100)
|
if (slow_log_0 - bitrate_0 > -0x100)
|
||||||
wps->w.c [0].error_limit = exp2s (slow_log_0 - bitrate_0 + 0x100);
|
w->c [0].error_limit = exp2s (slow_log_0 - bitrate_0 + 0x100);
|
||||||
else
|
else
|
||||||
wps->w.c [0].error_limit = 0;
|
w->c [0].error_limit = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
wps->w.c [0].error_limit = exp2s (bitrate_0);
|
w->c [0].error_limit = exp2s (bitrate_0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int bitrate_1 = (wps->w.bitrate_acc [1] += wps->w.bitrate_delta [1]) >> 16;
|
int bitrate_1 = (w->bitrate_acc [1] += w->bitrate_delta [1]) >> 16;
|
||||||
|
|
||||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
if (flags & HYBRID_BITRATE) {
|
||||||
int slow_log_0 = (wps->w.c [0].slow_level + SLO) >> SLS;
|
int slow_log_0 = (w->c [0].slow_level + SLO) >> SLS;
|
||||||
int slow_log_1 = (wps->w.c [1].slow_level + SLO) >> SLS;
|
int slow_log_1 = (w->c [1].slow_level + SLO) >> SLS;
|
||||||
|
|
||||||
if (wps->wphdr.flags & HYBRID_BALANCE) {
|
if (flags & HYBRID_BALANCE) {
|
||||||
int balance = (slow_log_1 - slow_log_0 + bitrate_1 + 1) >> 1;
|
int balance = (slow_log_1 - slow_log_0 + bitrate_1 + 1) >> 1;
|
||||||
|
|
||||||
if (balance > bitrate_0) {
|
if (balance > bitrate_0) {
|
||||||
|
@ -255,18 +316,18 @@ static void update_error_limit (WavpackStream *wps)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slow_log_0 - bitrate_0 > -0x100)
|
if (slow_log_0 - bitrate_0 > -0x100)
|
||||||
wps->w.c [0].error_limit = exp2s (slow_log_0 - bitrate_0 + 0x100);
|
w->c [0].error_limit = exp2s (slow_log_0 - bitrate_0 + 0x100);
|
||||||
else
|
else
|
||||||
wps->w.c [0].error_limit = 0;
|
w->c [0].error_limit = 0;
|
||||||
|
|
||||||
if (slow_log_1 - bitrate_1 > -0x100)
|
if (slow_log_1 - bitrate_1 > -0x100)
|
||||||
wps->w.c [1].error_limit = exp2s (slow_log_1 - bitrate_1 + 0x100);
|
w->c [1].error_limit = exp2s (slow_log_1 - bitrate_1 + 0x100);
|
||||||
else
|
else
|
||||||
wps->w.c [1].error_limit = 0;
|
w->c [1].error_limit = 0;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
wps->w.c [0].error_limit = exp2s (bitrate_0);
|
w->c [0].error_limit = exp2s (bitrate_0);
|
||||||
wps->w.c [1].error_limit = exp2s (bitrate_1);
|
w->c [1].error_limit = exp2s (bitrate_1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -281,75 +342,78 @@ static ulong read_code (Bitstream *bs, ulong maxcode);
|
||||||
// of WORD_EOF indicates that the end of the bitstream was reached (all 1s) or
|
// of WORD_EOF indicates that the end of the bitstream was reached (all 1s) or
|
||||||
// some other error occurred.
|
// some other error occurred.
|
||||||
|
|
||||||
long get_words (WavpackStream *wps, int nchans, int nsamples, long *buffer)
|
long get_words (long *buffer, int nsamples, ulong flags,
|
||||||
|
struct words_data *w, Bitstream *bs)
|
||||||
{
|
{
|
||||||
|
register struct entropy_data *c = w->c;
|
||||||
|
int csamples;
|
||||||
|
|
||||||
|
if (!(flags & MONO_FLAG))
|
||||||
|
nsamples *= 2;
|
||||||
|
|
||||||
|
for (csamples = 0; csamples < nsamples; ++csamples) {
|
||||||
ulong ones_count, low, mid, high;
|
ulong ones_count, low, mid, high;
|
||||||
register struct entropy_data *c;
|
|
||||||
long *bptr = buffer;
|
|
||||||
|
|
||||||
nsamples *= nchans;
|
if (!(flags & MONO_FLAG))
|
||||||
|
c = w->c + (csamples & 1);
|
||||||
|
|
||||||
while (nsamples--) {
|
if (!(w->c [0].median [0] & ~1) && !w->holding_zero && !w->holding_one && !(w->c [1].median [0] & ~1)) {
|
||||||
|
|
||||||
c = wps->w.c + ((nchans == 1) ? 0 : (~nsamples & 1));
|
|
||||||
|
|
||||||
if (!(wps->w.c [0].median [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.c [1].median [0] & ~1)) {
|
|
||||||
ulong mask;
|
ulong mask;
|
||||||
int cbits;
|
int cbits;
|
||||||
|
|
||||||
if (wps->w.zeros_acc) {
|
if (w->zeros_acc) {
|
||||||
if (--wps->w.zeros_acc) {
|
if (--w->zeros_acc) {
|
||||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||||
*bptr++ = 0;
|
*buffer++ = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
|
for (cbits = 0; cbits < 33 && getbit (bs); ++cbits);
|
||||||
|
|
||||||
if (cbits == 33)
|
if (cbits == 33)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (cbits < 2)
|
if (cbits < 2)
|
||||||
wps->w.zeros_acc = cbits;
|
w->zeros_acc = cbits;
|
||||||
else {
|
else {
|
||||||
for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1)
|
for (mask = 1, w->zeros_acc = 0; --cbits; mask <<= 1)
|
||||||
if (getbit (&wps->wvbits))
|
if (getbit (bs))
|
||||||
wps->w.zeros_acc |= mask;
|
w->zeros_acc |= mask;
|
||||||
|
|
||||||
wps->w.zeros_acc |= mask;
|
w->zeros_acc |= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wps->w.zeros_acc) {
|
if (w->zeros_acc) {
|
||||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||||
CLEAR (wps->w.c [0].median);
|
CLEAR (w->c [0].median);
|
||||||
CLEAR (wps->w.c [1].median);
|
CLEAR (w->c [1].median);
|
||||||
*bptr++ = 0;
|
*buffer++ = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wps->w.holding_zero)
|
if (w->holding_zero)
|
||||||
ones_count = wps->w.holding_zero = 0;
|
ones_count = w->holding_zero = 0;
|
||||||
else {
|
else {
|
||||||
int next8;
|
int next8;
|
||||||
|
|
||||||
if (wps->wvbits.bc < 8) {
|
if (bs->bc < 8) {
|
||||||
if (++(wps->wvbits.ptr) == wps->wvbits.end)
|
if (++(bs->ptr) == bs->end)
|
||||||
wps->wvbits.wrap (&wps->wvbits);
|
bs->wrap (bs);
|
||||||
|
|
||||||
next8 = (wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc) & 0xff;
|
next8 = (bs->sr |= *(bs->ptr) << bs->bc) & 0xff;
|
||||||
wps->wvbits.bc += 8;
|
bs->bc += 8;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
next8 = wps->wvbits.sr & 0xff;
|
next8 = bs->sr & 0xff;
|
||||||
|
|
||||||
if (next8 == 0xff) {
|
if (next8 == 0xff) {
|
||||||
wps->wvbits.bc -= 8;
|
bs->bc -= 8;
|
||||||
wps->wvbits.sr >>= 8;
|
bs->sr >>= 8;
|
||||||
|
|
||||||
for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count);
|
for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count);
|
||||||
|
|
||||||
if (ones_count == (LIMIT_ONES + 1))
|
if (ones_count == (LIMIT_ONES + 1))
|
||||||
break;
|
break;
|
||||||
|
@ -358,7 +422,7 @@ long get_words (WavpackStream *wps, int nchans, int nsamples, long *buffer)
|
||||||
ulong mask;
|
ulong mask;
|
||||||
int cbits;
|
int cbits;
|
||||||
|
|
||||||
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
|
for (cbits = 0; cbits < 33 && getbit (bs); ++cbits);
|
||||||
|
|
||||||
if (cbits == 33)
|
if (cbits == 33)
|
||||||
break;
|
break;
|
||||||
|
@ -367,7 +431,7 @@ long get_words (WavpackStream *wps, int nchans, int nsamples, long *buffer)
|
||||||
ones_count = cbits;
|
ones_count = cbits;
|
||||||
else {
|
else {
|
||||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||||
if (getbit (&wps->wvbits))
|
if (getbit (bs))
|
||||||
ones_count |= mask;
|
ones_count |= mask;
|
||||||
|
|
||||||
ones_count |= mask;
|
ones_count |= mask;
|
||||||
|
@ -377,24 +441,24 @@ long get_words (WavpackStream *wps, int nchans, int nsamples, long *buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
wps->wvbits.bc -= (ones_count = ones_count_table [next8]) + 1;
|
bs->bc -= (ones_count = ones_count_table [next8]) + 1;
|
||||||
wps->wvbits.sr >>= ones_count + 1;
|
bs->sr >>= ones_count + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wps->w.holding_one) {
|
if (w->holding_one) {
|
||||||
wps->w.holding_one = ones_count & 1;
|
w->holding_one = ones_count & 1;
|
||||||
ones_count = (ones_count >> 1) + 1;
|
ones_count = (ones_count >> 1) + 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
wps->w.holding_one = ones_count & 1;
|
w->holding_one = ones_count & 1;
|
||||||
ones_count >>= 1;
|
ones_count >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
wps->w.holding_zero = ~wps->w.holding_one & 1;
|
w->holding_zero = ~w->holding_one & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((wps->wphdr.flags & HYBRID_FLAG) && (nchans == 1 || (nsamples & 1)))
|
if ((flags & HYBRID_FLAG) && ((flags & MONO_FLAG) || !(csamples & 1)))
|
||||||
update_error_limit (wps);
|
update_error_limit (w, flags);
|
||||||
|
|
||||||
if (ones_count == 0) {
|
if (ones_count == 0) {
|
||||||
low = 0;
|
low = 0;
|
||||||
|
@ -428,21 +492,21 @@ long get_words (WavpackStream *wps, int nchans, int nsamples, long *buffer)
|
||||||
mid = (high + low + 1) >> 1;
|
mid = (high + low + 1) >> 1;
|
||||||
|
|
||||||
if (!c->error_limit)
|
if (!c->error_limit)
|
||||||
mid = read_code (&wps->wvbits, high - low) + low;
|
mid = read_code (bs, high - low) + low;
|
||||||
else while (high - low > c->error_limit) {
|
else while (high - low > c->error_limit) {
|
||||||
if (getbit (&wps->wvbits))
|
if (getbit (bs))
|
||||||
mid = (high + (low = mid) + 1) >> 1;
|
mid = (high + (low = mid) + 1) >> 1;
|
||||||
else
|
else
|
||||||
mid = ((high = mid - 1) + low + 1) >> 1;
|
mid = ((high = mid - 1) + low + 1) >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*bptr++ = getbit (&wps->wvbits) ? ~mid : mid;
|
*buffer++ = getbit (bs) ? ~mid : mid;
|
||||||
|
|
||||||
if (wps->wphdr.flags & HYBRID_BITRATE)
|
if (flags & HYBRID_BITRATE)
|
||||||
c->slow_level = c->slow_level - ((c->slow_level + SLO) >> SLS) + mylog2 (mid);
|
c->slow_level = c->slow_level - ((c->slow_level + SLO) >> SLS) + mylog2 (mid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return nchans == 1 ? (bptr - buffer) : ((bptr - buffer) / 2);
|
return (flags & MONO_FLAG) ? csamples : (csamples / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a single unsigned value from the specified bitstream with a value
|
// Read a single unsigned value from the specified bitstream with a value
|
||||||
|
@ -472,6 +536,180 @@ static ulong read_code (Bitstream *bs, ulong maxcode)
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function is an optimized version of send_word() that only handles
|
||||||
|
// lossless (error_limit == 0). It does not return a value because it always
|
||||||
|
// encodes the exact value passed.
|
||||||
|
|
||||||
|
void send_word_lossless (WavpackStream *wps, long value, int chan)
|
||||||
|
{
|
||||||
|
register struct words_data *w = &wps->w;
|
||||||
|
register struct entropy_data *c = w->c + chan;
|
||||||
|
int sign = (value < 0) ? 1 : 0;
|
||||||
|
ulong ones_count, low, high;
|
||||||
|
|
||||||
|
if (!(wps->w.c [0].median [0] & ~1) && !wps->w.holding_zero && !(wps->w.c [1].median [0] & ~1)) {
|
||||||
|
if (wps->w.zeros_acc) {
|
||||||
|
if (value)
|
||||||
|
flush_word (wps);
|
||||||
|
else {
|
||||||
|
wps->w.zeros_acc++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value) {
|
||||||
|
putbit_0 (&wps->wvbits);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CLEAR (wps->w.c [0].median);
|
||||||
|
CLEAR (wps->w.c [1].median);
|
||||||
|
wps->w.zeros_acc = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sign)
|
||||||
|
value = ~value;
|
||||||
|
|
||||||
|
if ((unsigned long) value < GET_MED (0)) {
|
||||||
|
ones_count = low = 0;
|
||||||
|
high = GET_MED (0) - 1;
|
||||||
|
DEC_MED0 ();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
low = GET_MED (0);
|
||||||
|
INC_MED0 ();
|
||||||
|
|
||||||
|
if (value - low < GET_MED (1)) {
|
||||||
|
ones_count = 1;
|
||||||
|
high = low + GET_MED (1) - 1;
|
||||||
|
DEC_MED1 ();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
low += GET_MED (1);
|
||||||
|
INC_MED1 ();
|
||||||
|
|
||||||
|
if (value - low < GET_MED (2)) {
|
||||||
|
ones_count = 2;
|
||||||
|
high = low + GET_MED (2) - 1;
|
||||||
|
DEC_MED2 ();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ones_count = 2 + (value - low) / GET_MED (2);
|
||||||
|
low += (ones_count - 2) * GET_MED (2);
|
||||||
|
high = low + GET_MED (2) - 1;
|
||||||
|
INC_MED2 ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wps->w.holding_zero) {
|
||||||
|
if (ones_count)
|
||||||
|
wps->w.holding_one++;
|
||||||
|
|
||||||
|
flush_word (wps);
|
||||||
|
|
||||||
|
if (ones_count) {
|
||||||
|
wps->w.holding_zero = 1;
|
||||||
|
ones_count--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wps->w.holding_zero = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
wps->w.holding_zero = 1;
|
||||||
|
|
||||||
|
wps->w.holding_one = ones_count * 2;
|
||||||
|
|
||||||
|
if (high != low) {
|
||||||
|
ulong maxcode = high - low, code = value - low;
|
||||||
|
int bitcount = count_bits (maxcode);
|
||||||
|
ulong 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 |= ((long) 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) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wps->w.holding_zero) {
|
||||||
|
putbit_0 (&wps->wvbits);
|
||||||
|
wps->w.holding_zero = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wps->w.pend_count) {
|
||||||
|
|
||||||
|
while (wps->w.pend_count > 24) {
|
||||||
|
putbit (wps->w.pend_data & 1, &wps->wvbits);
|
||||||
|
wps->w.pend_data >>= 1;
|
||||||
|
wps->w.pend_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
putbits (wps->w.pend_data, wps->w.pend_count, &wps->wvbits);
|
||||||
|
wps->w.pend_data = wps->w.pend_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The concept of a base 2 logarithm is used in many parts of WavPack. It is
|
// 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
|
// 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
|
// values storing only 16 bits (actually fewer). It is also used in the hybrid
|
||||||
|
@ -507,6 +745,15 @@ static int mylog2 (unsigned long avalue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This function returns the log2 for the specified 32-bit signed value.
|
||||||
|
// All input values are valid and the return values are in the range of
|
||||||
|
// +/- 8192.
|
||||||
|
|
||||||
|
int log2s (long value)
|
||||||
|
{
|
||||||
|
return (value < 0) ? -mylog2 (-value) : mylog2 (value);
|
||||||
|
}
|
||||||
|
|
||||||
// This function returns the original integer represented by the supplied
|
// This function returns the original integer represented by the supplied
|
||||||
// logarithm (at least within the provided accuracy). The log is signed,
|
// 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
|
// but since a full 32-bit value is returned this can be used for unsigned
|
||||||
|
@ -531,6 +778,19 @@ long exp2s (int log)
|
||||||
// to and from an 8-bit signed character version for storage in metadata. The
|
// 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.
|
// weights are clipped here in the case that they are outside that range.
|
||||||
|
|
||||||
|
char store_weight (int weight)
|
||||||
|
{
|
||||||
|
if (weight > 1024)
|
||||||
|
weight = 1024;
|
||||||
|
else if (weight < -1024)
|
||||||
|
weight = -1024;
|
||||||
|
|
||||||
|
if (weight > 0)
|
||||||
|
weight -= (weight + 64) >> 7;
|
||||||
|
|
||||||
|
return (weight + 4) >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
int restore_weight (char weight)
|
int restore_weight (char weight)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static void strcpy_loc (char *dst, char *src) { while (*src) *dst++ = *src++; *dst = 0; }
|
static void strcpy_loc (char *dst, char *src) { while ((*dst++ = *src++) != 0); }
|
||||||
|
|
||||||
///////////////////////////// local table storage ////////////////////////////
|
///////////////////////////// local table storage ////////////////////////////
|
||||||
|
|
||||||
|
@ -354,3 +354,202 @@ static ulong read_next_header (read_stream infile, WavpackHeader *wphdr)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Open context for writing WavPack files. The returned context pointer is used
|
||||||
|
// in all following calls to the library. A return value of NULL indicates
|
||||||
|
// that memory could not be allocated for the context.
|
||||||
|
|
||||||
|
WavpackContext *WavpackOpenFileOutput (void)
|
||||||
|
{
|
||||||
|
CLEAR (wpc);
|
||||||
|
return &wpc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the output buffer limits. This must be done before calling
|
||||||
|
// WavpackPackSamples(), but also may be done afterward to adjust
|
||||||
|
// the usable buffer. Note that writing CANNOT wrap in the buffer; the
|
||||||
|
// entire output block must fit in the buffer.
|
||||||
|
|
||||||
|
void WavpackSetOutputBuffer (WavpackContext *wpc, uchar *begin, uchar *end)
|
||||||
|
{
|
||||||
|
wpc->stream.blockbuff = begin;
|
||||||
|
wpc->stream.blockend = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set configuration for writing WavPack files. This must be done before
|
||||||
|
// sending any actual samples, however it is okay to send wrapper or other
|
||||||
|
// metadata before calling this. The "config" structure contains the following
|
||||||
|
// required information:
|
||||||
|
|
||||||
|
// config->bytes_per_sample see WavpackGetBytesPerSample() for info
|
||||||
|
// config->bits_per_sample see WavpackGetBitsPerSample() for info
|
||||||
|
// config->num_channels self evident
|
||||||
|
// config->sample_rate self evident
|
||||||
|
|
||||||
|
// In addition, the following fields and flags may be set:
|
||||||
|
|
||||||
|
// config->flags:
|
||||||
|
// --------------
|
||||||
|
// o CONFIG_HYBRID_FLAG select hybrid mode (must set bitrate)
|
||||||
|
// o CONFIG_JOINT_STEREO select joint stereo (must set override also)
|
||||||
|
// o CONFIG_JOINT_OVERRIDE override default joint stereo selection
|
||||||
|
// o CONFIG_HYBRID_SHAPE select hybrid noise shaping (set override &
|
||||||
|
// shaping_weight != 0.0)
|
||||||
|
// o CONFIG_SHAPE_OVERRIDE override default hybrid noise shaping
|
||||||
|
// (set CONFIG_HYBRID_SHAPE and shaping_weight)
|
||||||
|
// o CONFIG_FAST_FLAG "fast" compression mode
|
||||||
|
// o CONFIG_HIGH_FLAG "high" compression mode
|
||||||
|
// o CONFIG_BITRATE_KBPS hybrid bitrate is kbps, not bits / sample
|
||||||
|
|
||||||
|
// config->bitrate hybrid bitrate in either bits/sample or kbps
|
||||||
|
// config->shaping_weight hybrid noise shaping coefficient override
|
||||||
|
// config->float_norm_exp select floating-point data (127 for +/-1.0)
|
||||||
|
|
||||||
|
// If the number of samples to be written is known then it should be passed
|
||||||
|
// here. If the duration is not known then pass -1. In the case that the size
|
||||||
|
// is not known (or the writing is terminated early) then it is suggested that
|
||||||
|
// the application retrieve the first block written and let the library update
|
||||||
|
// the total samples indication. A function is provided to do this update and
|
||||||
|
// it should be done to the "correction" file also. If this cannot be done
|
||||||
|
// (because a pipe is being used, for instance) then a valid WavPack will still
|
||||||
|
// be created, but when applications want to access that file they will have
|
||||||
|
// to seek all the way to the end to determine the actual duration. Also, if
|
||||||
|
// a RIFF header has been included then it should be updated as well or the
|
||||||
|
// WavPack file will not be directly unpackable to a valid wav file (although
|
||||||
|
// it will still be usable by itself). A return of FALSE indicates an error.
|
||||||
|
|
||||||
|
int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, ulong total_samples)
|
||||||
|
{
|
||||||
|
WavpackStream *wps = &wpc->stream;
|
||||||
|
ulong flags = (config->bytes_per_sample - 1), shift = 0;
|
||||||
|
int num_chans = config->num_channels;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((wpc->config.flags & CONFIG_HYBRID_FLAG) ||
|
||||||
|
wpc->config.float_norm_exp ||
|
||||||
|
num_chans < 1 || num_chans > 2)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
wpc->total_samples = total_samples;
|
||||||
|
wpc->config.sample_rate = config->sample_rate;
|
||||||
|
wpc->config.num_channels = config->num_channels;
|
||||||
|
wpc->config.bits_per_sample = config->bits_per_sample;
|
||||||
|
wpc->config.bytes_per_sample = config->bytes_per_sample;
|
||||||
|
wpc->config.flags = config->flags;
|
||||||
|
|
||||||
|
shift = (config->bytes_per_sample * 8) - config->bits_per_sample;
|
||||||
|
|
||||||
|
for (i = 0; i < 15; ++i)
|
||||||
|
if (wpc->config.sample_rate == sample_rates [i])
|
||||||
|
break;
|
||||||
|
|
||||||
|
flags |= i << SRATE_LSB;
|
||||||
|
flags |= shift << SHIFT_LSB;
|
||||||
|
flags |= CROSS_DECORR;
|
||||||
|
|
||||||
|
if (!(config->flags & CONFIG_JOINT_OVERRIDE) || (config->flags & CONFIG_JOINT_STEREO))
|
||||||
|
flags |= JOINT_STEREO;
|
||||||
|
|
||||||
|
memcpy (wps->wphdr.ckID, "wvpk", 4);
|
||||||
|
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||||
|
wps->wphdr.total_samples = wpc->total_samples;
|
||||||
|
wps->wphdr.version = 0x403;
|
||||||
|
wps->wphdr.flags = flags;
|
||||||
|
|
||||||
|
wps->wphdr.flags |= INITIAL_BLOCK;
|
||||||
|
wps->wphdr.flags |= FINAL_BLOCK;
|
||||||
|
|
||||||
|
if (num_chans == 1) {
|
||||||
|
wps->wphdr.flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE);
|
||||||
|
wps->wphdr.flags |= MONO_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
pack_init (wpc);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add wrapper (currently RIFF only) to WavPack blocks. This should be called
|
||||||
|
// before sending any audio samples for the RIFF header or after all samples
|
||||||
|
// have been sent for any RIFF trailer. WavpackFlushSamples() should be called
|
||||||
|
// between sending the last samples and calling this for trailer data to make
|
||||||
|
// sure that headers and trailers don't get mixed up in very short files. If
|
||||||
|
// the exact contents of the RIFF header are not known because, for example,
|
||||||
|
// the file duration is uncertain or trailing chunks are possible, simply write
|
||||||
|
// a "dummy" header of the correct length. When all data has been written it
|
||||||
|
// will be possible to read the first block written and update the header
|
||||||
|
// directly. An example of this can be found in the Audition filter. A
|
||||||
|
// return of FALSE indicates an error.
|
||||||
|
|
||||||
|
void WavpackAddWrapper (WavpackContext *wpc, void *data, ulong bcount)
|
||||||
|
{
|
||||||
|
wpc->wrapper_data = data;
|
||||||
|
wpc->wrapper_bytes = bcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pack the specified samples. Samples must be stored in longs in the native
|
||||||
|
// endian format of the executing processor. The number of samples specified
|
||||||
|
// indicates composite samples (sometimes called "frames"). So, the actual
|
||||||
|
// number of data points would be this "sample_count" times the number of
|
||||||
|
// channels. Note that samples are accumulated here until enough exist to
|
||||||
|
// create a complete WavPack block (or several blocks for multichannel audio).
|
||||||
|
// If an application wants to break a block at a specific sample, then it must
|
||||||
|
// simply call WavpackFlushSamples() to force an early termination. Completed
|
||||||
|
// WavPack blocks are send to the function provided in the initial call to
|
||||||
|
// WavpackOpenFileOutput(). A return of FALSE indicates an error.
|
||||||
|
|
||||||
|
ulong WavpackPackSamples (WavpackContext *wpc, long *sample_buffer, ulong sample_count)
|
||||||
|
{
|
||||||
|
WavpackStream *wps = &wpc->stream;
|
||||||
|
ulong flags = wps->wphdr.flags;
|
||||||
|
ulong bcount;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
flags &= ~MAG_MASK;
|
||||||
|
flags += (1 << MAG_LSB) * ((flags & BYTES_STORED) * 8 + 7);
|
||||||
|
|
||||||
|
wps->wphdr.block_index = wps->sample_index;
|
||||||
|
wps->wphdr.block_samples = sample_count;
|
||||||
|
wps->wphdr.flags = flags;
|
||||||
|
|
||||||
|
result = pack_block (wpc, sample_buffer);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
strcpy_loc (wpc->error_message, "output buffer overflowed!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bcount = ((WavpackHeader *) wps->blockbuff)->ckSize + 8;
|
||||||
|
native_to_little_endian ((WavpackHeader *) wps->blockbuff, WavpackHeaderFormat);
|
||||||
|
|
||||||
|
return bcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given the pointer to the first block written (to either a .wv or .wvc file),
|
||||||
|
// update the block with the actual number of samples written. This should
|
||||||
|
// be done if WavpackSetConfiguration() was called with an incorrect number
|
||||||
|
// of samples (or -1). It is the responsibility of the application to read and
|
||||||
|
// rewrite the block. An example of this can be found in the Audition filter.
|
||||||
|
|
||||||
|
void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block)
|
||||||
|
{
|
||||||
|
little_endian_to_native (wpc, WavpackHeaderFormat);
|
||||||
|
((WavpackHeader *) first_block)->total_samples = WavpackGetSampleIndex (wpc);
|
||||||
|
native_to_little_endian (wpc, WavpackHeaderFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Given the pointer to the first block written to a WavPack file, this
|
||||||
|
// function returns the location of the stored RIFF header that was originally
|
||||||
|
// written with WavpackAddWrapper(). This would normally be used to update
|
||||||
|
// the wav header to indicate that a different number of samples was actually
|
||||||
|
// written or if additional RIFF chunks are written at the end of the file.
|
||||||
|
// It is the responsibility of the application to read and rewrite the block.
|
||||||
|
// An example of this can be found in the Audition filter.
|
||||||
|
|
||||||
|
void *WavpackGetWrapperLocation (void *first_block)
|
||||||
|
{
|
||||||
|
if (((uchar *) first_block) [32] == ID_RIFF_HEADER)
|
||||||
|
return ((uchar *) first_block) + 34;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue