2016-08-28 20:03:54 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// **** WAVPACK **** //
|
|
|
|
// Hybrid Lossless Wavefile Compressor //
|
|
|
|
// Copyright (c) 1998 - 2013 Conifer Software. //
|
|
|
|
// All Rights Reserved. //
|
|
|
|
// Distributed under the BSD Software License (see license.txt) //
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// write_words.c
|
|
|
|
|
|
|
|
// This module provides entropy word encoding functions using
|
|
|
|
// a variation on the Rice method. This was introduced in version 3.93
|
|
|
|
// because it allows splitting the data into a "lossy" stream and a
|
|
|
|
// "correction" stream in a very efficient manner and is therefore ideal
|
|
|
|
// for the "hybrid" mode. For 4.0, the efficiency of this method was
|
|
|
|
// significantly improved by moving away from the normal Rice restriction of
|
|
|
|
// using powers of two for the modulus divisions and now the method can be
|
|
|
|
// used for both hybrid and pure lossless encoding.
|
|
|
|
|
|
|
|
// Samples are divided by median probabilities at 5/7 (71.43%), 10/49 (20.41%),
|
|
|
|
// and 20/343 (5.83%). Each zone has 3.5 times fewer samples than the
|
|
|
|
// previous. Using standard Rice coding on this data would result in 1.4
|
|
|
|
// bits per sample average (not counting sign bit). However, there is a
|
|
|
|
// very simple encoding that is over 99% efficient with this data and
|
|
|
|
// results in about 1.22 bits per sample.
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "wavpack_local.h"
|
|
|
|
|
|
|
|
///////////////////////////// executable code ////////////////////////////////
|
|
|
|
|
|
|
|
// Initialize entropy encoder for the specified stream. In lossless mode there
|
|
|
|
// are no parameters to select; in hybrid mode the bitrate mode and value need
|
|
|
|
// be initialized.
|
|
|
|
|
|
|
|
static void word_set_bitrate (WavpackStream *wps);
|
|
|
|
|
|
|
|
void init_words (WavpackStream *wps)
|
|
|
|
{
|
|
|
|
CLEAR (wps->w);
|
|
|
|
|
|
|
|
if (wps->wphdr.flags & HYBRID_FLAG)
|
|
|
|
word_set_bitrate (wps);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up parameters for hybrid mode based on header flags and "bits" field.
|
|
|
|
// This is currently only set up for the HYBRID_BITRATE mode in which the
|
|
|
|
// allowed error varies with the residual level (from "slow_level"). The
|
|
|
|
// simpler mode (which is not used yet) has the error level directly
|
|
|
|
// controlled from the metadata.
|
|
|
|
|
|
|
|
static void word_set_bitrate (WavpackStream *wps)
|
|
|
|
{
|
|
|
|
int bitrate_0, bitrate_1;
|
|
|
|
|
|
|
|
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
|
|
|
if (wps->wphdr.flags & FALSE_STEREO)
|
|
|
|
bitrate_0 = (wps->bits * 2 - 512) < 568 ? 0 : (wps->bits * 2 - 512) - 568;
|
|
|
|
else
|
|
|
|
bitrate_0 = wps->bits < 568 ? 0 : wps->bits - 568;
|
|
|
|
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA)) {
|
|
|
|
|
|
|
|
if (wps->wphdr.flags & HYBRID_BALANCE)
|
|
|
|
bitrate_1 = (wps->wphdr.flags & JOINT_STEREO) ? 256 : 0;
|
|
|
|
else {
|
|
|
|
bitrate_1 = bitrate_0;
|
|
|
|
|
|
|
|
if (wps->wphdr.flags & JOINT_STEREO) {
|
|
|
|
if (bitrate_0 < 128) {
|
|
|
|
bitrate_1 += bitrate_0;
|
|
|
|
bitrate_0 = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bitrate_0 -= 128;
|
|
|
|
bitrate_1 += 128;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
bitrate_1 = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
bitrate_0 = bitrate_1 = 0;
|
|
|
|
|
|
|
|
wps->w.bitrate_acc [0] = (int32_t) bitrate_0 << 16;
|
|
|
|
wps->w.bitrate_acc [1] = (int32_t) bitrate_1 << 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocates the correct space in the metadata structure and writes the
|
|
|
|
// current median values to it. Values are converted from 32-bit unsigned
|
|
|
|
// to our internal 16-bit wp_log2 values, and read_entropy_vars () is called
|
|
|
|
// to read the values back because we must compensate for the loss through
|
|
|
|
// the log function.
|
|
|
|
|
|
|
|
void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd)
|
|
|
|
{
|
|
|
|
unsigned char *byteptr;
|
|
|
|
int temp;
|
|
|
|
|
|
|
|
byteptr = wpmd->data = malloc (12);
|
|
|
|
wpmd->id = ID_ENTROPY_VARS;
|
|
|
|
|
|
|
|
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [0]);
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [1]);
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [2]);
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA)) {
|
|
|
|
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [0]);
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [1]);
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [2]);
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data);
|
|
|
|
read_entropy_vars (wps, wpmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocates enough space in the metadata structure and writes the current
|
|
|
|
// high word of the bitrate accumulator and the slow_level values to it. The
|
|
|
|
// slow_level values are converted from 32-bit unsigned to our internal 16-bit
|
|
|
|
// wp_log2 values. Afterward, read_entropy_vars () is called to read the values
|
|
|
|
// back because we must compensate for the loss through the log function and
|
|
|
|
// the truncation of the bitrate.
|
|
|
|
|
|
|
|
void write_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd)
|
|
|
|
{
|
|
|
|
unsigned char *byteptr;
|
|
|
|
int temp;
|
|
|
|
|
|
|
|
word_set_bitrate (wps);
|
|
|
|
byteptr = wpmd->data = malloc (512);
|
|
|
|
wpmd->id = ID_HYBRID_PROFILE;
|
|
|
|
|
|
|
|
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
|
|
|
*byteptr++ = temp = wp_log2s (wps->w.c [0].slow_level);
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA)) {
|
|
|
|
*byteptr++ = temp = wp_log2s (wps->w.c [1].slow_level);
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*byteptr++ = temp = wps->w.bitrate_acc [0] >> 16;
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA)) {
|
|
|
|
*byteptr++ = temp = wps->w.bitrate_acc [1] >> 16;
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wps->w.bitrate_delta [0] | wps->w.bitrate_delta [1]) {
|
|
|
|
*byteptr++ = temp = wp_log2s (wps->w.bitrate_delta [0]);
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA)) {
|
|
|
|
*byteptr++ = temp = wp_log2s (wps->w.bitrate_delta [1]);
|
|
|
|
*byteptr++ = temp >> 8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data);
|
|
|
|
read_hybrid_profile (wps, wpmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function writes the specified word to the open bitstream "wvbits" and,
|
|
|
|
// if the bitstream "wvcbits" is open, writes any correction data there. This
|
|
|
|
// function will work for either lossless or hybrid but because a version
|
|
|
|
// optimized for lossless exits below, it would normally be used for the hybrid
|
|
|
|
// mode only. The return value is the actual value stored to the stream (even
|
|
|
|
// if a correction file is being created) and is used as feedback to the
|
|
|
|
// predictor.
|
|
|
|
|
|
|
|
int32_t FASTCALL send_word (WavpackStream *wps, int32_t value, int chan)
|
|
|
|
{
|
|
|
|
struct entropy_data *c = wps->w.c + chan;
|
|
|
|
uint32_t ones_count, low, mid, high;
|
|
|
|
int sign = (value < 0) ? 1 : 0;
|
|
|
|
|
|
|
|
if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) {
|
|
|
|
if (wps->w.zeros_acc) {
|
|
|
|
if (value)
|
|
|
|
flush_word (wps);
|
|
|
|
else {
|
|
|
|
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
|
|
|
wps->w.zeros_acc++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (value)
|
|
|
|
putbit_0 (&wps->wvbits);
|
|
|
|
else {
|
|
|
|
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
|
|
|
CLEAR (wps->w.c [0].median);
|
|
|
|
CLEAR (wps->w.c [1].median);
|
|
|
|
wps->w.zeros_acc = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sign)
|
|
|
|
value = ~value;
|
|
|
|
|
|
|
|
if ((wps->wphdr.flags & HYBRID_FLAG) && !chan)
|
|
|
|
update_error_limit (wps);
|
|
|
|
|
|
|
|
if (value < (int32_t) GET_MED (0)) {
|
|
|
|
ones_count = low = 0;
|
|
|
|
high = GET_MED (0) - 1;
|
|
|
|
DEC_MED0 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low = GET_MED (0);
|
|
|
|
INC_MED0 ();
|
|
|
|
|
|
|
|
if (value - low < GET_MED (1)) {
|
|
|
|
ones_count = 1;
|
|
|
|
high = low + GET_MED (1) - 1;
|
|
|
|
DEC_MED1 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low += GET_MED (1);
|
|
|
|
INC_MED1 ();
|
|
|
|
|
|
|
|
if (value - low < GET_MED (2)) {
|
|
|
|
ones_count = 2;
|
|
|
|
high = low + GET_MED (2) - 1;
|
|
|
|
DEC_MED2 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ones_count = 2 + (value - low) / GET_MED (2);
|
|
|
|
low += (ones_count - 2) * GET_MED (2);
|
|
|
|
high = low + GET_MED (2) - 1;
|
|
|
|
INC_MED2 ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mid = (high + low + 1) >> 1;
|
|
|
|
|
|
|
|
if (wps->w.holding_zero) {
|
|
|
|
if (ones_count)
|
|
|
|
wps->w.holding_one++;
|
|
|
|
|
|
|
|
flush_word (wps);
|
|
|
|
|
|
|
|
if (ones_count) {
|
|
|
|
wps->w.holding_zero = 1;
|
|
|
|
ones_count--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
wps->w.holding_zero = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
wps->w.holding_zero = 1;
|
|
|
|
|
|
|
|
wps->w.holding_one = ones_count * 2;
|
|
|
|
|
|
|
|
if (!c->error_limit) {
|
|
|
|
if (high != low) {
|
|
|
|
uint32_t maxcode = high - low, code = value - low;
|
|
|
|
int bitcount = count_bits (maxcode);
|
|
|
|
uint32_t extras = bitset [bitcount] - maxcode - 1;
|
|
|
|
|
|
|
|
if (code < extras) {
|
|
|
|
wps->w.pend_data |= code << wps->w.pend_count;
|
|
|
|
wps->w.pend_count += bitcount - 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count;
|
|
|
|
wps->w.pend_count += bitcount - 1;
|
|
|
|
wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mid = value;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
while (high - low > c->error_limit)
|
|
|
|
if (value < (int32_t) mid) {
|
|
|
|
mid = ((high = mid - 1) + low + 1) >> 1;
|
|
|
|
wps->w.pend_count++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mid = (high + (low = mid) + 1) >> 1;
|
|
|
|
wps->w.pend_data |= bitset [wps->w.pend_count++];
|
|
|
|
}
|
|
|
|
|
|
|
|
wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++);
|
|
|
|
|
|
|
|
if (!wps->w.holding_zero)
|
|
|
|
flush_word (wps);
|
|
|
|
|
|
|
|
if (bs_is_open (&wps->wvcbits) && c->error_limit) {
|
|
|
|
uint32_t code = value - low, maxcode = high - low;
|
|
|
|
int bitcount = count_bits (maxcode);
|
|
|
|
uint32_t extras = bitset [bitcount] - maxcode - 1;
|
|
|
|
|
|
|
|
if (bitcount) {
|
|
|
|
if (code < extras)
|
|
|
|
putbits (code, bitcount - 1, &wps->wvcbits);
|
|
|
|
else {
|
|
|
|
putbits ((code + extras) >> 1, bitcount - 1, &wps->wvcbits);
|
|
|
|
putbit ((code + extras) & 1, &wps->wvcbits);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
|
|
|
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
|
|
|
c->slow_level += wp_log2 (mid);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sign ? ~mid : mid;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is an optimized version of send_word() that only handles
|
|
|
|
// lossless (error_limit == 0) and sends an entire buffer of either mono or
|
|
|
|
// stereo data rather than a single sample. Unlike the generalized
|
|
|
|
// send_word(), it does not return values because it always encodes
|
|
|
|
// the exact value passed.
|
|
|
|
|
|
|
|
void send_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples)
|
|
|
|
{
|
|
|
|
struct entropy_data *c = wps->w.c;
|
|
|
|
int32_t value, csamples;
|
|
|
|
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA))
|
|
|
|
nsamples *= 2;
|
|
|
|
|
|
|
|
for (csamples = 0; csamples < nsamples; ++csamples) {
|
|
|
|
int sign = ((value = *buffer++) < 0) ? 1 : 0;
|
|
|
|
uint32_t ones_count, low, high;
|
|
|
|
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA))
|
|
|
|
c = wps->w.c + (csamples & 1);
|
|
|
|
|
|
|
|
if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) {
|
|
|
|
if (wps->w.zeros_acc) {
|
|
|
|
if (value)
|
|
|
|
flush_word (wps);
|
|
|
|
else {
|
|
|
|
wps->w.zeros_acc++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (value)
|
|
|
|
putbit_0 (&wps->wvbits);
|
|
|
|
else {
|
|
|
|
CLEAR (wps->w.c [0].median);
|
|
|
|
CLEAR (wps->w.c [1].median);
|
|
|
|
wps->w.zeros_acc = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sign)
|
|
|
|
value = ~value;
|
|
|
|
|
|
|
|
if (value < (int32_t) GET_MED (0)) {
|
|
|
|
ones_count = low = 0;
|
|
|
|
high = GET_MED (0) - 1;
|
|
|
|
DEC_MED0 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low = GET_MED (0);
|
|
|
|
INC_MED0 ();
|
|
|
|
|
|
|
|
if (value - low < GET_MED (1)) {
|
|
|
|
ones_count = 1;
|
|
|
|
high = low + GET_MED (1) - 1;
|
|
|
|
DEC_MED1 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low += GET_MED (1);
|
|
|
|
INC_MED1 ();
|
|
|
|
|
|
|
|
if (value - low < GET_MED (2)) {
|
|
|
|
ones_count = 2;
|
|
|
|
high = low + GET_MED (2) - 1;
|
|
|
|
DEC_MED2 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ones_count = 2 + (value - low) / GET_MED (2);
|
|
|
|
low += (ones_count - 2) * GET_MED (2);
|
|
|
|
high = low + GET_MED (2) - 1;
|
|
|
|
INC_MED2 ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wps->w.holding_zero) {
|
|
|
|
if (ones_count)
|
|
|
|
wps->w.holding_one++;
|
|
|
|
|
|
|
|
flush_word (wps);
|
|
|
|
|
|
|
|
if (ones_count) {
|
|
|
|
wps->w.holding_zero = 1;
|
|
|
|
ones_count--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
wps->w.holding_zero = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
wps->w.holding_zero = 1;
|
|
|
|
|
|
|
|
wps->w.holding_one = ones_count * 2;
|
|
|
|
|
|
|
|
if (high != low) {
|
|
|
|
uint32_t maxcode = high - low, code = value - low;
|
|
|
|
int bitcount = count_bits (maxcode);
|
|
|
|
uint32_t extras = bitset [bitcount] - maxcode - 1;
|
|
|
|
|
|
|
|
if (code < extras) {
|
|
|
|
wps->w.pend_data |= code << wps->w.pend_count;
|
|
|
|
wps->w.pend_count += bitcount - 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count;
|
|
|
|
wps->w.pend_count += bitcount - 1;
|
|
|
|
wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++);
|
|
|
|
|
|
|
|
if (!wps->w.holding_zero)
|
|
|
|
flush_word (wps);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Used by send_word() and send_word_lossless() to actually send most the
|
|
|
|
// accumulated data onto the bitstream. This is also called directly from
|
|
|
|
// clients when all words have been sent.
|
|
|
|
|
|
|
|
void flush_word (WavpackStream *wps)
|
|
|
|
{
|
|
|
|
if (wps->w.zeros_acc) {
|
|
|
|
int cbits = count_bits (wps->w.zeros_acc);
|
|
|
|
|
|
|
|
while (cbits--)
|
|
|
|
putbit_1 (&wps->wvbits);
|
|
|
|
|
|
|
|
putbit_0 (&wps->wvbits);
|
|
|
|
|
|
|
|
while (wps->w.zeros_acc > 1) {
|
|
|
|
putbit (wps->w.zeros_acc & 1, &wps->wvbits);
|
|
|
|
wps->w.zeros_acc >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
wps->w.zeros_acc = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wps->w.holding_one) {
|
|
|
|
#ifdef LIMIT_ONES
|
|
|
|
if (wps->w.holding_one >= LIMIT_ONES) {
|
|
|
|
int cbits;
|
|
|
|
|
|
|
|
putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, &wps->wvbits);
|
|
|
|
wps->w.holding_one -= LIMIT_ONES;
|
|
|
|
cbits = count_bits (wps->w.holding_one);
|
|
|
|
|
|
|
|
while (cbits--)
|
|
|
|
putbit_1 (&wps->wvbits);
|
|
|
|
|
|
|
|
putbit_0 (&wps->wvbits);
|
|
|
|
|
|
|
|
while (wps->w.holding_one > 1) {
|
|
|
|
putbit (wps->w.holding_one & 1, &wps->wvbits);
|
|
|
|
wps->w.holding_one >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
wps->w.holding_zero = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
putbits (bitmask [wps->w.holding_one], wps->w.holding_one, &wps->wvbits);
|
|
|
|
|
|
|
|
wps->w.holding_one = 0;
|
|
|
|
#else
|
|
|
|
do {
|
|
|
|
putbit_1 (&wps->wvbits);
|
|
|
|
} while (--wps->w.holding_one);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wps->w.holding_zero) {
|
|
|
|
putbit_0 (&wps->wvbits);
|
|
|
|
wps->w.holding_zero = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (wps->w.pend_count) {
|
|
|
|
putbits (wps->w.pend_data, wps->w.pend_count, &wps->wvbits);
|
|
|
|
wps->w.pend_data = wps->w.pend_count = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is similar to send_word() except that no data is actually
|
|
|
|
// written to any stream, but it does return the value that would have been
|
|
|
|
// sent to a hybrid stream. It is used to determine beforehand how much noise
|
|
|
|
// will be added to samples.
|
|
|
|
|
|
|
|
int32_t nosend_word (WavpackStream *wps, int32_t value, int chan)
|
|
|
|
{
|
|
|
|
struct entropy_data *c = wps->w.c + chan;
|
|
|
|
uint32_t ones_count, low, mid, high;
|
|
|
|
int sign = (value < 0) ? 1 : 0;
|
|
|
|
|
|
|
|
if (sign)
|
|
|
|
value = ~value;
|
|
|
|
|
|
|
|
if ((wps->wphdr.flags & HYBRID_FLAG) && !chan)
|
|
|
|
update_error_limit (wps);
|
|
|
|
|
|
|
|
if (value < (int32_t) GET_MED (0)) {
|
|
|
|
low = 0;
|
|
|
|
high = GET_MED (0) - 1;
|
|
|
|
DEC_MED0 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low = GET_MED (0);
|
|
|
|
INC_MED0 ();
|
|
|
|
|
|
|
|
if (value - low < GET_MED (1)) {
|
|
|
|
high = low + GET_MED (1) - 1;
|
|
|
|
DEC_MED1 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low += GET_MED (1);
|
|
|
|
INC_MED1 ();
|
|
|
|
|
|
|
|
if (value - low < GET_MED (2)) {
|
|
|
|
high = low + GET_MED (2) - 1;
|
|
|
|
DEC_MED2 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ones_count = 2 + (value - low) / GET_MED (2);
|
|
|
|
low += (ones_count - 2) * GET_MED (2);
|
|
|
|
high = low + GET_MED (2) - 1;
|
|
|
|
INC_MED2 ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mid = (high + low + 1) >> 1;
|
|
|
|
|
|
|
|
if (!c->error_limit)
|
|
|
|
mid = value;
|
|
|
|
else
|
|
|
|
while (high - low > c->error_limit)
|
|
|
|
if (value < (int32_t) mid)
|
|
|
|
mid = ((high = mid - 1) + low + 1) >> 1;
|
|
|
|
else
|
|
|
|
mid = (high + (low = mid) + 1) >> 1;
|
|
|
|
|
|
|
|
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
|
|
|
c->slow_level += wp_log2 (mid);
|
|
|
|
|
|
|
|
return sign ? ~mid : mid;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is used to scan some number of samples to set the variables
|
2020-03-22 07:15:45 +00:00
|
|
|
// "slow_level" and the "median" array. In pure symmetrical encoding mode this
|
2016-08-28 20:03:54 +00:00
|
|
|
// would not be needed because these values would simply be continued from the
|
|
|
|
// previous block. However, in the -X modes and the 32-bit modes we cannot do
|
|
|
|
// this because parameters may change between blocks and the variables might
|
|
|
|
// not apply. This function can work in mono or stereo and can scan a block
|
|
|
|
// in either direction.
|
|
|
|
|
2020-03-22 07:15:45 +00:00
|
|
|
static void scan_word_pass (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir)
|
2016-08-28 20:03:54 +00:00
|
|
|
{
|
|
|
|
uint32_t flags = wps->wphdr.flags, value, low;
|
|
|
|
struct entropy_data *c = wps->w.c;
|
|
|
|
int chan;
|
|
|
|
|
|
|
|
if (flags & MONO_DATA) {
|
|
|
|
if (dir < 0) {
|
|
|
|
samples += (num_samples - 1);
|
|
|
|
dir = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
dir = 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (dir < 0) {
|
|
|
|
samples += (num_samples - 1) * 2;
|
|
|
|
dir = -2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
dir = 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (num_samples--) {
|
|
|
|
|
|
|
|
value = labs (samples [chan = 0]);
|
|
|
|
|
|
|
|
if (flags & HYBRID_BITRATE) {
|
|
|
|
wps->w.c [0].slow_level -= (wps->w.c [0].slow_level + SLO) >> SLS;
|
|
|
|
wps->w.c [0].slow_level += wp_log2 (value);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value < GET_MED (0)) {
|
|
|
|
DEC_MED0 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low = GET_MED (0);
|
|
|
|
INC_MED0 ();
|
|
|
|
|
|
|
|
if (value - low < GET_MED (1)) {
|
|
|
|
DEC_MED1 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low += GET_MED (1);
|
|
|
|
INC_MED1 ();
|
|
|
|
|
|
|
|
if (value - low < GET_MED (2)) {
|
|
|
|
DEC_MED2 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
INC_MED2 ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(flags & MONO_DATA)) {
|
|
|
|
value = labs (samples [chan = 1]);
|
|
|
|
c++;
|
|
|
|
|
|
|
|
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
|
|
|
wps->w.c [1].slow_level -= (wps->w.c [1].slow_level + SLO) >> SLS;
|
|
|
|
wps->w.c [1].slow_level += wp_log2 (value);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value < GET_MED (0)) {
|
|
|
|
DEC_MED0 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low = GET_MED (0);
|
|
|
|
INC_MED0 ();
|
|
|
|
|
|
|
|
if (value - low < GET_MED (1)) {
|
|
|
|
DEC_MED1 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low += GET_MED (1);
|
|
|
|
INC_MED1 ();
|
|
|
|
|
|
|
|
if (value - low < GET_MED (2)) {
|
|
|
|
DEC_MED2 ();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
INC_MED2 ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c--;
|
|
|
|
}
|
|
|
|
|
|
|
|
samples += dir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-22 07:15:45 +00:00
|
|
|
// Wrapper for scan_word_pass() than ensures that at least 2048 samples are processed by
|
|
|
|
// potentially making multiple passes through the data. See description of scan_word_pass()
|
|
|
|
// for more details.
|
|
|
|
|
|
|
|
void scan_word (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir)
|
|
|
|
{
|
|
|
|
init_words (wps);
|
|
|
|
|
|
|
|
if (num_samples) {
|
|
|
|
int passes = (2048 + num_samples - 1) / num_samples; // i.e., ceil (2048.0 / num_samples)
|
|
|
|
|
|
|
|
while (passes--)
|
|
|
|
scan_word_pass (wps, samples, num_samples, dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|