From dacbc16d5b2c2a113eab6b9295db12795d98e2cc Mon Sep 17 00:00:00 2001 From: Dave Bryant Date: Mon, 4 Jul 2005 06:38:00 +0000 Subject: 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 --- apps/codecs/libwavpack/SOURCES | 1 + apps/codecs/libwavpack/bits.c | 163 ++++--- apps/codecs/libwavpack/float.c | 90 ++-- apps/codecs/libwavpack/metadata.c | 136 ++++-- apps/codecs/libwavpack/pack.c | 450 ++++++++++++++++++++ apps/codecs/libwavpack/unpack.c | 869 ++++++++++++++++++-------------------- apps/codecs/libwavpack/wavpack.h | 317 +++++++++----- apps/codecs/libwavpack/words.c | 798 ++++++++++++++++++++++------------ apps/codecs/libwavpack/wputils.c | 431 ++++++++++++++----- 9 files changed, 2156 insertions(+), 1099 deletions(-) create mode 100644 apps/codecs/libwavpack/pack.c (limited to 'apps') diff --git a/apps/codecs/libwavpack/SOURCES b/apps/codecs/libwavpack/SOURCES index a4f0f2f7a9..17399351fd 100644 --- a/apps/codecs/libwavpack/SOURCES +++ b/apps/codecs/libwavpack/SOURCES @@ -2,6 +2,7 @@ bits.c float.c metadata.c unpack.c +pack.c words.c wputils.c #if CONFIG_CPU==MCF5249 && !defined(SIMULATOR) diff --git a/apps/codecs/libwavpack/bits.c b/apps/codecs/libwavpack/bits.c index 1fe6aacf75..bf056a9392 100644 --- a/apps/codecs/libwavpack/bits.c +++ b/apps/codecs/libwavpack/bits.c @@ -31,12 +31,12 @@ void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end, read_s bs->end = buffer_end; if (file) { - bs->ptr = bs->end - 1; - bs->file_bytes = file_bytes; - bs->file = file; + bs->ptr = bs->end - 1; + bs->file_bytes = file_bytes; + bs->file = file; } else - bs->ptr = bs->buf - 1; + bs->ptr = bs->buf - 1; bs->wrap = bs_read; } @@ -49,31 +49,70 @@ void bs_open_read (Bitstream *bs, uchar *buffer_start, uchar *buffer_end, read_s static void bs_read (Bitstream *bs) { if (bs->file && bs->file_bytes) { - ulong bytes_read, bytes_to_read = bs->end - bs->buf; + ulong bytes_read, bytes_to_read = bs->end - bs->buf; - if (bytes_to_read > bs->file_bytes) - bytes_to_read = bs->file_bytes; + if (bytes_to_read > bs->file_bytes) + bytes_to_read = bs->file_bytes; - bytes_read = bs->file (bs->buf, bytes_to_read); + 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; - } + 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; + bs->error = 1; if (bs->error) - memset (bs->buf, -1, bs->end - bs->buf); + memset (bs->buf, -1, bs->end - 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 //////////////////////////// void little_endian_to_native (void *data, char *format) @@ -82,27 +121,27 @@ void little_endian_to_native (void *data, char *format) 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 (*format >= '0' && *format <= '9') - cp += *format - '0'; - - break; - } - - 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 (*format >= '0' && *format <= '9') + cp += *format - '0'; + + break; + } + + format++; } } @@ -112,28 +151,28 @@ void native_to_little_endian (void *data, char *format) 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 (*format >= '0' && *format <= '9') - cp += *format - '0'; - - break; - } - - 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 (*format >= '0' && *format <= '9') + cp += *format - '0'; + + break; + } + + format++; } } diff --git a/apps/codecs/libwavpack/float.c b/apps/codecs/libwavpack/float.c index 3e678e824d..2208e616d8 100644 --- a/apps/codecs/libwavpack/float.c +++ b/apps/codecs/libwavpack/float.c @@ -1,8 +1,8 @@ //////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2004 Conifer Software. // -// All Rights Reserved. // +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2004 Conifer Software. // +// All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// @@ -16,7 +16,7 @@ int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd) char *byteptr = wpmd->data; if (bytecnt != 4) - return FALSE; + return FALSE; wps->float_flags = *byteptr++; wps->float_shift = *byteptr++; @@ -28,35 +28,35 @@ int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd) 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; + 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; } } @@ -66,18 +66,18 @@ void float_normalize (long *values, long num_values, int delta_exp) int exp; if (!delta_exp) - return; + 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++; + 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++; } } diff --git a/apps/codecs/libwavpack/metadata.c b/apps/codecs/libwavpack/metadata.c index 661b25edc8..ebc7dcf99d 100644 --- a/apps/codecs/libwavpack/metadata.c +++ b/apps/codecs/libwavpack/metadata.c @@ -12,46 +12,48 @@ #include "wavpack.h" +#include + int read_metadata_buff (WavpackContext *wpc, WavpackMetadata *wpmd) { uchar tchar; if (!wpc->infile (&wpmd->id, 1) || !wpc->infile (&tchar, 1)) - return FALSE; + return FALSE; wpmd->byte_length = tchar << 1; if (wpmd->id & ID_LARGE) { - wpmd->id &= ~ID_LARGE; + wpmd->id &= ~ID_LARGE; - if (!wpc->infile (&tchar, 1)) - return FALSE; + if (!wpc->infile (&tchar, 1)) + return FALSE; - wpmd->byte_length += (long) tchar << 9; + wpmd->byte_length += (long) tchar << 9; - if (!wpc->infile (&tchar, 1)) - return FALSE; + if (!wpc->infile (&tchar, 1)) + return FALSE; - wpmd->byte_length += (long) tchar << 17; + wpmd->byte_length += (long) tchar << 17; } if (wpmd->id & ID_ODD_SIZE) { - wpmd->id &= ~ID_ODD_SIZE; - wpmd->byte_length--; + wpmd->id &= ~ID_ODD_SIZE; + wpmd->byte_length--; } if (wpmd->byte_length && wpmd->byte_length <= (long)sizeof (wpc->read_buffer)) { - ulong bytes_to_read = wpmd->byte_length + (wpmd->byte_length & 1); + 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; - } + if (wpc->infile (wpc->read_buffer, bytes_to_read) != (long) bytes_to_read) { + wpmd->data = NULL; + return FALSE; + } - wpmd->data = wpc->read_buffer; + wpmd->data = wpc->read_buffer; } else - wpmd->data = NULL; + wpmd->data = NULL; return TRUE; } @@ -61,45 +63,89 @@ int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd) WavpackStream *wps = &wpc->stream; switch (wpmd->id) { - case ID_DUMMY: - return TRUE; + 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_DECORR_TERMS: - return read_decorr_terms (wps, wpmd); + case ID_HYBRID_PROFILE: + return read_hybrid_profile (wps, wpmd); - case ID_DECORR_WEIGHTS: - return read_decorr_weights (wps, wpmd); + case ID_FLOAT_INFO: + return read_float_info (wps, wpmd); - case ID_DECORR_SAMPLES: - return read_decorr_samples (wps, wpmd); + case ID_INT32_INFO: + return read_int32_info (wps, wpmd); - case ID_ENTROPY_VARS: - return read_entropy_vars (wps, wpmd); + case ID_CHANNEL_INFO: + return read_channel_info (wpc, wpmd); - case ID_HYBRID_PROFILE: - return read_hybrid_profile (wps, 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; + } +} - case ID_FLOAT_INFO: - return read_float_info (wps, wpmd); +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; - case ID_INT32_INFO: - return read_int32_info (wps, wpmd); + if (wpmd->byte_length & 1) + ((char *) wpmd->data) [wpmd->byte_length] = 0; - case ID_CHANNEL_INFO: - return read_channel_info (wpc, wpmd); + mdsize += (wpmd->byte_length > 510) ? 4 : 2; + buffer_start += wphdr->ckSize + 8; - case ID_CONFIG_BLOCK: - return read_config_info (wpc, wpmd); + if (buffer_start + mdsize >= buffer_end) + return FALSE; - case ID_WV_BITSTREAM: - return init_wv_bitstream (wpc, wpmd); + buffer_start [0] = wpmd->id | (wpmd->byte_length & 1 ? ID_ODD_SIZE : 0); + buffer_start [1] = (wpmd->byte_length + 1) >> 1; - case ID_SHAPING_WEIGHTS: - case ID_WVC_BITSTREAM: - case ID_WVX_BITSTREAM: - return TRUE; + 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; + } - default: - return (wpmd->id & ID_OPTIONAL_DATA) ? TRUE : FALSE; + 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; +} + diff --git a/apps/codecs/libwavpack/pack.c b/apps/codecs/libwavpack/pack.c new file mode 100644 index 0000000000..e695388d45 --- /dev/null +++ b/apps/codecs/libwavpack/pack.c @@ -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 + +// 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; +} diff --git a/apps/codecs/libwavpack/unpack.c b/apps/codecs/libwavpack/unpack.c index 5afaac3659..aaab2aa928 100644 --- a/apps/codecs/libwavpack/unpack.c +++ b/apps/codecs/libwavpack/unpack.c @@ -1,8 +1,8 @@ //////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2004 Conifer Software. // -// All Rights Reserved. // +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2004 Conifer Software. // +// All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// @@ -15,46 +15,13 @@ #include "wavpack.h" +#include #include -#include -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 -//////////////////////////////// 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 //////////////////////////////// // This function initializes everything required to unpack a WavPack block @@ -69,7 +36,7 @@ int unpack_init (WavpackContext *wpc) WavpackMetadata wpmd; if (wps->wphdr.block_samples && wps->wphdr.block_index != (ulong) -1) - wps->sample_index = wps->wphdr.block_index; + wps->sample_index = wps->wphdr.block_index; wps->mute_error = FALSE; wps->crc = 0xffffffff; @@ -78,27 +45,27 @@ int unpack_init (WavpackContext *wpc) CLEAR (wps->w); while (read_metadata_buff (wpc, &wpmd)) { - if (!process_metadata (wpc, &wpmd)) { - strcpy_loc (wpc->error_message, "invalid metadata!"); - return FALSE; - } + if (!process_metadata (wpc, &wpmd)) { + strcpy_loc (wpc->error_message, "invalid metadata!"); + return FALSE; + } - if (wpmd.id == ID_WV_BITSTREAM) - break; + if (wpmd.id == ID_WV_BITSTREAM) + break; } if (wps->wphdr.block_samples && !bs_is_open (&wps->wvbits)) { - strcpy_loc (wpc->error_message, "invalid WavPack file!"); - return FALSE; + strcpy_loc (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 & INT32_DATA) && wps->int32_sent_bits) + wpc->lossy_blocks = TRUE; - if ((wps->wphdr.flags & FLOAT_DATA) && - wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME)) - wpc->lossy_blocks = TRUE; + if ((wps->wphdr.flags & FLOAT_DATA) && + wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME)) + wpc->lossy_blocks = TRUE; } return TRUE; @@ -112,10 +79,10 @@ 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); + 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)); + 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; } @@ -134,16 +101,16 @@ int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) struct decorr_pass *dpp; if (termcnt > MAX_NTERMS) - return FALSE; + 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; + 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; + if (!dpp->term || dpp->term < -3 || (dpp->term > MAX_TERM && dpp->term < 17) || dpp->term > 18) + return FALSE; } return TRUE; @@ -162,19 +129,19 @@ int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) struct decorr_pass *dpp; if (!(wps->wphdr.flags & MONO_FLAG)) - termcnt /= 2; + termcnt /= 2; if (termcnt > wps->num_terms) - return FALSE; + return FALSE; for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - dpp->weight_A = dpp->weight_B = 0; + dpp->weight_A = dpp->weight_B = 0; while (--dpp >= wps->decorr_passes && termcnt--) { - dpp->weight_A = restore_weight (*byteptr++); + dpp->weight_A = restore_weight (*byteptr++); - if (!(wps->wphdr.flags & MONO_FLAG)) - dpp->weight_B = restore_weight (*byteptr++); + if (!(wps->wphdr.flags & MONO_FLAG)) + dpp->weight_B = restore_weight (*byteptr++); } return TRUE; @@ -196,49 +163,49 @@ int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) int tcount; for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { - CLEAR (dpp->samples_A); - CLEAR (dpp->samples_B); + CLEAR (dpp->samples_A); + CLEAR (dpp->samples_B); } if (wps->wphdr.version == 0x402 && (wps->wphdr.flags & HYBRID_FLAG)) { - byteptr += 2; + byteptr += 2; - if (!(wps->wphdr.flags & MONO_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++; - } - } + 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; } @@ -253,7 +220,7 @@ int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) char *byteptr = wpmd->data; if (bytecnt != 4) - return FALSE; + return FALSE; wps->int32_sent_bits = *byteptr++; wps->int32_zeros = *byteptr++; @@ -273,13 +240,13 @@ int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) ulong mask = 0; if (!bytecnt || bytecnt > 5) - return FALSE; + return FALSE; wpc->config.num_channels = *byteptr++; while (--bytecnt) { - mask |= (ulong) *byteptr++ << shift; - shift += 8; + mask |= (ulong) *byteptr++ << shift; + shift += 8; } wpc->config.channel_mask = mask; @@ -294,10 +261,10 @@ int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) 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; + wpc->config.flags &= 0xff; + wpc->config.flags |= (long) *byteptr++ << 8; + wpc->config.flags |= (long) *byteptr++ << 16; + wpc->config.flags |= (long) *byteptr << 24; } return TRUE; @@ -339,88 +306,88 @@ long unpack_samples (WavpackContext *wpc, long *buffer, ulong sample_count) int tcount; 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; + 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; + 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; + mute_limit *= 2; ///////////////////// handle version 4 mono data ///////////////////////// if (flags & MONO_FLAG) { - eptr = buffer + sample_count; - i = get_words (wps, 1, sample_count, buffer); + eptr = buffer + sample_count; + i = get_words (buffer, sample_count, flags, &wps->w, &wps->wvbits); - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - decorr_mono_pass (dpp, buffer, sample_count); + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + decorr_mono_pass (dpp, buffer, sample_count); - for (bptr = buffer; bptr < eptr; ++bptr) { - if (labs (bptr [0]) > mute_limit) { - i = bptr - buffer; - break; - } + for (bptr = buffer; bptr < eptr; ++bptr) { + if (labs (bptr [0]) > mute_limit) { + i = bptr - buffer; + break; + } - crc = crc * 3 + bptr [0]; - } + crc = crc * 3 + bptr [0]; + } } //////////////////// handle version 4 stereo data //////////////////////// else { - eptr = buffer + (sample_count * 2); - i = get_words (wps, 2, sample_count, buffer); - - if (sample_count < 16) - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) - decorr_stereo_pass (dpp, buffer, sample_count); - else - for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { - decorr_stereo_pass (dpp, buffer, 8); + eptr = buffer + (sample_count * 2); + i = get_words (buffer, sample_count, flags, &wps->w, &wps->wvbits); + + if (sample_count < 16) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + decorr_stereo_pass (dpp, buffer, sample_count); + else + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + decorr_stereo_pass (dpp, buffer, 8); #if CONFIG_CPU==MCF5249 && !defined(SIMULATOR) - decorr_stereo_pass_cont_mcf5249 (dpp, buffer + 16, sample_count - 8); + decorr_stereo_pass_cont_mcf5249 (dpp, buffer + 16, sample_count - 8); #else - decorr_stereo_pass_cont (dpp, buffer + 16, sample_count - 8); + decorr_stereo_pass_cont (dpp, buffer + 16, sample_count - 8); #endif - } - - if (flags & JOINT_STEREO) - for (bptr = buffer; bptr < eptr; bptr += 2) { - bptr [0] += (bptr [1] -= (bptr [0] >> 1)); - - if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { - i = (bptr - buffer) / 2; - break; - } - - crc = (crc * 3 + bptr [0]) * 3 + bptr [1]; - } - else - for (bptr = buffer; bptr < eptr; bptr += 2) { - if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { - i = (bptr - buffer) / 2; - break; - } - - crc = (crc * 3 + bptr [0]) * 3 + bptr [1]; - } + } + + if (flags & JOINT_STEREO) + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [0] += (bptr [1] -= (bptr [0] >> 1)); + + if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { + i = (bptr - buffer) / 2; + break; + } + + crc = (crc * 3 + bptr [0]) * 3 + bptr [1]; + } + else + for (bptr = buffer; bptr < eptr; bptr += 2) { + if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { + i = (bptr - buffer) / 2; + break; + } + + crc = (crc * 3 + bptr [0]) * 3 + bptr [1]; + } } if (i != sample_count) { - memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8)); - wps->mute_error = TRUE; - i = sample_count; + memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8)); + wps->mute_error = TRUE; + i = sample_count; } 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); + float_normalize (buffer, (flags & MONO_FLAG) ? i : i * 2, + 127 - wps->float_norm_exp + wpc->norm_offset); wps->sample_index += i; wps->crc = crc; @@ -436,107 +403,107 @@ static void decorr_stereo_pass (struct decorr_pass *dpp, long *buffer, long samp switch (dpp->term) { - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0]; - update_weight (weight_A, delta, sam_A, bptr [0]); - bptr [0] = dpp->samples_A [0]; - - sam_A = 2 * dpp->samples_B [0] - dpp->samples_B [1]; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = apply_weight (weight_B, sam_A) + bptr [1]; - update_weight (weight_B, delta, sam_A, bptr [1]); - bptr [1] = dpp->samples_B [0]; - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0]; - update_weight (weight_A, delta, sam_A, bptr [0]); - bptr [0] = dpp->samples_A [0]; - - sam_A = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; - dpp->samples_B [1] = dpp->samples_B [0]; - dpp->samples_B [0] = apply_weight (weight_B, sam_A) + bptr [1]; - update_weight (weight_B, delta, sam_A, bptr [1]); - bptr [1] = dpp->samples_B [0]; - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = dpp->samples_A [m]; - dpp->samples_A [k] = apply_weight (weight_A, sam_A) + bptr [0]; - update_weight (weight_A, delta, sam_A, bptr [0]); - bptr [0] = dpp->samples_A [k]; - - sam_A = dpp->samples_B [m]; - dpp->samples_B [k] = apply_weight (weight_B, sam_A) + bptr [1]; - update_weight (weight_B, delta, sam_A, bptr [1]); - bptr [1] = dpp->samples_B [k]; - - m = (m + 1) & (MAX_TERM - 1); - k = (k + 1) & (MAX_TERM - 1); - } - - if (m) { - long temp_samples [MAX_TERM]; - - memcpy (temp_samples, dpp->samples_A, sizeof (dpp->samples_A)); - - for (k = 0; k < MAX_TERM; k++, m++) - dpp->samples_A [k] = temp_samples [m & (MAX_TERM - 1)]; - - memcpy (temp_samples, dpp->samples_B, sizeof (dpp->samples_B)); - - for (k = 0; k < MAX_TERM; k++, m++) - dpp->samples_B [k] = temp_samples [m & (MAX_TERM - 1)]; - } - - break; - - case -1: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = bptr [0] + apply_weight (weight_A, dpp->samples_A [0]); - update_weight_clip (weight_A, delta, dpp->samples_A [0], bptr [0]); - bptr [0] = sam_A; - dpp->samples_A [0] = bptr [1] + apply_weight (weight_B, sam_A); - update_weight_clip (weight_B, delta, sam_A, bptr [1]); - bptr [1] = dpp->samples_A [0]; - } - - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_B = bptr [1] + apply_weight (weight_B, dpp->samples_B [0]); - update_weight_clip (weight_B, delta, dpp->samples_B [0], bptr [1]); - bptr [1] = sam_B; - dpp->samples_B [0] = bptr [0] + apply_weight (weight_A, sam_B); - update_weight_clip (weight_A, delta, sam_B, bptr [0]); - bptr [0] = dpp->samples_B [0]; - } - - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = bptr [0] + apply_weight (weight_A, dpp->samples_A [0]); - update_weight_clip (weight_A, delta, dpp->samples_A [0], bptr [0]); - sam_B = bptr [1] + apply_weight (weight_B, dpp->samples_B [0]); - update_weight_clip (weight_B, delta, dpp->samples_B [0], bptr [1]); - bptr [0] = dpp->samples_B [0] = sam_A; - bptr [1] = dpp->samples_A [0] = sam_B; - } - - break; + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0]; + update_weight (weight_A, delta, sam_A, bptr [0]); + bptr [0] = dpp->samples_A [0]; + + sam_A = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = apply_weight (weight_B, sam_A) + bptr [1]; + update_weight (weight_B, delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_B [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0]; + update_weight (weight_A, delta, sam_A, bptr [0]); + bptr [0] = dpp->samples_A [0]; + + sam_A = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = apply_weight (weight_B, sam_A) + bptr [1]; + update_weight (weight_B, delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_B [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = apply_weight (weight_A, sam_A) + bptr [0]; + update_weight (weight_A, delta, sam_A, bptr [0]); + bptr [0] = dpp->samples_A [k]; + + sam_A = dpp->samples_B [m]; + dpp->samples_B [k] = apply_weight (weight_B, sam_A) + bptr [1]; + update_weight (weight_B, delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_B [k]; + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + if (m) { + long temp_samples [MAX_TERM]; + + memcpy (temp_samples, dpp->samples_A, sizeof (dpp->samples_A)); + + for (k = 0; k < MAX_TERM; k++, m++) + dpp->samples_A [k] = temp_samples [m & (MAX_TERM - 1)]; + + memcpy (temp_samples, dpp->samples_B, sizeof (dpp->samples_B)); + + for (k = 0; k < MAX_TERM; k++, m++) + dpp->samples_B [k] = temp_samples [m & (MAX_TERM - 1)]; + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight (weight_A, dpp->samples_A [0]); + update_weight_clip (weight_A, delta, dpp->samples_A [0], bptr [0]); + bptr [0] = sam_A; + dpp->samples_A [0] = bptr [1] + apply_weight (weight_B, sam_A); + update_weight_clip (weight_B, delta, sam_A, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_B = bptr [1] + apply_weight (weight_B, dpp->samples_B [0]); + update_weight_clip (weight_B, delta, dpp->samples_B [0], bptr [1]); + bptr [1] = sam_B; + dpp->samples_B [0] = bptr [0] + apply_weight (weight_A, sam_B); + update_weight_clip (weight_A, delta, sam_B, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = bptr [0] + apply_weight (weight_A, dpp->samples_A [0]); + update_weight_clip (weight_A, delta, dpp->samples_A [0], bptr [0]); + sam_B = bptr [1] + apply_weight (weight_B, dpp->samples_B [0]); + update_weight_clip (weight_B, delta, dpp->samples_B [0], bptr [1]); + bptr [0] = dpp->samples_B [0] = sam_A; + bptr [1] = dpp->samples_A [0] = sam_B; + } + + break; } dpp->weight_A = weight_A; @@ -553,89 +520,89 @@ static void decorr_stereo_pass_cont (struct decorr_pass *dpp, long *buffer, long switch (dpp->term) { - case 17: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = 2 * bptr [-2] - bptr [-4]; - bptr [0] = apply_weight (weight_A, sam_A) + (sam_B = bptr [0]); - update_weight (weight_A, delta, sam_A, sam_B); - - sam_A = 2 * bptr [-1] - bptr [-3]; - bptr [1] = apply_weight (weight_B, sam_A) + (sam_B = bptr [1]); - update_weight (weight_B, delta, sam_A, sam_B); - } - - dpp->samples_B [0] = bptr [-1]; - dpp->samples_A [0] = bptr [-2]; - dpp->samples_B [1] = bptr [-3]; - dpp->samples_A [1] = bptr [-4]; - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr += 2) { - sam_A = (3 * bptr [-2] - bptr [-4]) >> 1; - bptr [0] = apply_weight (weight_A, sam_A) + (sam_B = bptr [0]); - update_weight (weight_A, delta, sam_A, sam_B); - - sam_A = (3 * bptr [-1] - bptr [-3]) >> 1; - bptr [1] = apply_weight (weight_B, sam_A) + (sam_B = bptr [1]); - update_weight (weight_B, delta, sam_A, sam_B); - } - - dpp->samples_B [0] = bptr [-1]; - dpp->samples_A [0] = bptr [-2]; - dpp->samples_B [1] = bptr [-3]; - dpp->samples_A [1] = bptr [-4]; - break; - - default: - for (bptr = buffer, tptr = buffer - (dpp->term * 2); bptr < eptr; bptr += 2, tptr += 2) { - bptr [0] = apply_weight (weight_A, tptr [0]) + (sam_A = bptr [0]); - update_weight (weight_A, delta, tptr [0], sam_A); - - bptr [1] = apply_weight (weight_B, tptr [1]) + (sam_A = bptr [1]); - update_weight (weight_B, delta, tptr [1], sam_A); - } - - for (k = dpp->term - 1, i = 8; i--; k--) { - dpp->samples_B [k & (MAX_TERM - 1)] = *--bptr; - dpp->samples_A [k & (MAX_TERM - 1)] = *--bptr; - } - - break; - - case -1: - for (bptr = buffer; bptr < eptr; bptr += 2) { - bptr [0] = apply_weight (weight_A, bptr [-1]) + (sam_A = bptr [0]); - update_weight_clip (weight_A, delta, bptr [-1], sam_A); - bptr [1] = apply_weight (weight_B, bptr [0]) + (sam_A = bptr [1]); - update_weight_clip (weight_B, delta, bptr [0], sam_A); - } - - dpp->samples_A [0] = bptr [-1]; - break; - - case -2: - for (bptr = buffer; bptr < eptr; bptr += 2) { - bptr [1] = apply_weight (weight_B, bptr [-2]) + (sam_A = bptr [1]); - update_weight_clip (weight_B, delta, bptr [-2], sam_A); - bptr [0] = apply_weight (weight_A, bptr [1]) + (sam_A = bptr [0]); - update_weight_clip (weight_A, delta, bptr [1], sam_A); - } - - dpp->samples_B [0] = bptr [-2]; - break; - - case -3: - for (bptr = buffer; bptr < eptr; bptr += 2) { - bptr [0] = apply_weight (weight_A, bptr [-1]) + (sam_A = bptr [0]); - update_weight_clip (weight_A, delta, bptr [-1], sam_A); - bptr [1] = apply_weight (weight_B, bptr [-2]) + (sam_A = bptr [1]); - update_weight_clip (weight_B, delta, bptr [-2], sam_A); - } - - dpp->samples_A [0] = bptr [-1]; - dpp->samples_B [0] = bptr [-2]; - break; + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = 2 * bptr [-2] - bptr [-4]; + bptr [0] = apply_weight (weight_A, sam_A) + (sam_B = bptr [0]); + update_weight (weight_A, delta, sam_A, sam_B); + + sam_A = 2 * bptr [-1] - bptr [-3]; + bptr [1] = apply_weight (weight_B, sam_A) + (sam_B = bptr [1]); + update_weight (weight_B, delta, sam_A, sam_B); + } + + dpp->samples_B [0] = bptr [-1]; + dpp->samples_A [0] = bptr [-2]; + dpp->samples_B [1] = bptr [-3]; + dpp->samples_A [1] = bptr [-4]; + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + sam_A = (3 * bptr [-2] - bptr [-4]) >> 1; + bptr [0] = apply_weight (weight_A, sam_A) + (sam_B = bptr [0]); + update_weight (weight_A, delta, sam_A, sam_B); + + sam_A = (3 * bptr [-1] - bptr [-3]) >> 1; + bptr [1] = apply_weight (weight_B, sam_A) + (sam_B = bptr [1]); + update_weight (weight_B, delta, sam_A, sam_B); + } + + dpp->samples_B [0] = bptr [-1]; + dpp->samples_A [0] = bptr [-2]; + dpp->samples_B [1] = bptr [-3]; + dpp->samples_A [1] = bptr [-4]; + break; + + default: + for (bptr = buffer, tptr = buffer - (dpp->term * 2); bptr < eptr; bptr += 2, tptr += 2) { + bptr [0] = apply_weight (weight_A, tptr [0]) + (sam_A = bptr [0]); + update_weight (weight_A, delta, tptr [0], sam_A); + + bptr [1] = apply_weight (weight_B, tptr [1]) + (sam_A = bptr [1]); + update_weight (weight_B, delta, tptr [1], sam_A); + } + + for (k = dpp->term - 1, i = 8; i--; k--) { + dpp->samples_B [k & (MAX_TERM - 1)] = *--bptr; + dpp->samples_A [k & (MAX_TERM - 1)] = *--bptr; + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [0] = apply_weight (weight_A, bptr [-1]) + (sam_A = bptr [0]); + update_weight_clip (weight_A, delta, bptr [-1], sam_A); + bptr [1] = apply_weight (weight_B, bptr [0]) + (sam_A = bptr [1]); + update_weight_clip (weight_B, delta, bptr [0], sam_A); + } + + dpp->samples_A [0] = bptr [-1]; + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [1] = apply_weight (weight_B, bptr [-2]) + (sam_A = bptr [1]); + update_weight_clip (weight_B, delta, bptr [-2], sam_A); + bptr [0] = apply_weight (weight_A, bptr [1]) + (sam_A = bptr [0]); + update_weight_clip (weight_A, delta, bptr [1], sam_A); + } + + dpp->samples_B [0] = bptr [-2]; + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [0] = apply_weight (weight_A, bptr [-1]) + (sam_A = bptr [0]); + update_weight_clip (weight_A, delta, bptr [-1], sam_A); + bptr [1] = apply_weight (weight_B, bptr [-2]) + (sam_A = bptr [1]); + update_weight_clip (weight_B, delta, bptr [-2], sam_A); + } + + dpp->samples_A [0] = bptr [-1]; + dpp->samples_B [0] = bptr [-2]; + break; } dpp->weight_A = weight_A; @@ -652,48 +619,48 @@ static void decorr_mono_pass (struct decorr_pass *dpp, long *buffer, long sample switch (dpp->term) { - case 17: - for (bptr = buffer; bptr < eptr; bptr++) { - sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0]; - update_weight (weight_A, delta, sam_A, bptr [0]); - bptr [0] = dpp->samples_A [0]; - } - - break; - - case 18: - for (bptr = buffer; bptr < eptr; bptr++) { - sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; - dpp->samples_A [1] = dpp->samples_A [0]; - dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0]; - update_weight (weight_A, delta, sam_A, bptr [0]); - bptr [0] = dpp->samples_A [0]; - } - - break; - - default: - for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr++) { - sam_A = dpp->samples_A [m]; - dpp->samples_A [k] = apply_weight (weight_A, sam_A) + bptr [0]; - update_weight (weight_A, delta, sam_A, bptr [0]); - bptr [0] = dpp->samples_A [k]; - m = (m + 1) & (MAX_TERM - 1); - k = (k + 1) & (MAX_TERM - 1); - } - - if (m) { - long temp_samples [MAX_TERM]; - - memcpy (temp_samples, dpp->samples_A, sizeof (dpp->samples_A)); - - for (k = 0; k < MAX_TERM; k++, m++) - dpp->samples_A [k] = temp_samples [m & (MAX_TERM - 1)]; - } - - break; + case 17: + for (bptr = buffer; bptr < eptr; bptr++) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0]; + update_weight (weight_A, delta, sam_A, bptr [0]); + bptr [0] = dpp->samples_A [0]; + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr++) { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = apply_weight (weight_A, sam_A) + bptr [0]; + update_weight (weight_A, delta, sam_A, bptr [0]); + bptr [0] = dpp->samples_A [0]; + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr++) { + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = apply_weight (weight_A, sam_A) + bptr [0]; + update_weight (weight_A, delta, sam_A, bptr [0]); + bptr [0] = dpp->samples_A [k]; + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + if (m) { + long temp_samples [MAX_TERM]; + + memcpy (temp_samples, dpp->samples_A, sizeof (dpp->samples_A)); + + for (k = 0; k < MAX_TERM; k++, m++) + dpp->samples_A [k] = temp_samples [m & (MAX_TERM - 1)]; + } + + break; } dpp->weight_A = weight_A; @@ -714,76 +681,76 @@ static void fixup_samples (WavpackStream *wps, long *buffer, ulong sample_count) int shift = (flags & SHIFT_MASK) >> SHIFT_LSB; if (flags & FLOAT_DATA) { - float_values (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2); - return; + 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; + 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: - default: + 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: + default: min_shifted = (min_value = (long) 0x80000000 >> shift) << shift; max_shifted = (max_value = (long) 0x7FFFFFFF >> 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; - } + 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; + if (!(flags & MONO_FLAG)) + sample_count *= 2; - while (sample_count--) - *buffer++ <<= shift; + while (sample_count--) + *buffer++ <<= shift; } } @@ -800,7 +767,7 @@ int check_crc_error (WavpackContext *wpc) int result = 0; if (wps->crc != wps->wphdr.crc) - ++result; + ++result; return result; } diff --git a/apps/codecs/libwavpack/wavpack.h b/apps/codecs/libwavpack/wavpack.h index 3aee4718b1..12212bb0f8 100644 --- a/apps/codecs/libwavpack/wavpack.h +++ b/apps/codecs/libwavpack/wavpack.h @@ -14,11 +14,10 @@ // 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 short ushort; -typedef unsigned long ulong; -typedef unsigned int uint; +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned long ulong; +typedef unsigned int uint; // This structure is used to access the individual fields of 32-bit ieee // floating point numbers. This will not be compatible with compilers that @@ -54,70 +53,71 @@ typedef struct { // 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 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 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 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 SHIFT_LSB 13 +#define SHIFT_MASK (0x1fL << SHIFT_LSB) -#define MAG_LSB 18 -#define MAG_MASK (0x1fL << MAG_LSB) +#define MAG_LSB 18 +#define MAG_MASK (0x1fL << MAG_LSB) -#define SRATE_LSB 23 -#define SRATE_MASK (0xfL << SRATE_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 +#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 { + uchar temp_data [64]; 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) +#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 /////////////////////////////// @@ -127,39 +127,39 @@ typedef struct { 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; + int flags, num_channels, float_norm_exp; + ulong 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 % +#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 /////////////////////////////// @@ -191,35 +191,38 @@ struct entropy_data { ulong median [3], slow_level, error_limit; }; +struct words_data { + ulong bitrate_delta [2], bitrate_acc [2]; + ulong pend_data, holding_one, zeros_acc; + int holding_zero, pend_count; + struct entropy_data c [2]; +}; + typedef struct { WavpackHeader wphdr; Bitstream wvbits; - struct { - ulong bitrate_delta [2], bitrate_acc [2]; - ulong pend_data, holding_one, zeros_acc; - int holding_zero, pend_count; - struct entropy_data c [2]; - } w; + struct words_data w; int num_terms, mute_error; ulong sample_index, crc; uchar int32_sent_bits, int32_zeros, int32_ones, int32_dups; uchar float_flags, float_shift, float_max_exp, float_norm_exp; - + uchar *blockbuff, *blockend; + struct decorr_pass decorr_passes [MAX_NTERMS]; } 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.) +#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 /////////////////////////////// @@ -231,6 +234,13 @@ typedef struct { WavpackStream stream; WavpackConfig config; + WavpackMetadata *metadata; + ulong metabytes; + int metacount; + + uchar *wrapper_data; + int wrapper_bytes; + uchar read_buffer [1024]; char error_message [80]; @@ -247,32 +257,96 @@ typedef struct { // bits.c 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 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)->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) \ + ((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; \ + 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); \ } +#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 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 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); int check_crc_error (WavpackContext *wpc); +// pack.c + +void pack_init (WavpackContext *wpc); +int pack_block (WavpackContext *wpc, long *buffer); + // metadata.c stuff int read_metadata_buff (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 +void init_words (WavpackStream *wps); int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd); +void write_entropy_vars (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); +char store_weight (int weight); int restore_weight (char weight); #define WORD_EOF (1L << 31) @@ -314,13 +402,13 @@ 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 +#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); @@ -332,3 +420,10 @@ int WavpackGetBitsPerSample (WavpackContext *wpc); int WavpackGetBytesPerSample (WavpackContext *wpc); int WavpackGetNumChannels (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); + + diff --git a/apps/codecs/libwavpack/words.c b/apps/codecs/libwavpack/words.c index 8e2fc427a6..75d8a86af7 100644 --- a/apps/codecs/libwavpack/words.c +++ b/apps/codecs/libwavpack/words.c @@ -29,7 +29,7 @@ //////////////////////////////// local macros ///////////////////////////////// -#define LIMIT_ONES 16 // maximum consecutive 1s sent for "div" data +#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). @@ -37,9 +37,9 @@ #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 +#define DIV0 128 // 5/7 of samples +#define DIV1 64 // 10/49 of samples +#define DIV2 32 // 20/343 of samples // this macro retrieves the specified median breakpoint (without frac; min = 1) #define GET_MED(med) (((c->median [med]) >> 4) + 1) @@ -66,23 +66,45 @@ ///////////////////////////// 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 [] = { - 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 + 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 [] = { @@ -136,6 +158,11 @@ static const char ones_count_table [] = { ///////////////////////////// executable code //////////////////////////////// +void init_words (WavpackStream *wps) +{ + CLEAR (wps->w); +} + static int mylog2 (unsigned long avalue); // Read the median log2 values from the specifed metadata structure, convert @@ -147,21 +174,55 @@ 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; + return FALSE; wps->w.c [0].median [0] = exp2s (byteptr [0] + (byteptr [1] << 8)); wps->w.c [0].median [1] = exp2s (byteptr [2] + (byteptr [3] << 8)); wps->w.c [0].median [2] = exp2s (byteptr [4] + (byteptr [5] << 8)); if (!(wps->wphdr.flags & MONO_FLAG)) { - wps->w.c [1].median [0] = exp2s (byteptr [6] + (byteptr [7] << 8)); - wps->w.c [1].median [1] = exp2s (byteptr [8] + (byteptr [9] << 8)); - wps->w.c [1].median [2] = exp2s (byteptr [10] + (byteptr [11] << 8)); + wps->w.c [1].median [0] = exp2s (byteptr [6] + (byteptr [7] << 8)); + wps->w.c [1].median [1] = exp2s (byteptr [8] + (byteptr [9] << 8)); + wps->w.c [1].median [2] = exp2s (byteptr [10] + (byteptr [11] << 8)); } return TRUE; } +// 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 // 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 @@ -173,37 +234,37 @@ int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd) uchar *endptr = byteptr + wpmd->byte_length; if (wps->wphdr.flags & HYBRID_BITRATE) { - wps->w.c [0].slow_level = exp2s (byteptr [0] + (byteptr [1] << 8)); - byteptr += 2; + wps->w.c [0].slow_level = exp2s (byteptr [0] + (byteptr [1] << 8)); + byteptr += 2; - if (!(wps->wphdr.flags & MONO_FLAG)) { - wps->w.c [1].slow_level = exp2s (byteptr [0] + (byteptr [1] << 8)); - byteptr += 2; - } + if (!(wps->wphdr.flags & MONO_FLAG)) { + wps->w.c [1].slow_level = 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; + 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; + 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 (!(wps->wphdr.flags & MONO_FLAG)) { + wps->w.bitrate_delta [1] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + } - if (byteptr < endptr) - return FALSE; + if (byteptr < endptr) + return FALSE; } else - wps->w.bitrate_delta [0] = wps->w.bitrate_delta [1] = 0; + wps->w.bitrate_delta [0] = wps->w.bitrate_delta [1] = 0; return TRUE; } @@ -214,60 +275,60 @@ int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd) // 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) +void update_error_limit (struct words_data *w, ulong flags) { - 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.c [0].slow_level + SLO) >> SLS; - - if (slow_log_0 - bitrate_0 > -0x100) - wps->w.c [0].error_limit = exp2s (slow_log_0 - bitrate_0 + 0x100); - else - wps->w.c [0].error_limit = 0; - } - else - wps->w.c [0].error_limit = exp2s (bitrate_0); + int bitrate_0 = (w->bitrate_acc [0] += w->bitrate_delta [0]) >> 16; + + if (flags & MONO_FLAG) { + if (flags & HYBRID_BITRATE) { + int slow_log_0 = (w->c [0].slow_level + SLO) >> SLS; + + if (slow_log_0 - bitrate_0 > -0x100) + w->c [0].error_limit = exp2s (slow_log_0 - bitrate_0 + 0x100); + else + w->c [0].error_limit = 0; + } + else + w->c [0].error_limit = exp2s (bitrate_0); } else { - int bitrate_1 = (wps->w.bitrate_acc [1] += wps->w.bitrate_delta [1]) >> 16; - - if (wps->wphdr.flags & HYBRID_BITRATE) { - int slow_log_0 = (wps->w.c [0].slow_level + SLO) >> SLS; - int slow_log_1 = (wps->w.c [1].slow_level + SLO) >> SLS; - - if (wps->wphdr.flags & HYBRID_BALANCE) { - int balance = (slow_log_1 - slow_log_0 + bitrate_1 + 1) >> 1; - - if (balance > bitrate_0) { - bitrate_1 = bitrate_0 * 2; - bitrate_0 = 0; - } - else if (-balance > bitrate_0) { - bitrate_0 = bitrate_0 * 2; - bitrate_1 = 0; - } - else { - bitrate_1 = bitrate_0 + balance; - bitrate_0 = bitrate_0 - balance; - } - } - - if (slow_log_0 - bitrate_0 > -0x100) - wps->w.c [0].error_limit = exp2s (slow_log_0 - bitrate_0 + 0x100); - else - wps->w.c [0].error_limit = 0; - - if (slow_log_1 - bitrate_1 > -0x100) - wps->w.c [1].error_limit = exp2s (slow_log_1 - bitrate_1 + 0x100); - else - wps->w.c [1].error_limit = 0; - } - else { - wps->w.c [0].error_limit = exp2s (bitrate_0); - wps->w.c [1].error_limit = exp2s (bitrate_1); - } + int bitrate_1 = (w->bitrate_acc [1] += w->bitrate_delta [1]) >> 16; + + if (flags & HYBRID_BITRATE) { + int slow_log_0 = (w->c [0].slow_level + SLO) >> SLS; + int slow_log_1 = (w->c [1].slow_level + SLO) >> SLS; + + if (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) + w->c [0].error_limit = exp2s (slow_log_0 - bitrate_0 + 0x100); + else + w->c [0].error_limit = 0; + + if (slow_log_1 - bitrate_1 > -0x100) + w->c [1].error_limit = exp2s (slow_log_1 - bitrate_1 + 0x100); + else + w->c [1].error_limit = 0; + } + else { + w->c [0].error_limit = exp2s (bitrate_0); + w->c [1].error_limit = exp2s (bitrate_1); + } } } @@ -281,168 +342,171 @@ static ulong read_code (Bitstream *bs, ulong maxcode); // of WORD_EOF indicates that the end of the bitstream was reached (all 1s) or // 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) { - ulong ones_count, low, mid, high; - register struct entropy_data *c; - long *bptr = buffer; - - nsamples *= nchans; - - while (nsamples--) { - - 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; - int cbits; - - if (wps->w.zeros_acc) { - if (--wps->w.zeros_acc) { - c->slow_level -= (c->slow_level + SLO) >> SLS; - *bptr++ = 0; - continue; - } - } - else { - for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); - - if (cbits == 33) - break; - - if (cbits < 2) - wps->w.zeros_acc = cbits; - else { - for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1) - if (getbit (&wps->wvbits)) - wps->w.zeros_acc |= mask; - - wps->w.zeros_acc |= mask; - } - - if (wps->w.zeros_acc) { - c->slow_level -= (c->slow_level + SLO) >> SLS; - CLEAR (wps->w.c [0].median); - CLEAR (wps->w.c [1].median); - *bptr++ = 0; - continue; - } - } - } - - if (wps->w.holding_zero) - ones_count = wps->w.holding_zero = 0; - else { - int next8; - - if (wps->wvbits.bc < 8) { - if (++(wps->wvbits.ptr) == wps->wvbits.end) - wps->wvbits.wrap (&wps->wvbits); - - next8 = (wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc) & 0xff; - wps->wvbits.bc += 8; - } - else - next8 = wps->wvbits.sr & 0xff; - - if (next8 == 0xff) { - wps->wvbits.bc -= 8; - wps->wvbits.sr >>= 8; - - for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count); - - if (ones_count == (LIMIT_ONES + 1)) - break; - - if (ones_count == LIMIT_ONES) { - ulong mask; - int cbits; - - for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); - - if (cbits == 33) - break; - - if (cbits < 2) - ones_count = cbits; - else { - for (mask = 1, ones_count = 0; --cbits; mask <<= 1) - if (getbit (&wps->wvbits)) - ones_count |= mask; - - ones_count |= mask; - } - - ones_count += LIMIT_ONES; - } - } - else { - wps->wvbits.bc -= (ones_count = ones_count_table [next8]) + 1; - wps->wvbits.sr >>= ones_count + 1; - } - - 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) && (nchans == 1 || (nsamples & 1))) - 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 (!c->error_limit) - mid = read_code (&wps->wvbits, high - low) + low; - else while (high - low > c->error_limit) { - if (getbit (&wps->wvbits)) - mid = (high + (low = mid) + 1) >> 1; - else - mid = ((high = mid - 1) + low + 1) >> 1; - } - - *bptr++ = getbit (&wps->wvbits) ? ~mid : mid; - - if (wps->wphdr.flags & HYBRID_BITRATE) - c->slow_level = c->slow_level - ((c->slow_level + SLO) >> SLS) + mylog2 (mid); + 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; + + if (!(flags & MONO_FLAG)) + c = w->c + (csamples & 1); + + if (!(w->c [0].median [0] & ~1) && !w->holding_zero && !w->holding_one && !(w->c [1].median [0] & ~1)) { + ulong mask; + int cbits; + + if (w->zeros_acc) { + if (--w->zeros_acc) { + c->slow_level -= (c->slow_level + SLO) >> SLS; + *buffer++ = 0; + continue; + } + } + else { + for (cbits = 0; cbits < 33 && getbit (bs); ++cbits); + + if (cbits == 33) + break; + + if (cbits < 2) + w->zeros_acc = cbits; + else { + for (mask = 1, w->zeros_acc = 0; --cbits; mask <<= 1) + if (getbit (bs)) + w->zeros_acc |= mask; + + w->zeros_acc |= mask; + } + + if (w->zeros_acc) { + c->slow_level -= (c->slow_level + SLO) >> SLS; + CLEAR (w->c [0].median); + CLEAR (w->c [1].median); + *buffer++ = 0; + continue; + } + } + } + + if (w->holding_zero) + ones_count = w->holding_zero = 0; + else { + int next8; + + if (bs->bc < 8) { + if (++(bs->ptr) == bs->end) + bs->wrap (bs); + + next8 = (bs->sr |= *(bs->ptr) << bs->bc) & 0xff; + bs->bc += 8; + } + else + next8 = bs->sr & 0xff; + + if (next8 == 0xff) { + bs->bc -= 8; + bs->sr >>= 8; + + for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count); + + if (ones_count == (LIMIT_ONES + 1)) + break; + + if (ones_count == LIMIT_ONES) { + ulong mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (bs); ++cbits); + + if (cbits == 33) + break; + + if (cbits < 2) + ones_count = cbits; + else { + for (mask = 1, ones_count = 0; --cbits; mask <<= 1) + if (getbit (bs)) + ones_count |= mask; + + ones_count |= mask; + } + + ones_count += LIMIT_ONES; + } + } + else { + bs->bc -= (ones_count = ones_count_table [next8]) + 1; + bs->sr >>= ones_count + 1; + } + + if (w->holding_one) { + w->holding_one = ones_count & 1; + ones_count = (ones_count >> 1) + 1; + } + else { + w->holding_one = ones_count & 1; + ones_count >>= 1; + } + + w->holding_zero = ~w->holding_one & 1; + } + + if ((flags & HYBRID_FLAG) && ((flags & MONO_FLAG) || !(csamples & 1))) + update_error_limit (w, flags); + + 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 (!c->error_limit) + mid = read_code (bs, high - low) + low; + else while (high - low > c->error_limit) { + if (getbit (bs)) + mid = (high + (low = mid) + 1) >> 1; + else + mid = ((high = mid - 1) + low + 1) >> 1; + } + + *buffer++ = getbit (bs) ? ~mid : mid; + + if (flags & HYBRID_BITRATE) + 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 @@ -457,21 +521,195 @@ static ulong read_code (Bitstream *bs, ulong maxcode) ulong extras = (1L << bitcount) - maxcode - 1, code; if (!bitcount) - return 0; + return 0; getbits (&code, bitcount - 1, bs); code &= (1L << (bitcount - 1)) - 1; if (code >= extras) { - code = (code << 1) - extras; + code = (code << 1) - extras; - if (getbit (bs)) - ++code; + if (getbit (bs)) + ++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 // 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 @@ -492,21 +730,30 @@ static int mylog2 (unsigned long avalue) int dbits; if ((avalue += avalue >> 9) < (1 << 8)) { - dbits = nbits_table [avalue]; - return (dbits << 8) + log2_table [(avalue << (9 - dbits)) & 0xff]; + 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]; + 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 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 // 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 @@ -517,26 +764,39 @@ long exp2s (int log) ulong value; if (log < 0) - return -exp2s (-log); + return -exp2s (-log); value = exp2_table [log & 0xff] | 0x100; if ((log >>= 8) <= 9) - return value >> (9 - log); + return value >> (9 - log); else - return value << (log - 9); + 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. +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 result; if ((result = (int) weight << 3) > 0) - result += (result + 64) >> 7; + result += (result + 64) >> 7; return result; } diff --git a/apps/codecs/libwavpack/wputils.c b/apps/codecs/libwavpack/wputils.c index 8d58b3b4d7..7f2ab14c44 100644 --- a/apps/codecs/libwavpack/wputils.c +++ b/apps/codecs/libwavpack/wputils.c @@ -1,8 +1,8 @@ //////////////////////////////////////////////////////////////////////////// -// **** WAVPACK **** // -// Hybrid Lossless Wavefile Compressor // -// Copyright (c) 1998 - 2004 Conifer Software. // -// All Rights Reserved. // +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2004 Conifer Software. // +// All Rights Reserved. // // Distributed under the BSD Software License (see license.txt) // //////////////////////////////////////////////////////////////////////////// @@ -19,7 +19,7 @@ #include -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 //////////////////////////// @@ -29,7 +29,7 @@ const ulong sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050, ///////////////////////////// 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 @@ -62,27 +62,27 @@ WavpackContext *WavpackOpenFileInput (read_stream infile, char *error) while (!wps->wphdr.block_samples) { - bcount = read_next_header (wpc.infile, &wps->wphdr); + bcount = read_next_header (wpc.infile, &wps->wphdr); - if (bcount == (ulong) -1) { - strcpy_loc (error, "invalid WavPack file!"); - return NULL; - } + if (bcount == (ulong) -1) { + strcpy_loc (error, "invalid WavPack file!"); + return NULL; + } - if ((wps->wphdr.flags & UNKNOWN_FLAGS) || wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { - strcpy_loc (error, "invalid WavPack file!"); - return NULL; - } + if ((wps->wphdr.flags & UNKNOWN_FLAGS) || wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { + strcpy_loc (error, "invalid WavPack file!"); + return NULL; + } - if (wps->wphdr.block_samples && wps->wphdr.total_samples != (ulong) -1) - wpc.total_samples = wps->wphdr.total_samples; + if (wps->wphdr.block_samples && wps->wphdr.total_samples != (ulong) -1) + wpc.total_samples = wps->wphdr.total_samples; - if (!unpack_init (&wpc)) { - strcpy_loc (error, wpc.error_message [0] ? wpc.error_message : - "invalid WavPack file!"); + if (!unpack_init (&wpc)) { + strcpy_loc (error, wpc.error_message [0] ? wpc.error_message : + "invalid WavPack file!"); - return NULL; - } + return NULL; + } } wpc.config.flags &= ~0xff; @@ -91,22 +91,22 @@ WavpackContext *WavpackOpenFileInput (read_stream infile, char *error) 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); + ((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 (!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; + 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; + wpc.reduced_channels = (wps->wphdr.flags & MONO_FLAG) ? 1 : 2; return &wpc; } @@ -125,22 +125,22 @@ 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->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->lossy_blocks) + mode &= ~MODE_LOSSLESS; - if (wpc->config.flags & CONFIG_FLOAT_DATA) - mode |= MODE_FLOAT; + 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_HIGH_FLAG) + mode |= MODE_HIGH; - if (wpc->config.flags & CONFIG_FAST_FLAG) - mode |= MODE_FAST; + if (wpc->config.flags & CONFIG_FAST_FLAG) + mode |= MODE_FAST; } return mode; @@ -163,70 +163,70 @@ ulong WavpackUnpackSamples (WavpackContext *wpc, long *buffer, ulong samples) 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 (!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 (bcount == (ulong) -1) + break; - if (wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { - strcpy_loc (wpc->error_message, "invalid WavPack file!"); - break; - } + if (wps->wphdr.version < 0x402 || wps->wphdr.version > 0x40f) { + strcpy_loc (wpc->error_message, "invalid 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->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->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 (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; + if (samples_to_unpack > samples) + samples_to_unpack = samples; - wps->sample_index += samples_to_unpack; - samples_unpacked += samples_to_unpack; - samples -= samples_to_unpack; + 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; + if (wpc->reduced_channels) + samples_to_unpack *= wpc->reduced_channels; + else + samples_to_unpack *= num_channels; - while (samples_to_unpack--) - *buffer++ = 0; + while (samples_to_unpack--) + *buffer++ = 0; - continue; - } + continue; + } - samples_to_unpack = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; + samples_to_unpack = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; - if (samples_to_unpack > samples) - samples_to_unpack = samples; + if (samples_to_unpack > samples) + samples_to_unpack = samples; - unpack_samples (wpc, buffer, samples_to_unpack); + 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; + 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; + 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 == wps->wphdr.block_index + wps->wphdr.block_samples) { + if (check_crc_error (wpc)) + wpc->crc_errors++; + } - if (wps->sample_index == wpc->total_samples) - break; + if (wps->sample_index == wpc->total_samples) + break; } return samples_unpacked; @@ -244,7 +244,7 @@ ulong WavpackGetNumSamples (WavpackContext *wpc) ulong WavpackGetSampleIndex (WavpackContext *wpc) { if (wpc) - return wpc->stream.sample_index; + return wpc->stream.sample_index; return (ulong) -1; } @@ -310,9 +310,9 @@ int WavpackGetBytesPerSample (WavpackContext *wpc) int WavpackGetReducedChannels (WavpackContext *wpc) { if (wpc) - return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels; + return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels; else - return 2; + return 2; } // Read from current file position until a valid 32-byte WavPack 4.0 header is @@ -328,29 +328,228 @@ static ulong read_next_header (read_stream infile, WavpackHeader *wphdr) 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; + 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; } } + +// 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; +} + -- cgit v1.2.3