372 lines
8.5 KiB
C
372 lines
8.5 KiB
C
////////////////////////////////////////////////////////////////////////////
|
|
// **** WAVPACK **** //
|
|
// Hybrid Lossless Wavefile Compressor //
|
|
// Copyright (c) 1998 - 2005 Conifer Software. //
|
|
// All Rights Reserved. //
|
|
// Distributed under the BSD Software License (see license.txt) //
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// float.c
|
|
|
|
#include "wavpack.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#ifdef DEBUG_ALLOC
|
|
#define malloc malloc_db
|
|
#define realloc realloc_db
|
|
#define free free_db
|
|
void *malloc_db (uint32_t size);
|
|
void *realloc_db (void *ptr, uint32_t size);
|
|
void free_db (void *ptr);
|
|
int32_t dump_alloc (void);
|
|
#endif
|
|
|
|
#ifdef PACK
|
|
|
|
void write_float_info (WavpackStream *wps, WavpackMetadata *wpmd)
|
|
{
|
|
char *byteptr;
|
|
|
|
byteptr = wpmd->data = malloc (4);
|
|
wpmd->id = ID_FLOAT_INFO;
|
|
*byteptr++ = wps->float_flags;
|
|
*byteptr++ = wps->float_shift;
|
|
*byteptr++ = wps->float_max_exp;
|
|
*byteptr++ = wps->float_norm_exp;
|
|
wpmd->byte_length = byteptr - (char *) wpmd->data;
|
|
}
|
|
|
|
int scan_float_data (WavpackStream *wps, f32 *values, int32_t num_values)
|
|
{
|
|
int32_t shifted_ones = 0, shifted_zeros = 0, shifted_both = 0;
|
|
int32_t false_zeros = 0, neg_zeros = 0;
|
|
uint32_t ordata = 0, crc = 0xffffffff;
|
|
int max_exp = 0, shift_count;
|
|
int32_t count, value;
|
|
f32 *dp;
|
|
|
|
wps->float_shift = wps->float_flags = 0;
|
|
|
|
for (dp = values, count = num_values; count--; dp++) {
|
|
crc = crc * 27 + dp->mantissa * 9 + dp->exponent * 3 + dp->sign;
|
|
|
|
if (dp->exponent > max_exp && dp->exponent < 255)
|
|
max_exp = dp->exponent;
|
|
}
|
|
|
|
wps->crc_x = crc;
|
|
|
|
for (dp = values, count = num_values; count--; dp++) {
|
|
if (dp->exponent == 255) {
|
|
wps->float_flags |= FLOAT_EXCEPTIONS;
|
|
value = 0x1000000;
|
|
shift_count = 0;
|
|
}
|
|
else if (dp->exponent) {
|
|
shift_count = max_exp - dp->exponent;
|
|
value = 0x800000 + dp->mantissa;
|
|
}
|
|
else {
|
|
shift_count = max_exp ? max_exp - 1 : 0;
|
|
value = dp->mantissa;
|
|
|
|
// if (dp->mantissa)
|
|
// denormals++;
|
|
}
|
|
|
|
if (shift_count < 25)
|
|
value >>= shift_count;
|
|
else
|
|
value = 0;
|
|
|
|
if (!value) {
|
|
if (dp->exponent || dp->mantissa)
|
|
++false_zeros;
|
|
else if (dp->sign)
|
|
++neg_zeros;
|
|
}
|
|
else if (shift_count) {
|
|
int32_t mask = (1 << shift_count) - 1;
|
|
|
|
if (!(dp->mantissa & mask))
|
|
shifted_zeros++;
|
|
else if ((dp->mantissa & mask) == mask)
|
|
shifted_ones++;
|
|
else
|
|
shifted_both++;
|
|
}
|
|
|
|
ordata |= value;
|
|
* (int32_t *) dp = (dp->sign) ? -value : value;
|
|
}
|
|
|
|
wps->float_max_exp = max_exp;
|
|
|
|
if (shifted_both)
|
|
wps->float_flags |= FLOAT_SHIFT_SENT;
|
|
else if (shifted_ones && !shifted_zeros)
|
|
wps->float_flags |= FLOAT_SHIFT_ONES;
|
|
else if (shifted_ones && shifted_zeros)
|
|
wps->float_flags |= FLOAT_SHIFT_SAME;
|
|
else if (ordata && !(ordata & 1)) {
|
|
while (!(ordata & 1)) {
|
|
wps->float_shift++;
|
|
ordata >>= 1;
|
|
}
|
|
|
|
for (dp = values, count = num_values; count--; dp++)
|
|
* (int32_t *) dp >>= wps->float_shift;
|
|
}
|
|
|
|
wps->wphdr.flags &= ~MAG_MASK;
|
|
|
|
while (ordata) {
|
|
wps->wphdr.flags += 1 << MAG_LSB;
|
|
ordata >>= 1;
|
|
}
|
|
|
|
if (false_zeros || neg_zeros)
|
|
wps->float_flags |= FLOAT_ZEROS_SENT;
|
|
|
|
if (neg_zeros)
|
|
wps->float_flags |= FLOAT_NEG_ZEROS;
|
|
|
|
// error_line ("samples = %d, max exp = %d, pre-shift = %d, denormals = %d",
|
|
// num_values, max_exp, wps->float_shift, denormals);
|
|
// if (wps->float_flags & FLOAT_EXCEPTIONS)
|
|
// error_line ("exceptions!");
|
|
// error_line ("shifted ones/zeros/both = %d/%d/%d, true/neg/false zeros = %d/%d/%d",
|
|
// shifted_ones, shifted_zeros, shifted_both, true_zeros, neg_zeros, false_zeros);
|
|
|
|
return wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME);
|
|
}
|
|
|
|
void send_float_data (WavpackStream *wps, f32 *values, int32_t num_values)
|
|
{
|
|
int max_exp = wps->float_max_exp;
|
|
int32_t count, value, shift_count;
|
|
f32 *dp;
|
|
|
|
for (dp = values, count = num_values; count--; dp++) {
|
|
if (dp->exponent == 255) {
|
|
if (dp->mantissa) {
|
|
putbit_1 (&wps->wvxbits);
|
|
putbits (dp->mantissa, 23, &wps->wvxbits);
|
|
}
|
|
else {
|
|
putbit_0 (&wps->wvxbits);
|
|
}
|
|
|
|
value = 0x1000000;
|
|
shift_count = 0;
|
|
}
|
|
else if (dp->exponent) {
|
|
shift_count = max_exp - dp->exponent;
|
|
value = 0x800000 + dp->mantissa;
|
|
}
|
|
else {
|
|
shift_count = max_exp ? max_exp - 1 : 0;
|
|
value = dp->mantissa;
|
|
}
|
|
|
|
if (shift_count < 25)
|
|
value >>= shift_count;
|
|
else
|
|
value = 0;
|
|
|
|
if (!value) {
|
|
if (wps->float_flags & FLOAT_ZEROS_SENT) {
|
|
if (dp->exponent || dp->mantissa) {
|
|
putbit_1 (&wps->wvxbits);
|
|
putbits (dp->mantissa, 23, &wps->wvxbits);
|
|
|
|
if (max_exp >= 25) {
|
|
putbits (dp->exponent, 8, &wps->wvxbits);
|
|
}
|
|
|
|
putbit (dp->sign, &wps->wvxbits);
|
|
}
|
|
else {
|
|
putbit_0 (&wps->wvxbits);
|
|
|
|
if (wps->float_flags & FLOAT_NEG_ZEROS)
|
|
putbit (dp->sign, &wps->wvxbits);
|
|
}
|
|
}
|
|
}
|
|
else if (shift_count) {
|
|
if (wps->float_flags & FLOAT_SHIFT_SENT) {
|
|
int32_t data = dp->mantissa & ((1 << shift_count) - 1);
|
|
putbits (data, shift_count, &wps->wvxbits);
|
|
}
|
|
else if (wps->float_flags & FLOAT_SHIFT_SAME) {
|
|
putbit (dp->mantissa & 1, &wps->wvxbits);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(UNPACK) || defined(INFO_ONLY)
|
|
|
|
int read_float_info (WavpackStream *wps, WavpackMetadata *wpmd)
|
|
{
|
|
int bytecnt = wpmd->byte_length;
|
|
char *byteptr = wpmd->data;
|
|
|
|
if (bytecnt != 4)
|
|
return FALSE;
|
|
|
|
wps->float_flags = *byteptr++;
|
|
wps->float_shift = *byteptr++;
|
|
wps->float_max_exp = *byteptr++;
|
|
wps->float_norm_exp = *byteptr;
|
|
return TRUE;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef UNPACK
|
|
|
|
static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values);
|
|
|
|
void float_values (WavpackStream *wps, int32_t *values, int32_t num_values)
|
|
{
|
|
uint32_t crc = wps->crc_x;
|
|
|
|
if (!bs_is_open (&wps->wvxbits)) {
|
|
float_values_nowvx (wps, values, num_values);
|
|
return;
|
|
}
|
|
|
|
while (num_values--) {
|
|
int shift_count = 0, exp = wps->float_max_exp;
|
|
f32 outval = { 0, 0, 0 };
|
|
uint32_t temp;
|
|
|
|
if (*values == 0) {
|
|
if (wps->float_flags & FLOAT_ZEROS_SENT) {
|
|
if (getbit (&wps->wvxbits)) {
|
|
getbits (&temp, 23, &wps->wvxbits);
|
|
outval.mantissa = temp;
|
|
|
|
if (exp >= 25) {
|
|
getbits (&temp, 8, &wps->wvxbits);
|
|
outval.exponent = temp;
|
|
}
|
|
|
|
outval.sign = getbit (&wps->wvxbits);
|
|
}
|
|
else if (wps->float_flags & FLOAT_NEG_ZEROS)
|
|
outval.sign = getbit (&wps->wvxbits);
|
|
}
|
|
}
|
|
else {
|
|
*values <<= wps->float_shift;
|
|
|
|
if (*values < 0) {
|
|
*values = -*values;
|
|
outval.sign = 1;
|
|
}
|
|
|
|
if (*values == 0x1000000) {
|
|
if (getbit (&wps->wvxbits)) {
|
|
getbits (&temp, 23, &wps->wvxbits);
|
|
outval.mantissa = temp;
|
|
}
|
|
|
|
outval.exponent = 255;
|
|
}
|
|
else {
|
|
if (exp)
|
|
while (!(*values & 0x800000) && --exp) {
|
|
shift_count++;
|
|
*values <<= 1;
|
|
}
|
|
|
|
if (shift_count) {
|
|
if ((wps->float_flags & FLOAT_SHIFT_ONES) ||
|
|
((wps->float_flags & FLOAT_SHIFT_SAME) && getbit (&wps->wvxbits)))
|
|
*values |= ((1 << shift_count) - 1);
|
|
else if (wps->float_flags & FLOAT_SHIFT_SENT) {
|
|
getbits (&temp, shift_count, &wps->wvxbits);
|
|
*values |= temp & ((1 << shift_count) - 1);
|
|
}
|
|
}
|
|
|
|
outval.mantissa = *values;
|
|
outval.exponent = exp;
|
|
}
|
|
}
|
|
|
|
crc = crc * 27 + outval.mantissa * 9 + outval.exponent * 3 + outval.sign;
|
|
* (f32 *) values++ = outval;
|
|
}
|
|
|
|
wps->crc_x = crc;
|
|
}
|
|
|
|
static void float_values_nowvx (WavpackStream *wps, int32_t *values, int32_t num_values)
|
|
{
|
|
while (num_values--) {
|
|
int shift_count = 0, exp = wps->float_max_exp;
|
|
f32 outval = { 0, 0, 0 };
|
|
|
|
if (*values) {
|
|
*values <<= wps->float_shift;
|
|
|
|
if (*values < 0) {
|
|
*values = -*values;
|
|
outval.sign = 1;
|
|
}
|
|
|
|
if (*values >= 0x1000000) {
|
|
while (*values & 0xf000000) {
|
|
*values >>= 1;
|
|
++exp;
|
|
}
|
|
}
|
|
else if (exp) {
|
|
while (!(*values & 0x800000) && --exp) {
|
|
shift_count++;
|
|
*values <<= 1;
|
|
}
|
|
|
|
if (shift_count && (wps->float_flags & FLOAT_SHIFT_ONES))
|
|
*values |= ((1 << shift_count) - 1);
|
|
}
|
|
|
|
outval.mantissa = *values;
|
|
outval.exponent = exp;
|
|
}
|
|
|
|
* (f32 *) values++ = outval;
|
|
}
|
|
}
|
|
|
|
void float_normalize (int32_t *values, int32_t num_values, int delta_exp)
|
|
{
|
|
f32 *fvalues = (f32 *) values, fzero = { 0, 0, 0 };
|
|
int exp;
|
|
|
|
if (!delta_exp)
|
|
return;
|
|
|
|
while (num_values--) {
|
|
if ((exp = fvalues->exponent) == 0 || exp + delta_exp <= 0)
|
|
*fvalues = fzero;
|
|
else if (exp == 255 || (exp += delta_exp) >= 255) {
|
|
fvalues->exponent = 255;
|
|
fvalues->mantissa = 0;
|
|
}
|
|
else
|
|
fvalues->exponent = exp;
|
|
|
|
fvalues++;
|
|
}
|
|
}
|
|
|
|
#endif
|