205 lines
7.5 KiB
C
205 lines
7.5 KiB
C
////////////////////////////////////////////////////////////////////////////
|
|
// **** WAVPACK **** //
|
|
// Hybrid Lossless Wavefile Compressor //
|
|
// Copyright (c) 1998 - 2013 Conifer Software. //
|
|
// All Rights Reserved. //
|
|
// Distributed under the BSD Software License (see license.txt) //
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// decorr_utils.c
|
|
|
|
// This module contains the functions that process metadata blocks that are
|
|
// specific to the decorrelator. These would be called any time a WavPack
|
|
// block was parsed. These are in a module separate from the actual unpack
|
|
// decorrelation code (unpack.c) so that if an application just wants to get
|
|
// information from WavPack files (rather than actually decoding audio) then
|
|
// less code needs to be linked.
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "wavpack_local.h"
|
|
|
|
///////////////////////////// executable code ////////////////////////////////
|
|
|
|
// Read decorrelation terms from specified metadata block into the
|
|
// decorr_passes array. The terms range from -3 to 8, plus 17 & 18;
|
|
// other values are reserved and generate errors for now. The delta
|
|
// ranges from 0 to 7 with all values valid. Note that the terms are
|
|
// stored in the opposite order in the decorr_passes array compared
|
|
// to packing.
|
|
|
|
int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd)
|
|
{
|
|
int termcnt = wpmd->byte_length;
|
|
unsigned char *byteptr = wpmd->data;
|
|
struct decorr_pass *dpp;
|
|
|
|
if (termcnt > MAX_NTERMS)
|
|
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;
|
|
|
|
if (!dpp->term || dpp->term < -3 || (dpp->term > MAX_TERM && dpp->term < 17) || dpp->term > 18 ||
|
|
((wps->wphdr.flags & MONO_DATA) && dpp->term < 0))
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Read decorrelation weights from specified metadata block into the
|
|
// decorr_passes array. The weights range +/-1024, but are rounded and
|
|
// truncated to fit in signed chars for metadata storage. Weights are
|
|
// separate for the two channels and are specified from the "last" term
|
|
// (first during encode). Unspecified weights are set to zero.
|
|
|
|
int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd)
|
|
{
|
|
int termcnt = wpmd->byte_length, tcount;
|
|
char *byteptr = wpmd->data;
|
|
struct decorr_pass *dpp;
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA))
|
|
termcnt /= 2;
|
|
|
|
if (termcnt > wps->num_terms)
|
|
return FALSE;
|
|
|
|
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
|
|
dpp->weight_A = dpp->weight_B = 0;
|
|
|
|
while (--dpp >= wps->decorr_passes && termcnt--) {
|
|
dpp->weight_A = restore_weight (*byteptr++);
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA))
|
|
dpp->weight_B = restore_weight (*byteptr++);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// Read decorrelation samples from specified metadata block into the
|
|
// decorr_passes array. 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 "last" term
|
|
// (first during encode) with unspecified samples set to zero. The
|
|
// number of samples stored varies with the actual term value, so
|
|
// those must obviously come first in the metadata.
|
|
|
|
int read_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd)
|
|
{
|
|
unsigned char *byteptr = wpmd->data;
|
|
unsigned char *endptr = byteptr + wpmd->byte_length;
|
|
struct decorr_pass *dpp;
|
|
int tcount;
|
|
|
|
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
|
|
CLEAR (dpp->samples_A);
|
|
CLEAR (dpp->samples_B);
|
|
}
|
|
|
|
if (wps->wphdr.version == 0x402 && (wps->wphdr.flags & HYBRID_FLAG)) {
|
|
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr)
|
|
return FALSE;
|
|
|
|
wps->dc.error [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
|
byteptr += 2;
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA)) {
|
|
wps->dc.error [1] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
|
byteptr += 2;
|
|
}
|
|
}
|
|
|
|
while (dpp-- > wps->decorr_passes && byteptr < endptr)
|
|
if (dpp->term > MAX_TERM) {
|
|
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 4 : 8) > endptr)
|
|
return FALSE;
|
|
|
|
dpp->samples_A [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
|
dpp->samples_A [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
|
byteptr += 4;
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA)) {
|
|
dpp->samples_B [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
|
dpp->samples_B [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
|
byteptr += 4;
|
|
}
|
|
}
|
|
else if (dpp->term < 0) {
|
|
if (byteptr + 4 > endptr)
|
|
return FALSE;
|
|
|
|
dpp->samples_A [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
|
dpp->samples_B [0] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
|
byteptr += 4;
|
|
}
|
|
else {
|
|
int m = 0, cnt = dpp->term;
|
|
|
|
while (cnt--) {
|
|
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr)
|
|
return FALSE;
|
|
|
|
dpp->samples_A [m] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
|
byteptr += 2;
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA)) {
|
|
dpp->samples_B [m] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
|
byteptr += 2;
|
|
}
|
|
|
|
m++;
|
|
}
|
|
}
|
|
|
|
return byteptr == endptr;
|
|
}
|
|
|
|
// Read the shaping weights from specified metadata block into the
|
|
// WavpackStream structure. Note that there must be two values (even
|
|
// for mono streams) and that the values are stored in the same
|
|
// manner as decorrelation weights. These would normally be read from
|
|
// the "correction" file and are used for lossless reconstruction of
|
|
// hybrid data.
|
|
|
|
int read_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd)
|
|
{
|
|
if (wpmd->byte_length == 2) {
|
|
char *byteptr = wpmd->data;
|
|
|
|
wps->dc.shaping_acc [0] = (int32_t) restore_weight (*byteptr++) << 16;
|
|
wps->dc.shaping_acc [1] = (int32_t) restore_weight (*byteptr++) << 16;
|
|
return TRUE;
|
|
}
|
|
else if (wpmd->byte_length >= (wps->wphdr.flags & MONO_DATA ? 4 : 8)) {
|
|
unsigned char *byteptr = wpmd->data;
|
|
|
|
wps->dc.error [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
|
wps->dc.shaping_acc [0] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
|
byteptr += 4;
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA)) {
|
|
wps->dc.error [1] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
|
wps->dc.shaping_acc [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
|
byteptr += 4;
|
|
}
|
|
|
|
if (wpmd->byte_length == (wps->wphdr.flags & MONO_DATA ? 6 : 12)) {
|
|
wps->dc.shaping_delta [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
|
|
|
if (!(wps->wphdr.flags & MONO_DATA))
|
|
wps->dc.shaping_delta [1] = wp_exp2s ((int16_t)(byteptr [2] + (byteptr [3] << 8)));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|