📄 unpack.c
字号:
// This monster actually unpacks the WavPack bitstream(s) into the specified
// buffer as 32-bit integers or floats (depending on orignal data). Lossy
// samples will be clipped to their original limits (i.e. 8-bit samples are
// clipped to -128/+127) but are still returned in longs. It is up to the
// caller to potentially reformat this for the final output including any
// multichannel distribution, block alignment or endian compensation. The
// function unpack_init() must have been called and the entire WavPack block
// must still be visible (although wps->blockbuff will not be accessed again).
// For maximum clarity, the function is broken up into segments that handle
// various modes. This makes for a few extra infrequent flag checks, but
// makes the code easier to follow because the nesting does not become so
// deep. For maximum efficiency, the conversion is isolated to tight loops
// that handle an entire buffer. The function returns the total number of
// samples unpacked, which can be less than the number requested if an error
// occurs or the end of the block is reached.
static void fixup_samples (WavpackStream *wps, long *buffer, ulong sample_count);
long unpack_samples (WavpackContext *wpc, long *buffer, ulong sample_count)
{
WavpackStream *wps = &wpc->stream;
ulong flags = wps->wphdr.flags, crc = wps->crc, i;
long mute_limit = (1L << ((flags & MAG_MASK) >> MAG_LSB)) + 2;
struct decorr_pass *dpp;
long read_word, *bptr;
int tcount, m = 0;
if (wps->sample_index + sample_count > wps->wphdr.block_index + wps->wphdr.block_samples)
sample_count = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index;
if (wps->mute_error) {
memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8));
wps->sample_index += sample_count;
return sample_count;
}
if (flags & HYBRID_FLAG)
mute_limit *= 2;
///////////////////// handle version 4 mono data /////////////////////////
if (flags & MONO_FLAG)
for (bptr = buffer, i = 0; i < sample_count; ++i) {
if ((read_word = get_word (wps, 0)) == WORD_EOF)
break;
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
long sam, temp;
int k;
if (dpp->term > MAX_TERM) {
if (dpp->term & 1)
sam = 2 * dpp->samples_A [0] - dpp->samples_A [1];
else
sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
dpp->samples_A [1] = dpp->samples_A [0];
k = 0;
}
else {
sam = dpp->samples_A [m];
k = (m + dpp->term) & (MAX_TERM - 1);
}
temp = apply_weight (dpp->weight_A, sam) + read_word;
update_weight (dpp->weight_A, dpp->delta, sam, read_word);
dpp->samples_A [k] = read_word = temp;
}
if (labs (read_word) > mute_limit)
break;
m = (m + 1) & (MAX_TERM - 1);
crc = crc * 3 + read_word;
*bptr++ = read_word;
}
//////////////////// handle version 4 stereo data ////////////////////////
else
for (bptr = buffer, i = 0; i < sample_count; ++i) {
long left, right, left2, right2;
if ((left = get_word (wps, 0)) == WORD_EOF ||
(right = get_word (wps, 1)) == WORD_EOF)
break;
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
if (dpp->term > 0) {
long sam_A, sam_B;
int k;
if (dpp->term > MAX_TERM) {
if (dpp->term & 1) {
sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1];
sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1];
}
else {
sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1;
sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1;
}
dpp->samples_A [1] = dpp->samples_A [0];
dpp->samples_B [1] = dpp->samples_B [0];
k = 0;
}
else {
sam_A = dpp->samples_A [m];
sam_B = dpp->samples_B [m];
k = (m + dpp->term) & (MAX_TERM - 1);
}
left2 = apply_weight (dpp->weight_A, sam_A) + left;
right2 = apply_weight (dpp->weight_B, sam_B) + right;
update_weight (dpp->weight_A, dpp->delta, sam_A, left);
update_weight (dpp->weight_B, dpp->delta, sam_B, right);
dpp->samples_A [k] = left = left2;
dpp->samples_B [k] = right = right2;
}
else if (dpp->term == -1) {
left2 = left + apply_weight (dpp->weight_A, dpp->samples_A [0]);
update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], left);
left = left2;
right2 = right + apply_weight (dpp->weight_B, left2);
update_weight_clip (dpp->weight_B, dpp->delta, left2, right);
dpp->samples_A [0] = right = right2;
}
else {
right2 = right + apply_weight (dpp->weight_B, dpp->samples_B [0]);
update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], right);
right = right2;
if (dpp->term == -3) {
right2 = dpp->samples_A [0];
dpp->samples_A [0] = right;
}
left2 = left + apply_weight (dpp->weight_A, right2);
update_weight_clip (dpp->weight_A, dpp->delta, right2, left);
dpp->samples_B [0] = left = left2;
}
m = (m + 1) & (MAX_TERM - 1);
if (flags & JOINT_STEREO)
left += (right -= (left >> 1));
if (labs (left) > mute_limit || labs (right) > mute_limit)
break;
crc = (crc * 3 + left) * 3 + right;
*bptr++ = left;
*bptr++ = right;
}
if (i != sample_count) {
memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8));
wps->mute_error = TRUE;
i = sample_count;
}
while (m--)
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++)
if (dpp->term > 0 && dpp->term <= MAX_TERM) {
long temp = dpp->samples_A [0];
memcpy (dpp->samples_A, dpp->samples_A + 1, sizeof (dpp->samples_A) - sizeof (dpp->samples_A [0]));
dpp->samples_A [MAX_TERM - 1] = temp;
temp = dpp->samples_B [0];
memcpy (dpp->samples_B, dpp->samples_B + 1, sizeof (dpp->samples_B) - sizeof (dpp->samples_B [0]));
dpp->samples_B [MAX_TERM - 1] = temp;
}
fixup_samples (wps, buffer, i);
if (flags & FLOAT_DATA)
float_normalize (buffer, (flags & MONO_FLAG) ? i : i * 2,
127 - wps->float_norm_exp + wpc->norm_offset);
wps->sample_index += i;
wps->crc = crc;
return i;
}
// This is a helper function for unpack_samples() that applies several final
// operations. First, if the data is 32-bit float data, then that conversion
// is done in the float.c module (whether lossy or lossless) and we return.
// Otherwise, if the extended integer data applies, then that operation is
// executed first. If the unpacked data is lossy (and not corrected) then
// it is clipped and shifted in a single operation. Otherwise, if it's
// lossless then the last step is to apply the final shift (if any).
static void fixup_samples (WavpackStream *wps, long *buffer, ulong sample_count)
{
ulong flags = wps->wphdr.flags;
int shift = (flags & SHIFT_MASK) >> SHIFT_LSB;
if (flags & FLOAT_DATA) {
float_values (wps, buffer, (flags & MONO_FLAG) ? sample_count : sample_count * 2);
return;
}
if (flags & INT32_DATA) {
ulong count = (flags & MONO_FLAG) ? sample_count : sample_count * 2;
int sent_bits = wps->int32_sent_bits, zeros = wps->int32_zeros;
int ones = wps->int32_ones, dups = wps->int32_dups;
// ulong mask = (1 << sent_bits) - 1;
long *dptr = buffer;
if (!(flags & HYBRID_FLAG) && !sent_bits && (zeros + ones + dups))
while (count--) {
if (zeros)
*dptr <<= zeros;
else if (ones)
*dptr = ((*dptr + 1) << ones) - 1;
else if (dups)
*dptr = ((*dptr + (*dptr & 1)) << dups) - (*dptr & 1);
dptr++;
}
else
shift += zeros + sent_bits + ones + dups;
}
if (flags & HYBRID_FLAG) {
long min_value, max_value, min_shifted, max_shifted;
switch (flags & BYTES_STORED) {
case 0:
min_shifted = (min_value = -128 >> shift) << shift;
max_shifted = (max_value = 127 >> shift) << shift;
break;
case 1:
min_shifted = (min_value = -32768 >> shift) << shift;
max_shifted = (max_value = 32767 >> shift) << shift;
break;
case 2:
min_shifted = (min_value = -8388608 >> shift) << shift;
max_shifted = (max_value = 8388607 >> shift) << shift;
break;
case 3:
min_shifted = (min_value = -(long)2147483648 >> shift) << shift;
max_shifted = (max_value = (long) 2147483647 >> shift) << shift;
break;
}
if (!(flags & MONO_FLAG))
sample_count *= 2;
while (sample_count--) {
if (*buffer < min_value)
*buffer++ = min_shifted;
else if (*buffer > max_value)
*buffer++ = max_shifted;
else
*buffer++ <<= shift;
}
}
else if (shift) {
if (!(flags & MONO_FLAG))
sample_count *= 2;
while (sample_count--)
*buffer++ <<= shift;
}
}
// This function checks the crc value(s) for an unpacked block, returning the
// number of actual crc errors detected for the block. The block must be
// completely unpacked before this test is valid. For losslessly unpacked
// blocks of float or extended integer data the extended crc is also checked.
// Note that WavPack's crc is not a CCITT approved polynomial algorithm, but
// is a much simpler method that is virtually as robust for real world data.
int check_crc_error (WavpackContext *wpc)
{
WavpackStream *wps = &wpc->stream;
int result = 0;
if (wps->crc != wps->wphdr.crc)
++result;
return result;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -