📄 unpack.c
字号:
////////////////////////////////////////////////////////////////////////////
// **** WAVPACK **** //
// Hybrid Lossless Wavefile Compressor //
// Copyright (c) 1998 - 2004 Conifer Software. //
// All Rights Reserved. //
// Distributed under the BSD Software License (see license.txt) //
////////////////////////////////////////////////////////////////////////////
// unpack.c
// This module actually handles the decompression of the audio data, except
// for the entropy decoding which is handled by the words.c module. For
// maximum efficiency, the conversion is isolated to tight loops that handle
// an entire buffer.
#include "wavpack.h"
#include <string.h>
#include <math.h>
#define LOSSY_MUTE
//////////////////////////////// local macros /////////////////////////////////
#define apply_weight_i(weight, sample) ((weight * sample + 512) >> 10)
#define apply_weight_f(weight, sample) (((((sample & 0xffff) * weight) >> 9) + \
(((sample & ~0xffff) >> 9) * weight) + 1) >> 1)
#define apply_weight(weight, sample) (sample != (short) sample ? \
apply_weight_f (weight, sample) : apply_weight_i (weight, sample))
#define update_weight(weight, delta, source, result) \
if (source && result) weight -= ((((source ^ result) >> 30) & 2) - 1) * delta;
#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
// and must be called before unpack_samples() is called to obtain audio data.
// It is assumed that the WavpackHeader has been read into the wps->wphdr
// (in the current WavpackStream). This is where all the metadata blocks are
// scanned up to the one containing the audio bitstream.
int unpack_init (WavpackContext *wpc)
{
WavpackStream *wps = &wpc->stream;
WavpackMetadata wpmd;
if (wps->wphdr.block_samples && wps->wphdr.block_index != (ulong) -1)
wps->sample_index = wps->wphdr.block_index;
wps->mute_error = FALSE;
wps->crc = 0xffffffff;
CLEAR (wps->wvbits);
CLEAR (wps->decorr_passes);
CLEAR (wps->w);
wps->wvbits.privdata = wpc->privdata;
while (read_metadata_buff (wpc, &wpmd)) {
if (!process_metadata (wpc, &wpmd)) {
//strcpy (wpc->error_message, "invalid metadata!");
return FALSE;
}
if (wpmd.id == ID_WV_BITSTREAM)
break;
}
if (wps->wphdr.block_samples && !bs_is_open (&wps->wvbits)) {
//strcpy (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 & FLOAT_DATA) &&
wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME))
wpc->lossy_blocks = TRUE;
}
return TRUE;
}
// This function initialzes the main bitstream for audio samples, which must
// be in the "wv" file.
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);
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));
return TRUE;
}
// 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;
uchar *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)
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_FLAG))
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_FLAG))
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)
{
uchar *byteptr = wpmd->data;
uchar *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)) {
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++;
}
}
return byteptr == endptr;
}
// Read the int32 data from the specified metadata into the specified stream.
// This data is used for integer data that has more than 24 bits of magnitude
// or, in some cases, used to eliminate redundant bits from any audio stream.
int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd)
{
int bytecnt = wpmd->byte_length;
char *byteptr = wpmd->data;
if (bytecnt != 4)
return FALSE;
wps->int32_sent_bits = *byteptr++;
wps->int32_zeros = *byteptr++;
wps->int32_ones = *byteptr++;
wps->int32_dups = *byteptr;
return TRUE;
}
// Read multichannel information from metadata. The first byte is the total
// number of channels and the following bytes represent the channel_mask
// as described for Microsoft WAVEFORMATEX.
int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd)
{
int bytecnt = wpmd->byte_length, shift = 0;
char *byteptr = wpmd->data;
ulong mask = 0;
if (!bytecnt || bytecnt > 5)
return FALSE;
wpc->config.num_channels = *byteptr++;
while (--bytecnt) {
mask |= (ulong) *byteptr++ << shift;
shift += 8;
}
wpc->config.channel_mask = mask;
return TRUE;
}
// Read configuration information from metadata.
int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd)
{
int bytecnt = wpmd->byte_length;
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;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -