cog/Frameworks/WavPack/Files/float.c

372 lines
8.8 KiB
C
Raw Normal View History

2006-04-21 20:43:47 +00:00
////////////////////////////////////////////////////////////////////////////
// **** 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;
}
}
#endif
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++;
}
}