Update wavpack library source
parent
e0f36dac15
commit
168fc5be6d
@ -0,0 +1,5 @@
|
||||
wpinclude_HEADERS = wavpack.h
|
||||
wpincludedir = $(prefix)/include/wavpack
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
Makefile.in
|
||||
@ -0,0 +1,57 @@
|
||||
lib_LTLIBRARIES = libwavpack.la
|
||||
|
||||
libwavpack_la_SOURCES = \
|
||||
common_utils.c \
|
||||
decorr_utils.c \
|
||||
entropy_utils.c \
|
||||
extra1.c \
|
||||
extra2.c \
|
||||
open_utils.c \
|
||||
open_filename.c \
|
||||
open_legacy.c \
|
||||
open_raw.c \
|
||||
pack.c \
|
||||
pack_dns.c \
|
||||
pack_floats.c \
|
||||
pack_utils.c \
|
||||
read_words.c \
|
||||
tags.c \
|
||||
tag_utils.c \
|
||||
unpack.c \
|
||||
unpack_floats.c \
|
||||
unpack_seek.c \
|
||||
unpack_utils.c \
|
||||
write_words.c
|
||||
|
||||
if ENABLE_LEGACY
|
||||
libwavpack_la_SOURCES += unpack3.c unpack3_open.c unpack3_seek.c
|
||||
endif
|
||||
|
||||
if ENABLE_DSD
|
||||
libwavpack_la_SOURCES += pack_dsd.c unpack_dsd.c
|
||||
endif
|
||||
|
||||
if ENABLE_X86ASM
|
||||
libwavpack_la_SOURCES += pack_x86.S unpack_x86.S
|
||||
endif
|
||||
|
||||
if ENABLE_X64ASM
|
||||
libwavpack_la_SOURCES += pack_x64.S unpack_x64.S
|
||||
endif
|
||||
|
||||
if ENABLE_ARMASM
|
||||
libwavpack_la_SOURCES += unpack_armv7.S
|
||||
endif
|
||||
|
||||
noinst_HEADERS = \
|
||||
decorr_tables.h \
|
||||
unpack3.h \
|
||||
wavpack_local.h \
|
||||
wavpack_version.h
|
||||
|
||||
libwavpack_la_CFLAGS = $(AM_CFLAGS)
|
||||
libwavpack_la_LIBADD = $(AM_LDADD) $(LIBM)
|
||||
libwavpack_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) -export-symbols-regex '^Wavpack.*$$' -no-undefined
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
Makefile.in
|
||||
@ -1,274 +0,0 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2006 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// bits.c
|
||||
|
||||
// This module provides utilities to support the BitStream structure which is
|
||||
// used to read and write all WavPack audio data streams. It also contains a
|
||||
// wrapper for the stream I/O functions and a set of functions dealing with
|
||||
// endian-ness, both for enhancing portability. Finally, a debug wrapper for
|
||||
// the malloc() system is provided.
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <io.h>
|
||||
#else
|
||||
#if defined(__OS2__)
|
||||
#include <io.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
////////////////////////// Bitstream functions ////////////////////////////////
|
||||
|
||||
#if !defined(NO_UNPACK) || defined(INFO_ONLY)
|
||||
|
||||
// Open the specified BitStream and associate with the specified buffer.
|
||||
|
||||
static void bs_read (Bitstream *bs);
|
||||
|
||||
void bs_open_read (Bitstream *bs, void *buffer_start, void *buffer_end)
|
||||
{
|
||||
bs->error = bs->sr = bs->bc = 0;
|
||||
bs->ptr = (bs->buf = buffer_start) - 1;
|
||||
bs->end = buffer_end;
|
||||
bs->wrap = bs_read;
|
||||
}
|
||||
|
||||
// This function is only called from the getbit() and getbits() macros when
|
||||
// the BitStream has been exhausted and more data is required. Sinve these
|
||||
// bistreams no longer access files, this function simple sets an error and
|
||||
// resets the buffer.
|
||||
|
||||
static void bs_read (Bitstream *bs)
|
||||
{
|
||||
bs->ptr = bs->buf - 1;
|
||||
bs->error = 1;
|
||||
}
|
||||
|
||||
// This function is called to close the bitstream. It returns the number of
|
||||
// full bytes actually read as bits.
|
||||
|
||||
uint32_t bs_close_read (Bitstream *bs)
|
||||
{
|
||||
uint32_t bytes_read;
|
||||
|
||||
if (bs->bc < sizeof (*(bs->ptr)) * 8)
|
||||
bs->ptr++;
|
||||
|
||||
bytes_read = (uint32_t)(bs->ptr - bs->buf) * sizeof (*(bs->ptr));
|
||||
|
||||
if (!(bytes_read & 1))
|
||||
++bytes_read;
|
||||
|
||||
CLEAR (*bs);
|
||||
return bytes_read;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef NO_PACK
|
||||
|
||||
// Open the specified BitStream using the specified buffer pointers. It is
|
||||
// assumed that enough buffer space has been allocated for all data that will
|
||||
// be written, otherwise an error will be generated.
|
||||
|
||||
static void bs_write (Bitstream *bs);
|
||||
|
||||
void bs_open_write (Bitstream *bs, void *buffer_start, void *buffer_end)
|
||||
{
|
||||
bs->error = bs->sr = bs->bc = 0;
|
||||
bs->ptr = bs->buf = buffer_start;
|
||||
bs->end = buffer_end;
|
||||
bs->wrap = bs_write;
|
||||
}
|
||||
|
||||
// This function is only called from the putbit() and putbits() macros when
|
||||
// the buffer is full, which is now flagged as an error.
|
||||
|
||||
static void bs_write (Bitstream *bs)
|
||||
{
|
||||
bs->ptr = bs->buf;
|
||||
bs->error = 1;
|
||||
}
|
||||
|
||||
// This function forces a flushing write of the specified BitStream, and
|
||||
// returns the total number of bytes written into the buffer.
|
||||
|
||||
uint32_t bs_close_write (Bitstream *bs)
|
||||
{
|
||||
uint32_t bytes_written;
|
||||
|
||||
if (bs->error)
|
||||
return (uint32_t) -1;
|
||||
|
||||
while (1) {
|
||||
while (bs->bc)
|
||||
putbit_1 (bs);
|
||||
|
||||
bytes_written = (uint32_t)(bs->ptr - bs->buf) * sizeof (*(bs->ptr));
|
||||
|
||||
if (bytes_written & 1) {
|
||||
putbit_1 (bs);
|
||||
}
|
||||
else
|
||||
break;
|
||||
};
|
||||
|
||||
CLEAR (*bs);
|
||||
return bytes_written;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/////////////////////// Endian Correction Routines ////////////////////////////
|
||||
|
||||
void little_endian_to_native (void *data, char *format)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) data;
|
||||
int32_t temp;
|
||||
|
||||
while (*format) {
|
||||
switch (*format) {
|
||||
case 'L':
|
||||
temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24);
|
||||
* (int32_t *) cp = temp;
|
||||
cp += 4;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
temp = cp [0] + (cp [1] << 8);
|
||||
* (short *) cp = (short) temp;
|
||||
cp += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit (*format))
|
||||
cp += *format - '0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
void native_to_little_endian (void *data, char *format)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) data;
|
||||
int32_t temp;
|
||||
|
||||
while (*format) {
|
||||
switch (*format) {
|
||||
case 'L':
|
||||
temp = * (int32_t *) cp;
|
||||
*cp++ = (unsigned char) temp;
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) (temp >> 16);
|
||||
*cp++ = (unsigned char) (temp >> 24);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
temp = * (short *) cp;
|
||||
*cp++ = (unsigned char) temp;
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit (*format))
|
||||
cp += *format - '0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////// Debug Wrapper for Malloc ///////////////////////////
|
||||
|
||||
#ifdef DEBUG_ALLOC
|
||||
|
||||
void *vptrs [512];
|
||||
|
||||
static void *add_ptr (void *ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 512; ++i)
|
||||
if (!vptrs [i]) {
|
||||
vptrs [i] = ptr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 512)
|
||||
error_line ("too many mallocs!");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void *del_ptr (void *ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 512; ++i)
|
||||
if (vptrs [i] == ptr) {
|
||||
vptrs [i] = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == 512)
|
||||
error_line ("free invalid ptr!");
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *malloc_db (uint32_t size)
|
||||
{
|
||||
if (size)
|
||||
return add_ptr (malloc (size));
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void free_db (void *ptr)
|
||||
{
|
||||
if (ptr)
|
||||
free (del_ptr (ptr));
|
||||
}
|
||||
|
||||
void *realloc_db (void *ptr, uint32_t size)
|
||||
{
|
||||
if (ptr && size)
|
||||
return add_ptr (realloc (del_ptr (ptr), size));
|
||||
else if (size)
|
||||
return malloc_db (size);
|
||||
else
|
||||
free_db (ptr);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t dump_alloc (void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (j = i = 0; i < 512; ++i)
|
||||
if (vptrs [i])
|
||||
j++;
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,771 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// common_utils.c
|
||||
|
||||
// This module provides a lot of the trivial WavPack API functions and several
|
||||
// functions that are common to both reading and writing WavPack files (like
|
||||
// WavpackCloseFile()). Functions here are restricted to those that have few
|
||||
// external dependancies and this is done so that applications that statically
|
||||
// link to the WavPack library (like the command-line utilities on Windows)
|
||||
// do not need to include the entire library image if they only use a subset
|
||||
// of it. This module will be loaded for ANY WavPack application.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#ifndef LIBWAVPACK_VERSION_STRING
|
||||
#include "wavpack_version.h"
|
||||
#endif
|
||||
|
||||
///////////////////////////// local table storage ////////////////////////////
|
||||
|
||||
const uint32_t sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050,
|
||||
24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 };
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// This function obtains general information about an open input file and
|
||||
// returns a mask with the following bit values:
|
||||
|
||||
// MODE_WVC: a .wvc file has been found and will be used for lossless
|
||||
// MODE_LOSSLESS: file is lossless (either pure or hybrid)
|
||||
// MODE_HYBRID: file is hybrid mode (either lossy or lossless)
|
||||
// MODE_FLOAT: audio data is 32-bit ieee floating point
|
||||
// MODE_VALID_TAG: file conatins a valid ID3v1 or APEv2 tag
|
||||
// MODE_HIGH: file was created in "high" mode (information only)
|
||||
// MODE_FAST: file was created in "fast" mode (information only)
|
||||
// MODE_EXTRA: file was created using "extra" mode (information only)
|
||||
// MODE_APETAG: file contains a valid APEv2 tag
|
||||
// MODE_SFX: file was created as a "self-extracting" executable
|
||||
// MODE_VERY_HIGH: file was created in the "very high" mode (or in
|
||||
// the "high" mode prior to 4.4)
|
||||
// MODE_MD5: file contains an MD5 checksum
|
||||
// MODE_XMODE: level used for extra mode (1-6, 0=unknown)
|
||||
// MODE_DNS: dynamic noise shaping
|
||||
|
||||
int WavpackGetMode (WavpackContext *wpc)
|
||||
{
|
||||
int mode = 0;
|
||||
|
||||
if (wpc) {
|
||||
if (wpc->config.flags & CONFIG_HYBRID_FLAG)
|
||||
mode |= MODE_HYBRID;
|
||||
else if (!(wpc->config.flags & CONFIG_LOSSY_MODE))
|
||||
mode |= MODE_LOSSLESS;
|
||||
|
||||
if (wpc->wvc_flag)
|
||||
mode |= (MODE_LOSSLESS | MODE_WVC);
|
||||
|
||||
if (wpc->lossy_blocks)
|
||||
mode &= ~MODE_LOSSLESS;
|
||||
|
||||
if (wpc->config.flags & CONFIG_FLOAT_DATA)
|
||||
mode |= MODE_FLOAT;
|
||||
|
||||
if (wpc->config.flags & (CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG)) {
|
||||
mode |= MODE_HIGH;
|
||||
|
||||
if ((wpc->config.flags & CONFIG_VERY_HIGH_FLAG) ||
|
||||
(wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.version < 0x405))
|
||||
mode |= MODE_VERY_HIGH;
|
||||
}
|
||||
|
||||
if (wpc->config.flags & CONFIG_FAST_FLAG)
|
||||
mode |= MODE_FAST;
|
||||
|
||||
if (wpc->config.flags & CONFIG_EXTRA_MODE)
|
||||
mode |= (MODE_EXTRA | (wpc->config.xmode << 12));
|
||||
|
||||
if (wpc->config.flags & CONFIG_CREATE_EXE)
|
||||
mode |= MODE_SFX;
|
||||
|
||||
if (wpc->config.flags & CONFIG_MD5_CHECKSUM)
|
||||
mode |= MODE_MD5;
|
||||
|
||||
if ((wpc->config.flags & CONFIG_HYBRID_FLAG) && (wpc->config.flags & CONFIG_DYNAMIC_SHAPING) &&
|
||||
wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.version >= 0x407)
|
||||
mode |= MODE_DNS;
|
||||
|
||||
#ifndef NO_TAGS
|
||||
if (valid_tag (&wpc->m_tag)) {
|
||||
mode |= MODE_VALID_TAG;
|
||||
|
||||
if (valid_tag (&wpc->m_tag) == 'A')
|
||||
mode |= MODE_APETAG;
|
||||
}
|
||||
#endif
|
||||
|
||||
mode |= (wpc->config.qmode << 16) & 0xFF0000;
|
||||
}
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
// This function obtains information about specific file features that were
|
||||
// added for version 5.0, specifically qualifications added to support CAF
|
||||
// and DSD files. Except for indicating the presence of DSD data, these
|
||||
// bits are meant to simply indicate the format of the data in the original
|
||||
// source file and do NOT indicate how the library will return the data to
|
||||
// the appication (which is always the same). This means that in general an
|
||||
// application that simply wants to play or process the audio data need not
|
||||
// be concerned about these. If the file is DSD audio, then either of the
|
||||
// QMDOE_DSD_LSB_FIRST or QMODE_DSD_MSB_FIRST bits will be set (but the
|
||||
// DSD audio is always returned to the caller MSB first).
|
||||
|
||||
// QMODE_BIG_ENDIAN 0x1 // big-endian data format (opposite of WAV format)
|
||||
// QMODE_SIGNED_BYTES 0x2 // 8-bit audio data is signed (opposite of WAV format)
|
||||
// QMODE_UNSIGNED_WORDS 0x4 // audio data (other than 8-bit) is unsigned (opposite of WAV format)
|
||||
// QMODE_REORDERED_CHANS 0x8 // source channels were not Microsoft order, so they were reordered
|
||||
// QMODE_DSD_LSB_FIRST 0x10 // DSD bytes, LSB first (most Sony .dsf files)
|
||||
// QMODE_DSD_MSB_FIRST 0x20 // DSD bytes, MSB first (Philips .dff files)
|
||||
// QMODE_DSD_IN_BLOCKS 0x40 // DSD data is blocked by channels (Sony .dsf only)
|
||||
|
||||
int WavpackGetQualifyMode (WavpackContext *wpc)
|
||||
{
|
||||
return wpc->config.qmode & 0xFF;
|
||||
}
|
||||
|
||||
// This function returns a pointer to a string describing the last error
|
||||
// generated by WavPack.
|
||||
|
||||
char *WavpackGetErrorMessage (WavpackContext *wpc)
|
||||
{
|
||||
return wpc->error_message;
|
||||
}
|
||||
|
||||
// Get total number of samples contained in the WavPack file, or -1 if unknown
|
||||
|
||||
uint32_t WavpackGetNumSamples (WavpackContext *wpc)
|
||||
{
|
||||
return (uint32_t) WavpackGetNumSamples64 (wpc);
|
||||
}
|
||||
|
||||
int64_t WavpackGetNumSamples64 (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->total_samples : -1;
|
||||
}
|
||||
|
||||
// Get the current sample index position, or -1 if unknown
|
||||
|
||||
uint32_t WavpackGetSampleIndex (WavpackContext *wpc)
|
||||
{
|
||||
return (uint32_t) WavpackGetSampleIndex64 (wpc);
|
||||
}
|
||||
|
||||
int64_t WavpackGetSampleIndex64 (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc) {
|
||||
#ifdef ENABLE_LEGACY
|
||||
if (wpc->stream3)
|
||||
return get_sample_index3 (wpc);
|
||||
else if (wpc->streams && wpc->streams [0])
|
||||
return wpc->streams [0]->sample_index;
|
||||
#else
|
||||
if (wpc->streams && wpc->streams [0])
|
||||
return wpc->streams [0]->sample_index;
|
||||
#endif
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get the number of errors encountered so far
|
||||
|
||||
int WavpackGetNumErrors (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->crc_errors : 0;
|
||||
}
|
||||
|
||||
// return TRUE if any uncorrected lossy blocks were actually written or read
|
||||
|
||||
int WavpackLossyBlocks (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->lossy_blocks : 0;
|
||||
}
|
||||
|
||||
// Calculate the progress through the file as a double from 0.0 (for begin)
|
||||
// to 1.0 (for done). A return value of -1.0 indicates that the progress is
|
||||
// unknown.
|
||||
|
||||
double WavpackGetProgress (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc && wpc->total_samples != -1 && wpc->total_samples != 0)
|
||||
return (double) WavpackGetSampleIndex64 (wpc) / wpc->total_samples;
|
||||
else
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
// Return the total size of the WavPack file(s) in bytes.
|
||||
|
||||
uint32_t WavpackGetFileSize (WavpackContext *wpc)
|
||||
{
|
||||
return (uint32_t) (wpc ? wpc->filelen + wpc->file2len : 0);
|
||||
}
|
||||
|
||||
int64_t WavpackGetFileSize64 (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->filelen + wpc->file2len : 0;
|
||||
}
|
||||
|
||||
// Calculate the ratio of the specified WavPack file size to the size of the
|
||||
// original audio data as a double greater than 0.0 and (usually) smaller than
|
||||
// 1.0. A value greater than 1.0 represents "negative" compression and a
|
||||
// return value of 0.0 indicates that the ratio cannot be determined.
|
||||
|
||||
double WavpackGetRatio (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc && wpc->total_samples != -1 && wpc->filelen) {
|
||||
double output_size = (double) wpc->total_samples * wpc->config.num_channels *
|
||||
wpc->config.bytes_per_sample;
|
||||
double input_size = (double) wpc->filelen + wpc->file2len;
|
||||
|
||||
if (output_size >= 1.0 && input_size >= 1.0)
|
||||
return input_size / output_size;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Calculate the average bitrate of the WavPack file in bits per second. A
|
||||
// return of 0.0 indicates that the bitrate cannot be determined. An option is
|
||||
// provided to use (or not use) any attendant .wvc file.
|
||||
|
||||
double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc)
|
||||
{
|
||||
if (wpc && wpc->total_samples != -1 && wpc->filelen) {
|
||||
double output_time = (double) wpc->total_samples / WavpackGetSampleRate (wpc);
|
||||
double input_size = (double) wpc->filelen + (count_wvc ? wpc->file2len : 0);
|
||||
|
||||
if (output_time >= 0.1 && input_size >= 1.0)
|
||||
return input_size * 8.0 / output_time;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Calculate the bitrate of the current WavPack file block in bits per second.
|
||||
// This can be used for an "instant" bit display and gets updated from about
|
||||
// 1 to 4 times per second. A return of 0.0 indicates that the bitrate cannot
|
||||
// be determined.
|
||||
|
||||
double WavpackGetInstantBitrate (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc && wpc->stream3)
|
||||
return WavpackGetAverageBitrate (wpc, TRUE);
|
||||
|
||||
if (wpc && wpc->streams && wpc->streams [0] && wpc->streams [0]->wphdr.block_samples) {
|
||||
double output_time = (double) wpc->streams [0]->wphdr.block_samples / WavpackGetSampleRate (wpc);
|
||||
double input_size = 0;
|
||||
int si;
|
||||
|
||||
for (si = 0; si < wpc->num_streams; ++si) {
|
||||
if (wpc->streams [si]->blockbuff)
|
||||
input_size += ((WavpackHeader *) wpc->streams [si]->blockbuff)->ckSize;
|
||||
|
||||
if (wpc->streams [si]->block2buff)
|
||||
input_size += ((WavpackHeader *) wpc->streams [si]->block2buff)->ckSize;
|
||||
}
|
||||
|
||||
if (output_time > 0.0 && input_size >= 1.0)
|
||||
return input_size * 8.0 / output_time;
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// This function allows retrieving the Core Audio File channel layout, many of which do not
|
||||
// conform to the Microsoft ordering standard that WavPack requires internally (at least for
|
||||
// those channels present in the "channel mask"). In addition to the layout tag, this function
|
||||
// returns the reordering string (if stored in the file) to allow the unpacker to reorder the
|
||||
// channels back to the specified layout (if it wants to restore the CAF order). The number of
|
||||
// channels in the layout is determined from the lower nybble of the layout word (and should
|
||||
// probably match the number of channels in the file), and if a reorder string is requested
|
||||
// then that much space must be allocated. Note that all the reordering is actually done
|
||||
// outside of this library, and that if reordering is done then the appropriate qmode bit
|
||||
// will be set.
|
||||
//
|
||||
// Note: Normally this function would not be used by an application unless it specifically
|
||||
// wanted to restore a non-standard channel order (to check an MD5, for example) or obtain
|
||||
// the Core Audio channel layout ID. For simple file decoding for playback, the channel_mask
|
||||
// should provide all the information required unless there are non-Microsoft channels
|
||||
// involved, in which case WavpackGetChannelIdentities() will provide the identities of
|
||||
// the other channels (if they are known).
|
||||
|
||||
uint32_t WavpackGetChannelLayout (WavpackContext *wpc, unsigned char *reorder)
|
||||
{
|
||||
if ((wpc->channel_layout & 0xff) && wpc->channel_reordering && reorder)
|
||||
memcpy (reorder, wpc->channel_reordering, wpc->channel_layout & 0xff);
|
||||
|
||||
return wpc->channel_layout;
|
||||
}
|
||||
|
||||
// This function provides the identities of ALL the channels in the file, including the
|
||||
// standard Microsoft channels (which come first, in order, and are numbered 1-18) and also
|
||||
// any non-Microsoft channels (which can be in any order and have values from 33-254). The
|
||||
// value 0x00 is invalid and 0xFF indicates an "unknown" or "unnassigned" channel. The
|
||||
// string is NULL terminated so the caller must supply enough space for the number
|
||||
// of channels indicated by WavpackGetNumChannels(), plus one.
|
||||
//
|
||||
// Note that this function returns the actual order of the channels in the Wavpack file
|
||||
// (i.e., the order returned by WavpackUnpackSamples()). If the file includes a "reordering"
|
||||
// string because the source file was not in Microsoft order that is NOT taken into account
|
||||
// here and really only needs to be considered if doing an MD5 verification or if it's
|
||||
// required to restore the original order/file (like wvunpack does).
|
||||
|
||||
void WavpackGetChannelIdentities (WavpackContext *wpc, unsigned char *identities)
|
||||
{
|
||||
int num_channels = wpc->config.num_channels, index = 1;
|
||||
uint32_t channel_mask = wpc->config.channel_mask;
|
||||
unsigned char *src = wpc->channel_identities;
|
||||
|
||||
while (num_channels--) {
|
||||
if (channel_mask) {
|
||||
while (!(channel_mask & 1)) {
|
||||
channel_mask >>= 1;
|
||||
index++;
|
||||
}
|
||||
|
||||
*identities++ = index++;
|
||||
channel_mask >>= 1;
|
||||
}
|
||||
else if (src && *src)
|
||||
*identities++ = *src++;
|
||||
else
|
||||
*identities++ = 0xff;
|
||||
}
|
||||
|
||||
*identities = 0;
|
||||
}
|
||||
|
||||
// For local use only. Install a callback to be executed when WavpackCloseFile() is called,
|
||||
// usually used to dump some statistics accumulated during encode or decode.
|
||||
|
||||
void install_close_callback (WavpackContext *wpc, void cb_func (void *wpc))
|
||||
{
|
||||
wpc->close_callback = cb_func;
|
||||
}
|
||||
|
||||
// Close the specified WavPack file and release all resources used by it.
|
||||
// Returns NULL.
|
||||
|
||||
WavpackContext *WavpackCloseFile (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc->close_callback)
|
||||
wpc->close_callback (wpc);
|
||||
|
||||
if (wpc->streams) {
|
||||
free_streams (wpc);
|
||||
|
||||
if (wpc->streams [0])
|
||||
free (wpc->streams [0]);
|
||||
|
||||
free (wpc->streams);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_LEGACY
|
||||
if (wpc->stream3)
|
||||
free_stream3 (wpc);
|
||||
#endif
|
||||
|
||||
if (wpc->reader && wpc->reader->close && wpc->wv_in)
|
||||
wpc->reader->close (wpc->wv_in);
|
||||
|
||||
if (wpc->reader && wpc->reader->close && wpc->wvc_in)
|
||||
wpc->reader->close (wpc->wvc_in);
|
||||
|
||||
WavpackFreeWrapper (wpc);
|
||||
|
||||
if (wpc->channel_reordering)
|
||||
free (wpc->channel_reordering);
|
||||
|
||||
#ifndef NO_TAGS
|
||||
free_tag (&wpc->m_tag);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->decimation_context)
|
||||
decimate_dsd_destroy (wpc->decimation_context);
|
||||
#endif
|
||||
|
||||
free (wpc);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// These routines are used to access (and free) header and trailer data that
|
||||
// was retrieved from the Wavpack file. The header will be available before
|
||||
// the samples are decoded and the trailer will be available after all samples
|
||||
// have been read.
|
||||
|
||||
uint32_t WavpackGetWrapperBytes (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->wrapper_bytes : 0;
|
||||
}
|
||||
|
||||
unsigned char *WavpackGetWrapperData (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->wrapper_data : NULL;
|
||||
}
|
||||
|
||||
void WavpackFreeWrapper (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc && wpc->wrapper_data) {
|
||||
free (wpc->wrapper_data);
|
||||
wpc->wrapper_data = NULL;
|
||||
wpc->wrapper_bytes = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the sample rate of the specified WavPack file
|
||||
|
||||
uint32_t WavpackGetSampleRate (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? (wpc->dsd_multiplier ? wpc->config.sample_rate * wpc->dsd_multiplier : wpc->config.sample_rate) : 44100;
|
||||
}
|
||||
|
||||
// Returns the native sample rate of the specified WavPack file
|
||||
// (provides the native rate for DSD files rather than the "byte" rate that's used for
|
||||
// seeking, duration, etc. and would generally be used just for user facing reports)
|
||||
|
||||
uint32_t WavpackGetNativeSampleRate (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? (wpc->dsd_multiplier ? wpc->config.sample_rate * wpc->dsd_multiplier * 8 : wpc->config.sample_rate) : 44100;
|
||||
}
|
||||
|
||||
// Returns the number of channels of the specified WavPack file. Note that
|
||||
// this is the actual number of channels contained in the file even if the
|
||||
// OPEN_2CH_MAX flag was specified when the file was opened.
|
||||
|
||||
int WavpackGetNumChannels (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->config.num_channels : 2;
|
||||
}
|
||||
|
||||
// Returns the standard Microsoft channel mask for the specified WavPack
|
||||
// file. A value of zero indicates that there is no speaker assignment
|
||||
// information.
|
||||
|
||||
int WavpackGetChannelMask (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->config.channel_mask : 0;
|
||||
}
|
||||
|
||||
// Return the normalization value for floating point data (valid only
|
||||
// if floating point data is present). A value of 127 indicates that
|
||||
// the floating point range is +/- 1.0. Higher values indicate a
|
||||
// larger floating point range.
|
||||
|
||||
int WavpackGetFloatNormExp (WavpackContext *wpc)
|
||||
{
|
||||
return wpc->config.float_norm_exp;
|
||||
}
|
||||
|
||||
// Returns the actual number of valid bits per sample contained in the
|
||||
// original file, which may or may not be a multiple of 8. Floating data
|
||||
// always has 32 bits, integers may be from 1 to 32 bits each. When this
|
||||
// value is not a multiple of 8, then the "extra" bits are located in the
|
||||
// LSBs of the results. That is, values are right justified when unpacked
|
||||
// into ints, but are left justified in the number of bytes used by the
|
||||
// original data.
|
||||
|
||||
int WavpackGetBitsPerSample (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->config.bits_per_sample : 16;
|
||||
}
|
||||
|
||||
// Returns the number of bytes used for each sample (1 to 4) in the original
|
||||
// file. This is required information for the user of this module because the
|
||||
// audio data is returned in the LOWER bytes of the long buffer and must be
|
||||
// left-shifted 8, 16, or 24 bits if normalized longs are required.
|
||||
|
||||
int WavpackGetBytesPerSample (WavpackContext *wpc)
|
||||
{
|
||||
return wpc ? wpc->config.bytes_per_sample : 2;
|
||||
}
|
||||
|
||||
// If the OPEN_2CH_MAX flag is specified when opening the file, this function
|
||||
// will return the actual number of channels decoded from the file (which may
|
||||
// or may not be less than the actual number of channels, but will always be
|
||||
// 1 or 2). Normally, this will be the front left and right channels of a
|
||||
// multichannel file.
|
||||
|
||||
int WavpackGetReducedChannels (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc)
|
||||
return wpc->reduced_channels ? wpc->reduced_channels : wpc->config.num_channels;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Free all memory allocated for raw WavPack blocks (for all allocated streams)
|
||||
// and free all additonal streams. This does not free the default stream ([0])
|
||||
// which is always kept around.
|
||||
|
||||
void free_streams (WavpackContext *wpc)
|
||||
{
|
||||
int si = wpc->num_streams;
|
||||
|
||||
while (si--) {
|
||||
if (wpc->streams [si]->blockbuff) {
|
||||
free (wpc->streams [si]->blockbuff);
|
||||
wpc->streams [si]->blockbuff = NULL;
|
||||
}
|
||||
|
||||
if (wpc->streams [si]->block2buff) {
|
||||
free (wpc->streams [si]->block2buff);
|
||||
wpc->streams [si]->block2buff = NULL;
|
||||
}
|
||||
|
||||
if (wpc->streams [si]->sample_buffer) {
|
||||
free (wpc->streams [si]->sample_buffer);
|
||||
wpc->streams [si]->sample_buffer = NULL;
|
||||
}
|
||||
|
||||
if (wpc->streams [si]->dc.shaping_data) {
|
||||
free (wpc->streams [si]->dc.shaping_data);
|
||||
wpc->streams [si]->dc.shaping_data = NULL;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->streams [si]->dsd.probabilities) {
|
||||
free (wpc->streams [si]->dsd.probabilities);
|
||||
wpc->streams [si]->dsd.probabilities = NULL;
|
||||
}
|
||||
|
||||
if (wpc->streams [si]->dsd.summed_probabilities) {
|
||||
free (wpc->streams [si]->dsd.summed_probabilities);
|
||||
wpc->streams [si]->dsd.summed_probabilities = NULL;
|
||||
}
|
||||
|
||||
if (wpc->streams [si]->dsd.value_lookup) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < wpc->streams [si]->dsd.history_bins; ++i)
|
||||
if (wpc->streams [si]->dsd.value_lookup [i])
|
||||
free (wpc->streams [si]->dsd.value_lookup [i]);
|
||||
|
||||
free (wpc->streams [si]->dsd.value_lookup);
|
||||
wpc->streams [si]->dsd.value_lookup = NULL;
|
||||
}
|
||||
|
||||
if (wpc->streams [si]->dsd.ptable) {
|
||||
free (wpc->streams [si]->dsd.ptable);
|
||||
wpc->streams [si]->dsd.ptable = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (si) {
|
||||
wpc->num_streams--;
|
||||
free (wpc->streams [si]);
|
||||
wpc->streams [si] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wpc->current_stream = 0;
|
||||
}
|
||||
|
||||
void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp)
|
||||
{
|
||||
f32 *fvalues = (f32 *) values;
|
||||
int exp;
|
||||
|
||||
if (!delta_exp)
|
||||
return;
|
||||
|
||||
while (num_values--) {
|
||||
if ((exp = get_exponent (*fvalues)) == 0 || exp + delta_exp <= 0)
|
||||
*fvalues = 0;
|
||||
else if (exp == 255 || (exp += delta_exp) >= 255) {
|
||||
set_exponent (*fvalues, 255);
|
||||
set_mantissa (*fvalues, 0);
|
||||
}
|
||||
else
|
||||
set_exponent (*fvalues, exp);
|
||||
|
||||
fvalues++;
|
||||
}
|
||||
}
|
||||
|
||||
void WavpackLittleEndianToNative (void *data, char *format)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) data;
|
||||
int64_t temp;
|
||||
|
||||
while (*format) {
|
||||
switch (*format) {
|
||||
case 'D':
|
||||
temp = cp [0] + ((int64_t) cp [1] << 8) + ((int64_t) cp [2] << 16) + ((int64_t) cp [3] << 24) +
|
||||
((int64_t) cp [4] << 32) + ((int64_t) cp [5] << 40) + ((int64_t) cp [6] << 48) + ((int64_t) cp [7] << 56);
|
||||
* (int64_t *) cp = temp;
|
||||
cp += 8;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
temp = cp [0] + ((int32_t) cp [1] << 8) + ((int32_t) cp [2] << 16) + ((int32_t) cp [3] << 24);
|
||||
* (int32_t *) cp = (int32_t) temp;
|
||||
cp += 4;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
temp = cp [0] + (cp [1] << 8);
|
||||
* (int16_t *) cp = (int16_t) temp;
|
||||
cp += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit (*format))
|
||||
cp += *format - '0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
void WavpackNativeToLittleEndian (void *data, char *format)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) data;
|
||||
int64_t temp;
|
||||
|
||||
while (*format) {
|
||||
switch (*format) {
|
||||
case 'D':
|
||||
temp = * (int64_t *) cp;
|
||||
*cp++ = (unsigned char) temp;
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) (temp >> 16);
|
||||
*cp++ = (unsigned char) (temp >> 24);
|
||||
*cp++ = (unsigned char) (temp >> 32);
|
||||
*cp++ = (unsigned char) (temp >> 40);
|
||||
*cp++ = (unsigned char) (temp >> 48);
|
||||
*cp++ = (unsigned char) (temp >> 56);
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
temp = * (int32_t *) cp;
|
||||
*cp++ = (unsigned char) temp;
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) (temp >> 16);
|
||||
*cp++ = (unsigned char) (temp >> 24);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
temp = * (int16_t *) cp;
|
||||
*cp++ = (unsigned char) temp;
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit (*format))
|
||||
cp += *format - '0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
void WavpackBigEndianToNative (void *data, char *format)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) data;
|
||||
int64_t temp;
|
||||
|
||||
while (*format) {
|
||||
switch (*format) {
|
||||
case 'D':
|
||||
temp = cp [7] + ((int64_t) cp [6] << 8) + ((int64_t) cp [5] << 16) + ((int64_t) cp [4] << 24) +
|
||||
((int64_t) cp [3] << 32) + ((int64_t) cp [2] << 40) + ((int64_t) cp [1] << 48) + ((int64_t) cp [0] << 56);
|
||||
* (int64_t *) cp = temp;
|
||||
cp += 8;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
temp = cp [3] + ((int32_t) cp [2] << 8) + ((int32_t) cp [1] << 16) + ((int32_t) cp [0] << 24);
|
||||
* (int32_t *) cp = (int32_t) temp;
|
||||
cp += 4;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
temp = cp [1] + (cp [0] << 8);
|
||||
* (int16_t *) cp = (int16_t) temp;
|
||||
cp += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit (*format))
|
||||
cp += *format - '0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
void WavpackNativeToBigEndian (void *data, char *format)
|
||||
{
|
||||
unsigned char *cp = (unsigned char *) data;
|
||||
int64_t temp;
|
||||
|
||||
while (*format) {
|
||||
switch (*format) {
|
||||
case 'D':
|
||||
temp = * (int64_t *) cp;
|
||||
*cp++ = (unsigned char) (temp >> 56);
|
||||
*cp++ = (unsigned char) (temp >> 48);
|
||||
*cp++ = (unsigned char) (temp >> 40);
|
||||
*cp++ = (unsigned char) (temp >> 32);
|
||||
*cp++ = (unsigned char) (temp >> 24);
|
||||
*cp++ = (unsigned char) (temp >> 16);
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) temp;
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
temp = * (int32_t *) cp;
|
||||
*cp++ = (unsigned char) (temp >> 24);
|
||||
*cp++ = (unsigned char) (temp >> 16);
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) temp;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
temp = * (int16_t *) cp;
|
||||
*cp++ = (unsigned char) (temp >> 8);
|
||||
*cp++ = (unsigned char) temp;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (isdigit (*format))
|
||||
cp += *format - '0';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
format++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t WavpackGetLibraryVersion (void)
|
||||
{
|
||||
return (LIBWAVPACK_MAJOR<<16)
|
||||
|(LIBWAVPACK_MINOR<<8)
|
||||
|(LIBWAVPACK_MICRO<<0);
|
||||
}
|
||||
|
||||
const char *WavpackGetLibraryVersionString (void)
|
||||
{
|
||||
return LIBWAVPACK_VERSION_STRING;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,204 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** 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 = (unsigned char *)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 = (char *)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 = (unsigned char *)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 = (char *)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 = (unsigned char *)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;
|
||||
}
|
||||
@ -0,0 +1,378 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// entropy_utils.c
|
||||
|
||||
// This module contains the functions that process metadata blocks that are
|
||||
// specific to the entropy decoder; these would be called any time a WavPack
|
||||
// block was parsed. Additionally, it contains tables and functions that are
|
||||
// common to both entropy coding and decoding. These are in a module separate
|
||||
// from the actual entropy encoder (write_words.c) and decoder (read_words.c)
|
||||
// so that if applications that just do a subset of the full WavPack reading
|
||||
// and writing can link with a subset of the library.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// local table storage ////////////////////////////
|
||||
|
||||
const uint32_t bitset [] = {
|
||||
1L << 0, 1L << 1, 1L << 2, 1L << 3,
|
||||
1L << 4, 1L << 5, 1L << 6, 1L << 7,
|
||||
1L << 8, 1L << 9, 1L << 10, 1L << 11,
|
||||
1L << 12, 1L << 13, 1L << 14, 1L << 15,
|
||||
1L << 16, 1L << 17, 1L << 18, 1L << 19,
|
||||
1L << 20, 1L << 21, 1L << 22, 1L << 23,
|
||||
1L << 24, 1L << 25, 1L << 26, 1L << 27,
|
||||
1L << 28, 1L << 29, 1L << 30, 1L << 31
|
||||
};
|
||||
|
||||
const uint32_t bitmask [] = {
|
||||
(1L << 0) - 1, (1L << 1) - 1, (1L << 2) - 1, (1L << 3) - 1,
|
||||
(1L << 4) - 1, (1L << 5) - 1, (1L << 6) - 1, (1L << 7) - 1,
|
||||
(1L << 8) - 1, (1L << 9) - 1, (1L << 10) - 1, (1L << 11) - 1,
|
||||
(1L << 12) - 1, (1L << 13) - 1, (1L << 14) - 1, (1L << 15) - 1,
|
||||
(1L << 16) - 1, (1L << 17) - 1, (1L << 18) - 1, (1L << 19) - 1,
|
||||
(1L << 20) - 1, (1L << 21) - 1, (1L << 22) - 1, (1L << 23) - 1,
|
||||
(1L << 24) - 1, (1L << 25) - 1, (1L << 26) - 1, (1L << 27) - 1,
|
||||
(1L << 28) - 1, (1L << 29) - 1, (1L << 30) - 1, 0x7fffffff
|
||||
};
|
||||
|
||||
const char nbits_table [] = {
|
||||
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, // 0 - 15
|
||||
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 16 - 31
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 32 - 47
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 48 - 63
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 64 - 79
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 80 - 95
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 96 - 111
|
||||
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 112 - 127
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 128 - 143
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 144 - 159
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 160 - 175
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 176 - 191
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 192 - 207
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 208 - 223
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, // 224 - 239
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 // 240 - 255
|
||||
};
|
||||
|
||||
static const unsigned char log2_table [] = {
|
||||
0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15,
|
||||
0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a,
|
||||
0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34, 0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e,
|
||||
0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
|
||||
0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
|
||||
0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75,
|
||||
0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85,
|
||||
0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
|
||||
0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
|
||||
0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2,
|
||||
0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0,
|
||||
0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce,
|
||||
0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb,
|
||||
0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4,
|
||||
0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9, 0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff
|
||||
};
|
||||
|
||||
static const unsigned char exp2_table [] = {
|
||||
0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16,
|
||||
0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23,
|
||||
0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d,
|
||||
0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
|
||||
0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
|
||||
0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
|
||||
0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
|
||||
0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a,
|
||||
0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
|
||||
0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
|
||||
0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
|
||||
0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4,
|
||||
0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde, 0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9,
|
||||
0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff
|
||||
};
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// Read the median log2 values from the specifed metadata structure, convert
|
||||
// them back to 32-bit unsigned values and store them. If length is not
|
||||
// exactly correct then we flag and return an error.
|
||||
|
||||
int read_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char *byteptr = (unsigned char *)wpmd->data;
|
||||
|
||||
if (wpmd->byte_length != ((wps->wphdr.flags & MONO_DATA) ? 6 : 12))
|
||||
return FALSE;
|
||||
|
||||
wps->w.c [0].median [0] = wp_exp2s (byteptr [0] + (byteptr [1] << 8));
|
||||
wps->w.c [0].median [1] = wp_exp2s (byteptr [2] + (byteptr [3] << 8));
|
||||
wps->w.c [0].median [2] = wp_exp2s (byteptr [4] + (byteptr [5] << 8));
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
wps->w.c [1].median [0] = wp_exp2s (byteptr [6] + (byteptr [7] << 8));
|
||||
wps->w.c [1].median [1] = wp_exp2s (byteptr [8] + (byteptr [9] << 8));
|
||||
wps->w.c [1].median [2] = wp_exp2s (byteptr [10] + (byteptr [11] << 8));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Read the hybrid related values from the specifed metadata structure, convert
|
||||
// them back to their internal formats and store them. The extended profile
|
||||
// stuff is not implemented yet, so return an error if we get more data than
|
||||
// we know what to do with.
|
||||
|
||||
int read_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char *byteptr = (unsigned char *)wpmd->data;
|
||||
unsigned char *endptr = byteptr + wpmd->byte_length;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr)
|
||||
return FALSE;
|
||||
|
||||
wps->w.c [0].slow_level = wp_exp2s (byteptr [0] + (byteptr [1] << 8));
|
||||
byteptr += 2;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
wps->w.c [1].slow_level = wp_exp2s (byteptr [0] + (byteptr [1] << 8));
|
||||
byteptr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr)
|
||||
return FALSE;
|
||||
|
||||
wps->w.bitrate_acc [0] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16;
|
||||
byteptr += 2;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
wps->w.bitrate_acc [1] = (int32_t)(byteptr [0] + (byteptr [1] << 8)) << 16;
|
||||
byteptr += 2;
|
||||
}
|
||||
|
||||
if (byteptr < endptr) {
|
||||
if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr)
|
||||
return FALSE;
|
||||
|
||||
wps->w.bitrate_delta [0] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
byteptr += 2;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
wps->w.bitrate_delta [1] = wp_exp2s ((int16_t)(byteptr [0] + (byteptr [1] << 8)));
|
||||
byteptr += 2;
|
||||
}
|
||||
|
||||
if (byteptr < endptr)
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
wps->w.bitrate_delta [0] = wps->w.bitrate_delta [1] = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// This function is called during both encoding and decoding of hybrid data to
|
||||
// update the "error_limit" variable which determines the maximum sample error
|
||||
// allowed in the main bitstream. In the HYBRID_BITRATE mode (which is the only
|
||||
// currently implemented) this is calculated from the slow_level values and the
|
||||
// bitrate accumulators. Note that the bitrate accumulators can be changing.
|
||||
|
||||
void update_error_limit (WavpackStream *wps)
|
||||
{
|
||||
int bitrate_0 = (wps->w.bitrate_acc [0] += wps->w.bitrate_delta [0]) >> 16;
|
||||
|
||||
if (wps->wphdr.flags & MONO_DATA) {
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
int slow_log_0 = (wps->w.c [0].slow_level + SLO) >> SLS;
|
||||
|
||||
if (slow_log_0 - bitrate_0 > -0x100)
|
||||
wps->w.c [0].error_limit = wp_exp2s (slow_log_0 - bitrate_0 + 0x100);
|
||||
else
|
||||
wps->w.c [0].error_limit = 0;
|
||||
}
|
||||
else
|
||||
wps->w.c [0].error_limit = wp_exp2s (bitrate_0);
|
||||
}
|
||||
else {
|
||||
int bitrate_1 = (wps->w.bitrate_acc [1] += wps->w.bitrate_delta [1]) >> 16;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
int slow_log_0 = (wps->w.c [0].slow_level + SLO) >> SLS;
|
||||
int slow_log_1 = (wps->w.c [1].slow_level + SLO) >> SLS;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BALANCE) {
|
||||
int balance = (slow_log_1 - slow_log_0 + bitrate_1 + 1) >> 1;
|
||||
|
||||
if (balance > bitrate_0) {
|
||||
bitrate_1 = bitrate_0 * 2;
|
||||
bitrate_0 = 0;
|
||||
}
|
||||
else if (-balance > bitrate_0) {
|
||||
bitrate_0 = bitrate_0 * 2;
|
||||
bitrate_1 = 0;
|
||||
}
|
||||
else {
|
||||
bitrate_1 = bitrate_0 + balance;
|
||||
bitrate_0 = bitrate_0 - balance;
|
||||
}
|
||||
}
|
||||
|
||||
if (slow_log_0 - bitrate_0 > -0x100)
|
||||
wps->w.c [0].error_limit = wp_exp2s (slow_log_0 - bitrate_0 + 0x100);
|
||||
else
|
||||
wps->w.c [0].error_limit = 0;
|
||||
|
||||
if (slow_log_1 - bitrate_1 > -0x100)
|
||||
wps->w.c [1].error_limit = wp_exp2s (slow_log_1 - bitrate_1 + 0x100);
|
||||
else
|
||||
wps->w.c [1].error_limit = 0;
|
||||
}
|
||||
else {
|
||||
wps->w.c [0].error_limit = wp_exp2s (bitrate_0);
|
||||
wps->w.c [1].error_limit = wp_exp2s (bitrate_1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The concept of a base 2 logarithm is used in many parts of WavPack. It is
|
||||
// a way of sufficiently accurately representing 32-bit signed and unsigned
|
||||
// values storing only 16 bits (actually fewer). It is also used in the hybrid
|
||||
// mode for quickly comparing the relative magnitude of large values (i.e.
|
||||
// division) and providing smooth exponentials using only addition.
|
||||
|
||||
// These are not strict logarithms in that they become linear around zero and
|
||||
// can therefore represent both zero and negative values. They have 8 bits
|
||||
// of precision and in "roundtrip" conversions the total error never exceeds 1
|
||||
// part in 225 except for the cases of +/-115 and +/-195 (which error by 1).
|
||||
|
||||
|
||||
// This function returns the log2 for the specified 32-bit unsigned value.
|
||||
// The maximum value allowed is about 0xff800000 and returns 8447.
|
||||
|
||||
int FASTCALL wp_log2 (uint32_t avalue)
|
||||
{
|
||||
int dbits;
|
||||
|
||||
if ((avalue += avalue >> 9) < (1 << 8)) {
|
||||
dbits = nbits_table [avalue];
|
||||
return (dbits << 8) + log2_table [(avalue << (9 - dbits)) & 0xff];
|
||||
}
|
||||
else {
|
||||
if (avalue < (1L << 16))
|
||||
dbits = nbits_table [avalue >> 8] + 8;
|
||||
else if (avalue < (1L << 24))
|
||||
dbits = nbits_table [avalue >> 16] + 16;
|
||||
else
|
||||
dbits = nbits_table [avalue >> 24] + 24;
|
||||
|
||||
return (dbits << 8) + log2_table [(avalue >> (dbits - 9)) & 0xff];
|
||||
}
|
||||
}
|
||||
|
||||
// This function scans a buffer of longs and accumulates the total log2 value
|
||||
// of all the samples. This is useful for determining maximum compression
|
||||
// because the bitstream storage required for entropy coding is proportional
|
||||
// to the base 2 log of the samples. On some platforms there is an assembly
|
||||
// version of this.
|
||||
|
||||
#if !defined(OPT_ASM_X86) && !defined(OPT_ASM_X64)
|
||||
|
||||
uint32_t log2buffer (int32_t *samples, uint32_t num_samples, int limit)
|
||||
{
|
||||
uint32_t result = 0, avalue;
|
||||
int dbits;
|
||||
|
||||
while (num_samples--) {
|
||||
avalue = abs (*samples++);
|
||||
|
||||
if ((avalue += avalue >> 9) < (1 << 8)) {
|
||||
dbits = nbits_table [avalue];
|
||||
result += (dbits << 8) + log2_table [(avalue << (9 - dbits)) & 0xff];
|
||||
}
|
||||
else {
|
||||
if (avalue < (1L << 16))
|
||||
dbits = nbits_table [avalue >> 8] + 8;
|
||||
else if (avalue < (1L << 24))
|
||||
dbits = nbits_table [avalue >> 16] + 16;
|
||||
else
|
||||
dbits = nbits_table [avalue >> 24] + 24;
|
||||
|
||||
result += dbits = (dbits << 8) + log2_table [(avalue >> (dbits - 9)) & 0xff];
|
||||
|
||||
if (limit && dbits >= limit)
|
||||
return (uint32_t) -1;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// This function returns the log2 for the specified 32-bit signed value.
|
||||
// All input values are valid and the return values are in the range of
|
||||
// +/- 8192.
|
||||
|
||||
int wp_log2s (int32_t value)
|
||||
{
|
||||
return (value < 0) ? -wp_log2 (-value) : wp_log2 (value);
|
||||
}
|
||||
|
||||
// This function returns the original integer represented by the supplied
|
||||
// logarithm (at least within the provided accuracy). The log is signed,
|
||||
// but since a full 32-bit value is returned this can be used for unsigned
|
||||
// conversions as well (i.e. the input range is -8192 to +8447).
|
||||
|
||||
int32_t wp_exp2s (int log)
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
if (log < 0)
|
||||
return -wp_exp2s (-log);
|
||||
|
||||
value = exp2_table [log & 0xff] | 0x100;
|
||||
|
||||
if ((log >>= 8) <= 9)
|
||||
return value >> (9 - log);
|
||||
else
|
||||
return value << (log - 9);
|
||||
}
|
||||
|
||||
// These two functions convert internal weights (which are normally +/-1024)
|
||||
// to and from an 8-bit signed character version for storage in metadata. The
|
||||
// weights are clipped here in the case that they are outside that range.
|
||||
|
||||
signed char store_weight (int weight)
|
||||
{
|
||||
if (weight > 1024)
|
||||
weight = 1024;
|
||||
else if (weight < -1024)
|
||||
weight = -1024;
|
||||
|
||||
if (weight > 0)
|
||||
weight -= (weight + 64) >> 7;
|
||||
|
||||
return (weight + 4) >> 3;
|
||||
}
|
||||
|
||||
int restore_weight (signed char weight)
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result = (int) weight << 3) > 0)
|
||||
result += (result + 64) >> 7;
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1,371 +0,0 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2006 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// float.c
|
||||
|
||||
#include "wavpack_local.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
|
||||
|
||||
#ifndef NO_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 = (int32_t)(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;
|
||||
int32_t count, value, shift_count;
|
||||
int max_exp = 0;
|
||||
f32 *dp;
|
||||
|
||||
wps->float_shift = wps->float_flags = 0;
|
||||
|
||||
for (dp = values, count = num_values; count--; dp++) {
|
||||
crc = crc * 27 + get_mantissa (*dp) * 9 + get_exponent (*dp) * 3 + get_sign (*dp);
|
||||
|
||||
if (get_exponent (*dp) > max_exp && get_exponent (*dp) < 255)
|
||||
max_exp = get_exponent (*dp);
|
||||
}
|
||||
|
||||
wps->crc_x = crc;
|
||||
|
||||
for (dp = values, count = num_values; count--; dp++) {
|
||||
if (get_exponent (*dp) == 255) {
|
||||
wps->float_flags |= FLOAT_EXCEPTIONS;
|
||||
value = 0x1000000;
|
||||
shift_count = 0;
|
||||
}
|
||||
else if (get_exponent (*dp)) {
|
||||
shift_count = max_exp - get_exponent (*dp);
|
||||
value = 0x800000 + get_mantissa (*dp);
|
||||
}
|
||||
else {
|
||||
shift_count = max_exp ? max_exp - 1 : 0;
|
||||
value = get_mantissa (*dp);
|
||||
|
||||
// if (get_mantissa (*dp))
|
||||
// denormals++;
|
||||
}
|
||||
|
||||
if (shift_count < 25)
|
||||
value >>= shift_count;
|
||||
else
|
||||
value = 0;
|
||||
|
||||
if (!value) {
|
||||
if (get_exponent (*dp) || get_mantissa (*dp))
|
||||
++false_zeros;
|
||||
else if (get_sign (*dp))
|
||||
++neg_zeros;
|
||||
}
|
||||
else if (shift_count) {
|
||||
int32_t mask = (1 << shift_count) - 1;
|
||||
|
||||
if (!(get_mantissa (*dp) & mask))
|
||||
shifted_zeros++;
|
||||
else if ((get_mantissa (*dp) & mask) == mask)
|
||||
shifted_ones++;
|
||||
else
|
||||
shifted_both++;
|
||||
}
|
||||
|
||||
ordata |= value;
|
||||
* (int32_t *) dp = (get_sign (*dp)) ? -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 (get_exponent (*dp) == 255) {
|
||||
if (get_mantissa (*dp)) {
|
||||
putbit_1 (&wps->wvxbits);
|
||||
putbits (get_mantissa (*dp), 23, &wps->wvxbits);
|
||||
}
|
||||
else {
|
||||
putbit_0 (&wps->wvxbits);
|
||||
}
|
||||
|
||||
value = 0x1000000;
|
||||
shift_count = 0;
|
||||
}
|
||||
else if (get_exponent (*dp)) {
|
||||
shift_count = max_exp - get_exponent (*dp);
|
||||
value = 0x800000 + get_mantissa (*dp);
|
||||
}
|
||||
else {
|
||||
shift_count = max_exp ? max_exp - 1 : 0;
|
||||
value = get_mantissa (*dp);
|
||||
}
|
||||
|
||||
if (shift_count < 25)
|
||||
value >>= shift_count;
|
||||
else
|
||||
value = 0;
|
||||
|
||||
if (!value) {
|
||||
if (wps->float_flags & FLOAT_ZEROS_SENT) {
|
||||
if (get_exponent (*dp) || get_mantissa (*dp)) {
|
||||
putbit_1 (&wps->wvxbits);
|
||||
putbits (get_mantissa (*dp), 23, &wps->wvxbits);
|
||||
|
||||
if (max_exp >= 25) {
|
||||
putbits (get_exponent (*dp), 8, &wps->wvxbits);
|
||||
}
|
||||
|
||||
putbit (get_sign (*dp), &wps->wvxbits);
|
||||
}
|
||||
else {
|
||||
putbit_0 (&wps->wvxbits);
|
||||
|
||||
if (wps->float_flags & FLOAT_NEG_ZEROS)
|
||||
putbit (get_sign (*dp), &wps->wvxbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (shift_count) {
|
||||
if (wps->float_flags & FLOAT_SHIFT_SENT) {
|
||||
int32_t data = get_mantissa (*dp) & ((1 << shift_count) - 1);
|
||||
putbits (data, shift_count, &wps->wvxbits);
|
||||
}
|
||||
else if (wps->float_flags & FLOAT_SHIFT_SAME) {
|
||||
putbit (get_mantissa (*dp) & 1, &wps->wvxbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(NO_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
|
||||
|
||||
#ifndef NO_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;
|
||||
uint32_t temp;
|
||||
|
||||
if (*values == 0) {
|
||||
if (wps->float_flags & FLOAT_ZEROS_SENT) {
|
||||
if (getbit (&wps->wvxbits)) {
|
||||
getbits (&temp, 23, &wps->wvxbits);
|
||||
set_mantissa (outval, temp);
|
||||
|
||||
if (exp >= 25) {
|
||||
getbits (&temp, 8, &wps->wvxbits);
|
||||
set_exponent (outval, temp);
|
||||
}
|
||||
|
||||
set_sign (outval, getbit (&wps->wvxbits));
|
||||
}
|
||||
else if (wps->float_flags & FLOAT_NEG_ZEROS)
|
||||
set_sign (outval, getbit (&wps->wvxbits));
|
||||
}
|
||||
}
|
||||
else {
|
||||
*values <<= wps->float_shift;
|
||||
|
||||
if (*values < 0) {
|
||||
*values = -*values;
|
||||
set_sign (outval, 1);
|
||||
}
|
||||
|
||||
if (*values == 0x1000000) {
|
||||
if (getbit (&wps->wvxbits)) {
|
||||
getbits (&temp, 23, &wps->wvxbits);
|
||||
set_mantissa (outval, temp);
|
||||
}
|
||||
|
||||
set_exponent (outval, 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);
|
||||
}
|
||||
}
|
||||
|
||||
set_mantissa (outval, *values);
|
||||
set_exponent (outval, exp);
|
||||
}
|
||||
}
|
||||
|
||||
crc = crc * 27 + get_mantissa (outval) * 9 + get_exponent (outval) * 3 + get_sign (outval);
|
||||
* (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;
|
||||
|
||||
if (*values) {
|
||||
*values <<= wps->float_shift;
|
||||
|
||||
if (*values < 0) {
|
||||
*values = -*values;
|
||||
set_sign (outval, 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);
|
||||
}
|
||||
|
||||
set_mantissa (outval, *values);
|
||||
set_exponent (outval, exp);
|
||||
}
|
||||
|
||||
* (f32 *) values++ = outval;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp)
|
||||
{
|
||||
f32 *fvalues = (f32 *) values;
|
||||
int exp;
|
||||
|
||||
if (!delta_exp)
|
||||
return;
|
||||
|
||||
while (num_values--) {
|
||||
if ((exp = get_exponent (*fvalues)) == 0 || exp + delta_exp <= 0)
|
||||
*fvalues = 0;
|
||||
else if (exp == 255 || (exp += delta_exp) >= 255) {
|
||||
set_exponent (*fvalues, 255);
|
||||
set_mantissa (*fvalues, 0);
|
||||
}
|
||||
else
|
||||
set_exponent (*fvalues, exp);
|
||||
|
||||
fvalues++;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,576 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="9.00"
|
||||
Name="libwavpack"
|
||||
ProjectGUID="{5CCCB9CF-0384-458F-BA08-72B73866840F}"
|
||||
RootNamespace="libwavpack"
|
||||
Keyword="Win32Proj"
|
||||
TargetFrameworkVersion="131072"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
<Platform
|
||||
Name="x64"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
<DefaultToolFile
|
||||
FileName="masm.rules"
|
||||
/>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="MASM"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;ENABLE_DSD"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="4"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="MASM"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;ENABLE_DSD"
|
||||
MinimalRebuild="true"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="1"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="MASM"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;ENABLE_DSD;OPT_ASM_X86"
|
||||
StringPooling="true"
|
||||
ExceptionHandling="0"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="false"
|
||||
EnableFunctionLevelLinking="true"
|
||||
DisableLanguageExtensions="false"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="0"
|
||||
CompileAs="0"
|
||||
OmitDefaultLibName="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
IgnoreAllDefaultLibraries="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
OutputDirectory="$(SolutionDir)$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="4"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="MASM"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="2"
|
||||
InlineFunctionExpansion="2"
|
||||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_CRT_SECURE_NO_DEPRECATE;ENABLE_DSD;OPT_ASM_X64"
|
||||
StringPooling="true"
|
||||
ExceptionHandling="0"
|
||||
RuntimeLibrary="0"
|
||||
BufferSecurityCheck="false"
|
||||
EnableFunctionLevelLinking="true"
|
||||
DisableLanguageExtensions="false"
|
||||
RuntimeTypeInfo="false"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="0"
|
||||
CompileAs="0"
|
||||
OmitDefaultLibName="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
IgnoreAllDefaultLibraries="true"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\decorr_tables.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack3.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\wavpack_local.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\wavpack_version.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\common_utils.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\decorr_utils.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\entropy_utils.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\extra1.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\extra2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\open_utils.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\open_filename.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\open_legacy.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\open_raw.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pack.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pack_dns.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pack_floats.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pack_utils.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pack_dsd.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pack_x64.asm"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\pack_x86.asm"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM"
|
||||
UseSafeExceptionHandlers="true"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM"
|
||||
UseSafeExceptionHandlers="true"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\read_words.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tag_utils.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\tags.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack3.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack3_open.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack3_seek.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack_floats.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack_seek.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack_utils.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack_dsd.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack_x64.asm"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\unpack_x86.asm"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM"
|
||||
UseSafeExceptionHandlers="true"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM"
|
||||
UseSafeExceptionHandlers="true"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Debug|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|x64"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="MASM64"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\write_words.c"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
@ -1,313 +0,0 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2006 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// metadata.c
|
||||
|
||||
// This module handles the metadata structure introduced in WavPack 4.0
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.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
|
||||
|
||||
#if !defined(NO_UNPACK) || defined(INFO_ONLY)
|
||||
|
||||
int read_metadata_buff (WavpackMetadata *wpmd, unsigned char *blockbuff, unsigned char **buffptr)
|
||||
{
|
||||
WavpackHeader *wphdr = (WavpackHeader *) blockbuff;
|
||||
unsigned char *buffend = blockbuff + wphdr->ckSize + 8;
|
||||
|
||||
if (buffend - *buffptr < 2)
|
||||
return FALSE;
|
||||
|
||||
wpmd->id = *(*buffptr)++;
|
||||
wpmd->byte_length = *(*buffptr)++ << 1;
|
||||
|
||||
if (wpmd->id & ID_LARGE) {
|
||||
wpmd->id &= ~ID_LARGE;
|
||||
|
||||
if (buffend - *buffptr < 2)
|
||||
return FALSE;
|
||||
|
||||
wpmd->byte_length += *(*buffptr)++ << 9;
|
||||
wpmd->byte_length += *(*buffptr)++ << 17;
|
||||
}
|
||||
|
||||
if (wpmd->id & ID_ODD_SIZE) {
|
||||
wpmd->id &= ~ID_ODD_SIZE;
|
||||
wpmd->byte_length--;
|
||||
}
|
||||
|
||||
if (wpmd->byte_length) {
|
||||
if (buffend - *buffptr < wpmd->byte_length + (wpmd->byte_length & 1)) {
|
||||
wpmd->data = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wpmd->data = *buffptr;
|
||||
(*buffptr) += wpmd->byte_length + (wpmd->byte_length & 1);
|
||||
}
|
||||
else
|
||||
wpmd->data = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
|
||||
switch (wpmd->id) {
|
||||
case ID_DUMMY:
|
||||
return TRUE;
|
||||
|
||||
case ID_DECORR_TERMS:
|
||||
return read_decorr_terms (wps, wpmd);
|
||||
|
||||
case ID_DECORR_WEIGHTS:
|
||||
return read_decorr_weights (wps, wpmd);
|
||||
|
||||
case ID_DECORR_SAMPLES:
|
||||
return read_decorr_samples (wps, wpmd);
|
||||
|
||||
case ID_ENTROPY_VARS:
|
||||
return read_entropy_vars (wps, wpmd);
|
||||
|
||||
case ID_HYBRID_PROFILE:
|
||||
return read_hybrid_profile (wps, wpmd);
|
||||
|
||||
case ID_SHAPING_WEIGHTS:
|
||||
return read_shaping_info (wps, wpmd);
|
||||
|
||||
case ID_FLOAT_INFO:
|
||||
return read_float_info (wps, wpmd);
|
||||
|
||||
case ID_INT32_INFO:
|
||||
return read_int32_info (wps, wpmd);
|
||||
|
||||
case ID_CHANNEL_INFO:
|
||||
return read_channel_info (wpc, wpmd);
|
||||
|
||||
case ID_CONFIG_BLOCK:
|
||||
return read_config_info (wpc, wpmd);
|
||||
|
||||
case ID_SAMPLE_RATE:
|
||||
return read_sample_rate (wpc, wpmd);
|
||||
|
||||
case ID_WV_BITSTREAM:
|
||||
return init_wv_bitstream (wps, wpmd);
|
||||
|
||||
case ID_WVC_BITSTREAM:
|
||||
return init_wvc_bitstream (wps, wpmd);
|
||||
|
||||
case ID_WVX_BITSTREAM:
|
||||
return init_wvx_bitstream (wps, wpmd);
|
||||
|
||||
case ID_RIFF_HEADER: case ID_RIFF_TRAILER:
|
||||
return read_wrapper_data (wpc, wpmd);
|
||||
|
||||
case ID_MD5_CHECKSUM:
|
||||
if (wpmd->byte_length == 16) {
|
||||
memcpy (wpc->config.md5_checksum, wpmd->data, 16);
|
||||
wpc->config.flags |= CONFIG_MD5_CHECKSUM;
|
||||
wpc->config.md5_read = 1;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return (wpmd->id & ID_OPTIONAL_DATA) ? TRUE : FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef NO_PACK
|
||||
|
||||
int copy_metadata (WavpackMetadata *wpmd, unsigned char *buffer_start, unsigned char *buffer_end)
|
||||
{
|
||||
uint32_t mdsize = wpmd->byte_length + (wpmd->byte_length & 1);
|
||||
WavpackHeader *wphdr = (WavpackHeader *) buffer_start;
|
||||
|
||||
if (wpmd->byte_length & 1)
|
||||
((char *) wpmd->data) [wpmd->byte_length] = 0;
|
||||
|
||||
mdsize += (wpmd->byte_length > 510) ? 4 : 2;
|
||||
buffer_start += wphdr->ckSize + 8;
|
||||
|
||||
if (buffer_start + mdsize >= buffer_end)
|
||||
return FALSE;
|
||||
|
||||
buffer_start [0] = wpmd->id | (wpmd->byte_length & 1 ? ID_ODD_SIZE : 0);
|
||||
buffer_start [1] = (wpmd->byte_length + 1) >> 1;
|
||||
|
||||
if (wpmd->byte_length > 510) {
|
||||
buffer_start [0] |= ID_LARGE;
|
||||
buffer_start [2] = (wpmd->byte_length + 1) >> 9;
|
||||
buffer_start [3] = (wpmd->byte_length + 1) >> 17;
|
||||
}
|
||||
|
||||
if (wpmd->data && wpmd->byte_length) {
|
||||
if (wpmd->byte_length > 510) {
|
||||
buffer_start [0] |= ID_LARGE;
|
||||
buffer_start [2] = (wpmd->byte_length + 1) >> 9;
|
||||
buffer_start [3] = (wpmd->byte_length + 1) >> 17;
|
||||
memcpy (buffer_start + 4, wpmd->data, mdsize - 4);
|
||||
}
|
||||
else
|
||||
memcpy (buffer_start + 2, wpmd->data, mdsize - 2);
|
||||
}
|
||||
|
||||
wphdr->ckSize += mdsize;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int add_to_metadata (WavpackContext *wpc, void *data, uint32_t bcount, unsigned char id)
|
||||
{
|
||||
WavpackMetadata *mdp;
|
||||
unsigned char *src = data;
|
||||
|
||||
while (bcount) {
|
||||
if (wpc->metacount) {
|
||||
uint32_t bc = bcount;
|
||||
|
||||
mdp = wpc->metadata + wpc->metacount - 1;
|
||||
|
||||
if (mdp->id == id) {
|
||||
if (wpc->metabytes + bcount > 1000000)
|
||||
bc = 1000000 - wpc->metabytes;
|
||||
|
||||
mdp->data = realloc (mdp->data, mdp->byte_length + bc);
|
||||
memcpy ((char *) mdp->data + mdp->byte_length, src, bc);
|
||||
mdp->byte_length += bc;
|
||||
wpc->metabytes += bc;
|
||||
bcount -= bc;
|
||||
src += bc;
|
||||
|
||||
if (wpc->metabytes >= 1000000 && !write_metadata_block (wpc))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (bcount) {
|
||||
wpc->metadata = realloc (wpc->metadata, (wpc->metacount + 1) * sizeof (WavpackMetadata));
|
||||
mdp = wpc->metadata + wpc->metacount++;
|
||||
mdp->byte_length = 0;
|
||||
mdp->data = NULL;
|
||||
mdp->id = id;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char *write_metadata (WavpackMetadata *wpmd, char *outdata)
|
||||
{
|
||||
unsigned char id = wpmd->id, wordlen [3];
|
||||
|
||||
wordlen [0] = (wpmd->byte_length + 1) >> 1;
|
||||
wordlen [1] = (wpmd->byte_length + 1) >> 9;
|
||||
wordlen [2] = (wpmd->byte_length + 1) >> 17;
|
||||
|
||||
if (wpmd->byte_length & 1) {
|
||||
// ((char *) wpmd->data) [wpmd->byte_length] = 0;
|
||||
id |= ID_ODD_SIZE;
|
||||
}
|
||||
|
||||
if (wordlen [1] || wordlen [2])
|
||||
id |= ID_LARGE;
|
||||
|
||||
*outdata++ = id;
|
||||
*outdata++ = wordlen [0];
|
||||
|
||||
if (id & ID_LARGE) {
|
||||
*outdata++ = wordlen [1];
|
||||
*outdata++ = wordlen [2];
|
||||
}
|
||||
|
||||
if (wpmd->data && wpmd->byte_length) {
|
||||
memcpy (outdata, wpmd->data, wpmd->byte_length);
|
||||
outdata += wpmd->byte_length;
|
||||
|
||||
if (wpmd->byte_length & 1)
|
||||
*outdata++ = 0;
|
||||
}
|
||||
|
||||
return outdata;
|
||||
}
|
||||
|
||||
int write_metadata_block (WavpackContext *wpc)
|
||||
{
|
||||
char *block_buff, *block_ptr;
|
||||
WavpackHeader *wphdr;
|
||||
|
||||
if (wpc->metacount) {
|
||||
int metacount = wpc->metacount, block_size = sizeof (WavpackHeader);
|
||||
WavpackMetadata *wpmdp = wpc->metadata;
|
||||
|
||||
while (metacount--) {
|
||||
block_size += wpmdp->byte_length + (wpmdp->byte_length & 1);
|
||||
block_size += (wpmdp->byte_length > 510) ? 4 : 2;
|
||||
wpmdp++;
|
||||
}
|
||||
|
||||
wphdr = (WavpackHeader *) (block_buff = malloc (block_size));
|
||||
|
||||
CLEAR (*wphdr);
|
||||
memcpy (wphdr->ckID, "wvpk", 4);
|
||||
wphdr->total_samples = wpc->total_samples;
|
||||
wphdr->version = wpc->stream_version;
|
||||
wphdr->ckSize = block_size - 8;
|
||||
wphdr->block_samples = 0;
|
||||
|
||||
block_ptr = (char *)(wphdr + 1);
|
||||
|
||||
wpmdp = wpc->metadata;
|
||||
|
||||
while (wpc->metacount) {
|
||||
block_ptr = write_metadata (wpmdp, block_ptr);
|
||||
wpc->metabytes -= wpmdp->byte_length;
|
||||
free_metadata (wpmdp++);
|
||||
wpc->metacount--;
|
||||
}
|
||||
|
||||
free (wpc->metadata);
|
||||
wpc->metadata = NULL;
|
||||
native_to_little_endian ((WavpackHeader *) block_buff, WavpackHeaderFormat);
|
||||
|
||||
if (!wpc->blockout (wpc->wv_out, block_buff, block_size)) {
|
||||
free (block_buff);
|
||||
strcpy (wpc->error_message, "can't write WavPack data, disk probably full!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
free (block_buff);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void free_metadata (WavpackMetadata *wpmd)
|
||||
{
|
||||
if (wpmd->data) {
|
||||
free (wpmd->data);
|
||||
wpmd->data = NULL;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,304 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// open_filename.c
|
||||
|
||||
// This module provides all the code required to open an existing WavPack
|
||||
// file, by filename, for reading. It does not contain the actual code to
|
||||
// unpack audio data and this was done so that programs that just want to
|
||||
// query WavPack files for information (like, for example, taggers) don't
|
||||
// need to link in a lot of unnecessary code.
|
||||
//
|
||||
// To allow opening files by filename, this code provides an interface
|
||||
// between the reader callback mechanism that WavPack uses internally and
|
||||
// the standard fstream C library. Note that in applications that do not
|
||||
// require opening files by filename, this module can be omitted (which
|
||||
// might make building easier).
|
||||
//
|
||||
// For Unicode support on Windows, a flag has been added (OPEN_FILE_UTF8)
|
||||
// that forces the filename string to be assumed UTF-8 and converted to
|
||||
// a widechar string suitable for _wfopen(). Without this flag we revert
|
||||
// to the previous behavior of simply calling fopen() and hoping that the
|
||||
// local character set works. This is ignored on non-Windows platforms
|
||||
// (which is okay because they are probably UTF-8 anyway).
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if (defined(__GNUC__) || defined(__sun)) && !defined(_WIN32)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef __OS2__
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define fileno _fileno
|
||||
static FILE *fopen_utf8 (const char *filename_utf8, const char *mode_utf8);
|
||||
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
|
||||
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FSEEKO
|
||||
#define fseek fseeko
|
||||
#define ftell ftello
|
||||
#endif
|
||||
|
||||
static int32_t read_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
return (int32_t) fread (data, 1, bcount, (FILE*) id);
|
||||
}
|
||||
|
||||
static int64_t get_pos (void *id)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _ftelli64 ((FILE*) id);
|
||||
#else
|
||||
return ftell ((FILE*) id);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int set_pos_abs (void *id, int64_t pos)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _fseeki64 (id, pos, SEEK_SET);
|
||||
#else
|
||||
return fseek (id, pos, SEEK_SET);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int set_pos_rel (void *id, int64_t delta, int mode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return _fseeki64 (id, delta, mode);
|
||||
#else
|
||||
return fseek (id, delta, mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int push_back_byte (void *id, int c)
|
||||
{
|
||||
return ungetc (c, id);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static int64_t get_length (void *id)
|
||||
{
|
||||
LARGE_INTEGER Size;
|
||||
HANDLE fHandle;
|
||||
|
||||
if (id == NULL)
|
||||
return 0;
|
||||
|
||||
fHandle = (HANDLE)_get_osfhandle(_fileno((FILE*) id));
|
||||
if (fHandle == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
Size.u.LowPart = GetFileSize(fHandle, &Size.u.HighPart);
|
||||
|
||||
if (Size.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
|
||||
return 0;
|
||||
|
||||
return (int64_t)Size.QuadPart;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int64_t get_length (void *id)
|
||||
{
|
||||
FILE *file = id;
|
||||
struct stat statbuf;
|
||||
|
||||
if (!file || fstat (fileno (file), &statbuf) || !S_ISREG(statbuf.st_mode))
|
||||
return 0;
|
||||
|
||||
return statbuf.st_size;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int can_seek (void *id)
|
||||
{
|
||||
FILE *file = id;
|
||||
struct stat statbuf;
|
||||
|
||||
return file && !fstat (fileno (file), &statbuf) && S_ISREG(statbuf.st_mode);
|
||||
}
|
||||
|
||||
static int32_t write_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
return (int32_t) fwrite (data, 1, bcount, (FILE*) id);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static int truncate_here (void *id)
|
||||
{
|
||||
FILE *file = id;
|
||||
int64_t curr_pos = _ftelli64 (file);
|
||||
|
||||
return _chsize_s (fileno (file), curr_pos);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int truncate_here (void *id)
|
||||
{
|
||||
FILE *file = id;
|
||||
off_t curr_pos = ftell (file);
|
||||
|
||||
return ftruncate (fileno (file), curr_pos);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int close_stream (void *id)
|
||||
{
|
||||
return fclose ((FILE*) id);
|
||||
}
|
||||
|
||||
// int32_t (*read_bytes)(void *id, void *data, int32_t bcount);
|
||||
// int32_t (*write_bytes)(void *id, void *data, int32_t bcount);
|
||||
// int64_t (*get_pos)(void *id); // new signature for large files
|
||||
// int (*set_pos_abs)(void *id, int64_t pos); // new signature for large files
|
||||
// int (*set_pos_rel)(void *id, int64_t delta, int mode); // new signature for large files
|
||||
// int (*push_back_byte)(void *id, int c);
|
||||
// int64_t (*get_length)(void *id); // new signature for large files
|
||||
// int (*can_seek)(void *id);
|
||||
// int (*truncate_here)(void *id); // new function to truncate file at current position
|
||||
// int (*close)(void *id); // new function to close file
|
||||
|
||||
static WavpackStreamReader64 freader = {
|
||||
read_bytes, write_bytes, get_pos, set_pos_abs, set_pos_rel,
|
||||
push_back_byte, get_length, can_seek, truncate_here, close_stream
|
||||
};
|
||||
|
||||
// This function attempts to open the specified WavPack file for reading. If
|
||||
// this fails for any reason then an appropriate message is copied to "error"
|
||||
// (which must accept 80 characters) and NULL is returned, otherwise a
|
||||
// pointer to a WavpackContext structure is returned (which is used to call
|
||||
// all other functions in this module). A filename beginning with "-" is
|
||||
// assumed to be stdin. The "flags" argument has the following bit mask
|
||||
// values to specify details of the open operation:
|
||||
|
||||
// OPEN_WVC: attempt to open/read "correction" file
|
||||
// OPEN_TAGS: attempt to read ID3v1 / APEv2 tags (requires seekable file)
|
||||
// OPEN_WRAPPER: make audio wrapper available (i.e. RIFF) to caller
|
||||
// OPEN_2CH_MAX: open only first stream of multichannel file (usually L/R)
|
||||
// OPEN_NORMALIZE: normalize floating point data to +/- 1.0 (w/ offset exp)
|
||||
// OPEN_STREAMING: blindly unpacks blocks w/o regard to header file position
|
||||
// OPEN_EDIT_TAGS: allow editing of tags (file must be writable)
|
||||
// OPEN_FILE_UTF8: assume infilename is UTF-8 encoded (Windows only)
|
||||
|
||||
// Version 4.2 of the WavPack library adds the OPEN_STREAMING flag. This is
|
||||
// essentially a "raw" mode where the library will simply decode any blocks
|
||||
// fed it through the reader callback, regardless of where those blocks came
|
||||
// from in a stream. The only requirement is that complete WavPack blocks are
|
||||
// fed to the decoder (and this may require multiple blocks in multichannel
|
||||
// mode) and that complete blocks are decoded (even if all samples are not
|
||||
// actually required). All the blocks must contain the same number of channels
|
||||
// and bit resolution, and the correction data must be either present or not.
|
||||
// All other parameters may change from block to block (like lossy/lossless).
|
||||
// Obviously, in this mode any seeking must be performed by the application
|
||||
// (and again, decoding must start at the beginning of the block containing
|
||||
// the seek sample).
|
||||
|
||||
WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset)
|
||||
{
|
||||
char *file_mode = (flags & OPEN_EDIT_TAGS) ? "r+b" : "rb";
|
||||
FILE *(*fopen_func)(const char *, const char *) = fopen;
|
||||
FILE *wv_id, *wvc_id;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (flags & OPEN_FILE_UTF8)
|
||||
fopen_func = fopen_utf8;
|
||||
#endif
|
||||
|
||||
if (*infilename == '-') {
|
||||
wv_id = stdin;
|
||||
#if defined(_WIN32)
|
||||
_setmode (fileno (stdin), O_BINARY);
|
||||
#endif
|
||||
#if defined(__OS2__)
|
||||
setmode (fileno (stdin), O_BINARY);
|
||||
#endif
|
||||
}
|
||||
else if ((wv_id = fopen_func (infilename, file_mode)) == NULL) {
|
||||
if (error) strcpy (error, (flags & OPEN_EDIT_TAGS) ? "can't open file for editing" : "can't open file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (wv_id != stdin && (flags & OPEN_WVC)) {
|
||||
char *in2filename = malloc (strlen (infilename) + 10);
|
||||
|
||||
strcpy (in2filename, infilename);
|
||||
strcat (in2filename, "c");
|
||||
wvc_id = fopen_func (in2filename, "rb");
|
||||
free (in2filename);
|
||||
}
|
||||
else
|
||||
wvc_id = NULL;
|
||||
|
||||
return WavpackOpenFileInputEx64 (&freader, wv_id, wvc_id, error, flags, norm_offset);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// The following code Copyright (c) 2004-2012 LoRd_MuldeR <mulder2@gmx.de>
|
||||
// (see cli/win32_unicode_support.c for full license)
|
||||
|
||||
static wchar_t *utf8_to_utf16(const char *input)
|
||||
{
|
||||
wchar_t *Buffer;
|
||||
int BuffSize = 0, Result = 0;
|
||||
|
||||
BuffSize = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
|
||||
Buffer = (wchar_t*) malloc(sizeof(wchar_t) * BuffSize);
|
||||
if(Buffer)
|
||||
{
|
||||
Result = MultiByteToWideChar(CP_UTF8, 0, input, -1, Buffer, BuffSize);
|
||||
}
|
||||
|
||||
return ((Result > 0) && (Result <= BuffSize)) ? Buffer : NULL;
|
||||
}
|
||||
|
||||
|
||||
static FILE *fopen_utf8(const char *filename_utf8, const char *mode_utf8)
|
||||
{
|
||||
FILE *ret = NULL;
|
||||
wchar_t *filename_utf16 = utf8_to_utf16(filename_utf8);
|
||||
wchar_t *mode_utf16 = utf8_to_utf16(mode_utf8);
|
||||
|
||||
if(filename_utf16 && mode_utf16)
|
||||
{
|
||||
ret = _wfopen(filename_utf16, mode_utf16);
|
||||
}
|
||||
|
||||
if(filename_utf16) free(filename_utf16);
|
||||
if(mode_utf16) free(mode_utf16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -0,0 +1,114 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2016 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// open_legacy.c
|
||||
|
||||
// This code provides an interface between the new reader callback mechanism that
|
||||
// WavPack uses internally and the old reader callback functions that did not
|
||||
// provide large file support.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
typedef struct {
|
||||
WavpackStreamReader *reader;
|
||||
void *id;
|
||||
} WavpackReaderTranslator;
|
||||
|
||||
static int32_t trans_read_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->read_bytes (trans->id, data, bcount);
|
||||
}
|
||||
|
||||
static int32_t trans_write_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->write_bytes (trans->id, data, bcount);
|
||||
}
|
||||
|
||||
static int64_t trans_get_pos (void *id)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->get_pos (trans->id);
|
||||
}
|
||||
|
||||
static int trans_set_pos_abs (void *id, int64_t pos)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->set_pos_abs (trans->id, (uint32_t) pos);
|
||||
}
|
||||
|
||||
static int trans_set_pos_rel (void *id, int64_t delta, int mode)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->set_pos_rel (trans->id, (int32_t) delta, mode);
|
||||
}
|
||||
|
||||
static int trans_push_back_byte (void *id, int c)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->push_back_byte (trans->id, c);
|
||||
}
|
||||
|
||||
static int64_t trans_get_length (void *id)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->get_length (trans->id);
|
||||
}
|
||||
|
||||
static int trans_can_seek (void *id)
|
||||
{
|
||||
WavpackReaderTranslator *trans = (WavpackReaderTranslator *)id;
|
||||
return trans->reader->can_seek (trans->id);
|
||||
}
|
||||
|
||||
static int trans_close_stream (void *id)
|
||||
{
|
||||
free (id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WavpackStreamReader64 trans_reader = {
|
||||
trans_read_bytes, trans_write_bytes, trans_get_pos, trans_set_pos_abs, trans_set_pos_rel,
|
||||
trans_push_back_byte, trans_get_length, trans_can_seek, NULL, trans_close_stream
|
||||
};
|
||||
|
||||
// This function is identical to WavpackOpenFileInput64() except that instead
|
||||
// of providing the new 64-bit reader callbacks, the old reader callbacks are
|
||||
// utilized and a translation layer is employed. It is provided as a compatibility
|
||||
// function for existing applications. To ensure that streaming applications using
|
||||
// this function continue to work, the OPEN_NO_CHECKSUM flag is forced on when
|
||||
// the OPEN_STREAMING flag is set.
|
||||
|
||||
WavpackContext *WavpackOpenFileInputEx (WavpackStreamReader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset)
|
||||
{
|
||||
WavpackReaderTranslator *trans_wv = NULL, *trans_wvc = NULL;
|
||||
|
||||
// this prevents existing streaming applications from failing if they try to pass
|
||||
// in blocks that have been modified from the original (e.g., Matroska blocks)
|
||||
|
||||
if (flags & OPEN_STREAMING)
|
||||
flags |= OPEN_NO_CHECKSUM;
|
||||
|
||||
if (wv_id) {
|
||||
trans_wv = (WavpackReaderTranslator *)malloc (sizeof (WavpackReaderTranslator));
|
||||
trans_wv->reader = reader;
|
||||
trans_wv->id = wv_id;
|
||||
}
|
||||
|
||||
if (wvc_id) {
|
||||
trans_wvc = (WavpackReaderTranslator *)malloc (sizeof (WavpackReaderTranslator));
|
||||
trans_wvc->reader = reader;
|
||||
trans_wvc->id = wvc_id;
|
||||
}
|
||||
|
||||
return WavpackOpenFileInputEx64 (&trans_reader, trans_wv, trans_wvc, error, flags, norm_offset);
|
||||
}
|
||||
@ -0,0 +1,315 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2016 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// open_raw.c
|
||||
|
||||
// This code provides the ability to decode WavPack frames directly from
|
||||
// memory for use in a streaming application. It can handle full blocks
|
||||
// or the headerless block data provided by Matroska and the DirectShow
|
||||
// WavPack splitter. For information about how Matroska stores WavPack,
|
||||
// see: https://www.matroska.org/technical/specs/codecid/wavpack.html
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned char *sptr, *dptr, *eptr, free_required;
|
||||
} RawSegment;
|
||||
|
||||
typedef struct {
|
||||
RawSegment *segments;
|
||||
int num_segments, curr_segment;
|
||||
unsigned char ungetc_char, ungetc_flag;
|
||||
} WavpackRawContext;
|
||||
|
||||
static int32_t raw_read_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
WavpackRawContext *rcxt = id;
|
||||
unsigned char *outptr = data;
|
||||
|
||||
while (bcount) {
|
||||
if (rcxt->ungetc_flag) {
|
||||
*outptr++ = rcxt->ungetc_char;
|
||||
rcxt->ungetc_flag = 0;
|
||||
bcount--;
|
||||
}
|
||||
else if (rcxt->curr_segment < rcxt->num_segments) {
|
||||
RawSegment *segptr = rcxt->segments + rcxt->curr_segment;
|
||||
int bytes_to_copy = (int)(segptr->eptr - segptr->dptr);
|
||||
|
||||
if (bytes_to_copy > bcount)
|
||||
bytes_to_copy = bcount;
|
||||
|
||||
memcpy (outptr, segptr->dptr, bytes_to_copy);
|
||||
outptr += bytes_to_copy;
|
||||
bcount -= bytes_to_copy;
|
||||
|
||||
if ((segptr->dptr += bytes_to_copy) == segptr->eptr)
|
||||
rcxt->curr_segment++;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return (int32_t)(outptr - (unsigned char *) data);
|
||||
}
|
||||
|
||||
static int32_t raw_write_bytes (void *id, void *data, int32_t bcount)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int64_t raw_get_pos (void *id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_set_pos_abs (void *id, int64_t pos)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_set_pos_rel (void *id, int64_t delta, int mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_push_back_byte (void *id, int c)
|
||||
{
|
||||
WavpackRawContext *rcxt = id;
|
||||
rcxt->ungetc_char = c;
|
||||
rcxt->ungetc_flag = 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
static int64_t raw_get_length (void *id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_can_seek (void *id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int raw_close_stream (void *id)
|
||||
{
|
||||
WavpackRawContext *rcxt = id;
|
||||
int i;
|
||||
|
||||
if (rcxt) {
|
||||
for (i = 0; i < rcxt->num_segments; ++i)
|
||||
if (rcxt->segments [i].sptr && rcxt->segments [i].free_required)
|
||||
free (rcxt->segments [i].sptr);
|
||||
|
||||
if (rcxt->segments) free (rcxt->segments);
|
||||
free (rcxt);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static WavpackStreamReader64 raw_reader = {
|
||||
raw_read_bytes, raw_write_bytes, raw_get_pos, raw_set_pos_abs, raw_set_pos_rel,
|
||||
raw_push_back_byte, raw_get_length, raw_can_seek, NULL, raw_close_stream
|
||||
};
|
||||
|
||||
// This function is similar to WavpackOpenFileInput() except that instead of
|
||||
// providing a filename to open, the caller provides pointers to buffered
|
||||
// WavPack frames (both standard and, optionally, correction data). It
|
||||
// decodes only a single frame. Note that in this context, a "frame" is a
|
||||
// collection of WavPack blocks that represent all the channels present. In
|
||||
// the case of mono or [most] stereo streams, this is the same thing, but
|
||||
// for multichannel streams each frame consists of several WavPack blocks
|
||||
// (which can contain only 1 or 2 channels).
|
||||
|
||||
WavpackContext *WavpackOpenRawDecoder (
|
||||
void *main_data, int32_t main_size,
|
||||
void *corr_data, int32_t corr_size,
|
||||
int16_t version, char *error, int flags, int norm_offset)
|
||||
{
|
||||
WavpackRawContext *raw_wv = NULL, *raw_wvc = NULL;
|
||||
|
||||
// if the WavPack data does not contain headers we assume Matroska-style storage
|
||||
// and recreate the missing headers
|
||||
|
||||
if (strncmp (main_data, "wvpk", 4)) {
|
||||
uint32_t multiple_blocks = 0, block_size, block_samples = 0, wphdr_flags, crc;
|
||||
uint32_t main_bytes = main_size, corr_bytes = corr_size;
|
||||
unsigned char *mcp = main_data;
|
||||
unsigned char *ccp = corr_data;
|
||||
int msi = 0, csi = 0;
|
||||
|
||||
raw_wv = malloc (sizeof (WavpackRawContext));
|
||||
memset (raw_wv, 0, sizeof (WavpackRawContext));
|
||||
|
||||
if (corr_data && corr_size) {
|
||||
raw_wvc = malloc (sizeof (WavpackRawContext));
|
||||
memset (raw_wvc, 0, sizeof (WavpackRawContext));
|
||||
}
|
||||
|
||||
while (main_bytes >= 12) {
|
||||
WavpackHeader *wphdr = malloc (sizeof (WavpackHeader));
|
||||
|
||||
if (!msi) {
|
||||
block_samples = *mcp++;
|
||||
block_samples += *mcp++ << 8;
|
||||
block_samples += *mcp++ << 16;
|
||||
block_samples += *mcp++ << 24;
|
||||
main_bytes -= 4;
|
||||
}
|
||||
|
||||
wphdr_flags = *mcp++;
|
||||
wphdr_flags += *mcp++ << 8;
|
||||
wphdr_flags += *mcp++ << 16;
|
||||
wphdr_flags += *mcp++ << 24;
|
||||
main_bytes -= 4;
|
||||
|
||||
// if the first block does not have the FINAL_BLOCK flag set,
|
||||
// then there are multiple blocks
|
||||
|
||||
if (!msi && !(wphdr_flags & FINAL_BLOCK))
|
||||
multiple_blocks = 1;
|
||||
|
||||
crc = *mcp++;
|
||||
crc += *mcp++ << 8;
|
||||
crc += *mcp++ << 16;
|
||||
crc += *mcp++ << 24;
|
||||
main_bytes -= 4;
|
||||
|
||||
if (multiple_blocks) {
|
||||
block_size = *mcp++;
|
||||
block_size += *mcp++ << 8;
|
||||
block_size += *mcp++ << 16;
|
||||
block_size += *mcp++ << 24;
|
||||
main_bytes -= 4;
|
||||
}
|
||||
else
|
||||
block_size = main_bytes;
|
||||
|
||||
if (block_size > main_bytes) {
|
||||
if (error) strcpy (error, "main block overran available data!");
|
||||
raw_close_stream (raw_wv);
|
||||
raw_close_stream (raw_wvc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset (wphdr, 0, sizeof (WavpackHeader));
|
||||
memcpy (wphdr->ckID, "wvpk", 4);
|
||||
wphdr->ckSize = sizeof (WavpackHeader) - 8 + block_size;
|
||||
SET_TOTAL_SAMPLES (*wphdr, block_samples);
|
||||
wphdr->block_samples = block_samples;
|
||||
wphdr->version = version;
|
||||
wphdr->flags = wphdr_flags;
|
||||
wphdr->crc = crc;
|
||||
WavpackLittleEndianToNative (wphdr, WavpackHeaderFormat);
|
||||
|
||||
raw_wv->num_segments += 2;
|
||||
raw_wv->segments = realloc (raw_wv->segments, sizeof (RawSegment) * raw_wv->num_segments);
|
||||
raw_wv->segments [msi].dptr = raw_wv->segments [msi].sptr = (unsigned char *) wphdr;
|
||||
raw_wv->segments [msi].eptr = raw_wv->segments [msi].dptr + sizeof (WavpackHeader);
|
||||
raw_wv->segments [msi++].free_required = 1;
|
||||
raw_wv->segments [msi].dptr = raw_wv->segments [msi].sptr = mcp;
|
||||
raw_wv->segments [msi].eptr = raw_wv->segments [msi].dptr + block_size;
|
||||
raw_wv->segments [msi++].free_required = 0;
|
||||
main_bytes -= block_size;
|
||||
mcp += block_size;
|
||||
|
||||
if (corr_data && corr_bytes >= 4) {
|
||||
wphdr = malloc (sizeof (WavpackHeader));
|
||||
|
||||
crc = *ccp++;
|
||||
crc += *ccp++ << 8;
|
||||
crc += *ccp++ << 16;
|
||||
crc += *ccp++ << 24;
|
||||
corr_bytes -= 4;
|
||||
|
||||
if (multiple_blocks) {
|
||||
block_size = *ccp++;
|
||||
block_size += *ccp++ << 8;
|
||||
block_size += *ccp++ << 16;
|
||||
block_size += *ccp++ << 24;
|
||||
corr_bytes -= 4;
|
||||
}
|
||||
else
|
||||
block_size = corr_bytes;
|
||||
|
||||
if (block_size > corr_bytes) {
|
||||
if (error) strcpy (error, "correction block overran available data!");
|
||||
raw_close_stream (raw_wv);
|
||||
raw_close_stream (raw_wvc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset (wphdr, 0, sizeof (WavpackHeader));
|
||||
memcpy (wphdr->ckID, "wvpk", 4);
|
||||
wphdr->ckSize = sizeof (WavpackHeader) - 8 + block_size;
|
||||
SET_TOTAL_SAMPLES (*wphdr, block_samples);
|
||||
wphdr->block_samples = block_samples;
|
||||
wphdr->version = version;
|
||||
wphdr->flags = wphdr_flags;
|
||||
wphdr->crc = crc;
|
||||
WavpackLittleEndianToNative (wphdr, WavpackHeaderFormat);
|
||||
|
||||
raw_wvc->num_segments += 2;
|
||||
raw_wvc->segments = realloc (raw_wvc->segments, sizeof (RawSegment) * raw_wvc->num_segments);
|
||||
raw_wvc->segments [csi].dptr = raw_wvc->segments [csi].sptr = (unsigned char *) wphdr;
|
||||
raw_wvc->segments [csi].eptr = raw_wvc->segments [csi].dptr + sizeof (WavpackHeader);
|
||||
raw_wvc->segments [csi++].free_required = 1;
|
||||
raw_wvc->segments [csi].dptr = raw_wvc->segments [csi].sptr = ccp;
|
||||
raw_wvc->segments [csi].eptr = raw_wvc->segments [csi].dptr + block_size;
|
||||
raw_wvc->segments [csi++].free_required = 0;
|
||||
corr_bytes -= block_size;
|
||||
ccp += block_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (main_bytes || (corr_data && corr_bytes)) {
|
||||
if (error) strcpy (error, "leftover multiblock data!");
|
||||
raw_close_stream (raw_wv);
|
||||
raw_close_stream (raw_wvc);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else { // the case of WavPack blocks with headers is much easier...
|
||||
if (main_data) {
|
||||
raw_wv = malloc (sizeof (WavpackRawContext));
|
||||
memset (raw_wv, 0, sizeof (WavpackRawContext));
|
||||
raw_wv->num_segments = 1;
|
||||
raw_wv->segments = malloc (sizeof (RawSegment) * raw_wv->num_segments);
|
||||
raw_wv->segments [0].dptr = raw_wv->segments [0].sptr = main_data;
|
||||
raw_wv->segments [0].eptr = raw_wv->segments [0].dptr + main_size;
|
||||
raw_wv->segments [0].free_required = 0;
|
||||
}
|
||||
|
||||
if (corr_data && corr_size) {
|
||||
raw_wvc = malloc (sizeof (WavpackRawContext));
|
||||
memset (raw_wvc, 0, sizeof (WavpackRawContext));
|
||||
raw_wvc->num_segments = 1;
|
||||
raw_wvc->segments = malloc (sizeof (RawSegment) * raw_wvc->num_segments);
|
||||
raw_wvc->segments [0].dptr = raw_wvc->segments [0].sptr = corr_data;
|
||||
raw_wvc->segments [0].eptr = raw_wvc->segments [0].dptr + corr_size;
|
||||
raw_wvc->segments [0].free_required = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return WavpackOpenFileInputEx64 (&raw_reader, raw_wv, raw_wvc, error, flags | OPEN_STREAMING | OPEN_NO_CHECKSUM, norm_offset);
|
||||
}
|
||||
|
||||
// Return the number of samples represented by the current (and in the raw case, only) frame.
|
||||
|
||||
uint32_t WavpackGetNumSamplesInFrame (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc && wpc->streams && wpc->streams [0])
|
||||
return wpc->streams [0]->wphdr.block_samples;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,191 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// pack_dns.c
|
||||
|
||||
// This module handles the implementation of "dynamic noise shaping" which is
|
||||
// designed to move the spectrum of the quantization noise introduced by lossy
|
||||
// compression up or down in frequency so that it is more likely to be masked
|
||||
// by the source material.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
static void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error);
|
||||
|
||||
void dynamic_noise_shaping (WavpackContext *wpc, int32_t *buffer, int shortening_allowed)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int32_t sample_count = wps->wphdr.block_samples;
|
||||
struct decorr_pass *ap = &wps->analysis_pass;
|
||||
uint32_t flags = wps->wphdr.flags;
|
||||
int32_t *bptr, temp, sam;
|
||||
short *swptr;
|
||||
int sc;
|
||||
|
||||
if (!wps->num_terms && sample_count > 8) {
|
||||
if (flags & MONO_DATA)
|
||||
for (bptr = buffer + sample_count - 3, sc = sample_count - 2; sc--;) {
|
||||
sam = (3 * bptr [1] - bptr [2]) >> 1;
|
||||
temp = *bptr-- - apply_weight (ap->weight_A, sam);
|
||||
update_weight (ap->weight_A, 2, sam, temp);
|
||||
}
|
||||
else
|
||||
for (bptr = buffer + (sample_count - 3) * 2 + 1, sc = sample_count - 2; sc--;) {
|
||||
sam = (3 * bptr [2] - bptr [4]) >> 1;
|
||||
temp = *bptr-- - apply_weight (ap->weight_B, sam);
|
||||
update_weight (ap->weight_B, 2, sam, temp);
|
||||
sam = (3 * bptr [2] - bptr [4]) >> 1;
|
||||
temp = *bptr-- - apply_weight (ap->weight_A, sam);
|
||||
update_weight (ap->weight_A, 2, sam, temp);
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_count > wps->dc.shaping_samples) {
|
||||
sc = sample_count - wps->dc.shaping_samples;
|
||||
swptr = wps->dc.shaping_data + wps->dc.shaping_samples;
|
||||
bptr = buffer + wps->dc.shaping_samples * ((flags & MONO_DATA) ? 1 : 2);
|
||||
|
||||
if (flags & MONO_DATA)
|
||||
while (sc--) {
|
||||
sam = (3 * ap->samples_A [0] - ap->samples_A [1]) >> 1;
|
||||
temp = *bptr - apply_weight (ap->weight_A, sam);
|
||||
update_weight (ap->weight_A, 2, sam, temp);
|
||||
ap->samples_A [1] = ap->samples_A [0];
|
||||
ap->samples_A [0] = *bptr++;
|
||||
*swptr++ = (ap->weight_A < 256) ? 1024 : 1536 - ap->weight_A * 2;
|
||||
}
|
||||
else
|
||||
while (sc--) {
|
||||
sam = (3 * ap->samples_A [0] - ap->samples_A [1]) >> 1;
|
||||
temp = *bptr - apply_weight (ap->weight_A, sam);
|
||||
update_weight (ap->weight_A, 2, sam, temp);
|
||||
ap->samples_A [1] = ap->samples_A [0];
|
||||
ap->samples_A [0] = *bptr++;
|
||||
|
||||
sam = (3 * ap->samples_B [0] - ap->samples_B [1]) >> 1;
|
||||
temp = *bptr - apply_weight (ap->weight_B, sam);
|
||||
update_weight (ap->weight_B, 2, sam, temp);
|
||||
ap->samples_B [1] = ap->samples_B [0];
|
||||
ap->samples_B [0] = *bptr++;
|
||||
|
||||
*swptr++ = (ap->weight_A + ap->weight_B < 512) ? 1024 : 1536 - ap->weight_A - ap->weight_B;
|
||||
}
|
||||
|
||||
wps->dc.shaping_samples = sample_count;
|
||||
}
|
||||
|
||||
if (wpc->wvc_flag) {
|
||||
int max_allowed_error = 1000000 / wpc->ave_block_samples;
|
||||
short max_error, trial_max_error;
|
||||
double initial_y, final_y;
|
||||
|
||||
if (max_allowed_error < 128)
|
||||
max_allowed_error = 128;
|
||||
|
||||
best_floating_line (wps->dc.shaping_data, sample_count, &initial_y, &final_y, &max_error);
|
||||
|
||||
if (shortening_allowed && max_error > max_allowed_error) {
|
||||
int min_samples = 0, max_samples = sample_count, trial_count;
|
||||
double trial_initial_y, trial_final_y;
|
||||
|
||||
while (1) {
|
||||
trial_count = (min_samples + max_samples) / 2;
|
||||
|
||||
best_floating_line (wps->dc.shaping_data, trial_count, &trial_initial_y,
|
||||
&trial_final_y, &trial_max_error);
|
||||
|
||||
if (trial_max_error < max_allowed_error) {
|
||||
max_error = trial_max_error;
|
||||
min_samples = trial_count;
|
||||
initial_y = trial_initial_y;
|
||||
final_y = trial_final_y;
|
||||
}
|
||||
else
|
||||
max_samples = trial_count;
|
||||
|
||||
if (min_samples > 10000 || max_samples - min_samples < 2)
|
||||
break;
|
||||
}
|
||||
|
||||
sample_count = min_samples;
|
||||
}
|
||||
|
||||
if (initial_y < -512) initial_y = -512;
|
||||
else if (initial_y > 1024) initial_y = 1024;
|
||||
|
||||
if (final_y < -512) final_y = -512;
|
||||
else if (final_y > 1024) final_y = 1024;
|
||||
#if 0
|
||||
error_line ("%.2f sec, sample count = %5d, max error = %3d, range = %5d, %5d, actual = %5d, %5d",
|
||||
(double) wps->sample_index / wpc->config.sample_rate, sample_count, max_error,
|
||||
(int) floor (initial_y), (int) floor (final_y),
|
||||
wps->dc.shaping_data [0], wps->dc.shaping_data [sample_count-1]);
|
||||
#endif
|
||||
if (sample_count != wps->wphdr.block_samples)
|
||||
wps->wphdr.block_samples = sample_count;
|
||||
|
||||
if (wpc->wvc_flag) {
|
||||
wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = (int32_t) floor (initial_y * 65536.0 + 0.5);
|
||||
|
||||
wps->dc.shaping_delta [0] = wps->dc.shaping_delta [1] =
|
||||
(int32_t) floor ((final_y - initial_y) / (sample_count - 1) * 65536.0 + 0.5);
|
||||
|
||||
wps->dc.shaping_array = NULL;
|
||||
}
|
||||
else
|
||||
wps->dc.shaping_array = wps->dc.shaping_data;
|
||||
}
|
||||
else
|
||||
wps->dc.shaping_array = wps->dc.shaping_data;
|
||||
}
|
||||
|
||||
// Given an array of integer data (in shorts), find the linear function that most closely
|
||||
// represents it (based on minimum sum of absolute errors). This is returned as the double
|
||||
// precision initial & final Y values of the best-fit line. The function can also optionally
|
||||
// compute and return a maximum error value (as a short). Note that the ends of the resulting
|
||||
// line may fall way outside the range of input values, so some sort of clipping may be
|
||||
// needed.
|
||||
|
||||
static void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error)
|
||||
{
|
||||
double left_sum = 0.0, right_sum = 0.0, center_x = (num_values - 1) / 2.0, center_y, m;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_values >> 1; ++i) {
|
||||
right_sum += values [num_values - i - 1];
|
||||
left_sum += values [i];
|
||||
}
|
||||
|
||||
if (num_values & 1) {
|
||||
right_sum += values [num_values >> 1] * 0.5;
|
||||
left_sum += values [num_values >> 1] * 0.5;
|
||||
}
|
||||
|
||||
center_y = (right_sum + left_sum) / num_values;
|
||||
m = (right_sum - left_sum) / ((double) num_values * num_values) * 4.0;
|
||||
|
||||
if (initial_y)
|
||||
*initial_y = center_y - m * center_x;
|
||||
|
||||
if (final_y)
|
||||
*final_y = center_y + m * center_x;
|
||||
|
||||
if (max_error) {
|
||||
double max = 0.0;
|
||||
|
||||
for (i = 0; i < num_values; ++i)
|
||||
if (fabs (values [i] - (center_y + (i - center_x) * m)) > max)
|
||||
max = fabs (values [i] - (center_y + (i - center_x) * m));
|
||||
|
||||
*max_error = (short) floor (max + 0.5);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,669 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** DSDPACK **** //
|
||||
// Lossless DSD (Direct Stream Digital) Audio Compressor //
|
||||
// Copyright (c) 2013 - 2016 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// pack_dsd.c
|
||||
|
||||
// This module actually handles the compression of the DSD audio data.
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// This function initializes everything required to pack WavPack DSD bitstreams
|
||||
// and must be called BEFORE any other function in this module.
|
||||
|
||||
void pack_dsd_init (WavpackContext *wpc)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
|
||||
wps->sample_index = 0;
|
||||
}
|
||||
|
||||
// Pack an entire block of samples (either mono or stereo) into a completed
|
||||
// WavPack block. This function is actually a shell for pack_samples() and
|
||||
// performs tasks like handling any shift required by the format, preprocessing
|
||||
// of floating point data or integer data over 24 bits wide, and implementing
|
||||
// the "extra" mode (via the extra?.c modules). It is assumed that there is
|
||||
// sufficient space for the completed block at "wps->blockbuff" and that
|
||||
// "wps->blockend" points to the end of the available space. A return value of
|
||||
// FALSE indicates an error.
|
||||
|
||||
// Pack an entire block of samples (either mono or stereo) into a completed
|
||||
// WavPack block. It is assumed that there is sufficient space for the
|
||||
// completed block at "wps->blockbuff" and that "wps->blockend" points to the
|
||||
// end of the available space. A return value of FALSE indicates an error.
|
||||
// Any unsent metadata is transmitted first, then required metadata for this
|
||||
// block is sent, and finally the compressed integer data is sent. If a "wpx"
|
||||
// stream is required for floating point data or large integer data, then this
|
||||
// must be handled outside this function. To find out how much data was written
|
||||
// the caller must look at the ckSize field of the written WavpackHeader, NOT
|
||||
// the one in the WavpackStream.
|
||||
|
||||
static int encode_buffer_high (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination);
|
||||
static int encode_buffer_fast (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination);
|
||||
|
||||
int pack_dsd_block (WavpackContext *wpc, int32_t *buffer)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
uint32_t flags = wps->wphdr.flags, mult = wpc->dsd_multiplier, data_count;
|
||||
uint32_t sample_count = wps->wphdr.block_samples;
|
||||
unsigned char *dsd_encoding, dsd_power = 0;
|
||||
int32_t res;
|
||||
|
||||
// This code scans stereo data to check whether it can be stored as mono data
|
||||
// (i.e., all L/R samples identical).
|
||||
|
||||
if (!(flags & MONO_FLAG)) {
|
||||
int32_t *sptr, *dptr, i;
|
||||
|
||||
for (sptr = buffer, i = 0; i < (int32_t) sample_count; sptr += 2, i++)
|
||||
if ((sptr [0] ^ sptr [1]) & 0xff)
|
||||
break;
|
||||
|
||||
if (i == sample_count) {
|
||||
wps->wphdr.flags = flags |= FALSE_STEREO;
|
||||
dptr = buffer;
|
||||
sptr = buffer;
|
||||
|
||||
for (i = sample_count; i--; sptr++)
|
||||
*dptr++ = *sptr++;
|
||||
}
|
||||
else
|
||||
wps->wphdr.flags = flags &= ~FALSE_STEREO;
|
||||
}
|
||||
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader));
|
||||
|
||||
if (wpc->metacount) {
|
||||
WavpackMetadata *wpmdp = wpc->metadata;
|
||||
|
||||
while (wpc->metacount) {
|
||||
copy_metadata (wpmdp, wps->blockbuff, wps->blockend);
|
||||
wpc->metabytes -= wpmdp->byte_length;
|
||||
free_metadata (wpmdp++);
|
||||
wpc->metacount--;
|
||||
}
|
||||
|
||||
free (wpc->metadata);
|
||||
wpc->metadata = NULL;
|
||||
}
|
||||
|
||||
if (!sample_count)
|
||||
return TRUE;
|
||||
|
||||
send_general_metadata (wpc);
|
||||
memcpy (&wps->wphdr, wps->blockbuff, sizeof (WavpackHeader));
|
||||
|
||||
dsd_encoding = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12;
|
||||
|
||||
while (mult >>= 1)
|
||||
dsd_power++;
|
||||
|
||||
*dsd_encoding++ = dsd_power;
|
||||
|
||||
if (wpc->config.flags & CONFIG_HIGH_FLAG) {
|
||||
int fast_res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding);
|
||||
|
||||
res = encode_buffer_high (wps, buffer, sample_count, dsd_encoding);
|
||||
|
||||
if ((fast_res != -1) && (res == -1 || res > fast_res))
|
||||
res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding);
|
||||
}
|
||||
else
|
||||
res = encode_buffer_fast (wps, buffer, sample_count, dsd_encoding);
|
||||
|
||||
if (res == -1) {
|
||||
int num_samples = sample_count * ((flags & MONO_DATA) ? 1 : 2);
|
||||
uint32_t crc = 0xffffffff;
|
||||
|
||||
*dsd_encoding++ = 0;
|
||||
|
||||
data_count = num_samples + 2;
|
||||
|
||||
while (num_samples--)
|
||||
crc += (crc << 1) + (*dsd_encoding++ = *buffer++);
|
||||
|
||||
((WavpackHeader *) wps->blockbuff)->crc = crc;
|
||||
}
|
||||
else
|
||||
data_count = res + 1;
|
||||
|
||||
if (data_count) {
|
||||
unsigned char *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8;
|
||||
|
||||
if (data_count & 1) {
|
||||
cptr [data_count + 4] = 0;
|
||||
*cptr++ = ID_DSD_BLOCK | ID_LARGE | ID_ODD_SIZE;
|
||||
data_count++;
|
||||
}
|
||||
else
|
||||
*cptr++ = ID_DSD_BLOCK | ID_LARGE;
|
||||
|
||||
*cptr++ = data_count >> 1;
|
||||
*cptr++ = data_count >> 9;
|
||||
*cptr++ = data_count >> 17;
|
||||
((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4;
|
||||
}
|
||||
|
||||
wps->sample_index += sample_count;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
// #define DSD_BYTE_READY(low,high) (((low) >> 24) == ((high) >> 24))
|
||||
// #define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) >> 24))
|
||||
#define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) & 0xff000000))
|
||||
|
||||
#define MAX_HISTORY_BITS 5
|
||||
#define MAX_PROBABILITY 0xa0 // set to 0xff to disable RLE encoding for probabilities table
|
||||
|
||||
#if (MAX_PROBABILITY < 0xff)
|
||||
|
||||
static int rle_encode (unsigned char *src, int bcount, unsigned char *destination)
|
||||
{
|
||||
int max_rle_zeros = 0xff - MAX_PROBABILITY;
|
||||
unsigned char *dp = destination;
|
||||
int zcount = 0;
|
||||
|
||||
while (bcount--) {
|
||||
if (*src) {
|
||||
while (zcount) {
|
||||
*dp++ = MAX_PROBABILITY + (zcount > max_rle_zeros ? max_rle_zeros : zcount);
|
||||
zcount -= (zcount > max_rle_zeros ? max_rle_zeros : zcount);
|
||||
}
|
||||
|
||||
*dp++ = *src++;
|
||||
}
|
||||
else {
|
||||
zcount++;
|
||||
src++;
|
||||
}
|
||||
}
|
||||
|
||||
while (zcount) {
|
||||
*dp++ = MAX_PROBABILITY + (zcount > max_rle_zeros ? max_rle_zeros : zcount);
|
||||
zcount -= (zcount > max_rle_zeros ? max_rle_zeros : zcount);
|
||||
}
|
||||
|
||||
*dp++ = 0;
|
||||
|
||||
return (int)(dp - destination);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void calculate_probabilities (int hist [256], unsigned char probs [256], unsigned short prob_sums [256])
|
||||
{
|
||||
int divisor, min_value, max_value, sum_values;
|
||||
int min_hits = 0x7fffffff, max_hits = 0, i;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
if (hist [i] < min_hits) min_hits = hist [i];
|
||||
if (hist [i] > max_hits) max_hits = hist [i];
|
||||
}
|
||||
|
||||
if (max_hits == 0) {
|
||||
memset (probs, 0, sizeof (*probs) * 256);
|
||||
memset (prob_sums, 0, sizeof (*prob_sums) * 256);
|
||||
return;
|
||||
}
|
||||
|
||||
// fprintf (stderr, "process_histogram(): hits = %d to %d\n", min_hits, max_hits);
|
||||
|
||||
if (max_hits > MAX_PROBABILITY)
|
||||
divisor = ((max_hits << 8) + (MAX_PROBABILITY >> 1)) / MAX_PROBABILITY;
|
||||
else
|
||||
divisor = 0;
|
||||
|
||||
while (1) {
|
||||
min_value = 0x7fffffff; max_value = 0; sum_values = 0;
|
||||
|
||||
for (i = 0; i < 256; ++i) {
|
||||
int value;
|
||||
|
||||
if (hist [i]) {
|
||||
if (divisor) {
|
||||
if (!(value = ((hist [i] << 8) + (divisor >> 1)) / divisor))
|
||||
value = 1;
|
||||
}
|
||||
else
|
||||
value = hist [i];
|
||||
|
||||
if (value < min_value) min_value = value;
|
||||
if (value > max_value) max_value = value;
|
||||
}
|
||||
else
|
||||
value = 0;
|
||||
|
||||
prob_sums [i] = sum_values += value;
|
||||
probs [i] = value;
|
||||
}
|
||||
|
||||
if (max_value > MAX_PROBABILITY) {
|
||||
divisor++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 0 // this code reduces probability values when they are completely redundant (i.e., common divisor), but
|
||||
// this doesn't really happen often enough to make it worthwhile
|
||||
|
||||
if (min_value > 1) {
|
||||
for (i = 0; i < 256; ++i)
|
||||
if (probs [i] % min_value)
|
||||
break;
|
||||
|
||||
if (i == 256) {
|
||||
for (i = 0; i < 256; ++i) {
|
||||
prob_sums [i] /= min_value;
|
||||
probs [i] /= min_value;
|
||||
}
|
||||
|
||||
// fprintf (stderr, "fixed min_value = %d, divisor = %d, probs_sum = %d\n", min_value, divisor, prob_sums [255]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int encode_buffer_fast (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination)
|
||||
{
|
||||
uint32_t flags = wps->wphdr.flags, crc = 0xffffffff;
|
||||
unsigned int low = 0, high = 0xffffffff, mult;
|
||||
unsigned short (*summed_probabilities) [256];
|
||||
unsigned char (*probabilities) [256];
|
||||
unsigned char *dp = destination, *ep;
|
||||
int history_bins, bc, p0 = 0, p1 = 0;
|
||||
int total_summed_probabilities = 0;
|
||||
int (*histogram) [256];
|
||||
int32_t *bp = buffer;
|
||||
char history_bits;
|
||||
|
||||
if (!(flags & MONO_DATA))
|
||||
num_samples *= 2;
|
||||
|
||||
if (num_samples < 280)
|
||||
return -1;
|
||||
else if (num_samples < 560)
|
||||
history_bits = 0;
|
||||
else if (num_samples < 1725)
|
||||
history_bits = 1;
|
||||
else if (num_samples < 5000)
|
||||
history_bits = 2;
|
||||
else if (num_samples < 14000)
|
||||
history_bits = 3;
|
||||
else if (num_samples < 28000)
|
||||
history_bits = 4;
|
||||
else if (num_samples < 76000)
|
||||
history_bits = 5;
|
||||
else if (num_samples < 130000)
|
||||
history_bits = 6;
|
||||
else if (num_samples < 300000)
|
||||
history_bits = 7;
|
||||
else
|
||||
history_bits = 8;
|
||||
|
||||
if (history_bits > MAX_HISTORY_BITS)
|
||||
history_bits = MAX_HISTORY_BITS;
|
||||
|
||||
history_bins = 1 << history_bits;
|
||||
histogram = malloc (sizeof (*histogram) * history_bins);
|
||||
memset (histogram, 0, sizeof (*histogram) * history_bins);
|
||||
probabilities = malloc (sizeof (*probabilities) * history_bins);
|
||||
summed_probabilities = malloc (sizeof (*summed_probabilities) * history_bins);
|
||||
|
||||
bc = num_samples;
|
||||
|
||||
if (flags & MONO_DATA)
|
||||
while (bc--) {
|
||||
crc += (crc << 1) + (*bp & 0xff);
|
||||
histogram [p0] [*bp & 0xff]++;
|
||||
p0 = *bp++ & (history_bins-1);
|
||||
}
|
||||
else
|
||||
while (bc--) {
|
||||
crc += (crc << 1) + (*bp & 0xff);
|
||||
histogram [p0] [*bp & 0xff]++;
|
||||
p0 = p1;
|
||||
p1 = *bp++ & (history_bins-1);
|
||||
}
|
||||
|
||||
for (p0 = 0; p0 < history_bins; p0++) {
|
||||
calculate_probabilities (histogram [p0], probabilities [p0], summed_probabilities [p0]);
|
||||
total_summed_probabilities += summed_probabilities [p0] [255];
|
||||
}
|
||||
|
||||
((WavpackHeader *) wps->blockbuff)->crc = crc;
|
||||
|
||||
// This code detects the case where the required value lookup tables grow silly big and cuts them back down. This would
|
||||
// normally only happen with large blocks or poorly compressible data. The target is to guarantee that the total memory
|
||||
// required for all three decode tables will be 2K bytes per history bin.
|
||||
|
||||
while (total_summed_probabilities > history_bins * 1280) {
|
||||
int max_sum = 0, sum_values = 0, largest_bin = 0;
|
||||
|
||||
for (p0 = 0; p0 < history_bins; ++p0)
|
||||
if (summed_probabilities [p0] [255] > max_sum) {
|
||||
max_sum = summed_probabilities [p0] [255];
|
||||
largest_bin = p0;
|
||||
}
|
||||
|
||||
total_summed_probabilities -= max_sum;
|
||||
p0 = largest_bin;
|
||||
|
||||
for (p1 = 0; p1 < 256; ++p1)
|
||||
summed_probabilities [p0] [p1] = sum_values += probabilities [p0] [p1] = (probabilities [p0] [p1] + 1) >> 1;
|
||||
|
||||
total_summed_probabilities += summed_probabilities [p0] [255];
|
||||
// fprintf (stderr, "processed bin 0x%02x, bin: %d --> %d, new sum = %d\n",
|
||||
// p0, max_sum, summed_probabilities [p0] [255], total_summed_probabilities);
|
||||
}
|
||||
|
||||
free (histogram);
|
||||
bp = buffer;
|
||||
bc = num_samples;
|
||||
*dp++ = 1;
|
||||
*dp++ = history_bits;
|
||||
*dp++ = MAX_PROBABILITY;
|
||||
ep = destination + num_samples - 10;
|
||||
|
||||
#if (MAX_PROBABILITY < 0xff)
|
||||
dp += rle_encode ((unsigned char *) probabilities, sizeof (*probabilities) * history_bins, dp);
|
||||
#else
|
||||
memcpy (dp, probabilities, sizeof (*probabilities) * history_bins);
|
||||
dp += sizeof (*probabilities) * history_bins;
|
||||
#endif
|
||||
|
||||
p0 = p1 = 0;
|
||||
|
||||
while (dp < ep && bc--) {
|
||||
|
||||
mult = (high - low) / summed_probabilities [p0] [255];
|
||||
|
||||
if (!mult) {
|
||||
high = low;
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
mult = (high - low) / summed_probabilities [p0] [255];
|
||||
}
|
||||
|
||||
if (*bp & 0xff)
|
||||
low += summed_probabilities [p0] [(*bp & 0xff)-1] * mult;
|
||||
|
||||
high = low + probabilities [p0] [*bp & 0xff] * mult - 1;
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
if (flags & MONO_DATA)
|
||||
p0 = *bp++ & (history_bins-1);
|
||||
else {
|
||||
p0 = p1;
|
||||
p1 = *bp++ & (history_bins-1);
|
||||
}
|
||||
}
|
||||
|
||||
high = low;
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
free (summed_probabilities);
|
||||
free (probabilities);
|
||||
|
||||
if (dp < ep)
|
||||
return (int)(dp - destination);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#define PTABLE_BITS 8
|
||||
#define PTABLE_BINS (1<<PTABLE_BITS)
|
||||
#define PTABLE_MASK (PTABLE_BINS-1)
|
||||
|
||||
#define INITIAL_TERM (1536/PTABLE_BINS)
|
||||
|
||||
#define UP 0x010000fe
|
||||
#define DOWN 0x00010000
|
||||
#define DECAY 8
|
||||
|
||||
#define PRECISION 20
|
||||
#define VALUE_ONE (1 << PRECISION)
|
||||
#define PRECISION_USE 12
|
||||
|
||||
#define RATE_S 20
|
||||
|
||||
static void init_ptable (int *table, int rate_i, int rate_s)
|
||||
{
|
||||
int value = 0x808000, rate = rate_i << 8, c, i;
|
||||
|
||||
for (c = (rate + 128) >> 8; c--;)
|
||||
value += (DOWN - value) >> DECAY;
|
||||
|
||||
for (i = 0; i < PTABLE_BINS/2; ++i) {
|
||||
table [i] = value;
|
||||
table [PTABLE_BINS-1-i] = 0x100ffff - value;
|
||||
|
||||
if (value > 0x010000) {
|
||||
rate += (rate * rate_s + 128) >> 8;
|
||||
|
||||
for (c = (rate + 64) >> 7; c--;)
|
||||
value += (DOWN - value) >> DECAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int normalize_ptable (int *ptable)
|
||||
{
|
||||
int rate = 0, min_error, error_sum, i;
|
||||
int ntable [PTABLE_BINS];
|
||||
|
||||
init_ptable (ntable, rate, RATE_S);
|
||||
|
||||
for (min_error = i = 0; i < PTABLE_BINS; ++i)
|
||||
min_error += abs (ptable [i] - ntable [i]) >> 8;
|
||||
|
||||
while (1) {
|
||||
init_ptable (ntable, ++rate, RATE_S);
|
||||
|
||||
for (error_sum = i = 0; i < PTABLE_BINS; ++i)
|
||||
error_sum += abs (ptable [i] - ntable [i]) >> 8;
|
||||
|
||||
if (error_sum < min_error)
|
||||
min_error = error_sum;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return rate - 1;
|
||||
}
|
||||
|
||||
static int encode_buffer_high (WavpackStream *wps, int32_t *buffer, int num_samples, unsigned char *destination)
|
||||
{
|
||||
int channel, stereo = (wps->wphdr.flags & MONO_DATA) ? 0 : 1;
|
||||
uint32_t crc = 0xffffffff, high = 0xffffffff, low = 0;
|
||||
unsigned char *dp = destination, *ep;
|
||||
DSDfilters *sp;
|
||||
|
||||
if (num_samples * (stereo + 1) < 280)
|
||||
return -1;
|
||||
|
||||
*dp++ = 3;
|
||||
ep = destination + num_samples * (stereo + 1) - 10;
|
||||
|
||||
if (!wps->sample_index) {
|
||||
if (!wps->dsd.ptable)
|
||||
wps->dsd.ptable = malloc (PTABLE_BINS * sizeof (*wps->dsd.ptable));
|
||||
|
||||
init_ptable (wps->dsd.ptable, INITIAL_TERM, RATE_S);
|
||||
|
||||
for (channel = 0; channel < 2; ++channel) {
|
||||
sp = wps->dsd.filters + channel;
|
||||
|
||||
sp->filter1 = sp->filter2 = sp->filter3 = sp->filter4 = sp->filter5 = VALUE_ONE / 2;
|
||||
sp->filter6 = sp->factor = 0;
|
||||
}
|
||||
|
||||
*dp++ = INITIAL_TERM;
|
||||
*dp++ = RATE_S;
|
||||
}
|
||||
else {
|
||||
int rate = normalize_ptable (wps->dsd.ptable);
|
||||
init_ptable (wps->dsd.ptable, rate, RATE_S);
|
||||
*dp++ = rate;
|
||||
*dp++ = RATE_S;
|
||||
}
|
||||
|
||||
for (channel = 0; channel <= stereo; ++channel) {
|
||||
sp = wps->dsd.filters + channel;
|
||||
|
||||
*dp = sp->filter1 >> (PRECISION - 8);
|
||||
sp->filter1 = *dp++ << (PRECISION - 8);
|
||||
|
||||
*dp = sp->filter2 >> (PRECISION - 8);
|
||||
sp->filter2 = *dp++ << (PRECISION - 8);
|
||||
|
||||
*dp = sp->filter3 >> (PRECISION - 8);
|
||||
sp->filter3 = *dp++ << (PRECISION - 8);
|
||||
|
||||
*dp = sp->filter4 >> (PRECISION - 8);
|
||||
sp->filter4 = *dp++ << (PRECISION - 8);
|
||||
|
||||
*dp = sp->filter5 >> (PRECISION - 8);
|
||||
sp->filter5 = *dp++ << (PRECISION - 8);
|
||||
|
||||
*dp++ = sp->factor;
|
||||
*dp++ = sp->factor >> 8;
|
||||
sp->filter6 = 0;
|
||||
sp->factor = (sp->factor << 16) >> 16;
|
||||
}
|
||||
|
||||
sp = wps->dsd.filters;
|
||||
|
||||
while (dp < ep && num_samples--) {
|
||||
int bitcount = 8;
|
||||
|
||||
crc += (crc << 1) + (sp->byte = *buffer++ & 0xff);
|
||||
sp [0].value = sp [0].filter1 - sp [0].filter5 + ((sp [0].filter6 * sp [0].factor) >> 2);
|
||||
|
||||
if (stereo) {
|
||||
crc += (crc << 1) + (sp [1].byte = *buffer++ & 0xff);
|
||||
sp [1].value = sp [1].filter1 - sp [1].filter5 + ((sp [1].filter6 * sp [1].factor) >> 2);
|
||||
}
|
||||
|
||||
while (bitcount--) {
|
||||
int32_t *pp = wps->dsd.ptable + ((sp [0].value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK);
|
||||
|
||||
if (sp [0].byte & 0x80) {
|
||||
high = low + ((high - low) >> 8) * (*pp >> 16);
|
||||
*pp += (UP - *pp) >> DECAY;
|
||||
sp [0].filter0 = -1;
|
||||
}
|
||||
else {
|
||||
low += 1 + ((high - low) >> 8) * (*pp >> 16);
|
||||
*pp += (DOWN - *pp) >> DECAY;
|
||||
sp [0].filter0 = 0;
|
||||
}
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
sp [0].value += sp [0].filter6 << 3;
|
||||
sp [0].factor += (((sp [0].value ^ sp [0].filter0) >> 31) | 1) & ((sp [0].value ^ (sp [0].value - (sp [0].filter6 << 4))) >> 31);
|
||||
sp [0].filter1 += ((sp [0].filter0 & VALUE_ONE) - sp [0].filter1) >> 6;
|
||||
sp [0].filter2 += ((sp [0].filter0 & VALUE_ONE) - sp [0].filter2) >> 4;
|
||||
sp [0].filter3 += (sp [0].filter2 - sp [0].filter3) >> 4;
|
||||
sp [0].filter4 += (sp [0].filter3 - sp [0].filter4) >> 4;
|
||||
sp [0].value = (sp [0].filter4 - sp [0].filter5) >> 4;
|
||||
sp [0].filter5 += sp [0].value;
|
||||
sp [0].filter6 += (sp [0].value - sp [0].filter6) >> 3;
|
||||
sp [0].value = sp [0].filter1 - sp [0].filter5 + ((sp [0].filter6 * sp [0].factor) >> 2);
|
||||
sp [0].byte <<= 1;
|
||||
|
||||
if (!stereo)
|
||||
continue;
|
||||
|
||||
pp = wps->dsd.ptable + ((sp [1].value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK);
|
||||
|
||||
if (sp [1].byte & 0x80) {
|
||||
high = low + ((high - low) >> 8) * (*pp >> 16);
|
||||
*pp += (UP - *pp) >> DECAY;
|
||||
sp [1].filter0 = -1;
|
||||
}
|
||||
else {
|
||||
low += 1 + ((high - low) >> 8) * (*pp >> 16);
|
||||
*pp += (DOWN - *pp) >> DECAY;
|
||||
sp [1].filter0 = 0;
|
||||
}
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
sp [1].value += sp [1].filter6 << 3;
|
||||
sp [1].factor += (((sp [1].value ^ sp [1].filter0) >> 31) | 1) & ((sp [1].value ^ (sp [1].value - (sp [1].filter6 << 4))) >> 31);
|
||||
sp [1].filter1 += ((sp [1].filter0 & VALUE_ONE) - sp [1].filter1) >> 6;
|
||||
sp [1].filter2 += ((sp [1].filter0 & VALUE_ONE) - sp [1].filter2) >> 4;
|
||||
sp [1].filter3 += (sp [1].filter2 - sp [1].filter3) >> 4;
|
||||
sp [1].filter4 += (sp [1].filter3 - sp [1].filter4) >> 4;
|
||||
sp [1].value = (sp [1].filter4 - sp [1].filter5) >> 4;
|
||||
sp [1].filter5 += sp [1].value;
|
||||
sp [1].filter6 += (sp [1].value - sp [1].filter6) >> 3;
|
||||
sp [1].value = sp [1].filter1 - sp [1].filter5 + ((sp [1].filter6 * sp [1].factor) >> 2);
|
||||
sp [1].byte <<= 1;
|
||||
}
|
||||
|
||||
sp [0].factor -= (sp->factor + 512) >> 10;
|
||||
|
||||
if (stereo)
|
||||
sp [1].factor -= (sp [1].factor + 512) >> 10;
|
||||
}
|
||||
|
||||
((WavpackHeader *) wps->blockbuff)->crc = crc;
|
||||
high = low;
|
||||
|
||||
while (DSD_BYTE_READY (high, low)) {
|
||||
*dp++ = high >> 24;
|
||||
high = (high << 8) | 0xff;
|
||||
low <<= 8;
|
||||
}
|
||||
|
||||
if (dp < ep)
|
||||
return (int)(dp - destination);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // ENABLE_DSD
|
||||
@ -0,0 +1,270 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// pack_floats.c
|
||||
|
||||
// This module deals with the compression of floating-point data. Note that no
|
||||
// floating point math is involved here...the values are only processed with
|
||||
// the macros that directly access the mantissa, exponent, and sign fields.
|
||||
// That's why we use the f32 type instead of the built-in float type.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
//#define DISPLAY_DIAGNOSTICS
|
||||
|
||||
// Scan the provided buffer of floating-point values and (1) convert the
|
||||
// significant portion of the data to integers for compression using the
|
||||
// regular WavPack algorithms (which only operate on integers) and (2)
|
||||
// determine whether the data requires a second stream for lossless
|
||||
// storage (which will usually be the case except when the floating-point
|
||||
// data was originally integer data). The converted integers are returned
|
||||
// "in-place" and a return value of TRUE indicates that a second stream
|
||||
// is required.
|
||||
|
||||
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;
|
||||
#ifdef DISPLAY_DIAGNOSTICS
|
||||
int32_t true_zeros = 0, denormals = 0, exceptions = 0;
|
||||
#endif
|
||||
uint32_t ordata = 0, crc = 0xffffffff;
|
||||
int32_t count, value, shift_count;
|
||||
int max_mag = 0, max_exp = 0;
|
||||
f32 *dp;
|
||||
|
||||
wps->float_shift = wps->float_flags = 0;
|
||||
|
||||
// First loop goes through all the data and (1) calculates the CRC and (2) finds the
|
||||
// max magnitude that does not have an exponent of 255 (reserved for +/-inf and NaN).
|
||||
for (dp = values, count = num_values; count--; dp++) {
|
||||
crc = crc * 27 + get_mantissa (*dp) * 9 + get_exponent (*dp) * 3 + get_sign (*dp);
|
||||
|
||||
if (get_exponent (*dp) < 255 && get_magnitude (*dp) > max_mag)
|
||||
max_mag = get_magnitude (*dp);
|
||||
}
|
||||
|
||||
wps->crc_x = crc;
|
||||
|
||||
// round up the magnitude so that when we convert the floating-point values to integers,
|
||||
// they will be (at most) just over 24-bits signed precision
|
||||
if (get_exponent (max_mag))
|
||||
max_exp = get_exponent (max_mag + 0x7F0000);
|
||||
|
||||
for (dp = values, count = num_values; count--; dp++) {
|
||||
// Exponent of 255 is reserved for +/-inf (mantissa = 0) or NaN (mantissa != 0).
|
||||
// we use a value one greater than 24-bits unsigned for this.
|
||||
if (get_exponent (*dp) == 255) {
|
||||
#ifdef DISPLAY_DIAGNOSTICS
|
||||
exceptions++;
|
||||
#endif
|
||||
wps->float_flags |= FLOAT_EXCEPTIONS;
|
||||
value = 0x1000000;
|
||||
shift_count = 0;
|
||||
}
|
||||
// This is the regular case. We generate a 24-bit unsigned value with the implied
|
||||
// '1' MSB set and calculate a shift that will make it line up with the biggest
|
||||
// samples in this block (although that shift would obviously shift out real data).
|
||||
else if (get_exponent (*dp)) {
|
||||
shift_count = max_exp - get_exponent (*dp);
|
||||
value = 0x800000 + get_mantissa (*dp);
|
||||
}
|
||||
// Zero exponent means either +/- zero (mantissa = 0) or denormals (mantissa != 0).
|
||||
// shift_count is set so that denormals (without an implied '1') will line up with
|
||||
// regular values (with their implied '1' added at bit 23). Trust me. We don't care
|
||||
// about the shift with zero.
|
||||
else {
|
||||
shift_count = max_exp ? max_exp - 1 : 0;
|
||||
value = get_mantissa (*dp);
|
||||
|
||||
#ifdef DISPLAY_DIAGNOSTICS
|
||||
if (get_mantissa (*dp))
|
||||
denormals++;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (shift_count < 25)
|
||||
value >>= shift_count; // perform the shift if there could be anything left
|
||||
else
|
||||
value = 0; // else just zero the value
|
||||
|
||||
// If we are going to encode an integer zero, then this might be a "false zero" which
|
||||
// means that there are significant bits but they're completely shifted out, or a
|
||||
// "negative zero" which is simply a floating point value that we have to encode
|
||||
// (and converting it to a positive zero would be an error).
|
||||
if (!value) {
|
||||
if (get_exponent (*dp) || get_mantissa (*dp))
|
||||
++false_zeros;
|
||||
else if (get_sign (*dp))
|
||||
++neg_zeros;
|
||||
#ifdef DISPLAY_DIAGNOSTICS
|
||||
else
|
||||
++true_zeros;
|
||||
#endif
|
||||
}
|
||||
// If we are going to shift something (but not everything) out of our integer before
|
||||
// encoding, then we generate a mask corresponding to the bits that will be shifted
|
||||
// out and increment the counter for the 3 possible cases of (1) all zeros, (2) all
|
||||
// ones, and (3) a mix of ones and zeros.
|
||||
else if (shift_count) {
|
||||
int32_t mask = (1 << shift_count) - 1;
|
||||
|
||||
if (!(get_mantissa (*dp) & mask))
|
||||
shifted_zeros++;
|
||||
else if ((get_mantissa (*dp) & mask) == mask)
|
||||
shifted_ones++;
|
||||
else
|
||||
shifted_both++;
|
||||
}
|
||||
|
||||
// "or" all the integer values together, and store the final integer with applied sign
|
||||
|
||||
ordata |= value;
|
||||
* (int32_t *) dp = (get_sign (*dp)) ? -value : value;
|
||||
}
|
||||
|
||||
wps->float_max_exp = max_exp; // on decode, we use this to calculate actual exponent
|
||||
|
||||
// Now, based on our various counts, we determine the scheme required to encode the bits
|
||||
// shifted out. Usually these will simply have to be sent literally, but in some rare cases
|
||||
// we can get away with always assuming ones shifted out, or assuming all the bits shifted
|
||||
// out in each value are the same (which means we only have to send a single bit).
|
||||
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;
|
||||
// Another case is that we only shift out zeros (or maybe nothing), and in that case we
|
||||
// check to see if our data actually has less than 24 or 25 bits of resolution, which means
|
||||
// that we reduce can the magnitude of the integers we are encoding (which saves all those
|
||||
// bits). The number of bits of reduced resolution is stored in float_shift.
|
||||
else if (ordata && !(ordata & 1)) {
|
||||
while (!(ordata & 1)) {
|
||||
wps->float_shift++;
|
||||
ordata >>= 1;
|
||||
}
|
||||
|
||||
// here we shift out all those zeros in the integer data we will encode
|
||||
for (dp = values, count = num_values; count--; dp++)
|
||||
* (int32_t *) dp >>= wps->float_shift;
|
||||
}
|
||||
|
||||
// Here we calculate the actual magnitude used by our integer data, although this is just
|
||||
// used for informational purposes during encode/decode to possibly use faster math.
|
||||
|
||||
wps->wphdr.flags &= ~MAG_MASK;
|
||||
|
||||
while (ordata) {
|
||||
wps->wphdr.flags += 1 << MAG_LSB;
|
||||
ordata >>= 1;
|
||||
}
|
||||
|
||||
// Finally, we have to set some flags that guide how we encode various types of "zeros".
|
||||
// If none of these are set (which is the most common situation), then every integer
|
||||
// zero in the decoded data will simply become a floating-point zero.
|
||||
|
||||
if (false_zeros || neg_zeros)
|
||||
wps->float_flags |= FLOAT_ZEROS_SENT;
|
||||
|
||||
if (neg_zeros)
|
||||
wps->float_flags |= FLOAT_NEG_ZEROS;
|
||||
|
||||
#ifdef DISPLAY_DIAGNOSTICS
|
||||
{
|
||||
int32_t *ip, min = 0x7fffffff, max = 0x80000000;
|
||||
for (ip = (int32_t *) values, count = num_values; count--; ip++) {
|
||||
if (*ip < min) min = *ip;
|
||||
if (*ip > max) max = *ip;
|
||||
}
|
||||
|
||||
fprintf (stderr, "integer range = %d to %d\n", min, max);
|
||||
}
|
||||
|
||||
fprintf (stderr, "samples = %d, max exp = %d, pre-shift = %d, denormals = %d, exceptions = %d, max_mag = %x\n",
|
||||
num_values, max_exp, wps->float_shift, denormals, exceptions, max_mag);
|
||||
fprintf (stderr, "shifted ones/zeros/both = %d/%d/%d, true/neg/false zeros = %d/%d/%d\n",
|
||||
shifted_ones, shifted_zeros, shifted_both, true_zeros, neg_zeros, false_zeros);
|
||||
#endif
|
||||
|
||||
return wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME);
|
||||
}
|
||||
|
||||
// Given a buffer of float data, convert the data to integers (which is what the WavPack compression
|
||||
// algorithms require) and write the other data required for lossless compression (which includes
|
||||
// significant bits shifted out of the integers, plus information about +/- zeros and exceptions
|
||||
// like NaN and +/- infinities) into the wvxbits stream (which is assumed to be opened). Note that
|
||||
// for this work correctly, scan_float_data() must have been called on the original data to set
|
||||
// the appropiate flags in float_flags and max_exp.
|
||||
|
||||
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 (get_exponent (*dp) == 255) {
|
||||
if (get_mantissa (*dp)) {
|
||||
putbit_1 (&wps->wvxbits);
|
||||
putbits (get_mantissa (*dp), 23, &wps->wvxbits);
|
||||
}
|
||||
else {
|
||||
putbit_0 (&wps->wvxbits);
|
||||
}
|
||||
|
||||
value = 0x1000000;
|
||||
shift_count = 0;
|
||||
}
|
||||
else if (get_exponent (*dp)) {
|
||||
shift_count = max_exp - get_exponent (*dp);
|
||||
value = 0x800000 + get_mantissa (*dp);
|
||||
}
|
||||
else {
|
||||
shift_count = max_exp ? max_exp - 1 : 0;
|
||||
value = get_mantissa (*dp);
|
||||
}
|
||||
|
||||
if (shift_count < 25)
|
||||
value >>= shift_count;
|
||||
else
|
||||
value = 0;
|
||||
|
||||
if (!value) {
|
||||
if (wps->float_flags & FLOAT_ZEROS_SENT) {
|
||||
if (get_exponent (*dp) || get_mantissa (*dp)) {
|
||||
putbit_1 (&wps->wvxbits);
|
||||
putbits (get_mantissa (*dp), 23, &wps->wvxbits);
|
||||
|
||||
if (max_exp >= 25) {
|
||||
putbits (get_exponent (*dp), 8, &wps->wvxbits);
|
||||
}
|
||||
|
||||
putbit (get_sign (*dp), &wps->wvxbits);
|
||||
}
|
||||
else {
|
||||
putbit_0 (&wps->wvxbits);
|
||||
|
||||
if (wps->float_flags & FLOAT_NEG_ZEROS)
|
||||
putbit (get_sign (*dp), &wps->wvxbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (shift_count) {
|
||||
if (wps->float_flags & FLOAT_SHIFT_SENT) {
|
||||
int32_t data = get_mantissa (*dp) & ((1 << shift_count) - 1);
|
||||
putbits (data, shift_count, &wps->wvxbits);
|
||||
}
|
||||
else if (wps->float_flags & FLOAT_SHIFT_SAME) {
|
||||
putbit (get_mantissa (*dp) & 1, &wps->wvxbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,614 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// read_words.c
|
||||
|
||||
// This module provides entropy word decoding functions using
|
||||
// a variation on the Rice method. This was introduced in version 3.93
|
||||
// because it allows splitting the data into a "lossy" stream and a
|
||||
// "correction" stream in a very efficient manner and is therefore ideal
|
||||
// for the "hybrid" mode. For 4.0, the efficiency of this method was
|
||||
// significantly improved by moving away from the normal Rice restriction of
|
||||
// using powers of two for the modulus divisions and now the method can be
|
||||
// used for both hybrid and pure lossless encoding.
|
||||
|
||||
// Samples are divided by median probabilities at 5/7 (71.43%), 10/49 (20.41%),
|
||||
// and 20/343 (5.83%). Each zone has 3.5 times fewer samples than the
|
||||
// previous. Using standard Rice coding on this data would result in 1.4
|
||||
// bits per sample average (not counting sign bit). However, there is a
|
||||
// very simple encoding that is over 99% efficient with this data and
|
||||
// results in about 1.22 bits per sample.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#if defined (HAVE___BUILTIN_CTZ) || defined (_WIN64)
|
||||
#define USE_CTZ_OPTIMIZATION // use ctz intrinsic (or Windows equivalent) to count trailing ones
|
||||
#else
|
||||
#define USE_NEXT8_OPTIMIZATION // optimization using a table to count trailing ones
|
||||
#endif
|
||||
|
||||
#define USE_BITMASK_TABLES // use tables instead of shifting for certain masking operations
|
||||
|
||||
///////////////////////////// local table storage ////////////////////////////
|
||||
|
||||
#ifdef USE_NEXT8_OPTIMIZATION
|
||||
static const char ones_count_table [] = {
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,7,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,6,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,5,
|
||||
0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,8
|
||||
};
|
||||
#endif
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
static uint32_t __inline read_code (Bitstream *bs, uint32_t maxcode);
|
||||
|
||||
// Read the next word from the bitstream "wvbits" and return the value. This
|
||||
// function can be used for hybrid or lossless streams, but since an
|
||||
// optimized version is available for lossless this function would normally
|
||||
// be used for hybrid only. If a hybrid lossless stream is being read then
|
||||
// the "correction" offset is written at the specified pointer. A return value
|
||||
// of WORD_EOF indicates that the end of the bitstream was reached (all 1s) or
|
||||
// some other error occurred.
|
||||
|
||||
int32_t FASTCALL get_word (WavpackStream *wps, int chan, int32_t *correction)
|
||||
{
|
||||
register struct entropy_data *c = wps->w.c + chan;
|
||||
uint32_t ones_count, low, mid, high;
|
||||
int32_t value;
|
||||
int sign;
|
||||
|
||||
if (!wps->wvbits.ptr)
|
||||
return WORD_EOF;
|
||||
|
||||
if (correction)
|
||||
*correction = 0;
|
||||
|
||||
if (!(wps->w.c [0].median [0] & ~1) && !wps->w.holding_zero && !wps->w.holding_one && !(wps->w.c [1].median [0] & ~1)) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
if (wps->w.zeros_acc) {
|
||||
if (--wps->w.zeros_acc) {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
return WORD_EOF;
|
||||
|
||||
if (cbits < 2)
|
||||
wps->w.zeros_acc = cbits;
|
||||
else {
|
||||
for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1)
|
||||
if (getbit (&wps->wvbits))
|
||||
wps->w.zeros_acc |= mask;
|
||||
|
||||
wps->w.zeros_acc |= mask;
|
||||
}
|
||||
|
||||
if (wps->w.zeros_acc) {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
CLEAR (wps->w.c [0].median);
|
||||
CLEAR (wps->w.c [1].median);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wps->w.holding_zero)
|
||||
ones_count = wps->w.holding_zero = 0;
|
||||
else {
|
||||
#ifdef USE_CTZ_OPTIMIZATION
|
||||
while (wps->wvbits.bc < LIMIT_ONES) {
|
||||
if (++(wps->wvbits.ptr) == wps->wvbits.end)
|
||||
wps->wvbits.wrap (&wps->wvbits);
|
||||
|
||||
wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc;
|
||||
wps->wvbits.bc += sizeof (*(wps->wvbits.ptr)) * 8;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
{ unsigned long res; _BitScanForward (&res, (unsigned long)~wps->wvbits.sr); ones_count = (uint32_t) res; }
|
||||
#else
|
||||
ones_count = __builtin_ctz (~wps->wvbits.sr);
|
||||
#endif
|
||||
|
||||
if (ones_count >= LIMIT_ONES) {
|
||||
wps->wvbits.bc -= ones_count;
|
||||
wps->wvbits.sr >>= ones_count;
|
||||
|
||||
for (; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count);
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
return WORD_EOF;
|
||||
|
||||
if (ones_count == LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
return WORD_EOF;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (&wps->wvbits))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
}
|
||||
else {
|
||||
wps->wvbits.bc -= ones_count + 1;
|
||||
wps->wvbits.sr >>= ones_count + 1;
|
||||
}
|
||||
#elif defined (USE_NEXT8_OPTIMIZATION)
|
||||
int next8;
|
||||
|
||||
if (wps->wvbits.bc < 8) {
|
||||
if (++(wps->wvbits.ptr) == wps->wvbits.end)
|
||||
wps->wvbits.wrap (&wps->wvbits);
|
||||
|
||||
next8 = (wps->wvbits.sr |= *(wps->wvbits.ptr) << wps->wvbits.bc) & 0xff;
|
||||
wps->wvbits.bc += sizeof (*(wps->wvbits.ptr)) * 8;
|
||||
}
|
||||
else
|
||||
next8 = wps->wvbits.sr & 0xff;
|
||||
|
||||
if (next8 == 0xff) {
|
||||
wps->wvbits.bc -= 8;
|
||||
wps->wvbits.sr >>= 8;
|
||||
|
||||
for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count);
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
return WORD_EOF;
|
||||
|
||||
if (ones_count == LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
return WORD_EOF;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (&wps->wvbits))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
}
|
||||
else {
|
||||
wps->wvbits.bc -= (ones_count = ones_count_table [next8]) + 1;
|
||||
wps->wvbits.sr >>= ones_count + 1;
|
||||
}
|
||||
#else
|
||||
for (ones_count = 0; ones_count < (LIMIT_ONES + 1) && getbit (&wps->wvbits); ++ones_count);
|
||||
|
||||
if (ones_count >= LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
return WORD_EOF;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
return WORD_EOF;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (&wps->wvbits))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wps->w.holding_one) {
|
||||
wps->w.holding_one = ones_count & 1;
|
||||
ones_count = (ones_count >> 1) + 1;
|
||||
}
|
||||
else {
|
||||
wps->w.holding_one = ones_count & 1;
|
||||
ones_count >>= 1;
|
||||
}
|
||||
|
||||
wps->w.holding_zero = ~wps->w.holding_one & 1;
|
||||
}
|
||||
|
||||
if ((wps->wphdr.flags & HYBRID_FLAG) && !chan)
|
||||
update_error_limit (wps);
|
||||
|
||||
if (ones_count == 0) {
|
||||
low = 0;
|
||||
high = GET_MED (0) - 1;
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (ones_count == 1) {
|
||||
high = low + GET_MED (1) - 1;
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (ones_count == 2) {
|
||||
high = low + GET_MED (2) - 1;
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
low += (ones_count - 2) * GET_MED (2);
|
||||
high = low + GET_MED (2) - 1;
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
low &= 0x7fffffff;
|
||||
high &= 0x7fffffff;
|
||||
|
||||
if (low > high) // make sure high and low make sense
|
||||
high = low;
|
||||
|
||||
mid = (high + low + 1) >> 1;
|
||||
|
||||
if (!c->error_limit)
|
||||
mid = read_code (&wps->wvbits, high - low) + low;
|
||||
else while (high - low > c->error_limit) {
|
||||
if (getbit (&wps->wvbits))
|
||||
mid = (high + (low = mid) + 1) >> 1;
|
||||
else
|
||||
mid = ((high = mid - 1) + low + 1) >> 1;
|
||||
}
|
||||
|
||||
sign = getbit (&wps->wvbits);
|
||||
|
||||
if (bs_is_open (&wps->wvcbits) && c->error_limit) {
|
||||
value = read_code (&wps->wvcbits, high - low) + low;
|
||||
|
||||
if (correction)
|
||||
*correction = sign ? (mid - value) : (value - mid);
|
||||
}
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
c->slow_level += wp_log2 (mid);
|
||||
}
|
||||
|
||||
return sign ? ~mid : mid;
|
||||
}
|
||||
|
||||
// This is an optimized version of get_word() that is used for lossless only
|
||||
// (error_limit == 0). Also, rather than obtaining a single sample, it can be
|
||||
// used to obtain an entire buffer of either mono or stereo samples.
|
||||
|
||||
int32_t get_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples)
|
||||
{
|
||||
struct entropy_data *c = wps->w.c;
|
||||
uint32_t ones_count, low, high;
|
||||
Bitstream *bs = &wps->wvbits;
|
||||
int32_t csamples;
|
||||
#ifdef USE_NEXT8_OPTIMIZATION
|
||||
int32_t next8;
|
||||
#endif
|
||||
|
||||
if (nsamples && !bs->ptr) {
|
||||
memset (buffer, 0, (wps->wphdr.flags & MONO_DATA) ? nsamples * 4 : nsamples * 8);
|
||||
return nsamples;
|
||||
}
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
nsamples *= 2;
|
||||
|
||||
for (csamples = 0; csamples < nsamples; ++csamples) {
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
c = wps->w.c + (csamples & 1);
|
||||
|
||||
if (wps->w.holding_zero) {
|
||||
wps->w.holding_zero = 0;
|
||||
low = read_code (bs, GET_MED (0) - 1);
|
||||
DEC_MED0 ();
|
||||
buffer [csamples] = (getbit (bs)) ? ~low : low;
|
||||
|
||||
if (++csamples == nsamples)
|
||||
break;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
c = wps->w.c + (csamples & 1);
|
||||
}
|
||||
|
||||
if (wps->w.c [0].median [0] < 2 && !wps->w.holding_one && wps->w.c [1].median [0] < 2) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
if (wps->w.zeros_acc) {
|
||||
if (--wps->w.zeros_acc) {
|
||||
buffer [csamples] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (cbits = 0; cbits < 33 && getbit (bs); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
break;
|
||||
|
||||
if (cbits < 2)
|
||||
wps->w.zeros_acc = cbits;
|
||||
else {
|
||||
for (mask = 1, wps->w.zeros_acc = 0; --cbits; mask <<= 1)
|
||||
if (getbit (bs))
|
||||
wps->w.zeros_acc |= mask;
|
||||
|
||||
wps->w.zeros_acc |= mask;
|
||||
}
|
||||
|
||||
if (wps->w.zeros_acc) {
|
||||
CLEAR (wps->w.c [0].median);
|
||||
CLEAR (wps->w.c [1].median);
|
||||
buffer [csamples] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_CTZ_OPTIMIZATION
|
||||
while (bs->bc < LIMIT_ONES) {
|
||||
if (++(bs->ptr) == bs->end)
|
||||
bs->wrap (bs);
|
||||
|
||||
bs->sr |= *(bs->ptr) << bs->bc;
|
||||
bs->bc += sizeof (*(bs->ptr)) * 8;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
{ unsigned long res; _BitScanForward (&res, (unsigned long)~wps->wvbits.sr); ones_count = (uint32_t) res; }
|
||||
#else
|
||||
ones_count = __builtin_ctz (~wps->wvbits.sr);
|
||||
#endif
|
||||
|
||||
if (ones_count >= LIMIT_ONES) {
|
||||
bs->bc -= ones_count;
|
||||
bs->sr >>= ones_count;
|
||||
|
||||
for (; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count);
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
break;
|
||||
|
||||
if (ones_count == LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (bs); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
break;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (bs))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bs->bc -= ones_count + 1;
|
||||
bs->sr >>= ones_count + 1;
|
||||
}
|
||||
#elif defined (USE_NEXT8_OPTIMIZATION)
|
||||
if (bs->bc < 8) {
|
||||
if (++(bs->ptr) == bs->end)
|
||||
bs->wrap (bs);
|
||||
|
||||
next8 = (bs->sr |= *(bs->ptr) << bs->bc) & 0xff;
|
||||
bs->bc += sizeof (*(bs->ptr)) * 8;
|
||||
}
|
||||
else
|
||||
next8 = bs->sr & 0xff;
|
||||
|
||||
if (next8 == 0xff) {
|
||||
bs->bc -= 8;
|
||||
bs->sr >>= 8;
|
||||
|
||||
for (ones_count = 8; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count);
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
break;
|
||||
|
||||
if (ones_count == LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (bs); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
break;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (bs))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bs->bc -= (ones_count = ones_count_table [next8]) + 1;
|
||||
bs->sr >>= ones_count + 1;
|
||||
}
|
||||
#else
|
||||
for (ones_count = 0; ones_count < (LIMIT_ONES + 1) && getbit (bs); ++ones_count);
|
||||
|
||||
if (ones_count >= LIMIT_ONES) {
|
||||
uint32_t mask;
|
||||
int cbits;
|
||||
|
||||
if (ones_count == (LIMIT_ONES + 1))
|
||||
break;
|
||||
|
||||
for (cbits = 0; cbits < 33 && getbit (bs); ++cbits);
|
||||
|
||||
if (cbits == 33)
|
||||
break;
|
||||
|
||||
if (cbits < 2)
|
||||
ones_count = cbits;
|
||||
else {
|
||||
for (mask = 1, ones_count = 0; --cbits; mask <<= 1)
|
||||
if (getbit (bs))
|
||||
ones_count |= mask;
|
||||
|
||||
ones_count |= mask;
|
||||
}
|
||||
|
||||
ones_count += LIMIT_ONES;
|
||||
}
|
||||
#endif
|
||||
|
||||
low = wps->w.holding_one;
|
||||
wps->w.holding_one = ones_count & 1;
|
||||
wps->w.holding_zero = ~ones_count & 1;
|
||||
ones_count = (ones_count >> 1) + low;
|
||||
|
||||
if (ones_count == 0) {
|
||||
low = 0;
|
||||
high = GET_MED (0) - 1;
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (ones_count == 1) {
|
||||
high = low + GET_MED (1) - 1;
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (ones_count == 2) {
|
||||
high = low + GET_MED (2) - 1;
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
low += (ones_count - 2) * GET_MED (2);
|
||||
high = low + GET_MED (2) - 1;
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
low += read_code (bs, high - low);
|
||||
buffer [csamples] = (getbit (bs)) ? ~low : low;
|
||||
}
|
||||
|
||||
return (wps->wphdr.flags & MONO_DATA) ? csamples : (csamples / 2);
|
||||
}
|
||||
|
||||
// Read a single unsigned value from the specified bitstream with a value
|
||||
// from 0 to maxcode. If there are exactly a power of two number of possible
|
||||
// codes then this will read a fixed number of bits; otherwise it reads the
|
||||
// minimum number of bits and then determines whether another bit is needed
|
||||
// to define the code.
|
||||
|
||||
static uint32_t __inline read_code (Bitstream *bs, uint32_t maxcode)
|
||||
{
|
||||
unsigned long local_sr;
|
||||
uint32_t extras, code;
|
||||
int bitcount;
|
||||
|
||||
if (maxcode < 2)
|
||||
return maxcode ? getbit (bs) : 0;
|
||||
|
||||
bitcount = count_bits (maxcode);
|
||||
#ifdef USE_BITMASK_TABLES
|
||||
extras = bitset [bitcount] - maxcode - 1;
|
||||
#else
|
||||
extras = (1 << bitcount) - maxcode - 1;
|
||||
#endif
|
||||
|
||||
local_sr = bs->sr;
|
||||
|
||||
while (bs->bc < bitcount) {
|
||||
if (++(bs->ptr) == bs->end)
|
||||
bs->wrap (bs);
|
||||
|
||||
local_sr |= (long)*(bs->ptr) << bs->bc;
|
||||
bs->bc += sizeof (*(bs->ptr)) * 8;
|
||||
}
|
||||
|
||||
#ifdef USE_BITMASK_TABLES
|
||||
if ((code = local_sr & bitmask [bitcount - 1]) >= extras)
|
||||
#else
|
||||
if ((code = local_sr & ((1 << (bitcount - 1)) - 1)) >= extras)
|
||||
#endif
|
||||
code = (code << 1) - extras + ((local_sr >> (bitcount - 1)) & 1);
|
||||
else
|
||||
bitcount--;
|
||||
|
||||
if (sizeof (local_sr) < 8 && bs->bc > sizeof (local_sr) * 8) {
|
||||
bs->bc -= bitcount;
|
||||
bs->sr = *(bs->ptr) >> (sizeof (*(bs->ptr)) * 8 - bs->bc);
|
||||
}
|
||||
else {
|
||||
bs->bc -= bitcount;
|
||||
bs->sr = local_sr >> bitcount;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
@ -0,0 +1,597 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// tag_utils.c
|
||||
|
||||
// This module provides the high-level API for creating, reading and editing
|
||||
// APEv2 tags on WavPack files. Read-only support is also provided for ID3v1
|
||||
// tags, but their use is not recommended.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define stricmp(x,y) _stricmp(x,y)
|
||||
#else
|
||||
#define stricmp strcasecmp
|
||||
#endif
|
||||
|
||||
static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size, int type);
|
||||
static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size);
|
||||
static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size, int type);
|
||||
static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size);
|
||||
static int append_ape_tag_item (WavpackContext *wpc, const char *item, const char *value, int vsize, int type);
|
||||
static int write_tag_blockout (WavpackContext *wpc);
|
||||
static int write_tag_reader (WavpackContext *wpc);
|
||||
static void tagcpy (char *dest, char *src, int tag_size);
|
||||
static int tagdata (char *src, int tag_size);
|
||||
|
||||
//////////////////// Global functions part of external API /////////////////////////
|
||||
|
||||
// Count and return the total number of tag items in the specified file.
|
||||
|
||||
int WavpackGetNumTagItems (WavpackContext *wpc)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (WavpackGetTagItemIndexed (wpc, i, NULL, 0))
|
||||
++i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// Count and return the total number of binary tag items in the specified file. This applies
|
||||
// only to APEv2 tags and was implemented as a separate function to avoid breaking the old API.
|
||||
|
||||
int WavpackGetNumBinaryTagItems (WavpackContext *wpc)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (WavpackGetBinaryTagItemIndexed (wpc, i, NULL, 0))
|
||||
++i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// Attempt to get the specified item from the specified file's ID3v1 or APEv2
|
||||
// tag. The "size" parameter specifies the amount of space available at "value",
|
||||
// if the desired item will not fit in this space then ellipses (...) will
|
||||
// be appended and the string terminated. Only text data are supported. The
|
||||
// actual length of the string is returned (or 0 if no matching value found).
|
||||
// Note that with APEv2 tags the length might not be the same as the number of
|
||||
// characters because UTF-8 encoding is used. Also, APEv2 tags can have multiple
|
||||
// (NULL separated) strings for a single value (this is why the length is
|
||||
// returned). If this function is called with a NULL "value" pointer (or a
|
||||
// zero "length") then only the actual length of the value data is returned
|
||||
// (not counting the terminating NULL). This can be used to determine the
|
||||
// actual memory to be allocated beforehand.
|
||||
|
||||
int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
if (value && size)
|
||||
*value = 0;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A')
|
||||
return get_ape_tag_item (m_tag, item, value, size, APE_TAG_TYPE_TEXT);
|
||||
else if (m_tag->id3_tag.tag_id [0] == 'T')
|
||||
return get_id3_tag_item (m_tag, item, value, size);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Attempt to get the specified binary item from the specified file's APEv2
|
||||
// tag. The "size" parameter specifies the amount of space available at "value".
|
||||
// If the desired item will not fit in this space then nothing will be copied
|
||||
// and 0 will be returned, otherwise the actual size will be returned. If this
|
||||
// function is called with a NULL "value" pointer (or a zero "length") then only
|
||||
// the actual length of the value data is returned and can be used to determine
|
||||
// the actual memory to be allocated beforehand.
|
||||
|
||||
int WavpackGetBinaryTagItem (WavpackContext *wpc, const char *item, char *value, int size)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
if (value && size)
|
||||
*value = 0;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A')
|
||||
return get_ape_tag_item (m_tag, item, value, size, APE_TAG_TYPE_BINARY);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This function looks up the tag item name by index and is used when the
|
||||
// application wants to access all the items in the file's ID3v1 or APEv2 tag.
|
||||
// Note that this function accesses only the item's name; WavpackGetTagItem()
|
||||
// still must be called to get the actual value. The "size" parameter specifies
|
||||
// the amount of space available at "item", if the desired item will not fit in
|
||||
// this space then ellipses (...) will be appended and the string terminated.
|
||||
// The actual length of the string is returned (or 0 if no item exists for
|
||||
// index). If this function is called with a NULL "value" pointer (or a
|
||||
// zero "length") then only the actual length of the item name is returned
|
||||
// (not counting the terminating NULL). This can be used to determine the
|
||||
// actual memory to be allocated beforehand. For binary tag values use the
|
||||
// otherwise identical WavpackGetBinaryTagItemIndexed ();
|
||||
|
||||
int WavpackGetTagItemIndexed (WavpackContext *wpc, int index, char *item, int size)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
if (item && size)
|
||||
*item = 0;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A')
|
||||
return get_ape_tag_item_indexed (m_tag, index, item, size, APE_TAG_TYPE_TEXT);
|
||||
else if (m_tag->id3_tag.tag_id [0] == 'T')
|
||||
return get_id3_tag_item_indexed (m_tag, index, item, size);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WavpackGetBinaryTagItemIndexed (WavpackContext *wpc, int index, char *item, int size)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
if (item && size)
|
||||
*item = 0;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A')
|
||||
return get_ape_tag_item_indexed (m_tag, index, item, size, APE_TAG_TYPE_BINARY);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// These two functions are used to append APEv2 tags to WavPack files; one is
|
||||
// for text values (UTF-8 encoded) and the other is for binary values. If no tag
|
||||
// has been started, then an empty one will be allocated first. When finished,
|
||||
// use WavpackWriteTag() to write the completed tag to the file. The purpose of
|
||||
// the passed size parameter is obvious for binary values, but might not be for
|
||||
// text values. Keep in mind that APEv2 text values can have multiple values
|
||||
// that are NULL separated, so the size is required to know the extent of the
|
||||
// value (although the final terminating NULL is not included in the passed
|
||||
// size). If the specified item already exists, it will be replaced with the
|
||||
// new value. ID3v1 tags are not supported.
|
||||
|
||||
int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize)
|
||||
{
|
||||
while (WavpackDeleteTagItem (wpc, item));
|
||||
return append_ape_tag_item (wpc, item, value, vsize, APE_TAG_TYPE_TEXT);
|
||||
}
|
||||
|
||||
int WavpackAppendBinaryTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize)
|
||||
{
|
||||
while (WavpackDeleteTagItem (wpc, item));
|
||||
return append_ape_tag_item (wpc, item, value, vsize, APE_TAG_TYPE_BINARY);
|
||||
}
|
||||
|
||||
// Delete the specified tag item from the APEv2 tag on the specified WavPack file
|
||||
// (fields cannot be deleted from ID3v1 tags). A return value of TRUE indicates
|
||||
// that the item was found and successfully deleted.
|
||||
|
||||
int WavpackDeleteTagItem (WavpackContext *wpc, const char *item)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A') {
|
||||
unsigned char *p = m_tag->ape_tag_data;
|
||||
unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m_tag->ape_tag_hdr.item_count; ++i) {
|
||||
int vsize, isize;
|
||||
|
||||
vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 8; // skip flags because we don't need them
|
||||
for (isize = 0; p[isize] && p + isize < q; ++isize);
|
||||
|
||||
if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q)
|
||||
break;
|
||||
|
||||
if (isize && vsize && !stricmp (item, (char *) p)) {
|
||||
unsigned char *d = p - 8;
|
||||
|
||||
p += isize + vsize + 1;
|
||||
|
||||
while (p < q)
|
||||
*d++ = *p++;
|
||||
|
||||
m_tag->ape_tag_hdr.length = (int32_t)(d - m_tag->ape_tag_data) + sizeof (APE_Tag_Hdr);
|
||||
m_tag->ape_tag_hdr.item_count--;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
p += isize + vsize + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Once a APEv2 tag has been created with WavpackAppendTag(), this function is
|
||||
// used to write the completed tag to the end of the WavPack file. Note that
|
||||
// this function uses the same "blockout" function that is used to write
|
||||
// regular WavPack blocks, although that's where the similarity ends. It is also
|
||||
// used to write tags that have been edited on existing files.
|
||||
|
||||
int WavpackWriteTag (WavpackContext *wpc)
|
||||
{
|
||||
if (wpc->blockout) // this is the case for creating fresh WavPack files
|
||||
return write_tag_blockout (wpc);
|
||||
else // otherwise we are editing existing tags (OPEN_EDIT_TAGS)
|
||||
return write_tag_reader (wpc);
|
||||
}
|
||||
|
||||
////////////////////////// local static functions /////////////////////////////
|
||||
|
||||
static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int size, int type)
|
||||
{
|
||||
unsigned char *p = m_tag->ape_tag_data;
|
||||
unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m_tag->ape_tag_hdr.item_count && q - p > 8; ++i) {
|
||||
int vsize, flags, isize;
|
||||
|
||||
vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
|
||||
flags = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
|
||||
for (isize = 0; p[isize] && p + isize < q; ++isize);
|
||||
|
||||
if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q)
|
||||
break;
|
||||
|
||||
if (isize && vsize && !stricmp (item, (char *) p) && ((flags & 6) >> 1) == type) {
|
||||
|
||||
if (!value || !size)
|
||||
return vsize;
|
||||
|
||||
if (type == APE_TAG_TYPE_BINARY) {
|
||||
if (vsize <= size) {
|
||||
memcpy (value, p + isize + 1, vsize);
|
||||
return vsize;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else if (vsize < size) {
|
||||
memcpy (value, p + isize + 1, vsize);
|
||||
value [vsize] = 0;
|
||||
return vsize;
|
||||
}
|
||||
else if (size >= 4) {
|
||||
memcpy (value, p + isize + 1, size - 1);
|
||||
value [size - 4] = value [size - 3] = value [size - 2] = '.';
|
||||
value [size - 1] = 0;
|
||||
return size - 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
p += isize + vsize + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_id3_tag_item (M_Tag *m_tag, const char *item, char *value, int size)
|
||||
{
|
||||
char lvalue [64];
|
||||
int len;
|
||||
|
||||
lvalue [0] = 0;
|
||||
|
||||
if (!stricmp (item, "title"))
|
||||
tagcpy (lvalue, m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title));
|
||||
else if (!stricmp (item, "artist"))
|
||||
tagcpy (lvalue, m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist));
|
||||
else if (!stricmp (item, "album"))
|
||||
tagcpy (lvalue, m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album));
|
||||
else if (!stricmp (item, "year"))
|
||||
tagcpy (lvalue, m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year));
|
||||
else if (!stricmp (item, "comment"))
|
||||
tagcpy (lvalue, m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.comment));
|
||||
else if (!stricmp (item, "track") && m_tag->id3_tag.comment [29] && !m_tag->id3_tag.comment [28])
|
||||
sprintf (lvalue, "%d", m_tag->id3_tag.comment [29]);
|
||||
else
|
||||
return 0;
|
||||
|
||||
len = (int) strlen (lvalue);
|
||||
|
||||
if (!value || !size)
|
||||
return len;
|
||||
|
||||
if (len < size) {
|
||||
strcpy (value, lvalue);
|
||||
return len;
|
||||
}
|
||||
else if (size >= 4) {
|
||||
strncpy (value, lvalue, size - 1);
|
||||
value [size - 4] = value [size - 3] = value [size - 2] = '.';
|
||||
value [size - 1] = 0;
|
||||
return size - 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size, int type)
|
||||
{
|
||||
unsigned char *p = m_tag->ape_tag_data;
|
||||
unsigned char *q = p + m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < m_tag->ape_tag_hdr.item_count && index >= 0 && q - p > 8; ++i) {
|
||||
int vsize, flags, isize;
|
||||
|
||||
vsize = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
|
||||
flags = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24); p += 4;
|
||||
for (isize = 0; p[isize] && p + isize < q; ++isize);
|
||||
|
||||
if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q)
|
||||
break;
|
||||
|
||||
if (isize && vsize && ((flags & 6) >> 1) == type && !index--) {
|
||||
|
||||
if (!item || !size)
|
||||
return isize;
|
||||
|
||||
if (isize < size) {
|
||||
memcpy (item, p, isize);
|
||||
item [isize] = 0;
|
||||
return isize;
|
||||
}
|
||||
else if (size >= 4) {
|
||||
memcpy (item, p, size - 1);
|
||||
item [size - 4] = item [size - 3] = item [size - 2] = '.';
|
||||
item [size - 1] = 0;
|
||||
return size - 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
p += isize + vsize + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_id3_tag_item_indexed (M_Tag *m_tag, int index, char *item, int size)
|
||||
{
|
||||
char lvalue [16];
|
||||
int len;
|
||||
|
||||
lvalue [0] = 0;
|
||||
|
||||
if (tagdata (m_tag->id3_tag.title, sizeof (m_tag->id3_tag.title)) && !index--)
|
||||
strcpy (lvalue, "Title");
|
||||
else if (tagdata (m_tag->id3_tag.artist, sizeof (m_tag->id3_tag.artist)) && !index--)
|
||||
strcpy (lvalue, "Artist");
|
||||
else if (tagdata (m_tag->id3_tag.album, sizeof (m_tag->id3_tag.album)) && !index--)
|
||||
strcpy (lvalue, "Album");
|
||||
else if (tagdata (m_tag->id3_tag.year, sizeof (m_tag->id3_tag.year)) && !index--)
|
||||
strcpy (lvalue, "Year");
|
||||
else if (tagdata (m_tag->id3_tag.comment, sizeof (m_tag->id3_tag.comment)) && !index--)
|
||||
strcpy (lvalue, "Comment");
|
||||
else if (m_tag->id3_tag.comment [29] && !m_tag->id3_tag.comment [28] && !index--)
|
||||
strcpy (lvalue, "Track");
|
||||
else
|
||||
return 0;
|
||||
|
||||
len = (int) strlen (lvalue);
|
||||
|
||||
if (!item || !size)
|
||||
return len;
|
||||
|
||||
if (len < size) {
|
||||
strcpy (item, lvalue);
|
||||
return len;
|
||||
}
|
||||
else if (size >= 4) {
|
||||
strncpy (item, lvalue, size - 1);
|
||||
item [size - 4] = item [size - 3] = item [size - 2] = '.';
|
||||
item [size - 1] = 0;
|
||||
return size - 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int append_ape_tag_item (WavpackContext *wpc, const char *item, const char *value, int vsize, int type)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
int isize = (int) strlen (item);
|
||||
|
||||
if (!m_tag->ape_tag_hdr.ID [0]) {
|
||||
strncpy (m_tag->ape_tag_hdr.ID, "APETAGEX", sizeof (m_tag->ape_tag_hdr.ID));
|
||||
m_tag->ape_tag_hdr.version = 2000;
|
||||
m_tag->ape_tag_hdr.length = sizeof (m_tag->ape_tag_hdr);
|
||||
m_tag->ape_tag_hdr.item_count = 0;
|
||||
m_tag->ape_tag_hdr.flags = APE_TAG_CONTAINS_HEADER; // we will include header on tags we originate
|
||||
}
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A') {
|
||||
int new_item_len = vsize + isize + 9, flags = type << 1;
|
||||
unsigned char *p;
|
||||
|
||||
if (m_tag->ape_tag_hdr.length + new_item_len > APE_TAG_MAX_LENGTH) {
|
||||
strcpy (wpc->error_message, "APEv2 tag exceeds maximum allowed length!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_tag->ape_tag_hdr.item_count++;
|
||||
m_tag->ape_tag_hdr.length += new_item_len;
|
||||
p = m_tag->ape_tag_data = (unsigned char*)realloc (m_tag->ape_tag_data, m_tag->ape_tag_hdr.length);
|
||||
p += m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr) - new_item_len;
|
||||
|
||||
*p++ = (unsigned char) vsize;
|
||||
*p++ = (unsigned char) (vsize >> 8);
|
||||
*p++ = (unsigned char) (vsize >> 16);
|
||||
*p++ = (unsigned char) (vsize >> 24);
|
||||
|
||||
*p++ = (unsigned char) flags;
|
||||
*p++ = (unsigned char) (flags >> 8);
|
||||
*p++ = (unsigned char) (flags >> 16);
|
||||
*p++ = (unsigned char) (flags >> 24);
|
||||
|
||||
strcpy ((char *) p, item);
|
||||
p += isize + 1;
|
||||
memcpy (p, value, vsize);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Append the stored APEv2 tag to the file being created using the "blockout" function callback.
|
||||
|
||||
static int write_tag_blockout (WavpackContext *wpc)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
int result = TRUE;
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A' && m_tag->ape_tag_hdr.item_count) {
|
||||
|
||||
// only write header if it's specified in the flags
|
||||
|
||||
if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER) {
|
||||
m_tag->ape_tag_hdr.flags |= APE_TAG_THIS_IS_HEADER;
|
||||
WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
result = wpc->blockout (wpc->wv_out, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr));
|
||||
WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
}
|
||||
|
||||
if (m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr))
|
||||
result = wpc->blockout (wpc->wv_out, m_tag->ape_tag_data, m_tag->ape_tag_hdr.length - sizeof (m_tag->ape_tag_hdr));
|
||||
|
||||
m_tag->ape_tag_hdr.flags &= ~APE_TAG_THIS_IS_HEADER; // this is NOT header
|
||||
WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
result = wpc->blockout (wpc->wv_out, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr));
|
||||
WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
}
|
||||
|
||||
if (!result)
|
||||
strcpy (wpc->error_message, "can't write WavPack data, disk probably full!");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Write the [potentially] edited tag to the existing WavPack file using the reader callback functions.
|
||||
|
||||
static int write_tag_reader (WavpackContext *wpc)
|
||||
{
|
||||
M_Tag *m_tag = &wpc->m_tag;
|
||||
int32_t tag_size = 0;
|
||||
int result;
|
||||
|
||||
// before we write an edited (or new) tag into an existing file, make sure it's safe and possible
|
||||
|
||||
if (m_tag->tag_begins_file) {
|
||||
strcpy (wpc->error_message, "can't edit tags located at the beginning of files!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!wpc->reader->can_seek (wpc->wv_in)) {
|
||||
strcpy (wpc->error_message, "can't edit tags on pipes or unseekable files!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!(wpc->open_flags & OPEN_EDIT_TAGS)) {
|
||||
strcpy (wpc->error_message, "can't edit tags without OPEN_EDIT_TAGS flag!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (m_tag->ape_tag_hdr.ID [0] == 'A' && m_tag->ape_tag_hdr.item_count &&
|
||||
m_tag->ape_tag_hdr.length > sizeof (m_tag->ape_tag_hdr))
|
||||
tag_size = m_tag->ape_tag_hdr.length;
|
||||
|
||||
// only write header if it's specified in the flags
|
||||
|
||||
if (tag_size && (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER))
|
||||
tag_size += sizeof (m_tag->ape_tag_hdr);
|
||||
|
||||
result = !wpc->reader->set_pos_rel (wpc->wv_in, m_tag->tag_file_pos, SEEK_END);
|
||||
|
||||
if (result && tag_size < -m_tag->tag_file_pos && !wpc->reader->truncate_here) {
|
||||
int nullcnt = (int) (-m_tag->tag_file_pos - tag_size);
|
||||
char zero [1] = { 0 };
|
||||
|
||||
while (nullcnt--)
|
||||
wpc->reader->write_bytes (wpc->wv_in, &zero, 1);
|
||||
}
|
||||
|
||||
if (result && tag_size) {
|
||||
if (m_tag->ape_tag_hdr.flags & APE_TAG_CONTAINS_HEADER) {
|
||||
m_tag->ape_tag_hdr.flags |= APE_TAG_THIS_IS_HEADER;
|
||||
WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
result = (wpc->reader->write_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr)) == sizeof (m_tag->ape_tag_hdr));
|
||||
WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
}
|
||||
|
||||
result = (wpc->reader->write_bytes (wpc->wv_in, m_tag->ape_tag_data, m_tag->ape_tag_hdr.length - sizeof (m_tag->ape_tag_hdr)) == sizeof (m_tag->ape_tag_hdr));
|
||||
m_tag->ape_tag_hdr.flags &= ~APE_TAG_THIS_IS_HEADER; // this is NOT header
|
||||
WavpackNativeToLittleEndian (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
result = (wpc->reader->write_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (m_tag->ape_tag_hdr)) == sizeof (m_tag->ape_tag_hdr));
|
||||
WavpackLittleEndianToNative (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format);
|
||||
}
|
||||
|
||||
if (result && tag_size < -m_tag->tag_file_pos && wpc->reader->truncate_here)
|
||||
result = !wpc->reader->truncate_here (wpc->wv_in);
|
||||
|
||||
if (!result)
|
||||
strcpy (wpc->error_message, "can't write WavPack data, disk probably full!");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Copy the specified ID3v1 tag value (with specified field size) from the
|
||||
// source pointer to the destination, eliminating leading spaces and trailing
|
||||
// spaces and nulls.
|
||||
|
||||
static void tagcpy (char *dest, char *src, int tag_size)
|
||||
{
|
||||
char *s1 = src, *s2 = src + tag_size - 1;
|
||||
|
||||
if (*s2 && !s2 [-1])
|
||||
s2--;
|
||||
|
||||
while (s1 <= s2)
|
||||
if (*s1 == ' ')
|
||||
++s1;
|
||||
else if (!*s2 || *s2 == ' ')
|
||||
--s2;
|
||||
else
|
||||
break;
|
||||
|
||||
while (*s1 && s1 <= s2)
|
||||
*dest++ = *s1++;
|
||||
|
||||
*dest = 0;
|
||||
}
|
||||
|
||||
static int tagdata (char *src, int tag_size)
|
||||
{
|
||||
char *s1 = src, *s2 = src + tag_size - 1;
|
||||
|
||||
if (*s2 && !s2 [-1])
|
||||
s2--;
|
||||
|
||||
while (s1 <= s2)
|
||||
if (*s1 == ' ')
|
||||
++s1;
|
||||
else if (!*s2 || *s2 == ' ')
|
||||
--s2;
|
||||
else
|
||||
break;
|
||||
|
||||
return (*s1 && s1 <= s2);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,289 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack3_open.c
|
||||
|
||||
// This module provides an extension to the open_utils.c module for handling
|
||||
// WavPack files prior to version 4.0, not including "raw" files. As these
|
||||
// modes are all obsolete and are no longer written, this code will not be
|
||||
// fully documented other than the global functions. However, full documenation
|
||||
// is provided in the version 3.97 source code. Note that this module only
|
||||
// provides the functionality of opening the files and obtaining information
|
||||
// from them; the actual audio decoding is located in the unpack3.c module.
|
||||
|
||||
#ifdef ENABLE_LEGACY
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
#include "unpack3.h"
|
||||
|
||||
#define ATTEMPT_ERROR_MUTING
|
||||
|
||||
// This provides an extension to the WavpackOpenFileRead () function contained
|
||||
// in the wputils.c module. It is assumed that an 'R' had been read as the
|
||||
// first character of the file/stream (indicating a non-raw pre version 4.0
|
||||
// WavPack file) and had been pushed back onto the stream (or simply seeked
|
||||
// back to).
|
||||
|
||||
WavpackContext *open_file3 (WavpackContext *wpc, char *error)
|
||||
{
|
||||
RiffChunkHeader RiffChunkHeader;
|
||||
ChunkHeader ChunkHeader;
|
||||
WavpackHeader3 wphdr;
|
||||
WavpackStream3 *wps;
|
||||
WaveHeader3 wavhdr;
|
||||
|
||||
CLEAR (wavhdr);
|
||||
wpc->stream3 = wps = (WavpackStream3 *) malloc (sizeof (WavpackStream3));
|
||||
CLEAR (*wps);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, &RiffChunkHeader, sizeof (RiffChunkHeader)) !=
|
||||
sizeof (RiffChunkHeader)) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (!strncmp (RiffChunkHeader.ckID, "RIFF", 4) && !strncmp (RiffChunkHeader.formType, "WAVE", 4)) {
|
||||
|
||||
if (wpc->open_flags & OPEN_WRAPPER) {
|
||||
wpc->wrapper_data = (unsigned char *)malloc (wpc->wrapper_bytes = sizeof (RiffChunkHeader));
|
||||
memcpy (wpc->wrapper_data, &RiffChunkHeader, sizeof (RiffChunkHeader));
|
||||
}
|
||||
|
||||
// If the first chunk is a wave RIFF header, then read the various chunks
|
||||
// until we get to the "data" chunk (and WavPack header should follow). If
|
||||
// the first chunk is not a RIFF, then we assume a "raw" WavPack file and
|
||||
// the WavPack header must be first.
|
||||
|
||||
while (1) {
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, &ChunkHeader, sizeof (ChunkHeader)) !=
|
||||
sizeof (ChunkHeader)) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
else {
|
||||
if (wpc->open_flags & OPEN_WRAPPER) {
|
||||
wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (ChunkHeader));
|
||||
memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &ChunkHeader, sizeof (ChunkHeader));
|
||||
wpc->wrapper_bytes += sizeof (ChunkHeader);
|
||||
}
|
||||
|
||||
WavpackLittleEndianToNative (&ChunkHeader, ChunkHeaderFormat);
|
||||
|
||||
if (!strncmp (ChunkHeader.ckID, "fmt ", 4)) {
|
||||
|
||||
if (ChunkHeader.ckSize < sizeof (wavhdr) ||
|
||||
wpc->reader->read_bytes (wpc->wv_in, &wavhdr, sizeof (wavhdr)) != sizeof (wavhdr)) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
else if (wpc->open_flags & OPEN_WRAPPER) {
|
||||
wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (wavhdr));
|
||||
memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &wavhdr, sizeof (wavhdr));
|
||||
wpc->wrapper_bytes += sizeof (wavhdr);
|
||||
}
|
||||
|
||||
WavpackLittleEndianToNative (&wavhdr, WaveHeader3Format);
|
||||
|
||||
if (ChunkHeader.ckSize > sizeof (wavhdr)) {
|
||||
uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1 - sizeof (wavhdr)) & ~1L;
|
||||
|
||||
if (bytes_to_skip > 1024 * 1024) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (wpc->open_flags & OPEN_WRAPPER) {
|
||||
wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip);
|
||||
wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip);
|
||||
wpc->wrapper_bytes += bytes_to_skip;
|
||||
}
|
||||
else {
|
||||
unsigned char *temp = (unsigned char *)malloc (bytes_to_skip);
|
||||
wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip);
|
||||
free (temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strncmp (ChunkHeader.ckID, "data", 4))
|
||||
break;
|
||||
else if ((ChunkHeader.ckSize + 1) & ~1L) {
|
||||
uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1) & ~1L;
|
||||
|
||||
if (bytes_to_skip > 1024 * 1024) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (wpc->open_flags & OPEN_WRAPPER) {
|
||||
wpc->wrapper_data = (unsigned char *)realloc (wpc->wrapper_data, wpc->wrapper_bytes + bytes_to_skip);
|
||||
wpc->reader->read_bytes (wpc->wv_in, wpc->wrapper_data + wpc->wrapper_bytes, bytes_to_skip);
|
||||
wpc->wrapper_bytes += bytes_to_skip;
|
||||
}
|
||||
else {
|
||||
unsigned char *temp = (unsigned char *)malloc (bytes_to_skip);
|
||||
wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip);
|
||||
free (temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (wavhdr.FormatTag != 1 || !wavhdr.NumChannels || wavhdr.NumChannels > 2 ||
|
||||
!wavhdr.SampleRate || wavhdr.BitsPerSample < 16 || wavhdr.BitsPerSample > 24 ||
|
||||
wavhdr.BlockAlign / wavhdr.NumChannels > 3 || wavhdr.BlockAlign % wavhdr.NumChannels ||
|
||||
wavhdr.BlockAlign / wavhdr.NumChannels < (wavhdr.BitsPerSample + 7) / 8) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
wpc->total_samples = ChunkHeader.ckSize / wavhdr.NumChannels /
|
||||
((wavhdr.BitsPerSample > 16) ? 3 : 2);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, &wphdr, 10) != 10) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (((char *) &wphdr) [8] == 2 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10, 2) != 2)) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
else if (((char *) &wphdr) [8] == 3 && (wpc->reader->read_bytes (wpc->wv_in, ((char *) &wphdr) + 10,
|
||||
sizeof (wphdr) - 10) != sizeof (wphdr) - 10)) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
WavpackLittleEndianToNative (&wphdr, WavpackHeader3Format);
|
||||
|
||||
// make sure this is a version we know about
|
||||
|
||||
if (strncmp (wphdr.ckID, "wvpk", 4) || wphdr.version < 1 || wphdr.version > 3) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
// Because I ran out of flag bits in the WavPack header, an amazingly ugly
|
||||
// kludge was forced upon me! This code takes care of preparing the flags
|
||||
// field for internal use and checking for unknown formats we can't decode
|
||||
|
||||
if (wphdr.version == 3) {
|
||||
|
||||
if (wphdr.flags & EXTREME_DECORR) {
|
||||
|
||||
if ((wphdr.flags & NOT_STORED_FLAGS) ||
|
||||
((wphdr.bits) &&
|
||||
(((wphdr.flags & NEW_HIGH_FLAG) &&
|
||||
(wphdr.flags & (FAST_FLAG | HIGH_FLAG))) ||
|
||||
(wphdr.flags & CROSS_DECORR)))) {
|
||||
if (error) strcpy (error, "not a valid WavPack file!");
|
||||
return WavpackCloseFile (wpc);
|
||||
}
|
||||
|
||||
if (wphdr.flags & CANCEL_EXTREME)
|
||||
wphdr.flags &= ~(EXTREME_DECORR | CANCEL_EXTREME);
|
||||
}
|
||||
else
|
||||
wphdr.flags &= ~CROSS_DECORR;
|
||||
}
|
||||
|
||||
// check to see if we should look for a "correction" file, and if so try
|
||||
// to open it for reading, then set WVC_FLAG accordingly
|
||||
|
||||
if (wpc->wvc_in && wphdr.version == 3 && wphdr.bits && (wphdr.flags & NEW_HIGH_FLAG)) {
|
||||
wpc->file2len = wpc->reader->get_length (wpc->wvc_in);
|
||||
wphdr.flags |= WVC_FLAG;
|
||||
wpc->wvc_flag = TRUE;
|
||||
}
|
||||
else
|
||||
wphdr.flags &= ~WVC_FLAG;
|
||||
|
||||
// check WavPack version to handle special requirements of versions
|
||||
// before 3.0 that had smaller headers
|
||||
|
||||
if (wphdr.version < 3) {
|
||||
wphdr.total_samples = (int32_t) wpc->total_samples;
|
||||
wphdr.flags = wavhdr.NumChannels == 1 ? MONO_FLAG : 0;
|
||||
wphdr.shift = 16 - wavhdr.BitsPerSample;
|
||||
|
||||
if (wphdr.version == 1)
|
||||
wphdr.bits = 0;
|
||||
}
|
||||
|
||||
wpc->config.sample_rate = wavhdr.SampleRate;
|
||||
wpc->config.num_channels = wavhdr.NumChannels;
|
||||
wpc->config.channel_mask = 5 - wavhdr.NumChannels;
|
||||
|
||||
if (wphdr.flags & MONO_FLAG)
|
||||
wpc->config.flags |= CONFIG_MONO_FLAG;
|
||||
|
||||
if (wphdr.flags & EXTREME_DECORR)
|
||||
wpc->config.flags |= CONFIG_HIGH_FLAG;
|
||||
|
||||
if (wphdr.bits) {
|
||||
if (wphdr.flags & NEW_HIGH_FLAG)
|
||||
wpc->config.flags |= CONFIG_HYBRID_FLAG;
|
||||
else
|
||||
wpc->config.flags |= CONFIG_LOSSY_MODE;
|
||||
}
|
||||
else if (!(wphdr.flags & HIGH_FLAG))
|
||||
wpc->config.flags |= CONFIG_FAST_FLAG;
|
||||
|
||||
wpc->config.bytes_per_sample = (wphdr.flags & BYTES_3) ? 3 : 2;
|
||||
wpc->config.bits_per_sample = wavhdr.BitsPerSample;
|
||||
|
||||
memcpy (&wps->wphdr, &wphdr, sizeof (wphdr));
|
||||
wps->wvbits.bufsiz = wps->wvcbits.bufsiz = 1024 * 1024;
|
||||
return wpc;
|
||||
}
|
||||
|
||||
// return currently decoded sample index
|
||||
|
||||
uint32_t get_sample_index3 (WavpackContext *wpc)
|
||||
{
|
||||
WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
|
||||
|
||||
return (wps) ? wps->sample_index : (uint32_t) -1;
|
||||
}
|
||||
|
||||
int get_version3 (WavpackContext *wpc)
|
||||
{
|
||||
WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
|
||||
|
||||
return (wps) ? wps->wphdr.version : 0;
|
||||
}
|
||||
|
||||
void free_stream3 (WavpackContext *wpc)
|
||||
{
|
||||
WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
|
||||
|
||||
if (wps) {
|
||||
#ifndef NO_SEEKING
|
||||
if (wps->unpack_data)
|
||||
free (wps->unpack_data);
|
||||
#endif
|
||||
if ((wps->wphdr.flags & WVC_FLAG) && wps->wvcbits.buf)
|
||||
free (wps->wvcbits.buf);
|
||||
|
||||
if (wps->wvbits.buf)
|
||||
free (wps->wvbits.buf);
|
||||
|
||||
free (wps);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ENABLE_LEGACY
|
||||
@ -0,0 +1,212 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack3_seek.c
|
||||
|
||||
// This module provides seeking support for WavPack files prior to version 4.0.
|
||||
|
||||
#ifdef ENABLE_LEGACY
|
||||
#ifndef NO_SEEKING
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
#include "unpack3.h"
|
||||
|
||||
static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources);
|
||||
static void bs_restore3 (Bitstream3 *bs);
|
||||
|
||||
// This is an extension for WavpackSeekSample (). Note that because WavPack
|
||||
// files created prior to version 4.0 are not inherently seekable, this
|
||||
// function could take a long time if a forward seek is requested to an
|
||||
// area that has not been played (or seeked through) yet.
|
||||
|
||||
int seek_sample3 (WavpackContext *wpc, uint32_t desired_index)
|
||||
{
|
||||
int points_index = desired_index / (((uint32_t) wpc->total_samples >> 8) + 1);
|
||||
WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3;
|
||||
|
||||
if (desired_index >= wpc->total_samples)
|
||||
return FALSE;
|
||||
|
||||
while (points_index)
|
||||
if (wps->index_points [points_index].saved &&
|
||||
wps->index_points [points_index].sample_index <= desired_index)
|
||||
break;
|
||||
else
|
||||
points_index--;
|
||||
|
||||
if (wps->index_points [points_index].saved)
|
||||
if (wps->index_points [points_index].sample_index > wps->sample_index ||
|
||||
wps->sample_index > desired_index) {
|
||||
wps->sample_index = wps->index_points [points_index].sample_index;
|
||||
unpack_restore (wps, wps->unpack_data + points_index * wps->unpack_size, TRUE);
|
||||
}
|
||||
|
||||
if (desired_index > wps->sample_index) {
|
||||
int32_t *buffer = (int32_t *) malloc (1024 * (wps->wphdr.flags & MONO_FLAG ? 4 : 8));
|
||||
uint32_t samples_to_skip = desired_index - wps->sample_index;
|
||||
|
||||
while (1) {
|
||||
if (samples_to_skip > 1024) {
|
||||
if (unpack_samples3 (wpc, buffer, 1024) == 1024)
|
||||
samples_to_skip -= 1024;
|
||||
else
|
||||
break;
|
||||
}
|
||||
else {
|
||||
samples_to_skip -= unpack_samples3 (wpc, buffer, samples_to_skip);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free (buffer);
|
||||
|
||||
if (samples_to_skip)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// This function restores the unpacking context from the specified pointer
|
||||
// and returns the updated pointer. After this call, unpack_samples() will
|
||||
// continue where it left off immediately before unpack_save() was called.
|
||||
// If the WavPack files and bitstreams might have been closed and reopened,
|
||||
// then the "keep_resources" flag should be set to avoid using the "old"
|
||||
// resources that were originally saved (and are probably now invalid).
|
||||
|
||||
static void *unpack_restore (WavpackStream3 *wps, void *source, int keep_resources)
|
||||
{
|
||||
int flags = wps->wphdr.flags, tcount;
|
||||
struct decorr_pass *dpp;
|
||||
FILE *temp_file;
|
||||
unsigned char *temp_buf;
|
||||
|
||||
unpack_init3 (wps);
|
||||
temp_file = wps->wvbits.id;
|
||||
temp_buf = wps->wvbits.buf;
|
||||
RESTORE (wps->wvbits, source);
|
||||
|
||||
if (keep_resources) {
|
||||
wps->wvbits.id = temp_file;
|
||||
wps->wvbits.ptr += temp_buf - wps->wvbits.buf;
|
||||
wps->wvbits.end += temp_buf - wps->wvbits.buf;
|
||||
wps->wvbits.buf = temp_buf;
|
||||
}
|
||||
|
||||
bs_restore3 (&wps->wvbits);
|
||||
|
||||
if (flags & WVC_FLAG) {
|
||||
temp_file = wps->wvcbits.id;
|
||||
temp_buf = wps->wvcbits.buf;
|
||||
RESTORE (wps->wvcbits, source);
|
||||
|
||||
if (keep_resources) {
|
||||
wps->wvcbits.id = temp_file;
|
||||
wps->wvcbits.ptr += temp_buf - wps->wvcbits.buf;
|
||||
wps->wvcbits.end += temp_buf - wps->wvcbits.buf;
|
||||
wps->wvcbits.buf = temp_buf;
|
||||
}
|
||||
|
||||
bs_restore3 (&wps->wvcbits);
|
||||
}
|
||||
|
||||
if (wps->wphdr.version == 3) {
|
||||
if (wps->wphdr.bits) {
|
||||
RESTORE (wps->w4, source);
|
||||
}
|
||||
else {
|
||||
RESTORE (wps->w1, source);
|
||||
}
|
||||
|
||||
RESTORE (wps->w3, source);
|
||||
RESTORE (wps->dc.crc, source);
|
||||
}
|
||||
else
|
||||
RESTORE (wps->w2, source);
|
||||
|
||||
if (wps->wphdr.bits) {
|
||||
RESTORE (wps->dc.error, source);
|
||||
}
|
||||
else {
|
||||
RESTORE (wps->dc.sum_level, source);
|
||||
RESTORE (wps->dc.left_level, source);
|
||||
RESTORE (wps->dc.right_level, source);
|
||||
RESTORE (wps->dc.diff_level, source);
|
||||
}
|
||||
|
||||
if (flags & OVER_20) {
|
||||
RESTORE (wps->dc.last_extra_bits, source);
|
||||
RESTORE (wps->dc.extra_bits_count, source);
|
||||
}
|
||||
|
||||
if (!(flags & EXTREME_DECORR)) {
|
||||
RESTORE (wps->dc.sample, source);
|
||||
RESTORE (wps->dc.weight, source);
|
||||
}
|
||||
|
||||
if (flags & (HIGH_FLAG | NEW_HIGH_FLAG))
|
||||
for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) {
|
||||
if (dpp->term > 0) {
|
||||
int count = dpp->term;
|
||||
int index = wps->dc.m;
|
||||
|
||||
RESTORE (dpp->weight_A, source);
|
||||
|
||||
while (count--) {
|
||||
RESTORE (dpp->samples_A [index], source);
|
||||
index = (index + 1) & (MAX_TERM - 1);
|
||||
}
|
||||
|
||||
if (!(flags & MONO_FLAG)) {
|
||||
count = dpp->term;
|
||||
index = wps->dc.m;
|
||||
|
||||
RESTORE (dpp->weight_B, source);
|
||||
|
||||
while (count--) {
|
||||
RESTORE (dpp->samples_B [index], source);
|
||||
index = (index + 1) & (MAX_TERM - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
RESTORE (dpp->weight_A, source);
|
||||
RESTORE (dpp->weight_B, source);
|
||||
RESTORE (dpp->samples_A [0], source);
|
||||
RESTORE (dpp->samples_B [0], source);
|
||||
}
|
||||
}
|
||||
|
||||
return source;
|
||||
}
|
||||
|
||||
// This function is called after a call to unpack_restore() has restored
|
||||
// the BitStream structure to a previous state and causes any required data
|
||||
// to be read from the file. This function is NOT supported for overlapped
|
||||
// operation.
|
||||
|
||||
static void bs_restore3 (Bitstream3 *bs)
|
||||
{
|
||||
uint32_t bytes_to_read = (uint32_t)(bs->end - bs->ptr - 1), bytes_read;
|
||||
|
||||
bs->reader->set_pos_abs (bs->id, bs->fpos - bytes_to_read);
|
||||
|
||||
if (bytes_to_read > 0) {
|
||||
|
||||
bytes_read = bs->reader->read_bytes (bs->id, bs->ptr + 1, bytes_to_read);
|
||||
|
||||
if (bytes_to_read != bytes_read)
|
||||
bs->end = bs->ptr + 1 + bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // NO_SEEKING
|
||||
#endif // ENABLE_LEGACY
|
||||
@ -0,0 +1,887 @@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@@ **** WAVPACK **** @@
|
||||
@@ Hybrid Lossless Wavefile Compressor @@
|
||||
@@ Copyright (c) 1998 - 2015 Conifer Software. @@
|
||||
@@ All Rights Reserved. @@
|
||||
@@ Distributed under the BSD Software License (see license.txt) @@
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
|
||||
.text
|
||||
.align
|
||||
.global unpack_decorr_stereo_pass_cont_armv7
|
||||
.global unpack_decorr_mono_pass_cont_armv7
|
||||
|
||||
/* This is an assembly optimized version of the following WavPack function:
|
||||
*
|
||||
* void decorr_stereo_pass_cont (struct decorr_pass *dpp,
|
||||
* int32_t *buffer,
|
||||
* int32_t sample_counti,
|
||||
* int32_t long_math);
|
||||
*
|
||||
* It performs a single pass of stereo decorrelation on the provided buffer.
|
||||
* Note that this version of the function requires that up to 8 previous stereo
|
||||
* samples are visible and correct. In other words, it ignores the "samples_*"
|
||||
* fields in the decorr_pass structure and gets the history data directly
|
||||
* from the buffer. It does, however, return the appropriate history samples
|
||||
* to the decorr_pass structure before returning.
|
||||
*
|
||||
* This should work on all ARM architectures. This version of the code
|
||||
* checks the magnitude of the decorrelation sample with a pair of shifts
|
||||
* to avoid possible overflow (and therefore ignores the "long_math" arg).
|
||||
* Previously I used the SSAT instruction for this, but then discovered that
|
||||
* SSAT is not universally available (although on the armv7 I'm testing on
|
||||
* it is slightly faster than the shifts).
|
||||
*
|
||||
* A mono version follows below.
|
||||
*/
|
||||
|
||||
/*
|
||||
* on entry:
|
||||
*
|
||||
* r0 = struct decorr_pass *dpp
|
||||
* r1 = int32_t *buffer
|
||||
* r2 = int32_t sample_count
|
||||
* r3 = int32_t long_math
|
||||
*/
|
||||
|
||||
unpack_decorr_stereo_pass_cont_armv7:
|
||||
|
||||
stmfd sp!, {r4 - r8, r10, r11, lr}
|
||||
|
||||
mov r5, r0 @ r5 = dpp
|
||||
mov r11, #512 @ r11 = 512 for rounding
|
||||
ldr r6, [r0, #4] @ r6 = dpp->delta
|
||||
ldr r4, [r0, #8] @ r4 = dpp->weight_A
|
||||
ldr r0, [r0, #12] @ r0 = dpp->weight_B
|
||||
cmp r2, #0 @ exit if no samples to process
|
||||
beq common_exit
|
||||
|
||||
add r7, r1, r2, asl #3 @ r7 = buffer ending position
|
||||
ldr r2, [r5, #0] @ r2 = dpp->term
|
||||
cmp r2, #0
|
||||
bmi minus_term
|
||||
|
||||
ldr lr, [r1, #-16] @ load 2 sample history from buffer
|
||||
ldr r10, [r1, #-12] @ for terms 2, 17, and 18
|
||||
ldr r8, [r1, #-8]
|
||||
ldr r3, [r1, #-4]
|
||||
cmp r2, #17
|
||||
beq term_17_loop
|
||||
cmp r2, #18
|
||||
beq term_18_loop
|
||||
cmp r2, #2
|
||||
beq term_2_loop
|
||||
b term_default_loop @ else handle default (1-8, except 2)
|
||||
|
||||
minus_term:
|
||||
mov r10, #1024 @ r10 = -1024 for weight clipping
|
||||
rsb r10, r10, #0 @ (only used for negative terms)
|
||||
cmn r2, #1
|
||||
beq term_minus_1
|
||||
cmn r2, #2
|
||||
beq term_minus_2
|
||||
cmn r2, #3
|
||||
beq term_minus_3
|
||||
b common_exit
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle term = 17 condition
|
||||
*
|
||||
* r0 = dpp->weight_B r8 = previous left sample
|
||||
* r1 = bptr r9 =
|
||||
* r2 = current sample r10 = second previous right sample
|
||||
* r3 = previous right sample r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = current decorrelation value
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr = second previous left sample
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
term_17_loop:
|
||||
rsb ip, lr, r8, asl #1 @ decorr value = (2 * prev) - 2nd prev
|
||||
mov lr, r8 @ previous becomes 2nd previous
|
||||
ldr r2, [r1], #4 @ get sample & update pointer
|
||||
mov r8, ip, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp ip, r8, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S117
|
||||
cmp ip, #0
|
||||
mla r8, ip, r4, r11 @ mult decorr value by weight, round,
|
||||
add r8, r2, r8, asr #10 @ shift, and add to new sample
|
||||
b S118
|
||||
|
||||
S117: mov r8, #0 @ use 64-bit multiply to avoid overflow
|
||||
smlal r11, r8, r4, ip
|
||||
add r8, r2, r8, lsl #22
|
||||
add r8, r8, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S118: strne r8, [r1, #-4] @ if change possible, store sample back
|
||||
cmpne r2, #0
|
||||
beq S325
|
||||
teq ip, r2 @ update weight based on signs
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
|
||||
S325: rsb ip, r10, r3, asl #1 @ do same thing for right channel
|
||||
mov r10, r3
|
||||
ldr r2, [r1], #4
|
||||
mov r3, ip, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp ip, r3, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S119
|
||||
cmp ip, #0
|
||||
mla r3, ip, r0, r11
|
||||
add r3, r2, r3, asr #10
|
||||
b S120
|
||||
|
||||
S119: mov r3, #0
|
||||
smlal r11, r3, r0, ip
|
||||
add r3, r2, r3, lsl #22
|
||||
add r3, r3, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S120: strne r3, [r1, #-4]
|
||||
cmpne r2, #0
|
||||
beq S329
|
||||
teq ip, r2
|
||||
submi r0, r0, r6
|
||||
addpl r0, r0, r6
|
||||
|
||||
S329: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi term_17_loop
|
||||
b store_1718 @ common exit for terms 17 & 18
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle term = 18 condition
|
||||
*
|
||||
* r0 = dpp->weight_B r8 = previous left sample
|
||||
* r1 = bptr r9 =
|
||||
* r2 = current sample r10 = second previous right sample
|
||||
* r3 = previous right sample r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = decorrelation value
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr = second previous left sample
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
term_18_loop:
|
||||
sub ip, r8, lr @ decorr value =
|
||||
mov lr, r8 @ ((3 * prev) - 2nd prev) >> 1
|
||||
add ip, r8, ip, asr #1
|
||||
ldr r2, [r1], #4 @ get sample & update pointer
|
||||
mov r8, ip, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp ip, r8, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S121
|
||||
cmp ip, #0
|
||||
mla r8, ip, r4, r11 @ mult decorr value by weight, round,
|
||||
add r8, r2, r8, asr #10 @ shift, and add to new sample
|
||||
b S122
|
||||
|
||||
S121: mov r8, #0 @ use 64-bit multiply to avoid overflow
|
||||
smlal r11, r8, r4, ip
|
||||
add r8, r2, r8, lsl #22
|
||||
add r8, r8, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S122: strne r8, [r1, #-4] @ if change possible, store sample back
|
||||
cmpne r2, #0
|
||||
beq S337
|
||||
teq ip, r2 @ update weight based on signs
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
|
||||
S337: sub ip, r3, r10 @ do same thing for right channel
|
||||
mov r10, r3
|
||||
add ip, r3, ip, asr #1
|
||||
ldr r2, [r1], #4
|
||||
mov r3, ip, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp ip, r3, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S123
|
||||
cmp ip, #0
|
||||
mla r3, ip, r0, r11
|
||||
add r3, r2, r3, asr #10
|
||||
b S124
|
||||
|
||||
S123: mov r3, #0
|
||||
smlal r11, r3, r0, ip
|
||||
add r3, r2, r3, lsl #22
|
||||
add r3, r3, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S124: strne r3, [r1, #-4]
|
||||
cmpne r2, #0
|
||||
beq S341
|
||||
teq ip, r2
|
||||
submi r0, r0, r6
|
||||
addpl r0, r0, r6
|
||||
|
||||
S341: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi term_18_loop
|
||||
|
||||
/* common exit for terms 17 & 18 */
|
||||
|
||||
store_1718:
|
||||
str r3, [r5, #48] @ store sample history into struct
|
||||
str r8, [r5, #16]
|
||||
str r10, [r5, #52]
|
||||
str lr, [r5, #20]
|
||||
b common_exit @ and return
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle term = 2 condition
|
||||
* (note that this case can be handled by the default term handler (1-8), but
|
||||
* this special case is faster because it doesn't have to read memory twice)
|
||||
*
|
||||
* r0 = dpp->weight_B r8 = previous left sample
|
||||
* r1 = bptr r9 =
|
||||
* r2 = current sample r10 = second previous right sample
|
||||
* r3 = previous right sample r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = decorrelation value
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr = second previous left sample
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
term_2_loop:
|
||||
mov ip, lr @ get decorrelation value
|
||||
mov lr, r8 @ previous becomes 2nd previous
|
||||
ldr r2, [r1], #4 @ get sample & update pointer
|
||||
mov r8, ip, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp ip, r8, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S125
|
||||
cmp ip, #0
|
||||
mla r8, ip, r4, r11 @ mult decorr value by weight, round,
|
||||
add r8, r2, r8, asr #10 @ shift, and add to new sample
|
||||
b S126
|
||||
|
||||
S125: mov r8, #0 @ use 64-bit multiply to avoid overflow
|
||||
smlal r11, r8, r4, ip
|
||||
add r8, r2, r8, lsl #22
|
||||
add r8, r8, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S126: strne r8, [r1, #-4] @ if change possible, store sample back
|
||||
cmpne r2, #0
|
||||
beq S225
|
||||
teq ip, r2 @ update weight based on signs
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
|
||||
S225: mov ip, r10 @ do same thing for right channel
|
||||
mov r10, r3
|
||||
ldr r2, [r1], #4
|
||||
mov r3, ip, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp ip, r3, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S127
|
||||
cmp ip, #0
|
||||
mla r3, ip, r0, r11
|
||||
add r3, r2, r3, asr #10
|
||||
b S128
|
||||
|
||||
S127: mov r3, #0
|
||||
smlal r11, r3, r0, ip
|
||||
add r3, r2, r3, lsl #22
|
||||
add r3, r3, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S128: strne r3, [r1, #-4]
|
||||
cmpne r2, #0
|
||||
beq S229
|
||||
teq ip, r2
|
||||
submi r0, r0, r6
|
||||
addpl r0, r0, r6
|
||||
|
||||
S229: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi term_2_loop
|
||||
b default_term_exit @ this exit updates all dpp->samples
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle default term condition
|
||||
*
|
||||
* r0 = dpp->weight_B r8 = result accumulator
|
||||
* r1 = bptr r9 =
|
||||
* r2 = dpp->term r10 =
|
||||
* r3 = decorrelation value r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = current sample
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr =
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
term_default_loop:
|
||||
ldr ip, [r1] @ get original sample
|
||||
ldr r3, [r1, -r2, asl #3] @ get decorrelation value based on term
|
||||
mov r8, r3, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp r3, r8, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S135
|
||||
cmp r3, #0
|
||||
mla r8, r3, r4, r11 @ mult decorr value by weight, round,
|
||||
add r8, ip, r8, asr #10 @ shift and add to new sample
|
||||
b S136
|
||||
|
||||
S135: mov r8, #0 @ use 64-bit multiply to avoid overflow
|
||||
smlal r11, r8, r4, r3
|
||||
add r8, ip, r8, lsl #22
|
||||
add r8, r8, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S136: str r8, [r1], #4 @ store update sample
|
||||
cmpne ip, #0
|
||||
beq S350
|
||||
teq ip, r3 @ update weight based on signs
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
|
||||
S350: ldr ip, [r1] @ do the same thing for right channel
|
||||
ldr r3, [r1, -r2, asl #3]
|
||||
mov r8, r3, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp r3, r8, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S137
|
||||
cmp r3, #0
|
||||
mla r8, r3, r0, r11
|
||||
add r8, ip, r8, asr #10
|
||||
b S138
|
||||
|
||||
S137: mov r8, #0
|
||||
smlal r11, r8, r0, r3
|
||||
add r8, ip, r8, lsl #22
|
||||
add r8, r8, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S138: str r8, [r1], #4
|
||||
cmpne ip, #0
|
||||
beq S354
|
||||
teq ip, r3
|
||||
submi r0, r0, r6
|
||||
addpl r0, r0, r6
|
||||
|
||||
S354: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi term_default_loop
|
||||
|
||||
/*
|
||||
* This exit is used by terms 1-8 to store the previous "term" samples (up to 8)
|
||||
* into the decorr pass structure history
|
||||
*/
|
||||
|
||||
default_term_exit:
|
||||
ldr r2, [r5, #0] @ r2 = dpp->term
|
||||
|
||||
S358: sub r2, r2, #1
|
||||
sub r1, r1, #8
|
||||
ldr r3, [r1, #4] @ get right sample and store in dpp->samples_B [r2]
|
||||
add r6, r5, #48
|
||||
str r3, [r6, r2, asl #2]
|
||||
ldr r3, [r1, #0] @ get left sample and store in dpp->samples_A [r2]
|
||||
add r6, r5, #16
|
||||
str r3, [r6, r2, asl #2]
|
||||
cmp r2, #0
|
||||
bne S358
|
||||
b common_exit
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle term = -1 condition
|
||||
*
|
||||
* r0 = dpp->weight_B r8 =
|
||||
* r1 = bptr r9 =
|
||||
* r2 = intermediate result r10 = -1024 (for clipping)
|
||||
* r3 = previous right sample r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = current sample
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr = updated left sample
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
term_minus_1:
|
||||
ldr r3, [r1, #-4]
|
||||
|
||||
term_minus_1_loop:
|
||||
ldr ip, [r1] @ for left channel the decorrelation value
|
||||
@ is the previous right sample (in r3)
|
||||
mov lr, r3, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp r3, lr, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S142
|
||||
cmp r3, #0
|
||||
mla r2, r3, r4, r11
|
||||
add lr, ip, r2, asr #10
|
||||
b S143
|
||||
|
||||
S142: mov lr, #0 @ use 64-bit multiply to avoid overflow
|
||||
smlal r11, lr, r4, r3
|
||||
add lr, ip, lr, lsl #22
|
||||
add lr, lr, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S143: str lr, [r1], #8
|
||||
cmpne ip, #0
|
||||
beq S361
|
||||
teq ip, r3 @ update weight based on signs
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
cmp r4, #1024
|
||||
movgt r4, #1024
|
||||
cmp r4, r10
|
||||
movlt r4, r10
|
||||
|
||||
S361: ldr r2, [r1, #-4] @ for right channel the decorrelation value
|
||||
@ is the just updated right sample (in lr)
|
||||
mov r3, lr, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp lr, r3, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S144
|
||||
cmp lr, #0
|
||||
mla r3, lr, r0, r11
|
||||
add r3, r2, r3, asr #10
|
||||
b S145
|
||||
|
||||
S144: mov r3, #0
|
||||
smlal r11, r3, r0, lr
|
||||
add r3, r2, r3, lsl #22
|
||||
add r3, r3, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S145: strne r3, [r1, #-4]
|
||||
cmpne r2, #0
|
||||
beq S369
|
||||
teq r2, lr
|
||||
submi r0, r0, r6
|
||||
addpl r0, r0, r6
|
||||
cmp r0, #1024 @ then clip weight to +/-1024
|
||||
movgt r0, #1024
|
||||
cmp r0, r10
|
||||
movlt r0, r10
|
||||
|
||||
S369: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi term_minus_1_loop
|
||||
|
||||
str r3, [r5, #16] @ else store right sample and exit
|
||||
b common_exit
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle term = -2 condition
|
||||
* (note that the channels are processed in the reverse order here)
|
||||
*
|
||||
* r0 = dpp->weight_B r8 =
|
||||
* r1 = bptr r9 =
|
||||
* r2 = intermediate result r10 = -1024 (for clipping)
|
||||
* r3 = previous left sample r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = current sample
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr = updated right sample
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
term_minus_2:
|
||||
ldr r3, [r1, #-8]
|
||||
|
||||
term_minus_2_loop:
|
||||
ldr ip, [r1, #4] @ for right channel the decorrelation value
|
||||
@ is the previous left sample (in r3)
|
||||
mov lr, r3, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp r3, lr, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S146
|
||||
cmp r3, #0
|
||||
mla r2, r3, r0, r11
|
||||
add lr, ip, r2, asr #10
|
||||
b S147
|
||||
|
||||
S146: mov lr, #0 @ use 64-bit multiply to avoid overflow
|
||||
smlal r11, lr, r0, r3
|
||||
add lr, ip, lr, lsl #22
|
||||
add lr, lr, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S147: strne lr, [r1, #4]
|
||||
cmpne ip, #0
|
||||
beq S380
|
||||
teq ip, r3 @ update weight based on signs
|
||||
submi r0, r0, r6
|
||||
addpl r0, r0, r6
|
||||
cmp r0, #1024 @ then clip weight to +/-1024
|
||||
movgt r0, #1024
|
||||
cmp r0, r10
|
||||
movlt r0, r10
|
||||
|
||||
S380: ldr r2, [r1, #0] @ for left channel the decorrelation value
|
||||
@ is the just updated left sample (in lr)
|
||||
mov r3, lr, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp lr, r3, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S148
|
||||
cmp lr, #0
|
||||
mla r3, lr, r4, r11
|
||||
add r3, r2, r3, asr #10
|
||||
b S149
|
||||
|
||||
S148: mov r3, #0
|
||||
smlal r11, r3, r4, lr
|
||||
add r3, r2, r3, lsl #22
|
||||
add r3, r3, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S149: str r3, [r1], #8
|
||||
cmpne r2, #0
|
||||
beq S388
|
||||
teq r2, lr
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
cmp r4, #1024
|
||||
movgt r4, #1024
|
||||
cmp r4, r10
|
||||
movlt r4, r10
|
||||
|
||||
S388: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi term_minus_2_loop
|
||||
|
||||
str r3, [r5, #48] @ else store left channel and exit
|
||||
b common_exit
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle term = -3 condition
|
||||
*
|
||||
* r0 = dpp->weight_B r8 = previous left sample
|
||||
* r1 = bptr r9 =
|
||||
* r2 = current left sample r10 = -1024 (for clipping)
|
||||
* r3 = previous right sample r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = intermediate result
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr =
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
term_minus_3:
|
||||
ldr r3, [r1, #-4] @ load previous samples
|
||||
ldr r8, [r1, #-8]
|
||||
|
||||
term_minus_3_loop:
|
||||
ldr ip, [r1]
|
||||
mov r2, r3, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp r3, r2, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S160
|
||||
cmp r3, #0
|
||||
mla r2, r3, r4, r11
|
||||
add r2, ip, r2, asr #10
|
||||
b S161
|
||||
|
||||
S160: mov r2, #0 @ use 64-bit multiply to avoid overflow
|
||||
smlal r11, r2, r4, r3
|
||||
add r2, ip, r2, lsl #22
|
||||
add r2, r2, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S161: str r2, [r1], #4
|
||||
cmpne ip, #0
|
||||
beq S399
|
||||
teq ip, r3 @ update weight based on signs
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
cmp r4, #1024 @ then clip weight to +/-1024
|
||||
movgt r4, #1024
|
||||
cmp r4, r10
|
||||
movlt r4, r10
|
||||
|
||||
S399: mov ip, r8 @ ip = previous left we use now
|
||||
mov r8, r2 @ r8 = current left we use next time
|
||||
ldr r2, [r1], #4
|
||||
mov r3, ip, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp ip, r3, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S162
|
||||
cmp ip, #0
|
||||
mla r3, ip, r0, r11
|
||||
add r3, r2, r3, asr #10
|
||||
b S163
|
||||
|
||||
S162: mov r3, #0
|
||||
smlal r11, r3, r0, ip
|
||||
add r3, r2, r3, lsl #22
|
||||
add r3, r3, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S163: strne r3, [r1, #-4]
|
||||
cmpne r2, #0
|
||||
beq S407
|
||||
teq ip, r2
|
||||
submi r0, r0, r6
|
||||
addpl r0, r0, r6
|
||||
cmp r0, #1024
|
||||
movgt r0, #1024
|
||||
cmp r0, r10
|
||||
movlt r0, r10
|
||||
|
||||
S407: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi term_minus_3_loop
|
||||
|
||||
str r3, [r5, #16] @ else store previous samples & exit
|
||||
str r8, [r5, #48]
|
||||
|
||||
/*
|
||||
* Before finally exiting we must store weights back for next time
|
||||
*/
|
||||
|
||||
common_exit:
|
||||
str r4, [r5, #8]
|
||||
str r0, [r5, #12]
|
||||
ldmfd sp!, {r4 - r8, r10, r11, pc}
|
||||
|
||||
|
||||
|
||||
/* This is a mono version of the function above. It does not handle negative terms.
|
||||
*
|
||||
* void decorr_mono_pass_cont (struct decorr_pass *dpp,
|
||||
* int32_t *buffer,
|
||||
* int32_t sample_counti,
|
||||
* int32_t long_math);
|
||||
* on entry:
|
||||
*
|
||||
* r0 = struct decorr_pass *dpp
|
||||
* r1 = int32_t *buffer
|
||||
* r2 = int32_t sample_count
|
||||
* r3 = int32_t long_math
|
||||
*/
|
||||
|
||||
unpack_decorr_mono_pass_cont_armv7:
|
||||
|
||||
stmfd sp!, {r4 - r8, r11, lr}
|
||||
|
||||
mov r5, r0 @ r5 = dpp
|
||||
mov r11, #512 @ r11 = 512 for rounding
|
||||
ldr r6, [r0, #4] @ r6 = dpp->delta
|
||||
ldr r4, [r0, #8] @ r4 = dpp->weight_A
|
||||
cmp r2, #0 @ exit if no samples to process
|
||||
beq mono_common_exit
|
||||
|
||||
add r7, r1, r2, asl #2 @ r7 = buffer ending position
|
||||
ldr r2, [r5, #0] @ r2 = dpp->term
|
||||
|
||||
ldr lr, [r1, #-8] @ load 2 sample history from buffer
|
||||
ldr r8, [r1, #-4]
|
||||
cmp r2, #17
|
||||
beq mono_term_17_loop
|
||||
cmp r2, #18
|
||||
beq mono_term_18_loop
|
||||
cmp r2, #2
|
||||
beq mono_term_2_loop
|
||||
b mono_term_default_loop @ else handle default (1-8, except 2)
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle term = 17 condition
|
||||
*
|
||||
* r0 = r8 = previous sample
|
||||
* r1 = bptr r9 =
|
||||
* r2 = current sample r10 =
|
||||
* r3 = r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = current decorrelation value
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr = second previous sample
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
mono_term_17_loop:
|
||||
rsb ip, lr, r8, asl #1 @ decorr value = (2 * prev) - 2nd prev
|
||||
mov lr, r8 @ previous becomes 2nd previous
|
||||
ldr r2, [r1], #4 @ get sample & update pointer
|
||||
mov r8, ip, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp ip, r8, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S717
|
||||
cmp ip, #0
|
||||
mla r8, ip, r4, r11 @ mult decorr value by weight, round,
|
||||
add r8, r2, r8, asr #10 @ shift, and add to new sample
|
||||
b S718
|
||||
|
||||
S717: mov r8, #0
|
||||
smlal r11, r8, r4, ip
|
||||
add r8, r2, r8, lsl #22
|
||||
add r8, r8, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S718: strne r8, [r1, #-4] @ if change possible, store sample back
|
||||
cmpne r2, #0
|
||||
beq S129
|
||||
teq ip, r2 @ update weight based on signs
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
|
||||
S129: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi mono_term_17_loop
|
||||
b mono_store_1718 @ common exit for terms 17 & 18
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle term = 18 condition
|
||||
*
|
||||
* r0 = r8 = previous sample
|
||||
* r1 = bptr r9 =
|
||||
* r2 = current sample r10 =
|
||||
* r3 = r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = decorrelation value
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr = second previous sample
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
mono_term_18_loop:
|
||||
sub ip, r8, lr @ decorr value =
|
||||
mov lr, r8 @ ((3 * prev) - 2nd prev) >> 1
|
||||
add ip, r8, ip, asr #1
|
||||
ldr r2, [r1], #4 @ get sample & update pointer
|
||||
mov r8, ip, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp ip, r8, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S817
|
||||
cmp ip, #0
|
||||
mla r8, ip, r4, r11 @ mult decorr value by weight, round,
|
||||
add r8, r2, r8, asr #10 @ shift, and add to new sample
|
||||
b S818
|
||||
|
||||
S817: mov r8, #0
|
||||
smlal r11, r8, r4, ip
|
||||
add r8, r2, r8, lsl #22
|
||||
add r8, r8, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S818: strne r8, [r1, #-4] @ if change possible, store sample back
|
||||
cmpne r2, #0
|
||||
beq S141
|
||||
teq ip, r2 @ update weight based on signs
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
|
||||
S141: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi mono_term_18_loop
|
||||
|
||||
/* common exit for terms 17 & 18 */
|
||||
|
||||
mono_store_1718:
|
||||
str r8, [r5, #16] @ store sample history into struct
|
||||
str lr, [r5, #20]
|
||||
b mono_common_exit @ and return
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle term = 2 condition
|
||||
* (note that this case can be handled by the default term handler (1-8), but
|
||||
* this special case is faster because it doesn't have to read memory twice)
|
||||
*
|
||||
* r0 = r8 = previous sample
|
||||
* r1 = bptr r9 =
|
||||
* r2 = current sample r10 =
|
||||
* r3 = r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = decorrelation value
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr = second previous sample
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
mono_term_2_loop:
|
||||
mov ip, lr @ get decorrelation value
|
||||
mov lr, r8 @ previous becomes 2nd previous
|
||||
ldr r2, [r1], #4 @ get sample & update pointer
|
||||
mov r8, ip, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp ip, r8, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S917
|
||||
cmp ip, #0
|
||||
mla r8, ip, r4, r11 @ mult decorr value by weight, round,
|
||||
add r8, r2, r8, asr #10 @ shift, and add to new sample
|
||||
b S918
|
||||
|
||||
S917: mov r8, #0
|
||||
smlal r11, r8, r4, ip
|
||||
add r8, r2, r8, lsl #22
|
||||
add r8, r8, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S918: strne r8, [r1, #-4] @ if change possible, store sample back
|
||||
cmpne r2, #0
|
||||
beq S029
|
||||
teq ip, r2 @ update weight based on signs
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
|
||||
S029: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi mono_term_2_loop
|
||||
b mono_default_term_exit @ this exit updates all dpp->samples
|
||||
|
||||
/*
|
||||
******************************************************************************
|
||||
* Loop to handle default term condition
|
||||
*
|
||||
* r0 = r8 = result accumulator
|
||||
* r1 = bptr r9 =
|
||||
* r2 = dpp->term r10 =
|
||||
* r3 = decorrelation value r11 = 512 (for rounding)
|
||||
* r4 = dpp->weight_A ip = current sample
|
||||
* r5 = dpp sp =
|
||||
* r6 = dpp->delta lr =
|
||||
* r7 = eptr pc =
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
||||
mono_term_default_loop:
|
||||
ldr ip, [r1] @ get original sample
|
||||
ldr r3, [r1, -r2, asl #2] @ get decorrelation value based on term
|
||||
mov r8, r3, lsl #11 @ check magnitude by shifting left then right
|
||||
cmp r3, r8, asr #11 @ and comparing, branch to 64-bit math if different
|
||||
bne S617
|
||||
mla r8, r3, r4, r11 @ mult decorr value by weight, round,
|
||||
add r8, ip, r8, asr #10 @ shift and add to new sample
|
||||
b S618
|
||||
|
||||
S617: mov r8, #0
|
||||
smlal r11, r8, r4, r3
|
||||
add r8, ip, r8, lsl #22
|
||||
add r8, r8, r11, lsr #10
|
||||
mov r11, #512
|
||||
|
||||
S618: str r8, [r1], #4 @ store update sample
|
||||
cmp r3, #0
|
||||
cmpne ip, #0
|
||||
beq S154
|
||||
teq ip, r3 @ update weight based on signs
|
||||
submi r4, r4, r6
|
||||
addpl r4, r4, r6
|
||||
|
||||
S154: cmp r7, r1 @ loop back if more samples to do
|
||||
bhi mono_term_default_loop
|
||||
|
||||
/*
|
||||
* This exit is used by terms 1-8 to store the previous "term" samples (up to 8)
|
||||
* into the decorr pass structure history
|
||||
*/
|
||||
|
||||
mono_default_term_exit:
|
||||
ldr r2, [r5, #0] @ r2 = dpp->term
|
||||
|
||||
S158: sub r2, r2, #1
|
||||
sub r1, r1, #4
|
||||
ldr r3, [r1, #0] @ get sample and store in dpp->samples_A [r2]
|
||||
add r6, r5, #16
|
||||
str r3, [r6, r2, asl #2]
|
||||
cmp r2, #0
|
||||
bne S158
|
||||
b mono_common_exit
|
||||
|
||||
/*
|
||||
* Before finally exiting we must store weight back for next time
|
||||
*/
|
||||
|
||||
mono_common_exit:
|
||||
str r4, [r5, #8]
|
||||
ldmfd sp!, {r4 - r8, r11, pc}
|
||||
|
||||
#ifdef __ELF__
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,616 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** DSDPACK **** //
|
||||
// Lossless DSD (Direct Stream Digital) Audio Compressor //
|
||||
// Copyright (c) 2013 - 2016 David Bryant. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack_dsd.c
|
||||
|
||||
// This module actually handles the uncompression of the DSD audio data.
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// This function initialzes the main range-encoded data for DSD audio samples
|
||||
|
||||
static int init_dsd_block_fast (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
static int init_dsd_block_high (WavpackStream *wps, WavpackMetadata *wpmd);
|
||||
static int decode_fast (WavpackStream *wps, int32_t *output, int sample_count);
|
||||
static int decode_high (WavpackStream *wps, int32_t *output, int sample_count);
|
||||
|
||||
int init_dsd_block (WavpackContext *wpc, WavpackMetadata *wpmd)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
|
||||
if (wpmd->byte_length < 2)
|
||||
return FALSE;
|
||||
|
||||
wps->dsd.byteptr = (unsigned char *)wpmd->data;
|
||||
wps->dsd.endptr = wps->dsd.byteptr + wpmd->byte_length;
|
||||
wpc->dsd_multiplier = 1 << *wps->dsd.byteptr++;
|
||||
wps->dsd.mode = *wps->dsd.byteptr++;
|
||||
|
||||
if (!wps->dsd.mode) {
|
||||
if (wps->dsd.endptr - wps->dsd.byteptr != wps->wphdr.block_samples * (wps->wphdr.flags & MONO_DATA ? 1 : 2)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wps->dsd.ready = 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (wps->dsd.mode == 1)
|
||||
return init_dsd_block_fast (wps, wpmd);
|
||||
else if (wps->dsd.mode == 3)
|
||||
return init_dsd_block_high (wps, wpmd);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int32_t unpack_dsd_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
uint32_t flags = wps->wphdr.flags;
|
||||
|
||||
// don't attempt to decode past the end of the block, but watch out for overflow!
|
||||
|
||||
if (wps->sample_index + sample_count > GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples &&
|
||||
GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index < sample_count)
|
||||
sample_count = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index);
|
||||
|
||||
if (GET_BLOCK_INDEX (wps->wphdr) > wps->sample_index || wps->wphdr.block_samples < sample_count)
|
||||
wps->mute_error = TRUE;
|
||||
|
||||
if (!wps->mute_error) {
|
||||
if (!wps->dsd.mode) {
|
||||
int total_samples = sample_count * ((flags & MONO_DATA) ? 1 : 2);
|
||||
int32_t *bptr = buffer;
|
||||
|
||||
if (wps->dsd.endptr - wps->dsd.byteptr < total_samples)
|
||||
total_samples = (int)(wps->dsd.endptr - wps->dsd.byteptr);
|
||||
|
||||
while (total_samples--)
|
||||
wps->crc += (wps->crc << 1) + (*bptr++ = *wps->dsd.byteptr++);
|
||||
}
|
||||
else if (wps->dsd.mode == 1) {
|
||||
if (!decode_fast (wps, buffer, sample_count))
|
||||
wps->mute_error = TRUE;
|
||||
}
|
||||
else if (!decode_high (wps, buffer, sample_count))
|
||||
wps->mute_error = TRUE;
|
||||
}
|
||||
|
||||
if (wps->mute_error) {
|
||||
int samples_to_null;
|
||||
if (wpc->reduced_channels == 1 || wpc->config.num_channels == 1 || (flags & MONO_FLAG))
|
||||
samples_to_null = sample_count;
|
||||
else
|
||||
samples_to_null = sample_count * 2;
|
||||
|
||||
while (samples_to_null--)
|
||||
*buffer++ = 0x55;
|
||||
|
||||
wps->sample_index += sample_count;
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
if (flags & FALSE_STEREO) {
|
||||
int32_t *dptr = buffer + sample_count * 2;
|
||||
int32_t *sptr = buffer + sample_count;
|
||||
int32_t c = sample_count;
|
||||
|
||||
while (c--) {
|
||||
*--dptr = *--sptr;
|
||||
*--dptr = *sptr;
|
||||
}
|
||||
}
|
||||
|
||||
wps->sample_index += sample_count;
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
// #define DSD_BYTE_READY(low,high) (((low) >> 24) == ((high) >> 24))
|
||||
// #define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) >> 24))
|
||||
#define DSD_BYTE_READY(low,high) (!(((low) ^ (high)) & 0xff000000))
|
||||
#define MAX_HISTORY_BITS 5
|
||||
|
||||
static int init_dsd_block_fast (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char history_bits, max_probability;
|
||||
int total_summed_probabilities = 0, i;
|
||||
|
||||
if (wps->dsd.byteptr == wps->dsd.endptr)
|
||||
return FALSE;
|
||||
|
||||
history_bits = *wps->dsd.byteptr++;
|
||||
|
||||
if (wps->dsd.byteptr == wps->dsd.endptr || history_bits > MAX_HISTORY_BITS)
|
||||
return FALSE;
|
||||
|
||||
wps->dsd.history_bins = 1 << history_bits;
|
||||
|
||||
wps->dsd.value_lookup = (unsigned char **)malloc (sizeof (*wps->dsd.value_lookup) * wps->dsd.history_bins);
|
||||
memset (wps->dsd.value_lookup, 0, sizeof (*wps->dsd.value_lookup) * wps->dsd.history_bins);
|
||||
wps->dsd.summed_probabilities = (int16_t (*)[256])malloc (sizeof (*wps->dsd.summed_probabilities) * wps->dsd.history_bins);
|
||||
wps->dsd.probabilities = (unsigned char (*)[256])malloc (sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins);
|
||||
|
||||
max_probability = *wps->dsd.byteptr++;
|
||||
|
||||
if (max_probability < 0xff) {
|
||||
unsigned char *outptr = (unsigned char *) wps->dsd.probabilities;
|
||||
unsigned char *outend = outptr + sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins;
|
||||
|
||||
while (outptr < outend && wps->dsd.byteptr < wps->dsd.endptr) {
|
||||
int code = *wps->dsd.byteptr++;
|
||||
|
||||
if (code > max_probability) {
|
||||
int zcount = code - max_probability;
|
||||
|
||||
while (outptr < outend && zcount--)
|
||||
*outptr++ = 0;
|
||||
}
|
||||
else if (code)
|
||||
*outptr++ = code;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (outptr < outend || (wps->dsd.byteptr < wps->dsd.endptr && *wps->dsd.byteptr++))
|
||||
return FALSE;
|
||||
}
|
||||
else if (wps->dsd.endptr - wps->dsd.byteptr > (int) sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins) {
|
||||
memcpy (wps->dsd.probabilities, wps->dsd.byteptr, sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins);
|
||||
wps->dsd.byteptr += sizeof (*wps->dsd.probabilities) * wps->dsd.history_bins;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
for (wps->dsd.p0 = 0; wps->dsd.p0 < wps->dsd.history_bins; ++wps->dsd.p0) {
|
||||
int32_t sum_values;
|
||||
unsigned char *vp;
|
||||
|
||||
for (sum_values = i = 0; i < 256; ++i)
|
||||
wps->dsd.summed_probabilities [wps->dsd.p0] [i] = sum_values += wps->dsd.probabilities [wps->dsd.p0] [i];
|
||||
|
||||
if (sum_values) {
|
||||
total_summed_probabilities += sum_values;
|
||||
vp = wps->dsd.value_lookup [wps->dsd.p0] = (unsigned char *)malloc (sum_values);
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
int c = wps->dsd.probabilities [wps->dsd.p0] [i];
|
||||
|
||||
while (c--)
|
||||
*vp++ = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wps->dsd.endptr - wps->dsd.byteptr < 4 || total_summed_probabilities > wps->dsd.history_bins * 1280)
|
||||
return FALSE;
|
||||
|
||||
for (i = 4; i--;)
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
|
||||
wps->dsd.p0 = wps->dsd.p1 = 0;
|
||||
wps->dsd.low = 0; wps->dsd.high = 0xffffffff;
|
||||
wps->dsd.ready = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int decode_fast (WavpackStream *wps, int32_t *output, int sample_count)
|
||||
{
|
||||
int total_samples = sample_count;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
total_samples *= 2;
|
||||
|
||||
while (total_samples--) {
|
||||
int mult, index, code, i;
|
||||
|
||||
if (!wps->dsd.summed_probabilities [wps->dsd.p0] [255])
|
||||
return 0;
|
||||
|
||||
mult = (wps->dsd.high - wps->dsd.low) / wps->dsd.summed_probabilities [wps->dsd.p0] [255];
|
||||
|
||||
if (!mult) {
|
||||
if (wps->dsd.endptr - wps->dsd.byteptr >= 4)
|
||||
for (i = 4; i--;)
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
|
||||
wps->dsd.low = 0;
|
||||
wps->dsd.high = 0xffffffff;
|
||||
mult = wps->dsd.high / wps->dsd.summed_probabilities [wps->dsd.p0] [255];
|
||||
|
||||
if (!mult)
|
||||
return 0;
|
||||
}
|
||||
|
||||
index = (wps->dsd.value - wps->dsd.low) / mult;
|
||||
|
||||
if (index >= wps->dsd.summed_probabilities [wps->dsd.p0] [255])
|
||||
return 0;
|
||||
|
||||
if ((*output++ = code = wps->dsd.value_lookup [wps->dsd.p0] [index]))
|
||||
wps->dsd.low += wps->dsd.summed_probabilities [wps->dsd.p0] [code-1] * mult;
|
||||
|
||||
wps->dsd.high = wps->dsd.low + wps->dsd.probabilities [wps->dsd.p0] [code] * mult - 1;
|
||||
wps->crc += (wps->crc << 1) + code;
|
||||
|
||||
if (wps->wphdr.flags & MONO_DATA)
|
||||
wps->dsd.p0 = code & (wps->dsd.history_bins-1);
|
||||
else {
|
||||
wps->dsd.p0 = wps->dsd.p1;
|
||||
wps->dsd.p1 = code & (wps->dsd.history_bins-1);
|
||||
}
|
||||
|
||||
while (DSD_BYTE_READY (wps->dsd.high, wps->dsd.low) && wps->dsd.byteptr < wps->dsd.endptr) {
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
wps->dsd.high = (wps->dsd.high << 8) | 0xff;
|
||||
wps->dsd.low <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#define PTABLE_BITS 8
|
||||
#define PTABLE_BINS (1<<PTABLE_BITS)
|
||||
#define PTABLE_MASK (PTABLE_BINS-1)
|
||||
|
||||
#define UP 0x010000fe
|
||||
#define DOWN 0x00010000
|
||||
#define DECAY 8
|
||||
|
||||
#define PRECISION 20
|
||||
#define VALUE_ONE (1 << PRECISION)
|
||||
#define PRECISION_USE 12
|
||||
|
||||
#define RATE_S 20
|
||||
|
||||
static void init_ptable (int *table, int rate_i, int rate_s)
|
||||
{
|
||||
int value = 0x808000, rate = rate_i << 8, c, i;
|
||||
|
||||
for (c = (rate + 128) >> 8; c--;)
|
||||
value += (DOWN - value) >> DECAY;
|
||||
|
||||
for (i = 0; i < PTABLE_BINS/2; ++i) {
|
||||
table [i] = value;
|
||||
table [PTABLE_BINS-1-i] = 0x100ffff - value;
|
||||
|
||||
if (value > 0x010000) {
|
||||
rate += (rate * rate_s + 128) >> 8;
|
||||
|
||||
for (c = (rate + 64) >> 7; c--;)
|
||||
value += (DOWN - value) >> DECAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int init_dsd_block_high (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
uint32_t flags = wps->wphdr.flags;
|
||||
int channel, rate_i, rate_s, i;
|
||||
|
||||
if (wps->dsd.endptr - wps->dsd.byteptr < ((flags & MONO_DATA) ? 13 : 20))
|
||||
return FALSE;
|
||||
|
||||
rate_i = *wps->dsd.byteptr++;
|
||||
rate_s = *wps->dsd.byteptr++;
|
||||
|
||||
if (rate_s != RATE_S)
|
||||
return FALSE;
|
||||
|
||||
wps->dsd.ptable = (int32_t *)malloc (PTABLE_BINS * sizeof (*wps->dsd.ptable));
|
||||
init_ptable (wps->dsd.ptable, rate_i, rate_s);
|
||||
|
||||
for (channel = 0; channel < ((flags & MONO_DATA) ? 1 : 2); ++channel) {
|
||||
DSDfilters *sp = wps->dsd.filters + channel;
|
||||
|
||||
sp->filter1 = *wps->dsd.byteptr++ << (PRECISION - 8);
|
||||
sp->filter2 = *wps->dsd.byteptr++ << (PRECISION - 8);
|
||||
sp->filter3 = *wps->dsd.byteptr++ << (PRECISION - 8);
|
||||
sp->filter4 = *wps->dsd.byteptr++ << (PRECISION - 8);
|
||||
sp->filter5 = *wps->dsd.byteptr++ << (PRECISION - 8);
|
||||
sp->filter6 = 0;
|
||||
sp->factor = *wps->dsd.byteptr++ & 0xff;
|
||||
sp->factor |= (*wps->dsd.byteptr++ << 8) & 0xff00;
|
||||
sp->factor = (sp->factor << 16) >> 16;
|
||||
}
|
||||
|
||||
wps->dsd.high = 0xffffffff;
|
||||
wps->dsd.low = 0x0;
|
||||
|
||||
for (i = 4; i--;)
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
|
||||
wps->dsd.ready = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int decode_high (WavpackStream *wps, int32_t *output, int sample_count)
|
||||
{
|
||||
int total_samples = sample_count, stereo = (wps->wphdr.flags & MONO_DATA) ? 0 : 1;
|
||||
DSDfilters *sp = wps->dsd.filters;
|
||||
|
||||
while (total_samples--) {
|
||||
int bitcount = 8;
|
||||
|
||||
sp [0].value = sp [0].filter1 - sp [0].filter5 + ((sp [0].filter6 * sp [0].factor) >> 2);
|
||||
|
||||
if (stereo)
|
||||
sp [1].value = sp [1].filter1 - sp [1].filter5 + ((sp [1].filter6 * sp [1].factor) >> 2);
|
||||
|
||||
while (bitcount--) {
|
||||
int32_t *pp = wps->dsd.ptable + ((sp [0].value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK);
|
||||
uint32_t split = wps->dsd.low + ((wps->dsd.high - wps->dsd.low) >> 8) * (*pp >> 16);
|
||||
|
||||
if (wps->dsd.value <= split) {
|
||||
wps->dsd.high = split;
|
||||
*pp += (UP - *pp) >> DECAY;
|
||||
sp [0].filter0 = -1;
|
||||
}
|
||||
else {
|
||||
wps->dsd.low = split + 1;
|
||||
*pp += (DOWN - *pp) >> DECAY;
|
||||
sp [0].filter0 = 0;
|
||||
}
|
||||
|
||||
while (DSD_BYTE_READY (wps->dsd.high, wps->dsd.low) && wps->dsd.byteptr < wps->dsd.endptr) {
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
wps->dsd.high = (wps->dsd.high << 8) | 0xff;
|
||||
wps->dsd.low <<= 8;
|
||||
}
|
||||
|
||||
sp [0].value += sp [0].filter6 << 3;
|
||||
sp [0].byte = (sp [0].byte << 1) | (sp [0].filter0 & 1);
|
||||
sp [0].factor += (((sp [0].value ^ sp [0].filter0) >> 31) | 1) & ((sp [0].value ^ (sp [0].value - (sp [0].filter6 << 4))) >> 31);
|
||||
sp [0].filter1 += ((sp [0].filter0 & VALUE_ONE) - sp [0].filter1) >> 6;
|
||||
sp [0].filter2 += ((sp [0].filter0 & VALUE_ONE) - sp [0].filter2) >> 4;
|
||||
sp [0].filter3 += (sp [0].filter2 - sp [0].filter3) >> 4;
|
||||
sp [0].filter4 += (sp [0].filter3 - sp [0].filter4) >> 4;
|
||||
sp [0].value = (sp [0].filter4 - sp [0].filter5) >> 4;
|
||||
sp [0].filter5 += sp [0].value;
|
||||
sp [0].filter6 += (sp [0].value - sp [0].filter6) >> 3;
|
||||
sp [0].value = sp [0].filter1 - sp [0].filter5 + ((sp [0].filter6 * sp [0].factor) >> 2);
|
||||
|
||||
if (!stereo)
|
||||
continue;
|
||||
|
||||
pp = wps->dsd.ptable + ((sp [1].value >> (PRECISION - PRECISION_USE)) & PTABLE_MASK);
|
||||
split = wps->dsd.low + ((wps->dsd.high - wps->dsd.low) >> 8) * (*pp >> 16);
|
||||
|
||||
if (wps->dsd.value <= split) {
|
||||
wps->dsd.high = split;
|
||||
*pp += (UP - *pp) >> DECAY;
|
||||
sp [1].filter0 = -1;
|
||||
}
|
||||
else {
|
||||
wps->dsd.low = split + 1;
|
||||
*pp += (DOWN - *pp) >> DECAY;
|
||||
sp [1].filter0 = 0;
|
||||
}
|
||||
|
||||
while (DSD_BYTE_READY (wps->dsd.high, wps->dsd.low) && wps->dsd.byteptr < wps->dsd.endptr) {
|
||||
wps->dsd.value = (wps->dsd.value << 8) | *wps->dsd.byteptr++;
|
||||
wps->dsd.high = (wps->dsd.high << 8) | 0xff;
|
||||
wps->dsd.low <<= 8;
|
||||
}
|
||||
|
||||
sp [1].value += sp [1].filter6 << 3;
|
||||
sp [1].byte = (sp [1].byte << 1) | (sp [1].filter0 & 1);
|
||||
sp [1].factor += (((sp [1].value ^ sp [1].filter0) >> 31) | 1) & ((sp [1].value ^ (sp [1].value - (sp [1].filter6 << 4))) >> 31);
|
||||
sp [1].filter1 += ((sp [1].filter0 & VALUE_ONE) - sp [1].filter1) >> 6;
|
||||
sp [1].filter2 += ((sp [1].filter0 & VALUE_ONE) - sp [1].filter2) >> 4;
|
||||
sp [1].filter3 += (sp [1].filter2 - sp [1].filter3) >> 4;
|
||||
sp [1].filter4 += (sp [1].filter3 - sp [1].filter4) >> 4;
|
||||
sp [1].value = (sp [1].filter4 - sp [1].filter5) >> 4;
|
||||
sp [1].filter5 += sp [1].value;
|
||||
sp [1].filter6 += (sp [1].value - sp [1].filter6) >> 3;
|
||||
sp [1].value = sp [1].filter1 - sp [1].filter5 + ((sp [1].filter6 * sp [1].factor) >> 2);
|
||||
}
|
||||
|
||||
wps->crc += (wps->crc << 1) + (*output++ = sp [0].byte & 0xff);
|
||||
sp [0].factor -= (sp [0].factor + 512) >> 10;
|
||||
|
||||
if (stereo) {
|
||||
wps->crc += (wps->crc << 1) + (*output++ = wps->dsd.filters [1].byte & 0xff);
|
||||
wps->dsd.filters [1].factor -= (wps->dsd.filters [1].factor + 512) >> 10;
|
||||
}
|
||||
}
|
||||
|
||||
return sample_count;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
#if 0
|
||||
|
||||
// 80 term DSD decimation filter
|
||||
// < 1 dB down at 20 kHz
|
||||
// > 108 dB stopband attenuation (fs/16)
|
||||
|
||||
static const int32_t decm_filter [] = {
|
||||
4, 17, 56, 147, 336, 693, 1320, 2359,
|
||||
4003, 6502, 10170, 15392, 22623, 32389, 45275, 61920,
|
||||
82994, 109174, 141119, 179431, 224621, 277068, 336983, 404373,
|
||||
479004, 560384, 647741, 740025, 835917, 933849, 1032042, 1128551,
|
||||
1221329, 1308290, 1387386, 1456680, 1514425, 1559128, 1589610, 1605059,
|
||||
1605059, 1589610, 1559128, 1514425, 1456680, 1387386, 1308290, 1221329,
|
||||
1128551, 1032042, 933849, 835917, 740025, 647741, 560384, 479004,
|
||||
404373, 336983, 277068, 224621, 179431, 141119, 109174, 82994,
|
||||
61920, 45275, 32389, 22623, 15392, 10170, 6502, 4003,
|
||||
2359, 1320, 693, 336, 147, 56, 17, 4,
|
||||
};
|
||||
|
||||
#define NUM_FILTER_TERMS 80
|
||||
|
||||
#else
|
||||
|
||||
// 56 term decimation filter
|
||||
// < 0.5 dB down at 20 kHz
|
||||
// > 100 dB stopband attenuation (fs/12)
|
||||
|
||||
static const int32_t decm_filter [] = {
|
||||
4, 17, 56, 147, 336, 692, 1315, 2337,
|
||||
3926, 6281, 9631, 14216, 20275, 28021, 37619, 49155,
|
||||
62616, 77870, 94649, 112551, 131049, 149507, 167220, 183448,
|
||||
197472, 208636, 216402, 220385, 220385, 216402, 208636, 197472,
|
||||
183448, 167220, 149507, 131049, 112551, 94649, 77870, 62616,
|
||||
49155, 37619, 28021, 20275, 14216, 9631, 6281, 3926,
|
||||
2337, 1315, 692, 336, 147, 56, 17, 4,
|
||||
};
|
||||
|
||||
#define NUM_FILTER_TERMS 56
|
||||
|
||||
#endif
|
||||
|
||||
#define HISTORY_BYTES ((NUM_FILTER_TERMS+7)/8)
|
||||
|
||||
typedef struct {
|
||||
unsigned char delay [HISTORY_BYTES];
|
||||
} DecimationChannel;
|
||||
|
||||
typedef struct {
|
||||
int32_t conv_tables [HISTORY_BYTES] [256];
|
||||
DecimationChannel *chans;
|
||||
int num_channels;
|
||||
} DecimationContext;
|
||||
|
||||
void *decimate_dsd_init (int num_channels)
|
||||
{
|
||||
DecimationContext *context = (DecimationContext *)malloc (sizeof (DecimationContext));
|
||||
double filter_sum = 0, filter_scale;
|
||||
int skipped_terms, i, j;
|
||||
|
||||
if (!context)
|
||||
return context;
|
||||
|
||||
memset (context, 0, sizeof (*context));
|
||||
context->num_channels = num_channels;
|
||||
context->chans = (DecimationChannel *)malloc (num_channels * sizeof (DecimationChannel));
|
||||
|
||||
if (!context->chans) {
|
||||
free (context);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_FILTER_TERMS; ++i)
|
||||
filter_sum += decm_filter [i];
|
||||
|
||||
filter_scale = ((1 << 23) - 1) / filter_sum * 16.0;
|
||||
// fprintf (stderr, "convolution, %d terms, %f sum, %f scale\n", NUM_FILTER_TERMS, filter_sum, filter_scale);
|
||||
|
||||
for (skipped_terms = i = 0; i < NUM_FILTER_TERMS; ++i) {
|
||||
int scaled_term = (int) floor (decm_filter [i] * filter_scale + 0.5);
|
||||
|
||||
if (scaled_term) {
|
||||
for (j = 0; j < 256; ++j)
|
||||
if (j & (0x80 >> (i & 0x7)))
|
||||
context->conv_tables [i >> 3] [j] += scaled_term;
|
||||
else
|
||||
context->conv_tables [i >> 3] [j] -= scaled_term;
|
||||
}
|
||||
else
|
||||
skipped_terms++;
|
||||
}
|
||||
|
||||
// fprintf (stderr, "%d terms skipped\n", skipped_terms);
|
||||
|
||||
decimate_dsd_reset (context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void decimate_dsd_reset (void *decimate_context)
|
||||
{
|
||||
DecimationContext *context = (DecimationContext *) decimate_context;
|
||||
int chan = 0, i;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
for (chan = 0; chan < context->num_channels; ++chan)
|
||||
for (i = 0; i < HISTORY_BYTES; ++i)
|
||||
context->chans [chan].delay [i] = 0x55;
|
||||
}
|
||||
|
||||
void decimate_dsd_run (void *decimate_context, int32_t *samples, int num_samples)
|
||||
{
|
||||
DecimationContext *context = (DecimationContext *) decimate_context;
|
||||
int chan = 0;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
while (num_samples) {
|
||||
DecimationChannel *sp = context->chans + chan;
|
||||
int sum = 0;
|
||||
|
||||
#if (HISTORY_BYTES == 10)
|
||||
sum += context->conv_tables [0] [sp->delay [0] = sp->delay [1]];
|
||||
sum += context->conv_tables [1] [sp->delay [1] = sp->delay [2]];
|
||||
sum += context->conv_tables [2] [sp->delay [2] = sp->delay [3]];
|
||||
sum += context->conv_tables [3] [sp->delay [3] = sp->delay [4]];
|
||||
sum += context->conv_tables [4] [sp->delay [4] = sp->delay [5]];
|
||||
sum += context->conv_tables [5] [sp->delay [5] = sp->delay [6]];
|
||||
sum += context->conv_tables [6] [sp->delay [6] = sp->delay [7]];
|
||||
sum += context->conv_tables [7] [sp->delay [7] = sp->delay [8]];
|
||||
sum += context->conv_tables [8] [sp->delay [8] = sp->delay [9]];
|
||||
sum += context->conv_tables [9] [sp->delay [9] = *samples];
|
||||
#elif (HISTORY_BYTES == 7)
|
||||
sum += context->conv_tables [0] [sp->delay [0] = sp->delay [1]];
|
||||
sum += context->conv_tables [1] [sp->delay [1] = sp->delay [2]];
|
||||
sum += context->conv_tables [2] [sp->delay [2] = sp->delay [3]];
|
||||
sum += context->conv_tables [3] [sp->delay [3] = sp->delay [4]];
|
||||
sum += context->conv_tables [4] [sp->delay [4] = sp->delay [5]];
|
||||
sum += context->conv_tables [5] [sp->delay [5] = sp->delay [6]];
|
||||
sum += context->conv_tables [6] [sp->delay [6] = *samples];
|
||||
#else
|
||||
int i;
|
||||
|
||||
for (i = 0; i < HISTORY_BYTES-1; ++i)
|
||||
sum += context->conv_tables [i] [sp->delay [i] = sp->delay [i+1]];
|
||||
|
||||
sum += context->conv_tables [i] [sp->delay [i] = *samples];
|
||||
#endif
|
||||
|
||||
*samples++ = sum >> 4;
|
||||
|
||||
if (++chan == context->num_channels) {
|
||||
num_samples--;
|
||||
chan = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decimate_dsd_destroy (void *decimate_context)
|
||||
{
|
||||
DecimationContext *context = (DecimationContext *) decimate_context;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
if (context->chans)
|
||||
free (context->chans);
|
||||
|
||||
free (context);
|
||||
}
|
||||
|
||||
#endif // ENABLE_DSD
|
||||
@ -0,0 +1,134 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack_floats.c
|
||||
|
||||
// This module deals with the restoration of floating-point data. Note that no
|
||||
// floating point math is involved here...the values are only processed with
|
||||
// the macros that directly access the mantissa, exponent, and sign fields.
|
||||
// That's why we use the f32 type instead of the built-in float type.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
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;
|
||||
uint32_t temp;
|
||||
|
||||
if (*values == 0) {
|
||||
if (wps->float_flags & FLOAT_ZEROS_SENT) {
|
||||
if (getbit (&wps->wvxbits)) {
|
||||
getbits (&temp, 23, &wps->wvxbits);
|
||||
set_mantissa (outval, temp);
|
||||
|
||||
if (exp >= 25) {
|
||||
getbits (&temp, 8, &wps->wvxbits);
|
||||
set_exponent (outval, temp);
|
||||
}
|
||||
|
||||
set_sign (outval, getbit (&wps->wvxbits));
|
||||
}
|
||||
else if (wps->float_flags & FLOAT_NEG_ZEROS)
|
||||
set_sign (outval, getbit (&wps->wvxbits));
|
||||
}
|
||||
}
|
||||
else {
|
||||
*values <<= wps->float_shift;
|
||||
|
||||
if (*values < 0) {
|
||||
*values = -*values;
|
||||
set_sign (outval, 1);
|
||||
}
|
||||
|
||||
if (*values == 0x1000000) {
|
||||
if (getbit (&wps->wvxbits)) {
|
||||
getbits (&temp, 23, &wps->wvxbits);
|
||||
set_mantissa (outval, temp);
|
||||
}
|
||||
|
||||
set_exponent (outval, 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);
|
||||
}
|
||||
}
|
||||
|
||||
set_mantissa (outval, *values);
|
||||
set_exponent (outval, exp);
|
||||
}
|
||||
}
|
||||
|
||||
crc = crc * 27 + get_mantissa (outval) * 9 + get_exponent (outval) * 3 + get_sign (outval);
|
||||
* (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;
|
||||
|
||||
if (*values) {
|
||||
*values <<= wps->float_shift;
|
||||
|
||||
if (*values < 0) {
|
||||
*values = -*values;
|
||||
set_sign (outval, 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);
|
||||
}
|
||||
|
||||
set_mantissa (outval, *values);
|
||||
set_exponent (outval, exp);
|
||||
}
|
||||
|
||||
* (f32 *) values++ = outval;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,375 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack_seek.c
|
||||
|
||||
// This module provides the high-level API for unpacking audio data from
|
||||
// a specific sample index (i.e., seeking).
|
||||
|
||||
#ifndef NO_SEEKING
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
static int64_t find_sample (WavpackContext *wpc, void *infile, int64_t header_pos, int64_t sample);
|
||||
|
||||
// Seek to the specifed sample index, returning TRUE on success. Note that
|
||||
// files generated with version 4.0 or newer will seek almost immediately.
|
||||
// Older files can take quite long if required to seek through unplayed
|
||||
// portions of the file, but will create a seek map so that reverse seeks
|
||||
// (or forward seeks to already scanned areas) will be very fast. After a
|
||||
// FALSE return the file should not be accessed again (other than to close
|
||||
// it); this is a fatal error.
|
||||
|
||||
int WavpackSeekSample (WavpackContext *wpc, uint32_t sample)
|
||||
{
|
||||
return WavpackSeekSample64 (wpc, sample);
|
||||
}
|
||||
|
||||
int WavpackSeekSample64 (WavpackContext *wpc, int64_t sample)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams ? wpc->streams [wpc->current_stream = 0] : NULL;
|
||||
uint32_t bcount, samples_to_skip, samples_to_decode = 0;
|
||||
int32_t *buffer;
|
||||
|
||||
if (wpc->total_samples == -1 || sample >= wpc->total_samples ||
|
||||
!wpc->reader->can_seek (wpc->wv_in) || (wpc->open_flags & OPEN_STREAMING) ||
|
||||
(wpc->wvc_flag && !wpc->reader->can_seek (wpc->wvc_in)))
|
||||
return FALSE;
|
||||
|
||||
#ifdef ENABLE_LEGACY
|
||||
if (wpc->stream3)
|
||||
return seek_sample3 (wpc, (uint32_t) sample);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->decimation_context) { // the decimation code needs some context to be sample accurate
|
||||
if (sample < 16) {
|
||||
samples_to_decode = (uint32_t) sample;
|
||||
sample = 0;
|
||||
}
|
||||
else {
|
||||
samples_to_decode = 16;
|
||||
sample -= 16;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) || sample < GET_BLOCK_INDEX (wps->wphdr) ||
|
||||
sample >= GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples) {
|
||||
|
||||
free_streams (wpc);
|
||||
wpc->filepos = find_sample (wpc, wpc->wv_in, wpc->filepos, sample);
|
||||
|
||||
if (wpc->filepos == -1)
|
||||
return FALSE;
|
||||
|
||||
if (wpc->wvc_flag) {
|
||||
wpc->file2pos = find_sample (wpc, wpc->wvc_in, 0, sample);
|
||||
|
||||
if (wpc->file2pos == -1)
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!wps->blockbuff) {
|
||||
wpc->reader->set_pos_abs (wpc->wv_in, wpc->filepos);
|
||||
wpc->reader->read_bytes (wpc->wv_in, &wps->wphdr, sizeof (WavpackHeader));
|
||||
WavpackLittleEndianToNative (&wps->wphdr, WavpackHeaderFormat);
|
||||
wps->blockbuff = (unsigned char *)malloc (wps->wphdr.ckSize + 8);
|
||||
memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader));
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + sizeof (WavpackHeader), wps->wphdr.ckSize - 24) !=
|
||||
wps->wphdr.ckSize - 24) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// render corrupt blocks harmless
|
||||
if (!WavpackVerifySingleBlock (wps->blockbuff, !(wpc->open_flags & OPEN_NO_CHECKSUM))) {
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
wps->wphdr.block_samples = 0;
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
}
|
||||
|
||||
SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index);
|
||||
memcpy (wps->blockbuff, &wps->wphdr, sizeof (WavpackHeader));
|
||||
wps->init_done = FALSE;
|
||||
|
||||
if (wpc->wvc_flag) {
|
||||
wpc->reader->set_pos_abs (wpc->wvc_in, wpc->file2pos);
|
||||
wpc->reader->read_bytes (wpc->wvc_in, &wps->wphdr, sizeof (WavpackHeader));
|
||||
WavpackLittleEndianToNative (&wps->wphdr, WavpackHeaderFormat);
|
||||
wps->block2buff = (unsigned char *)malloc (wps->wphdr.ckSize + 8);
|
||||
memcpy (wps->block2buff, &wps->wphdr, sizeof (WavpackHeader));
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + sizeof (WavpackHeader), wps->wphdr.ckSize - 24) !=
|
||||
wps->wphdr.ckSize - 24) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// render corrupt blocks harmless
|
||||
if (!WavpackVerifySingleBlock (wps->block2buff, !(wpc->open_flags & OPEN_NO_CHECKSUM))) {
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
wps->wphdr.block_samples = 0;
|
||||
memcpy (wps->block2buff, &wps->wphdr, 32);
|
||||
}
|
||||
|
||||
SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index);
|
||||
memcpy (wps->block2buff, &wps->wphdr, sizeof (WavpackHeader));
|
||||
}
|
||||
|
||||
if (!wps->init_done && !unpack_init (wpc)) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wps->init_done = TRUE;
|
||||
}
|
||||
|
||||
while (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) {
|
||||
if (++wpc->current_stream == wpc->num_streams) {
|
||||
|
||||
if (wpc->num_streams == wpc->max_streams) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wpc->streams = (WavpackStream **)realloc (wpc->streams, (wpc->num_streams + 1) * sizeof (wpc->streams [0]));
|
||||
wps = wpc->streams [wpc->num_streams++] = (WavpackStream *)malloc (sizeof (WavpackStream));
|
||||
CLEAR (*wps);
|
||||
bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr);
|
||||
|
||||
if (bcount == (uint32_t) -1) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wps->blockbuff = (unsigned char *)malloc (wps->wphdr.ckSize + 8);
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) !=
|
||||
wps->wphdr.ckSize - 24) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// render corrupt blocks harmless
|
||||
if (!WavpackVerifySingleBlock (wps->blockbuff, !(wpc->open_flags & OPEN_NO_CHECKSUM))) {
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
wps->wphdr.block_samples = 0;
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
}
|
||||
|
||||
wps->init_done = FALSE;
|
||||
|
||||
if (wpc->wvc_flag && !read_wvc_block (wpc)) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!wps->init_done && !unpack_init (wpc)) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
wps->init_done = TRUE;
|
||||
}
|
||||
else
|
||||
wps = wpc->streams [wpc->current_stream];
|
||||
}
|
||||
|
||||
if (sample < wps->sample_index) {
|
||||
for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++)
|
||||
if (!unpack_init (wpc))
|
||||
return FALSE;
|
||||
else
|
||||
wpc->streams [wpc->current_stream]->init_done = TRUE;
|
||||
}
|
||||
|
||||
samples_to_skip = (uint32_t) (sample - wps->sample_index);
|
||||
|
||||
if (samples_to_skip > 131072) {
|
||||
free_streams (wpc);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (samples_to_skip) {
|
||||
buffer = (int32_t *)malloc (samples_to_skip * 8);
|
||||
|
||||
for (wpc->current_stream = 0; wpc->current_stream < wpc->num_streams; wpc->current_stream++)
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->streams [wpc->current_stream]->wphdr.flags & DSD_FLAG)
|
||||
unpack_dsd_samples (wpc, buffer, samples_to_skip);
|
||||
else
|
||||
#endif
|
||||
unpack_samples (wpc, buffer, samples_to_skip);
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
|
||||
wpc->current_stream = 0;
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->decimation_context)
|
||||
decimate_dsd_reset (wpc->decimation_context);
|
||||
|
||||
if (samples_to_decode) {
|
||||
buffer = (int32_t *)malloc (samples_to_decode * wpc->config.num_channels * 4);
|
||||
|
||||
if (buffer) {
|
||||
WavpackUnpackSamples (wpc, buffer, samples_to_decode);
|
||||
free (buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// Find a valid WavPack header, searching either from the current file position
|
||||
// (or from the specified position if not -1) and store it (endian corrected)
|
||||
// at the specified pointer. The return value is the exact file position of the
|
||||
// header, although we may have actually read past it. Because this function
|
||||
// is used for seeking to a specific audio sample, it only considers blocks
|
||||
// that contain audio samples for the initial stream to be valid.
|
||||
|
||||
#define BUFSIZE 4096
|
||||
|
||||
static int64_t find_header (WavpackStreamReader64 *reader, void *id, int64_t filepos, WavpackHeader *wphdr)
|
||||
{
|
||||
unsigned char *buffer = (unsigned char *)malloc (BUFSIZE), *sp = buffer, *ep = buffer;
|
||||
|
||||
if (filepos != (uint32_t) -1 && reader->set_pos_abs (id, filepos)) {
|
||||
free (buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int bleft;
|
||||
|
||||
if (sp < ep) {
|
||||
bleft = (int)(ep - sp);
|
||||
memcpy (buffer, sp, bleft);
|
||||
ep -= (sp - buffer);
|
||||
sp = buffer;
|
||||
}
|
||||
else {
|
||||
if (sp > ep)
|
||||
if (reader->set_pos_rel (id, (int32_t)(sp - ep), SEEK_CUR)) {
|
||||
free (buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sp = ep = buffer;
|
||||
bleft = 0;
|
||||
}
|
||||
|
||||
ep += reader->read_bytes (id, ep, BUFSIZE - bleft);
|
||||
|
||||
if (ep - sp < 32) {
|
||||
free (buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (sp + 32 <= ep)
|
||||
if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' &&
|
||||
!(*++sp & 1) && sp [2] < 16 && !sp [3] && (sp [2] || sp [1] || *sp >= 24) && sp [5] == 4 &&
|
||||
sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff) && sp [18] < 3 && !sp [19]) {
|
||||
memcpy (wphdr, sp - 4, sizeof (*wphdr));
|
||||
WavpackLittleEndianToNative (wphdr, WavpackHeaderFormat);
|
||||
|
||||
if (wphdr->block_samples && (wphdr->flags & INITIAL_BLOCK)) {
|
||||
free (buffer);
|
||||
return reader->get_pos (id) - (ep - sp + 4);
|
||||
}
|
||||
|
||||
if (wphdr->ckSize > 1024)
|
||||
sp += wphdr->ckSize - 1024;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find the WavPack block that contains the specified sample. If "header_pos"
|
||||
// is zero, then no information is assumed except the total number of samples
|
||||
// in the file and its size in bytes. If "header_pos" is non-zero then we
|
||||
// assume that it is the file position of the valid header image contained in
|
||||
// the first stream and we can limit our search to either the portion above
|
||||
// or below that point. If a .wvc file is being used, then this must be called
|
||||
// for that file also.
|
||||
|
||||
static int64_t find_sample (WavpackContext *wpc, void *infile, int64_t header_pos, int64_t sample)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams [wpc->current_stream];
|
||||
int64_t file_pos1 = 0, file_pos2 = wpc->reader->get_length (infile);
|
||||
int64_t sample_pos1 = 0, sample_pos2 = wpc->total_samples;
|
||||
double ratio = 0.96;
|
||||
int file_skip = 0;
|
||||
|
||||
if (sample >= wpc->total_samples)
|
||||
return -1;
|
||||
|
||||
if (header_pos && wps->wphdr.block_samples) {
|
||||
if (GET_BLOCK_INDEX (wps->wphdr) > sample) {
|
||||
sample_pos2 = GET_BLOCK_INDEX (wps->wphdr);
|
||||
file_pos2 = header_pos;
|
||||
}
|
||||
else if (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples <= sample) {
|
||||
sample_pos1 = GET_BLOCK_INDEX (wps->wphdr);
|
||||
file_pos1 = header_pos;
|
||||
}
|
||||
else
|
||||
return header_pos;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
double bytes_per_sample;
|
||||
int64_t seek_pos;
|
||||
|
||||
bytes_per_sample = (double) file_pos2 - file_pos1;
|
||||
bytes_per_sample /= sample_pos2 - sample_pos1;
|
||||
seek_pos = file_pos1 + (file_skip ? 32 : 0);
|
||||
seek_pos += (int64_t)(bytes_per_sample * (sample - sample_pos1) * ratio);
|
||||
seek_pos = find_header (wpc->reader, infile, seek_pos, &wps->wphdr);
|
||||
|
||||
if (seek_pos != (int64_t) -1)
|
||||
SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index);
|
||||
|
||||
if (seek_pos == (int64_t) -1 || seek_pos >= file_pos2) {
|
||||
if (ratio > 0.0) {
|
||||
if ((ratio -= 0.24) < 0.0)
|
||||
ratio = 0.0;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else if (GET_BLOCK_INDEX (wps->wphdr) > sample) {
|
||||
sample_pos2 = GET_BLOCK_INDEX (wps->wphdr);
|
||||
file_pos2 = seek_pos;
|
||||
}
|
||||
else if (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples <= sample) {
|
||||
|
||||
if (seek_pos == file_pos1)
|
||||
file_skip = 1;
|
||||
else {
|
||||
sample_pos1 = GET_BLOCK_INDEX (wps->wphdr);
|
||||
file_pos1 = seek_pos;
|
||||
}
|
||||
}
|
||||
else
|
||||
return seek_pos;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,411 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// unpack_utils.c
|
||||
|
||||
// This module provides the high-level API for unpacking audio data from
|
||||
// WavPack files. It manages the buffers used to interleave the data passed
|
||||
// back to the application from the individual streams. The actual audio
|
||||
// stream decompression is handled in the unpack.c module.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// Unpack the specified number of samples from the current file position.
|
||||
// Note that "samples" here refers to "complete" samples, which would be
|
||||
// 2 longs for stereo files or even more for multichannel files, so the
|
||||
// required memory at "buffer" is 4 * samples * num_channels bytes. The
|
||||
// audio data is returned right-justified in 32-bit longs in the endian
|
||||
// mode native to the executing processor. So, if the original data was
|
||||
// 16-bit, then the values returned would be +/-32k. Floating point data
|
||||
// can also be returned if the source was floating point data (and this
|
||||
// can be optionally normalized to +/-1.0 by using the appropriate flag
|
||||
// in the call to WavpackOpenFileInput ()). The actual number of samples
|
||||
// unpacked is returned, which should be equal to the number requested unless
|
||||
// the end of fle is encountered or an error occurs. After all samples have
|
||||
// been unpacked then 0 will be returned.
|
||||
|
||||
uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples)
|
||||
{
|
||||
WavpackStream *wps = wpc->streams ? wpc->streams [wpc->current_stream = 0] : NULL;
|
||||
int num_channels = wpc->config.num_channels, file_done = FALSE;
|
||||
uint32_t bcount, samples_unpacked = 0, samples_to_unpack;
|
||||
int32_t *bptr = buffer;
|
||||
|
||||
#ifdef ENABLE_LEGACY
|
||||
if (wpc->stream3)
|
||||
return unpack_samples3 (wpc, buffer, samples);
|
||||
#endif
|
||||
|
||||
while (samples) {
|
||||
|
||||
// if the current block has no audio, or it's not the first block of a multichannel
|
||||
// sequence, or the sample we're on is past the last sample in this block...we need
|
||||
// to free up the streams and read the next block
|
||||
|
||||
if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) ||
|
||||
wps->sample_index >= GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples) {
|
||||
|
||||
int64_t nexthdrpos;
|
||||
|
||||
if (wpc->wrapper_bytes >= MAX_WRAPPER_BYTES)
|
||||
break;
|
||||
|
||||
free_streams (wpc);
|
||||
nexthdrpos = wpc->reader->get_pos (wpc->wv_in);
|
||||
bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr);
|
||||
|
||||
if (bcount == (uint32_t) -1)
|
||||
break;
|
||||
|
||||
wpc->filepos = nexthdrpos + bcount;
|
||||
|
||||
// allocate the memory for the entire raw block and read it in
|
||||
|
||||
wps->blockbuff = (unsigned char *)malloc (wps->wphdr.ckSize + 8);
|
||||
|
||||
if (!wps->blockbuff)
|
||||
break;
|
||||
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) !=
|
||||
wps->wphdr.ckSize - 24) {
|
||||
strcpy (wpc->error_message, "can't read all of last block!");
|
||||
wps->wphdr.block_samples = 0;
|
||||
wps->wphdr.ckSize = 24;
|
||||
break;
|
||||
}
|
||||
|
||||
// render corrupt blocks harmless
|
||||
if (!WavpackVerifySingleBlock (wps->blockbuff, !(wpc->open_flags & OPEN_NO_CHECKSUM))) {
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
wps->wphdr.block_samples = 0;
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
}
|
||||
|
||||
// potentially adjusting block_index must be done AFTER verifying block
|
||||
|
||||
if (wpc->open_flags & OPEN_STREAMING)
|
||||
SET_BLOCK_INDEX (wps->wphdr, wps->sample_index = 0);
|
||||
else
|
||||
SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index);
|
||||
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
wps->init_done = FALSE; // we have not yet called unpack_init() for this block
|
||||
|
||||
// if this block has audio, but not the sample index we were expecting, flag an error
|
||||
|
||||
if (wps->wphdr.block_samples && wps->sample_index != GET_BLOCK_INDEX (wps->wphdr))
|
||||
wpc->crc_errors++;
|
||||
|
||||
// if this block has audio, and we're in hybrid lossless mode, read the matching wvc block
|
||||
|
||||
if (wps->wphdr.block_samples && wpc->wvc_flag)
|
||||
read_wvc_block (wpc);
|
||||
|
||||
// if the block does NOT have any audio, call unpack_init() to process non-audio stuff
|
||||
|
||||
if (!wps->wphdr.block_samples) {
|
||||
if (!wps->init_done && !unpack_init (wpc))
|
||||
wpc->crc_errors++;
|
||||
|
||||
wps->init_done = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// if the current block has no audio, or it's not the first block of a multichannel
|
||||
// sequence, or the sample we're on is past the last sample in this block...we need
|
||||
// to loop back and read the next block
|
||||
|
||||
if (!wps->wphdr.block_samples || !(wps->wphdr.flags & INITIAL_BLOCK) ||
|
||||
wps->sample_index >= GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples)
|
||||
continue;
|
||||
|
||||
// There seems to be some missing data, like a block was corrupted or something.
|
||||
// If it's not too much data, just fill in with silence here and loop back.
|
||||
|
||||
if (wps->sample_index < GET_BLOCK_INDEX (wps->wphdr)) {
|
||||
int32_t zvalue = (wps->wphdr.flags & DSD_FLAG) ? 0x55 : 0;
|
||||
|
||||
samples_to_unpack = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) - wps->sample_index);
|
||||
|
||||
if (!samples_to_unpack || samples_to_unpack > 262144) {
|
||||
strcpy (wpc->error_message, "discontinuity found, aborting file!");
|
||||
wps->wphdr.block_samples = 0;
|
||||
wps->wphdr.ckSize = 24;
|
||||
break;
|
||||
}
|
||||
|
||||
if (samples_to_unpack > samples)
|
||||
samples_to_unpack = samples;
|
||||
|
||||
wps->sample_index += samples_to_unpack;
|
||||
samples_unpacked += samples_to_unpack;
|
||||
samples -= samples_to_unpack;
|
||||
|
||||
samples_to_unpack *= (wpc->reduced_channels ? wpc->reduced_channels : num_channels);
|
||||
|
||||
while (samples_to_unpack--)
|
||||
*bptr++ = zvalue;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// calculate number of samples to process from this block, then initialize the decoder for
|
||||
// this block if we haven't already
|
||||
|
||||
samples_to_unpack = (uint32_t) (GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples - wps->sample_index);
|
||||
|
||||
if (samples_to_unpack > samples)
|
||||
samples_to_unpack = samples;
|
||||
|
||||
if (!wps->init_done && !unpack_init (wpc))
|
||||
wpc->crc_errors++;
|
||||
|
||||
wps->init_done = TRUE;
|
||||
|
||||
// if this block is not the final block of a multichannel sequence (and we're not truncating
|
||||
// to stereo), then enter this conditional block...otherwise we just unpack the samples directly
|
||||
|
||||
if (!wpc->reduced_channels && !(wps->wphdr.flags & FINAL_BLOCK)) {
|
||||
int32_t *temp_buffer = (int32_t *)malloc (samples_to_unpack * 8), *src, *dst;
|
||||
int offset = 0; // offset to next channel in sequence (0 to num_channels - 1)
|
||||
uint32_t samcnt;
|
||||
|
||||
// since we are getting samples from multiple bocks in a multichannel sequence, we must
|
||||
// allocate a temporary buffer to unpack to so that we can re-interleave the samples
|
||||
|
||||
if (!temp_buffer)
|
||||
break;
|
||||
|
||||
// loop through all the streams...
|
||||
|
||||
while (1) {
|
||||
|
||||
// if the stream has not been allocated and corresponding block read, do that here...
|
||||
|
||||
if (wpc->current_stream == wpc->num_streams) {
|
||||
wpc->streams = (WavpackStream **)realloc (wpc->streams, (wpc->num_streams + 1) * sizeof (wpc->streams [0]));
|
||||
|
||||
if (!wpc->streams)
|
||||
break;
|
||||
|
||||
wps = wpc->streams [wpc->num_streams++] = (WavpackStream *)malloc (sizeof (WavpackStream));
|
||||
|
||||
if (!wps)
|
||||
break;
|
||||
|
||||
CLEAR (*wps);
|
||||
bcount = read_next_header (wpc->reader, wpc->wv_in, &wps->wphdr);
|
||||
|
||||
if (bcount == (uint32_t) -1) {
|
||||
wpc->streams [0]->wphdr.block_samples = 0;
|
||||
wpc->streams [0]->wphdr.ckSize = 24;
|
||||
file_done = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
wps->blockbuff = (unsigned char *)malloc (wps->wphdr.ckSize + 8);
|
||||
|
||||
if (!wps->blockbuff)
|
||||
break;
|
||||
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
|
||||
if (wpc->reader->read_bytes (wpc->wv_in, wps->blockbuff + 32, wps->wphdr.ckSize - 24) !=
|
||||
wps->wphdr.ckSize - 24) {
|
||||
wpc->streams [0]->wphdr.block_samples = 0;
|
||||
wpc->streams [0]->wphdr.ckSize = 24;
|
||||
file_done = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
// render corrupt blocks harmless
|
||||
if (!WavpackVerifySingleBlock (wps->blockbuff, !(wpc->open_flags & OPEN_NO_CHECKSUM))) {
|
||||
wps->wphdr.ckSize = sizeof (WavpackHeader) - 8;
|
||||
wps->wphdr.block_samples = 0;
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
}
|
||||
|
||||
// potentially adjusting block_index must be done AFTER verifying block
|
||||
|
||||
if (wpc->open_flags & OPEN_STREAMING)
|
||||
SET_BLOCK_INDEX (wps->wphdr, wps->sample_index = 0);
|
||||
else
|
||||
SET_BLOCK_INDEX (wps->wphdr, GET_BLOCK_INDEX (wps->wphdr) - wpc->initial_index);
|
||||
|
||||
memcpy (wps->blockbuff, &wps->wphdr, 32);
|
||||
|
||||
// if this block has audio, and we're in hybrid lossless mode, read the matching wvc block
|
||||
|
||||
if (wpc->wvc_flag)
|
||||
read_wvc_block (wpc);
|
||||
|
||||
// initialize the unpacker for this block
|
||||
|
||||
if (!unpack_init (wpc))
|
||||
wpc->crc_errors++;
|
||||
|
||||
wps->init_done = TRUE;
|
||||
}
|
||||
else
|
||||
wps = wpc->streams [wpc->current_stream];
|
||||
|
||||
// unpack the correct number of samples (either mono or stereo) into the temp buffer
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wps->wphdr.flags & DSD_FLAG)
|
||||
unpack_dsd_samples (wpc, src = temp_buffer, samples_to_unpack);
|
||||
else
|
||||
#endif
|
||||
unpack_samples (wpc, src = temp_buffer, samples_to_unpack);
|
||||
|
||||
samcnt = samples_to_unpack;
|
||||
dst = bptr + offset;
|
||||
|
||||
// if the block is mono, copy the samples from the single channel into the destination
|
||||
// using num_channels as the stride
|
||||
|
||||
if (wps->wphdr.flags & MONO_FLAG) {
|
||||
while (samcnt--) {
|
||||
dst [0] = *src++;
|
||||
dst += num_channels;
|
||||
}
|
||||
|
||||
offset++;
|
||||
}
|
||||
|
||||
// if the block is stereo, and we don't have room for two more channels, just copy one
|
||||
// and flag an error
|
||||
|
||||
else if (offset == num_channels - 1) {
|
||||
while (samcnt--) {
|
||||
dst [0] = src [0];
|
||||
dst += num_channels;
|
||||
src += 2;
|
||||
}
|
||||
|
||||
wpc->crc_errors++;
|
||||
offset++;
|
||||
}
|
||||
|
||||
// otherwise copy the stereo samples into the destination
|
||||
|
||||
else {
|
||||
while (samcnt--) {
|
||||
dst [0] = *src++;
|
||||
dst [1] = *src++;
|
||||
dst += num_channels;
|
||||
}
|
||||
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
// check several clues that we're done with this set of blocks and exit if we are; else do next stream
|
||||
|
||||
if ((wps->wphdr.flags & FINAL_BLOCK) || wpc->current_stream == wpc->max_streams - 1 || offset == num_channels)
|
||||
break;
|
||||
else
|
||||
wpc->current_stream++;
|
||||
}
|
||||
|
||||
// if we didn't get all the channels we expected, mute the buffer and flag an error
|
||||
|
||||
if (offset != num_channels) {
|
||||
if (wps->wphdr.flags & DSD_FLAG) {
|
||||
int samples_to_zero = samples_to_unpack * num_channels;
|
||||
int32_t *zptr = bptr;
|
||||
|
||||
while (samples_to_zero--)
|
||||
*zptr++ = 0x55;
|
||||
}
|
||||
else
|
||||
memset (bptr, 0, samples_to_unpack * num_channels * 4);
|
||||
|
||||
wpc->crc_errors++;
|
||||
}
|
||||
|
||||
// go back to the first stream (we're going to leave them all loaded for now because they might have more samples)
|
||||
// and free the temp buffer
|
||||
|
||||
wps = wpc->streams [wpc->current_stream = 0];
|
||||
free (temp_buffer);
|
||||
}
|
||||
// catch the error situation where we have only one channel but run into a stereo block
|
||||
// (this avoids overwriting the caller's buffer)
|
||||
else if (!(wps->wphdr.flags & MONO_FLAG) && (num_channels == 1 || wpc->reduced_channels == 1)) {
|
||||
memset (bptr, 0, samples_to_unpack * sizeof (*bptr));
|
||||
wps->sample_index += samples_to_unpack;
|
||||
wpc->crc_errors++;
|
||||
}
|
||||
#ifdef ENABLE_DSD
|
||||
else if (wps->wphdr.flags & DSD_FLAG)
|
||||
unpack_dsd_samples (wpc, bptr, samples_to_unpack);
|
||||
#endif
|
||||
else
|
||||
unpack_samples (wpc, bptr, samples_to_unpack);
|
||||
|
||||
if (file_done) {
|
||||
strcpy (wpc->error_message, "can't read all of last block!");
|
||||
break;
|
||||
}
|
||||
|
||||
if (wpc->reduced_channels)
|
||||
bptr += samples_to_unpack * wpc->reduced_channels;
|
||||
else
|
||||
bptr += samples_to_unpack * num_channels;
|
||||
|
||||
samples_unpacked += samples_to_unpack;
|
||||
samples -= samples_to_unpack;
|
||||
|
||||
// if we just finished a block, check for a calculated crc error
|
||||
// (and back up the streams a little if possible in case we passed a header)
|
||||
|
||||
if (wps->sample_index == GET_BLOCK_INDEX (wps->wphdr) + wps->wphdr.block_samples) {
|
||||
if (check_crc_error (wpc)) {
|
||||
int32_t *zptr = bptr, zvalue = (wps->wphdr.flags & DSD_FLAG) ? 0x55 : 0;
|
||||
uint32_t samples_to_zero = wps->wphdr.block_samples;
|
||||
|
||||
if (samples_to_zero > samples_to_unpack)
|
||||
samples_to_zero = samples_to_unpack;
|
||||
|
||||
samples_to_zero *= (wpc->reduced_channels ? wpc->reduced_channels : num_channels);
|
||||
|
||||
while (samples_to_zero--)
|
||||
*--zptr = zvalue;
|
||||
|
||||
if (wps->blockbuff && wpc->reader->can_seek (wpc->wv_in)) {
|
||||
int32_t rseek = ((WavpackHeader *) wps->blockbuff)->ckSize / 3;
|
||||
wpc->reader->set_pos_rel (wpc->wv_in, (rseek > 16384) ? -16384 : -rseek, SEEK_CUR);
|
||||
}
|
||||
|
||||
if (wpc->wvc_flag && wps->block2buff && wpc->reader->can_seek (wpc->wvc_in)) {
|
||||
int32_t rseek = ((WavpackHeader *) wps->block2buff)->ckSize / 3;
|
||||
wpc->reader->set_pos_rel (wpc->wvc_in, (rseek > 16384) ? -16384 : -rseek, SEEK_CUR);
|
||||
}
|
||||
|
||||
wpc->crc_errors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (wpc->total_samples != -1 && wps->sample_index == wpc->total_samples)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DSD
|
||||
if (wpc->decimation_context)
|
||||
decimate_dsd_run (wpc->decimation_context, buffer, samples_unpacked);
|
||||
#endif
|
||||
|
||||
return samples_unpacked;
|
||||
}
|
||||
@ -0,0 +1,957 @@
|
||||
############################################################################
|
||||
## **** WAVPACK **** ##
|
||||
## Hybrid Lossless Wavefile Compressor ##
|
||||
## Copyright (c) 1998 - 2015 Conifer Software. ##
|
||||
## All Rights Reserved. ##
|
||||
## Distributed under the BSD Software License (see license.txt) ##
|
||||
############################################################################
|
||||
|
||||
.intel_syntax noprefix
|
||||
.text
|
||||
|
||||
.globl _unpack_decorr_stereo_pass_cont_x64win
|
||||
.globl _unpack_decorr_mono_pass_cont_x64win
|
||||
|
||||
.globl unpack_decorr_stereo_pass_cont_x64win
|
||||
.globl unpack_decorr_mono_pass_cont_x64win
|
||||
|
||||
.globl _unpack_decorr_stereo_pass_cont_x64
|
||||
.globl _unpack_decorr_mono_pass_cont_x64
|
||||
|
||||
.globl unpack_decorr_stereo_pass_cont_x64
|
||||
.globl unpack_decorr_mono_pass_cont_x64
|
||||
|
||||
# This is an assembly optimized version of the following WavPack function:
|
||||
#
|
||||
# void unpack_decorr_stereo_pass_cont (struct decorr_pass *dpp,
|
||||
# int32_t *buffer,
|
||||
# int32_t sample_count,
|
||||
# int32_t long_math;
|
||||
#
|
||||
# It performs a single pass of stereo decorrelation on the provided buffer.
|
||||
# Note that this version of the function requires that up to 8 previous
|
||||
# stereo samples are visible and correct. In other words, it ignores the
|
||||
# "samples_*" fields in the decorr_pass structure and gets the history data
|
||||
# directly from the buffer. It does, however, return the appropriate history
|
||||
# samples to the decorr_pass structure before returning.
|
||||
#
|
||||
# The "long_math" argument is used to specify that a 32-bit multiply is
|
||||
# not enough for the "apply_weight" operation (although in this case it
|
||||
# would only apply to the -1 and -2 terms because the MMX code does not have
|
||||
# this limitation) but we ignore the parameter and use the overflow detection
|
||||
# of the "imul" instruction to switch automatically to the "long_math" loop.
|
||||
#
|
||||
# This is written to work on an X86-64 processor (also called the AMD64)
|
||||
# running in 64-bit mode and generally uses the MMX extensions to improve
|
||||
# the performance by processing both stereo channels together. Unfortunately
|
||||
# this is not easily used for terms -1 and -2, so these terms are handled
|
||||
# sequentially with regular assembler code.
|
||||
#
|
||||
# This version has entry points for both the System V ABI and the Windows
|
||||
# X64 ABI. It does not use the "red zone" or the "shadow area"; it saves the
|
||||
# non-volatile registers for both ABIs on the stack and allocates another
|
||||
# 8 bytes on the stack to store the dpp pointer. Note that it does NOT
|
||||
# provide unwind data for the Windows ABI (the unpack_x64.asm module for
|
||||
# MSVC does). The arguments are passed in registers:
|
||||
#
|
||||
# System V Windows
|
||||
# rdi rcx struct decorr_pass *dpp
|
||||
# rsi rdx int32_t *buffer
|
||||
# edx r8 int32_t sample_count
|
||||
# ecx r9 int32_t long_math
|
||||
#
|
||||
# registers after entry:
|
||||
#
|
||||
# rdi bptr
|
||||
# rsi eptr
|
||||
#
|
||||
# stack usage:
|
||||
#
|
||||
# [rsp+0] = *dpp
|
||||
#
|
||||
|
||||
_unpack_decorr_stereo_pass_cont_x64win:
|
||||
unpack_decorr_stereo_pass_cont_x64win:
|
||||
push rbp
|
||||
push rbx
|
||||
push rdi
|
||||
push rsi
|
||||
sub rsp, 8
|
||||
mov rdi, rcx # copy params from win regs to Linux regs
|
||||
mov rsi, rdx # so we can leave following code similar
|
||||
mov rdx, r8
|
||||
mov rcx, r9
|
||||
jmp entry # jump into common portion
|
||||
|
||||
_unpack_decorr_stereo_pass_cont_x64:
|
||||
unpack_decorr_stereo_pass_cont_x64:
|
||||
push rbp
|
||||
push rbx
|
||||
push rdi
|
||||
push rsi
|
||||
sub rsp, 8
|
||||
|
||||
entry: mov [rsp], rdi # store dpp* at [rsp]
|
||||
and edx, edx # if sample_count is zero, do nothing
|
||||
jz done
|
||||
|
||||
mov rdi, rsi # rdi = bptr
|
||||
lea rsi, [rdi+rdx*8] # rsi = eptr
|
||||
|
||||
mov rax, [rsp] # get term from dpp struct & vector to handler
|
||||
mov eax, [rax]
|
||||
cmp al, 17
|
||||
je term_17_entry
|
||||
cmp al, 18
|
||||
je term_18_entry
|
||||
cmp al, -1
|
||||
je term_minus_1_entry
|
||||
cmp al, -2
|
||||
je term_minus_2_entry
|
||||
cmp al, -3
|
||||
je term_minus_3_entry
|
||||
|
||||
#
|
||||
# registers in default term loop:
|
||||
#
|
||||
# rbx term * -8 (for indexing correlation sample)
|
||||
# rdi bptr
|
||||
# rsi eptr
|
||||
#
|
||||
# mm0, mm1 scratch
|
||||
# mm2 original sample values
|
||||
# mm3 correlation sample
|
||||
# mm4 zero (for pcmpeqd)
|
||||
# mm5 weights
|
||||
# mm6 delta
|
||||
# mm7 512 (for rounding)
|
||||
#
|
||||
|
||||
default_term_entry:
|
||||
imul rbx, rax, -8 # set RBX to term * -8
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 # mm7 = round (512)
|
||||
mov rdx, [rsp] # set RDX to *dpp
|
||||
mov eax, [rdx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 # mm6 = delta (0-7)
|
||||
mov eax, 0xFFFF # mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 # mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [rdx+8] # mm5 = weight_AB masked to 16 bits
|
||||
pxor mm4, mm4 # mm4 = zero (for pcmpeqd)
|
||||
jmp default_term_loop
|
||||
|
||||
.balign 64
|
||||
default_term_loop:
|
||||
movq mm3, [rdi+rbx] # mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm0, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm0, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm0, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [rdi] # mm2 = left_right
|
||||
pslld mm0, 5
|
||||
paddd mm1, mm7 # add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm0, mm2
|
||||
paddd mm0, mm1 # add shifted sums
|
||||
movq [rdi], mm0 # store result
|
||||
movq mm0, mm3
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 # mm0 = sign (sam_AB ^ left_right)
|
||||
add rdi, 8
|
||||
pcmpeqd mm2, mm4 # mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm4 # mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 # mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 # mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 # and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb default_term_loop
|
||||
|
||||
pslld mm5, 16 # sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov rdx, [rsp] # point to dpp
|
||||
movq [rdx+8], mm5 # put weight_AB back
|
||||
emms
|
||||
|
||||
mov ecx, [rdx] # ecx = dpp->term
|
||||
|
||||
default_store_samples:
|
||||
dec ecx
|
||||
sub rdi, 8 # back up one full sample
|
||||
mov eax, [rdi+4]
|
||||
mov [rdx+rcx*4+48], eax # store samples_B [ecx]
|
||||
mov eax, [rdi]
|
||||
mov [rdx+rcx*4+16], eax # store samples_A [ecx]
|
||||
test ecx, ecx
|
||||
jnz default_store_samples
|
||||
jmp done
|
||||
|
||||
#
|
||||
# registers in term 17 & 18 loops:
|
||||
#
|
||||
# rdi bptr
|
||||
# rsi eptr
|
||||
#
|
||||
# mm0, mm1 scratch
|
||||
# mm2 original sample values
|
||||
# mm3 correlation samples
|
||||
# mm4 last calculated values (so we don't need to reload)
|
||||
# mm5 weights
|
||||
# mm6 delta
|
||||
# mm7 512 (for rounding)
|
||||
#
|
||||
|
||||
term_17_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 # mm7 = round (512)
|
||||
mov rdx, [rsp] # set RDX to *dpp
|
||||
mov eax, [rdx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 # mm6 = delta (0-7)
|
||||
mov eax, 0xFFFF # mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 # mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [rdx+8] # mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [rdi-8] # preload last calculated values in mm4
|
||||
jmp term_17_loop
|
||||
|
||||
.balign 64
|
||||
term_17_loop:
|
||||
paddd mm4, mm4
|
||||
psubd mm4, [rdi-16] # mm3 = sam_AB
|
||||
movq mm3, mm4
|
||||
movq mm1, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [rdi] # mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 # add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 # add shifted sums
|
||||
movq mm0, mm3
|
||||
movq [rdi], mm4 # store result
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 # mm0 = sign (sam_AB ^ left_right)
|
||||
add rdi, 8
|
||||
pxor mm1, mm1 # mm1 = zero
|
||||
pcmpeqd mm2, mm1 # mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 # mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 # mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 # mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 # and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb term_17_loop
|
||||
jmp term_1718_exit # terms 17 & 18 treat samples_AB[] the same
|
||||
|
||||
term_18_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 # mm7 = round (512)
|
||||
mov rdx, [rsp] # set RDX to *dpp
|
||||
mov eax, [rdx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 # mm6 = delta (0-7)
|
||||
mov eax, 0xFFFF # mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 # mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [rdx+8] # mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [rdi-8] # preload last calculated values in mm4
|
||||
jmp term_18_loop
|
||||
|
||||
.balign 64
|
||||
term_18_loop:
|
||||
movq mm3, mm4
|
||||
psubd mm3, [rdi-16]
|
||||
psrad mm3, 1
|
||||
paddd mm3, mm4 # mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm4, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [rdi] # mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 # add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 # add shifted sums
|
||||
movq mm0, mm3
|
||||
movq [rdi], mm4 # store result
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 # mm0 = sign (sam_AB ^ left_right)
|
||||
add rdi, 8
|
||||
pxor mm1, mm1 # mm1 = zero
|
||||
pcmpeqd mm2, mm1 # mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 # mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 # mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 # mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 # and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb term_18_loop
|
||||
|
||||
term_1718_exit:
|
||||
pslld mm5, 16 # sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov rdx, [rsp] # point to dpp
|
||||
movq [rdx+8], mm5 # put weight_AB back
|
||||
emms
|
||||
|
||||
mov eax, [rdi-4] # dpp->samples_B [0] = bptr [-1];
|
||||
mov [rdx+48], eax
|
||||
mov eax, [rdi-8] # dpp->samples_A [0] = bptr [-2];
|
||||
mov [rdx+16], eax
|
||||
mov eax, [rdi-12] # dpp->samples_B [1] = bptr [-3];
|
||||
mov [rdx+52], eax
|
||||
mov eax, [rdi-16] # dpp->samples_A [1] = bptr [-4];
|
||||
mov [rdx+20], eax
|
||||
jmp done
|
||||
|
||||
#
|
||||
# registers in term -1 & -2 loops:
|
||||
#
|
||||
# eax,ebx,edx scratch
|
||||
# ecx weight_A
|
||||
# ebp weight_B
|
||||
# rdi bptr
|
||||
# rsi eptr
|
||||
# r8d delta
|
||||
#
|
||||
|
||||
term_minus_1_entry:
|
||||
cld
|
||||
mov rdx, [rsp] # point to dpp
|
||||
mov ecx, [rdx+8] # ecx = weight_A
|
||||
mov ebp, [rdx+12] # ebp = weight_B
|
||||
mov r8d, [rdx+4] # r8d = delta
|
||||
mov eax, [rdi-4]
|
||||
jmp term_minus_1_loop
|
||||
|
||||
.balign 64
|
||||
term_minus_1_loop:
|
||||
mov ebx, eax
|
||||
imul eax, ecx
|
||||
mov edx, [rdi]
|
||||
jo OV11
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L182
|
||||
test edx, edx
|
||||
je L182
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L183
|
||||
mov ecx, edx
|
||||
L183: xor ecx, ebx
|
||||
L182: mov ebx, eax
|
||||
imul eax, ebp
|
||||
mov edx, [rdi]
|
||||
jo OV12
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L187
|
||||
test edx, edx
|
||||
je L187
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L188
|
||||
mov ebp, edx
|
||||
L188: xor ebp, ebx
|
||||
L187: cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb term_minus_1_loop
|
||||
jmp term_minus_1_done
|
||||
|
||||
OV11: mov eax, ebx # restore previous sample into eax
|
||||
jmp long_term_minus_1_loop
|
||||
|
||||
OV12: mov eax, ebx # restore previous sample into eax
|
||||
jmp L282
|
||||
|
||||
.balign 64
|
||||
long_term_minus_1_loop:
|
||||
mov ebx, eax
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L282
|
||||
test edx, edx
|
||||
je L282
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L283
|
||||
mov ecx, edx
|
||||
L283: xor ecx, ebx
|
||||
L282: mov ebx, eax
|
||||
imul ebp
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L287
|
||||
test edx, edx
|
||||
je L287
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L288
|
||||
mov ebp, edx
|
||||
L288: xor ebp, ebx
|
||||
L287: cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb long_term_minus_1_loop
|
||||
|
||||
term_minus_1_done:
|
||||
mov rdx, [rsp] # point to dpp
|
||||
mov [rdx+8], ecx # store weights back
|
||||
mov [rdx+12], ebp
|
||||
mov eax, [rdi-4] # dpp->samples_A [0] = bptr [-1];
|
||||
mov [rdx+16], eax
|
||||
jmp done
|
||||
|
||||
term_minus_2_entry:
|
||||
mov rdx, [rsp] # point to dpp
|
||||
mov ecx, [rdx+8] # ecx = weight_A
|
||||
mov ebp, [rdx+12] # ebp = weight_B
|
||||
mov r8d, [rdx+4] # r8d = delta
|
||||
mov eax, [rdi-8]
|
||||
jmp term_minus_2_loop
|
||||
|
||||
.balign 64
|
||||
term_minus_2_loop:
|
||||
mov ebx, eax
|
||||
imul eax, ebp
|
||||
mov edx, [rdi+4]
|
||||
jo OV21
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [rdi+4], eax
|
||||
test ebx, ebx
|
||||
je L194
|
||||
test edx, edx
|
||||
je L194
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L195
|
||||
mov ebp, edx
|
||||
L195: xor ebp, ebx
|
||||
L194: mov ebx, eax
|
||||
imul eax, ecx
|
||||
mov edx, [rdi]
|
||||
jo OV22
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [rdi], eax
|
||||
test ebx, ebx
|
||||
je L199
|
||||
test edx, edx
|
||||
je L199
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L200
|
||||
mov ecx, edx
|
||||
L200: xor ecx, ebx
|
||||
L199: add rdi, 8
|
||||
cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb term_minus_2_loop
|
||||
jmp term_minus_2_done
|
||||
|
||||
OV21: mov eax, ebx # restore previous sample into eax
|
||||
jmp long_term_minus_2_loop
|
||||
|
||||
OV22: mov eax, ebx # restore previous sample into eax
|
||||
jmp L294
|
||||
|
||||
.balign 64
|
||||
long_term_minus_2_loop:
|
||||
mov ebx, eax
|
||||
imul ebp
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi+4]
|
||||
add eax, edx
|
||||
mov [rdi+4], eax
|
||||
test ebx, ebx
|
||||
je L294
|
||||
test edx, edx
|
||||
je L294
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L295
|
||||
mov ebp, edx
|
||||
L295: xor ebp, ebx
|
||||
L294: mov ebx, eax
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
mov [rdi], eax
|
||||
test ebx, ebx
|
||||
je L299
|
||||
test edx, edx
|
||||
je L299
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L300
|
||||
mov ecx, edx
|
||||
L300: xor ecx, ebx
|
||||
L299: add rdi, 8
|
||||
cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb long_term_minus_2_loop
|
||||
|
||||
term_minus_2_done:
|
||||
mov rdx, [rsp] # point to dpp
|
||||
mov [rdx+8], ecx # store weights back
|
||||
mov [rdx+12], ebp
|
||||
mov eax, [rdi-8] # dpp->samples_B [0] = bptr [-2];
|
||||
mov [rdx+48], eax
|
||||
jmp done
|
||||
|
||||
#
|
||||
# registers in term -3 loop:
|
||||
#
|
||||
# rdi bptr
|
||||
# rsi eptr
|
||||
#
|
||||
# mm0, mm1 scratch
|
||||
# mm2 original sample values
|
||||
# mm3 correlation samples
|
||||
# mm4 last calculated values (so we don't need to reload)
|
||||
# mm5 weights
|
||||
# mm6 delta
|
||||
# mm7 512 (for rounding)
|
||||
#
|
||||
|
||||
term_minus_3_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 # mm7 = round (512)
|
||||
mov rdx, [rsp] # set RDX to *dpp
|
||||
mov eax, [rdx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 # mm6 = delta (0-7)
|
||||
mov eax, 0xFFFF # mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 # mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [rdx+8] # mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [rdi-8]
|
||||
jmp term_minus_3_loop
|
||||
|
||||
.balign 64
|
||||
term_minus_3_loop:
|
||||
movq mm3, mm4
|
||||
psrlq mm3, 32
|
||||
punpckldq mm3, mm4 # mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm4, mm3
|
||||
pslld mm1, 1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [rdi] # mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 # add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 # add shifted sums
|
||||
movq [rdi], mm4 # store result
|
||||
movq mm0, mm3
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 # mm0 = sign (sam_AB ^ left_right)
|
||||
add rdi, 8
|
||||
pxor mm1, mm1 # mm1 = zero
|
||||
pcmpeqd mm2, mm1 # mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 # mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 # mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 # mask delta with zeros check
|
||||
pcmpeqd mm1, mm1
|
||||
psubd mm1, mm7
|
||||
psubd mm1, mm7
|
||||
psubd mm1, mm0
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm1
|
||||
paddusw mm5, mm2 # and add to weight_AB
|
||||
psubw mm5, mm1
|
||||
pxor mm5, mm0
|
||||
cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb term_minus_3_loop
|
||||
|
||||
pslld mm5, 16 # sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov rdx, [rsp] # point to dpp
|
||||
movq [rdx+8], mm5 # put weight_AB back
|
||||
emms
|
||||
|
||||
mov edx, [rdi-4] # dpp->samples_A [0] = bptr [-1];
|
||||
mov rax, [rsp]
|
||||
mov [rax+16], edx
|
||||
mov edx, [rdi-8] # dpp->samples_B [0] = bptr [-2];
|
||||
mov [rax+48], edx
|
||||
|
||||
done: add rsp, 8
|
||||
pop rsi
|
||||
pop rdi
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
#######################################################################################################################
|
||||
#
|
||||
# This is the mono version of the above function. It does not use MMX and does not handle negative terms.
|
||||
#
|
||||
# void unpack_decorr_mono_pass_cont (struct decorr_pass *dpp,
|
||||
# int32_t *buffer,
|
||||
# int32_t sample_count,
|
||||
# int32_t long_math;
|
||||
# arguments on entry:
|
||||
#
|
||||
# System V Windows
|
||||
# rdi rcx struct decorr_pass *dpp
|
||||
# rsi rdx int32_t *buffer
|
||||
# edx r8 int32_t sample_count
|
||||
# ecx r9 int32_t long_math
|
||||
#
|
||||
# registers after entry:
|
||||
#
|
||||
# rdi bptr
|
||||
# rsi eptr
|
||||
#
|
||||
# stack usage:
|
||||
#
|
||||
# [rsp+0] = *dpp
|
||||
#
|
||||
|
||||
_unpack_decorr_mono_pass_cont_x64win:
|
||||
unpack_decorr_mono_pass_cont_x64win:
|
||||
push rbp
|
||||
push rbx
|
||||
push rdi
|
||||
push rsi
|
||||
sub rsp, 8
|
||||
|
||||
mov rdi, rcx # copy params from win regs to Linux regs
|
||||
mov rsi, rdx # so we can leave following code similar
|
||||
mov rdx, r8
|
||||
mov rcx, r9
|
||||
jmp mentry # jump into common portion
|
||||
|
||||
_unpack_decorr_mono_pass_cont_x64:
|
||||
unpack_decorr_mono_pass_cont_x64:
|
||||
push rbp
|
||||
push rbx
|
||||
push rdi
|
||||
push rsi
|
||||
sub rsp, 8
|
||||
|
||||
mentry: mov [rsp], rdi # store dpp* into [rsp]
|
||||
and edx, edx # if sample_count is zero, do nothing
|
||||
jz mono_done
|
||||
|
||||
cld # we use stosd
|
||||
mov rdi, rsi # rdi = bptr
|
||||
lea rsi, [rdi+rdx*4] # rsi = eptr
|
||||
|
||||
mov rax, [rsp] # get term from dpp struct & vector to handler
|
||||
mov eax, [rax]
|
||||
cmp al, 17
|
||||
je mono_17_entry
|
||||
cmp al, 18
|
||||
je mono_18_entry
|
||||
|
||||
#
|
||||
# registers during default term processing loop:
|
||||
# rdi active buffer pointer
|
||||
# rsi end of buffer pointer
|
||||
# r8d delta
|
||||
# ecx weight_A
|
||||
# ebx term * -4
|
||||
# eax,edx scratch
|
||||
#
|
||||
|
||||
default_mono_entry:
|
||||
imul rbx, rax, -4 # set rbx to term * -4 for decorrelation index
|
||||
mov rdx, [rsp]
|
||||
mov ecx, [rdx+8] # ecx = weight, r8d = delta
|
||||
mov r8d, [rdx+4]
|
||||
jmp default_mono_loop
|
||||
|
||||
#
|
||||
# registers during processing loop for terms 17 & 18:
|
||||
# rdi active buffer pointer
|
||||
# rsi end of buffer pointer
|
||||
# r8d delta
|
||||
# ecx weight_A
|
||||
# ebp previously calculated value
|
||||
# ebx calculated correlation sample
|
||||
# eax,edx scratch
|
||||
#
|
||||
|
||||
mono_17_entry:
|
||||
mov rdx, [rsp] # rdx = dpp*
|
||||
mov ecx, [rdx+8] # ecx = weight, r8d = delta
|
||||
mov r8d, [rdx+4]
|
||||
mov ebp, [rdi-4]
|
||||
jmp mono_17_loop
|
||||
|
||||
mono_18_entry:
|
||||
mov rdx, [rsp] # rdx = dpp*
|
||||
mov ecx, [rdx+8] # ecx = weight, r8d = delta
|
||||
mov r8d, [rdx+4]
|
||||
mov ebp, [rdi-4]
|
||||
jmp mono_18_loop
|
||||
|
||||
.balign 64
|
||||
default_mono_loop:
|
||||
mov eax, [rdi+rbx]
|
||||
imul eax, ecx
|
||||
mov edx, [rdi]
|
||||
jo long_default_mono_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [rdi], eax
|
||||
mov eax, [rdi+rbx]
|
||||
add rdi, 4
|
||||
test edx, edx
|
||||
je L100
|
||||
test eax, eax
|
||||
je L100
|
||||
xor eax, edx
|
||||
cdq
|
||||
xor ecx, edx
|
||||
add ecx, r8d
|
||||
xor ecx, edx
|
||||
L100: cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb default_mono_loop
|
||||
jmp default_mono_done
|
||||
|
||||
.balign 64
|
||||
long_default_mono_loop:
|
||||
mov eax, [rdi+rbx]
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
mov [rdi], eax
|
||||
mov eax, [rdi+rbx]
|
||||
add rdi, 4
|
||||
test edx, edx
|
||||
je L101
|
||||
test eax, eax
|
||||
je L101
|
||||
xor eax, edx
|
||||
cdq
|
||||
xor ecx, edx
|
||||
add ecx, r8d
|
||||
xor ecx, edx
|
||||
L101: cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb long_default_mono_loop
|
||||
|
||||
default_mono_done:
|
||||
mov rdx, [rsp] # edx = dpp*
|
||||
mov [rdx+8], ecx # store weight_A back
|
||||
mov ecx, [rdx] # ecx = dpp->term
|
||||
|
||||
default_mono_store_samples:
|
||||
dec ecx
|
||||
sub rdi, 4 # back up one full sample
|
||||
mov eax, [rdi]
|
||||
mov [rdx+rcx*4+16], eax # store samples_A [ecx]
|
||||
test ecx, ecx
|
||||
jnz default_mono_store_samples
|
||||
jmp mono_done
|
||||
|
||||
.balign 64
|
||||
mono_17_loop:
|
||||
lea ebx, [ebp+ebp]
|
||||
sub ebx, [rdi-8]
|
||||
mov eax, ecx
|
||||
imul eax, ebx
|
||||
mov edx, [rdi]
|
||||
jo long_mono_17_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L117
|
||||
test edx, edx
|
||||
je L117
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
xor ecx, ebx
|
||||
L117: cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb mono_17_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
.balign 64
|
||||
long_mono_17_loop:
|
||||
lea ebx, [ebp+ebp]
|
||||
sub ebx, [rdi-8]
|
||||
mov eax, ecx
|
||||
imul ebx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L217
|
||||
test edx, edx
|
||||
je L217
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
xor ecx, ebx
|
||||
L217: cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb long_mono_17_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
.balign 64
|
||||
mono_18_loop:
|
||||
lea ebx, [ebp+ebp*2]
|
||||
sub ebx, [rdi-8]
|
||||
sar ebx, 1
|
||||
mov eax, ecx
|
||||
imul eax, ebx
|
||||
mov edx, [rdi]
|
||||
jo long_mono_18_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L118
|
||||
test edx, edx
|
||||
je L118
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
xor ecx, ebx
|
||||
L118: cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb mono_18_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
.balign 64
|
||||
long_mono_18_loop:
|
||||
lea ebx, [ebp+ebp*2]
|
||||
sub ebx, [rdi-8]
|
||||
sar ebx, 1
|
||||
mov eax, ecx
|
||||
imul ebx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L218
|
||||
test edx, edx
|
||||
je L218
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
xor ecx, ebx
|
||||
L218: cmp rdi, rsi # compare bptr and eptr to see if we're done
|
||||
jb long_mono_18_loop
|
||||
|
||||
mono_1718_exit:
|
||||
mov rdx, [rsp] # edx = dpp*
|
||||
mov [rdx+8], ecx # store weight_A back
|
||||
mov eax, [rdi-4] # dpp->samples_A [0] = bptr [-1];
|
||||
mov [rdx+16], eax
|
||||
mov eax, [rdi-8] # dpp->samples_A [1] = bptr [-2];
|
||||
mov [rdx+20], eax
|
||||
|
||||
mono_done:
|
||||
add rsp, 8
|
||||
pop rsi
|
||||
pop rdi
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
#ifdef __ELF__
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,930 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; **** WAVPACK **** ;;
|
||||
;; Hybrid Lossless Wavefile Compressor ;;
|
||||
;; Copyright (c) 1998 - 2015 Conifer Software. ;;
|
||||
;; All Rights Reserved. ;;
|
||||
;; Distributed under the BSD Software License (see license.txt) ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
include <ksamd64.inc>
|
||||
|
||||
asmcode segment page 'CODE'
|
||||
|
||||
; This is an assembly optimized version of the following WavPack function:
|
||||
;
|
||||
; void unpack_decorr_stereo_pass_cont (struct decorr_pass *dpp,
|
||||
; int32_t *buffer,
|
||||
; int32_t sample_count,
|
||||
; int32_t long_math;
|
||||
;
|
||||
; It performs a single pass of stereo decorrelation on the provided buffer.
|
||||
; Note that this version of the function requires that up to 8 previous
|
||||
; stereo samples are visible and correct. In other words, it ignores the
|
||||
; "samples_*" fields in the decorr_pass structure and gets the history data
|
||||
; directly from the buffer. It does, however, return the appropriate history
|
||||
; samples to the decorr_pass structure before returning.
|
||||
;
|
||||
; The "long_math" argument is used to specify that a 32-bit multiply is
|
||||
; not enough for the "apply_weight" operation (although in this case it
|
||||
; would only apply to the -1 and -2 terms because the MMX code does not have
|
||||
; this limitation) but we ignore the parameter and use the overflow detection
|
||||
; of the "imul" instruction to switch automatically to the "long_math" loop.
|
||||
;
|
||||
; This is written to work on an X86-64 processor (also called the AMD64)
|
||||
; running in 64-bit mode and generally uses the MMX extensions to improve
|
||||
; the performance by processing both stereo channels together. Unfortunately
|
||||
; this is not easily used for terms -1 and -2, so these terms are handled
|
||||
; sequentially with regular assembler code.
|
||||
;
|
||||
; This version is for 64-bit Windows. The arguments are passed in registers:
|
||||
;
|
||||
; rcx struct decorr_pass *dpp
|
||||
; rdx int32_t *buffer
|
||||
; r8d int32_t sample_count
|
||||
; r9d int32_t long_math
|
||||
;
|
||||
; registers after entry:
|
||||
;
|
||||
; rdi bptr
|
||||
; rsi eptr
|
||||
; ecx long_math (only used for terms -1 and -2)
|
||||
;
|
||||
; stack usage:
|
||||
;
|
||||
; [rsp+0] = *dpp
|
||||
;
|
||||
|
||||
unpack_decorr_stereo_pass_cont_x64win proc public frame
|
||||
push_reg rbp ; save non-volatile registers on stack
|
||||
push_reg rbx ; (alphabetically)
|
||||
push_reg rdi
|
||||
push_reg rsi
|
||||
alloc_stack 8 ; allocate 8 bytes on stack & align to 16 bytes
|
||||
end_prologue
|
||||
|
||||
mov [rsp], rcx ; [rsp] = *dpp
|
||||
mov rdi, rcx ; copy params from win regs to Linux regs
|
||||
mov rsi, rdx ; so we can leave following code similar
|
||||
mov rdx, r8
|
||||
mov rcx, r9
|
||||
|
||||
and edx, edx ; if sample_count is zero, do nothing
|
||||
jz done
|
||||
|
||||
mov rdi, rsi ; rdi = bptr
|
||||
lea rsi, [rdi+rdx*8] ; rsi = eptr
|
||||
|
||||
mov rax, [rsp] ; get term from dpp struct & vector to handler
|
||||
mov eax, [rax]
|
||||
cmp al, 17
|
||||
je term_17_entry
|
||||
cmp al, 18
|
||||
je term_18_entry
|
||||
cmp al, -1
|
||||
je term_minus_1_entry
|
||||
cmp al, -2
|
||||
je term_minus_2_entry
|
||||
cmp al, -3
|
||||
je term_minus_3_entry
|
||||
|
||||
;
|
||||
; registers in default term loop:
|
||||
;
|
||||
; rbx term * -8 (for indexing correlation sample)
|
||||
; rdi bptr
|
||||
; rsi eptr
|
||||
;
|
||||
; mm0, mm1 scratch
|
||||
; mm2 original sample values
|
||||
; mm3 correlation sample
|
||||
; mm4 zero (for pcmpeqd)
|
||||
; mm5 weights
|
||||
; mm6 delta
|
||||
; mm7 512 (for rounding)
|
||||
;
|
||||
|
||||
default_term_entry:
|
||||
imul rbx, rax, -8 ; set RBX to term * -8
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 ; mm7 = round (512)
|
||||
mov rdx, [rsp] ; set RDX to *dpp
|
||||
mov eax, [rdx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 ; mm6 = delta (0-7)
|
||||
mov eax, 0FFFFh ; mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 ; mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [rdx+8] ; mm5 = weight_AB masked to 16 bits
|
||||
pxor mm4, mm4 ; mm4 = zero (for pcmpeqd)
|
||||
jmp default_term_loop
|
||||
|
||||
align 64
|
||||
default_term_loop:
|
||||
movq mm3, [rdi+rbx] ; mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm0, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm0, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm0, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [rdi] ; mm2 = left_right
|
||||
pslld mm0, 5
|
||||
paddd mm1, mm7 ; add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm0, mm2
|
||||
paddd mm0, mm1 ; add shifted sums
|
||||
movq [rdi], mm0 ; store result
|
||||
movq mm0, mm3
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 ; mm0 = sign (sam_AB ^ left_right)
|
||||
add rdi, 8
|
||||
pcmpeqd mm2, mm4 ; mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm4 ; mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 ; mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 ; mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 ; and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb default_term_loop
|
||||
|
||||
pslld mm5, 16 ; sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov rdx, [rsp] ; point to dpp
|
||||
movq [rdx+8], mm5 ; put weight_AB back
|
||||
emms
|
||||
|
||||
mov ecx, [rdx] ; ecx = dpp->term
|
||||
|
||||
default_store_samples:
|
||||
dec ecx
|
||||
sub rdi, 8 ; back up one full sample
|
||||
mov eax, [rdi+4]
|
||||
mov [rdx+rcx*4+48], eax ; store samples_B [ecx]
|
||||
mov eax, [rdi]
|
||||
mov [rdx+rcx*4+16], eax ; store samples_A [ecx]
|
||||
test ecx, ecx
|
||||
jnz default_store_samples
|
||||
jmp done
|
||||
|
||||
;
|
||||
; registers in term 17 & 18 loops:
|
||||
;
|
||||
; rdi bptr
|
||||
; rsi eptr
|
||||
;
|
||||
; mm0, mm1 scratch
|
||||
; mm2 original sample values
|
||||
; mm3 correlation samples
|
||||
; mm4 last calculated values (so we don't need to reload)
|
||||
; mm5 weights
|
||||
; mm6 delta
|
||||
; mm7 512 (for rounding)
|
||||
;
|
||||
|
||||
term_17_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 ; mm7 = round (512)
|
||||
mov rdx, [rsp] ; set RDX to *dpp
|
||||
mov eax, [rdx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 ; mm6 = delta (0-7)
|
||||
mov eax, 0FFFFh ; mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 ; mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [rdx+8] ; mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [rdi-8] ; preload last calculated values in mm4
|
||||
jmp term_17_loop
|
||||
|
||||
align 64
|
||||
term_17_loop:
|
||||
paddd mm4, mm4
|
||||
psubd mm4, [rdi-16] ; mm3 = sam_AB
|
||||
movq mm3, mm4
|
||||
movq mm1, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [rdi] ; mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 ; add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 ; add shifted sums
|
||||
movq mm0, mm3
|
||||
movq [rdi], mm4 ; store result
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 ; mm0 = sign (sam_AB ^ left_right)
|
||||
add rdi, 8
|
||||
pxor mm1, mm1 ; mm1 = zero
|
||||
pcmpeqd mm2, mm1 ; mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 ; mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 ; mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 ; mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 ; and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb term_17_loop
|
||||
jmp term_1718_exit ; terms 17 & 18 treat samples_AB[] the same
|
||||
|
||||
term_18_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 ; mm7 = round (512)
|
||||
mov rdx, [rsp] ; set RDX to *dpp
|
||||
mov eax, [rdx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 ; mm6 = delta (0-7)
|
||||
mov eax, 0FFFFh ; mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 ; mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [rdx+8] ; mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [rdi-8] ; preload last calculated values in mm4
|
||||
jmp term_18_loop
|
||||
|
||||
align 64
|
||||
term_18_loop:
|
||||
movq mm3, mm4
|
||||
psubd mm3, [rdi-16]
|
||||
psrad mm3, 1
|
||||
paddd mm3, mm4 ; mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm4, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [rdi] ; mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 ; add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 ; add shifted sums
|
||||
movq mm0, mm3
|
||||
movq [rdi], mm4 ; store result
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 ; mm0 = sign (sam_AB ^ left_right)
|
||||
add rdi, 8
|
||||
pxor mm1, mm1 ; mm1 = zero
|
||||
pcmpeqd mm2, mm1 ; mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 ; mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 ; mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 ; mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 ; and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb term_18_loop
|
||||
|
||||
term_1718_exit:
|
||||
pslld mm5, 16 ; sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov rdx, [rsp] ; point to dpp
|
||||
movq [rdx+8], mm5 ; put weight_AB back
|
||||
emms
|
||||
|
||||
mov eax, [rdi-4] ; dpp->samples_B [0] = bptr [-1];
|
||||
mov [rdx+48], eax
|
||||
mov eax, [rdi-8] ; dpp->samples_A [0] = bptr [-2];
|
||||
mov [rdx+16], eax
|
||||
mov eax, [rdi-12] ; dpp->samples_B [1] = bptr [-3];
|
||||
mov [rdx+52], eax
|
||||
mov eax, [rdi-16] ; dpp->samples_A [1] = bptr [-4];
|
||||
mov [rdx+20], eax
|
||||
jmp done
|
||||
|
||||
;
|
||||
; registers in term -1 & -2 loops:
|
||||
;
|
||||
; eax,ebx,edx scratch
|
||||
; ecx weight_A
|
||||
; ebp weight_B
|
||||
; rdi bptr
|
||||
; rsi eptr
|
||||
; r8d delta
|
||||
;
|
||||
|
||||
term_minus_1_entry:
|
||||
cld
|
||||
mov rdx, [rsp] ; point to dpp
|
||||
mov ecx, [rdx+8] ; ecx = weight_A
|
||||
mov ebp, [rdx+12] ; ebp = weight_B
|
||||
mov r8d, [rdx+4] ; r8d = delta
|
||||
mov eax, [rdi-4]
|
||||
jmp term_minus_1_loop
|
||||
|
||||
align 64
|
||||
term_minus_1_loop:
|
||||
mov ebx, eax
|
||||
imul eax, ecx
|
||||
mov edx, [rdi]
|
||||
jo OV11
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L182
|
||||
test edx, edx
|
||||
je L182
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L183
|
||||
mov ecx, edx
|
||||
L183: xor ecx, ebx
|
||||
L182: mov ebx, eax
|
||||
imul eax, ebp
|
||||
mov edx, [rdi]
|
||||
jo OV12
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L187
|
||||
test edx, edx
|
||||
je L187
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L188
|
||||
mov ebp, edx
|
||||
L188: xor ebp, ebx
|
||||
L187: cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb term_minus_1_loop
|
||||
jmp term_minus_1_done
|
||||
|
||||
OV11: mov eax, ebx ; restore previous sample into eax
|
||||
jmp long_term_minus_1_loop
|
||||
|
||||
OV12: mov eax, ebx ; restore previous sample into eax
|
||||
jmp L282
|
||||
|
||||
align 64
|
||||
long_term_minus_1_loop:
|
||||
mov ebx, eax
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L282
|
||||
test edx, edx
|
||||
je L282
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L283
|
||||
mov ecx, edx
|
||||
L283: xor ecx, ebx
|
||||
L282: mov ebx, eax
|
||||
imul ebp
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L287
|
||||
test edx, edx
|
||||
je L287
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L288
|
||||
mov ebp, edx
|
||||
L288: xor ebp, ebx
|
||||
L287: cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb long_term_minus_1_loop
|
||||
|
||||
term_minus_1_done:
|
||||
mov rdx, [rsp] ; point to dpp
|
||||
mov [rdx+8], ecx ; store weights back
|
||||
mov [rdx+12], ebp
|
||||
mov eax, [rdi-4] ; dpp->samples_A [0] = bptr [-1];
|
||||
mov [rdx+16], eax
|
||||
jmp done
|
||||
|
||||
term_minus_2_entry:
|
||||
mov rdx, [rsp] ; point to dpp
|
||||
mov ecx, [rdx+8] ; ecx = weight_A
|
||||
mov ebp, [rdx+12] ; ebp = weight_B
|
||||
mov r8d, [rdx+4] ; r8d = delta
|
||||
mov eax, [rdi-8]
|
||||
jmp term_minus_2_loop
|
||||
|
||||
align 64
|
||||
term_minus_2_loop:
|
||||
mov ebx, eax
|
||||
imul eax, ebp
|
||||
mov edx, [rdi+4]
|
||||
jo OV21
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [rdi+4], eax
|
||||
test ebx, ebx
|
||||
je L194
|
||||
test edx, edx
|
||||
je L194
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L195
|
||||
mov ebp, edx
|
||||
L195: xor ebp, ebx
|
||||
L194: mov ebx, eax
|
||||
imul eax, ecx
|
||||
mov edx, [rdi]
|
||||
jo OV22
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [rdi], eax
|
||||
test ebx, ebx
|
||||
je L199
|
||||
test edx, edx
|
||||
je L199
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L200
|
||||
mov ecx, edx
|
||||
L200: xor ecx, ebx
|
||||
L199: add rdi, 8
|
||||
cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb term_minus_2_loop
|
||||
jmp term_minus_2_done
|
||||
|
||||
OV21: mov eax, ebx ; restore previous sample into eax
|
||||
jmp long_term_minus_2_loop
|
||||
|
||||
OV22: mov eax, ebx ; restore previous sample into eax
|
||||
jmp L294
|
||||
|
||||
align 64
|
||||
long_term_minus_2_loop:
|
||||
mov ebx, eax
|
||||
imul ebp
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi+4]
|
||||
add eax, edx
|
||||
mov [rdi+4], eax
|
||||
test ebx, ebx
|
||||
je L294
|
||||
test edx, edx
|
||||
je L294
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L295
|
||||
mov ebp, edx
|
||||
L295: xor ebp, ebx
|
||||
L294: mov ebx, eax
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
mov [rdi], eax
|
||||
test ebx, ebx
|
||||
je L299
|
||||
test edx, edx
|
||||
je L299
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L300
|
||||
mov ecx, edx
|
||||
L300: xor ecx, ebx
|
||||
L299: add rdi, 8
|
||||
cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb long_term_minus_2_loop
|
||||
|
||||
term_minus_2_done:
|
||||
mov rdx, [rsp] ; point to dpp
|
||||
mov [rdx+8], ecx ; store weights back
|
||||
mov [rdx+12], ebp
|
||||
mov eax, [rdi-8] ; dpp->samples_B [0] = bptr [-2];
|
||||
mov [rdx+48], eax
|
||||
jmp done
|
||||
|
||||
;
|
||||
; registers in term -3 loop:
|
||||
;
|
||||
; rdi bptr
|
||||
; rsi eptr
|
||||
;
|
||||
; mm0, mm1 scratch
|
||||
; mm2 original sample values
|
||||
; mm3 correlation samples
|
||||
; mm4 last calculated values (so we don't need to reload)
|
||||
; mm5 weights
|
||||
; mm6 delta
|
||||
; mm7 512 (for rounding)
|
||||
;
|
||||
|
||||
term_minus_3_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 ; mm7 = round (512)
|
||||
mov rdx, [rsp] ; set RDX to *dpp
|
||||
mov eax, [rdx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 ; mm6 = delta (0-7)
|
||||
mov eax, 0FFFFh ; mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 ; mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [rdx+8] ; mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [rdi-8]
|
||||
jmp term_minus_3_loop
|
||||
|
||||
align 64
|
||||
term_minus_3_loop:
|
||||
movq mm3, mm4
|
||||
psrlq mm3, 32
|
||||
punpckldq mm3, mm4 ; mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm4, mm3
|
||||
pslld mm1, 1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [rdi] ; mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 ; add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 ; add shifted sums
|
||||
movq [rdi], mm4 ; store result
|
||||
movq mm0, mm3
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 ; mm0 = sign (sam_AB ^ left_right)
|
||||
add rdi, 8
|
||||
pxor mm1, mm1 ; mm1 = zero
|
||||
pcmpeqd mm2, mm1 ; mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 ; mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 ; mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 ; mask delta with zeros check
|
||||
pcmpeqd mm1, mm1
|
||||
psubd mm1, mm7
|
||||
psubd mm1, mm7
|
||||
psubd mm1, mm0
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm1
|
||||
paddusw mm5, mm2 ; and add to weight_AB
|
||||
psubw mm5, mm1
|
||||
pxor mm5, mm0
|
||||
cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb term_minus_3_loop
|
||||
|
||||
pslld mm5, 16 ; sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov rdx, [rsp] ; point to dpp
|
||||
movq [rdx+8], mm5 ; put weight_AB back
|
||||
emms
|
||||
|
||||
mov edx, [rdi-4] ; dpp->samples_A [0] = bptr [-1];
|
||||
mov rax, [rsp]
|
||||
mov [rax+16], edx
|
||||
mov edx, [rdi-8] ; dpp->samples_B [0] = bptr [-2];
|
||||
mov [rax+48], edx
|
||||
|
||||
done: add rsp, 8 ; begin epilog by deallocating stack
|
||||
pop rsi ; restore non-volatile registers & return
|
||||
pop rdi
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
unpack_decorr_stereo_pass_cont_x64win endp
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
; This is the mono version of the above function. It does not use MMX and does not
|
||||
; handle negative terms (since they don't apply to mono), but is otherwise similar.
|
||||
;
|
||||
; void unpack_decorr_mono_pass_cont (struct decorr_pass *dpp,
|
||||
; int32_t *buffer,
|
||||
; int32_t sample_count,
|
||||
; int32_t long_math;
|
||||
; arguments on entry:
|
||||
;
|
||||
; rcx struct decorr_pass *dpp
|
||||
; rdx int32_t *buffer
|
||||
; r8d int32_t sample_count
|
||||
; r9d int32_t long_math
|
||||
;
|
||||
; registers after entry:
|
||||
;
|
||||
; rdi bptr
|
||||
; rsi eptr
|
||||
; ecx long_math
|
||||
;
|
||||
; stack usage:
|
||||
;
|
||||
; [rsp+0] = *dpp
|
||||
;
|
||||
|
||||
unpack_decorr_mono_pass_cont_x64win proc public frame
|
||||
push_reg rbp ; save non-volatile registers on stack
|
||||
push_reg rbx ; (alphabetically)
|
||||
push_reg rdi
|
||||
push_reg rsi
|
||||
alloc_stack 8 ; allocate 8 bytes on stack & align to 16 bytes
|
||||
end_prologue
|
||||
|
||||
mov [rsp], rcx ; [rsp] = *dpp
|
||||
mov rdi, rcx ; copy params from win regs to Linux regs
|
||||
mov rsi, rdx ; so we can leave following code similar
|
||||
mov rdx, r8
|
||||
mov rcx, r9
|
||||
|
||||
and edx, edx ; if sample_count is zero, do nothing
|
||||
jz mono_done
|
||||
|
||||
cld
|
||||
mov rdi, rsi ; rdi = bptr
|
||||
lea rsi, [rdi+rdx*4] ; rsi = eptr
|
||||
|
||||
mov rax, [rsp] ; get term from dpp struct & vector to handler
|
||||
mov eax, [rax]
|
||||
cmp al, 17
|
||||
je mono_17_entry
|
||||
cmp al, 18
|
||||
je mono_18_entry
|
||||
|
||||
;
|
||||
; registers during default term processing loop:
|
||||
; rdi active buffer pointer
|
||||
; rsi end of buffer pointer
|
||||
; r8d delta
|
||||
; ecx weight_A
|
||||
; ebx term * -4
|
||||
; eax,edx scratch
|
||||
;
|
||||
|
||||
default_mono_entry:
|
||||
imul rbx, rax, -4 ; set rbx to term * -4 for decorrelation index
|
||||
mov rdx, [rsp]
|
||||
mov ecx, [rdx+8] ; ecx = weight, r8d = delta
|
||||
mov r8d, [rdx+4]
|
||||
jmp default_mono_loop
|
||||
|
||||
;
|
||||
; registers during processing loop for terms 17 & 18:
|
||||
; rdi active buffer pointer
|
||||
; rsi end of buffer pointer
|
||||
; r8d delta
|
||||
; ecx weight_A
|
||||
; ebp previously calculated value
|
||||
; ebx calculated correlation sample
|
||||
; eax,edx scratch
|
||||
;
|
||||
|
||||
mono_17_entry:
|
||||
mov rdx, [rsp] ; rdx = dpp*
|
||||
mov ecx, [rdx+8] ; ecx = weight, r8d = delta
|
||||
mov r8d, [rdx+4]
|
||||
mov ebp, [rdi-4]
|
||||
jmp mono_17_loop
|
||||
|
||||
mono_18_entry:
|
||||
mov rdx, [rsp] ; rdx = dpp*
|
||||
mov ecx, [rdx+8] ; ecx = weight, r8d = delta
|
||||
mov r8d, [rdx+4]
|
||||
mov ebp, [rdi-4]
|
||||
jmp mono_18_loop
|
||||
|
||||
align 64
|
||||
default_mono_loop:
|
||||
mov eax, [rdi+rbx]
|
||||
imul eax, ecx
|
||||
mov edx, [rdi]
|
||||
jo long_default_mono_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [rdi], eax
|
||||
mov eax, [rdi+rbx]
|
||||
add rdi, 4
|
||||
test edx, edx
|
||||
je L100
|
||||
test eax, eax
|
||||
je L100
|
||||
xor eax, edx
|
||||
cdq
|
||||
xor ecx, edx
|
||||
add ecx, r8d
|
||||
xor ecx, edx
|
||||
L100: cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb default_mono_loop
|
||||
jmp default_mono_done
|
||||
|
||||
align 64
|
||||
long_default_mono_loop:
|
||||
mov eax, [rdi+rbx]
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
mov [rdi], eax
|
||||
mov eax, [rdi+rbx]
|
||||
add rdi, 4
|
||||
test edx, edx
|
||||
je L101
|
||||
test eax, eax
|
||||
je L101
|
||||
xor eax, edx
|
||||
cdq
|
||||
xor ecx, edx
|
||||
add ecx, r8d
|
||||
xor ecx, edx
|
||||
L101: cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb long_default_mono_loop
|
||||
|
||||
default_mono_done:
|
||||
mov rdx, [rsp] ; edx = dpp*
|
||||
mov [rdx+8], ecx ; store weight_A back
|
||||
mov ecx, [rdx] ; ecx = dpp->term
|
||||
|
||||
default_mono_store_samples:
|
||||
dec ecx
|
||||
sub rdi, 4 ; back up one full sample
|
||||
mov eax, [rdi]
|
||||
mov [rdx+rcx*4+16], eax ; store samples_A [ecx]
|
||||
test ecx, ecx
|
||||
jnz default_mono_store_samples
|
||||
jmp mono_done
|
||||
|
||||
align 64
|
||||
mono_17_loop:
|
||||
lea ebx, [ebp+ebp]
|
||||
sub ebx, [rdi-8]
|
||||
mov eax, ecx
|
||||
imul eax, ebx
|
||||
mov edx, [rdi]
|
||||
jo long_mono_17_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L117
|
||||
test edx, edx
|
||||
je L117
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
xor ecx, ebx
|
||||
L117: cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb mono_17_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
align 64
|
||||
long_mono_17_loop:
|
||||
lea ebx, [ebp+ebp]
|
||||
sub ebx, [rdi-8]
|
||||
mov eax, ecx
|
||||
imul ebx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L217
|
||||
test edx, edx
|
||||
je L217
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
xor ecx, ebx
|
||||
L217: cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb long_mono_17_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
align 64
|
||||
mono_18_loop:
|
||||
lea ebx, [ebp+ebp*2]
|
||||
sub ebx, [rdi-8]
|
||||
sar ebx, 1
|
||||
mov eax, ecx
|
||||
imul eax, ebx
|
||||
mov edx, [rdi]
|
||||
jo long_mono_18_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L118
|
||||
test edx, edx
|
||||
je L118
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
xor ecx, ebx
|
||||
L118: cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb mono_18_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
align 64
|
||||
long_mono_18_loop:
|
||||
lea ebx, [ebp+ebp*2]
|
||||
sub ebx, [rdi-8]
|
||||
sar ebx, 1
|
||||
mov eax, ecx
|
||||
imul ebx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [rdi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L218
|
||||
test edx, edx
|
||||
je L218
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, r8d
|
||||
xor ecx, ebx
|
||||
L218: cmp rdi, rsi ; compare bptr and eptr to see if we're done
|
||||
jb long_mono_18_loop
|
||||
|
||||
mono_1718_exit:
|
||||
mov rdx, [rsp] ; edx = dpp*
|
||||
mov [rdx+8], ecx ; store weight_A back
|
||||
mov eax, [rdi-4] ; dpp->samples_A [0] = bptr [-1];
|
||||
mov [rdx+16], eax
|
||||
mov eax, [rdi-8] ; dpp->samples_A [1] = bptr [-2];
|
||||
mov [rdx+20], eax
|
||||
|
||||
mono_done:
|
||||
add rsp, 8 ; begin epilog by deallocating stack
|
||||
pop rsi ; restore non-volatile registers & return
|
||||
pop rdi
|
||||
pop rbx
|
||||
pop rbp
|
||||
ret
|
||||
|
||||
unpack_decorr_mono_pass_cont_x64win endp
|
||||
|
||||
asmcode ends
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -0,0 +1,970 @@
|
||||
############################################################################
|
||||
## **** WAVPACK **** ##
|
||||
## Hybrid Lossless Wavefile Compressor ##
|
||||
## Copyright (c) 1998 - 2015 Conifer Software. ##
|
||||
## All Rights Reserved. ##
|
||||
## Distributed under the BSD Software License (see license.txt) ##
|
||||
############################################################################
|
||||
|
||||
.intel_syntax noprefix
|
||||
.text
|
||||
|
||||
.globl _unpack_decorr_stereo_pass_cont_x86
|
||||
.globl _unpack_decorr_mono_pass_cont_x86
|
||||
.globl _unpack_cpu_has_feature_x86
|
||||
|
||||
.globl unpack_decorr_stereo_pass_cont_x86
|
||||
.globl unpack_decorr_mono_pass_cont_x86
|
||||
.globl unpack_cpu_has_feature_x86
|
||||
|
||||
|
||||
# This module contains X86 assembly optimized versions of functions required
|
||||
# to decode WavPack files. Note that the stereo versions of these functions
|
||||
# use the MMX registers and instructions of the X86 processor, and so a
|
||||
# helper function is provided to make a runtime check for that feature.
|
||||
|
||||
# This is an assembly optimized version of the following WavPack function:
|
||||
#
|
||||
# void unpack_decorr_stereo_pass_cont (struct decorr_pass *dpp,
|
||||
# int32_t *buffer,
|
||||
# int32_t sample_count,
|
||||
# int32_t long_math;
|
||||
#
|
||||
# It performs a single pass of stereo decorrelation on the provided buffer.
|
||||
# Note that this version of the function requires that up to 8 previous
|
||||
# stereo samples are visible and correct. In other words, it ignores the
|
||||
# "samples_*" fields in the decorr_pass structure and gets the history data
|
||||
# directly from the buffer. It does, however, return the appropriate history
|
||||
# samples to the decorr_pass structure before returning.
|
||||
#
|
||||
# The "long_math" argument is used to specify that a 32-bit multiply is
|
||||
# not enough for the "apply_weight" operation (although in this case it
|
||||
# would only apply to the -1 and -2 terms because the MMX code does not have
|
||||
# this limitation) but we ignore the parameter and use the overflow detection
|
||||
# of the "imul" instruction to switch automatically to the "long_math" loop.
|
||||
#
|
||||
# This is written to work on an IA-32 processor and uses the MMX extensions
|
||||
# to improve the performance by processing both stereo channels together.
|
||||
# For terms -1 and -2 the MMX extensions are not usable, and so these are
|
||||
# performed independently without them.
|
||||
#
|
||||
# arguments on entry:
|
||||
#
|
||||
# struct decorr_pass *dpp [ebp+8]
|
||||
# int32_t *buffer [ebp+12]
|
||||
# int32_t sample_count [ebp+16]
|
||||
# int32_t long_math [ebp+20]
|
||||
#
|
||||
# registers after entry:
|
||||
#
|
||||
# rdi bptr
|
||||
# rsi eptr
|
||||
#
|
||||
# on stack (used for terms -1 and -2 only):
|
||||
#
|
||||
# int32_t delta DWORD [esp]
|
||||
#
|
||||
|
||||
_unpack_decorr_stereo_pass_cont_x86:
|
||||
unpack_decorr_stereo_pass_cont_x86:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
mov edx, [ebp+8] # copy delta from dpp to top of stack
|
||||
mov eax, [edx+4]
|
||||
push eax
|
||||
|
||||
mov edi, [ebp+12] # edi = buffer
|
||||
mov eax, [ebp+16] # get sample_count and divide by 8
|
||||
shl eax, 3
|
||||
jz done # exit now if there's nothing to do
|
||||
|
||||
add eax, edi # else add to buffer point to make eptr
|
||||
mov esi, eax
|
||||
|
||||
mov eax, [ebp+8] # get term from dpp and vector appropriately
|
||||
mov eax, [eax]
|
||||
cmp eax, 17
|
||||
je term_17_entry
|
||||
cmp eax, 18
|
||||
je term_18_entry
|
||||
cmp eax, -1
|
||||
je term_minus_1_entry
|
||||
cmp eax, -2
|
||||
je term_minus_2_entry
|
||||
cmp eax, -3
|
||||
je term_minus_3_entry
|
||||
|
||||
#
|
||||
# registers during default term processing loop:
|
||||
# edi active buffer pointer
|
||||
# esi end of buffer pointer
|
||||
#
|
||||
# MMX:
|
||||
# mm0, mm1 scratch
|
||||
# mm2 original sample values
|
||||
# mm3 correlation samples
|
||||
# mm4 zero (for pcmpeqd)
|
||||
# mm5 weights
|
||||
# mm6 delta
|
||||
# mm7 512 (for rounding)
|
||||
#
|
||||
|
||||
default_term_entry:
|
||||
imul ebx, eax, -8 # set ebx to term * -8 for decorrelation index
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 # mm7 = round (512)
|
||||
mov edx, [ebp+8] # edx = *dpp
|
||||
mov eax, [edx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 # mm6 = delta (0-7)
|
||||
mov eax, 0xFFFF # mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 # mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [edx+8] # mm5 = weight_AB masked to 16 bits
|
||||
pxor mm4, mm4 # mm4 = zero (for pcmpeqd)
|
||||
jmp default_term_loop
|
||||
|
||||
.balign 64
|
||||
default_term_loop:
|
||||
movq mm3, [edi+ebx] # mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm0, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm0, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm0, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [edi] # mm2 = left_right
|
||||
pslld mm0, 5
|
||||
paddd mm1, mm7 # add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm0, mm2
|
||||
paddd mm0, mm1 # add shifted sums
|
||||
movq [edi], mm0 # store result
|
||||
movq mm0, mm3
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 # mm0 = sign (sam_AB ^ left_right)
|
||||
add edi, 8
|
||||
pcmpeqd mm2, mm4 # mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm4 # mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 # mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 # mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 # and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb default_term_loop
|
||||
|
||||
pslld mm5, 16 # sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov eax, [ebp+8] # point to dpp
|
||||
movq [eax+8], mm5 # put weight_AB back
|
||||
emms
|
||||
mov edx, [ebp+8] # access dpp with edx
|
||||
mov ecx, [edx] # ecx = dpp->term
|
||||
|
||||
default_store_samples:
|
||||
dec ecx
|
||||
sub edi, 8 # back up one full sample
|
||||
mov eax, [edi+4]
|
||||
mov [edx+ecx*4+48], eax # store samples_B [ecx]
|
||||
mov eax, [edi]
|
||||
mov [edx+ecx*4+16], eax # store samples_A [ecx]
|
||||
test ecx, ecx
|
||||
jnz default_store_samples
|
||||
|
||||
jmp done
|
||||
|
||||
#
|
||||
# registers during processing loop for terms 17 & 18:
|
||||
# edi active buffer pointer
|
||||
# esi end of buffer pointer
|
||||
#
|
||||
# MMX:
|
||||
# mm0, mm1 scratch
|
||||
# mm2 original sample values
|
||||
# mm3 calculated correlation samples
|
||||
# mm4 last calculated values (so we don't need to reload)
|
||||
# mm5 weights
|
||||
# mm6 delta
|
||||
# mm7 512 (for rounding)
|
||||
#
|
||||
|
||||
term_17_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 # mm7 = round (512)
|
||||
mov edx, [ebp+8] # point to dpp & get delta
|
||||
mov eax, [edx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 # mm6 = delta (0-7)
|
||||
mov eax, 0xFFFF # mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 # mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [edx+8] # mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [edi-8] # preload previous calculated values
|
||||
jmp term_17_loop
|
||||
|
||||
.balign 64
|
||||
term_17_loop:
|
||||
paddd mm4, mm4
|
||||
psubd mm4, [edi-16] # mm3 = sam_AB
|
||||
movq mm3, mm4
|
||||
movq mm1, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [edi] # mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 # add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 # add shifted sums
|
||||
movq mm0, mm3
|
||||
movq [edi], mm4 # store result
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 # mm0 = sign (sam_AB ^ left_right)
|
||||
add edi, 8
|
||||
pxor mm1, mm1 # mm1 = zero
|
||||
pcmpeqd mm2, mm1 # mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 # mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 # mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 # mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 # and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb term_17_loop
|
||||
|
||||
pslld mm5, 16 # sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov eax, [ebp+8] # point to dpp
|
||||
movq [eax+8], mm5 # put weight_AB back
|
||||
emms
|
||||
jmp term_1718_exit
|
||||
|
||||
term_18_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 # mm7 = round (512)
|
||||
mov edx, [ebp+8] # point to dpp & get delta
|
||||
mov eax, [edx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 # mm6 = delta (0-7)
|
||||
mov eax, 0xFFFF # mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 # mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [edx+8] # mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [edi-8] # preload previous calculated value
|
||||
jmp term_18_loop
|
||||
|
||||
.balign 64
|
||||
term_18_loop:
|
||||
movq mm3, mm4
|
||||
psubd mm3, [edi-16]
|
||||
psrad mm3, 1
|
||||
paddd mm3, mm4 # mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm4, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [edi] # mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 # add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 # add shifted sums
|
||||
movq mm0, mm3
|
||||
movq [edi], mm4 # store result
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 # mm0 = sign (sam_AB ^ left_right)
|
||||
add edi, 8
|
||||
pxor mm1, mm1 # mm1 = zero
|
||||
pcmpeqd mm2, mm1 # mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 # mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 # mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 # mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 # and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb term_18_loop
|
||||
|
||||
pslld mm5, 16 # sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov eax, [ebp+8] # point to dpp
|
||||
movq [eax+8], mm5 # put weight_AB back
|
||||
emms
|
||||
|
||||
term_1718_exit:
|
||||
mov edx, [edi-4] # dpp->samples_B [0] = bptr [-1];
|
||||
mov eax, [ebp+8]
|
||||
mov [eax+48], edx
|
||||
mov edx, [edi-8] # dpp->samples_A [0] = bptr [-2];
|
||||
mov [eax+16], edx
|
||||
mov edx, [edi-12] # dpp->samples_B [1] = bptr [-3];
|
||||
mov [eax+52], edx
|
||||
mov edx, [edi-16] # dpp->samples_A [1] = bptr [-4];
|
||||
mov [eax+20], edx
|
||||
jmp done
|
||||
|
||||
#
|
||||
# registers in term -1 & -2 loops:
|
||||
#
|
||||
# eax,ebx,edx scratch
|
||||
# ecx weight_A
|
||||
# ebp weight_B
|
||||
# edi bptr
|
||||
# esi eptr
|
||||
#
|
||||
|
||||
term_minus_1_entry:
|
||||
cld # we use stosd here...
|
||||
mov eax, [ebp+8] # point to dpp
|
||||
mov ecx, [eax+8] # ecx = weight_A and ebp = weight_B
|
||||
mov ebp, [eax+12]
|
||||
mov eax, [edi-4]
|
||||
jmp term_minus_1_loop
|
||||
|
||||
.balign 64
|
||||
term_minus_1_loop:
|
||||
mov ebx, eax
|
||||
imul eax, ecx
|
||||
mov edx, [edi]
|
||||
jo OV11
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L182
|
||||
test edx, edx
|
||||
je L182
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L183
|
||||
mov ecx, edx
|
||||
L183: xor ecx, ebx
|
||||
L182: mov ebx, eax
|
||||
imul eax, ebp
|
||||
mov edx, [edi]
|
||||
jo OV12
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L189
|
||||
test edx, edx
|
||||
je L189
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L188
|
||||
mov ebp, edx
|
||||
L188: xor ebp, ebx
|
||||
L189: cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb term_minus_1_loop
|
||||
jmp term_minus_1_done
|
||||
|
||||
OV11: mov eax, ebx # restore previous sample into eax
|
||||
jmp long_term_minus_1_loop
|
||||
|
||||
OV12: mov eax, ebx # restore previous sample into eax
|
||||
jmp L282
|
||||
|
||||
.balign 64
|
||||
long_term_minus_1_loop:
|
||||
mov ebx, eax
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L282
|
||||
test edx, edx
|
||||
je L282
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L283
|
||||
mov ecx, edx
|
||||
L283: xor ecx, ebx
|
||||
L282: mov ebx, eax
|
||||
imul ebp
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L289
|
||||
test edx, edx
|
||||
je L289
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L288
|
||||
mov ebp, edx
|
||||
L288: xor ebp, ebx
|
||||
L289: cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb long_term_minus_1_loop
|
||||
|
||||
term_minus_1_done:
|
||||
mov edx, ebp
|
||||
mov ebp, esp # restore ebp (we've pushed 4 DWORDS)
|
||||
add ebp, 16
|
||||
mov eax, [ebp+8] # point to dpp
|
||||
mov [eax+8], ecx
|
||||
mov [eax+12], edx
|
||||
mov edx, [edi-4] # dpp->samples_A [0] = bptr [-1]
|
||||
mov [eax+16], edx
|
||||
jmp done
|
||||
|
||||
|
||||
term_minus_2_entry:
|
||||
mov eax, [ebp+8] # point to dpp
|
||||
mov ecx, [eax+8] # ecx = weight_A and ebp = weight_B
|
||||
mov ebp, [eax+12]
|
||||
mov eax, [edi-8]
|
||||
jmp term_minus_2_loop
|
||||
|
||||
.balign 64
|
||||
term_minus_2_loop:
|
||||
mov ebx, eax
|
||||
imul eax, ebp
|
||||
mov edx, [edi+4]
|
||||
jo OV21
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [edi+4], eax
|
||||
test ebx, ebx
|
||||
je L194
|
||||
test edx, edx
|
||||
je L194
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L195
|
||||
mov ebp, edx
|
||||
L195: xor ebp, ebx
|
||||
L194: mov ebx, eax
|
||||
imul eax, ecx
|
||||
mov edx, [edi]
|
||||
jo OV22
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [edi], eax
|
||||
add edi, 8
|
||||
test ebx, ebx
|
||||
je L201
|
||||
test edx, edx
|
||||
je L201
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L200
|
||||
mov ecx, edx
|
||||
L200: xor ecx, ebx
|
||||
L201: cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb term_minus_2_loop
|
||||
jmp term_minus_2_done
|
||||
|
||||
OV21: mov eax, ebx # restore previous sample into eax
|
||||
jmp long_term_minus_2_loop
|
||||
|
||||
OV22: mov eax, ebx # restore previous sample into eax
|
||||
jmp L294
|
||||
|
||||
.balign 64
|
||||
long_term_minus_2_loop:
|
||||
mov ebx, eax
|
||||
imul ebp
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi+4]
|
||||
add eax, edx
|
||||
mov [edi+4], eax
|
||||
test ebx, ebx
|
||||
je L294
|
||||
test edx, edx
|
||||
je L294
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L295
|
||||
mov ebp, edx
|
||||
L295: xor ebp, ebx
|
||||
L294: mov ebx, eax
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
mov [edi], eax
|
||||
add edi, 8
|
||||
test ebx, ebx
|
||||
je L301
|
||||
test edx, edx
|
||||
je L301
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L300
|
||||
mov ecx, edx
|
||||
L300: xor ecx, ebx
|
||||
L301: cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb long_term_minus_2_loop
|
||||
|
||||
term_minus_2_done:
|
||||
mov edx, ebp
|
||||
lea ebp, [esp+16] # restore ebp (we've pushed 4 DWORDS)
|
||||
mov eax, [ebp+8] # point to dpp
|
||||
mov [eax+8], ecx
|
||||
mov [eax+12], edx
|
||||
mov edx, [edi-8] # dpp->samples_B [0] = bptr [-2];
|
||||
mov [eax+48], edx
|
||||
jmp done
|
||||
|
||||
#
|
||||
# registers during processing loop for term -3:
|
||||
# edi active buffer pointer
|
||||
# esi end of buffer pointer
|
||||
#
|
||||
# MMX:
|
||||
# mm0, mm1 scratch
|
||||
# mm2 original sample values
|
||||
# mm3 calculated correlation samples
|
||||
# mm4 last calculated values (so we don't need to reload)
|
||||
# mm5 weights
|
||||
# mm6 delta
|
||||
# mm7 512 (for rounding)
|
||||
#
|
||||
|
||||
term_minus_3_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 # mm7 = round (512)
|
||||
mov edx, [ebp+8] # point to dpp & get delta
|
||||
mov eax, [edx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 # mm6 = delta (0-7)
|
||||
mov eax, 0xFFFF # mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 # mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [edx+8] # mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [edi-8] # preload previous calculated values
|
||||
jmp term_minus_3_loop
|
||||
|
||||
.balign 64
|
||||
term_minus_3_loop:
|
||||
movq mm3, mm4 # mm3 = swap dwords (mm4)
|
||||
psrlq mm3, 32
|
||||
punpckldq mm3, mm4 # mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm4, mm3
|
||||
pslld mm1, 1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [edi] # mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 # add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 # add shifted sums
|
||||
movq [edi], mm4 # store result
|
||||
movq mm0, mm3
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 # mm0 = sign (sam_AB ^ left_right)
|
||||
add edi, 8
|
||||
pxor mm1, mm1 # mm1 = zero
|
||||
pcmpeqd mm2, mm1 # mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 # mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 # mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 # mask delta with zeros check
|
||||
pcmpeqd mm1, mm1
|
||||
psubd mm1, mm7
|
||||
psubd mm1, mm7
|
||||
psubd mm1, mm0
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm1
|
||||
paddusw mm5, mm2 # and add to weight_AB
|
||||
psubw mm5, mm1
|
||||
pxor mm5, mm0
|
||||
cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb term_minus_3_loop
|
||||
|
||||
pslld mm5, 16 # sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov eax, [ebp+8] # point to dpp
|
||||
movq [eax+8], mm5 # put weight_AB back
|
||||
emms
|
||||
mov edx, [edi-4] # dpp->samples_A [0] = bptr [-1];
|
||||
mov eax, [ebp+8]
|
||||
mov [eax+16], edx
|
||||
mov edx, [edi-8] # dpp->samples_B [0] = bptr [-2];
|
||||
mov [eax+48], edx
|
||||
|
||||
done: pop eax # pop delta & saved regs
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
#######################################################################################################################
|
||||
#
|
||||
# This is the mono version of the above function. It does not use MMX and does not handle negative terms.
|
||||
#
|
||||
# void unpack_decorr_mono_pass_cont (struct decorr_pass *dpp,
|
||||
# int32_t *buffer,
|
||||
# int32_t sample_count,
|
||||
# int32_t long_math;
|
||||
# arguments on entry:
|
||||
#
|
||||
# struct decorr_pass *dpp [ebp+8]
|
||||
# int32_t *buffer [ebp+12]
|
||||
# int32_t sample_count [ebp+16]
|
||||
# int32_t long_math [ebp+20]
|
||||
#
|
||||
# registers after entry:
|
||||
#
|
||||
# rdi bptr
|
||||
# rsi eptr
|
||||
#
|
||||
# on stack:
|
||||
#
|
||||
# int16_t delta DWORD [esp]
|
||||
#
|
||||
|
||||
_unpack_decorr_mono_pass_cont_x86:
|
||||
unpack_decorr_mono_pass_cont_x86:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
cld
|
||||
|
||||
mov edx, [ebp+8] # copy delta from dpp to local stack
|
||||
mov eax, [edx+4]
|
||||
push eax
|
||||
|
||||
mov edi, [ebp+12] # edi = buffer
|
||||
mov eax, [ebp+16] # get sample_count and multiply by 4
|
||||
shl eax, 2
|
||||
jz mono_done # exit now if there's nothing to do
|
||||
lea esi, [edi+eax] # else add to buffer point to make eptr
|
||||
|
||||
mov eax, [ebp+8] # get term from dpp and vector appropriately
|
||||
mov eax, [eax]
|
||||
cmp eax, 17
|
||||
je mono_17_entry
|
||||
cmp eax, 18
|
||||
je mono_18_entry
|
||||
|
||||
#
|
||||
# registers during default term processing loop:
|
||||
# edi active buffer pointer
|
||||
# esi end of buffer pointer
|
||||
# ecx weight_A
|
||||
# ebp free
|
||||
# ebx term * -4
|
||||
# eax,edx scratch
|
||||
#
|
||||
|
||||
default_mono_entry:
|
||||
imul ebx, eax, -4 # set ebx to term * -4 for decorrelation index
|
||||
mov edx, [ebp+8] # edx = dpp*
|
||||
mov ecx, [edx+8] # ecx = weight
|
||||
jmp default_mono_loop
|
||||
|
||||
#
|
||||
# registers during processing loop for terms 17 & 18:
|
||||
# edi active buffer pointer
|
||||
# esi end of buffer pointer
|
||||
# ecx weight_A
|
||||
# ebp previously calculated value
|
||||
# ebx calculated correlation sample
|
||||
# eax,edx scratch
|
||||
#
|
||||
|
||||
mono_17_entry:
|
||||
mov edx, [ebp+8] # edx = dpp*
|
||||
mov ecx, [edx+8] # ecx = weight_A
|
||||
mov ebp, [edi-4]
|
||||
jmp mono_17_loop
|
||||
|
||||
mono_18_entry:
|
||||
mov edx, [ebp+8] # edx = dpp*
|
||||
mov ecx, [edx+8] # ecx = weight_A
|
||||
mov ebp, [edi-4]
|
||||
jmp mono_18_loop
|
||||
|
||||
.balign 64
|
||||
default_mono_loop:
|
||||
mov eax, [edi+ebx]
|
||||
imul eax, ecx
|
||||
mov edx, [edi]
|
||||
jo long_default_mono_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [edi], eax
|
||||
mov eax, [edi+ebx]
|
||||
add edi, 4
|
||||
test edx, edx
|
||||
je L100
|
||||
test eax, eax
|
||||
je L100
|
||||
xor eax, edx
|
||||
cdq
|
||||
xor ecx, edx
|
||||
add ecx, [esp]
|
||||
xor ecx, edx
|
||||
L100: cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb default_mono_loop
|
||||
jmp default_mono_done
|
||||
|
||||
.balign 64
|
||||
long_default_mono_loop:
|
||||
mov eax, [edi+ebx]
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
mov [edi], eax
|
||||
mov eax, [edi+ebx]
|
||||
add edi, 4
|
||||
test edx, edx
|
||||
je L101
|
||||
test eax, eax
|
||||
je L101
|
||||
xor eax, edx
|
||||
cdq
|
||||
xor ecx, edx
|
||||
add ecx, [esp]
|
||||
xor ecx, edx
|
||||
L101: cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb long_default_mono_loop
|
||||
|
||||
default_mono_done:
|
||||
mov edx, [ebp+8] # edx = dpp*
|
||||
mov [edx+8], ecx # store weight_A back
|
||||
mov ecx, [edx] # ecx = dpp->term
|
||||
|
||||
default_mono_store_samples:
|
||||
dec ecx
|
||||
sub edi, 4 # back up one full sample
|
||||
mov eax, [edi]
|
||||
mov [edx+ecx*4+16], eax # store samples_A [ecx]
|
||||
test ecx, ecx
|
||||
jnz default_mono_store_samples
|
||||
jmp mono_done
|
||||
|
||||
.balign 64
|
||||
mono_17_loop:
|
||||
lea ebx, [ebp+ebp]
|
||||
sub ebx, [edi-8]
|
||||
mov eax, ecx
|
||||
imul eax, ebx
|
||||
mov edx, [edi]
|
||||
jo long_mono_17_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L117
|
||||
test edx, edx
|
||||
je L117
|
||||
mov eax, [esp]
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor eax, ebx
|
||||
sub eax, ebx
|
||||
add ecx, eax
|
||||
L117: cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb mono_17_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
.balign 64
|
||||
long_mono_17_loop:
|
||||
lea ebx, [ebp+ebp]
|
||||
sub ebx, [edi-8]
|
||||
mov eax, ecx
|
||||
imul ebx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L217
|
||||
test edx, edx
|
||||
je L217
|
||||
mov eax, [esp]
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor eax, ebx
|
||||
sub eax, ebx
|
||||
add ecx, eax
|
||||
L217: cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb long_mono_17_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
.balign 64
|
||||
mono_18_loop:
|
||||
lea ebx, [ebp+ebp*2]
|
||||
sub ebx, [edi-8]
|
||||
sar ebx, 1
|
||||
mov eax, ecx
|
||||
imul eax, ebx
|
||||
mov edx, [edi]
|
||||
jo long_mono_18_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L118
|
||||
test edx, edx
|
||||
je L118
|
||||
mov eax, [esp]
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor eax, ebx
|
||||
sub eax, ebx
|
||||
add ecx, eax
|
||||
L118: cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb mono_18_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
.balign 64
|
||||
long_mono_18_loop:
|
||||
lea ebx, [ebp+ebp*2]
|
||||
sub ebx, [edi-8]
|
||||
sar ebx, 1
|
||||
mov eax, ecx
|
||||
imul ebx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L218
|
||||
test edx, edx
|
||||
je L218
|
||||
mov eax, [esp]
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor eax, ebx
|
||||
sub eax, ebx
|
||||
add ecx, eax
|
||||
L218: cmp edi, esi # compare bptr and eptr to see if we're done
|
||||
jb long_mono_18_loop
|
||||
|
||||
mono_1718_exit:
|
||||
lea ebp, [esp+16] # restore ebp (we've pushed 4 DWORDS)
|
||||
mov edx, [ebp+8] # edx = dpp*
|
||||
mov [edx+8], ecx # store weight_A back
|
||||
mov eax, [edi-4] # dpp->samples_A [0] = bptr [-1];
|
||||
mov [edx+16], eax
|
||||
mov eax, [edi-8] # dpp->samples_A [1] = bptr [-2];
|
||||
mov [edx+20], eax
|
||||
|
||||
mono_done:
|
||||
pop eax # pop delta & saved regs
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
# Helper function to determine if specified CPU feature is available (used here for MMX).
|
||||
# Input parameter is index of feature to be checked (EDX from CPUID(1) only, MMX = 23).
|
||||
# Return value is the specified bit (0 or 1) or 0 if CPUID is not supported.
|
||||
|
||||
_unpack_cpu_has_feature_x86:
|
||||
unpack_cpu_has_feature_x86:
|
||||
pushfd # save eflags
|
||||
pushfd # push another copy
|
||||
xor dword ptr [esp], 0x200000 # toggle ID bit on stack & pop it back into eflags
|
||||
popfd
|
||||
pushfd # store possibly modified eflags
|
||||
pop eax # and pop back into eax
|
||||
xor eax, [esp] # compare to original pushed eflags
|
||||
popfd # restore original eflags
|
||||
and eax, 0x200000 # eax = 1 if eflags ID bit was changable
|
||||
jz oldcpu # return zero if CPUID is not available (wow!)
|
||||
|
||||
push ebx # we must save ebx
|
||||
mov eax, 1 # do cpuid (1) to get features into edx
|
||||
cpuid
|
||||
mov eax, edx # copy into eax for shift
|
||||
mov cl, [esp+8] # get parameter and shift that bit index into LSB
|
||||
sar eax, cl
|
||||
and eax, 1
|
||||
pop ebx # restore ebx and return 0 or 1
|
||||
|
||||
oldcpu: ret # return value in eax
|
||||
|
||||
#ifdef __ELF__
|
||||
.section .note.GNU-stack,"",@progbits
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,958 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; **** WAVPACK **** ;;
|
||||
;; Hybrid Lossless Wavefile Compressor ;;
|
||||
;; Copyright (c) 1998 - 2015 Conifer Software. ;;
|
||||
;; All Rights Reserved. ;;
|
||||
;; Distributed under the BSD Software License (see license.txt) ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
.686
|
||||
.mmx
|
||||
.model flat
|
||||
asmcode segment page 'CODE'
|
||||
public _unpack_decorr_stereo_pass_cont_x86
|
||||
public _unpack_decorr_mono_pass_cont_x86
|
||||
public _unpack_cpu_has_feature_x86
|
||||
|
||||
; This is an assembly optimized version of the following WavPack function:
|
||||
;
|
||||
; void unpack_decorr_stereo_pass_cont (struct decorr_pass *dpp,
|
||||
; int32_t *buffer,
|
||||
; int32_t sample_count,
|
||||
; int32_t long_math;
|
||||
;
|
||||
; It performs a single pass of stereo decorrelation on the provided buffer.
|
||||
; Note that this version of the function requires that up to 8 previous
|
||||
; stereo samples are visible and correct. In other words, it ignores the
|
||||
; "samples_*" fields in the decorr_pass structure and gets the history data
|
||||
; directly from the buffer. It does, however, return the appropriate history
|
||||
; samples to the decorr_pass structure before returning.
|
||||
;
|
||||
; The "long_math" argument is used to specify that a 32-bit multiply is
|
||||
; not enough for the "apply_weight" operation (although in this case it
|
||||
; would only apply to the -1 and -2 terms because the MMX code does not have
|
||||
; this limitation) but we ignore the parameter and use the overflow detection
|
||||
; of the "imul" instruction to switch automatically to the "long_math" loop.
|
||||
;
|
||||
; This is written to work on an IA-32 processor and uses the MMX extensions
|
||||
; to improve the performance by processing both stereo channels together.
|
||||
; For terms -1 and -2 the MMX extensions are not usable, and so these are
|
||||
; performed independently without them.
|
||||
;
|
||||
; arguments on entry:
|
||||
;
|
||||
; struct decorr_pass *dpp [ebp+8]
|
||||
; int32_t *buffer [ebp+12]
|
||||
; int32_t sample_count [ebp+16]
|
||||
; int32_t long_math [ebp+20]
|
||||
;
|
||||
; registers after entry:
|
||||
;
|
||||
; rdi bptr
|
||||
; rsi eptr
|
||||
;
|
||||
; on stack (used for terms -1 and -2 only):
|
||||
;
|
||||
; int32_t delta DWORD [esp]
|
||||
;
|
||||
|
||||
_unpack_decorr_stereo_pass_cont_x86:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
mov edx, [ebp+8] ; copy delta from dpp to top of stack
|
||||
mov eax, [edx+4]
|
||||
push eax
|
||||
|
||||
mov edi, [ebp+12] ; edi = buffer
|
||||
mov eax, [ebp+16] ; get sample_count and divide by 8
|
||||
sal eax, 3
|
||||
jz done ; exit now if there's nothing to do
|
||||
|
||||
add eax, edi ; else add to buffer point to make eptr
|
||||
mov esi, eax
|
||||
|
||||
mov eax, [ebp+8] ; get term from dpp and vector appropriately
|
||||
mov eax, [eax]
|
||||
cmp eax, 17
|
||||
je term_17_entry
|
||||
cmp eax, 18
|
||||
je term_18_entry
|
||||
cmp eax, -1
|
||||
je term_minus_1_entry
|
||||
cmp eax, -2
|
||||
je term_minus_2_entry
|
||||
cmp eax, -3
|
||||
je term_minus_3_entry
|
||||
|
||||
;
|
||||
; registers during default term processing loop:
|
||||
; edi active buffer pointer
|
||||
; esi end of buffer pointer
|
||||
;
|
||||
; MMX:
|
||||
; mm0, mm1 scratch
|
||||
; mm2 original sample values
|
||||
; mm3 correlation samples
|
||||
; mm4 zero (for pcmpeqd)
|
||||
; mm5 weights
|
||||
; mm6 delta
|
||||
; mm7 512 (for rounding)
|
||||
;
|
||||
|
||||
default_term_entry:
|
||||
imul ebx, eax, -8 ; set ebx to term * -8 for decorrelation index
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 ; mm7 = round (512)
|
||||
mov edx, [ebp+8] ; edx = *dpp
|
||||
mov eax, [edx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 ; mm6 = delta (0-7)
|
||||
mov eax, 0FFFFh ; mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 ; mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [edx+8] ; mm5 = weight_AB masked to 16 bits
|
||||
pxor mm4, mm4 ; mm4 = zero (for pcmpeqd)
|
||||
jmp default_term_loop
|
||||
|
||||
align 64
|
||||
default_term_loop:
|
||||
movq mm3, [edi+ebx] ; mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm0, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm0, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm0, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [edi] ; mm2 = left_right
|
||||
pslld mm0, 5
|
||||
paddd mm1, mm7 ; add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm0, mm2
|
||||
paddd mm0, mm1 ; add shifted sums
|
||||
movq [edi], mm0 ; store result
|
||||
movq mm0, mm3
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 ; mm0 = sign (sam_AB ^ left_right)
|
||||
add edi, 8
|
||||
pcmpeqd mm2, mm4 ; mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm4 ; mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 ; mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 ; mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 ; and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb default_term_loop
|
||||
|
||||
pslld mm5, 16 ; sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov eax, [ebp+8] ; point to dpp
|
||||
movq [eax+8], mm5 ; put weight_AB back
|
||||
emms
|
||||
mov edx, [ebp+8] ; access dpp with edx
|
||||
mov ecx, [edx] ; ecx = dpp->term
|
||||
|
||||
default_store_samples:
|
||||
dec ecx
|
||||
sub edi, 8 ; back up one full sample
|
||||
mov eax, [edi+4]
|
||||
mov [edx+ecx*4+48], eax ; store samples_B [ecx]
|
||||
mov eax, [edi]
|
||||
mov [edx+ecx*4+16], eax ; store samples_A [ecx]
|
||||
test ecx, ecx
|
||||
jnz default_store_samples
|
||||
|
||||
jmp done
|
||||
|
||||
;
|
||||
; registers during processing loop for terms 17 & 18:
|
||||
; edi active buffer pointer
|
||||
; esi end of buffer pointer
|
||||
;
|
||||
; MMX:
|
||||
; mm0, mm1 scratch
|
||||
; mm2 original sample values
|
||||
; mm3 calculated correlation samples
|
||||
; mm4 last calculated values (so we don't need to reload)
|
||||
; mm5 weights
|
||||
; mm6 delta
|
||||
; mm7 512 (for rounding)
|
||||
;
|
||||
|
||||
term_17_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 ; mm7 = round (512)
|
||||
mov edx, [ebp+8] ; point to dpp & get delta
|
||||
mov eax, [edx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 ; mm6 = delta (0-7)
|
||||
mov eax, 0FFFFh ; mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 ; mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [edx+8] ; mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [edi-8] ; preload previous calculated values
|
||||
jmp term_17_loop
|
||||
|
||||
align 64
|
||||
term_17_loop:
|
||||
paddd mm4, mm4
|
||||
psubd mm4, [edi-16] ; mm3 = sam_AB
|
||||
movq mm3, mm4
|
||||
movq mm1, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [edi] ; mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 ; add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 ; add shifted sums
|
||||
movq mm0, mm3
|
||||
movq [edi], mm4 ; store result
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 ; mm0 = sign (sam_AB ^ left_right)
|
||||
add edi, 8
|
||||
pxor mm1, mm1 ; mm1 = zero
|
||||
pcmpeqd mm2, mm1 ; mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 ; mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 ; mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 ; mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 ; and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb term_17_loop
|
||||
|
||||
pslld mm5, 16 ; sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov eax, [ebp+8] ; point to dpp
|
||||
movq [eax+8], mm5 ; put weight_AB back
|
||||
emms
|
||||
jmp term_1718_exit
|
||||
|
||||
term_18_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 ; mm7 = round (512)
|
||||
mov edx, [ebp+8] ; point to dpp & get delta
|
||||
mov eax, [edx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 ; mm6 = delta (0-7)
|
||||
mov eax, 0FFFFh ; mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 ; mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [edx+8] ; mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [edi-8] ; preload previous calculated value
|
||||
jmp term_18_loop
|
||||
|
||||
align 64
|
||||
term_18_loop:
|
||||
movq mm3, mm4
|
||||
psubd mm3, [edi-16]
|
||||
psrad mm3, 1
|
||||
paddd mm3, mm4 ; mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm4, mm3
|
||||
paddd mm1, mm1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [edi] ; mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 ; add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 ; add shifted sums
|
||||
movq mm0, mm3
|
||||
movq [edi], mm4 ; store result
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 ; mm0 = sign (sam_AB ^ left_right)
|
||||
add edi, 8
|
||||
pxor mm1, mm1 ; mm1 = zero
|
||||
pcmpeqd mm2, mm1 ; mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 ; mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 ; mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 ; mask delta with zeros check
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm2 ; and add to weight_AB
|
||||
pxor mm5, mm0
|
||||
cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb term_18_loop
|
||||
|
||||
pslld mm5, 16 ; sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov eax, [ebp+8] ; point to dpp
|
||||
movq [eax+8], mm5 ; put weight_AB back
|
||||
emms
|
||||
|
||||
term_1718_exit:
|
||||
mov edx, [edi-4] ; dpp->samples_B [0] = bptr [-1];
|
||||
mov eax, [ebp+8]
|
||||
mov [eax+48], edx
|
||||
mov edx, [edi-8] ; dpp->samples_A [0] = bptr [-2];
|
||||
mov [eax+16], edx
|
||||
mov edx, [edi-12] ; dpp->samples_B [1] = bptr [-3];
|
||||
mov [eax+52], edx
|
||||
mov edx, [edi-16] ; dpp->samples_A [1] = bptr [-4];
|
||||
mov [eax+20], edx
|
||||
jmp done
|
||||
|
||||
;
|
||||
; registers in term -1 & -2 loops:
|
||||
;
|
||||
; eax,ebx,edx scratch
|
||||
; ecx weight_A
|
||||
; ebp weight_B
|
||||
; edi bptr
|
||||
; esi eptr
|
||||
;
|
||||
|
||||
term_minus_1_entry:
|
||||
cld ; we use stosd here...
|
||||
mov eax, [ebp+8] ; point to dpp
|
||||
mov ecx, [eax+8] ; ecx = weight_A and ebp = weight_B
|
||||
mov ebp, [eax+12]
|
||||
mov eax, [edi-4]
|
||||
jmp term_minus_1_loop
|
||||
|
||||
align 64
|
||||
term_minus_1_loop:
|
||||
mov ebx, eax
|
||||
imul eax, ecx
|
||||
mov edx, [edi]
|
||||
jo OV11
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L182
|
||||
test edx, edx
|
||||
je L182
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L183
|
||||
mov ecx, edx
|
||||
L183: xor ecx, ebx
|
||||
L182: mov ebx, eax
|
||||
imul eax, ebp
|
||||
mov edx, [edi]
|
||||
jo OV12
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L189
|
||||
test edx, edx
|
||||
je L189
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L188
|
||||
mov ebp, edx
|
||||
L188: xor ebp, ebx
|
||||
L189: cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb term_minus_1_loop
|
||||
jmp term_minus_1_done
|
||||
|
||||
OV11: mov eax, ebx ; restore previous sample into eax
|
||||
jmp long_term_minus_1_loop
|
||||
|
||||
OV12: mov eax, ebx ; restore previous sample into eax
|
||||
jmp L282
|
||||
|
||||
align 64
|
||||
long_term_minus_1_loop:
|
||||
mov ebx, eax
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L282
|
||||
test edx, edx
|
||||
je L282
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L283
|
||||
mov ecx, edx
|
||||
L283: xor ecx, ebx
|
||||
L282: mov ebx, eax
|
||||
imul ebp
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
je L289
|
||||
test edx, edx
|
||||
je L289
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L288
|
||||
mov ebp, edx
|
||||
L288: xor ebp, ebx
|
||||
L289: cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb long_term_minus_1_loop
|
||||
|
||||
term_minus_1_done:
|
||||
mov edx, ebp
|
||||
mov ebp, esp ; restore ebp (we've pushed 4 DWORDS)
|
||||
add ebp, 16
|
||||
mov eax, [ebp+8] ; point to dpp
|
||||
mov [eax+8], ecx
|
||||
mov [eax+12], edx
|
||||
mov edx, [edi-4] ; dpp->samples_A [0] = bptr [-1]
|
||||
mov [eax+16], edx
|
||||
jmp done
|
||||
|
||||
|
||||
term_minus_2_entry:
|
||||
mov eax, [ebp+8] ; point to dpp
|
||||
mov ecx, [eax+8] ; ecx = weight_A and ebp = weight_B
|
||||
mov ebp, [eax+12]
|
||||
mov eax, [edi-8]
|
||||
jmp term_minus_2_loop
|
||||
|
||||
align 64
|
||||
term_minus_2_loop:
|
||||
mov ebx, eax
|
||||
imul eax, ebp
|
||||
mov edx, [edi+4]
|
||||
jo OV21
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [edi+4], eax
|
||||
test ebx, ebx
|
||||
je L194
|
||||
test edx, edx
|
||||
je L194
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L195
|
||||
mov ebp, edx
|
||||
L195: xor ebp, ebx
|
||||
L194: mov ebx, eax
|
||||
imul eax, ecx
|
||||
mov edx, [edi]
|
||||
jo OV22
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [edi], eax
|
||||
add edi, 8
|
||||
test ebx, ebx
|
||||
je L201
|
||||
test edx, edx
|
||||
je L201
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L200
|
||||
mov ecx, edx
|
||||
L200: xor ecx, ebx
|
||||
L201: cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb term_minus_2_loop
|
||||
jmp term_minus_2_done
|
||||
|
||||
OV21: mov eax, ebx ; restore previous sample into eax
|
||||
jmp long_term_minus_2_loop
|
||||
|
||||
OV22: mov eax, ebx ; restore previous sample into eax
|
||||
jmp L294
|
||||
|
||||
align 64
|
||||
long_term_minus_2_loop:
|
||||
mov ebx, eax
|
||||
imul ebp
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi+4]
|
||||
add eax, edx
|
||||
mov [edi+4], eax
|
||||
test ebx, ebx
|
||||
je L294
|
||||
test edx, edx
|
||||
je L294
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ebp, ebx
|
||||
add ebp, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ebp, edx
|
||||
jle L295
|
||||
mov ebp, edx
|
||||
L295: xor ebp, ebx
|
||||
L294: mov ebx, eax
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
mov [edi], eax
|
||||
add edi, 8
|
||||
test ebx, ebx
|
||||
je L301
|
||||
test edx, edx
|
||||
je L301
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor ecx, ebx
|
||||
add ecx, [esp]
|
||||
mov edx, 1024
|
||||
add edx, ebx
|
||||
cmp ecx, edx
|
||||
jle L300
|
||||
mov ecx, edx
|
||||
L300: xor ecx, ebx
|
||||
L301: cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb long_term_minus_2_loop
|
||||
|
||||
term_minus_2_done:
|
||||
mov edx, ebp
|
||||
lea ebp, [esp+16] ; restore ebp (we've pushed 4 DWORDS)
|
||||
mov eax, [ebp+8] ; point to dpp
|
||||
mov [eax+8], ecx
|
||||
mov [eax+12], edx
|
||||
mov edx, [edi-8] ; dpp->samples_B [0] = bptr [-2];
|
||||
mov [eax+48], edx
|
||||
jmp done
|
||||
|
||||
;
|
||||
; registers during processing loop for term -3:
|
||||
; edi active buffer pointer
|
||||
; esi end of buffer pointer
|
||||
;
|
||||
; MMX:
|
||||
; mm0, mm1 scratch
|
||||
; mm2 original sample values
|
||||
; mm3 calculated correlation samples
|
||||
; mm4 last calculated values (so we don't need to reload)
|
||||
; mm5 weights
|
||||
; mm6 delta
|
||||
; mm7 512 (for rounding)
|
||||
;
|
||||
|
||||
term_minus_3_entry:
|
||||
mov eax, 512
|
||||
movd mm7, eax
|
||||
punpckldq mm7, mm7 ; mm7 = round (512)
|
||||
mov edx, [ebp+8] ; point to dpp & get delta
|
||||
mov eax, [edx+4]
|
||||
movd mm6, eax
|
||||
punpckldq mm6, mm6 ; mm6 = delta (0-7)
|
||||
mov eax, 0FFFFh ; mask high weights to zero for PMADDWD
|
||||
movd mm5, eax
|
||||
punpckldq mm5, mm5 ; mm5 = weight mask 0x0000FFFF0000FFFF
|
||||
pand mm5, [edx+8] ; mm5 = weight_AB masked to 16 bits
|
||||
movq mm4, [edi-8] ; preload previous calculated values
|
||||
jmp term_minus_3_loop
|
||||
|
||||
align 64
|
||||
term_minus_3_loop:
|
||||
movq mm3, mm4 ; mm3 = swap dwords (mm4)
|
||||
psrlq mm3, 32
|
||||
punpckldq mm3, mm4 ; mm3 = sam_AB
|
||||
movq mm1, mm3
|
||||
movq mm4, mm3
|
||||
pslld mm1, 1
|
||||
psrld mm4, 15
|
||||
psrlw mm1, 1
|
||||
pmaddwd mm4, mm5
|
||||
pmaddwd mm1, mm5
|
||||
movq mm2, [edi] ; mm2 = left_right
|
||||
pslld mm4, 5
|
||||
paddd mm1, mm7 ; add 512 for rounding
|
||||
psrad mm1, 10
|
||||
paddd mm4, mm2
|
||||
paddd mm4, mm1 ; add shifted sums
|
||||
movq [edi], mm4 ; store result
|
||||
movq mm0, mm3
|
||||
pxor mm0, mm2
|
||||
psrad mm0, 31 ; mm0 = sign (sam_AB ^ left_right)
|
||||
add edi, 8
|
||||
pxor mm1, mm1 ; mm1 = zero
|
||||
pcmpeqd mm2, mm1 ; mm2 = 1s if left_right was zero
|
||||
pcmpeqd mm3, mm1 ; mm3 = 1s if sam_AB was zero
|
||||
por mm2, mm3 ; mm2 = 1s if either was zero
|
||||
pandn mm2, mm6 ; mask delta with zeros check
|
||||
pcmpeqd mm1, mm1
|
||||
psubd mm1, mm7
|
||||
psubd mm1, mm7
|
||||
psubd mm1, mm0
|
||||
pxor mm5, mm0
|
||||
paddw mm5, mm1
|
||||
paddusw mm5, mm2 ; and add to weight_AB
|
||||
psubw mm5, mm1
|
||||
pxor mm5, mm0
|
||||
cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb term_minus_3_loop
|
||||
|
||||
pslld mm5, 16 ; sign-extend 16-bit weights back to dwords
|
||||
psrad mm5, 16
|
||||
mov eax, [ebp+8] ; point to dpp
|
||||
movq [eax+8], mm5 ; put weight_AB back
|
||||
emms
|
||||
mov edx, [edi-4] ; dpp->samples_A [0] = bptr [-1];
|
||||
mov eax, [ebp+8]
|
||||
mov [eax+16], edx
|
||||
mov edx, [edi-8] ; dpp->samples_B [0] = bptr [-2];
|
||||
mov [eax+48], edx
|
||||
|
||||
done: pop eax ; pop delta & saved regs
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;
|
||||
; This is the mono version of the above function. It does not use MMX and does not handle negative terms.
|
||||
;
|
||||
; void unpack_decorr_mono_pass_cont (struct decorr_pass *dpp,
|
||||
; int32_t *buffer,
|
||||
; int32_t sample_count,
|
||||
; int32_t long_math;
|
||||
; arguments on entry:
|
||||
;
|
||||
; struct decorr_pass *dpp [ebp+8]
|
||||
; int32_t *buffer [ebp+12]
|
||||
; int32_t sample_count [ebp+16]
|
||||
; int32_t long_math [ebp+20]
|
||||
;
|
||||
; registers after entry:
|
||||
;
|
||||
; rdi bptr
|
||||
; rsi eptr
|
||||
;
|
||||
; on stack:
|
||||
;
|
||||
; int16_t delta DWORD [esp]
|
||||
;
|
||||
|
||||
_unpack_decorr_mono_pass_cont_x86:
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push ebx
|
||||
push esi
|
||||
push edi
|
||||
cld
|
||||
|
||||
mov edx, [ebp+8] ; copy delta from dpp to local stack
|
||||
mov eax, [edx+4]
|
||||
push eax
|
||||
|
||||
mov edi, [ebp+12] ; edi = buffer
|
||||
mov eax, [ebp+16] ; get sample_count and multiply by 4
|
||||
sal eax, 2
|
||||
jz mono_done ; exit now if there's nothing to do
|
||||
lea esi, [edi+eax] ; else add to buffer point to make eptr
|
||||
|
||||
mov eax, [ebp+8] ; get term from dpp and vector appropriately
|
||||
mov eax, [eax]
|
||||
cmp eax, 17
|
||||
je mono_17_entry
|
||||
cmp eax, 18
|
||||
je mono_18_entry
|
||||
|
||||
;
|
||||
; registers during default term processing loop:
|
||||
; edi active buffer pointer
|
||||
; esi end of buffer pointer
|
||||
; ecx weight_A
|
||||
; ebp free
|
||||
; ebx term * -4
|
||||
; eax,edx scratch
|
||||
;
|
||||
|
||||
default_mono_entry:
|
||||
imul ebx, eax, -4 ; set ebx to term * -4 for decorrelation index
|
||||
mov edx, [ebp+8] ; edx = dpp*
|
||||
mov ecx, [edx+8] ; ecx = weight
|
||||
jmp default_mono_loop
|
||||
|
||||
;
|
||||
; registers during processing loop for terms 17 & 18:
|
||||
; edi active buffer pointer
|
||||
; esi end of buffer pointer
|
||||
; ecx weight_A
|
||||
; ebp previously calculated value
|
||||
; ebx calculated correlation sample
|
||||
; eax,edx scratch
|
||||
;
|
||||
|
||||
mono_17_entry:
|
||||
mov edx, [ebp+8] ; edx = dpp*
|
||||
mov ecx, [edx+8] ; ecx = weight_A
|
||||
mov ebp, [edi-4]
|
||||
jmp mono_17_loop
|
||||
|
||||
mono_18_entry:
|
||||
mov edx, [ebp+8] ; edx = dpp*
|
||||
mov ecx, [edx+8] ; ecx = weight_A
|
||||
mov ebp, [edi-4]
|
||||
jmp mono_18_loop
|
||||
|
||||
align 64
|
||||
default_mono_loop:
|
||||
mov eax, [edi+ebx]
|
||||
imul eax, ecx
|
||||
mov edx, [edi]
|
||||
jo long_default_mono_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
mov [edi], eax
|
||||
mov eax, [edi+ebx]
|
||||
add edi, 4
|
||||
test edx, edx
|
||||
je L100
|
||||
test eax, eax
|
||||
je L100
|
||||
xor eax, edx
|
||||
cdq
|
||||
xor ecx, edx
|
||||
add ecx, [esp]
|
||||
xor ecx, edx
|
||||
L100: cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb default_mono_loop
|
||||
jmp default_mono_done
|
||||
|
||||
align 64
|
||||
long_default_mono_loop:
|
||||
mov eax, [edi+ebx]
|
||||
imul ecx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
mov [edi], eax
|
||||
mov eax, [edi+ebx]
|
||||
add edi, 4
|
||||
test edx, edx
|
||||
je L101
|
||||
test eax, eax
|
||||
je L101
|
||||
xor eax, edx
|
||||
cdq
|
||||
xor ecx, edx
|
||||
add ecx, [esp]
|
||||
xor ecx, edx
|
||||
L101: cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb long_default_mono_loop
|
||||
|
||||
default_mono_done:
|
||||
mov edx, [ebp+8] ; edx = dpp*
|
||||
mov [edx+8], ecx ; store weight_A back
|
||||
mov ecx, [edx] ; ecx = dpp->term
|
||||
|
||||
default_mono_store_samples:
|
||||
dec ecx
|
||||
sub edi, 4 ; back up one full sample
|
||||
mov eax, [edi]
|
||||
mov [edx+ecx*4+16], eax ; store samples_A [ecx]
|
||||
test ecx, ecx
|
||||
jnz default_mono_store_samples
|
||||
jmp mono_done
|
||||
|
||||
align 64
|
||||
mono_17_loop:
|
||||
lea ebx, [ebp+ebp]
|
||||
sub ebx, [edi-8]
|
||||
mov eax, ecx
|
||||
imul eax, ebx
|
||||
mov edx, [edi]
|
||||
jo long_mono_17_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L117
|
||||
test edx, edx
|
||||
je L117
|
||||
mov eax, [esp]
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor eax, ebx
|
||||
sub eax, ebx
|
||||
add ecx, eax
|
||||
L117: cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb mono_17_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
align 64
|
||||
long_mono_17_loop:
|
||||
lea ebx, [ebp+ebp]
|
||||
sub ebx, [edi-8]
|
||||
mov eax, ecx
|
||||
imul ebx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L217
|
||||
test edx, edx
|
||||
je L217
|
||||
mov eax, [esp]
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor eax, ebx
|
||||
sub eax, ebx
|
||||
add ecx, eax
|
||||
L217: cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb long_mono_17_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
align 64
|
||||
mono_18_loop:
|
||||
lea ebx, [ebp+ebp*2]
|
||||
sub ebx, [edi-8]
|
||||
sar ebx, 1
|
||||
mov eax, ecx
|
||||
imul eax, ebx
|
||||
mov edx, [edi]
|
||||
jo long_mono_18_loop
|
||||
sar eax, 10
|
||||
adc eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L118
|
||||
test edx, edx
|
||||
je L118
|
||||
mov eax, [esp]
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor eax, ebx
|
||||
sub eax, ebx
|
||||
add ecx, eax
|
||||
L118: cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb mono_18_loop
|
||||
jmp mono_1718_exit
|
||||
|
||||
align 64
|
||||
long_mono_18_loop:
|
||||
lea ebx, [ebp+ebp*2]
|
||||
sub ebx, [edi-8]
|
||||
sar ebx, 1
|
||||
mov eax, ecx
|
||||
imul ebx
|
||||
shl edx, 22
|
||||
shr eax, 10
|
||||
adc eax, edx
|
||||
mov edx, [edi]
|
||||
add eax, edx
|
||||
stosd
|
||||
test ebx, ebx
|
||||
mov ebp, eax
|
||||
je L218
|
||||
test edx, edx
|
||||
je L218
|
||||
mov eax, [esp]
|
||||
xor ebx, edx
|
||||
sar ebx, 31
|
||||
xor eax, ebx
|
||||
sub eax, ebx
|
||||
add ecx, eax
|
||||
L218: cmp edi, esi ; compare bptr and eptr to see if we're done
|
||||
jb long_mono_18_loop
|
||||
|
||||
mono_1718_exit:
|
||||
lea ebp, [esp+16] ; restore ebp (we've pushed 4 DWORDS)
|
||||
mov edx, [ebp+8] ; edx = dpp*
|
||||
mov [edx+8], ecx ; store weight_A back
|
||||
mov eax, [edi-4] ; dpp->samples_A [0] = bptr [-1];
|
||||
mov [edx+16], eax
|
||||
mov eax, [edi-8] ; dpp->samples_A [1] = bptr [-2];
|
||||
mov [edx+20], eax
|
||||
|
||||
mono_done:
|
||||
pop eax ; pop delta & saved regs
|
||||
pop edi
|
||||
pop esi
|
||||
pop ebx
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
; Helper function to determine if specified CPU feature is available (used here for MMX).
|
||||
; Input parameter is index of feature to be checked (EDX from CPUID(1) only, MMX = 23).
|
||||
; Return value is the specified bit (0 or 1) or 0 if CPUID is not supported.
|
||||
|
||||
_unpack_cpu_has_feature_x86:
|
||||
pushfd ; save eflags
|
||||
pushfd ; push another copy
|
||||
xor dword ptr [esp], 200000h ; toggle ID bit on stack & pop it back into eflags
|
||||
popfd
|
||||
pushfd ; store possibly modified eflags
|
||||
pop eax ; and pop back into eax
|
||||
xor eax, [esp] ; compare to original pushed eflags
|
||||
popfd ; restore original eflags
|
||||
and eax, 200000h ; eax = 1 if eflags ID bit was changable
|
||||
jz oldcpu ; return zero if CPUID is not available (wow!)
|
||||
|
||||
push ebx ; we must save ebx
|
||||
mov eax, 1 ; do cpuid (1) to get features into edx
|
||||
cpuid
|
||||
mov eax, edx ; copy into eax for shift
|
||||
mov cl, [esp+8] ; get parameter and shift that bit index into LSB
|
||||
sar eax, cl
|
||||
and eax, 1
|
||||
pop ebx ; restore ebx and return 0 or 1
|
||||
|
||||
oldcpu: ret ; return value in eax
|
||||
|
||||
asmcode ends
|
||||
|
||||
end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,688 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// **** WAVPACK **** //
|
||||
// Hybrid Lossless Wavefile Compressor //
|
||||
// Copyright (c) 1998 - 2013 Conifer Software. //
|
||||
// All Rights Reserved. //
|
||||
// Distributed under the BSD Software License (see license.txt) //
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// write_words.c
|
||||
|
||||
// This module provides entropy word encoding functions using
|
||||
// a variation on the Rice method. This was introduced in version 3.93
|
||||
// because it allows splitting the data into a "lossy" stream and a
|
||||
// "correction" stream in a very efficient manner and is therefore ideal
|
||||
// for the "hybrid" mode. For 4.0, the efficiency of this method was
|
||||
// significantly improved by moving away from the normal Rice restriction of
|
||||
// using powers of two for the modulus divisions and now the method can be
|
||||
// used for both hybrid and pure lossless encoding.
|
||||
|
||||
// Samples are divided by median probabilities at 5/7 (71.43%), 10/49 (20.41%),
|
||||
// and 20/343 (5.83%). Each zone has 3.5 times fewer samples than the
|
||||
// previous. Using standard Rice coding on this data would result in 1.4
|
||||
// bits per sample average (not counting sign bit). However, there is a
|
||||
// very simple encoding that is over 99% efficient with this data and
|
||||
// results in about 1.22 bits per sample.
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "wavpack_local.h"
|
||||
|
||||
///////////////////////////// executable code ////////////////////////////////
|
||||
|
||||
// Initialize entropy encoder for the specified stream. In lossless mode there
|
||||
// are no parameters to select; in hybrid mode the bitrate mode and value need
|
||||
// be initialized.
|
||||
|
||||
static void word_set_bitrate (WavpackStream *wps);
|
||||
|
||||
void init_words (WavpackStream *wps)
|
||||
{
|
||||
CLEAR (wps->w);
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_FLAG)
|
||||
word_set_bitrate (wps);
|
||||
}
|
||||
|
||||
// Set up parameters for hybrid mode based on header flags and "bits" field.
|
||||
// This is currently only set up for the HYBRID_BITRATE mode in which the
|
||||
// allowed error varies with the residual level (from "slow_level"). The
|
||||
// simpler mode (which is not used yet) has the error level directly
|
||||
// controlled from the metadata.
|
||||
|
||||
static void word_set_bitrate (WavpackStream *wps)
|
||||
{
|
||||
int bitrate_0, bitrate_1;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
if (wps->wphdr.flags & FALSE_STEREO)
|
||||
bitrate_0 = (wps->bits * 2 - 512) < 568 ? 0 : (wps->bits * 2 - 512) - 568;
|
||||
else
|
||||
bitrate_0 = wps->bits < 568 ? 0 : wps->bits - 568;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BALANCE)
|
||||
bitrate_1 = (wps->wphdr.flags & JOINT_STEREO) ? 256 : 0;
|
||||
else {
|
||||
bitrate_1 = bitrate_0;
|
||||
|
||||
if (wps->wphdr.flags & JOINT_STEREO) {
|
||||
if (bitrate_0 < 128) {
|
||||
bitrate_1 += bitrate_0;
|
||||
bitrate_0 = 0;
|
||||
}
|
||||
else {
|
||||
bitrate_0 -= 128;
|
||||
bitrate_1 += 128;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
bitrate_1 = 0;
|
||||
}
|
||||
else
|
||||
bitrate_0 = bitrate_1 = 0;
|
||||
|
||||
wps->w.bitrate_acc [0] = (int32_t) bitrate_0 << 16;
|
||||
wps->w.bitrate_acc [1] = (int32_t) bitrate_1 << 16;
|
||||
}
|
||||
|
||||
// Allocates the correct space in the metadata structure and writes the
|
||||
// current median values to it. Values are converted from 32-bit unsigned
|
||||
// to our internal 16-bit wp_log2 values, and read_entropy_vars () is called
|
||||
// to read the values back because we must compensate for the loss through
|
||||
// the log function.
|
||||
|
||||
void write_entropy_vars (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char *byteptr;
|
||||
int temp;
|
||||
|
||||
byteptr = wpmd->data = malloc (12);
|
||||
wpmd->id = ID_ENTROPY_VARS;
|
||||
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [0]);
|
||||
*byteptr++ = temp >> 8;
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [1]);
|
||||
*byteptr++ = temp >> 8;
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [0].median [2]);
|
||||
*byteptr++ = temp >> 8;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [0]);
|
||||
*byteptr++ = temp >> 8;
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [1]);
|
||||
*byteptr++ = temp >> 8;
|
||||
*byteptr++ = temp = wp_log2 (wps->w.c [1].median [2]);
|
||||
*byteptr++ = temp >> 8;
|
||||
}
|
||||
|
||||
wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data);
|
||||
read_entropy_vars (wps, wpmd);
|
||||
}
|
||||
|
||||
// Allocates enough space in the metadata structure and writes the current
|
||||
// high word of the bitrate accumulator and the slow_level values to it. The
|
||||
// slow_level values are converted from 32-bit unsigned to our internal 16-bit
|
||||
// wp_log2 values. Afterward, read_entropy_vars () is called to read the values
|
||||
// back because we must compensate for the loss through the log function and
|
||||
// the truncation of the bitrate.
|
||||
|
||||
void write_hybrid_profile (WavpackStream *wps, WavpackMetadata *wpmd)
|
||||
{
|
||||
unsigned char *byteptr;
|
||||
int temp;
|
||||
|
||||
word_set_bitrate (wps);
|
||||
byteptr = wpmd->data = malloc (512);
|
||||
wpmd->id = ID_HYBRID_PROFILE;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
*byteptr++ = temp = wp_log2s (wps->w.c [0].slow_level);
|
||||
*byteptr++ = temp >> 8;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
*byteptr++ = temp = wp_log2s (wps->w.c [1].slow_level);
|
||||
*byteptr++ = temp >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
*byteptr++ = temp = wps->w.bitrate_acc [0] >> 16;
|
||||
*byteptr++ = temp >> 8;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
*byteptr++ = temp = wps->w.bitrate_acc [1] >> 16;
|
||||
*byteptr++ = temp >> 8;
|
||||
}
|
||||
|
||||
if (wps->w.bitrate_delta [0] | wps->w.bitrate_delta [1]) {
|
||||
*byteptr++ = temp = wp_log2s (wps->w.bitrate_delta [0]);
|
||||
*byteptr++ = temp >> 8;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA)) {
|
||||
*byteptr++ = temp = wp_log2s (wps->w.bitrate_delta [1]);
|
||||
*byteptr++ = temp >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
wpmd->byte_length = (int32_t)(byteptr - (unsigned char *) wpmd->data);
|
||||
read_hybrid_profile (wps, wpmd);
|
||||
}
|
||||
|
||||
// This function writes the specified word to the open bitstream "wvbits" and,
|
||||
// if the bitstream "wvcbits" is open, writes any correction data there. This
|
||||
// function will work for either lossless or hybrid but because a version
|
||||
// optimized for lossless exits below, it would normally be used for the hybrid
|
||||
// mode only. The return value is the actual value stored to the stream (even
|
||||
// if a correction file is being created) and is used as feedback to the
|
||||
// predictor.
|
||||
|
||||
int32_t FASTCALL send_word (WavpackStream *wps, int32_t value, int chan)
|
||||
{
|
||||
struct entropy_data *c = wps->w.c + chan;
|
||||
uint32_t ones_count, low, mid, high;
|
||||
int sign = (value < 0) ? 1 : 0;
|
||||
|
||||
if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) {
|
||||
if (wps->w.zeros_acc) {
|
||||
if (value)
|
||||
flush_word (wps);
|
||||
else {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
wps->w.zeros_acc++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (value)
|
||||
putbit_0 (&wps->wvbits);
|
||||
else {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
CLEAR (wps->w.c [0].median);
|
||||
CLEAR (wps->w.c [1].median);
|
||||
wps->w.zeros_acc = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (sign)
|
||||
value = ~value;
|
||||
|
||||
if ((wps->wphdr.flags & HYBRID_FLAG) && !chan)
|
||||
update_error_limit (wps);
|
||||
|
||||
if (value < (int32_t) GET_MED (0)) {
|
||||
ones_count = low = 0;
|
||||
high = GET_MED (0) - 1;
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (value - low < GET_MED (1)) {
|
||||
ones_count = 1;
|
||||
high = low + GET_MED (1) - 1;
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (value - low < GET_MED (2)) {
|
||||
ones_count = 2;
|
||||
high = low + GET_MED (2) - 1;
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
ones_count = 2 + (value - low) / GET_MED (2);
|
||||
low += (ones_count - 2) * GET_MED (2);
|
||||
high = low + GET_MED (2) - 1;
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mid = (high + low + 1) >> 1;
|
||||
|
||||
if (wps->w.holding_zero) {
|
||||
if (ones_count)
|
||||
wps->w.holding_one++;
|
||||
|
||||
flush_word (wps);
|
||||
|
||||
if (ones_count) {
|
||||
wps->w.holding_zero = 1;
|
||||
ones_count--;
|
||||
}
|
||||
else
|
||||
wps->w.holding_zero = 0;
|
||||
}
|
||||
else
|
||||
wps->w.holding_zero = 1;
|
||||
|
||||
wps->w.holding_one = ones_count * 2;
|
||||
|
||||
if (!c->error_limit) {
|
||||
if (high != low) {
|
||||
uint32_t maxcode = high - low, code = value - low;
|
||||
int bitcount = count_bits (maxcode);
|
||||
uint32_t extras = bitset [bitcount] - maxcode - 1;
|
||||
|
||||
if (code < extras) {
|
||||
wps->w.pend_data |= code << wps->w.pend_count;
|
||||
wps->w.pend_count += bitcount - 1;
|
||||
}
|
||||
else {
|
||||
wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count;
|
||||
wps->w.pend_count += bitcount - 1;
|
||||
wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++;
|
||||
}
|
||||
}
|
||||
|
||||
mid = value;
|
||||
}
|
||||
else
|
||||
while (high - low > c->error_limit)
|
||||
if (value < (int32_t) mid) {
|
||||
mid = ((high = mid - 1) + low + 1) >> 1;
|
||||
wps->w.pend_count++;
|
||||
}
|
||||
else {
|
||||
mid = (high + (low = mid) + 1) >> 1;
|
||||
wps->w.pend_data |= bitset [wps->w.pend_count++];
|
||||
}
|
||||
|
||||
wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++);
|
||||
|
||||
if (!wps->w.holding_zero)
|
||||
flush_word (wps);
|
||||
|
||||
if (bs_is_open (&wps->wvcbits) && c->error_limit) {
|
||||
uint32_t code = value - low, maxcode = high - low;
|
||||
int bitcount = count_bits (maxcode);
|
||||
uint32_t extras = bitset [bitcount] - maxcode - 1;
|
||||
|
||||
if (bitcount) {
|
||||
if (code < extras)
|
||||
putbits (code, bitcount - 1, &wps->wvcbits);
|
||||
else {
|
||||
putbits ((code + extras) >> 1, bitcount - 1, &wps->wvcbits);
|
||||
putbit ((code + extras) & 1, &wps->wvcbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
c->slow_level += wp_log2 (mid);
|
||||
}
|
||||
|
||||
return sign ? ~mid : mid;
|
||||
}
|
||||
|
||||
// This function is an optimized version of send_word() that only handles
|
||||
// lossless (error_limit == 0) and sends an entire buffer of either mono or
|
||||
// stereo data rather than a single sample. Unlike the generalized
|
||||
// send_word(), it does not return values because it always encodes
|
||||
// the exact value passed.
|
||||
|
||||
void send_words_lossless (WavpackStream *wps, int32_t *buffer, int32_t nsamples)
|
||||
{
|
||||
struct entropy_data *c = wps->w.c;
|
||||
int32_t value, csamples;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
nsamples *= 2;
|
||||
|
||||
for (csamples = 0; csamples < nsamples; ++csamples) {
|
||||
int sign = ((value = *buffer++) < 0) ? 1 : 0;
|
||||
uint32_t ones_count, low, high;
|
||||
|
||||
if (!(wps->wphdr.flags & MONO_DATA))
|
||||
c = wps->w.c + (csamples & 1);
|
||||
|
||||
if (wps->w.c [0].median [0] < 2 && !wps->w.holding_zero && wps->w.c [1].median [0] < 2) {
|
||||
if (wps->w.zeros_acc) {
|
||||
if (value)
|
||||
flush_word (wps);
|
||||
else {
|
||||
wps->w.zeros_acc++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (value)
|
||||
putbit_0 (&wps->wvbits);
|
||||
else {
|
||||
CLEAR (wps->w.c [0].median);
|
||||
CLEAR (wps->w.c [1].median);
|
||||
wps->w.zeros_acc = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (sign)
|
||||
value = ~value;
|
||||
|
||||
if (value < (int32_t) GET_MED (0)) {
|
||||
ones_count = low = 0;
|
||||
high = GET_MED (0) - 1;
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (value - low < GET_MED (1)) {
|
||||
ones_count = 1;
|
||||
high = low + GET_MED (1) - 1;
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (value - low < GET_MED (2)) {
|
||||
ones_count = 2;
|
||||
high = low + GET_MED (2) - 1;
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
ones_count = 2 + (value - low) / GET_MED (2);
|
||||
low += (ones_count - 2) * GET_MED (2);
|
||||
high = low + GET_MED (2) - 1;
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wps->w.holding_zero) {
|
||||
if (ones_count)
|
||||
wps->w.holding_one++;
|
||||
|
||||
flush_word (wps);
|
||||
|
||||
if (ones_count) {
|
||||
wps->w.holding_zero = 1;
|
||||
ones_count--;
|
||||
}
|
||||
else
|
||||
wps->w.holding_zero = 0;
|
||||
}
|
||||
else
|
||||
wps->w.holding_zero = 1;
|
||||
|
||||
wps->w.holding_one = ones_count * 2;
|
||||
|
||||
if (high != low) {
|
||||
uint32_t maxcode = high - low, code = value - low;
|
||||
int bitcount = count_bits (maxcode);
|
||||
uint32_t extras = bitset [bitcount] - maxcode - 1;
|
||||
|
||||
if (code < extras) {
|
||||
wps->w.pend_data |= code << wps->w.pend_count;
|
||||
wps->w.pend_count += bitcount - 1;
|
||||
}
|
||||
else {
|
||||
wps->w.pend_data |= ((code + extras) >> 1) << wps->w.pend_count;
|
||||
wps->w.pend_count += bitcount - 1;
|
||||
wps->w.pend_data |= ((code + extras) & 1) << wps->w.pend_count++;
|
||||
}
|
||||
}
|
||||
|
||||
wps->w.pend_data |= ((int32_t) sign << wps->w.pend_count++);
|
||||
|
||||
if (!wps->w.holding_zero)
|
||||
flush_word (wps);
|
||||
}
|
||||
}
|
||||
|
||||
// Used by send_word() and send_word_lossless() to actually send most the
|
||||
// accumulated data onto the bitstream. This is also called directly from
|
||||
// clients when all words have been sent.
|
||||
|
||||
void flush_word (WavpackStream *wps)
|
||||
{
|
||||
if (wps->w.zeros_acc) {
|
||||
int cbits = count_bits (wps->w.zeros_acc);
|
||||
|
||||
while (cbits--)
|
||||
putbit_1 (&wps->wvbits);
|
||||
|
||||
putbit_0 (&wps->wvbits);
|
||||
|
||||
while (wps->w.zeros_acc > 1) {
|
||||
putbit (wps->w.zeros_acc & 1, &wps->wvbits);
|
||||
wps->w.zeros_acc >>= 1;
|
||||
}
|
||||
|
||||
wps->w.zeros_acc = 0;
|
||||
}
|
||||
|
||||
if (wps->w.holding_one) {
|
||||
#ifdef LIMIT_ONES
|
||||
if (wps->w.holding_one >= LIMIT_ONES) {
|
||||
int cbits;
|
||||
|
||||
putbits ((1L << LIMIT_ONES) - 1, LIMIT_ONES + 1, &wps->wvbits);
|
||||
wps->w.holding_one -= LIMIT_ONES;
|
||||
cbits = count_bits (wps->w.holding_one);
|
||||
|
||||
while (cbits--)
|
||||
putbit_1 (&wps->wvbits);
|
||||
|
||||
putbit_0 (&wps->wvbits);
|
||||
|
||||
while (wps->w.holding_one > 1) {
|
||||
putbit (wps->w.holding_one & 1, &wps->wvbits);
|
||||
wps->w.holding_one >>= 1;
|
||||
}
|
||||
|
||||
wps->w.holding_zero = 0;
|
||||
}
|
||||
else
|
||||
putbits (bitmask [wps->w.holding_one], wps->w.holding_one, &wps->wvbits);
|
||||
|
||||
wps->w.holding_one = 0;
|
||||
#else
|
||||
do {
|
||||
putbit_1 (&wps->wvbits);
|
||||
} while (--wps->w.holding_one);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (wps->w.holding_zero) {
|
||||
putbit_0 (&wps->wvbits);
|
||||
wps->w.holding_zero = 0;
|
||||
}
|
||||
|
||||
if (wps->w.pend_count) {
|
||||
putbits (wps->w.pend_data, wps->w.pend_count, &wps->wvbits);
|
||||
wps->w.pend_data = wps->w.pend_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This function is similar to send_word() except that no data is actually
|
||||
// written to any stream, but it does return the value that would have been
|
||||
// sent to a hybrid stream. It is used to determine beforehand how much noise
|
||||
// will be added to samples.
|
||||
|
||||
int32_t nosend_word (WavpackStream *wps, int32_t value, int chan)
|
||||
{
|
||||
struct entropy_data *c = wps->w.c + chan;
|
||||
uint32_t ones_count, low, mid, high;
|
||||
int sign = (value < 0) ? 1 : 0;
|
||||
|
||||
if (sign)
|
||||
value = ~value;
|
||||
|
||||
if ((wps->wphdr.flags & HYBRID_FLAG) && !chan)
|
||||
update_error_limit (wps);
|
||||
|
||||
if (value < (int32_t) GET_MED (0)) {
|
||||
low = 0;
|
||||
high = GET_MED (0) - 1;
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (value - low < GET_MED (1)) {
|
||||
high = low + GET_MED (1) - 1;
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (value - low < GET_MED (2)) {
|
||||
high = low + GET_MED (2) - 1;
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
ones_count = 2 + (value - low) / GET_MED (2);
|
||||
low += (ones_count - 2) * GET_MED (2);
|
||||
high = low + GET_MED (2) - 1;
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mid = (high + low + 1) >> 1;
|
||||
|
||||
if (!c->error_limit)
|
||||
mid = value;
|
||||
else
|
||||
while (high - low > c->error_limit)
|
||||
if (value < (int32_t) mid)
|
||||
mid = ((high = mid - 1) + low + 1) >> 1;
|
||||
else
|
||||
mid = (high + (low = mid) + 1) >> 1;
|
||||
|
||||
c->slow_level -= (c->slow_level + SLO) >> SLS;
|
||||
c->slow_level += wp_log2 (mid);
|
||||
|
||||
return sign ? ~mid : mid;
|
||||
}
|
||||
|
||||
// This function is used to scan some number of samples to set the variables
|
||||
// "slow_level" and the "median" array. In pure symetrical encoding mode this
|
||||
// would not be needed because these values would simply be continued from the
|
||||
// previous block. However, in the -X modes and the 32-bit modes we cannot do
|
||||
// this because parameters may change between blocks and the variables might
|
||||
// not apply. This function can work in mono or stereo and can scan a block
|
||||
// in either direction.
|
||||
|
||||
static void scan_word_pass (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir)
|
||||
{
|
||||
uint32_t flags = wps->wphdr.flags, value, low;
|
||||
struct entropy_data *c = wps->w.c;
|
||||
int chan;
|
||||
|
||||
if (flags & MONO_DATA) {
|
||||
if (dir < 0) {
|
||||
samples += (num_samples - 1);
|
||||
dir = -1;
|
||||
}
|
||||
else
|
||||
dir = 1;
|
||||
}
|
||||
else {
|
||||
if (dir < 0) {
|
||||
samples += (num_samples - 1) * 2;
|
||||
dir = -2;
|
||||
}
|
||||
else
|
||||
dir = 2;
|
||||
}
|
||||
|
||||
while (num_samples--) {
|
||||
|
||||
value = labs (samples [chan = 0]);
|
||||
|
||||
if (flags & HYBRID_BITRATE) {
|
||||
wps->w.c [0].slow_level -= (wps->w.c [0].slow_level + SLO) >> SLS;
|
||||
wps->w.c [0].slow_level += wp_log2 (value);
|
||||
}
|
||||
|
||||
if (value < GET_MED (0)) {
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (value - low < GET_MED (1)) {
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (value - low < GET_MED (2)) {
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & MONO_DATA)) {
|
||||
value = labs (samples [chan = 1]);
|
||||
c++;
|
||||
|
||||
if (wps->wphdr.flags & HYBRID_BITRATE) {
|
||||
wps->w.c [1].slow_level -= (wps->w.c [1].slow_level + SLO) >> SLS;
|
||||
wps->w.c [1].slow_level += wp_log2 (value);
|
||||
}
|
||||
|
||||
if (value < GET_MED (0)) {
|
||||
DEC_MED0 ();
|
||||
}
|
||||
else {
|
||||
low = GET_MED (0);
|
||||
INC_MED0 ();
|
||||
|
||||
if (value - low < GET_MED (1)) {
|
||||
DEC_MED1 ();
|
||||
}
|
||||
else {
|
||||
low += GET_MED (1);
|
||||
INC_MED1 ();
|
||||
|
||||
if (value - low < GET_MED (2)) {
|
||||
DEC_MED2 ();
|
||||
}
|
||||
else {
|
||||
INC_MED2 ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c--;
|
||||
}
|
||||
|
||||
samples += dir;
|
||||
}
|
||||
}
|
||||
|
||||
// Wrapper for scan_word_pass() than ensures that at least 2048 samples are processed by
|
||||
// potentially making multiple passes through the data. See description of scan_word_pass()
|
||||
// for more details.
|
||||
|
||||
void scan_word (WavpackStream *wps, int32_t *samples, uint32_t num_samples, int dir)
|
||||
{
|
||||
init_words (wps);
|
||||
|
||||
if (num_samples) {
|
||||
int passes = (2048 + num_samples - 1) / num_samples; // i.e., ceil (2048.0 / num_samples)
|
||||
|
||||
while (passes--)
|
||||
scan_word_pass (wps, samples, num_samples, dir);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue