From e342ad80c2c699ea6018b0db6f23ea5cadea913f Mon Sep 17 00:00:00 2001 From: chudov Date: Wed, 15 Oct 2008 00:34:23 +0000 Subject: [PATCH] x64 build for wavpack, library updated to 4.5.0 --- CUETools/CUETools.sln | 30 +- WavPackDotNet/WavPack/libwavpack.lib | Bin 194614 -> 0 bytes WavPackDotNet/WavPackDotNet.cpp | 11 +- WavPackDotNet/WavPackDotNet.vcproj | 158 +- wavpack-4.4.1/include/wavpack.h | 300 -- wavpack-4.5.0/ChangeLog | 379 +++ wavpack-4.5.0/README | 103 + .../include}/wavpack.h | 12 +- wavpack-4.5.0/license.txt | 25 + wavpack-4.5.0/src/bits.c | 271 ++ wavpack-4.5.0/src/extra1.c | 671 ++++ wavpack-4.5.0/src/extra2.c | 1355 ++++++++ wavpack-4.5.0/src/float.c | 371 ++ wavpack-4.5.0/src/libwavpack.sln | 26 + wavpack-4.5.0/src/libwavpack.vcproj | 359 ++ wavpack-4.5.0/src/metadata.c | 313 ++ wavpack-4.5.0/src/pack.c | 2992 +++++++++++++++++ wavpack-4.5.0/src/unpack.c | 1399 ++++++++ wavpack-4.5.0/src/unpack3.c | 2195 ++++++++++++ wavpack-4.5.0/src/unpack3.h | 113 + .../src/wavpack_local.h | 36 +- wavpack-4.5.0/src/wavpack_version.h | 19 + wavpack-4.5.0/src/words.c | 1468 ++++++++ .../src/wputils.c | 145 +- 24 files changed, 12372 insertions(+), 379 deletions(-) delete mode 100644 WavPackDotNet/WavPack/libwavpack.lib delete mode 100644 wavpack-4.4.1/include/wavpack.h create mode 100644 wavpack-4.5.0/ChangeLog create mode 100644 wavpack-4.5.0/README rename {WavPackDotNet/WavPack => wavpack-4.5.0/include}/wavpack.h (95%) create mode 100644 wavpack-4.5.0/license.txt create mode 100644 wavpack-4.5.0/src/bits.c create mode 100644 wavpack-4.5.0/src/extra1.c create mode 100644 wavpack-4.5.0/src/extra2.c create mode 100644 wavpack-4.5.0/src/float.c create mode 100644 wavpack-4.5.0/src/libwavpack.sln create mode 100644 wavpack-4.5.0/src/libwavpack.vcproj create mode 100644 wavpack-4.5.0/src/metadata.c create mode 100644 wavpack-4.5.0/src/pack.c create mode 100644 wavpack-4.5.0/src/unpack.c create mode 100644 wavpack-4.5.0/src/unpack3.c create mode 100644 wavpack-4.5.0/src/unpack3.h rename {wavpack-4.4.1 => wavpack-4.5.0}/src/wavpack_local.h (94%) create mode 100644 wavpack-4.5.0/src/wavpack_version.h create mode 100644 wavpack-4.5.0/src/words.c rename {wavpack-4.4.1 => wavpack-4.5.0}/src/wputils.c (95%) diff --git a/CUETools/CUETools.sln b/CUETools/CUETools.sln index f4f867a..21562dd 100644 --- a/CUETools/CUETools.sln +++ b/CUETools/CUETools.sln @@ -3,9 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 9.00 # Visual Studio 2005 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUETools", "CUETools.csproj", "{EF351583-A9CD-4530-92C3-20AC02136BC2}" ProjectSection(ProjectDependencies) = postProject - {9AE965C4-301E-4C01-B90F-297AF341ACC6} = {9AE965C4-301E-4C01-B90F-297AF341ACC6} - {E70FA90A-7012-4A52-86B5-362B699D1540} = {E70FA90A-7012-4A52-86B5-362B699D1540} {CC2E74B6-534A-43D8-9F16-AC03FE955000} = {CC2E74B6-534A-43D8-9F16-AC03FE955000} + {E70FA90A-7012-4A52-86B5-362B699D1540} = {E70FA90A-7012-4A52-86B5-362B699D1540} + {9AE965C4-301E-4C01-B90F-297AF341ACC6} = {9AE965C4-301E-4C01-B90F-297AF341ACC6} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FLACDotNet", "..\FLACDotNet\FLACDotNet.vcproj", "{E70FA90A-7012-4A52-86B5-362B699D1540}" @@ -15,8 +15,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FLACDotNet", "..\FLACDotNet EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "APEDotNet", "..\APEDotNet\APEDotNet.vcproj", "{9AE965C4-301E-4C01-B90F-297AF341ACC6}" ProjectSection(ProjectDependencies) = postProject - {CA200BCB-DFC6-4153-9BD4-785BC768B26B} = {CA200BCB-DFC6-4153-9BD4-785BC768B26B} {0B9C97D4-61B8-4294-A1DF-BA90752A1779} = {0B9C97D4-61B8-4294-A1DF-BA90752A1779} + {CA200BCB-DFC6-4153-9BD4-785BC768B26B} = {CA200BCB-DFC6-4153-9BD4-785BC768B26B} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CodecLibs", "CodecLibs", "{8B179853-B7D6-479C-B8B2-6CBCE835D040}" @@ -24,6 +24,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WavPackDotNet", "..\WavPackDotNet\WavPackDotNet.vcproj", "{CC2E74B6-534A-43D8-9F16-AC03FE955000}" ProjectSection(ProjectDependencies) = postProject {CA200BCB-DFC6-4153-9BD4-785BC768B26B} = {CA200BCB-DFC6-4153-9BD4-785BC768B26B} + {5CCCB9CF-0384-458F-BA08-72B73866840F} = {5CCCB9CF-0384-458F-BA08-72B73866840F} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MACLib", "..\MAC_SDK\Source\MACLib\MACLib.vcproj", "{0B9C97D4-61B8-4294-A1DF-BA90752A1779}" @@ -34,6 +35,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC_static", "..\flac\s EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "APETagDotNet", "..\APETagDotNet\APETagDotNet.csproj", "{CA200BCB-DFC6-4153-9BD4-785BC768B26B}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwavpack", "..\wavpack-4.5.0\src\libwavpack.vcproj", "{5CCCB9CF-0384-458F-BA08-72B73866840F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -93,13 +96,15 @@ Global {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Debug|Any CPU.ActiveCfg = Debug|Win32 {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Debug|Win32.ActiveCfg = Debug|Win32 {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Debug|Win32.Build.0 = Debug|Win32 - {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Debug|x64.ActiveCfg = Debug|Win32 + {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Debug|x64.ActiveCfg = Debug|x64 + {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Debug|x64.Build.0 = Debug|x64 {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Debug|x86.ActiveCfg = Debug|Win32 {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Debug|x86.Build.0 = Debug|Win32 {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Release|Any CPU.ActiveCfg = Release|Win32 {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Release|Win32.ActiveCfg = Release|Win32 {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Release|Win32.Build.0 = Release|Win32 - {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Release|x64.ActiveCfg = Release|Win32 + {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Release|x64.ActiveCfg = Release|x64 + {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Release|x64.Build.0 = Release|x64 {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Release|x86.ActiveCfg = Release|Win32 {CC2E74B6-534A-43D8-9F16-AC03FE955000}.Release|x86.Build.0 = Release|Win32 {0B9C97D4-61B8-4294-A1DF-BA90752A1779}.Debug|Any CPU.ActiveCfg = Debug|x64 @@ -146,6 +151,20 @@ Global {CA200BCB-DFC6-4153-9BD4-785BC768B26B}.Release|x64.Build.0 = Release|x64 {CA200BCB-DFC6-4153-9BD4-785BC768B26B}.Release|x86.ActiveCfg = Release|x86 {CA200BCB-DFC6-4153-9BD4-785BC768B26B}.Release|x86.Build.0 = Release|x86 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|Any CPU.ActiveCfg = Debug|x64 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|Win32.ActiveCfg = Debug|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|Win32.Build.0 = Debug|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|x64.ActiveCfg = Debug|x64 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|x64.Build.0 = Debug|x64 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|x86.ActiveCfg = Debug|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|x86.Build.0 = Debug|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|Any CPU.ActiveCfg = Release|x64 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|Win32.ActiveCfg = Release|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|Win32.Build.0 = Release|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|x64.ActiveCfg = Release|x64 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|x64.Build.0 = Release|x64 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|x86.ActiveCfg = Release|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -156,5 +175,6 @@ Global {E70FA90A-7012-4A52-86B5-362B699D1540} = {85F88959-C9E9-4989-ACB1-67BA9D1BEFE7} {0B9C97D4-61B8-4294-A1DF-BA90752A1779} = {8B179853-B7D6-479C-B8B2-6CBCE835D040} {4CEFBC84-C215-11DB-8314-0800200C9A66} = {8B179853-B7D6-479C-B8B2-6CBCE835D040} + {5CCCB9CF-0384-458F-BA08-72B73866840F} = {8B179853-B7D6-479C-B8B2-6CBCE835D040} EndGlobalSection EndGlobal diff --git a/WavPackDotNet/WavPack/libwavpack.lib b/WavPackDotNet/WavPack/libwavpack.lib deleted file mode 100644 index 66ed3a9bf84348e4ec63cb38f5f8f9da15d2fc58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194614 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 z 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 #include -#include "WavPack\wavpack.h" +#include "wavpack.h" #include -//typedef char str_ansi; -//typedef wchar_t str_utf16; -//#define BOOL int -//#define TRUE 1 -//#define FALSE 0 -//#include "..\MAC_SDK\Shared\SmartPtr.h" -//#include "..\MAC_SDK\Shared\APETag.h" namespace WavPackDotNet { int write_block(void *id, void *data, int32_t length); @@ -63,7 +56,7 @@ namespace WavPackDotNet { memcpy ((void*) pPath, (const wchar_t*)pathChars.ToPointer(), pathLen*sizeof(wchar_t)); Marshal::FreeHGlobal(pathChars); - _wpc = WavpackOpenFileInput(pPath, errorMessage, OPEN_WVC, 0); + _wpc = WavpackOpenFileInput (pPath, errorMessage, OPEN_WVC, 0); if (_wpc == NULL) { throw gcnew Exception("Unable to initialize the decoder."); } diff --git a/WavPackDotNet/WavPackDotNet.vcproj b/WavPackDotNet/WavPackDotNet.vcproj index 398d30d..8416406 100644 --- a/WavPackDotNet/WavPackDotNet.vcproj +++ b/WavPackDotNet/WavPackDotNet.vcproj @@ -11,6 +11,9 @@ + @@ -41,6 +44,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - -#if defined(_WIN32) && !defined(__MINGW32__) -#include -typedef unsigned __int64 uint64_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int8 uint8_t; -typedef __int64 int64_t; -typedef __int32 int32_t; -typedef __int16 int16_t; -typedef __int8 int8_t; -typedef float float32_t; -#else -#include -#endif - -typedef unsigned char uchar; - -#if !defined(__GNUC__) || defined(WIN32) -typedef unsigned short ushort; -typedef unsigned int uint; -#endif - -// RIFF / wav header formats (these occur at the beginning of both wav files -// and pre-4.0 WavPack files that are not in the "raw" mode). Generally, an -// application using the library to read or write WavPack files will not be -// concerned with any of these. - -typedef struct { - char ckID [4]; - uint32_t ckSize; - char formType [4]; -} RiffChunkHeader; - -typedef struct { - char ckID [4]; - uint32_t ckSize; -} ChunkHeader; - -#define ChunkHeaderFormat "4L" - -typedef struct { - ushort FormatTag, NumChannels; - uint32_t SampleRate, BytesPerSecond; - ushort BlockAlign, BitsPerSample; - ushort cbSize, ValidBitsPerSample; - int32_t ChannelMask; - ushort SubFormat; - char GUID [14]; -} WaveHeader; - -#define WaveHeaderFormat "SSLLSSSSLS" - -// This is the ONLY structure that occurs in WavPack files (as of version -// 4.0), and is the preamble to every block in both the .wv and .wvc -// files (in little-endian format). Normally, this structure has no use -// to an application using the library to read or write WavPack files, -// but if an application needs to manually parse WavPack files then this -// would be used (with appropriate endian correction). - -typedef struct { - char ckID [4]; - uint32_t ckSize; - short version; - uchar track_no, index_no; - uint32_t total_samples, block_index, block_samples, flags, crc; -} WavpackHeader; - -#define WavpackHeaderFormat "4LS2LLLLL" - -// or-values for WavpackHeader.flags -#define BYTES_STORED 3 // 1-4 bytes/sample -#define MONO_FLAG 4 // not stereo -#define HYBRID_FLAG 8 // hybrid mode -#define JOINT_STEREO 0x10 // joint stereo -#define CROSS_DECORR 0x20 // no-delay cross decorrelation -#define HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) -#define FLOAT_DATA 0x80 // ieee 32-bit floating point data - -#define INT32_DATA 0x100 // special extended int handling -#define HYBRID_BITRATE 0x200 // bitrate noise (hybrid mode only) -#define HYBRID_BALANCE 0x400 // balance noise (hybrid stereo mode only) - -#define INITIAL_BLOCK 0x800 // initial block of multichannel segment -#define FINAL_BLOCK 0x1000 // final block of multichannel segment - -#define SHIFT_LSB 13 -#define SHIFT_MASK (0x1fL << SHIFT_LSB) - -#define MAG_LSB 18 -#define MAG_MASK (0x1fL << MAG_LSB) - -#define SRATE_LSB 23 -#define SRATE_MASK (0xfL << SRATE_LSB) - -#define FALSE_STEREO 0x40000000 // block is stereo, but data is mono - -#define IGNORED_FLAGS 0x18000000 // reserved, but ignore if encountered -#define NEW_SHAPING 0x20000000 // use IIR filter for negative shaping -#define UNKNOWN_FLAGS 0x80000000 // also reserved, but refuse decode if - // encountered - -#define MONO_DATA (MONO_FLAG | FALSE_STEREO) - -#define MIN_STREAM_VERS 0x402 // lowest stream version we'll decode -#define MAX_STREAM_VERS 0x410 // highest stream version we'll decode or encode -#define CUR_STREAM_VERS 0x405 // stream version we are writing now - -// These are the mask bit definitions for the metadata chunk id byte (see format.txt) - -#define ID_UNIQUE 0x3f -#define ID_OPTIONAL_DATA 0x20 -#define ID_ODD_SIZE 0x40 -#define ID_LARGE 0x80 - -#define ID_DUMMY 0x0 -#define ID_ENCODER_INFO 0x1 -#define ID_DECORR_TERMS 0x2 -#define ID_DECORR_WEIGHTS 0x3 -#define ID_DECORR_SAMPLES 0x4 -#define ID_ENTROPY_VARS 0x5 -#define ID_HYBRID_PROFILE 0x6 -#define ID_SHAPING_WEIGHTS 0x7 -#define ID_FLOAT_INFO 0x8 -#define ID_INT32_INFO 0x9 -#define ID_WV_BITSTREAM 0xa -#define ID_WVC_BITSTREAM 0xb -#define ID_WVX_BITSTREAM 0xc -#define ID_CHANNEL_INFO 0xd - -#define ID_RIFF_HEADER (ID_OPTIONAL_DATA | 0x1) -#define ID_RIFF_TRAILER (ID_OPTIONAL_DATA | 0x2) -#define ID_REPLAY_GAIN (ID_OPTIONAL_DATA | 0x3) // never used (APEv2) -#define ID_CUESHEET (ID_OPTIONAL_DATA | 0x4) // never used (APEv2) -#define ID_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0x5) -#define ID_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x6) -#define ID_SAMPLE_RATE (ID_OPTIONAL_DATA | 0x7) - -///////////////////////// WavPack Configuration /////////////////////////////// - -// This external structure is used during encode to provide configuration to -// the encoding engine and during decoding to provide fle information back to -// the higher level functions. Not all fields are used in both modes. - -typedef struct { - float bitrate, shaping_weight; - int bits_per_sample, bytes_per_sample; - int qmode, flags, xmode, num_channels, float_norm_exp; - int32_t block_samples, extra_flags, sample_rate, channel_mask; - uchar md5_checksum [16], md5_read; - int num_tag_strings; - char **tag_strings; -} WavpackConfig; - -#define CONFIG_HYBRID_FLAG 8 // hybrid mode -#define CONFIG_JOINT_STEREO 0x10 // joint stereo -#define CONFIG_HYBRID_SHAPE 0x40 // noise shape (hybrid mode only) -#define CONFIG_FAST_FLAG 0x200 // fast mode -#define CONFIG_HIGH_FLAG 0x800 // high quality mode -#define CONFIG_VERY_HIGH_FLAG 0x1000 // very high -#define CONFIG_BITRATE_KBPS 0x2000 // bitrate is kbps, not bits / sample -#define CONFIG_SHAPE_OVERRIDE 0x8000 // shaping mode specified -#define CONFIG_JOINT_OVERRIDE 0x10000 // joint-stereo mode specified -#define CONFIG_CREATE_EXE 0x40000 // create executable -#define CONFIG_CREATE_WVC 0x80000 // create correction file -#define CONFIG_OPTIMIZE_WVC 0x100000 // maximize bybrid compression -#define CONFIG_CALC_NOISE 0x800000 // calc noise in hybrid mode -#define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode -#define CONFIG_SKIP_WVX 0x4000000 // no wvx stream w/ floats & big ints -#define CONFIG_MD5_CHECKSUM 0x8000000 // store MD5 signature -#define CONFIG_OPTIMIZE_MONO 0x80000000 // optimize for mono streams posing as stereo - -////////////// Callbacks used for reading & writing WavPack streams ////////// - -typedef struct { - int32_t (*read_bytes)(void *id, void *data, int32_t bcount); - uint32_t (*get_pos)(void *id); - int (*set_pos_abs)(void *id, uint32_t pos); - int (*set_pos_rel)(void *id, int32_t delta, int mode); - int (*push_back_byte)(void *id, int c); - uint32_t (*get_length)(void *id); - int (*can_seek)(void *id); - - // this callback is for writing edited tags only - int32_t (*write_bytes)(void *id, void *data, int32_t bcount); -} WavpackStreamReader; - -typedef int (*WavpackBlockOutput)(void *id, void *data, int32_t bcount); - -//////////////////////////// function prototypes ///////////////////////////// - -// Note: See wputils.c sourcecode for descriptions for using these functions. - -typedef void WavpackContext; - -#ifdef __cplusplus -extern "C" { -#endif - -WavpackContext *WavpackOpenFileInputEx (WavpackStreamReader *reader, void *wv_id, void *wvc_id, char *error, int flags, int norm_offset); -WavpackContext *WavpackOpenFileInput (const wchar_t *infilename, char *error, int flags, int norm_offset); - -#define OPEN_WVC 0x1 // open/read "correction" file -#define OPEN_TAGS 0x2 // read ID3v1 / APEv2 tags (seekable file) -#define OPEN_WRAPPER 0x4 // make audio wrapper available (i.e. RIFF) -#define OPEN_2CH_MAX 0x8 // open multichannel as stereo (no downmix) -#define OPEN_NORMALIZE 0x10 // normalize floating point data to +/- 1.0 -#define OPEN_STREAMING 0x20 // "streaming" mode blindly unpacks blocks - // w/o regard to header file position info -#define OPEN_EDIT_TAGS 0x40 // allow editing of tags - -int WavpackGetMode (WavpackContext *wpc); - -#define MODE_WVC 0x1 -#define MODE_LOSSLESS 0x2 -#define MODE_HYBRID 0x4 -#define MODE_FLOAT 0x8 -#define MODE_VALID_TAG 0x10 -#define MODE_HIGH 0x20 -#define MODE_FAST 0x40 -#define MODE_EXTRA 0x80 -#define MODE_APETAG 0x100 -#define MODE_SFX 0x200 -#define MODE_VERY_HIGH 0x400 -#define MODE_MD5 0x800 - -char *WavpackGetErrorMessage (WavpackContext *wpc); -int WavpackGetVersion (WavpackContext *wpc); -uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples); -uint32_t WavpackGetNumSamples (WavpackContext *wpc); -uint32_t WavpackGetSampleIndex (WavpackContext *wpc); -int WavpackGetNumErrors (WavpackContext *wpc); -int WavpackLossyBlocks (WavpackContext *wpc); -int WavpackSeekSample (WavpackContext *wpc, uint32_t sample); -WavpackContext *WavpackCloseFile (WavpackContext *wpc); -uint32_t WavpackGetSampleRate (WavpackContext *wpc); -int WavpackGetBitsPerSample (WavpackContext *wpc); -int WavpackGetBytesPerSample (WavpackContext *wpc); -int WavpackGetNumChannels (WavpackContext *wpc); -int WavpackGetChannelMask (WavpackContext *wpc); -int WavpackGetReducedChannels (WavpackContext *wpc); -int WavpackGetFloatNormExp (WavpackContext *wpc); -int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]); -uint32_t WavpackGetWrapperBytes (WavpackContext *wpc); -uchar *WavpackGetWrapperData (WavpackContext *wpc); -void WavpackFreeWrapper (WavpackContext *wpc); -void WavpackSeekTrailingWrapper (WavpackContext *wpc); -double WavpackGetProgress (WavpackContext *wpc); -uint32_t WavpackGetFileSize (WavpackContext *wpc); -double WavpackGetRatio (WavpackContext *wpc); -double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc); -double WavpackGetInstantBitrate (WavpackContext *wpc); -int WavpackGetNumTagItems (WavpackContext *wpc); -int WavpackGetTagItem (WavpackContext *wpc, const char *item, char *value, int size); -int WavpackGetTagItemIndexed (WavpackContext *wpc, int index, char *item, int size); -int WavpackAppendTagItem (WavpackContext *wpc, const char *item, const char *value, int vsize); -int WavpackDeleteTagItem (WavpackContext *wpc, const char *item); -int WavpackWriteTag (WavpackContext *wpc); - -WavpackContext *WavpackOpenFileOutput (WavpackBlockOutput blockout, void *wv_id, void *wvc_id); -int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples); -int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount); -int WavpackStoreMD5Sum (WavpackContext *wpc, uchar data [16]); -int WavpackPackInit (WavpackContext *wpc); -int WavpackPackSamples (WavpackContext *wpc, int32_t *sample_buffer, uint32_t sample_count); -int WavpackFlushSamples (WavpackContext *wpc); -void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block); -void *WavpackGetWrapperLocation (void *first_block, uint32_t *size); -double WavpackGetEncodedNoise (WavpackContext *wpc, double *peak); - -void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp); - -void WavpackLittleEndianToNative (void *data, char *format); -void WavpackNativeToLittleEndian (void *data, char *format); - -uint32_t WavpackGetLibraryVersion (); -const char *WavpackGetLibraryVersionString (); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/wavpack-4.5.0/ChangeLog b/wavpack-4.5.0/ChangeLog new file mode 100644 index 0000000..3beabfd --- /dev/null +++ b/wavpack-4.5.0/ChangeLog @@ -0,0 +1,379 @@ + ---------------------------- + Release 4.50 - June 13, 2008 + ---------------------------- + + WavPack Library Source Code - 4.50 + ---------------------------------- + added: dynamic noise shaping for improved hybrid quality + added: option to merge blocks of similar redundancy + added: ability to store and retrieve extra mode level + fixed: alignment fault on some big-endian machines + fixed: compiling with enable-mmx on gcc 4.3.x (thanks Joachim) + improved: allow bitrate to be calculated for files down to 1/10 second + improved: decoding of corrupt files (prevents heap overrun crashes) + + wavpack.exe (command-line encoder) - 4.50 + ----------------------------------------- + added: dynamic noise shaping for improved hybrid quality + added: --channel-order option to reorder nonconforming multichannel files + added: --merge-blocks option to optimize storage of LossyWAV output files + added: ignore -o on Windows for compatibility with Linux version + fixed: alignment fault on some big-endian machines + improved: reformatted and expanded --help display + + wvunpack.exe (command-line decoder) - 4.50 + ------------------------------------------ + fixed: don't ignore fractions of seconds in --skip option + added: show extra level and dns status for newer files (-s command) + added: ignore -o on Windows for compatibility with Linux version + improved: decoding of corrupt files (prevents heap overrun crashes) + improved: display bitrate for files down to 1/10 second + + in_wv.dll (winamp plugin) - 2.5 + ------------------------------- + added: transcoding API (allows CD burning, format conversion, ReplayGain calc, etc.) + added: metadata writing API (for Auto-Tag, etc.) + added: full Unicode support for info box (older Winamps) and media library + added: standard Winamp metadata display & edit for newer Winamps + added: option to pass multichannel audio + added: option to pass all audio as 16-bit (for better compatibility) + added: option to output 24-bit audio when ReplayGain is active + added: genre display to info box (older Winamps) + fixed: seek bar sometimes vacillates when moved + fixed: crash when winamp is opened with files in playlist moved or deleted + improved: hi-res audio now output as 24-bit (not 32-bit) for better compatibility (EQ, etc.) + improved: performance of adding tracks to library, especially from network drives + improved: decoding of corrupt files (prevents heap overrun crashes) + + cool_wv4.flt (CoolEdit / Audition filter) - 2.9 + ----------------------------------------------- + added: about box + added: dynamic noise shaping for improved hybrid quality + improved: display bitrate for files as short as 1/10 second + improved: decoding of corrupt files (prevents heap overrun crashes) + improved: replace "extra processing" switch with a slider (0-6) + + + -------------------------- + Release 4.41 - May 6, 2007 + -------------------------- + + WavPack Library Source Code - 4.41 + ---------------------------------- + added: create wavpackdll.dll for Windows (not used yet) + fixed: corrupt floating-point audio on big-endian machines + fixed: put MSVC projects in their own subdir (fixed build problems) + fixed: limit RIFF data buffering to 16 MB to prevent out-of-memory crash + improved: attempt to mute errors when decoding corrupt legacy WavPack files + improved: overall performance enhancements of 10% to 30% (depending on mode) + added: MMX intrinsics for 24-bit (and higher) stereo encoding (thanks to + Joachim Henke) + + wavpack.exe (command-line encoder) - 4.41 + ----------------------------------------- + fixed: corrupt floating-point audio on big-endian machines + improved: refuse to encode WAV files over 4 GB or with over 16 MB RIFF data + improved: overall performance enhancements of 10% to 30% (depending on mode) + added: MMX intrinsics for 24-bit (and higher) stereo encoding (thanks to + Joachim Henke) + + wvunpack.exe (command-line decoder) - 4.41 + ------------------------------------------ + fixed: corrupt floating-point audio on big-endian machines + fixed: restore files mistakenly encoded with huge RIFF chunks + improved: attempt to mute errors when decoding corrupt legacy WavPack files + improved: overall performance enhancements of 10% to 30% (depending on mode) + added: --skip and --until commands to unpack specified range of audio data + added: MMX intrinsics for 24-bit (and higher) stereo encoding (thanks to + Joachim Henke) + + wvgain.exe (command-line ReplayGain scanner) - 4.41 + --------------------------------------------------- + improved: overall performance enhancements of 10% to 30% (depending on mode) + added: MMX intrinsics for 24-bit (and higher) stereo encoding (thanks to + Joachim Henke) + + cool_wv4.flt (CoolEdit / Audition filter) - 2.8 + ----------------------------------------------- + fixed: read all RIFF metadata from files created in other applications + improved: attempt to mute errors when decoding corrupt legacy WavPack files + improved: overall performance enhancements of 10% to 30% (depending on mode) + added: MMX intrinsics for 24-bit (and higher) stereo encoding (thanks to + Joachim Henke) + + + ------------------------------- + Release 4.40 - December 3, 2006 + ------------------------------- + + WavPack Library Source Code - 4.40 + ---------------------------------- + added: new hardware-friendly "high" mode that compresses almost as well as + old "high" mode but decodes significantly faster; old "high" mode + now available as "very high" + added: option added to improve compression of mono material in stereo files + (requires at least version 4.3 decoder) + added: function to obtain channel mapping information on decoding + added: function to get trailing wrapper info (RIFF) without decoding file + improved: "extra" mode levels 1-3 completely revamped, fast enough for use + improved: reorganized to create a standard library that should more easily + integrate into other applications; eliminated namespace issues + improved: more robust handling of corrupt files + + wavpack.exe (command-line encoder) - 4.40 + ----------------------------------------- + added: accepts long option names including --help for full usage info + added: new hardware-friendly "high" mode that compresses almost as well as + old "high" mode but decodes significantly faster; old "high" mode + now available as "very high" (-hh) + added: --optimize-mono option added to improve compression of mono material + in stereo files (requires at least version 4.3 decoder) + improved: "extra" mode levels 1-3 completely revamped, fast enough for use + improved: switched to Microsoft Visual Studio 2005 (win32 only) + removed: support for Windows 95 + + wvunpack.exe (command-line decoder) - 4.40 + ------------------------------------------ + added: cuesheet extraction (to .cue file or stdout) + added: wav header generation on decode for files with missing RIFF + information, or forced with -w option + added: more summary info (wrapper info + channel assignments) + improved: more robust handling of corrupt files + improved: separate options for raw (-r) and blind stream decoding (-b) + improved: switched to Microsoft Visual Studio 2005 (win32 only) + removed: support for Windows 95 + + wvgain.exe (command-line ReplayGain scanner) - 4.40 + --------------------------------------------------- + improved: switched to Microsoft Visual Studio 2005 (win32 only) + removed: support for Windows 95 + + wvselfx.exe (self-extraction stub) - 4.40 + ------------------------------------------ + added: automatic cuesheet extraction (if present in APEv2 tag) + + in_wv.dll (winamp plugin) - 2.4 + ------------------------------- + fixed: quietly skips deleted files in playlist + improved: more robust handling of corrupt files + improved: APEv2 tags are read even if followed by ID3v1 tag + + cool_wv4.flt (CoolEdit / Audition filter) - 2.7 + ----------------------------------------------- + added: new hardware-friendly "high" mode that compresses almost as well as + old "high" mode but decodes significantly faster; old "high" mode + now available as "v. high" + improved: more robust handling of corrupt files + + + ---------------------- + Update - April 5, 2006 + ---------------------- + + WavPack Library Source Code - 4.32 + wavpack.exe (command-line encoder) - 4.32 + ----------------------------------------- + fixed: generating RIFF headers on big-endian machines caused crash + + + -------------------------- + Update - December 10, 2005 + -------------------------- + + wavpack.exe (command-line encoder) - 4.31 + wvunpack.exe (command-line decoder) - 4.31 + ------------------------------------------ + fixed: detect debug mode in all cases (win32 only) + improved: use latest service pack and SDK for building (win32 only) + improved: better directory choice for logging file (win32 only) + improved: allow shell to expand wildcards (*nix only) + added: option (-o) to specify output directory or path (*nix only) + added: option (-t) to copy timestamp (*nix only) + + wvgain.exe (command-line ReplayGain scanner) - 4.31 + --------------------------------------------------- + new + + WavPack Library Source Code - 4.31 + ---------------------------------- + fixed: failing seek with some files that had been played to the end + fixed: small memory leak when opening hybrid lossless files + improved: signed characters no longer must be default + improved: APEv2 tags are read even if followed by ID3v1 tag + improved: limited APEv2 tag editing capability + + + ------------------------------ + Release 4.3 - November 1, 2005 + ------------------------------ + + wavpack.exe (command-line encoder) - 4.3 + ---------------------------------------- + fixed: bug causing termination error with very wide screen widths + added: command-line option (-l) to use low priority for batch operation + added: command-line option (-r) to generate a fresh RIFF header + added: debug mode (rename to wavpack_debug.exe) + added: automatically detect lower resolution data even without -x1 + added: src and dst dirs are searched also for tag source files (handy for EAC) + added: wildcard accepted for tag source files (handy for EAC) + added: handle non-standard sampling rates + improved: returns error status for any error + improved: use longer blocks in multichannel files (better "high" compression) + + wvunpack.exe (command-line decoder) - 4.3 + ----------------------------------------- + fixed: very rare decoding bug causing overflow with hi-res files + fixed: bug causing termination error with very wide screen widths + fixed: formatting error in duration display + added: command-line option (-ss) to include tags in summary dump + added: command-line option (-l) to use low priority for batch operation + added: debug mode (rename to wvunpack_debug.exe) + improved: returns error status for any error + improved: more robust decoding of damaged (or invalid) files + + in_wv.dll (winamp plugin) - 2.3 + nxWavPack.dll (Nero plugin) - 1.2 + WavPack_Apollo.dll (Apollo plugin) - 1.3 + cool_wv4.flt (CoolEdit / Audition filter) - 2.6 + ----------------------------------------------- + fixed: very rare decoding bug causing overflow with hi-res files + improved: handle ID3v1.1 tags (now includes track number) + improved: more robust decoding of damaged (or invalid) files + added: handle non-standard sampling rates + + foo_wavpack.dll (foobar plugin) - 2.3 + ----------------------------------------------- + fixed: any error during WavPack file open caused crash if wvc file present + fixed: very rare decoding bug causing overflow with hi-res files + improved: more robust decoding of damaged (or invalid) files + added: handle non-standard sampling rates + + WavPack Library Source Code - 4.3 + --------------------------------- + fixed: very rare decoding bug causing overflow with hi-res files + added: automatic generation of RIFF wav header during encoding + added: new functions to access tags by index (instead of item name) + added: automatically detect lower resolution data during encoding + added: handle non-standard sampling rates + improved: more robust decoding of damaged (or invalid) files + improved: use longer blocks in multichannel files (better "high" compression) + improved: two structures renamed to avoid namespace conflict + removed: legacy code for Borland compiler + + + -------------------------- + Update - September 1, 2005 + -------------------------- + + wavpack.exe (command-line encoder) - 4.22 + cool_wv4.flt (CoolEdit / Audition filter) - 2.5 + ----------------------------------------------- + fixed: possible corrupt files written (24 or 32-bit + "extra" mode) + + + --------------------------- + Release 4.2 - April 2, 2005 + --------------------------- + + wavpack.exe (command-line encoder) - 4.2 + ---------------------------------------- + fixed: handling of wav files larger than 2 gig + improved: stereo lossless encoding speed (including "extra" mode) + added: -i option to ignore length specified in wav header + added: -w option to write APEv2 tags directly from command line + + wvunpack.exe (command-line decoder) - 4.2 + ----------------------------------------- + improved: decoding speed + + in_wv.dll (winamp plugin) - 2.2 + ------------------------------- + added: winamp media library support + improved: decoding speed + + foo_wavpack.dll (foobar plugin) - 2.2 + ------------------------------------- + improved: decoding speed + + nxWavPack.dll (Nero plugin) - 1.1 + Cool_wv4.flt (CoolEdit / Audition filter) - 2.4 + ----------------------------------------------- + fixed: handling of wav files larger than 2 gig + improved: encoding and decoding speed + + WavPack Library Source Code - 4.2 + --------------------------------- + improved: encoding and decoding speed + fixed: works correctly with 64-bit compilers + added: mode bit to open files in "streaming" mode + + + -------------------------- + Update - December 12, 2004 + -------------------------- + + WavPack_Apollo.dll (Apollo plugin) - 1.2 + ---------------------------------------- + fixed: crash when Apollo opened and WavPack plugin can't find config file + + + -------------------------------- + Release 4.1 - September 14, 2004 + -------------------------------- + + wavpack.exe (command-line encoder) - 4.1 + ---------------------------------------- + fixed: hybrid mode + "extra" mode + very low bitrates making corrupt files + fixed: mono or multichannel files causing crash (no corruption possible) + added: third name specification for "correction" file (EAC specific) + added: -t option to preserve timestamps + added: error summary for batch mode + + wvunpack.exe (command-line decoder) - 4.1 + ----------------------------------------- + fixed: hybrid mode decoding bugs (very obscure situations) + added: -s option to dump file summary to stdout + added: -t option to preserve timestamps + added: error summary for batch mode + + wvselfx.exe (self-extraction stub) - 4.1 + ---------------------------------------- + fixed: hybrid mode decoding bugs (very obscure situations) + + in_wv.dll (winamp plugin) - 2.1 + ------------------------------- + fixed: international characters in tags display properly (UTF-8 to Ansi) + added: maximum tag data field width changed from 64 chars to 128 chars + added: new infobox items including encoder version & modes, track #, md5 + + foo_wavpack.dll (foobar plugin) - 2.1 + ------------------------------------- + added: new database items including encoder version & modes and md5 + + WavPack_Apollo.dll (Apollo plugin) - 1.1 + ---------------------------------------- + fixed: international characters in tags display properly (UTF-8 to Ansi) + + Cool_wv4.flt (CoolEdit / Audition filter) - 2.2 + ----------------------------------------------- + fixed: hybrid mode + "extra" mode + very low bitrates making corrupt files + fixed: saving mono file causing crash (no corruption possible) + fixed: hybrid mode decoding bugs (very obscure situations) + fixed: partial saves (with "Cancel") have incorrect RIFF header if unpacked + + nxWavPack.dll (Nero plugin) - 1.0 + --------------------------------- + new + + WavPack Library Source Code - 4.1 + --------------------------------- + fixed: hybrid mode + "extra" mode + very low bitrates making corrupt files + fixed: mono or multichannel files causing crash (no corruption possible) + fixed: hybrid mode decoding bugs (very obscure situations) + added: mode bits for determining additional encode info (extra, sfx) + added: function to return total compressed file length (including wvc) + added: function to return encoder version (1, 2, 3, or 4) + added: ability to obtain MD5 sum before decoding file (requires seek to end) + added: mode bit for determining tag type (for proper character translation) + added: ability to encode WavPack files without knowing length in advance + added: option for small "information only" version of library diff --git a/wavpack-4.5.0/README b/wavpack-4.5.0/README new file mode 100644 index 0000000..fd8fe6f --- /dev/null +++ b/wavpack-4.5.0/README @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2006 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +This package contains all the source code required to build the WavPack +command-line programs and the WavPack library and it has been tested on many +platforms. + +On Windows there are solution and project files for Visual Studio 2005 and +additional sourcecode to build the CoolEdit/Audition plugin and the winamp +plugin. The CoolEdit/Audition plugin provides a good example for using the +library to both read and write WavPack files. + +To build everything on Linux, type: + +1. ./configure [--enable-mmx] +2. make +3. make install (optionally, to install into /usr/local/bin) + +If you are using the code directly from SVN (rather than a distribution) +then you will need to do a ./autogen.sh before the configure step. For +processors that support MMX, use the --enable-mmx switch to utilize MMX +intrinsics to speed up encoding of stereo 24-bit (and higher) audio. + +Notes: + +1. There are two documentation files contained in the distribution: + + doc/library_use.txt contains a detailed description of the API provided + by WavPack library appropriate for read and writing + WavPack files + + doc/file_format.txt contains a description of the WavPack file format, + including details needed for parsing WavPack blocks + and interpreting the block header and flags + + There is also a description of the WavPack algorithms in the forth edition + of David Salomon's book "Data Compression: The Complete Reference". The + section on WavPack can be found here: + + www.wavpack.com/WavPack.pdf + +2. This code is designed to be easy to port to other platforms. File I/O is + done with streams and all file functions (except "fopen") are handled in + a wrapper in the "utils.c" module. The code is endian-independent. + + To maintain compatibility on various platforms, the following conventions + are used: A "short" must be 16-bits and an "int" must be 32-bits. + The "long" type is not used. The "char" type must be 8-bits, signed or + unsigned. + +3. For WavPack file decoding, a library interface in "wputils.c" provides all + the functionality required for both the winamp plugin and the "wvunpack" + command-line program (including the transparent decoding of "correction" + files). There is also an alternate entry point that uses reader callbacks + for all input, although in this case it is the caller's responsibility to + to open the "correction" file. The header file "include/wavpack.h" + includes everything needed while hiding all the WavPack internals from the + application. + +4. For WavPack file creation, the library interface in "wputils.c" provides + all the functionality for both the Audition filter and the "wavpack" + command-line program. No file I/O is performed by the library when creating + WavPack files. Instead, the user supplies a "write_block" function that + accepts completed WavPack blocks. It is also possible to append APEv2 tags + to WavPack files during creation and edit APEv2 tags on existing files + (although there is no support currently for "binary" fields in the tags). + +5. The following #define's can be optionally used to eliminate some functionality + to create smaller binaries. It is important that they must be specified + the same for the compilation of ALL files: + + NO_UNPACK no unpacking of audio samples from WavPack files + (also don't include unpack.c) + NO_PACK no creating WavPack files from raw audio data + (also don't include pack.c, extra1.c and extra2.c) + INFO_ONLY to obtain information from WavPack files, but not audio + (also don't include pack.c, extra1.c and extra2.c) + NO_SEEKING to not allow seeking to a specific sample index (unpack only) + NO_USE_FSTREAMS to not open WavPack files by name using fstreams + NO_TAGS to not read specified fields from ID3v1 and APEv2 tags and + create APEv2 tags + VER4_ONLY to only handle WavPack files from versions 4.0 onward + WIN32 required for Win32 platform + +6. There are alternate versions of this library available specifically designed + for "resource limited" CPUs or hardware encoding and decoding. There is the + "tiny decoder" library which works with less than 32k of code and less than + 4k of data and has assembly language optimizations for the ARM and Freescale + ColdFire CPUs. The "tiny encoder" is also designed for embedded use and + handles the pure lossless, lossy, and hybrid lossless modes. Neither of the + "tiny" versions use any memory allocation functions nor do they require + floating-point arithmetic support. + + For applications requiring very low latency, there is a special version of + the library that supports a variation on the regular WavPack block format + to facilitate this. + +7. Questions or comments should be directed to david@wavpack.com diff --git a/WavPackDotNet/WavPack/wavpack.h b/wavpack-4.5.0/include/wavpack.h similarity index 95% rename from WavPackDotNet/WavPack/wavpack.h rename to wavpack-4.5.0/include/wavpack.h index 8ba9d91..ad29eb0 100644 --- a/WavPackDotNet/WavPack/wavpack.h +++ b/wavpack-4.5.0/include/wavpack.h @@ -121,7 +121,7 @@ typedef struct { #define MIN_STREAM_VERS 0x402 // lowest stream version we'll decode #define MAX_STREAM_VERS 0x410 // highest stream version we'll decode or encode -#define CUR_STREAM_VERS 0x405 // stream version we are writing now +#define CUR_STREAM_VERS 0x407 // stream version we are writing now // These are the mask bit definitions for the metadata chunk id byte (see format.txt) @@ -178,6 +178,7 @@ typedef struct { #define CONFIG_BITRATE_KBPS 0x2000 // bitrate is kbps, not bits / sample #define CONFIG_SHAPE_OVERRIDE 0x8000 // shaping mode specified #define CONFIG_JOINT_OVERRIDE 0x10000 // joint-stereo mode specified +#define CONFIG_DYNAMIC_SHAPING 0x20000 // dynamic noise shaping #define CONFIG_CREATE_EXE 0x40000 // create executable #define CONFIG_CREATE_WVC 0x80000 // create correction file #define CONFIG_OPTIMIZE_WVC 0x100000 // maximize bybrid compression @@ -185,6 +186,7 @@ typedef struct { #define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode #define CONFIG_SKIP_WVX 0x4000000 // no wvx stream w/ floats & big ints #define CONFIG_MD5_CHECKSUM 0x8000000 // store MD5 signature +#define CONFIG_MERGE_BLOCKS 0x10000000 // merge blocks of equal redundancy (for lossyWAV) #define CONFIG_OPTIMIZE_MONO 0x80000000 // optimize for mono streams posing as stereo ////////////// Callbacks used for reading & writing WavPack streams ////////// @@ -235,11 +237,13 @@ int WavpackGetMode (WavpackContext *wpc); #define MODE_VALID_TAG 0x10 #define MODE_HIGH 0x20 #define MODE_FAST 0x40 -#define MODE_EXTRA 0x80 +#define MODE_EXTRA 0x80 // extra mode used, see MODE_XMODE for possible level #define MODE_APETAG 0x100 #define MODE_SFX 0x200 #define MODE_VERY_HIGH 0x400 #define MODE_MD5 0x800 +#define MODE_XMODE 0x7000 // mask for extra level (1-6, 0=unknown) +#define MODE_DNS 0x8000 char *WavpackGetErrorMessage (WavpackContext *wpc); int WavpackGetVersion (WavpackContext *wpc); @@ -290,8 +294,8 @@ void WavpackFloatNormalize (int32_t *values, int32_t num_values, int delta_exp); void WavpackLittleEndianToNative (void *data, char *format); void WavpackNativeToLittleEndian (void *data, char *format); -uint32_t WavpackGetLibraryVersion (); -const char *WavpackGetLibraryVersionString (); +uint32_t WavpackGetLibraryVersion (void); +const char *WavpackGetLibraryVersionString (void); #ifdef __cplusplus } diff --git a/wavpack-4.5.0/license.txt b/wavpack-4.5.0/license.txt new file mode 100644 index 0000000..a20b215 --- /dev/null +++ b/wavpack-4.5.0/license.txt @@ -0,0 +1,25 @@ + Copyright (c) 1998 - 2008 Conifer Software + All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Conifer Software nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/wavpack-4.5.0/src/bits.c b/wavpack-4.5.0/src/bits.c new file mode 100644 index 0000000..097c60f --- /dev/null +++ b/wavpack-4.5.0/src/bits.c @@ -0,0 +1,271 @@ +//////////////////////////////////////////////////////////////////////////// +// **** 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 +#include +#include +#include + +#if defined(WIN32) +#include +#else +#include +#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) +{ + uchar *cp = (uchar *) 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) +{ + uchar *cp = (uchar *) data; + int32_t temp; + + while (*format) { + switch (*format) { + case 'L': + temp = * (int32_t *) cp; + *cp++ = (uchar) temp; + *cp++ = (uchar) (temp >> 8); + *cp++ = (uchar) (temp >> 16); + *cp++ = (uchar) (temp >> 24); + break; + + case 'S': + temp = * (short *) cp; + *cp++ = (uchar) temp; + *cp++ = (uchar) (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 diff --git a/wavpack-4.5.0/src/extra1.c b/wavpack-4.5.0/src/extra1.c new file mode 100644 index 0000000..4936fb6 --- /dev/null +++ b/wavpack-4.5.0/src/extra1.c @@ -0,0 +1,671 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2006 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// extra1.c + +// This module handles the "extra" mode for mono files. + +#include "wavpack_local.h" + +#include +#include +#include +#include + +//#define USE_OVERHEAD +#define LOG_LIMIT 6912 +//#define EXTRA_DUMP + +#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 + +//////////////////////////////// local tables /////////////////////////////// + +typedef struct { + int32_t *sampleptrs [MAX_NTERMS+2]; + struct decorr_pass dps [MAX_NTERMS]; + int nterms, log_limit; + uint32_t best_bits; +} WavpackExtraInfo; + +static void decorr_mono_pass (int32_t *in_samples, int32_t *out_samples, uint32_t num_samples, struct decorr_pass *dpp, int dir) +{ + int m = 0, i; + + dpp->sum_A = 0; + + if (dir < 0) { + out_samples += (num_samples - 1); + in_samples += (num_samples - 1); + dir = -1; + } + else + dir = 1; + + dpp->weight_A = restore_weight (store_weight (dpp->weight_A)); + + for (i = 0; i < 8; ++i) + dpp->samples_A [i] = exp2s (log2s (dpp->samples_A [i])); + + if (dpp->term > MAX_TERM) { + while (num_samples--) { + int32_t left, sam_A; + + if (dpp->term & 1) + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = left = in_samples [0]; + + left -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + dpp->sum_A += dpp->weight_A; + out_samples [0] = left; + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term > 0) { + while (num_samples--) { + int k = (m + dpp->term) & (MAX_TERM - 1); + int32_t left, sam_A; + + sam_A = dpp->samples_A [m]; + dpp->samples_A [k] = left = in_samples [0]; + m = (m + 1) & (MAX_TERM - 1); + + left -= apply_weight (dpp->weight_A, sam_A); + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + dpp->sum_A += dpp->weight_A; + out_samples [0] = left; + in_samples += dir; + out_samples += dir; + } + } + + if (m && dpp->term > 0 && dpp->term <= MAX_TERM) { + int32_t temp_A [MAX_TERM]; + int k; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } +} + +static void reverse_mono_decorr (struct decorr_pass *dpp) +{ + if (dpp->term > MAX_TERM) { + int32_t sam_A; + + if (dpp->term & 1) + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = sam_A; + + if (dpp->term & 1) + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = sam_A; + } + else if (dpp->term > 1) { + int i = 0, j = dpp->term - 1, cnt = dpp->term / 2; + + while (cnt--) { + i &= (MAX_TERM - 1); + j &= (MAX_TERM - 1); + dpp->samples_A [i] ^= dpp->samples_A [j]; + dpp->samples_A [j] ^= dpp->samples_A [i]; + dpp->samples_A [i++] ^= dpp->samples_A [j--]; + } + +// CLEAR (dpp->samples_A); + } +} + +static void decorr_mono_buffer (int32_t *samples, int32_t *outsamples, uint32_t num_samples, struct decorr_pass *dpp, int tindex) +{ + struct decorr_pass dp, *dppi = dpp + tindex; + int delta = dppi->delta, pre_delta, term = dppi->term; + + if (delta == 7) + pre_delta = 7; + else if (delta < 2) + pre_delta = 3; + else + pre_delta = delta + 1; + + CLEAR (dp); + dp.term = term; + dp.delta = pre_delta; + decorr_mono_pass (samples, outsamples, num_samples > 2048 ? 2048 : num_samples, &dp, -1); + dp.delta = delta; + + if (tindex == 0) + reverse_mono_decorr (&dp); + else + CLEAR (dp.samples_A); + + memcpy (dppi->samples_A, dp.samples_A, sizeof (dp.samples_A)); + dppi->weight_A = dp.weight_A; + + if (delta == 0) { + dp.delta = 1; + decorr_mono_pass (samples, outsamples, num_samples, &dp, 1); + dp.delta = 0; + memcpy (dp.samples_A, dppi->samples_A, sizeof (dp.samples_A)); + dppi->weight_A = dp.weight_A = dp.sum_A / num_samples; + } + +// if (memcmp (dppi, &dp, sizeof (dp))) +// error_line ("decorr_passes don't match, delta = %d", delta); + + decorr_mono_pass (samples, outsamples, num_samples, &dp, 1); +} + +static int log2overhead (int first_term, int num_terms) +{ +#ifdef USE_OVERHEAD + if (first_term > MAX_TERM) + return (4 + num_terms * 2) << 11; + else + return (2 + num_terms * 2) << 11; +#else + return 0; +#endif +} + +static void recurse_mono (WavpackContext *wpc, WavpackExtraInfo *info, int depth, int delta, uint32_t input_bits) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int term, branches = ((wpc->config.extra_flags & EXTRA_BRANCHES) >> 6) - depth; + int32_t *samples, *outsamples; + uint32_t term_bits [22], bits; + + if (branches < 1 || depth + 1 == info->nterms) + branches = 1; + + CLEAR (term_bits); + samples = info->sampleptrs [depth]; + outsamples = info->sampleptrs [depth + 1]; + + for (term = 1; term <= 18; ++term) { + if (term == 17 && branches == 1 && depth + 1 < info->nterms) + continue; + + if (term > 8 && term < 17) + continue; + + if ((wpc->config.flags & CONFIG_FAST_FLAG) && (term > 4 && term < 17)) + continue; + + info->dps [depth].term = term; + info->dps [depth].delta = delta; + decorr_mono_buffer (samples, outsamples, wps->wphdr.block_samples, info->dps, depth); + bits = log2buffer (outsamples, wps->wphdr.block_samples, info->log_limit); + + if (bits != (uint32_t) -1) + bits += log2overhead (info->dps [0].term, depth + 1); + + if (bits < info->best_bits) { + info->best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * (depth + 1)); + memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [depth + 1], wps->wphdr.block_samples * 4); + } + + term_bits [term + 3] = bits; + } + + while (depth + 1 < info->nterms && branches--) { + uint32_t local_best_bits = input_bits; + int best_term = 0, i; + + for (i = 0; i < 22; ++i) + if (term_bits [i] && term_bits [i] < local_best_bits) { + local_best_bits = term_bits [i]; +// term_bits [i] = 0; + best_term = i - 3; + } + + if (!best_term) + break; + + term_bits [best_term + 3] = 0; + + info->dps [depth].term = best_term; + info->dps [depth].delta = delta; + decorr_mono_buffer (samples, outsamples, wps->wphdr.block_samples, info->dps, depth); + +// if (log2buffer (outsamples, wps->wphdr.block_samples * 2, 0) != local_best_bits) +// error_line ("data doesn't match!"); + + recurse_mono (wpc, info, depth + 1, delta, local_best_bits); + } +} + +static void delta_mono (WavpackContext *wpc, WavpackExtraInfo *info) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int lower = FALSE, delta, d; + uint32_t bits; + + if (wps->decorr_passes [0].term) + delta = wps->decorr_passes [0].delta; + else + return; + + for (d = delta - 1; d >= 0; --d) { + int i; + + if (!d && (wps->wphdr.flags & HYBRID_FLAG)) + break; + + for (i = 0; i < info->nterms && wps->decorr_passes [i].term; ++i) { + info->dps [i].term = wps->decorr_passes [i].term; + info->dps [i].delta = d; + decorr_mono_buffer (info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, info->dps, i); + } + + bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples, info->log_limit); + + if (bits != (uint32_t) -1) + bits += log2overhead (wps->decorr_passes [0].term, i); + + if (bits < info->best_bits) { + lower = TRUE; + info->best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i); + memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 4); + } + else + break; + } + + for (d = delta + 1; !lower && d <= 7; ++d) { + int i; + + for (i = 0; i < info->nterms && wps->decorr_passes [i].term; ++i) { + info->dps [i].term = wps->decorr_passes [i].term; + info->dps [i].delta = d; + decorr_mono_buffer (info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, info->dps, i); + } + + bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples, info->log_limit); + + if (bits != (uint32_t) -1) + bits += log2overhead (wps->decorr_passes [0].term, i); + + if (bits < info->best_bits) { + info->best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i); + memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 4); + } + else + break; + } +} + +static void sort_mono (WavpackContext *wpc, WavpackExtraInfo *info) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int reversed = TRUE; + uint32_t bits; + + while (reversed) { + int ri, i; + + memcpy (info->dps, wps->decorr_passes, sizeof (wps->decorr_passes)); + reversed = FALSE; + + for (ri = 0; ri < info->nterms && wps->decorr_passes [ri].term; ++ri) { + + if (ri + 1 >= info->nterms || !wps->decorr_passes [ri+1].term) + break; + + if (wps->decorr_passes [ri].term == wps->decorr_passes [ri+1].term) { + decorr_mono_buffer (info->sampleptrs [ri], info->sampleptrs [ri+1], wps->wphdr.block_samples, info->dps, ri); + continue; + } + + info->dps [ri] = wps->decorr_passes [ri+1]; + info->dps [ri+1] = wps->decorr_passes [ri]; + + for (i = ri; i < info->nterms && wps->decorr_passes [i].term; ++i) + decorr_mono_buffer (info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, info->dps, i); + + bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples, info->log_limit); + + if (bits != (uint32_t) -1) + bits += log2overhead (wps->decorr_passes [0].term, i); + + if (bits < info->best_bits) { + reversed = TRUE; + info->best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i); + memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 4); + } + else { + info->dps [ri] = wps->decorr_passes [ri]; + info->dps [ri+1] = wps->decorr_passes [ri+1]; + decorr_mono_buffer (info->sampleptrs [ri], info->sampleptrs [ri+1], wps->wphdr.block_samples, info->dps, ri); + } + } + } +} + +static const uint32_t xtable [] = { 91, 123, 187, 251 }; + +static void analyze_mono (WavpackContext *wpc, int32_t *samples, int do_samples) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + WavpackExtraInfo info; + int i; + +#ifdef LOG_LIMIT + info.log_limit = (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) + 4) * 256; + + if (info.log_limit > LOG_LIMIT) + info.log_limit = LOG_LIMIT; +#else + info.log_limit = 0; +#endif + + if (wpc->config.flags & (CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG)) + wpc->config.extra_flags = xtable [wpc->config.xmode - 4]; + else + wpc->config.extra_flags = xtable [wpc->config.xmode - 3]; + + info.nterms = wps->num_terms; + + for (i = 0; i < info.nterms + 2; ++i) + info.sampleptrs [i] = malloc (wps->wphdr.block_samples * 4); + + memcpy (info.dps, wps->decorr_passes, sizeof (info.dps)); + memcpy (info.sampleptrs [0], samples, wps->wphdr.block_samples * 4); + + for (i = 0; i < info.nterms && info.dps [i].term; ++i) + decorr_mono_pass (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps + i, 1); + + info.best_bits = log2buffer (info.sampleptrs [info.nterms], wps->wphdr.block_samples, 0) * 1; + info.best_bits += log2overhead (info.dps [0].term, i); + memcpy (info.sampleptrs [info.nterms + 1], info.sampleptrs [i], wps->wphdr.block_samples * 4); + + if (wpc->config.extra_flags & EXTRA_BRANCHES) + recurse_mono (wpc, &info, 0, (int) floor (wps->delta_decay + 0.5), + log2buffer (info.sampleptrs [0], wps->wphdr.block_samples, 0)); + + if (wpc->config.extra_flags & EXTRA_SORT_FIRST) + sort_mono (wpc, &info); + + if (wpc->config.extra_flags & EXTRA_TRY_DELTAS) { + delta_mono (wpc, &info); + + if ((wpc->config.extra_flags & EXTRA_ADJUST_DELTAS) && wps->decorr_passes [0].term) + wps->delta_decay = (float)((wps->delta_decay * 2.0 + wps->decorr_passes [0].delta) / 3.0); + else + wps->delta_decay = 2.0; + } + + if (wpc->config.extra_flags & EXTRA_SORT_LAST) + sort_mono (wpc, &info); + + if (do_samples) + memcpy (samples, info.sampleptrs [info.nterms + 1], wps->wphdr.block_samples * 4); + + for (i = 0; i < info.nterms; ++i) + if (!wps->decorr_passes [i].term) + break; + + wps->num_terms = i; + + for (i = 0; i < info.nterms + 2; ++i) + free (info.sampleptrs [i]); +} + +static void mono_add_noise (WavpackStream *wps, int32_t *lptr, int32_t *rptr) +{ + int shaping_weight, new = wps->wphdr.flags & NEW_SHAPING; + short *shaping_array = wps->dc.shaping_array; + int32_t error = 0, temp, cnt; + + scan_word (wps, rptr, wps->wphdr.block_samples, -1); + cnt = wps->wphdr.block_samples; + + if (wps->wphdr.flags & HYBRID_SHAPE) { + while (cnt--) { + if (shaping_array) + shaping_weight = *shaping_array++; + else + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + + temp = -apply_weight (shaping_weight, error); + + if (new && shaping_weight < 0 && temp) { + if (temp == error) + temp = (temp < 0) ? temp + 1 : temp - 1; + + lptr [0] += (error = nosend_word (wps, rptr [0], 0) - rptr [0] + temp); + } + else + lptr [0] += (error = nosend_word (wps, rptr [0], 0) - rptr [0]) + temp; + + lptr++; + rptr++; + } + + if (!shaping_array) + wps->dc.shaping_acc [0] -= wps->dc.shaping_delta [0] * wps->wphdr.block_samples; + } + else + while (cnt--) { + lptr [0] += nosend_word (wps, rptr [0], 0) - rptr [0]; + lptr++; + rptr++; + } +} + +void execute_mono (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples) +{ + int32_t *temp_buffer [2], *best_buffer, *noisy_buffer = NULL; + struct decorr_pass temp_decorr_pass, save_decorr_passes [MAX_NTERMS]; + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int32_t num_samples = wps->wphdr.block_samples; + int32_t buf_size = sizeof (int32_t) * num_samples; + uint32_t best_size = (uint32_t) -1, size; + int log_limit, pi, i; + + for (i = 0; i < num_samples; ++i) + if (samples [i]) + break; + + if (i == num_samples) { + CLEAR (wps->decorr_passes); + wps->num_terms = 0; + init_words (wps); + return; + } + +#ifdef LOG_LIMIT + log_limit = (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) + 4) * 256; + + if (log_limit > LOG_LIMIT) + log_limit = LOG_LIMIT; +#else + log_limit = 0; +#endif + + CLEAR (save_decorr_passes); + temp_buffer [0] = malloc (buf_size); + temp_buffer [1] = malloc (buf_size); + best_buffer = malloc (buf_size); + + if (wps->num_passes > 1 && (wps->wphdr.flags & HYBRID_FLAG)) { + CLEAR (temp_decorr_pass); + temp_decorr_pass.delta = 2; + temp_decorr_pass.term = 18; + + decorr_mono_pass (samples, temp_buffer [0], + num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1); + + reverse_mono_decorr (&temp_decorr_pass); + decorr_mono_pass (samples, temp_buffer [0], num_samples, &temp_decorr_pass, 1); + CLEAR (temp_decorr_pass); + temp_decorr_pass.delta = 2; + temp_decorr_pass.term = 17; + + decorr_mono_pass (temp_buffer [0], temp_buffer [1], + num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1); + + decorr_mono_pass (temp_buffer [0], temp_buffer [1], num_samples, &temp_decorr_pass, 1); + noisy_buffer = malloc (buf_size); + memcpy (noisy_buffer, samples, buf_size); + mono_add_noise (wps, noisy_buffer, temp_buffer [1]); + no_history = 1; + } + + if (no_history || wps->num_passes >= 7) + wps->best_decorr = wps->mask_decorr = 0; + + for (pi = 0; pi < wps->num_passes;) { + const WavpackDecorrSpec *wpds; + int nterms, c, j; + + if (!pi) + c = wps->best_decorr; + else { + if (wps->mask_decorr == 0) + c = 0; + else + c = (wps->best_decorr & (wps->mask_decorr - 1)) | wps->mask_decorr; + + if (c == wps->best_decorr) { + wps->mask_decorr = wps->mask_decorr ? ((wps->mask_decorr << 1) & (wps->num_decorrs - 1)) : 1; + continue; + } + } + + wpds = &wps->decorr_specs [c]; + nterms = (int) strlen (wpds->terms); + + while (1) { + memcpy (temp_buffer [0], noisy_buffer ? noisy_buffer : samples, buf_size); + CLEAR (save_decorr_passes); + + for (j = 0; j < nterms; ++j) { + CLEAR (temp_decorr_pass); + temp_decorr_pass.delta = wpds->delta; + temp_decorr_pass.term = wpds->terms [j]; + + if (temp_decorr_pass.term < 0) + temp_decorr_pass.term = 1; + + decorr_mono_pass (temp_buffer [j&1], temp_buffer [~j&1], + num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1); + + if (j) { + CLEAR (temp_decorr_pass.samples_A); + } + else + reverse_mono_decorr (&temp_decorr_pass); + + memcpy (save_decorr_passes + j, &temp_decorr_pass, sizeof (struct decorr_pass)); + decorr_mono_pass (temp_buffer [j&1], temp_buffer [~j&1], num_samples, &temp_decorr_pass, 1); + } + + size = log2buffer (temp_buffer [j&1], num_samples, log_limit); + + if (size == (uint32_t) -1 && nterms) + nterms >>= 1; + else + break; + } + + size += log2overhead (wpds->terms [0], nterms); + + if (size < best_size) { + memcpy (best_buffer, temp_buffer [j&1], buf_size); + memcpy (wps->decorr_passes, save_decorr_passes, sizeof (struct decorr_pass) * MAX_NTERMS); + wps->num_terms = nterms; + wps->best_decorr = c; + best_size = size; + } + + if (pi++) + wps->mask_decorr = wps->mask_decorr ? ((wps->mask_decorr << 1) & (wps->num_decorrs - 1)) : 1; + } + + if (wpc->config.xmode > 3) { + if (noisy_buffer) { + analyze_mono (wpc, noisy_buffer, do_samples); + + if (do_samples) + memcpy (samples, noisy_buffer, buf_size); + } + else + analyze_mono (wpc, samples, do_samples); + } + else if (do_samples) + memcpy (samples, best_buffer, buf_size); + + if (no_history || wpc->config.xmode > 3) + scan_word (wps, best_buffer, num_samples, -1); + + if (noisy_buffer) + free (noisy_buffer); + + free (temp_buffer [1]); + free (temp_buffer [0]); + free (best_buffer); + +#ifdef EXTRA_DUMP + if (1) { + char string [256], substring [20]; + int i; + + sprintf (string, "M: terms ="); + + for (i = 0; i < wps->num_terms; ++i) { + if (wps->decorr_passes [i].term) { + if (i && wps->decorr_passes [i-1].delta == wps->decorr_passes [i].delta) + sprintf (substring, " %d", wps->decorr_passes [i].term); + else + sprintf (substring, " %d->%d", wps->decorr_passes [i].term, + wps->decorr_passes [i].delta); + } + else + sprintf (substring, " *"); + + strcat (string, substring); + } + + error_line (string); + } +#endif +} + diff --git a/wavpack-4.5.0/src/extra2.c b/wavpack-4.5.0/src/extra2.c new file mode 100644 index 0000000..17fcf01 --- /dev/null +++ b/wavpack-4.5.0/src/extra2.c @@ -0,0 +1,1355 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2006 Conifer Software. // +// MMX optimizations (c) 2006 Joachim Henke // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// extra2.c + +// This module handles the "extra" mode for stereo files. + +#include "wavpack_local.h" + +#include +#include +#include +#include + +//#define USE_OVERHEAD +#define LOG_LIMIT 6912 +//#define EXTRA_DUMP + +#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 + +//////////////////////////////// local tables /////////////////////////////// + +typedef struct { + int32_t *sampleptrs [MAX_NTERMS+2]; + struct decorr_pass dps [MAX_NTERMS]; + int nterms, log_limit, gt16bit; + uint32_t best_bits; +} WavpackExtraInfo; + +#ifdef OPT_MMX + +static void decorr_stereo_pass (int32_t *in_samples, int32_t *out_samples, int32_t num_samples, struct decorr_pass *dpp, int dir) +{ + const __m64 + delta = _mm_set1_pi32 (dpp->delta), + fill = _mm_set1_pi32 (0x7bff), + mask = _mm_set1_pi32 (0x7fff), + round = _mm_set1_pi32 (512), + zero = _mm_set1_pi32 (0); + __m64 + sum_AB = zero, + weight_AB = _mm_set_pi32 (restore_weight (store_weight (dpp->weight_B)), restore_weight (store_weight (dpp->weight_A))), + left_right, sam_AB, tmp0, tmp1, samples_AB [MAX_TERM]; + int k, m = 0; + + if (dir < 0) { + out_samples += (num_samples - 1) * 2; + in_samples += (num_samples - 1) * 2; + dir = -2; + } + else + dir = 2; + + for (k = 0; k < MAX_TERM; ++k) { + ((int32_t *) samples_AB) [k * 2] = exp2s (log2s (dpp->samples_A [k])); + ((int32_t *) samples_AB) [k * 2 + 1] = exp2s (log2s (dpp->samples_B [k])); + } + + if (dpp->term > 0) { + if (dpp->term == 17) { + while (num_samples--) { + left_right = *(__m64 *) in_samples; + tmp0 = samples_AB [0]; + sam_AB = _m_paddd (tmp0, tmp0); + sam_AB = _m_psubd (sam_AB, samples_AB [1]); + samples_AB [0] = left_right; + samples_AB [1] = tmp0; + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) out_samples = left_right; + + tmp0 = _m_pxor (sam_AB, left_right); + tmp0 = _m_psradi (tmp0, 31); + tmp1 = _m_pxor (delta, tmp0); + tmp1 = _m_psubd (tmp1, tmp0); + sam_AB = _m_pcmpeqd (sam_AB, zero); + tmp0 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, sam_AB); + tmp0 = _m_pandn (tmp0, tmp1); + weight_AB = _m_paddd (weight_AB, tmp0); + + sum_AB = _m_paddd (sum_AB, weight_AB); + + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term == 18) { + while (num_samples--) { + left_right = *(__m64 *) in_samples; + tmp0 = samples_AB [0]; + sam_AB = _m_psubd (tmp0, samples_AB [1]); + sam_AB = _m_psradi (sam_AB, 1); + sam_AB = _m_paddd (sam_AB, tmp0); + samples_AB [0] = left_right; + samples_AB [1] = tmp0; + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) out_samples = left_right; + + tmp0 = _m_pxor (sam_AB, left_right); + tmp0 = _m_psradi (tmp0, 31); + tmp1 = _m_pxor (delta, tmp0); + tmp1 = _m_psubd (tmp1, tmp0); + sam_AB = _m_pcmpeqd (sam_AB, zero); + tmp0 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, sam_AB); + tmp0 = _m_pandn (tmp0, tmp1); + weight_AB = _m_paddd (weight_AB, tmp0); + + sum_AB = _m_paddd (sum_AB, weight_AB); + + in_samples += dir; + out_samples += dir; + } + } + else { + k = dpp->term & (MAX_TERM - 1); + while (num_samples--) { + left_right = *(__m64 *) in_samples; + sam_AB = samples_AB [m]; + samples_AB [k] = left_right; + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) out_samples = left_right; + + tmp0 = _m_pxor (sam_AB, left_right); + tmp0 = _m_psradi (tmp0, 31); + tmp1 = _m_pxor (delta, tmp0); + tmp1 = _m_psubd (tmp1, tmp0); + sam_AB = _m_pcmpeqd (sam_AB, zero); + tmp0 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, sam_AB); + tmp0 = _m_pandn (tmp0, tmp1); + weight_AB = _m_paddd (weight_AB, tmp0); + + sum_AB = _m_paddd (sum_AB, weight_AB); + + in_samples += dir; + out_samples += dir; + k = (k + 1) & (MAX_TERM - 1); + m = (m + 1) & (MAX_TERM - 1); + } + } + } + else { + if (dpp->term == -1) { + while (num_samples--) { + left_right = *(__m64 *) in_samples; + sam_AB = samples_AB [0]; + samples_AB [0] = _m_punpckhdq (left_right, sam_AB); + sam_AB = _m_punpckldq (sam_AB, left_right); + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) out_samples = left_right; + + tmp0 = _m_pcmpeqd (sam_AB, zero); + tmp1 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, tmp1); + tmp0 = _m_pandn (tmp0, delta); + sam_AB = _m_pxor (sam_AB, left_right); + sam_AB = _m_psradi (sam_AB, 31); + tmp1 = _m_psubd (fill, sam_AB); + weight_AB = _m_pxor (weight_AB, sam_AB); + weight_AB = _m_paddd (weight_AB, tmp1); + weight_AB = _m_paddsw (weight_AB, tmp0); + weight_AB = _m_psubd (weight_AB, tmp1); + weight_AB = _m_pxor (weight_AB, sam_AB); + + sum_AB = _m_paddd (sum_AB, weight_AB); + + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term == -2) { + while (num_samples--) { + left_right = *(__m64 *) in_samples; + sam_AB = samples_AB [0]; + samples_AB [0] = _m_punpckldq (sam_AB, left_right); + sam_AB = _m_punpckhdq (left_right, sam_AB); + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) out_samples = left_right; + + tmp0 = _m_pcmpeqd (sam_AB, zero); + tmp1 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, tmp1); + tmp0 = _m_pandn (tmp0, delta); + sam_AB = _m_pxor (sam_AB, left_right); + sam_AB = _m_psradi (sam_AB, 31); + tmp1 = _m_psubd (fill, sam_AB); + weight_AB = _m_pxor (weight_AB, sam_AB); + weight_AB = _m_paddd (weight_AB, tmp1); + weight_AB = _m_paddsw (weight_AB, tmp0); + weight_AB = _m_psubd (weight_AB, tmp1); + weight_AB = _m_pxor (weight_AB, sam_AB); + + sum_AB = _m_paddd (sum_AB, weight_AB); + + in_samples += dir; + out_samples += dir; + } + } + else if (dpp->term == -3) { + while (num_samples--) { + left_right = *(__m64 *) in_samples; + sam_AB = samples_AB [0]; + tmp0 = _m_punpckhdq (left_right, left_right); + samples_AB [0] = _m_punpckldq (tmp0, left_right); + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) out_samples = left_right; + + tmp0 = _m_pcmpeqd (sam_AB, zero); + tmp1 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, tmp1); + tmp0 = _m_pandn (tmp0, delta); + sam_AB = _m_pxor (sam_AB, left_right); + sam_AB = _m_psradi (sam_AB, 31); + tmp1 = _m_psubd (fill, sam_AB); + weight_AB = _m_pxor (weight_AB, sam_AB); + weight_AB = _m_paddd (weight_AB, tmp1); + weight_AB = _m_paddsw (weight_AB, tmp0); + weight_AB = _m_psubd (weight_AB, tmp1); + weight_AB = _m_pxor (weight_AB, sam_AB); + + sum_AB = _m_paddd (sum_AB, weight_AB); + + in_samples += dir; + out_samples += dir; + } + } + } + dpp->sum_A = ((int32_t *) &sum_AB) [0]; + dpp->sum_B = ((int32_t *) &sum_AB) [1]; + dpp->weight_A = ((int32_t *) &weight_AB) [0]; + dpp->weight_B = ((int32_t *) &weight_AB) [1]; + + for (k = 0; k < MAX_TERM; ++k) { + dpp->samples_A [k] = ((int32_t *) samples_AB) [m * 2]; + dpp->samples_B [k] = ((int32_t *) samples_AB) [m * 2 + 1]; + m = (m + 1) & (MAX_TERM - 1); + } + _mm_empty (); +} + +#else + +static void decorr_stereo_pass (int32_t *in_samples, int32_t *out_samples, int32_t num_samples, struct decorr_pass *dpp, int dir) +{ + int m = 0, i; + + dpp->sum_A = dpp->sum_B = 0; + + if (dir < 0) { + out_samples += (num_samples - 1) * 2; + in_samples += (num_samples - 1) * 2; + dir = -2; + } + else + dir = 2; + + dpp->weight_A = restore_weight (store_weight (dpp->weight_A)); + dpp->weight_B = restore_weight (store_weight (dpp->weight_B)); + + for (i = 0; i < 8; ++i) { + dpp->samples_A [i] = exp2s (log2s (dpp->samples_A [i])); + dpp->samples_B [i] = exp2s (log2s (dpp->samples_B [i])); + } + + switch (dpp->term) { + + case 2: + while (num_samples--) { + int32_t sam, tmp; + + sam = dpp->samples_A [0]; + dpp->samples_A [0] = dpp->samples_A [1]; + out_samples [0] = tmp = (dpp->samples_A [1] = in_samples [0]) - apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + dpp->sum_A += dpp->weight_A; + + sam = dpp->samples_B [0]; + dpp->samples_B [0] = dpp->samples_B [1]; + out_samples [1] = tmp = (dpp->samples_B [1] = in_samples [1]) - apply_weight (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + dpp->sum_B += dpp->weight_B; + + in_samples += dir; + out_samples += dir; + } + + break; + + case 17: + while (num_samples--) { + int32_t sam, tmp; + + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + out_samples [0] = tmp = (dpp->samples_A [0] = in_samples [0]) - apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + dpp->sum_A += dpp->weight_A; + + sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + out_samples [1] = tmp = (dpp->samples_B [0] = in_samples [1]) - apply_weight (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + dpp->sum_B += dpp->weight_B; + + in_samples += dir; + out_samples += dir; + } + + break; + + case 18: + while (num_samples--) { + int32_t sam, tmp; + + sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); + dpp->samples_A [1] = dpp->samples_A [0]; + out_samples [0] = tmp = (dpp->samples_A [0] = in_samples [0]) - apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + dpp->sum_A += dpp->weight_A; + + sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); + dpp->samples_B [1] = dpp->samples_B [0]; + out_samples [1] = tmp = (dpp->samples_B [0] = in_samples [1]) - apply_weight (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + dpp->sum_B += dpp->weight_B; + + in_samples += dir; + out_samples += dir; + } + + break; + + default: { + int k = dpp->term & (MAX_TERM - 1); + + while (num_samples--) { + int32_t sam, tmp; + + sam = dpp->samples_A [m]; + out_samples [0] = tmp = (dpp->samples_A [k] = in_samples [0]) - apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + dpp->sum_A += dpp->weight_A; + + sam = dpp->samples_B [m]; + out_samples [1] = tmp = (dpp->samples_B [k] = in_samples [1]) - apply_weight (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + dpp->sum_B += dpp->weight_B; + + in_samples += dir; + out_samples += dir; + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + if (m) { + int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; + int k; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + dpp->samples_B [k] = temp_B [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } + + break; + } + + case -1: + while (num_samples--) { + int32_t sam_A, sam_B, tmp; + + sam_A = dpp->samples_A [0]; + out_samples [0] = tmp = (sam_B = in_samples [0]) - apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); + dpp->sum_A += dpp->weight_A; + + out_samples [1] = tmp = (dpp->samples_A [0] = in_samples [1]) - apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); + dpp->sum_B += dpp->weight_B; + + in_samples += dir; + out_samples += dir; + } + + break; + + case -2: + while (num_samples--) { + int32_t sam_A, sam_B, tmp; + + sam_B = dpp->samples_B [0]; + out_samples [1] = tmp = (sam_A = in_samples [1]) - apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); + dpp->sum_B += dpp->weight_B; + + out_samples [0] = tmp = (dpp->samples_B [0] = in_samples [0]) - apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); + dpp->sum_A += dpp->weight_A; + + in_samples += dir; + out_samples += dir; + } + + break; + + case -3: + while (num_samples--) { + int32_t sam_A, sam_B, tmp; + + sam_A = dpp->samples_A [0]; + sam_B = dpp->samples_B [0]; + + dpp->samples_A [0] = tmp = in_samples [1]; + out_samples [1] = tmp -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); + dpp->sum_B += dpp->weight_B; + + dpp->samples_B [0] = tmp = in_samples [0]; + out_samples [0] = tmp -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); + dpp->sum_A += dpp->weight_A; + + in_samples += dir; + out_samples += dir; + } + + break; + } +} + +#endif + +static void decorr_stereo_pass_quick (int32_t *in_samples, int32_t *out_samples, int32_t num_samples, struct decorr_pass *dpp, int dir) +{ + int m = 0, i; + + if (dir < 0) { + out_samples += (num_samples - 1) * 2; + in_samples += (num_samples - 1) * 2; + dir = -2; + } + else + dir = 2; + + dpp->weight_A = restore_weight (store_weight (dpp->weight_A)); + dpp->weight_B = restore_weight (store_weight (dpp->weight_B)); + + for (i = 0; i < 8; ++i) { + dpp->samples_A [i] = exp2s (log2s (dpp->samples_A [i])); + dpp->samples_B [i] = exp2s (log2s (dpp->samples_B [i])); + } + + switch (dpp->term) { + + case 2: + while (num_samples--) { + int32_t sam, tmp; + + sam = dpp->samples_A [0]; + dpp->samples_A [0] = dpp->samples_A [1]; + out_samples [0] = tmp = (dpp->samples_A [1] = in_samples [0]) - apply_weight_i (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = dpp->samples_B [0]; + dpp->samples_B [0] = dpp->samples_B [1]; + out_samples [1] = tmp = (dpp->samples_B [1] = in_samples [1]) - apply_weight_i (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + + in_samples += dir; + out_samples += dir; + } + + break; + + case 17: + while (num_samples--) { + int32_t sam, tmp; + + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + out_samples [0] = tmp = (dpp->samples_A [0] = in_samples [0]) - apply_weight_i (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + out_samples [1] = tmp = (dpp->samples_B [0] = in_samples [1]) - apply_weight_i (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + + in_samples += dir; + out_samples += dir; + } + + break; + + case 18: + while (num_samples--) { + int32_t sam, tmp; + + sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); + dpp->samples_A [1] = dpp->samples_A [0]; + out_samples [0] = tmp = (dpp->samples_A [0] = in_samples [0]) - apply_weight_i (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); + dpp->samples_B [1] = dpp->samples_B [0]; + out_samples [1] = tmp = (dpp->samples_B [0] = in_samples [1]) - apply_weight_i (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + + in_samples += dir; + out_samples += dir; + } + + break; + + default: { + int k = dpp->term & (MAX_TERM - 1); + + while (num_samples--) { + int32_t sam, tmp; + + sam = dpp->samples_A [m]; + out_samples [0] = tmp = (dpp->samples_A [k] = in_samples [0]) - apply_weight_i (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = dpp->samples_B [m]; + out_samples [1] = tmp = (dpp->samples_B [k] = in_samples [1]) - apply_weight_i (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + + in_samples += dir; + out_samples += dir; + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + if (m) { + int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; + int k; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + dpp->samples_B [k] = temp_B [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } + + break; + } + + case -1: + while (num_samples--) { + int32_t sam_A, sam_B, tmp; + + sam_A = dpp->samples_A [0]; + out_samples [0] = tmp = (sam_B = in_samples [0]) - apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); + + out_samples [1] = tmp = (dpp->samples_A [0] = in_samples [1]) - apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); + + in_samples += dir; + out_samples += dir; + } + + break; + + case -2: + while (num_samples--) { + int32_t sam_A, sam_B, tmp; + + sam_B = dpp->samples_B [0]; + out_samples [1] = tmp = (sam_A = in_samples [1]) - apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); + + out_samples [0] = tmp = (dpp->samples_B [0] = in_samples [0]) - apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); + + in_samples += dir; + out_samples += dir; + } + + break; + + case -3: + while (num_samples--) { + int32_t sam_A, sam_B, tmp; + + sam_A = dpp->samples_A [0]; + sam_B = dpp->samples_B [0]; + + dpp->samples_A [0] = tmp = in_samples [1]; + out_samples [1] = tmp -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); + + dpp->samples_B [0] = tmp = in_samples [0]; + out_samples [0] = tmp -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); + + in_samples += dir; + out_samples += dir; + } + + break; + } +} + +static void reverse_decorr (struct decorr_pass *dpp) +{ + if (dpp->term > MAX_TERM) { + int32_t sam_A, sam_B; + + if (dpp->term & 1) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_A [0] = sam_A; + dpp->samples_B [0] = sam_B; + + if (dpp->term & 1) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + + dpp->samples_A [1] = sam_A; + dpp->samples_B [1] = sam_B; + } + else if (dpp->term > 1) { + int i = 0, j = dpp->term - 1, cnt = dpp->term / 2; + + while (cnt--) { + i &= (MAX_TERM - 1); + j &= (MAX_TERM - 1); + dpp->samples_A [i] ^= dpp->samples_A [j]; + dpp->samples_A [j] ^= dpp->samples_A [i]; + dpp->samples_A [i] ^= dpp->samples_A [j]; + dpp->samples_B [i] ^= dpp->samples_B [j]; + dpp->samples_B [j] ^= dpp->samples_B [i]; + dpp->samples_B [i++] ^= dpp->samples_B [j--]; + } + } + else if (dpp->term == -1) { + } + else if (dpp->term == -2) { + } + else if (dpp->term == -3) { + } +} + +static void decorr_stereo_buffer (WavpackExtraInfo *info, int32_t *samples, int32_t *outsamples, int32_t num_samples, int tindex) +{ + struct decorr_pass dp, *dppi = info->dps + tindex; + int delta = dppi->delta, pre_delta; + int term = dppi->term; + + if (delta == 7) + pre_delta = 7; + else if (delta < 2) + pre_delta = 3; + else + pre_delta = delta + 1; + + CLEAR (dp); + dp.term = term; + dp.delta = pre_delta; + decorr_stereo_pass (samples, outsamples, num_samples > 2048 ? 2048 : num_samples, &dp, -1); + dp.delta = delta; + + if (tindex == 0) + reverse_decorr (&dp); + else { + CLEAR (dp.samples_A); + CLEAR (dp.samples_B); + } + + memcpy (dppi->samples_A, dp.samples_A, sizeof (dp.samples_A)); + memcpy (dppi->samples_B, dp.samples_B, sizeof (dp.samples_B)); + dppi->weight_A = dp.weight_A; + dppi->weight_B = dp.weight_B; + + if (delta == 0) { + dp.delta = 1; + decorr_stereo_pass (samples, outsamples, num_samples, &dp, 1); + dp.delta = 0; + memcpy (dp.samples_A, dppi->samples_A, sizeof (dp.samples_A)); + memcpy (dp.samples_B, dppi->samples_B, sizeof (dp.samples_B)); + dppi->weight_A = dp.weight_A = dp.sum_A / num_samples; + dppi->weight_B = dp.weight_B = dp.sum_B / num_samples; + } + +// if (memcmp (dppi, &dp, sizeof (dp))) +// error_line ("decorr_passes don't match, delta = %d", delta); + + if (info->gt16bit) + decorr_stereo_pass (samples, outsamples, num_samples, &dp, 1); + else + decorr_stereo_pass_quick (samples, outsamples, num_samples, &dp, 1); +} + +static int log2overhead (int first_term, int num_terms) +{ +#ifdef USE_OVERHEAD + if (first_term > MAX_TERM) + return (8 + num_terms * 3) << 11; + else + return (4 + num_terms * 3) << 11; +#else + return 0; +#endif +} + +static void recurse_stereo (WavpackContext *wpc, WavpackExtraInfo *info, int depth, int delta, uint32_t input_bits) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int term, branches = ((wpc->config.extra_flags & EXTRA_BRANCHES) >> 6) - depth; + int32_t *samples, *outsamples; + uint32_t term_bits [22], bits; + + if (branches < 1 || depth + 1 == info->nterms) + branches = 1; + + CLEAR (term_bits); + samples = info->sampleptrs [depth]; + outsamples = info->sampleptrs [depth + 1]; + + for (term = -3; term <= 18; ++term) { + if (!term || (term > 8 && term < 17)) + continue; + + if (term == 17 && branches == 1 && depth + 1 < info->nterms) + continue; + + if (term == -1 || term == -2) + if (!(wps->wphdr.flags & CROSS_DECORR)) + continue; + + if ((wpc->config.flags & CONFIG_FAST_FLAG) && (term > 4 && term < 17)) + continue; + + info->dps [depth].term = term; + info->dps [depth].delta = delta; + decorr_stereo_buffer (info, samples, outsamples, wps->wphdr.block_samples, depth); + bits = log2buffer (outsamples, wps->wphdr.block_samples * 2, info->log_limit); + + if (bits != (uint32_t) -1) + bits += log2overhead (info->dps [0].term, depth + 1); + + if (bits < info->best_bits) { + info->best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * (depth + 1)); + memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [depth + 1], wps->wphdr.block_samples * 8); + } + + term_bits [term + 3] = bits; + } + + while (depth + 1 < info->nterms && branches--) { + uint32_t local_best_bits = input_bits; + int best_term = 0, i; + + for (i = 0; i < 22; ++i) + if (term_bits [i] && term_bits [i] < local_best_bits) { + local_best_bits = term_bits [i]; +// term_bits [i] = 0; + best_term = i - 3; + } + + if (!best_term) + break; + + term_bits [best_term + 3] = 0; + + info->dps [depth].term = best_term; + info->dps [depth].delta = delta; + decorr_stereo_buffer (info, samples, outsamples, wps->wphdr.block_samples, depth); + +// if (log2buffer (outsamples, wps->wphdr.block_samples * 2, 0) != local_best_bits) +// error_line ("data doesn't match!"); + + recurse_stereo (wpc, info, depth + 1, delta, local_best_bits); + } +} + +static void delta_stereo (WavpackContext *wpc, WavpackExtraInfo *info) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int lower = FALSE; + int delta, d; + uint32_t bits; + + if (wps->decorr_passes [0].term) + delta = wps->decorr_passes [0].delta; + else + return; + + for (d = delta - 1; d >= 0; --d) { + int i; + + if (!d && (wps->wphdr.flags & HYBRID_FLAG)) + break; + + for (i = 0; i < info->nterms && wps->decorr_passes [i].term; ++i) { + info->dps [i].term = wps->decorr_passes [i].term; + info->dps [i].delta = d; + decorr_stereo_buffer (info, info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, i); + } + + bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); + + if (bits != (uint32_t) -1) + bits += log2overhead (wps->decorr_passes [0].term, i); + + if (bits < info->best_bits) { + lower = TRUE; + info->best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i); + memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 8); + } + else + break; + } + + for (d = delta + 1; !lower && d <= 7; ++d) { + int i; + + for (i = 0; i < info->nterms && wps->decorr_passes [i].term; ++i) { + info->dps [i].term = wps->decorr_passes [i].term; + info->dps [i].delta = d; + decorr_stereo_buffer (info, info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, i); + } + + bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); + + if (bits != (uint32_t) -1) + bits += log2overhead (wps->decorr_passes [0].term, i); + + if (bits < info->best_bits) { + info->best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i); + memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 8); + } + else + break; + } +} + +static void sort_stereo (WavpackContext *wpc, WavpackExtraInfo *info) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int reversed = TRUE; + uint32_t bits; + + while (reversed) { + int ri, i; + + memcpy (info->dps, wps->decorr_passes, sizeof (wps->decorr_passes)); + reversed = FALSE; + + for (ri = 0; ri < info->nterms && wps->decorr_passes [ri].term; ++ri) { + + if (ri + 1 >= info->nterms || !wps->decorr_passes [ri+1].term) + break; + + if (wps->decorr_passes [ri].term == wps->decorr_passes [ri+1].term) { + decorr_stereo_buffer (info, info->sampleptrs [ri], info->sampleptrs [ri+1], wps->wphdr.block_samples, ri); + continue; + } + + info->dps [ri] = wps->decorr_passes [ri+1]; + info->dps [ri+1] = wps->decorr_passes [ri]; + + for (i = ri; i < info->nterms && wps->decorr_passes [i].term; ++i) + decorr_stereo_buffer (info, info->sampleptrs [i], info->sampleptrs [i+1], wps->wphdr.block_samples, i); + + bits = log2buffer (info->sampleptrs [i], wps->wphdr.block_samples * 2, info->log_limit); + + if (bits != (uint32_t) -1) + bits += log2overhead (wps->decorr_passes [0].term, i); + + if (bits < info->best_bits) { + reversed = TRUE; + info->best_bits = bits; + CLEAR (wps->decorr_passes); + memcpy (wps->decorr_passes, info->dps, sizeof (info->dps [0]) * i); + memcpy (info->sampleptrs [info->nterms + 1], info->sampleptrs [i], wps->wphdr.block_samples * 8); + } + else { + info->dps [ri] = wps->decorr_passes [ri]; + info->dps [ri+1] = wps->decorr_passes [ri+1]; + decorr_stereo_buffer (info, info->sampleptrs [ri], info->sampleptrs [ri+1], wps->wphdr.block_samples, ri); + } + } + } +} + +static const uint32_t xtable [] = { 91, 123, 187, 251 }; + +static void analyze_stereo (WavpackContext *wpc, int32_t *samples, int do_samples) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + WavpackExtraInfo info; + int i; + + info.gt16bit = ((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) >= 16; + +#ifdef LOG_LIMIT + info.log_limit = (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) + 4) * 256; + + if (info.log_limit > LOG_LIMIT) + info.log_limit = LOG_LIMIT; +#else + info.log_limit = 0; +#endif + + if (wpc->config.flags & (CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG)) + wpc->config.extra_flags = xtable [wpc->config.xmode - 4]; + else + wpc->config.extra_flags = xtable [wpc->config.xmode - 3]; + + info.nterms = wps->num_terms; + + for (i = 0; i < info.nterms + 2; ++i) + info.sampleptrs [i] = malloc (wps->wphdr.block_samples * 8); + + memcpy (info.dps, wps->decorr_passes, sizeof (info.dps)); + memcpy (info.sampleptrs [0], samples, wps->wphdr.block_samples * 8); + + for (i = 0; i < info.nterms && info.dps [i].term; ++i) + if (info.gt16bit) + decorr_stereo_pass (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps + i, 1); + else + decorr_stereo_pass_quick (info.sampleptrs [i], info.sampleptrs [i + 1], wps->wphdr.block_samples, info.dps + i, 1); + + info.best_bits = log2buffer (info.sampleptrs [info.nterms], wps->wphdr.block_samples * 2, 0) * 1; + info.best_bits += log2overhead (info.dps [0].term, i); + memcpy (info.sampleptrs [info.nterms + 1], info.sampleptrs [i], wps->wphdr.block_samples * 8); + + if (wpc->config.extra_flags & EXTRA_BRANCHES) + recurse_stereo (wpc, &info, 0, (int) floor (wps->delta_decay + 0.5), + log2buffer (info.sampleptrs [0], wps->wphdr.block_samples * 2, 0)); + + if (wpc->config.extra_flags & EXTRA_SORT_FIRST) + sort_stereo (wpc, &info); + + if (wpc->config.extra_flags & EXTRA_TRY_DELTAS) { + delta_stereo (wpc, &info); + + if ((wpc->config.extra_flags & EXTRA_ADJUST_DELTAS) && wps->decorr_passes [0].term) + wps->delta_decay = (float)((wps->delta_decay * 2.0 + wps->decorr_passes [0].delta) / 3.0); + else + wps->delta_decay = 2.0; + } + + if (wpc->config.extra_flags & EXTRA_SORT_LAST) + sort_stereo (wpc, &info); + + if (do_samples) + memcpy (samples, info.sampleptrs [info.nterms + 1], wps->wphdr.block_samples * 8); + + for (i = 0; i < info.nterms; ++i) + if (!wps->decorr_passes [i].term) + break; + + wps->num_terms = i; + + for (i = 0; i < info.nterms + 2; ++i) + free (info.sampleptrs [i]); +} + +static void stereo_add_noise (WavpackStream *wps, int32_t *lptr, int32_t *rptr) +{ + int shaping_weight, new = wps->wphdr.flags & NEW_SHAPING; + short *shaping_array = wps->dc.shaping_array; + int32_t error [2], temp, cnt; + + scan_word (wps, rptr, wps->wphdr.block_samples, -1); + cnt = wps->wphdr.block_samples; + CLEAR (error); + + if (wps->wphdr.flags & HYBRID_SHAPE) { + while (cnt--) { + if (shaping_array) + shaping_weight = *shaping_array++; + else + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + + temp = -apply_weight (shaping_weight, error [0]); + + if (new && shaping_weight < 0 && temp) { + if (temp == error [0]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + lptr [0] += (error [0] = nosend_word (wps, rptr [0], 0) - rptr [0] + temp); + } + else + lptr [0] += (error [0] = nosend_word (wps, rptr [0], 0) - rptr [0]) + temp; + + if (!shaping_array) + shaping_weight = (wps->dc.shaping_acc [1] += wps->dc.shaping_delta [1]) >> 16; + + temp = -apply_weight (shaping_weight, error [1]); + + if (new && shaping_weight < 0 && temp) { + if (temp == error [1]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + lptr [1] += (error [1] = nosend_word (wps, rptr [1], 1) - rptr [1] + temp); + } + else + lptr [1] += (error [1] = nosend_word (wps, rptr [1], 1) - rptr [1]) + temp; + + lptr += 2; + rptr += 2; + } + + if (!shaping_array) { + wps->dc.shaping_acc [0] -= wps->dc.shaping_delta [0] * wps->wphdr.block_samples; + wps->dc.shaping_acc [1] -= wps->dc.shaping_delta [1] * wps->wphdr.block_samples; + } + } + else + while (cnt--) { + lptr [0] += nosend_word (wps, rptr [0], 0) - rptr [0]; + lptr [1] += nosend_word (wps, rptr [1], 1) - rptr [1]; + lptr += 2; + rptr += 2; + } +} + +void execute_stereo (WavpackContext *wpc, int32_t *samples, int no_history, int do_samples) +{ + int32_t *temp_buffer [2], *best_buffer, *noisy_buffer = NULL, *js_buffer = NULL; + struct decorr_pass temp_decorr_pass, save_decorr_passes [MAX_NTERMS]; + WavpackStream *wps = wpc->streams [wpc->current_stream]; + int32_t num_samples = wps->wphdr.block_samples; + int32_t buf_size = sizeof (int32_t) * num_samples * 2; + uint32_t best_size = (uint32_t) -1, size; + int log_limit, force_js = 0, force_ts = 0, pi, i; + + for (i = 0; i < num_samples * 2; ++i) + if (samples [i]) + break; + + if (i == num_samples * 2) { + wps->wphdr.flags &= ~((uint32_t) JOINT_STEREO); + CLEAR (wps->decorr_passes); + wps->num_terms = 0; + init_words (wps); + return; + } + +#ifdef LOG_LIMIT + log_limit = (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) + 4) * 256; + + if (log_limit > LOG_LIMIT) + log_limit = LOG_LIMIT; +#else + log_limit = 0; +#endif + + if (wpc->config.flags & CONFIG_JOINT_OVERRIDE) { + if (wps->wphdr.flags & JOINT_STEREO) + force_js = 1; + else + force_ts = 1; + } + + CLEAR (save_decorr_passes); + temp_buffer [0] = malloc (buf_size); + temp_buffer [1] = malloc (buf_size); + best_buffer = malloc (buf_size); + + if (wps->num_passes > 1 && (wps->wphdr.flags & HYBRID_FLAG)) { + CLEAR (temp_decorr_pass); + temp_decorr_pass.delta = 2; + temp_decorr_pass.term = 18; + + decorr_stereo_pass (samples, temp_buffer [0], + num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1); + + reverse_decorr (&temp_decorr_pass); + decorr_stereo_pass (samples, temp_buffer [0], num_samples, &temp_decorr_pass, 1); + CLEAR (temp_decorr_pass); + temp_decorr_pass.delta = 2; + temp_decorr_pass.term = 17; + + decorr_stereo_pass (temp_buffer [0], temp_buffer [1], + num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1); + + decorr_stereo_pass (temp_buffer [0], temp_buffer [1], num_samples, &temp_decorr_pass, 1); + noisy_buffer = malloc (buf_size); + memcpy (noisy_buffer, samples, buf_size); + stereo_add_noise (wps, noisy_buffer, temp_buffer [1]); + no_history = 1; + } + + if (no_history || wps->num_passes >= 7) + wps->best_decorr = wps->mask_decorr = 0; + + for (pi = 0; pi < wps->num_passes;) { + const WavpackDecorrSpec *wpds; + int nterms, c, j; + + if (!pi) + c = wps->best_decorr; + else { + if (wps->mask_decorr == 0) + c = 0; + else + c = (wps->best_decorr & (wps->mask_decorr - 1)) | wps->mask_decorr; + + if (c == wps->best_decorr) { + wps->mask_decorr = wps->mask_decorr ? ((wps->mask_decorr << 1) & (wps->num_decorrs - 1)) : 1; + continue; + } + } + + wpds = &wps->decorr_specs [c]; + nterms = (int) strlen (wpds->terms); + + while (1) { + if (force_js || (wpds->joint_stereo && !force_ts)) { + if (!js_buffer) { + int32_t *lptr, cnt = num_samples; + + lptr = js_buffer = malloc (buf_size); + memcpy (js_buffer, noisy_buffer ? noisy_buffer : samples, buf_size); + + while (cnt--) { + lptr [1] += ((lptr [0] -= lptr [1]) >> 1); + lptr += 2; + } + } + + memcpy (temp_buffer [0], js_buffer, buf_size); + } + else + memcpy (temp_buffer [0], noisy_buffer ? noisy_buffer : samples, buf_size); + + CLEAR (save_decorr_passes); + + for (j = 0; j < nterms; ++j) { + CLEAR (temp_decorr_pass); + temp_decorr_pass.delta = wpds->delta; + temp_decorr_pass.term = wpds->terms [j]; + + if (temp_decorr_pass.term < 0 && !(wps->wphdr.flags & CROSS_DECORR)) + temp_decorr_pass.term = -3; + + decorr_stereo_pass (temp_buffer [j&1], temp_buffer [~j&1], + num_samples > 2048 ? 2048 : num_samples, &temp_decorr_pass, -1); + + if (j) { + CLEAR (temp_decorr_pass.samples_A); + CLEAR (temp_decorr_pass.samples_B); + } + else + reverse_decorr (&temp_decorr_pass); + + memcpy (save_decorr_passes + j, &temp_decorr_pass, sizeof (struct decorr_pass)); + + if (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) >= 16) + decorr_stereo_pass (temp_buffer [j&1], temp_buffer [~j&1], num_samples, &temp_decorr_pass, 1); + else + decorr_stereo_pass_quick (temp_buffer [j&1], temp_buffer [~j&1], num_samples, &temp_decorr_pass, 1); + } + + size = log2buffer (temp_buffer [j&1], num_samples * 2, log_limit); + + if (size == (uint32_t) -1 && nterms) + nterms >>= 1; + else + break; + } + + size += log2overhead (wpds->terms [0], nterms); + + if (size < best_size) { + memcpy (best_buffer, temp_buffer [j&1], buf_size); + memcpy (wps->decorr_passes, save_decorr_passes, sizeof (struct decorr_pass) * MAX_NTERMS); + wps->num_terms = nterms; + wps->best_decorr = c; + best_size = size; + } + + if (pi++) + wps->mask_decorr = wps->mask_decorr ? ((wps->mask_decorr << 1) & (wps->num_decorrs - 1)) : 1; + } + + if (force_js || (wps->decorr_specs [wps->best_decorr].joint_stereo && !force_ts)) + wps->wphdr.flags |= JOINT_STEREO; + else + wps->wphdr.flags &= ~((uint32_t) JOINT_STEREO); + + if (wpc->config.xmode > 3) { + if (wps->wphdr.flags & JOINT_STEREO) { + analyze_stereo (wpc, js_buffer, do_samples); + + if (do_samples) + memcpy (samples, js_buffer, buf_size); + } + else if (noisy_buffer) { + analyze_stereo (wpc, noisy_buffer, do_samples); + + if (do_samples) + memcpy (samples, noisy_buffer, buf_size); + } + else + analyze_stereo (wpc, samples, do_samples); + } + else if (do_samples) + memcpy (samples, best_buffer, buf_size); + + if (wpc->config.xmode > 3 || no_history || wps->joint_stereo != wps->decorr_specs [wps->best_decorr].joint_stereo) { + wps->joint_stereo = wps->decorr_specs [wps->best_decorr].joint_stereo; + scan_word (wps, best_buffer, num_samples, -1); + } + + if (noisy_buffer) + free (noisy_buffer); + + if (js_buffer) + free (js_buffer); + + free (temp_buffer [1]); + free (temp_buffer [0]); + free (best_buffer); + +#ifdef EXTRA_DUMP + if (1) { + char string [256], substring [20]; + int i; + + sprintf (string, "%s: terms =", + (wps->wphdr.flags & JOINT_STEREO) ? "JS" : "TS"); + + for (i = 0; i < wps->num_terms; ++i) { + if (wps->decorr_passes [i].term) { + if (i && wps->decorr_passes [i-1].delta == wps->decorr_passes [i].delta) + sprintf (substring, " %d", wps->decorr_passes [i].term); + else + sprintf (substring, " %d->%d", wps->decorr_passes [i].term, + wps->decorr_passes [i].delta); + } + else + sprintf (substring, " *"); + + strcat (string, substring); + } + + error_line (string); + } +#endif +} + diff --git a/wavpack-4.5.0/src/float.c b/wavpack-4.5.0/src/float.c new file mode 100644 index 0000000..a01cfb3 --- /dev/null +++ b/wavpack-4.5.0/src/float.c @@ -0,0 +1,371 @@ +//////////////////////////////////////////////////////////////////////////// +// **** 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 + +#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++; + } +} diff --git a/wavpack-4.5.0/src/libwavpack.sln b/wavpack-4.5.0/src/libwavpack.sln new file mode 100644 index 0000000..5bfa1f1 --- /dev/null +++ b/wavpack-4.5.0/src/libwavpack.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwavpack", "libwavpack.vcproj", "{5CCCB9CF-0384-458F-BA08-72B73866840F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|Win32.ActiveCfg = Debug|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|Win32.Build.0 = Debug|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|x64.ActiveCfg = Debug|x64 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Debug|x64.Build.0 = Debug|x64 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|Win32.ActiveCfg = Release|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|Win32.Build.0 = Release|Win32 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|x64.ActiveCfg = Release|x64 + {5CCCB9CF-0384-458F-BA08-72B73866840F}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/wavpack-4.5.0/src/libwavpack.vcproj b/wavpack-4.5.0/src/libwavpack.vcproj new file mode 100644 index 0000000..132c0f5 --- /dev/null +++ b/wavpack-4.5.0/src/libwavpack.vcproj @@ -0,0 +1,359 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wavpack-4.5.0/src/metadata.c b/wavpack-4.5.0/src/metadata.c new file mode 100644 index 0000000..c6d641e --- /dev/null +++ b/wavpack-4.5.0/src/metadata.c @@ -0,0 +1,313 @@ +//////////////////////////////////////////////////////////////////////////// +// **** 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 +#include + +#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, uchar *blockbuff, uchar **buffptr) +{ + WavpackHeader *wphdr = (WavpackHeader *) blockbuff; + uchar *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, uchar *buffer_start, uchar *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, uchar id) +{ + WavpackMetadata *mdp; + uchar *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) +{ + uchar 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; + } +} diff --git a/wavpack-4.5.0/src/pack.c b/wavpack-4.5.0/src/pack.c new file mode 100644 index 0000000..837b597 --- /dev/null +++ b/wavpack-4.5.0/src/pack.c @@ -0,0 +1,2992 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2006 Conifer Software. // +// MMX optimizations (c) 2006 Joachim Henke // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// pack.c + +// This module actually handles the compression of the audio data, except for +// the entropy coding which is handled by the words? modules. For efficiency, +// the conversion is isolated to tight loops that handle an entire buffer. + +#include "wavpack_local.h" + +#include +#include +#include +#include + +#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 + +//////////////////////////////// local tables /////////////////////////////// + +// These two tables specify the characteristics of the decorrelation filters. +// Each term represents one layer of the sequential filter, where positive +// values indicate the relative sample involved from the same channel (1=prev), +// 17 & 18 are special functions using the previous 2 samples, and negative +// values indicate cross channel decorrelation (in stereo only). + +static const WavpackDecorrSpec fast_specs [] = { + { 1, 2,18,17 }, // 0 + { 1, 1,17,17 }, // 1 + { 0, 2,18,17 }, // 2 + { 0, 1,17,17 }, // 3 + { 1, 3, 1,18 }, // 4 + { 1, 1,17, 1 }, // 5 + { 0, 1, 1,17 }, // 6 + { 0, 1,-2,17 }, // 7 + { 0, 2,-1,17 }, // 8 + { 1, 1,17, 2 }, // 9 + { 0, 3,18,18 }, // 10 + { 0, 1,17, 1 }, // 11 + { 1, 6, 1, 2 }, // 12 + { 1, 1,17, 3 }, // 13 + { 0, 1,-2, 3 }, // 14 + { 0, 1, 2,17 }, // 15 + { 0, 1,18,-2 }, // 16 + { 0, 1,-1,17 }, // 17 + { 0, 1,18,17 }, // 18 + { 0, 1,17, 2 }, // 19 + { 1, 2,18,-2 }, // 20 + { 1, 1, 1,17 }, // 21 + { 0, 3,18, 2 }, // 22 + { 0, 1,17,-2 }, // 23 + { 0, 1,18,-2 }, // 24 + { 1, 2,17,-3 }, // 25 + { 0, 1,18, 3 }, // 26 + { 0, 1,18,18 }, // 27 + { 1, 1, 1, 3 }, // 28 + { 1, 1,18, 3 }, // 29 + { 1, 1, 1, 3 }, // 30 + { 0, 2,18,17 }, // 31 + { 1, 1, 1,17 }, // 32 + { 1, 1,17, 3 }, // 33 + { 0, 3,18,17 }, // 34 + { 0, 1,18,18 }, // 35 + { 1, 1, 1, 3 }, // 36 + { 1, 1, 1,18 }, // 37 + { 0, 1,18,-2 }, // 38 + { 0, 2,18,17 }, // 39 + { 0, 1,-1,18 }, // 40 + { 1, 1,17, 3 }, // 41 + { 0, 1,17, 2 }, // 42 + { 0, 1,17, 3 }, // 43 + { 1, 1,18, 2 }, // 44 + { 1, 1,17,-2 }, // 45 + { 0, 1, 1,-2 }, // 46 + { 0, 2,18,17 }, // 47 + { 0, 1,17,-2 }, // 48 + { 1, 1,17,-2 }, // 49 + { 0, 1,18, 3 }, // 50 + { 0, 1, 2,17 }, // 51 + { 1, 2,18,-3 }, // 52 + { 1, 2, 1,18 }, // 53 + { 1, 2,18, 2 }, // 54 + { 0, 1,17,-1 }, // 55 + { 0, 1,17,-2 }, // 56 + { 1, 1,17,-2 }, // 57 + { 1, 1, 1, 3 }, // 58 + { 0, 1, 1,17 }, // 59 + { 1, 2,18,-2 }, // 60 + { 1, 2,17,-3 }, // 61 + { 0, 2,18,17 }, // 62 + { 0, 2,18,17 }, // 63 + { 1, 1,17, 2 }, // 64 + { 1, 2,18,18 }, // 65 + { 0, 1,17, 2 }, // 66 + { 0, 1,18,17 }, // 67 + { 1, 1, 1,17 }, // 68 + { 1, 1,17, 2 }, // 69 + { 0, 2,18,18 }, // 70 + { 0, 2,18,17 }, // 71 + { 1, 2,17,-3 }, // 72 + { 1, 6, 1, 2 }, // 73 + { 0, 3,17,17 }, // 74 + { 0, 1, 1,18 }, // 75 + { 0, 1, 1,-2 }, // 76 + { 1, 1,17, 2 }, // 77 + { 0, 2,18,17 }, // 78 + { 0, 2,18,17 }, // 79 + { 1, 1,18, 3 }, // 80 + { 1, 2,17,-3 }, // 81 + { 0, 1,17, 2 }, // 82 + { 0, 1,17, 3 }, // 83 + { 0, 1,18,-2 }, // 84 + { 1, 1,18,18 }, // 85 + { 1, 6, 1, 2 }, // 86 + { 0, 2,18,17 }, // 87 + { 0, 2,18,17 }, // 88 + { 0, 1,-1,17 }, // 89 + { 1, 1,18, 3 }, // 90 + { 0, 1,17,18 }, // 91 + { 1, 1,17, 3 }, // 92 + { 0, 1,18, 3 }, // 93 + { 0, 2,18,17 }, // 94 + { 0, 2,18,17 }, // 95 + { 1, 2,18, 2 }, // 96 + { 0, 1,-2, 3 }, // 97 + { 0, 4,18,-1 }, // 98 + { 0, 2,18,18 }, // 99 + { 0, 1,-2, 3 }, // 100 + { 1, 1,17,-2 }, // 101 + { 0, 1,17, 3 }, // 102 + { 0, 2,18,17 }, // 103 + { 0, 2,-1,18 }, // 104 + { 1, 1, 2,17 }, // 105 + { 0, 2,17,-2 }, // 106 + { 0, 1,17, 2 }, // 107 + { 1, 2,18,-3 }, // 108 + { 0, 1,17,-2 }, // 109 + { 0, 2,18,17 }, // 110 + { 0, 2,18,17 }, // 111 + { 1, 1,17,-2 }, // 112 + { 1, 2,17,-3 }, // 113 + { 1, 1, 1, 3 }, // 114 + { 1, 1, 2,17 }, // 115 + { 1, 2,18, 2 }, // 116 + { 1, 1, 2,17 }, // 117 + { 1, 1,18, 2 }, // 118 + { 0, 2,18,17 }, // 119 + { 0, 2,18,17 }, // 120 + { 0, 1,17,-2 }, // 121 + { 0, 2,18,17 }, // 122 + { 0, 2,17,-1 }, // 123 + { 0, 2,18,-2 }, // 124 + { 0, 2,18,17 }, // 125 + { 0, 2,18,17 }, // 126 + { 0, 2,18,17 }, // 127 + { 1, 1, 1, 3 }, // 128 + { 0, 2,-2,17 }, // 129 + { 0, 2,18,-2 }, // 130 + { 0, 2,17,-2 }, // 131 + { 1, 1, 2,17 }, // 132 + { 1, 1, 1, 3 }, // 133 + { 0, 1, 2,17 }, // 134 + { 0, 2,18,17 }, // 135 + { 0, 3,-1,17 }, // 136 + { 1, 1, 2,17 }, // 137 + { 0, 2,18,18 }, // 138 + { 0, 1,17, 2 }, // 139 + { 1, 4,18,-3 }, // 140 + { 1, 1,18, 1 }, // 141 + { 0, 2,18,17 }, // 142 + { 0, 2,18,17 }, // 143 + { 1, 2,18,-1 }, // 144 + { 0, 1,-1,18 }, // 145 + { 1, 6, 1, 2 }, // 146 + { 1, 1,17, 2 }, // 147 + { 1, 4,18, 3 }, // 148 + { 0, 1, 1,17 }, // 149 + { 0, 1,18, 2 }, // 150 + { 0, 2,18,17 }, // 151 + { 0, 2,18,17 }, // 152 + { 1, 2,17, 2 }, // 153 + { 0, 2,18,-2 }, // 154 + { 0, 1, 1,18 }, // 155 + { 1, 2,18,-3 }, // 156 + { 0, 2,18,17 }, // 157 + { 0, 2,18,17 }, // 158 + { 0, 2,18,17 }, // 159 + { 1, 2,18,18 }, // 160 + { 1, 3,17,17 }, // 161 + { 0, 1,-2,17 }, // 162 + { 0, 1,17,18 }, // 163 + { 0, 1,-1, 3 }, // 164 + { 1, 1, 2,17 }, // 165 + { 0, 2,18,-1 }, // 166 + { 0, 2,18,17 }, // 167 + { 0, 2,18,17 }, // 168 + { 1, 1,17,-2 }, // 169 + { 1, 2,17, 2 }, // 170 + { 1, 1,18, 3 }, // 171 + { 0, 1,18, 2 }, // 172 + { 1, 2,17,-3 }, // 173 + { 0, 2,18,17 }, // 174 + { 0, 2,18,17 }, // 175 + { 0, 1,-2,17 }, // 176 + { 0, 1,17,-1 }, // 177 + { 0, 1,18,-1 }, // 178 + { 0, 2,18,17 }, // 179 + { 1, 2,17,-3 }, // 180 + { 1, 1, 1,18 }, // 181 + { 1, 3,18, 2 }, // 182 + { 0, 2,18,17 }, // 183 + { 0, 2,18,17 }, // 184 + { 0, 2,18,17 }, // 185 + { 0, 2,18,17 }, // 186 + { 0, 3,18,18 }, // 187 + { 0, 1, 1,-2 }, // 188 + { 0, 2,18,17 }, // 189 + { 0, 2,18,17 }, // 190 + { 0, 2,18,17 }, // 191 + { 1, 2,17,-3 }, // 192 + { 1, 1,18,18 }, // 193 + { 0, 2,18, 2 }, // 194 + { 0, 1,17,18 }, // 195 + { 1, 2,18, 2 }, // 196 + { 1, 1,17,-2 }, // 197 + { 0, 2,17,-1 }, // 198 + { 0, 2,18,17 }, // 199 + { 0, 2,18,17 }, // 200 + { 0, 2,18,17 }, // 201 + { 0, 1, 1,-2 }, // 202 + { 0, 1,18, 1 }, // 203 + { 1, 2,18,-2 }, // 204 + { 0, 1,17, 2 }, // 205 + { 0, 2,18,17 }, // 206 + { 0, 2,18,17 }, // 207 + { 1, 1,17, 3 }, // 208 + { 0, 1,17,-1 }, // 209 + { 0, 1,18, 2 }, // 210 + { 1, 1,17, 3 }, // 211 + { 1, 1,17,-2 }, // 212 + { 0, 1,18,18 }, // 213 + { 0, 2,18,17 }, // 214 + { 0, 2,18,17 }, // 215 + { 0, 2,18,17 }, // 216 + { 0, 2,18,17 }, // 217 + { 0, 2,18,17 }, // 218 + { 1, 1,17,18 }, // 219 + { 0, 1,-2, 3 }, // 220 + { 0, 2,18,17 }, // 221 + { 0, 2,18,17 }, // 222 + { 0, 2,18,17 }, // 223 + { 1, 2,18,-3 }, // 224 + { 0, 2,18,17 }, // 225 + { 0, 3,18, 2 }, // 226 + { 0, 1, 1,18 }, // 227 + { 0, 2,18,17 }, // 228 + { 0, 1,17,-1 }, // 229 + { 0, 2,18,17 }, // 230 + { 0, 2,18,17 }, // 231 + { 0, 2,18,17 }, // 232 + { 0, 1,-2, 3 }, // 233 + { 0, 3,17,17 }, // 234 + { 0, 2,18,17 }, // 235 + { 0, 2,18,17 }, // 236 + { 1, 1,17, 2 }, // 237 + { 0, 2,18,17 }, // 238 + { 0, 2,18,17 }, // 239 + { 1, 1,17, 2 }, // 240 + { 0, 2,18,17 }, // 241 + { 0, 2,18,17 }, // 242 + { 0, 2,18,17 }, // 243 + { 0, 2,18, 2 }, // 244 + { 0, 2,18,17 }, // 245 + { 0, 2,18,17 }, // 246 + { 0, 2,18,17 }, // 247 + { 0, 2,18,17 }, // 248 + { 0, 2,18,17 }, // 249 + { 0, 2,18,17 }, // 250 + { 0, 2,18,17 }, // 251 + { 0, 2,18,17 }, // 252 + { 0, 2,18,17 }, // 253 + { 0, 2,18,17 }, // 254 + { 0, 2,18,17 }, // 255 +}; + +static const WavpackDecorrSpec default_specs [] = { + { 1, 2,18,18, 2,17, 3 }, // 0 + { 0, 2,18,17,-1, 3, 2 }, // 1 + { 1, 1,17,18,18,-2, 2 }, // 2 + { 0, 2,18,17, 3,-2,17 }, // 3 + { 1, 2,18,17, 2,17, 3 }, // 4 + { 0, 1,18,18,-1, 2,17 }, // 5 + { 0, 1,17,17,-2, 2, 3 }, // 6 + { 0, 1,18,-2,18, 2,17 }, // 7 + { 1, 2,18,18,-1, 2, 3 }, // 8 + { 0, 2,18,17, 3, 2, 5 }, // 9 + { 1, 1,18,17,18, 2, 5 }, // 10 + { 0, 1,17,17,-2, 2, 3 }, // 11 + { 0, 1,18,-2,18, 2, 5 }, // 12 + { 0, 1,17,-2,17, 2,-3 }, // 13 + { 1, 1,17,-2,17, 1, 2 }, // 14 + { 0, 1,17,17,-2, 2, 3 }, // 15 + { 1, 1,18, 3, 1, 5, 4 }, // 16 + { 1, 4,18,18, 2, 3,-2 }, // 17 + { 0, 1, 1,-1,-1, 2,17 }, // 18 + { 0, 2,18,17, 3, 2, 5 }, // 19 + { 0, 1,18,18,18, 2,17 }, // 20 + { 0, 1,18,17,-1, 2,18 }, // 21 + { 1, 1,17, 3, 2, 1, 7 }, // 22 + { 0, 2,18,-2,18, 2, 3 }, // 23 + { 1, 3,18,-3,18, 2, 3 }, // 24 + { 0, 3,18,17, 2, 3,17 }, // 25 + { 1, 1,17,17, 2, 1, 4 }, // 26 + { 0, 1,17,18,-2, 2,17 }, // 27 + { 1, 1,18,18, 3, 5, 2 }, // 28 + { 0, 1,17,17, 2,18, 4 }, // 29 + { 0, 1,18,17, 1, 4, 6 }, // 30 + { 1, 1, 3,17,18, 2,17 }, // 31 + { 1, 1,17, 3, 2, 1, 7 }, // 32 + { 0, 1,18,17,-1, 2, 3 }, // 33 + { 1, 1,17,17, 2, 1, 4 }, // 34 + { 1, 2,18,17,-1,17, 3 }, // 35 + { 1, 2,18,17, 2, 3,-1 }, // 36 + { 0, 2,18,18,-2, 2,17 }, // 37 + { 0, 1,17,17, 2,18, 4 }, // 38 + { 0, 5,-2,18,18,18, 2 }, // 39 + { 1, 1,18,18,-1, 6, 3 }, // 40 + { 0, 1,17,17,-2, 2, 3 }, // 41 + { 1, 1,18,17,18, 2,17 }, // 42 + { 0, 1,18,17, 4, 3, 1 }, // 43 + { 0, 1,-2,18, 2, 2,18 }, // 44 + { 1, 2,18,18,-2, 2,-1 }, // 45 + { 1, 1,17,17, 2, 1, 4 }, // 46 + { 0, 1,17,18,-2, 2,17 }, // 47 + { 1, 1,17, 3, 2, 1, 7 }, // 48 + { 1, 3,18,-3,18, 2, 3 }, // 49 + { 1, 2,18,18,-2, 2,-1 }, // 50 + { 1, 1,18,18, 3, 5, 2 }, // 51 + { 0, 2,18,18,-1, 2,17 }, // 52 + { 0, 1,18,-1,17,18, 2 }, // 53 + { 0, 1,17,-1, 2, 3, 6 }, // 54 + { 0, 1,18,-2,18, 2, 5 }, // 55 + { 1, 2,18,18,-2, 2,-1 }, // 56 + { 0, 3,18,18, 2, 3,17 }, // 57 + { 0, 1,17,17, 2,18, 4 }, // 58 + { 1, 1,17,-2,17, 1, 2 }, // 59 + { 0, 1,-1, 3, 5, 4, 7 }, // 60 + { 0, 3,18,18, 3, 2, 5 }, // 61 + { 0, 1,17,17, 2,18, 4 }, // 62 + { 0, 1,18,17,-2,18, 3 }, // 63 + { 0, 2,18,18,-2, 2,17 }, // 64 + { 0, 3,18,17,-2, 2, 3 }, // 65 + { 1, 1,18,18,-2, 2,17 }, // 66 + { 0, 1,18,17, 4, 3, 1 }, // 67 + { 1, 2, 3,18,17, 2,17 }, // 68 + { 1, 2,18,18, 2,-2,18 }, // 69 + { 1, 2,18,18,-1,18, 2 }, // 70 + { 0, 2,18,18,-2, 2,17 }, // 71 + { 1, 3,18,18, 2, 3,-2 }, // 72 + { 0, 3,18,18, 3, 2, 5 }, // 73 + { 0, 1,18,-2,18, 2, 5 }, // 74 + { 1, 1,17, 3, 2, 1, 7 }, // 75 + { 1, 3,18,18,-2, 2,18 }, // 76 + { 1, 1,17,18,18,-2, 2 }, // 77 + { 0, 1,18,-2,18, 2, 5 }, // 78 + { 0, 2,18,-2,18, 2, 3 }, // 79 + { 0, 1,-1, 3, 4, 5, 7 }, // 80 + { 1, 1,17,17, 2,-1, 7 }, // 81 + { 0, 1,18,-1,-1, 2,-2 }, // 82 + { 0, 2,18,17, 2, 3,17 }, // 83 + { 0, 1,18,17, 2,18, 2 }, // 84 + { 0, 2,18,17,-1, 2,17 }, // 85 + { 0, 1, 1,18, 3, 2, 5 }, // 86 + { 0, 2,18,-2, 4,18, 2 }, // 87 + { 1, 1,18, 3, 1, 5, 4 }, // 88 + { 0, 1,18,17,18, 2, 5 }, // 89 + { 1, 1,18, 3, 1, 5, 4 }, // 90 + { 0, 4,18,18,-2, 2,18 }, // 91 + { 1, 1,18,18, 3, 2, 5 }, // 92 + { 1, 1,17,17, 2, 1, 4 }, // 93 + { 0, 2,18,18,-2,18, 2 }, // 94 + { 0, 2,18,18,-2,18, 2 }, // 95 + { 1, 1,18,18, 2, 1, 3 }, // 96 + { 1, 1,17,17, 2, 1, 4 }, // 97 + { 1, 2,17,17, 2,18, 3 }, // 98 + { 0, 1,18,17, 1, 4, 6 }, // 99 + { 1, 2,18,18,-2, 2,-1 }, // 100 + { 0, 1,18,-2,18, 2, 5 }, // 101 + { 1, 1,17, 2,18, 2,17 }, // 102 + { 0, 2,18,18,-2,18, 2 }, // 103 + { 0, 1,18,18, 3, 6,-1 }, // 104 + { 0, 1,18,17, 2,18, 3 }, // 105 + { 0, 1,18,17,-2, 2,17 }, // 106 + { 1, 1, 3,17,18, 2,17 }, // 107 + { 1, 3,18,-3,18, 2, 3 }, // 108 + { 1, 3,18,18,-3,18, 2 }, // 109 + { 1, 1,18, 3, 1, 5, 4 }, // 110 + { 0, 1,17,-2,17, 2,-3 }, // 111 + { 1, 1,18,18, 3, 5, 2 }, // 112 + { 1, 2,18,18,-2, 2,-1 }, // 113 + { 0, 1,18,-1,-1, 2,-2 }, // 114 + { 1, 1,18, 3, 1, 5, 4 }, // 115 + { 0, 3,18,17,-1, 2,17 }, // 116 + { 1, 3,18,17, 2,18,-2 }, // 117 + { 0, 2,18,18,-2,18, 2 }, // 118 + { 1, 2,18,18,-2, 2,-1 }, // 119 + { 1, 1,18, 3, 1, 5, 4 }, // 120 + { 0, 4, 3,18,18, 2,17 }, // 121 + { 0, 2,18,18,-2,18, 2 }, // 122 + { 1, 1,18,17,-1,18, 2 }, // 123 + { 0, 2,18,18,-2,18, 2 }, // 124 + { 0, 2,18,18,-2,18, 2 }, // 125 + { 0, 2,18,18,-2,18, 2 }, // 126 + { 0, 2,18,18,-2,18, 2 }, // 127 + { 1, 1,18,18,18, 3, 2 }, // 128 + { 0, 1,17,-1, 2, 3, 6 }, // 129 + { 0, 1,17,-1, 2, 3, 6 }, // 130 + { 0, 2,18,17,-2, 3, 2 }, // 131 + { 1, 3,18,17, 2,-2,18 }, // 132 + { 0, 2,18,18, 2,17, 3 }, // 133 + { 0, 1,18,18, 2,18,-2 }, // 134 + { 0, 2,18,-2, 4,18, 2 }, // 135 + { 0, 1,-2,18, 2, 2,18 }, // 136 + { 0, 2,18,17, 3, 6, 2 }, // 137 + { 0, 1,18,17,18, 2, 5 }, // 138 + { 0, 3,18,18,-2, 3, 2 }, // 139 + { 1, 1,18,18, 2,18, 5 }, // 140 + { 0, 1,17,-1, 2, 3, 6 }, // 141 + { 1, 4,18,18, 2, 3,-2 }, // 142 + { 0, 2,18,17,18, 2,-2 }, // 143 + { 0, 1, 1,18, 3, 2, 5 }, // 144 + { 1, 4,18,-2,18, 2, 3 }, // 145 + { 1, 2,18, 2,18, 3,-2 }, // 146 + { 0, 2,18,18,18, 2, 4 }, // 147 + { 0, 2, 3,17,18, 2,17 }, // 148 + { 1, 1,18,-1,18, 2,17 }, // 149 + { 1, 2,17,17, 2,18, 3 }, // 150 + { 0, 2,18,17,-2, 3, 2 }, // 151 + { 0, 1, 1,-1,-1, 2,17 }, // 152 + { 0, 3, 3,18,18, 2,17 }, // 153 + { 0, 1,18,-1,17,18, 2 }, // 154 + { 0, 1,18,17, 2,18, 3 }, // 155 + { 0, 2,18,18,-2,18, 2 }, // 156 + { 0, 1,18,17, 2,18, 2 }, // 157 + { 0, 2,18,18,-2,18, 2 }, // 158 + { 0, 2,18,18,-2,18, 2 }, // 159 + { 1, 2,17,17, 2,18, 3 }, // 160 + { 0, 1,18,17,-2, 2, 3 }, // 161 + { 0, 1,18,-2,18, 2, 5 }, // 162 + { 1, 4,18,-2,18, 2, 3 }, // 163 + { 1, 3,18,17, 2, 3, 6 }, // 164 + { 0, 2,18,18, 2,17, 3 }, // 165 + { 0, 2,18,17, 2,18, 2 }, // 166 + { 0, 2,18,18,-2,18, 2 }, // 167 + { 1, 1,18,18, 3, 5, 2 }, // 168 + { 0, 2,18,18,-2, 2, 3 }, // 169 + { 1, 2,18,17, 2,17, 3 }, // 170 + { 0, 1,18,17, 2, 3,18 }, // 171 + { 0, 2,18,18,-2,18, 2 }, // 172 + { 1, 4,18,18, 2, 3,-2 }, // 173 + { 0, 1,17,-2,17, 2,-3 }, // 174 + { 0, 1,17,17, 2,18, 4 }, // 175 + { 1, 1,18,18,18, 2, 4 }, // 176 + { 1, 2,18, 2,18, 3,-2 }, // 177 + { 1, 1,18,18,-2, 2,17 }, // 178 + { 0, 2,18,18,-2,18, 2 }, // 179 + { 0, 2,18,18, 2,17, 3 }, // 180 + { 0, 2,18,18,18, 2, 4 }, // 181 + { 0, 2,18,18,-2,18, 2 }, // 182 + { 0, 2,18,17,-2, 3, 2 }, // 183 + { 0, 1, 1,-1,-1, 2,17 }, // 184 + { 1, 4,18,18, 2, 3,-2 }, // 185 + { 0, 2,18,18,-2,18, 2 }, // 186 + { 0, 1,18,-2,18, 3, 2 }, // 187 + { 0, 2,18,18,-2,18, 2 }, // 188 + { 0, 2,18,18,-2,18, 2 }, // 189 + { 0, 2,18,18,-2,18, 2 }, // 190 + { 0, 2,18,18,-2,18, 2 }, // 191 + { 0, 1,18,18,-2, 2,17 }, // 192 + { 0, 3,18,17, 2, 3,17 }, // 193 + { 1, 2,18,18, 2,-2,18 }, // 194 + { 0, 1,-1, 3, 5, 4, 7 }, // 195 + { 1, 1,18, 3, 1, 5, 4 }, // 196 + { 1, 1,18,18,-2,18, 3 }, // 197 + { 0, 2,18,17,18, 2,-2 }, // 198 + { 0, 2,18,18, 2,17, 3 }, // 199 + { 1, 2,18, 2,18, 3,-2 }, // 200 + { 1, 4,18,18, 2, 3,-2 }, // 201 + { 1, 3,18,17, 2, 3, 6 }, // 202 + { 0, 2,18,18,-2,18, 2 }, // 203 + { 1, 2,18,17,-2,-1,17 }, // 204 + { 0, 1,17,-1, 2, 3, 6 }, // 205 + { 0, 2,18,18,-2,18, 2 }, // 206 + { 0, 2,18,18,-2, 2, 3 }, // 207 + { 1, 1,18,18,18, 2, 5 }, // 208 + { 0, 1,17,17,-2, 2, 3 }, // 209 + { 0, 2,18,18,-2,18, 2 }, // 210 + { 0, 2,18,17, 3, 6, 2 }, // 211 + { 0, 2,18,17,18, 2, 3 }, // 212 + { 0, 3,18,17,-3,18, 2 }, // 213 + { 0, 1,18,18,18, 2, 3 }, // 214 + { 0, 1,18,-2,-3, 2, 6 }, // 215 + { 0, 2,18,18,-2,18, 2 }, // 216 + { 1, 1,18,17,18, 2, 5 }, // 217 + { 0, 2,18,18,-2,18, 2 }, // 218 + { 0, 2,18,18,-2,18, 2 }, // 219 + { 1, 1,18,17,18, 2, 5 }, // 220 + { 0, 2,18,18,-2,18, 2 }, // 221 + { 0, 2,18,18,-2,18, 2 }, // 222 + { 0, 2,18,18,-2,18, 2 }, // 223 + { 0, 1,18,18,18, 2, 3 }, // 224 + { 1, 1,17,-2,17, 1, 2 }, // 225 + { 1, 1,17,17, 2,-1, 7 }, // 226 + { 0, 1,18,17, 4, 3, 1 }, // 227 + { 1, 3,18,-3,18, 2, 3 }, // 228 + { 0, 1, 1,18, 3, 2, 5 }, // 229 + { 0, 2,18,18,-2,18, 2 }, // 230 + { 0, 2,18,18,-2,18, 2 }, // 231 + { 0, 1,18,18, 3, 6, 2 }, // 232 + { 0, 1,17,17, 2,18, 4 }, // 233 + { 0, 1,17,17, 2,18, 4 }, // 234 + { 0, 2,18,18,-2,18, 2 }, // 235 + { 0, 2,18,18,-2,18, 2 }, // 236 + { 0, 2,18,18,-2,18, 2 }, // 237 + { 1, 2,18,-2,18, 3, 2 }, // 238 + { 1, 1,17,-2,17, 1, 2 }, // 239 + { 1, 1,18,18, 3, 2, 5 }, // 240 + { 0, 1,18,18,-1, 2, 3 }, // 241 + { 0, 2,18,18,-2,18, 2 }, // 242 + { 0, 2,18,18,-2,18, 2 }, // 243 + { 0, 1,18,17,18, 2, 5 }, // 244 + { 0, 2,18,18,-2,18, 2 }, // 245 + { 0, 2,18,18,-2,18, 2 }, // 246 + { 0, 2,18,18,-2,18, 2 }, // 247 + { 0, 2,18,18,-2,18, 2 }, // 248 + { 0, 1, 3,18,18, 2,17 }, // 249 + { 0, 2,18,18,-2,18, 2 }, // 250 + { 0, 2,18,18,-2,18, 2 }, // 251 + { 0, 2,18,18,-2,18, 2 }, // 252 + { 0, 2,18,18,-2,18, 2 }, // 253 + { 0, 2,18,18,-2,18, 2 }, // 254 + { 0, 2,18,18,-2,18, 2 }, // 255 +}; + +static const WavpackDecorrSpec high_specs [] = { + { 1, 2,18,18,18,-2, 2, 3, 5,-1,17, 4 }, // 0 + { 0, 1,18,17,-2, 2,18, 3, 7, 2, 5, 4 }, // 1 + { 1, 2, 1,18, 3, 6,-2,18, 2, 3, 4, 5 }, // 2 + { 0, 2,18,18,-2, 2,18, 3, 6, 2,17, 4 }, // 3 + { 1, 2,18,18, 2,18, 3, 2,-1, 4,18, 5 }, // 4 + { 1, 1, 7, 6, 5, 3, 4, 2, 5, 4, 3, 7 }, // 5 + { 1, 1,17, 3,18, 7, 2, 6, 1, 4, 3, 5 }, // 6 + { 1, 1,-2,18,18,18, 3,-2, 6, 5, 2, 1 }, // 7 + { 1, 2,18,18,-1,18, 2, 3, 6,-2,17, 5 }, // 8 + { 0, 1,17,17,18, 3, 6, 4, 5, 2,18,-2 }, // 9 + { 1, 2, 1,18,-2, 3, 5, 2, 4,-1, 6, 1 }, // 10 + { 0, 2,18,18, 3, 6,18, 2, 4, 8, 5, 3 }, // 11 + { 0, 1,-2, 1,18, 2,-2, 7,18, 2,-1, 5 }, // 12 + { 1, 1, 4, 3, 8, 1, 5, 2, 5, 6, 2, 8 }, // 13 + { 1, 1,17,18, 2, 6, 3, 4,-1, 1, 8, 6 }, // 14 + { 0, 1,18,18, 3, 6, 3,-2, 2, 5,-1, 1 }, // 15 + { 0, 1,18,18,17,-1, 2,-2,18, 3, 4, 5 }, // 16 + { 1, 2,18,17, 2,-2,18, 3, 5, 7, 2, 4 }, // 17 + { 1, 2,18,18, 3, 6,-2,18, 2, 5, 8, 3 }, // 18 + { 0, 1,18,17, 2,18,18, 2, 6, 5,17, 7 }, // 19 + { 1, 2,18,17, 2,18, 3, 2, 6,18,-1, 4 }, // 20 + { 1, 1, 5, 3, 6, 5, 3, 4, 1, 2, 4, 7 }, // 21 + { 1, 1, 5, 3, 6, 5, 3, 4, 1, 2, 4, 7 }, // 22 + { 0, 1,-2,18,18,18,-2, 3, 2, 4, 6, 5 }, // 23 + { 1, 2,18,17,-3, 3,-1,18, 2, 3, 6, 5 }, // 24 + { 0, 1,17,18, 7, 3,-2, 7, 1, 2, 4, 5 }, // 25 + { 1, 1, 2,18,18,-2, 2, 4,-1,18, 3, 6 }, // 26 + { 0, 3, 1,18, 4, 3, 5, 2, 4,18, 2, 3 }, // 27 + { 0, 1,-2,18, 2,18, 3, 7,18, 2, 6,-2 }, // 28 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 29 + { 1, 1,18,18, 5, 4, 6, 4, 5, 1, 4, 3 }, // 30 + { 1, 1,18, 3, 6, 5, 7, 8, 2, 3, 1,-1 }, // 31 + { 1, 1,18,18,18, 2,-2, 3, 5,18, 2, 8 }, // 32 + { 0, 2,18,17,-2, 2, 3,18,-3, 5, 2, 7 }, // 33 + { 1, 1, 1, 1,-1, 8,17, 3,-2, 2, 6,17 }, // 34 + { 0, 2,18,18,17, 2,-2, 3, 2, 4,18, 5 }, // 35 + { 1, 1,17,18, 2,-1, 5, 7,18, 3, 4, 6 }, // 36 + { 1, 1, 5, 4, 5,17, 3, 6, 3, 4, 7, 2 }, // 37 + { 0, 1,17, 3, 1, 7, 4, 2, 5,-2,18, 6 }, // 38 + { 0, 1,17,18, 2,18, 4, 3, 5, 7,-3, 6 }, // 39 + { 1, 2,17,17,-3,-2, 2, 8,18,-1, 3, 5 }, // 40 + { 0, 1,17,17,18, 2, 3, 6,-2, 8, 1, 7 }, // 41 + { 1, 1, 1, 2, 6,-2,18, 2, 5,-3, 7,-2 }, // 42 + { 0, 1,18,18, 3,18, 6, 8,-2, 2, 3, 5 }, // 43 + { 0, 1,18,17, 2,18,-2, 3, 7, 6, 2, 4 }, // 44 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 45 + { 1, 1,18,18, 2,-1, 3, 6, 1, 3, 4, 8 }, // 46 + { 0, 1,18,18, 3, 6, 5, 3,-2, 2,18,-1 }, // 47 + { 0, 1,18,17,-3,18, 2, 4,-2, 3, 6,17 }, // 48 + { 1, 3, 1, 2,17, 3,18, 7,-1, 5, 2, 4 }, // 49 + { 1, 1,18, 3,18, 6, 8,18,-2, 5, 7, 2 }, // 50 + { 0, 1,17, 2,18, 6, 3, 2, 5, 4, 8, 1 }, // 51 + { 0, 1,18,17,-1, 2, 3,18,18, 2, 3,17 }, // 52 + { 1, 1,18, 7, 6, 5, 5, 3, 1, 4, 2, 4 }, // 53 + { 1, 1, 6,17, 3, 8, 1, 5, 7,-1, 2, 1 }, // 54 + { 1, 1,18,-2,18, 3,-2, 2, 7, 4, 6,18 }, // 55 + { 1, 3,18,-3,18, 2, 3,18,-1, 7, 2, 5 }, // 56 + { 0, 2,18,-2, 7, 1, 3, 2, 4, 6,-3, 7 }, // 57 + { 1, 1,18,-2, 2,-3,18,-2,17,-1, 4, 2 }, // 58 + { 0, 3,17,17, 2, 5, 3, 7,18, 6, 4, 2 }, // 59 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 60 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 61 + { 1, 1,18,17, 4, 6, 6, 4, 5, 3, 4, 1 }, // 62 + { 0, 1,18, 5, 3, 6, 2, 3, 8, 1, 3, 7 }, // 63 + { 1, 2,18,17,-2, 2,18, 3, 5, 7,-1, 2 }, // 64 + { 0, 1, 1,18,18, 3, 6,-1, 4, 8, 5, 2 }, // 65 + { 1, 1, 1, 5, 3, 4, 1, 1, 3, 5, 7, 3 }, // 66 + { 0, 1, 3,18,18, 2,18,18,-1, 2, 3,18 }, // 67 + { 1, 2,18,18,-1,18, 2, 3, 4, 6,18, 5 }, // 68 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 69 + { 1, 1,18, 3, 1, 4, 5, 2, 7, 1, 3, 6 }, // 70 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 71 + { 1, 2,18,18,-1,18, 2, 3, 5,-2, 6, 8 }, // 72 + { 1, 1,17,18, 4, 8, 3, 2, 5, 2, 7, 6 }, // 73 + { 1, 4, 1, 2, 5,18,-2, 2, 3, 7,-1, 4 }, // 74 + { 0, 2,18,17,-1, 3, 6,18, 2, 3, 7, 5 }, // 75 + { 0, 1,-2,18, 2,-3, 6,18, 4, 3,-2, 5 }, // 76 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 77 + { 0, 1,17,17, 6, 2, 4, 8, 3, 5,-1,17 }, // 78 + { 1, 1,18, 3,18, 6, 8,18,-2, 5, 7, 2 }, // 79 + { 1, 2,17,17,-3, 2,18,-2, 8, 3, 6,-1 }, // 80 + { 1, 1,18,-2,17,18, 2, 3,-2, 6, 5, 4 }, // 81 + { 1, 2,18,17,-1, 3,18, 2, 5, 3, 6,-3 }, // 82 + { 0, 1,18,17, 2,18, 7,18, 2, 4, 3,17 }, // 83 + { 1, 3,18,18, 5, 6, 4, 3, 4,18, 6, 5 }, // 84 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 85 + { 1, 1, 7, 6, 5, 3, 4, 2, 5, 4, 3, 7 }, // 86 + { 0, 1,-2,18,18,18, 3, 6, 4, 2, 5, 2 }, // 87 + { 0, 3,18,17,-3,18, 3, 2, 5,-1,17, 3 }, // 88 + { 1, 1,17,18, 7, 3, 1, 7, 4, 2, 6, 5 }, // 89 + { 1, 1,18, 2,-2,-1,18, 5, 3,-2, 1, 2 }, // 90 + { 0, 3,18,18,-1, 3, 2, 7, 5,18, 4, 3 }, // 91 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 92 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 93 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 94 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 95 + { 1, 1,17,18, 2,-2, 4, 8,18, 3, 6, 5 }, // 96 + { 0, 2,18,17, 3, 5,-2, 7, 2,18, 3,-1 }, // 97 + { 1, 1,18, 2,-2,-1,18, 5, 3,-2, 1, 2 }, // 98 + { 0, 2, 3,17,18,18, 2, 5, 7, 6,18, 3 }, // 99 + { 1, 1,17,18,18, 4, 3, 2,18, 7, 8,-1 }, // 100 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 101 + { 0, 1,17, 1, 2, 3, 5, 6, 1, 4, 8,17 }, // 102 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 103 + { 0, 2,18,17,-1,18,-3, 2, 8, 3, 6,17 }, // 104 + { 1, 1,17,17, 1, 2, 4, 5,-1, 2, 1, 6 }, // 105 + { 1, 1, 1, 2, 6,-2,18, 2,-3, 3,-2, 5 }, // 106 + { 0, 1,18, 3,18, 6,18, 5, 2, 4,-1, 8 }, // 107 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 108 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 109 + { 1, 1,18,18,-1, 2,18, 3, 6, 4,-2, 7 }, // 110 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 111 + { 0, 2,-1,18,18,18, 2,-2, 4, 7, 2, 3 }, // 112 + { 0, 3, 3,17,-2, 5, 2, 7,18, 6, 4, 5 }, // 113 + { 0, 1,17, 6,18, 3, 8, 4, 5, 3, 8,18 }, // 114 + { 0, 2,18, 2, 6, 2,18, 3, 2, 4, 5, 8 }, // 115 + { 0, 1, 3,18,18, 2,18,-1, 2,18, 2,17 }, // 116 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 117 + { 0, 1, 3, 6,17,-2, 5, 1, 2, 7, 4, 8 }, // 118 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 119 + { 1, 3, 3,18,17, 5, 6, 2, 7,-2, 8,18 }, // 120 + { 1, 1,18,-1, 3, 1, 7, 2,-1, 4, 6,17 }, // 121 + { 1, 1,18, 2,-2,-1,18, 5, 3,-2, 1, 2 }, // 122 + { 0, 2,18, 1, 2,18, 3, 6, 5, 2, 4, 8 }, // 123 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 124 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 125 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 126 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 127 + { 1, 1,17,-2, 2,18,18, 8, 5, 3, 2, 6 }, // 128 + { 0, 1,18,17, 2,18, 3, 2, 7,-2,18, 4 }, // 129 + { 1, 2, 1,18, 2, 3,-1, 5, 6, 4, 7,17 }, // 130 + { 0, 2,18,17, 3, 6,-2, 2, 3, 8, 5,17 }, // 131 + { 0, 2,18,18, 3, 2,18,-1, 2, 4, 3,17 }, // 132 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 133 + { 1, 2,17,-1,18, 2, 3,-2, 5,18, 2, 7 }, // 134 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 135 + { 1, 2,18,-3,18, 2, 3,-2,18, 5, 6,-3 }, // 136 + { 0, 2,18,17, 3, 5,-2, 7, 2,18, 3,-1 }, // 137 + { 1, 1, 1,18,-1, 2, 3, 1,-2, 8, 2, 5 }, // 138 + { 0, 1,18,18, 3, 6,18, 2, 3, 4, 8, 5 }, // 139 + { 0, 1,-2, 1,18, 2,-2, 5, 7,18, 2,-1 }, // 140 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 141 + { 1, 1,17,18,-1, 2, 8, 3, 4, 5, 1, 7 }, // 142 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 143 + { 0, 2,18,18,-1, 2,18, 3,-2, 5, 4, 2 }, // 144 + { 1, 1,18,17, 2,18, 3, 8, 5, 2, 7,17 }, // 145 + { 0, 1,18,18, 3,18, 6, 8,-2, 2, 3, 5 }, // 146 + { 0, 1,18,18, 2,18, 2, 6,18, 2,17, 7 }, // 147 + { 1, 3,18,17,18, 2, 8,18, 5,-1, 3, 6 }, // 148 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 149 + { 1, 1,18, 7, 6, 5, 5, 3, 1, 4, 2, 4 }, // 150 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 151 + { 1, 2,18,17,-1, 3, 6,18, 2, 5, 8, 3 }, // 152 + { 0, 1,17,18,18, 4, 7, 2, 3,-2,18, 5 }, // 153 + { 1, 2,18, 1, 2, 6, 2, 5,18, 2, 4, 8 }, // 154 + { 0, 4,18, 4, 1, 2, 3, 5, 4, 1, 2, 6 }, // 155 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 156 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 157 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 158 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 159 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 160 + { 0, 2,18,17, 2,-1,18, 3,-3, 5, 2, 4 }, // 161 + { 0, 1,17,17, 3, 6, 3, 5,-2, 2,18,-1 }, // 162 + { 0, 2,18,18, 3,-2,18, 2,-3, 5, 3, 6 }, // 163 + { 1, 1,17,17, 2, 4, 1, 3, 5, 2, 6,-3 }, // 164 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 165 + { 0, 1,17, 1, 3, 2, 7, 1, 6, 3, 4, 8 }, // 166 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 167 + { 0, 1,17,-1,18, 2, 1, 5, 3, 8,-1,-2 }, // 168 + { 1, 1,17,18,-1, 8, 2, 5, 3, 4, 1, 6 }, // 169 + { 1, 2, 1,18, 3,-1, 5, 1, 2, 4, 7, 6 }, // 170 + { 0, 1,18,18, 3, 6, 5, 3,-2, 2,18,-1 }, // 171 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 172 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 173 + { 0, 1, 1,18,-1, 3, 8, 5, 6, 1, 2, 3 }, // 174 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 175 + { 0, 2,18,18, 2, 3, 6,18,-1, 4, 2, 3 }, // 176 + { 1, 1, 1, 3, 5,18, 2, 6, 7, 2, 3, 1 }, // 177 + { 1, 1, 1, 3, 8,18, 5, 2, 7, 1, 3,-2 }, // 178 + { 0, 2,17, 2,18, 3, 6, 2, 4, 5, 8, 3 }, // 179 + { 0, 1,18,17, 2,18, 3, 2, 7,-2,18, 4 }, // 180 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 181 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 182 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 183 + { 1, 2,18,-3,18,-1, 3,-2, 5, 7, 1, 2 }, // 184 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 185 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 186 + { 0, 3,18,18, 2, 6,18, 5,18, 2, 3,17 }, // 187 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 188 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 189 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 190 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 191 + { 1, 3, 1,-1, 1, 3,-2, 2, 5, 7,-3,18 }, // 192 + { 1, 2,18, 7, 3,-3, 2, 8, 2, 5, 4,17 }, // 193 + { 1, 1, 1, 4, 5, 1, 3, 4, 6, 7, 8, 3 }, // 194 + { 0, 1,18,17, 2,18,-1, 2, 3,18, 2, 4 }, // 195 + { 0, 2,18,18,-2,18, 2, 3, 4, 7, 5,17 }, // 196 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 197 + { 1, 1,17,18, 2, 1, 3, 2, 5, 1, 2, 3 }, // 198 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 199 + { 0, 2,18,18,-1, 2, 3, 5, 8, 6, 1,-2 }, // 200 + { 0, 1,17,18, 8, 3, 4, 6, 5, 2, 8, 7 }, // 201 + { 1, 2, 1, 3,-2,18, 2, 5, 1, 7,-1,-2 }, // 202 + { 0, 3,18,17,-1, 3,18, 2, 3, 6, 4,17 }, // 203 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 204 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 205 + { 1, 2,18,18, 4,18, 6, 7, 8, 3,18, 2 }, // 206 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 207 + { 0, 2,17,-3,17, 2,-2, 8, 3,18, 4,-3 }, // 208 + { 1, 1,18,17, 3, 5, 6, 2, 8, 1, 3, 7 }, // 209 + { 0, 1,18,18, 3, 6, 5, 3,-2, 2,18,-1 }, // 210 + { 0, 3,18,18, 2, 6,18, 5,18, 2, 3,17 }, // 211 + { 1, 1,18,18, 5, 4, 6, 4, 5, 1, 4, 3 }, // 212 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 213 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 214 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 215 + { 0, 2, 3,17,18,-3, 2, 5,18, 6,-1, 7 }, // 216 + { 1, 1,17,18, 3, 2, 5,-1, 6, 8, 4, 7 }, // 217 + { 1, 1,18, 1,-2, 3, 2, 1, 7, 6, 3, 4 }, // 218 + { 0, 3, 1, 2,17, 3,18, 2, 7, 5, 4,-1 }, // 219 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 220 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 221 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 222 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 223 + { 1, 1,17,-2, 2,18,18, 8, 5, 3, 2, 6 }, // 224 + { 0, 2,18, 5,18, 2, 3, 7,-2, 1, 6, 8 }, // 225 + { 0, 1, 2,-1,18,-1, 2, 4,-3, 5,18, 3 }, // 226 + { 0, 1, 3,17,18, 5, 2,18, 7, 3, 6, 5 }, // 227 + { 1, 4, 1, 2, 5,18,-2, 2, 3, 7,-1, 4 }, // 228 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 229 + { 0, 1, 1,18, 2, 1, 3, 4, 1, 5, 2, 7 }, // 230 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 231 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 232 + { 0, 1,17,17,18, 2, 4, 5,18,-2, 6, 3 }, // 233 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 234 + { 0, 2,18,18,-1, 3, 5, 6, 8,18, 2, 3 }, // 235 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 236 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 237 + { 0, 1,18,18, 4, 6, 8,18, 7, 3, 2, 5 }, // 238 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 239 + { 0, 2,-1,18,18,18, 2, 4,-2, 2, 3, 6 }, // 240 + { 0, 2,18,-2, 7, 1, 3, 2, 4, 6,-3, 7 }, // 241 + { 1, 1,17,18, 8, 3, 4, 6,-2, 5, 3, 8 }, // 242 + { 0, 2,18, 1, 2, 6, 2, 8, 3,18, 5, 4 }, // 243 + { 1, 1, 3,18,18, 2,18, 2,18, 3, 2,18 }, // 244 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 245 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 246 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 247 + { 1, 1, 3,17,18, 5, 2, 6, 7, 1, 4, 8 }, // 248 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 249 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 250 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 251 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 252 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 253 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 254 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2, 8 }, // 255 +}; + +static const WavpackDecorrSpec very_high_specs [] = { + { 1, 2,18,18, 2, 3,-2,18, 2, 4, 7, 5, 3, 6, 8,-1,18, 2 }, // 0 + { 0, 1,18,18,-1,18, 2, 3, 4, 6, 5, 7,18,-3, 8, 2,-1, 3 }, // 1 + { 1, 2, 1,18,-2, 4,18, 2, 3, 6,-1, 7, 5,-2,18, 8, 2, 4 }, // 2 + { 0, 1,17,17, 2, 3, 4,18,-1, 5, 6, 7,18, 2, 8,17, 3,-2 }, // 3 + { 1, 1,18,18, 2,18, 3, 2,18, 4,-1, 3,18, 2, 6, 8,17, 5 }, // 4 + { 0, 2,18,17, 2, 3,-2, 5,18,-3, 2, 4, 7, 3, 6, 8, 5,17 }, // 5 + { 1, 1,18,-2, 2,-3,18, 5,-2,18, 2, 3, 6, 2,17, 4, 7,-1 }, // 6 + { 1, 1,17, 8,18, 3,-2, 2, 5, 4,18, 6, 3, 8, 7, 2, 5, 4 }, // 7 + { 0, 2,18,17,-2, 2,18, 3, 2, 5,-3, 4, 7,18, 3, 8, 6, 2 }, // 8 + { 1, 1, 3, 6, 5, 5, 1, 3, 7, 4, 2, 6, 4,18, 3, 7, 5, 6 }, // 9 + { 1, 2, 1,18, 3, 2,-2, 1, 5, 4, 6, 2, 7, 1, 8, 3,-1, 1 }, // 10 + { 0, 1,18,18, 2, 3, 6, 3, 5,-2, 2, 4,18, 3,-2,-1, 6, 7 }, // 11 + { 0, 1,-2,18, 2,18, 7, 2, 6,-2, 3, 4,18,18, 2,-3, 8, 5 }, // 12 + { 0, 2,18,18,18, 2, 4, 3,18, 5, 3, 6,-2, 2, 4,18, 8, 7 }, // 13 + { 0, 1,-2, 1,18, 2,-2,18,-1, 5, 7, 2, 3, 4,18, 2, 6, 2 }, // 14 + { 1, 1,17,18, 3, 2, 1, 7,-1, 2, 4, 3, 5, 6,-2,18, 7, 8 }, // 15 + { 1, 1,18,18, 2,18, 3, 4, 6,-2,18, 5, 8, 2, 3, 7, 4,-1 }, // 16 + { 0, 1,18,18,18,-1, 2, 3, 4, 6, 8,18, 3, 5, 2, 6, 7, 4 }, // 17 + { 1, 1,17,-2,18,18, 2, 5, 3, 8, 2,-1, 6, 1, 3, 4, 7, 5 }, // 18 + { 0, 1,17,17,18, 2, 3, 6,-2, 8, 1, 7, 5, 2, 3, 1, 4, 8 }, // 19 + { 1, 1,17,17, 3, 2, 7, 1, 4, 3, 6, 2, 5,-2, 8, 7,18, 6 }, // 20 + { 0, 1,18,17,-2, 2,18, 3,-3, 7, 6, 5, 2, 4,-1, 8, 3,17 }, // 21 + { 1, 1, 2,18,18,-2, 2, 4,-1, 5,18, 3, 8, 6, 2, 7,17, 4 }, // 22 + { 0, 1,17, 3, 6, 8, 5, 4, 3, 8, 1,18, 7, 2, 4, 5, 6, 3 }, // 23 + { 1, 2,17,18, 4, 8, 3, 2, 5, 7, 6, 8, 2, 7,-2,18, 3, 4 }, // 24 + { 1, 1, 6, 5, 5, 3, 4, 7, 3, 2, 4, 6, 3, 7, 1, 5, 2, 4 }, // 25 + { 1, 1, 1,18,-1, 2, 1, 3, 8,-2, 2, 5, 6, 3, 8, 7,18, 4 }, // 26 + { 0, 1, 1,17,-1,18, 3, 2, 5, 4, 6, 7, 8, 3, 4, 2, 1,-2 }, // 27 + { 0, 1,18, 2,18,18, 2,18, 6,-2,18, 7, 5, 4, 3, 2,18,-2 }, // 28 + { 0, 3, 1, 4,18, 3, 2, 4, 1, 5, 2, 3, 6,18, 8, 7, 2, 4 }, // 29 + { 0, 1,17,-2, 1,-3, 2,18, 3,-2, 4,18, 3, 6, 7,-3, 2, 8 }, // 30 + { 1, 1,17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 }, // 31 + { 1, 2,18,-1,17,18, 2, 3,-2,18, 5, 8, 2, 4, 3, 7, 6,-1 }, // 32 + { 1, 1,18,18,18,-2, 4, 2, 3,18, 5, 8, 2, 4, 6, 7,-2, 3 }, // 33 + { 1, 2,18,18,-2,18,-1, 3, 2, 5,18,-2, 7, 2, 3, 4, 6, 8 }, // 34 + { 0, 1,17,18,-1, 2, 4,18, 8, 3, 6, 5, 7,-3, 2, 4, 3,17 }, // 35 + { 1, 1,18,18,17, 2,-1,18, 3, 2,18, 6, 5, 4,18, 7, 2,-1 }, // 36 + { 0, 2, 1,18,-1,18, 3, 2, 4, 6,-3, 7,-1, 5, 1, 2, 3, 8 }, // 37 + { 1, 1, 1,17,-2, 2,-3, 6, 3, 5, 1, 2, 7, 6, 8,-2, 4, 1 }, // 38 + { 0, 1,17,-1, 5, 1, 4, 3, 6, 2,-2,18, 3, 2, 4, 5, 8,-1 }, // 39 + { 0, 2,18,18,17, 2, 3,-2, 5,18, 2, 4, 7, 8, 6,17, 3, 5 }, // 40 + { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 41 + { 1, 2, 1,-1, 3, 2,18, 7,-2, 5, 2, 6, 4, 3,-1,18, 8, 7 }, // 42 + { 0, 2,18,17, 3,18, 2, 5, 4, 3, 6, 2, 7, 8,18, 3, 4, 5 }, // 43 + { 1, 1, 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 }, // 44 + { 0, 2,18,18, 3,-3,18, 2, 6, 5, 3, 7,18, 4,-2, 8, 2, 3 }, // 45 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 46 + { 1, 1,17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 }, // 47 + { 1, 1, 3, 6, 5, 5, 1, 3, 7, 4, 2, 6, 4,18, 3, 7, 5, 6 }, // 48 + { 0, 1,18,18,18, 2, 4,-1,18, 8,-1, 2, 3, 4, 6,-2, 1, 7 }, // 49 + { 1, 1,18,-2,17,18, 2, 6, 3,-2, 5, 4, 7, 1,-3, 8, 2, 6 }, // 50 + { 0, 1,17,18,18, 4, 2, 7, 3, 6,-2,18, 8, 4, 5, 2, 7,17 }, // 51 + { 1, 1,18,18, 5, 4, 6, 4, 1, 5, 4, 3, 2, 5, 6, 1, 4, 5 }, // 52 + { 0, 1,18,18,-2,18, 2,-3, 3, 8, 5,18, 6, 4, 3,-1, 7, 2 }, // 53 + { 1, 1,18, 2,-2,-3,18, 5, 2, 3,-2, 4, 6, 1,-3, 2, 7, 8 }, // 54 + { 0, 1,18, 3, 5, 8, 2, 6, 7, 3, 1, 5, 2,-1, 8, 6, 7, 4 }, // 55 + { 1, 1, 4, 3, 8, 1, 5, 6, 2, 5, 8,-2, 2, 7, 3,18, 5, 4 }, // 56 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 57 + { 1, 1,17, 3,18,18, 7, 2, 4,18, 6, 2, 3,-1, 8, 5,18,-3 }, // 58 + { 0, 1, 3,17,18, 2,18, 6, 7,-3,18, 2, 5, 6, 3, 8, 7,-1 }, // 59 + { 1, 1,18,18, 2,18,18, 2,-1, 7, 3,18, 5, 2, 6, 4,-1,18 }, // 60 + { 0, 3,18, 3, 4, 1, 5, 2,18, 4, 2, 3,18, 7, 6, 1, 2, 4 }, // 61 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 62 + { 1, 1,17, 1,18, 2, 3, 6, 4, 5, 7,18, 3, 8, 2, 4,-2,17 }, // 63 + { 1, 2,18,17, 2, 3, 5,18, 6,-2, 7, 3, 2, 4,18, 8,-1, 5 }, // 64 + { 0, 2, 1,18,-1,18, 3, 2, 4, 6,-3, 7,-1, 5, 1, 2, 3, 8 }, // 65 + { 1, 1, 1,18,-1, 8, 2, 6, 3,-2, 1, 2, 5, 4,-3, 8, 6, 3 }, // 66 + { 0, 1,18,18, 2,18, 2,18, 7, 6,18, 2,-2, 3, 5, 4,18, 8 }, // 67 + { 1, 2,18,17, 2, 3,18,-1, 2, 3, 6,18, 5, 4, 3, 7, 2, 8 }, // 68 + { 1, 2,18,18, 3,-2, 4,18, 5, 7, 6, 2, 4,-3, 8, 5,18, 3 }, // 69 + { 1, 1,17,-2,18,18, 2, 5, 3, 8, 2,-1, 6, 1, 3, 4, 7, 5 }, // 70 + { 1, 1, 3,17,18, 5, 7, 2, 4, 6, 1, 8,-1, 3, 7, 4, 1, 2 }, // 71 + { 0, 2, 1,-2, 2,18, 3, 5, 2, 4, 7,-1, 2, 3, 5,18,-2, 4 }, // 72 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 73 + { 1, 1, 1, 2,-2, 6,18,-3, 2, 7, 3,-2, 5, 6, 1, 8, 2, 4 }, // 74 + { 0, 1,18,18,18, 3,-2, 6,18, 2, 4, 3, 5, 8, 7, 6, 2,-2 }, // 75 + { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 76 + { 0, 1, 3,17,18, 2, 5,18, 6, 7, 5,-2, 2, 4,18, 3, 6, 8 }, // 77 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 78 + { 0, 2,17,-1,18, 2, 4,-1, 8, 3,18, 7,-3, 4, 5, 1, 2,-2 }, // 79 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 8, 6, 4, 5, 7,-1 }, // 80 + { 1, 1,18,18, 3, 6, 4, 8,-2, 2, 5, 3, 7,18, 6, 8, 4, 2 }, // 81 + { 1, 1,17,18,18,-2, 5, 2, 3, 1, 4,-1, 8, 6, 5, 3, 2,18 }, // 82 + { 1, 1,17,17, 1, 2, 4, 5, 2, 6,-1, 3, 1, 1,-2, 4, 2, 7 }, // 83 + { 1, 1,17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 }, // 84 + { 0, 1,18,17,-2,-3, 1, 2, 3, 2, 5, 4, 7,-3, 6,-2, 2, 1 }, // 85 + { 1, 1, 1, 3, 5,18, 1, 2, 7, 3, 6, 2, 5, 8,-1, 1, 4, 7 }, // 86 + { 1, 1,17, 3, 6, 8, 1, 4, 5, 3,-2, 7, 2, 8, 5, 6,18, 3 }, // 87 + { 1, 1,17,18, 2, 4, 8,-2, 3, 1, 5, 6, 7, 1, 2, 3, 4, 7 }, // 88 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 89 + { 1, 1, 3, 1, 8,18, 5, 2, 3,18, 6, 7,-2, 4, 3, 2, 8,18 }, // 90 + { 0, 1,18,17, 2,18, 3, 4,-1,18, 7, 6, 2, 8, 4,18,18, 5 }, // 91 + { 0, 1,18,18, 2,18,18, 2, 7,-2, 6, 5, 4, 3,18, 3, 2,17 }, // 92 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 93 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 94 + { 1, 1,17, 8,18, 3, 2, 1, 5, 4, 6,-1, 3,-3, 8,18, 7, 2 }, // 95 + { 1, 2,18,17,18, 2, 3, 5,-2,18, 6,-1, 2, 3, 7, 4, 8,17 }, // 96 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 8, 6, 4, 5, 7,-1 }, // 97 + { 1, 2,18,18,-2,17, 2,18, 3, 4,18, 8, 7,-1, 2, 4, 5,17 }, // 98 + { 0, 2,17,-3,17, 3, 2,-2,18, 8, 4,-3, 2,18, 5, 3,-2, 6 }, // 99 + { 0, 1,18,18, 2,18,18, 2, 7,-2, 6, 5, 4, 3,18, 3, 2,17 }, // 100 + { 0, 2, 1,18,-1, 3, 5, 2,-3,18, 7, 3,-1, 6, 4, 2,17, 5 }, // 101 + { 1, 1,17,-2,17, 2,-3, 1, 5,-1, 4, 6, 3, 2, 8, 7,-2, 5 }, // 102 + { 1, 1, 1,18, 1, 3, 5, 8, 6, 2, 3,-1, 7, 1, 4, 8, 5,-3 }, // 103 + { 0, 2, 3,18,18, 2,18,-2, 6, 5, 7, 2, 4,18, 3, 6,-3, 5 }, // 104 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 105 + { 1, 1, 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 }, // 106 + { 0, 4,18, 2,17, 3,18,-2, 2, 6,18, 2, 7, 3, 5, 4, 8,18 }, // 107 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 108 + { 0, 1,18,18, 2, 3, 6, 3, 5,-2, 2, 4,18, 3,-2,-1, 6, 7 }, // 109 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 110 + { 1, 1,17, 1, 2, 5, 3,-2, 1, 4, 3, 7, 6,-3, 2, 1, 1, 2 }, // 111 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 112 + { 1, 1,18,18,-2,18,-2, 2, 3, 6,18, 4,-1, 2, 3, 8, 1, 4 }, // 113 + { 1, 1,17,-2,17, 2,-3, 1, 5,-1, 4, 6, 3, 2, 8, 7,-2, 5 }, // 114 + { 0, 1,17,17,18, 3, 2,18,18, 6, 8, 2,-2, 3, 5, 4,17,18 }, // 115 + { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 116 + { 1, 1, 1, 3,-3,18,18, 6, 5,18, 2,-1, 3, 8, 7,-3, 4,17 }, // 117 + { 1, 1,18, 1, 2, 1, 3, 8, 7, 4, 1, 5, 2,-1,-3,18, 6, 2 }, // 118 + { 0, 1,18, 3, 5, 2, 6, 8,18, 5, 7, 2, 3,-1, 6, 7, 8, 5 }, // 119 + { 0, 2,18, 3,-2, 7, 8, 2, 5, 4,-3, 8, 3, 2,18, 5, 4, 6 }, // 120 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 121 + { 1, 3, 1, 1, 2, 5, 2, 7, 4, 3,-1,18,-2, 8, 2, 1, 6, 7 }, // 122 + { 0, 1, 3,17,18, 5, 2, 6, 7,18, 4, 5, 3, 6,18, 2, 7, 8 }, // 123 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 124 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 125 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 126 + { 0, 1, 1,18, 1, 2, 3, 5, 1, 2, 6, 7, 4, 3, 8, 1,17, 5 }, // 127 + { 1, 2,17,-1,18,-2, 2, 3, 5,18, 2, 4, 6, 7, 3,-1, 5, 8 }, // 128 + { 1, 1,18,18,-3,18,-2, 2, 3,-2,18, 6, 4, 5, 8, 3,17,-3 }, // 129 + { 1, 1,18, 7, 6, 5, 5, 3, 1, 4, 2, 7, 3, 4,-3, 6,18, 8 }, // 130 + { 0, 2,18,18, 2, 3, 5,18, 2, 4, 3, 6,18, 7, 8,-1, 5, 2 }, // 131 + { 0, 1,18,17,-1, 2,18, 3, 2,18, 4, 3,18, 2, 6, 5, 8,17 }, // 132 + { 0, 2,18,17, 2, 3,18, 5,-1, 6, 7, 8, 2, 3, 4, 5,18, 6 }, // 133 + { 1, 2,18,-3,18, 2, 3,-2,-3, 5,18, 7, 6, 2, 4, 3, 8,-2 }, // 134 + { 1, 1,17,18,18,-2, 2, 3, 5, 4, 8,18,-1, 5, 3, 6,-2, 7 }, // 135 + { 1, 2,18,17, 2,-2,18, 3,-1, 4,18, 2, 7, 5, 3, 8, 6, 4 }, // 136 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 137 + { 1, 1, 1, 5, 1, 3, 4, 3, 7, 5, 1, 3, 6, 1, 2, 4, 3, 8 }, // 138 + { 0, 2,18,18, 3, 3,-2, 2, 5,18, 6, 3,-1, 4, 7,-1, 1, 2 }, // 139 + { 0, 1,-2, 1,18, 2,-2, 5, 7,18, 3, 2, 6, 2,-1, 4,-2,17 }, // 140 + { 0, 2,18,18,18, 2, 3,-2,18, 5, 4, 2, 6, 8, 3,-2, 4,18 }, // 141 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 142 + { 1, 1,17,18,-1, 3, 2, 5, 1, 3, 2, 8, 4, 7, 6, 2,-1, 5 }, // 143 + { 1, 1,17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 }, // 144 + { 0, 1,18,18,-2,18, 2, 3, 4, 5, 6,18, 8, 2, 3, 7,-2, 4 }, // 145 + { 0, 1,18,-2,18,18,-3,-2, 2, 3, 5, 8, 1, 2, 6, 4, 7,-1 }, // 146 + { 0, 1,18,17, 2,18, 3,-2, 2, 7, 6, 4,18, 3, 8, 7, 4, 2 }, // 147 + { 1, 1,17,18,18, 4, 2, 3, 7, 6,18, 8, 5,-1, 4, 2, 3,17 }, // 148 + { 1, 1,18,17,18, 2, 5, 3,-2,18, 6, 2, 3, 4, 8, 7, 5,-1 }, // 149 + { 0, 1, 2,-1,18,-1, 2, 4,-3,18, 5, 3, 6,18, 2, 4, 7, 8 }, // 150 + { 1, 1,17,18, 8, 3, 6, 4,-1, 5, 2, 7, 3, 8, 6, 5,18, 4 }, // 151 + { 0, 2,18, 3,-2, 7, 8, 2, 5, 4,-3, 8, 3, 2,18, 5, 4, 6 }, // 152 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 153 + { 1, 1, 1,18,-1, 8, 2, 6, 3,-2, 1, 2, 5, 4,-3, 8, 6, 3 }, // 154 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 155 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 156 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 157 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 158 + { 0, 1,17,18,18, 4, 2, 7, 3, 6,-2,18, 8, 4, 5, 2, 7,17 }, // 159 + { 1, 2,18,-1,18, 3,-2,18, 2, 5, 3, 6, 7, 2,-1,18, 8, 4 }, // 160 + { 1, 2, 1,18,-2, 4,18, 2, 3, 6,-1, 7, 5,-2,18, 8, 2, 4 }, // 161 + { 1, 2, 1,18,-3, 2, 3,18,-1, 5, 6, 2, 8, 3, 4, 1,-2, 7 }, // 162 + { 0, 1, 1,17,-1,18, 3, 2, 5, 4, 6, 7, 8, 3, 4, 2, 1,-2 }, // 163 + { 1, 1,18,17,18, 4, 3, 5, 1, 2, 6, 3, 4, 7, 1, 8, 5, 2 }, // 164 + { 0, 1,18,-2, 7, 1, 3, 2,-3, 4, 6,-2, 7, 8, 1, 5, 4, 3 }, // 165 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 166 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 167 + { 0, 2,18,18,18,-2, 2, 5, 3, 7,18, 2, 4,-3, 5, 6, 3, 8 }, // 168 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 169 + { 0, 3, 3,18,-1, 5, 2, 7,18, 6, 5, 2, 4, 3,-1, 7,18, 6 }, // 170 + { 0, 2,18,18,18, 4, 3, 2, 6, 4, 8,18, 5, 3, 2, 7,-2, 6 }, // 171 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 172 + { 0, 2,18,18,18, 2, 3,-2,18, 5, 4, 2, 6, 8, 3,-2, 4,18 }, // 173 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 174 + { 1, 1,17, 8,18, 3, 2, 1, 5, 4, 6,-1, 3,-3, 8,18, 7, 2 }, // 175 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 176 + { 0, 1,-1,18,18,18, 2, 4, 6,-2, 2, 8, 3, 4,18, 7,-1, 6 }, // 177 + { 0, 1,18, 1,-2, 2, 4, 1, 3,-1, 2, 5, 7, 1, 6, 8,-2,17 }, // 178 + { 0, 1,17,17,18, 2, 5, 4,18, 3, 8, 7, 4, 6, 8, 1, 5, 2 }, // 179 + { 1, 2,18,18, 5, 4, 6, 3, 4,18, 8, 4,-1, 7, 5, 3, 6, 2 }, // 180 + { 0, 1,18,18,-3,18, 3, 6, 2, 5, 7,18, 3, 8,-1, 4, 5, 2 }, // 181 + { 1, 1,18, 2,-2,-3,18, 5, 2,-2, 4, 3, 6,18, 8,-1, 2, 7 }, // 182 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 183 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 184 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 185 + { 1, 1,17, 1, 7, 2, 3,18,-2, 3, 6, 4, 2, 7, 8, 5, 3,17 }, // 186 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 187 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 188 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 189 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 190 + { 0, 1,17,18, 3,18, 2, 5, 4, 7,-3, 6, 3, 2,18, 4, 7, 3 }, // 191 + { 1, 1, 1, 7, 4, 5, 3, 4, 5, 1, 3, 6, 3, 2, 4, 8,-2, 7 }, // 192 + { 0, 1, 1,18,-1,-2,18, 3, 2,-1, 6, 7, 4, 5, 3,18, 2,-3 }, // 193 + { 1, 1,18,18,-1, 3, 6,18, 5, 4, 8, 2, 3, 6,18, 7, 4,-2 }, // 194 + { 0, 2,18,18, 2, 6,18, 2,18, 5, 3,18, 2, 4, 7, 8, 3,18 }, // 195 + { 1, 1, 3,18,18, 5,18, 6, 2, 4, 7,-2,18, 5, 8, 6, 3, 2 }, // 196 + { 0, 1,18,-2, 7, 1, 3, 2,-3, 4, 6,-2, 7, 8, 1, 5, 4, 3 }, // 197 + { 1, 1,18,-2,18, 2, 5,18, 3,-2, 4, 7, 2,-1, 8, 6, 5, 1 }, // 198 + { 1, 1,17,17, 5,18, 4, 1, 2, 8, 6, 4,-2, 3, 5,-1, 1, 8 }, // 199 + { 0, 2, 1, 2,17, 3, 7,18, 2,-1, 4, 5,18, 2, 7, 3, 6, 8 }, // 200 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 201 + { 1, 1, 3, 6,17, 8, 7, 5,18,-1, 1, 2, 3, 4, 2, 6, 8, 1 }, // 202 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 203 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 204 + { 0, 2,18,18,18, 2,-2, 3, 6, 4, 8,18, 2, 5, 7, 4, 3, 6 }, // 205 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 206 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 207 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 208 + { 1, 1,18, 1, 8, 3, 5, 6, 4,-1, 8, 3, 7,18, 2, 5, 8, 4 }, // 209 + { 1, 1,17,18, 5, 2, 4, 3, 1, 6,-2, 1, 3, 2, 4, 5,-1,17 }, // 210 + { 1, 1,18,17, 2,18, 3,-3, 7, 2, 6, 4, 3, 5,18, 8, 2,-2 }, // 211 + { 1, 1,18,17,18, 4, 3, 5,-1,18, 2, 7, 8, 4, 6, 3,18, 5 }, // 212 + { 0, 1,18,17,18,-2, 2,-3, 3, 4, 8, 5, 2,18, 6, 3, 7,-2 }, // 213 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 214 + { 1, 1,17,18, 8, 3, 4, 6,18, 5,-2, 3, 8, 5, 2, 4, 7, 6 }, // 215 + { 0, 1,18,-2, 3, 5, 1, 7, 3, 2, 6,-3, 4, 1, 5, 8, 3,-2 }, // 216 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 217 + { 1, 1, 3,17,18, 5,-1,18, 2, 6, 7,18, 5, 3,-3,-1, 6, 2 }, // 218 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 219 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 220 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 221 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 222 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 223 + { 1, 3,18,17,-2, 3,-1,18, 2, 5, 3, 7, 6, 2, 4, 8,18, 5 }, // 224 + { 0, 1,18,-1,18, 2,18, 3, 5,18, 2, 8,18, 5, 4,-1, 6, 2 }, // 225 + { 1, 2,18,-2,18,18, 2, 3, 4,-3, 2, 5,18, 7, 4, 3, 8, 6 }, // 226 + { 0, 2,17,-1,18, 2,-1, 1, 7, 3, 8, 5,-2, 4, 1, 2,-3, 6 }, // 227 + { 0, 1,18,17, 2,18, 2,18, 6, 7, 4, 3,18, 5, 2,-2,17, 8 }, // 228 + { 0, 3,18,17, 2, 3,-3,-1,18, 2, 4, 5,18, 7, 3, 2,-3, 6 }, // 229 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 230 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 231 + { 0, 2, 3,18,18,18, 2, 6, 5,18, 7, 2, 4, 6,18, 5, 3, 8 }, // 232 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 233 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 234 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 235 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 236 + { 0, 1,18,18, 3, 6, 3,-2, 2,18, 5,-1, 7, 3, 4,-2, 2, 6 }, // 237 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 238 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 239 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 240 + { 1, 1,18,17,18,18,-2, 2, 3,-3,18, 6, 4, 2,-2, 8, 3, 7 }, // 241 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 242 + { 0, 1,18,18,18, 4, 2, 7, 8,18, 3, 2,-2, 4, 7, 6,17, 5 }, // 243 + { 1, 1,18,18,-1,-2, 8, 3,18, 6, 3, 5, 8, 2, 4, 7, 1, 6 }, // 244 + { 1, 1, 1,-3, 3,18,18, 2,-1, 3, 6, 5,18, 4, 7,-2, 8, 3 }, // 245 + { 1, 1, 1,18, 4, 2, 5,18, 1, 3,-1, 6, 1, 4, 8, 2, 5, 1 }, // 246 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 247 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 248 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 249 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 250 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 251 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 252 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 253 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 254 + { 0, 1,-1,18,18, 2,18, 3, 5,18, 2,18, 6, 8, 4, 5, 7,-1 }, // 255 +}; + +#define NUM_FAST_SPECS (sizeof (fast_specs) / sizeof (fast_specs [0])) +#define NUM_DEFAULT_SPECS (sizeof (default_specs) / sizeof (default_specs [0])) +#define NUM_HIGH_SPECS (sizeof (high_specs) / sizeof (high_specs [0])) +#define NUM_VERY_HIGH_SPECS (sizeof (very_high_specs) / sizeof (very_high_specs [0])) + +///////////////////////////// executable code //////////////////////////////// + +// This function initializes everything required to pack WavPack bitstreams +// and must be called BEFORE any other function in this module. + +void pack_init (WavpackContext *wpc) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + wps->sample_index = 0; + wps->delta_decay = 2.0; + CLEAR (wps->decorr_passes); + CLEAR (wps->dc); + + /* although we set the term and delta values here for clarity, they're + * actually hardcoded in the analysis function for speed + */ + + CLEAR (wps->analysis_pass); + wps->analysis_pass.term = 18; + wps->analysis_pass.delta = 2; + + if (wpc->config.flags & CONFIG_AUTO_SHAPING) { + if (wpc->config.flags & CONFIG_OPTIMIZE_WVC) + wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = -512L << 16; + else if (wpc->config.sample_rate >= 64000) + wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = 1024L << 16; + else + wpc->config.flags |= CONFIG_DYNAMIC_SHAPING; + } + else { + int32_t weight = (int32_t) floor (wpc->config.shaping_weight * 1024.0 + 0.5); + + if (weight <= -1000) + weight = -1000; + + wps->dc.shaping_acc [0] = wps->dc.shaping_acc [1] = weight << 16; + } + + if (wpc->config.flags & CONFIG_DYNAMIC_SHAPING) + wps->dc.shaping_data = malloc (wpc->max_samples * sizeof (*wps->dc.shaping_data)); + + if (!wpc->config.xmode) + wps->num_passes = 0; + else if (wpc->config.xmode == 1) + wps->num_passes = 2; + else if (wpc->config.xmode == 2) + wps->num_passes = 4; + else + wps->num_passes = 9; + + if (wpc->config.flags & CONFIG_VERY_HIGH_FLAG) { + wps->num_decorrs = NUM_VERY_HIGH_SPECS; + wps->decorr_specs = very_high_specs; + } + else if (wpc->config.flags & CONFIG_HIGH_FLAG) { + wps->num_decorrs = NUM_HIGH_SPECS; + wps->decorr_specs = high_specs; + } + else if (wpc->config.flags & CONFIG_FAST_FLAG) { + wps->num_decorrs = NUM_FAST_SPECS; + wps->decorr_specs = fast_specs; + } + else { + wps->num_decorrs = NUM_DEFAULT_SPECS; + wps->decorr_specs = default_specs; + } + + init_words (wps); +} + +// Allocate room for and copy the decorrelation terms from the decorr_passes +// array into the specified metadata structure. Both the actual term id and +// the delta are packed into single characters. + +void write_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int tcount = wps->num_terms; + struct decorr_pass *dpp; + char *byteptr; + + byteptr = wpmd->data = malloc (tcount + 1); + wpmd->id = ID_DECORR_TERMS; + + for (dpp = wps->decorr_passes; tcount--; ++dpp) + *byteptr++ = ((dpp->term + 5) & 0x1f) | ((dpp->delta << 5) & 0xe0); + + wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data); +} + +// Allocate room for and copy the decorrelation term weights from the +// decorr_passes array into the specified metadata structure. The weights +// range +/-1024, but are rounded and truncated to fit in signed chars for +// metadata storage. Weights are separate for the two channels + +void write_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) +{ + struct decorr_pass *dpp = wps->decorr_passes; + int tcount = wps->num_terms, i; + char *byteptr; + + byteptr = wpmd->data = malloc ((tcount * 2) + 1); + wpmd->id = ID_DECORR_WEIGHTS; + + for (i = wps->num_terms - 1; i >= 0; --i) + if (store_weight (dpp [i].weight_A) || + (!(wps->wphdr.flags & MONO_DATA) && store_weight (dpp [i].weight_B))) + break; + + tcount = i + 1; + + for (i = 0; i < wps->num_terms; ++i) { + if (i < tcount) { + dpp [i].weight_A = restore_weight (*byteptr++ = store_weight (dpp [i].weight_A)); + + if (!(wps->wphdr.flags & MONO_DATA)) + dpp [i].weight_B = restore_weight (*byteptr++ = store_weight (dpp [i].weight_B)); + } + else + dpp [i].weight_A = dpp [i].weight_B = 0; + } + + wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data); +} + +// Allocate room for and copy the decorrelation samples from the decorr_passes +// array into the specified metadata structure. 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 first term +// with unspecified samples set to zero. The number of samples stored varies +// with the actual term value, so those must obviously be specified before +// these in the metadata list. Any number of terms can have their samples +// specified from no terms to all the terms, however I have found that +// sending more than the first term's samples is a waste. The "wcount" +// variable can be set to the number of terms to have their samples stored. + +void write_decorr_samples (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int tcount = wps->num_terms, wcount = 1, temp; + struct decorr_pass *dpp; + uchar *byteptr; + + byteptr = wpmd->data = malloc (256); + wpmd->id = ID_DECORR_SAMPLES; + + for (dpp = wps->decorr_passes; tcount--; ++dpp) + if (wcount) { + if (dpp->term > MAX_TERM) { + dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + dpp->samples_A [1] = exp2s (temp = log2s (dpp->samples_A [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + dpp->samples_B [1] = exp2s (temp = log2s (dpp->samples_B [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + } + else if (dpp->term < 0) { + dpp->samples_A [0] = exp2s (temp = log2s (dpp->samples_A [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + dpp->samples_B [0] = exp2s (temp = log2s (dpp->samples_B [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + else { + int m = 0, cnt = dpp->term; + + while (cnt--) { + dpp->samples_A [m] = exp2s (temp = log2s (dpp->samples_A [m])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + dpp->samples_B [m] = exp2s (temp = log2s (dpp->samples_B [m])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + + m++; + } + } + + wcount--; + } + else { + CLEAR (dpp->samples_A); + CLEAR (dpp->samples_B); + } + + wpmd->byte_length = (int32_t)(byteptr - (uchar *) wpmd->data); +} + +// Allocate room for and copy the noise shaping info into the specified +// metadata structure. These would normally be written to the +// "correction" file and are used for lossless reconstruction of +// hybrid data. The "delta" parameter is not yet used in encoding as it +// will be part of the "quality" mode. + +void write_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + char *byteptr; + int temp; + + byteptr = wpmd->data = malloc (12); + wpmd->id = ID_SHAPING_WEIGHTS; + + wps->dc.error [0] = exp2s (temp = log2s (wps->dc.error [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + wps->dc.shaping_acc [0] = exp2s (temp = log2s (wps->dc.shaping_acc [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->dc.error [1] = exp2s (temp = log2s (wps->dc.error [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + wps->dc.shaping_acc [1] = exp2s (temp = log2s (wps->dc.shaping_acc [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + + if (wps->dc.shaping_delta [0] | wps->dc.shaping_delta [1]) { + wps->dc.shaping_delta [0] = exp2s (temp = log2s (wps->dc.shaping_delta [0])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->dc.shaping_delta [1] = exp2s (temp = log2s (wps->dc.shaping_delta [1])); + *byteptr++ = temp; + *byteptr++ = temp >> 8; + } + } + + wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data); +} + +// Allocate room for and copy the int32 data values into the specified +// metadata structure. This data is used for integer data that has more +// than 24 bits of magnitude or, in some cases, it's used to eliminate +// redundant bits from any audio stream. + +void write_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_INT32_INFO; + *byteptr++ = wps->int32_sent_bits; + *byteptr++ = wps->int32_zeros; + *byteptr++ = wps->int32_ones; + *byteptr++ = wps->int32_dups; + wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data); +} + +// Allocate room for and copy the multichannel information into the specified +// metadata structure. The first byte is the total number of channels and the +// following bytes represent the channel_mask as described for Microsoft +// WAVEFORMATEX. + +void write_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + uint32_t mask = wpc->config.channel_mask; + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_CHANNEL_INFO; + *byteptr++ = wpc->config.num_channels; + + while (mask) { + *byteptr++ = mask; + mask >>= 8; + } + + wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data); +} + +// Allocate room for and copy the configuration information into the specified +// metadata structure. Currently, we just store the upper 3 bytes of +// config.flags and only in the first block of audio data. Note that this is +// for informational purposes not required for playback or decoding (like +// whether high or fast mode was specified). + +void write_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_CONFIG_BLOCK; + *byteptr++ = (char) (wpc->config.flags >> 8); + *byteptr++ = (char) (wpc->config.flags >> 16); + *byteptr++ = (char) (wpc->config.flags >> 24); + + if (wpc->config.flags & CONFIG_EXTRA_MODE) + *byteptr++ = (char) wpc->config.xmode; + + wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data); +} + +// Allocate room for and copy the non-standard sampling rateinto the specified +// metadata structure. We just store the lower 3 bytes of the sampling rate. +// Note that this would only be used when the sampling rate was not included +// in the table of 15 "standard" values. + +void write_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd) + +{ + char *byteptr; + + byteptr = wpmd->data = malloc (4); + wpmd->id = ID_SAMPLE_RATE; + *byteptr++ = (char) (wpc->config.sample_rate); + *byteptr++ = (char) (wpc->config.sample_rate >> 8); + *byteptr++ = (char) (wpc->config.sample_rate >> 16); + wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data); +} + +// 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. + +static void best_floating_line (short *values, int num_values, double *initial_y, double *final_y, short *max_error); +static void dynamic_noise_shaping (WavpackContext *wpc, int32_t *buffer, int shortening_allowed); +static int scan_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values); +static void scan_int32_quick (WavpackStream *wps, int32_t *values, int32_t num_values); +static void send_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values); +static int scan_redundancy (int32_t *values, int32_t num_values); +static int pack_samples (WavpackContext *wpc, int32_t *buffer); + +int pack_block (WavpackContext *wpc, int32_t *buffer) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags, sflags = wps->wphdr.flags; + int32_t sample_count = wps->wphdr.block_samples, *orig_data = NULL; + int dynamic_shaping_done = FALSE; + + if (!wpc->current_stream && !(flags & FLOAT_DATA) && (flags & MAG_MASK) >> MAG_LSB < 24) { + if ((wpc->config.flags & CONFIG_DYNAMIC_SHAPING) && !wpc->config.block_samples) { + dynamic_noise_shaping (wpc, buffer, TRUE); + sample_count = wps->wphdr.block_samples; + dynamic_shaping_done = TRUE; + } + else if (wpc->block_boundary && sample_count >= (int32_t) wpc->block_boundary * 2) { + int bc = sample_count / wpc->block_boundary, chans = (flags & MONO_DATA) ? 1 : 2; + int res = scan_redundancy (buffer, wpc->block_boundary * chans), i; + + for (i = 1; i < bc; ++i) + if (res != scan_redundancy (buffer + (i * wpc->block_boundary * chans), + wpc->block_boundary * chans)) { + sample_count = wps->wphdr.block_samples = wpc->block_boundary * i; + break; + } + } + } + + if (!(flags & MONO_FLAG) && wpc->stream_version >= 0x410) { + int32_t lor = 0, diff = 0; + int32_t *sptr, *dptr, i; + + for (sptr = buffer, i = 0; i < (int32_t) sample_count; sptr += 2, i++) { + lor |= sptr [0] | sptr [1]; + diff |= sptr [0] - sptr [1]; + + if (lor && diff) + break; + } + + if (i == sample_count && lor && !diff) { + flags &= ~(JOINT_STEREO | CROSS_DECORR | HYBRID_BALANCE); + wps->wphdr.flags = flags |= FALSE_STEREO; + dptr = buffer; + sptr = buffer; + + for (i = sample_count; i--; sptr++) + *dptr++ = *sptr++; + + if (!wps->false_stereo) { + wps->false_stereo = 1; + wps->num_terms = 0; + init_words (wps); + } + } + else if (wps->false_stereo) { + wps->false_stereo = 0; + wps->num_terms = 0; + init_words (wps); + } + } + + if (flags & SHIFT_MASK) { + int shift = (flags & SHIFT_MASK) >> SHIFT_LSB; + int mag = (flags & MAG_MASK) >> MAG_LSB; + uint32_t cnt = sample_count; + int32_t *ptr = buffer; + + if (flags & MONO_DATA) + while (cnt--) + *ptr++ >>= shift; + else + while (cnt--) { + *ptr++ >>= shift; + *ptr++ >>= shift; + } + + if ((mag -= shift) < 0) + flags &= ~MAG_MASK; + else + flags -= (1 << MAG_LSB) * shift; + + wps->wphdr.flags = flags; + } + + if ((flags & FLOAT_DATA) || (flags & MAG_MASK) >> MAG_LSB >= 24) { + if ((!(flags & HYBRID_FLAG) || wpc->wvc_flag) && !(wpc->config.flags & CONFIG_SKIP_WVX)) { + orig_data = malloc (sizeof (f32) * ((flags & MONO_DATA) ? sample_count : sample_count * 2)); + memcpy (orig_data, buffer, sizeof (f32) * ((flags & MONO_DATA) ? sample_count : sample_count * 2)); + + if (flags & FLOAT_DATA) { + wps->float_norm_exp = wpc->config.float_norm_exp; + + if (!scan_float_data (wps, (f32 *) buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2)) { + free (orig_data); + orig_data = NULL; + } + } + else { + if (!scan_int32_data (wps, buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2)) { + free (orig_data); + orig_data = NULL; + } + } + } + else { + if (flags & FLOAT_DATA) { + wps->float_norm_exp = wpc->config.float_norm_exp; + + if (scan_float_data (wps, (f32 *) buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2)) + wpc->lossy_blocks = TRUE; + } + else if (scan_int32_data (wps, buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2)) + wpc->lossy_blocks = TRUE; + } + + wps->num_terms = 0; + } + else { + scan_int32_quick (wps, buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2); + + if (wps->shift != wps->int32_zeros + wps->int32_ones + wps->int32_dups) { + wps->shift = wps->int32_zeros + wps->int32_ones + wps->int32_dups; + wps->num_terms = 0; + } + } + + if ((wpc->config.flags & CONFIG_DYNAMIC_SHAPING) && !dynamic_shaping_done) + dynamic_noise_shaping (wpc, buffer, FALSE); + + if (!wps->num_passes && !wps->num_terms) { + wps->num_passes = 1; + + if (flags & MONO_DATA) + execute_mono (wpc, buffer, 1, 0); + else + execute_stereo (wpc, buffer, 1, 0); + + wps->num_passes = 0; + } + + if (!pack_samples (wpc, buffer)) { + wps->wphdr.flags = sflags; + + if (orig_data) + free (orig_data); + + return FALSE; + } + else + wps->wphdr.flags = sflags; + + if (wps->dc.shaping_data) { + if (wps->dc.shaping_samples != sample_count) + memcpy (wps->dc.shaping_data, wps->dc.shaping_data + sample_count, + (wps->dc.shaping_samples - sample_count) * sizeof (*wps->dc.shaping_data)); + + wps->dc.shaping_samples -= sample_count; + } + + if (orig_data) { + uint32_t data_count; + uchar *cptr; + + if (wpc->wvc_flag) + cptr = wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 8; + else + cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8; + + bs_open_write (&wps->wvxbits, cptr + 8, wpc->wvc_flag ? wps->block2end : wps->blockend); + + if (flags & FLOAT_DATA) + send_float_data (wps, (f32*) orig_data, (flags & MONO_DATA) ? sample_count : sample_count * 2); + else + send_int32_data (wps, orig_data, (flags & MONO_DATA) ? sample_count : sample_count * 2); + + data_count = bs_close_write (&wps->wvxbits); + free (orig_data); + + if (data_count) { + if (data_count != (uint32_t) -1) { + *cptr++ = ID_WVX_BITSTREAM | ID_LARGE; + *cptr++ = (data_count += 4) >> 1; + *cptr++ = data_count >> 9; + *cptr++ = data_count >> 17; + *cptr++ = wps->crc_x; + *cptr++ = wps->crc_x >> 8; + *cptr++ = wps->crc_x >> 16; + *cptr = wps->crc_x >> 24; + + if (wpc->wvc_flag) + ((WavpackHeader *) wps->block2buff)->ckSize += data_count + 4; + else + ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4; + } + else + return FALSE; + } + } + + return TRUE; +} + +static 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; +} + +// Quickly scan a buffer of long integer data and determine whether any +// redundancy in the LSBs can be used to reduce the data's magnitude. If yes, +// then the INT32_DATA flag is set and the int32 parameters are set. This +// version is designed to terminate as soon as it figures out that no +// redundancy is available so that it can be used for all files. + +static void scan_int32_quick (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + uint32_t magdata = 0, ordata = 0, xordata = 0, anddata = ~0; + int total_shift = 0; + int32_t *dp, count; + + wps->int32_sent_bits = wps->int32_zeros = wps->int32_ones = wps->int32_dups = 0; + + for (dp = values, count = num_values; count--; dp++) { + magdata |= (*dp < 0) ? ~*dp : *dp; + xordata |= *dp ^ -(*dp & 1); + anddata &= *dp; + ordata |= *dp; + + if ((ordata & 1) && !(anddata & 1) && (xordata & 2)) + return; + } + + wps->wphdr.flags &= ~MAG_MASK; + + while (magdata) { + wps->wphdr.flags += 1 << MAG_LSB; + magdata >>= 1; + } + + if (!(wps->wphdr.flags & MAG_MASK)) + return; + + if (!(ordata & 1)) + while (!(ordata & 1)) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_zeros++; + total_shift++; + ordata >>= 1; + } + else if (anddata & 1) + while (anddata & 1) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_ones++; + total_shift++; + anddata >>= 1; + } + else if (!(xordata & 2)) + while (!(xordata & 2)) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_dups++; + total_shift++; + xordata >>= 1; + } + + if (total_shift) { + wps->wphdr.flags |= INT32_DATA; + + for (dp = values, count = num_values; count--; dp++) + *dp >>= total_shift; + } +} + +static int scan_redundancy (int32_t *values, int32_t num_values) +{ + uint32_t ordata = 0, xordata = 0, anddata = ~0; + int redundant_bits = 0; + int32_t *dp, count; + + for (dp = values, count = num_values; count--; dp++) { + xordata |= *dp ^ -(*dp & 1); + anddata &= *dp; + ordata |= *dp; + + if ((ordata & 1) && !(anddata & 1) && (xordata & 2)) + return 0; + } + + if (!ordata || anddata == ~0 || !xordata) + return 0; + + if (!(ordata & 1)) + while (!(ordata & 1)) { + redundant_bits++; + ordata >>= 1; + } + else if (anddata & 1) + while (anddata & 1) { + redundant_bits = (redundant_bits + 1) | 0x40; + anddata >>= 1; + } + else if (!(xordata & 2)) + while (!(xordata & 2)) { + redundant_bits = (redundant_bits + 1) | 0x80; + redundant_bits++; + xordata >>= 1; + } + + return redundant_bits; +} + +// Scan a buffer of long integer data and determine whether any redundancy in +// the LSBs can be used to reduce the data's magnitude. If yes, then the +// INT32_DATA flag is set and the int32 parameters are set. If bits must still +// be transmitted literally to get down to 24 bits (which is all the integer +// compression code can handle) then we return TRUE to indicate that a wvx +// stream must be created in either lossless mode. + +static int scan_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + uint32_t magdata = 0, ordata = 0, xordata = 0, anddata = ~0; + uint32_t crc = 0xffffffff; + int total_shift = 0; + int32_t *dp, count; + + wps->int32_sent_bits = wps->int32_zeros = wps->int32_ones = wps->int32_dups = 0; + + for (dp = values, count = num_values; count--; dp++) { + crc = crc * 9 + (*dp & 0xffff) * 3 + ((*dp >> 16) & 0xffff); + magdata |= (*dp < 0) ? ~*dp : *dp; + xordata |= *dp ^ -(*dp & 1); + anddata &= *dp; + ordata |= *dp; + } + + wps->crc_x = crc; + wps->wphdr.flags &= ~MAG_MASK; + + while (magdata) { + wps->wphdr.flags += 1 << MAG_LSB; + magdata >>= 1; + } + + if (!((wps->wphdr.flags & MAG_MASK) >> MAG_LSB)) { + wps->wphdr.flags &= ~INT32_DATA; + return FALSE; + } + + if (!(ordata & 1)) + while (!(ordata & 1)) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_zeros++; + total_shift++; + ordata >>= 1; + } + else if (anddata & 1) + while (anddata & 1) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_ones++; + total_shift++; + anddata >>= 1; + } + else if (!(xordata & 2)) + while (!(xordata & 2)) { + wps->wphdr.flags -= 1 << MAG_LSB; + wps->int32_dups++; + total_shift++; + xordata >>= 1; + } + + if (((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) > 23) { + wps->int32_sent_bits = (uchar)(((wps->wphdr.flags & MAG_MASK) >> MAG_LSB) - 23); + total_shift += wps->int32_sent_bits; + wps->wphdr.flags &= ~MAG_MASK; + wps->wphdr.flags += 23 << MAG_LSB; + } + + if (total_shift) { + wps->wphdr.flags |= INT32_DATA; + + for (dp = values, count = num_values; count--; dp++) + *dp >>= total_shift; + } + + return wps->int32_sent_bits; +} + +// For the specified buffer values and the int32 parameters stored in "wps", +// send the literal bits required to the "wvxbits" bitstream. + +static void send_int32_data (WavpackStream *wps, int32_t *values, int32_t num_values) +{ + int sent_bits = wps->int32_sent_bits, pre_shift; + int32_t mask = (1 << sent_bits) - 1; + int32_t count, value, *dp; + + pre_shift = wps->int32_zeros + wps->int32_ones + wps->int32_dups; + + if (sent_bits) + for (dp = values, count = num_values; count--; dp++) { + value = (*dp >> pre_shift) & mask; + putbits (value, sent_bits, &wps->wvxbits); + } +} + +// 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 void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); + +static int pack_samples (WavpackContext *wpc, int32_t *buffer) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags, data_count, crc, crc2, i; + uint32_t sample_count = wps->wphdr.block_samples; + short *shaping_array = wps->dc.shaping_array; + int tcount, lossy = FALSE, m = 0; + double noise_acc = 0.0, noise; + struct decorr_pass *dpp; + WavpackMetadata wpmd; + int32_t *bptr; + + crc = crc2 = 0xffffffff; + + if (!(flags & HYBRID_FLAG) && (flags & MONO_DATA)) { + int32_t *eptr = buffer + sample_count; + + for (bptr = buffer; bptr < eptr;) + crc += (crc << 1) + *bptr++; + + if (wps->num_passes) + execute_mono (wpc, buffer, !wps->num_terms, 1); + } + else if (!(flags & HYBRID_FLAG) && !(flags & MONO_DATA)) { + int32_t *eptr = buffer + (sample_count * 2); + + for (bptr = buffer; bptr < eptr; bptr += 2) + crc += (crc << 3) + (bptr [0] << 1) + bptr [0] + bptr [1]; + + if (wps->num_passes) { + execute_stereo (wpc, buffer, !wps->num_terms, 1); + flags = wps->wphdr.flags; + } + } + else if ((flags & HYBRID_FLAG) && (flags & MONO_DATA)) { + if (wps->num_passes) + execute_mono (wpc, buffer, !wps->num_terms, 0); + } + else if ((flags & HYBRID_FLAG) && !(flags & MONO_DATA)) { + if (wps->num_passes) { + execute_stereo (wpc, buffer, !wps->num_terms, 0); + flags = wps->wphdr.flags; + } + } + + 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; + + write_decorr_terms (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + write_decorr_weights (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + write_decorr_samples (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + write_entropy_vars (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + + if ((flags & SRATE_MASK) == SRATE_MASK && wpc->config.sample_rate != 44100) { + write_sample_rate (wpc, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if (flags & HYBRID_FLAG) { + write_hybrid_profile (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if (flags & FLOAT_DATA) { + write_float_info (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if (flags & INT32_DATA) { + write_int32_info (wps, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if ((flags & INITIAL_BLOCK) && + (wpc->config.num_channels > 2 || + wpc->config.channel_mask != 0x5 - wpc->config.num_channels)) { + write_channel_info (wpc, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + if ((flags & INITIAL_BLOCK) && !wps->sample_index) { + write_config_info (wpc, &wpmd); + copy_metadata (&wpmd, wps->blockbuff, wps->blockend); + free_metadata (&wpmd); + } + + bs_open_write (&wps->wvbits, wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 12, wps->blockend); + + if (wpc->wvc_flag) { + wps->wphdr.ckSize = sizeof (WavpackHeader) - 8; + memcpy (wps->block2buff, &wps->wphdr, sizeof (WavpackHeader)); + + if (flags & HYBRID_SHAPE) { + write_shaping_info (wps, &wpmd); + copy_metadata (&wpmd, wps->block2buff, wps->block2end); + free_metadata (&wpmd); + } + + bs_open_write (&wps->wvcbits, wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 12, wps->block2end); + } + + /////////////////////// handle lossless mono mode ///////////////////////// + + if (!(flags & HYBRID_FLAG) && (flags & MONO_DATA)) { + if (!wps->num_passes) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t code = *bptr; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam; + + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = code; + } + else { + sam = dpp->samples_A [m]; + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = code; + } + + code -= apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, code); + } + + m = (m + 1) & (MAX_TERM - 1); + *bptr++ = code; + } + + send_words_lossless (wps, buffer, sample_count); + } + + //////////////////// handle the lossless stereo mode ////////////////////// + + else if (!(flags & HYBRID_FLAG) && !(flags & MONO_DATA)) { + int32_t *eptr = buffer + (sample_count * 2); + + if (!wps->num_passes) { + if (flags & JOINT_STEREO) + for (bptr = buffer; bptr < eptr; bptr += 2) + bptr [1] += ((bptr [0] -= bptr [1]) >> 1); + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) + if (((flags & MAG_MASK) >> MAG_LSB) >= 16 || dpp->delta != 2) + decorr_stereo_pass (dpp, buffer, sample_count); + else + decorr_stereo_pass_id2 (dpp, buffer, sample_count); + } + + send_words_lossless (wps, buffer, sample_count); + } + + /////////////////// handle the lossy/hybrid mono mode ///////////////////// + + else if ((flags & HYBRID_FLAG) && (flags & MONO_DATA)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t code, temp; + int shaping_weight; + + crc2 += (crc2 << 1) + (code = *bptr++); + + if (flags & HYBRID_SHAPE) { + if (shaping_array) + shaping_weight = *shaping_array++; + else + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + + temp = -apply_weight (shaping_weight, wps->dc.error [0]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [0]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [0] = -code; + code += temp; + } + else + wps->dc.error [0] = -(code += temp); + } + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) + dpp->samples_A [2] = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + dpp->samples_A [2] = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + code -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [2])); + } + else + code -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [m])); + + code = send_word (wps, code, 0); + + while (--dpp >= wps->decorr_passes) { + if (dpp->term > MAX_TERM) { + update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [2], code); + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = (code += dpp->aweight_A); + } + else { + int32_t sam = dpp->samples_A [m]; + + update_weight (dpp->weight_A, dpp->delta, sam, code); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = (code += dpp->aweight_A); + } + } + + wps->dc.error [0] += code; + m = (m + 1) & (MAX_TERM - 1); + + if ((crc += (crc << 1) + code) != crc2) + lossy = TRUE; + + if (wpc->config.flags & CONFIG_CALC_NOISE) { + noise = code - bptr [-1]; + + noise_acc += noise *= noise; + wps->dc.noise_ave = (wps->dc.noise_ave * 0.99) + (noise * 0.01); + + if (wps->dc.noise_ave > wps->dc.noise_max) + wps->dc.noise_max = wps->dc.noise_ave; + } + } + + /////////////////// handle the lossy/hybrid stereo mode /////////////////// + + else if ((flags & HYBRID_FLAG) && !(flags & MONO_DATA)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t left, right, temp; + int shaping_weight; + + left = *bptr++; + crc2 += (crc2 << 3) + (left << 1) + left + (right = *bptr++); + + if (flags & HYBRID_SHAPE) { + if (shaping_array) + shaping_weight = *shaping_array++; + else + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + + temp = -apply_weight (shaping_weight, wps->dc.error [0]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [0]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [0] = -left; + left += temp; + } + else + wps->dc.error [0] = -(left += temp); + + if (!shaping_array) + shaping_weight = (wps->dc.shaping_acc [1] += wps->dc.shaping_delta [1]) >> 16; + + temp = -apply_weight (shaping_weight, wps->dc.error [1]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [1]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [1] = -right; + right += temp; + } + else + wps->dc.error [1] = -(right += temp); + } + + if (flags & JOINT_STEREO) + right += ((left -= right) >> 1); + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount-- ; dpp++) + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) { + dpp->samples_A [2] = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_B [2] = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + dpp->samples_A [2] = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + dpp->samples_B [2] = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + + left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [2])); + right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [2])); + } + else if (dpp->term > 0) { + left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [m])); + right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [m])); + } + else { + if (dpp->term == -1) + dpp->samples_B [0] = left; + else if (dpp->term == -2) + dpp->samples_A [0] = right; + + left -= (dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [0])); + right -= (dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [0])); + } + + left = send_word (wps, left, 0); + right = send_word (wps, right, 1); + + while (--dpp >= wps->decorr_passes) + if (dpp->term > MAX_TERM) { + update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [2], left); + update_weight (dpp->weight_B, dpp->delta, dpp->samples_B [2], right); + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + + dpp->samples_A [0] = (left += dpp->aweight_A); + dpp->samples_B [0] = (right += dpp->aweight_B); + } + else if (dpp->term > 0) { + int k = (m + dpp->term) & (MAX_TERM - 1); + + update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [m], left); + dpp->samples_A [k] = (left += dpp->aweight_A); + + update_weight (dpp->weight_B, dpp->delta, dpp->samples_B [m], right); + dpp->samples_B [k] = (right += dpp->aweight_B); + } + else { + if (dpp->term == -1) { + dpp->samples_B [0] = left + dpp->aweight_A; + dpp->aweight_B = apply_weight (dpp->weight_B, dpp->samples_B [0]); + } + else if (dpp->term == -2) { + dpp->samples_A [0] = right + dpp->aweight_B; + dpp->aweight_A = apply_weight (dpp->weight_A, dpp->samples_A [0]); + } + + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], left); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], right); + dpp->samples_B [0] = (left += dpp->aweight_A); + dpp->samples_A [0] = (right += dpp->aweight_B); + } + + if (flags & JOINT_STEREO) + left += (right -= (left >> 1)); + + wps->dc.error [0] += left; + wps->dc.error [1] += right; + m = (m + 1) & (MAX_TERM - 1); + + if ((crc += (crc << 3) + (left << 1) + left + right) != crc2) + lossy = TRUE; + + if (wpc->config.flags & CONFIG_CALC_NOISE) { + noise = (double)(left - bptr [-2]) * (left - bptr [-2]); + noise += (double)(right - bptr [-1]) * (right - bptr [-1]); + + noise_acc += noise /= 2.0; + wps->dc.noise_ave = (wps->dc.noise_ave * 0.99) + (noise * 0.01); + + if (wps->dc.noise_ave > wps->dc.noise_max) + wps->dc.noise_max = wps->dc.noise_ave; + } + } + + if (m) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0 && dpp->term <= MAX_TERM) { + int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; + int k; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + dpp->samples_B [k] = temp_B [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } + + if (wpc->config.flags & CONFIG_CALC_NOISE) + wps->dc.noise_sum += noise_acc; + + flush_word (wps); + data_count = bs_close_write (&wps->wvbits); + + if (data_count) { + if (data_count != (uint32_t) -1) { + uchar *cptr = wps->blockbuff + ((WavpackHeader *) wps->blockbuff)->ckSize + 8; + + *cptr++ = ID_WV_BITSTREAM | ID_LARGE; + *cptr++ = data_count >> 1; + *cptr++ = data_count >> 9; + *cptr++ = data_count >> 17; + ((WavpackHeader *) wps->blockbuff)->ckSize += data_count + 4; + } + else + return FALSE; + } + + ((WavpackHeader *) wps->blockbuff)->crc = crc; + + if (wpc->wvc_flag) { + data_count = bs_close_write (&wps->wvcbits); + + if (data_count && lossy) { + if (data_count != (uint32_t) -1) { + uchar *cptr = wps->block2buff + ((WavpackHeader *) wps->block2buff)->ckSize + 8; + + *cptr++ = ID_WVC_BITSTREAM | ID_LARGE; + *cptr++ = data_count >> 1; + *cptr++ = data_count >> 9; + *cptr++ = data_count >> 17; + ((WavpackHeader *) wps->block2buff)->ckSize += data_count + 4; + } + else + return FALSE; + } + + ((WavpackHeader *) wps->block2buff)->crc = crc2; + } + else if (lossy) + wpc->lossy_blocks = TRUE; + + wps->sample_index += sample_count; + return TRUE; +} + +// Perform a pass of the stereo decorrelation as specified by the referenced +// dpp structure. This version is optimized for samples that can use the +// simple apply_weight macro (i.e. <= 16-bit audio) and for when the weight +// delta is 2 (which is the case with all the default, non -x modes). For +// cases that do not fit this model, the more general decorr_stereo_pass() +// is provided. Note that this function returns the dpp->samples_X[] values +// in the "normalized" positions for terms 1-8. + +static void decorr_stereo_pass_id2 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2); + int m, k; + + switch (dpp->term) { + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam, tmp; + + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + bptr [0] = tmp = (dpp->samples_A [0] = bptr [0]) - apply_weight_i (dpp->weight_A, sam); + update_weight_d2 (dpp->weight_A, dpp->delta, sam, tmp); + + sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + bptr [1] = tmp = (dpp->samples_B [0] = bptr [1]) - apply_weight_i (dpp->weight_B, sam); + update_weight_d2 (dpp->weight_B, dpp->delta, sam, tmp); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam, tmp; + + sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); + dpp->samples_A [1] = dpp->samples_A [0]; + bptr [0] = tmp = (dpp->samples_A [0] = bptr [0]) - apply_weight_i (dpp->weight_A, sam); + update_weight_d2 (dpp->weight_A, dpp->delta, sam, tmp); + + sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); + dpp->samples_B [1] = dpp->samples_B [0]; + bptr [1] = tmp = (dpp->samples_B [0] = bptr [1]) - apply_weight_i (dpp->weight_B, sam); + update_weight_d2 (dpp->weight_B, dpp->delta, sam, tmp); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam, tmp; + + sam = dpp->samples_A [m]; + bptr [0] = tmp = (dpp->samples_A [k] = bptr [0]) - apply_weight_i (dpp->weight_A, sam); + update_weight_d2 (dpp->weight_A, dpp->delta, sam, tmp); + + sam = dpp->samples_B [m]; + bptr [1] = tmp = (dpp->samples_B [k] = bptr [1]) - apply_weight_i (dpp->weight_B, sam); + update_weight_d2 (dpp->weight_B, dpp->delta, sam, tmp); + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + if (m) { + int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + dpp->samples_B [k] = temp_B [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam_A, sam_B, tmp; + + sam_A = dpp->samples_A [0]; + bptr [0] = tmp = (sam_B = bptr [0]) - apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, tmp); + + bptr [1] = tmp = (dpp->samples_A [0] = bptr [1]) - apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, tmp); + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam_A, sam_B, tmp; + + sam_B = dpp->samples_B [0]; + bptr [1] = tmp = (sam_A = bptr [1]) - apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, tmp); + + bptr [0] = tmp = (dpp->samples_B [0] = bptr [0]) - apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, tmp); + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam_A, sam_B, tmp; + + sam_A = dpp->samples_A [0]; + sam_B = dpp->samples_B [0]; + + dpp->samples_A [0] = tmp = bptr [1]; + bptr [1] = tmp -= apply_weight_i (dpp->weight_B, sam_B); + update_weight_clip_d2 (dpp->weight_B, dpp->delta, sam_B, tmp); + + dpp->samples_B [0] = tmp = bptr [0]; + bptr [0] = tmp -= apply_weight_i (dpp->weight_A, sam_A); + update_weight_clip_d2 (dpp->weight_A, dpp->delta, sam_A, tmp); + } + + break; + } +} + +// Perform a pass of the stereo decorrelation as specified by the referenced +// dpp structure. This function is provided in both a regular C version and +// an MMX version (using intrinsics) written by Joachim Henke. The MMX version +// is significantly faster when the sample data requires the full-resolution +// apply_weight macro. However, when the data is lower resolution (<= 16-bit) +// then the difference is slight (or the MMX is even slower), so for these +// cases the simpler decorr_stereo_pass_id2() is used. Note that this function +// returns the dpp->samples_X[] values in the "normalized" positions for +// terms 1-8. + +#ifdef OPT_MMX + +static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + const __m64 + delta = _mm_set1_pi32 (dpp->delta), + fill = _mm_set1_pi32 (0x7bff), + mask = _mm_set1_pi32 (0x7fff), + round = _mm_set1_pi32 (512), + zero = _mm_set1_pi32 (0); + __m64 + weight_AB = _mm_set_pi32 (restore_weight (store_weight (dpp->weight_B)), restore_weight (store_weight (dpp->weight_A))), + left_right, sam_AB, tmp0, tmp1, samples_AB [MAX_TERM]; + int k, m = 0; + + for (k = 0; k < MAX_TERM; ++k) { + ((int32_t *) samples_AB) [k * 2] = exp2s (log2s (dpp->samples_A [k])); + ((int32_t *) samples_AB) [k * 2 + 1] = exp2s (log2s (dpp->samples_B [k])); + } + + if (dpp->term > 0) { + if (dpp->term == 17) { + while (sample_count--) { + left_right = *(__m64 *) buffer; + tmp0 = samples_AB [0]; + sam_AB = _m_paddd (tmp0, tmp0); + sam_AB = _m_psubd (sam_AB, samples_AB [1]); + samples_AB [0] = left_right; + samples_AB [1] = tmp0; + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) buffer = left_right; + + tmp0 = _m_pxor (sam_AB, left_right); + tmp0 = _m_psradi (tmp0, 31); + tmp1 = _m_pxor (delta, tmp0); + tmp1 = _m_psubd (tmp1, tmp0); + sam_AB = _m_pcmpeqd (sam_AB, zero); + tmp0 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, sam_AB); + tmp0 = _m_pandn (tmp0, tmp1); + weight_AB = _m_paddd (weight_AB, tmp0); + + buffer += 2; + } + } + else if (dpp->term == 18) { + while (sample_count--) { + left_right = *(__m64 *) buffer; + tmp0 = samples_AB [0]; + sam_AB = _m_psubd (tmp0, samples_AB [1]); + sam_AB = _m_psradi (sam_AB, 1); + sam_AB = _m_paddd (sam_AB, tmp0); + samples_AB [0] = left_right; + samples_AB [1] = tmp0; + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) buffer = left_right; + + tmp0 = _m_pxor (sam_AB, left_right); + tmp0 = _m_psradi (tmp0, 31); + tmp1 = _m_pxor (delta, tmp0); + tmp1 = _m_psubd (tmp1, tmp0); + sam_AB = _m_pcmpeqd (sam_AB, zero); + tmp0 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, sam_AB); + tmp0 = _m_pandn (tmp0, tmp1); + weight_AB = _m_paddd (weight_AB, tmp0); + + buffer += 2; + } + } + else { + k = dpp->term & (MAX_TERM - 1); + while (sample_count--) { + left_right = *(__m64 *) buffer; + sam_AB = samples_AB [m]; + samples_AB [k] = left_right; + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) buffer = left_right; + + tmp0 = _m_pxor (sam_AB, left_right); + tmp0 = _m_psradi (tmp0, 31); + tmp1 = _m_pxor (delta, tmp0); + tmp1 = _m_psubd (tmp1, tmp0); + sam_AB = _m_pcmpeqd (sam_AB, zero); + tmp0 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, sam_AB); + tmp0 = _m_pandn (tmp0, tmp1); + weight_AB = _m_paddd (weight_AB, tmp0); + + buffer += 2; + k = (k + 1) & (MAX_TERM - 1); + m = (m + 1) & (MAX_TERM - 1); + } + } + } + else { + if (dpp->term == -1) { + while (sample_count--) { + left_right = *(__m64 *) buffer; + sam_AB = samples_AB [0]; + samples_AB [0] = _m_punpckhdq (left_right, sam_AB); + sam_AB = _m_punpckldq (sam_AB, left_right); + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) buffer = left_right; + + tmp0 = _m_pcmpeqd (sam_AB, zero); + tmp1 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, tmp1); + tmp0 = _m_pandn (tmp0, delta); + sam_AB = _m_pxor (sam_AB, left_right); + sam_AB = _m_psradi (sam_AB, 31); + tmp1 = _m_psubd (fill, sam_AB); + weight_AB = _m_pxor (weight_AB, sam_AB); + weight_AB = _m_paddd (weight_AB, tmp1); + weight_AB = _m_paddsw (weight_AB, tmp0); + weight_AB = _m_psubd (weight_AB, tmp1); + weight_AB = _m_pxor (weight_AB, sam_AB); + + buffer += 2; + } + } + else if (dpp->term == -2) { + while (sample_count--) { + left_right = *(__m64 *) buffer; + sam_AB = samples_AB [0]; + samples_AB [0] = _m_punpckldq (sam_AB, left_right); + sam_AB = _m_punpckhdq (left_right, sam_AB); + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) buffer = left_right; + + tmp0 = _m_pcmpeqd (sam_AB, zero); + tmp1 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, tmp1); + tmp0 = _m_pandn (tmp0, delta); + sam_AB = _m_pxor (sam_AB, left_right); + sam_AB = _m_psradi (sam_AB, 31); + tmp1 = _m_psubd (fill, sam_AB); + weight_AB = _m_pxor (weight_AB, sam_AB); + weight_AB = _m_paddd (weight_AB, tmp1); + weight_AB = _m_paddsw (weight_AB, tmp0); + weight_AB = _m_psubd (weight_AB, tmp1); + weight_AB = _m_pxor (weight_AB, sam_AB); + + buffer += 2; + } + } + else if (dpp->term == -3) { + while (sample_count--) { + left_right = *(__m64 *) buffer; + sam_AB = samples_AB [0]; + tmp0 = _m_punpckhdq (left_right, left_right); + samples_AB [0] = _m_punpckldq (tmp0, left_right); + + tmp0 = _m_paddd (sam_AB, sam_AB); + tmp1 = _m_pand (sam_AB, mask); + tmp0 = _m_psrldi (tmp0, 16); + tmp1 = _m_pmaddwd (tmp1, weight_AB); + tmp0 = _m_pmaddwd (tmp0, weight_AB); + tmp1 = _m_paddd (tmp1, round); + tmp0 = _m_pslldi (tmp0, 5); + tmp1 = _m_psradi (tmp1, 10); + left_right = _m_psubd (left_right, tmp0); + left_right = _m_psubd (left_right, tmp1); + + *(__m64 *) buffer = left_right; + + tmp0 = _m_pcmpeqd (sam_AB, zero); + tmp1 = _m_pcmpeqd (left_right, zero); + tmp0 = _m_por (tmp0, tmp1); + tmp0 = _m_pandn (tmp0, delta); + sam_AB = _m_pxor (sam_AB, left_right); + sam_AB = _m_psradi (sam_AB, 31); + tmp1 = _m_psubd (fill, sam_AB); + weight_AB = _m_pxor (weight_AB, sam_AB); + weight_AB = _m_paddd (weight_AB, tmp1); + weight_AB = _m_paddsw (weight_AB, tmp0); + weight_AB = _m_psubd (weight_AB, tmp1); + weight_AB = _m_pxor (weight_AB, sam_AB); + + buffer += 2; + } + } + } + + dpp->weight_A = ((int32_t *) &weight_AB) [0]; + dpp->weight_B = ((int32_t *) &weight_AB) [1]; + + for (k = 0; k < MAX_TERM; ++k) { + dpp->samples_A [k] = ((int32_t *) samples_AB) [m * 2]; + dpp->samples_B [k] = ((int32_t *) samples_AB) [m * 2 + 1]; + m = (m + 1) & (MAX_TERM - 1); + } + + _mm_empty (); +} + +#else + +static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2); + int m, k; + + switch (dpp->term) { + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam, tmp; + + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + bptr [0] = tmp = (dpp->samples_A [0] = bptr [0]) - apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + bptr [1] = tmp = (dpp->samples_B [0] = bptr [1]) - apply_weight (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam, tmp; + + sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); + dpp->samples_A [1] = dpp->samples_A [0]; + bptr [0] = tmp = (dpp->samples_A [0] = bptr [0]) - apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); + dpp->samples_B [1] = dpp->samples_B [0]; + bptr [1] = tmp = (dpp->samples_B [0] = bptr [1]) - apply_weight (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam, tmp; + + sam = dpp->samples_A [m]; + bptr [0] = tmp = (dpp->samples_A [k] = bptr [0]) - apply_weight (dpp->weight_A, sam); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = dpp->samples_B [m]; + bptr [1] = tmp = (dpp->samples_B [k] = bptr [1]) - apply_weight (dpp->weight_B, sam); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + if (m) { + int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + dpp->samples_B [k] = temp_B [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam_A, sam_B, tmp; + + sam_A = dpp->samples_A [0]; + bptr [0] = tmp = (sam_B = bptr [0]) - apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); + + bptr [1] = tmp = (dpp->samples_A [0] = bptr [1]) - apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam_A, sam_B, tmp; + + sam_B = dpp->samples_B [0]; + bptr [1] = tmp = (sam_A = bptr [1]) - apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); + + bptr [0] = tmp = (dpp->samples_B [0] = bptr [0]) - apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam_A, sam_B, tmp; + + sam_A = dpp->samples_A [0]; + sam_B = dpp->samples_B [0]; + + dpp->samples_A [0] = tmp = bptr [1]; + bptr [1] = tmp -= apply_weight (dpp->weight_B, sam_B); + update_weight_clip (dpp->weight_B, dpp->delta, sam_B, tmp); + + dpp->samples_B [0] = tmp = bptr [0]; + bptr [0] = tmp -= apply_weight (dpp->weight_A, sam_A); + update_weight_clip (dpp->weight_A, dpp->delta, sam_A, tmp); + } + + break; + } +} + +#endif + +////////////////////////////////////////////////////////////////////////////// +// This function returns the accumulated RMS noise as a double if the // +// CALC_NOISE bit was set in the WavPack header. The peak noise can also be // +// returned if desired. See wavpack.c for the calculations required to // +// convert this into decibels of noise below full scale. // +////////////////////////////////////////////////////////////////////////////// + +double WavpackGetEncodedNoise (WavpackContext *wpc, double *peak) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + + if (peak) + *peak = wps->dc.noise_max; + + return wps->dc.noise_sum; +} + +// 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. + +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); + } +} diff --git a/wavpack-4.5.0/src/unpack.c b/wavpack-4.5.0/src/unpack.c new file mode 100644 index 0000000..80942c5 --- /dev/null +++ b/wavpack-4.5.0/src/unpack.c @@ -0,0 +1,1399 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2006 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack.c + +// This module actually handles the decompression of the audio data, except +// for the entropy decoding which is handled by the words? modules. For +// maximum efficiency, the conversion is isolated to tight loops that handle +// an entire buffer. + +#include "wavpack_local.h" + +#include +#include +#include +#include + +// This flag provides faster decoding speed at the expense of more code. The +// improvement applies to 16-bit stereo lossless only. + +#define FAST_DECODE + +#define LOSSY_MUTE + +#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 + +///////////////////////////// executable code //////////////////////////////// + +// This function initializes everything required to unpack a WavPack block +// and must be called before unpack_samples() is called to obtain audio data. +// It is assumed that the WavpackHeader has been read into the wps->wphdr +// (in the current WavpackStream) and that the entire block has been read at +// wps->blockbuff. If a correction file is available (wpc->wvc_flag = TRUE) +// then the corresponding correction block must be read into wps->block2buff +// and its WavpackHeader has overwritten the header at wps->wphdr. This is +// where all the metadata blocks are scanned including those that contain +// bitstream data. + +int unpack_init (WavpackContext *wpc) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uchar *blockptr, *block2ptr; + WavpackMetadata wpmd; + + wps->mute_error = FALSE; + wps->crc = wps->crc_x = 0xffffffff; + CLEAR (wps->wvbits); + CLEAR (wps->wvcbits); + CLEAR (wps->wvxbits); + CLEAR (wps->decorr_passes); + CLEAR (wps->dc); + CLEAR (wps->w); + + if (!(wps->wphdr.flags & MONO_FLAG) && wpc->config.num_channels && wps->wphdr.block_samples && + (wpc->reduced_channels == 1 || wpc->config.num_channels == 1)) { + wps->mute_error = TRUE; + return FALSE; + } + + if ((wps->wphdr.flags & UNKNOWN_FLAGS) || (wps->wphdr.flags & MONO_DATA) == MONO_DATA) { + wps->mute_error = TRUE; + return FALSE; + } + + blockptr = wps->blockbuff + sizeof (WavpackHeader); + + while (read_metadata_buff (&wpmd, wps->blockbuff, &blockptr)) + if (!process_metadata (wpc, &wpmd)) { + wps->mute_error = TRUE; + return FALSE; + } + + if (wps->wphdr.block_samples && wpc->wvc_flag && wps->block2buff) { + block2ptr = wps->block2buff + sizeof (WavpackHeader); + + while (read_metadata_buff (&wpmd, wps->block2buff, &block2ptr)) + if (!process_metadata (wpc, &wpmd)) { + wps->mute_error = TRUE; + return FALSE; + } + } + + if (wps->wphdr.block_samples && !bs_is_open (&wps->wvbits)) { + if (bs_is_open (&wps->wvcbits)) + strcpy (wpc->error_message, "can't unpack correction files alone!"); + + wps->mute_error = TRUE; + return FALSE; + } + + if (wps->wphdr.block_samples && !bs_is_open (&wps->wvxbits)) { + if ((wps->wphdr.flags & INT32_DATA) && wps->int32_sent_bits) + wpc->lossy_blocks = TRUE; + + if ((wps->wphdr.flags & FLOAT_DATA) && + wps->float_flags & (FLOAT_EXCEPTIONS | FLOAT_ZEROS_SENT | FLOAT_SHIFT_SENT | FLOAT_SHIFT_SAME)) + wpc->lossy_blocks = TRUE; + } + + if (wps->wphdr.block_samples) + wps->sample_index = wps->wphdr.block_index; + + return TRUE; +} + +// This function initialzes the main bitstream for audio samples, which must +// be in the "wv" file. + +int init_wv_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + if (!wpmd->byte_length) + return FALSE; + + bs_open_read (&wps->wvbits, wpmd->data, (uchar *) wpmd->data + wpmd->byte_length); + return TRUE; +} + +// This function initialzes the "correction" bitstream for audio samples, +// which currently must be in the "wvc" file. + +int init_wvc_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + if (!wpmd->byte_length) + return FALSE; + + bs_open_read (&wps->wvcbits, wpmd->data, (uchar *) wpmd->data + wpmd->byte_length); + return TRUE; +} + +// This function initialzes the "extra" bitstream for audio samples which +// contains the information required to losslessly decompress 32-bit float data +// or integer data that exceeds 24 bits. This bitstream is in the "wv" file +// for pure lossless data or the "wvc" file for hybrid lossless. This data +// would not be used for hybrid lossy mode. There is also a 32-bit CRC stored +// in the first 4 bytes of these blocks. + +int init_wvx_bitstream (WavpackStream *wps, WavpackMetadata *wpmd) +{ + uchar *cp = wpmd->data; + + if (wpmd->byte_length <= 4) + return FALSE; + + wps->crc_wvx = *cp++; + wps->crc_wvx |= (int32_t) *cp++ << 8; + wps->crc_wvx |= (int32_t) *cp++ << 16; + wps->crc_wvx |= (int32_t) *cp++ << 24; + + bs_open_read (&wps->wvxbits, cp, (uchar *) wpmd->data + wpmd->byte_length); + return TRUE; +} + +// Read decorrelation terms from specified metadata block into the +// decorr_passes array. The terms range from -3 to 8, plus 17 & 18; +// other values are reserved and generate errors for now. The delta +// ranges from 0 to 7 with all values valid. Note that the terms are +// stored in the opposite order in the decorr_passes array compared +// to packing. + +int read_decorr_terms (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int termcnt = wpmd->byte_length; + uchar *byteptr = wpmd->data; + struct decorr_pass *dpp; + + if (termcnt > MAX_NTERMS) + return FALSE; + + wps->num_terms = termcnt; + + for (dpp = wps->decorr_passes + termcnt - 1; termcnt--; dpp--) { + dpp->term = (int)(*byteptr & 0x1f) - 5; + dpp->delta = (*byteptr++ >> 5) & 0x7; + + if (!dpp->term || dpp->term < -3 || (dpp->term > MAX_TERM && dpp->term < 17) || dpp->term > 18) + return FALSE; + } + + return TRUE; +} + +// Read decorrelation weights from specified metadata block into the +// decorr_passes array. The weights range +/-1024, but are rounded and +// truncated to fit in signed chars for metadata storage. Weights are +// separate for the two channels and are specified from the "last" term +// (first during encode). Unspecified weights are set to zero. + +int read_decorr_weights (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int termcnt = wpmd->byte_length, tcount; + char *byteptr = wpmd->data; + struct decorr_pass *dpp; + + if (!(wps->wphdr.flags & MONO_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) +{ + uchar *byteptr = wpmd->data; + uchar *endptr = byteptr + wpmd->byte_length; + struct decorr_pass *dpp; + int tcount; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + CLEAR (dpp->samples_A); + CLEAR (dpp->samples_B); + } + + if (wps->wphdr.version == 0x402 && (wps->wphdr.flags & HYBRID_FLAG)) { + if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) + return FALSE; + + wps->dc.error [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->dc.error [1] = exp2s ((short)(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] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_A [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + + if (!(wps->wphdr.flags & MONO_DATA)) { + dpp->samples_B [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_B [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + } + else if (dpp->term < 0) { + if (byteptr + 4 > endptr) + return FALSE; + + dpp->samples_A [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + dpp->samples_B [0] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + else { + int m = 0, cnt = dpp->term; + + while (cnt--) { + if (byteptr + (wps->wphdr.flags & MONO_DATA ? 2 : 4) > endptr) + return FALSE; + + dpp->samples_A [m] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + dpp->samples_B [m] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + } + + m++; + } + } + + return byteptr == endptr; +} + +// Read the shaping weights from specified metadata block into the +// WavpackStream structure. Note that there must be two values (even +// for mono streams) and that the values are stored in the same +// manner as decorrelation weights. These would normally be read from +// the "correction" file and are used for lossless reconstruction of +// hybrid data. + +int read_shaping_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + if (wpmd->byte_length == 2) { + char *byteptr = wpmd->data; + + wps->dc.shaping_acc [0] = (int32_t) restore_weight (*byteptr++) << 16; + wps->dc.shaping_acc [1] = (int32_t) restore_weight (*byteptr++) << 16; + return TRUE; + } + else if (wpmd->byte_length >= (wps->wphdr.flags & MONO_DATA ? 4 : 8)) { + uchar *byteptr = wpmd->data; + + wps->dc.error [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + wps->dc.shaping_acc [0] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->dc.error [1] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + wps->dc.shaping_acc [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + byteptr += 4; + } + + if (wpmd->byte_length == (wps->wphdr.flags & MONO_DATA ? 6 : 12)) { + wps->dc.shaping_delta [0] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + + if (!(wps->wphdr.flags & MONO_DATA)) + wps->dc.shaping_delta [1] = exp2s ((short)(byteptr [2] + (byteptr [3] << 8))); + } + + return TRUE; + } + + return FALSE; +} + +// Read the int32 data from the specified metadata into the specified stream. +// This data is used for integer data that has more than 24 bits of magnitude +// or, in some cases, used to eliminate redundant bits from any audio stream. + +int read_int32_info (WavpackStream *wps, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + char *byteptr = wpmd->data; + + if (bytecnt != 4) + return FALSE; + + wps->int32_sent_bits = *byteptr++; + wps->int32_zeros = *byteptr++; + wps->int32_ones = *byteptr++; + wps->int32_dups = *byteptr; + + return TRUE; +} + +// Read multichannel information from metadata. The first byte is the total +// number of channels and the following bytes represent the channel_mask +// as described for Microsoft WAVEFORMATEX. + +int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length, shift = 0; + uchar *byteptr = wpmd->data; + uint32_t mask = 0; + + if (!bytecnt || bytecnt > 5) + return FALSE; + + if (!wpc->config.num_channels) { + wpc->config.num_channels = *byteptr++; + + while (--bytecnt) { + mask |= (uint32_t) *byteptr++ << shift; + shift += 8; + } + + wpc->config.channel_mask = mask; + } + + return TRUE; +} + +// Read configuration information from metadata. + +int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + uchar *byteptr = wpmd->data; + + if (bytecnt >= 3) { + wpc->config.flags &= 0xff; + wpc->config.flags |= (int32_t) *byteptr++ << 8; + wpc->config.flags |= (int32_t) *byteptr++ << 16; + wpc->config.flags |= (int32_t) *byteptr++ << 24; + + if (bytecnt >= 4 && (wpc->config.flags & CONFIG_EXTRA_MODE)) + wpc->config.xmode = *byteptr; + } + + return TRUE; +} + +// Read non-standard sampling rate from metadata. + +int read_sample_rate (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + int bytecnt = wpmd->byte_length; + uchar *byteptr = wpmd->data; + + if (bytecnt == 3) { + wpc->config.sample_rate = (int32_t) *byteptr++; + wpc->config.sample_rate |= (int32_t) *byteptr++ << 8; + wpc->config.sample_rate |= (int32_t) *byteptr++ << 16; + } + + return TRUE; +} + +// Read wrapper data from metadata. Currently, this consists of the RIFF +// header and trailer that wav files contain around the audio data but could +// be used for other formats as well. Because WavPack files contain all the +// information required for decoding and playback, this data can probably +// be ignored except when an exact wavefile restoration is needed. + +int read_wrapper_data (WavpackContext *wpc, WavpackMetadata *wpmd) +{ + if ((wpc->open_flags & OPEN_WRAPPER) && wpc->wrapper_bytes < MAX_WRAPPER_BYTES) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + wpmd->byte_length); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, wpmd->data, wpmd->byte_length); + wpc->wrapper_bytes += wpmd->byte_length; + } + + return TRUE; +} + +#ifndef NO_UNPACK + +// This monster actually unpacks the WavPack bitstream(s) into the specified +// buffer as 32-bit integers or floats (depending on orignal data). Lossy +// samples will be clipped to their original limits (i.e. 8-bit samples are +// clipped to -128/+127) but are still returned in longs. It is up to the +// caller to potentially reformat this for the final output including any +// multichannel distribution, block alignment or endian compensation. The +// function unpack_init() must have been called and the entire WavPack block +// must still be visible (although wps->blockbuff will not be accessed again). +// For maximum clarity, the function is broken up into segments that handle +// various modes. This makes for a few extra infrequent flag checks, but +// makes the code easier to follow because the nesting does not become so +// deep. For maximum efficiency, the conversion is isolated to tight loops +// that handle an entire buffer. The function returns the total number of +// samples unpacked, which can be less than the number requested if an error +// occurs or the end of the block is reached. + +static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_1717 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_1718 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_1818 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void decorr_stereo_pass_nn (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count); +static void fixup_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count); + +int32_t unpack_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags, crc = wps->crc, i; + int32_t mute_limit = (1L << ((flags & MAG_MASK) >> MAG_LSB)) + 2; + int32_t correction [2], read_word, *bptr; + struct decorr_pass *dpp; + int tcount, m = 0; + + if (wps->sample_index + sample_count > wps->wphdr.block_index + wps->wphdr.block_samples) + sample_count = wps->wphdr.block_index + wps->wphdr.block_samples - wps->sample_index; + + if (wps->mute_error) { + if (wpc->reduced_channels == 1 || wpc->config.num_channels == 1 || (flags & MONO_FLAG)) + memset (buffer, 0, sample_count * 4); + else + memset (buffer, 0, sample_count * 8); + + wps->sample_index += sample_count; + return sample_count; + } + + if ((flags & HYBRID_FLAG) && !wps->block2buff) + mute_limit *= 2; + + //////////////// handle lossless or hybrid lossy mono data ///////////////// + + if (!wps->block2buff && (flags & MONO_DATA)) { + int32_t *eptr = buffer + sample_count; + + if (flags & HYBRID_FLAG) { + i = sample_count; + + for (bptr = buffer; bptr < eptr;) + if ((*bptr++ = get_word (wps, 0, NULL)) == WORD_EOF) { + i = (uint32_t)(bptr - buffer); + break; + } + } + else + i = get_words_lossless (wps, buffer, sample_count); + + for (bptr = buffer; bptr < eptr;) { + read_word = *bptr; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam, temp; + int k; + + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); + + dpp->samples_A [1] = dpp->samples_A [0]; + k = 0; + } + else { + sam = dpp->samples_A [m]; + k = (m + dpp->term) & (MAX_TERM - 1); + } + + temp = apply_weight (dpp->weight_A, sam) + read_word; + update_weight (dpp->weight_A, dpp->delta, sam, read_word); + dpp->samples_A [k] = read_word = temp; + } + + if (labs (read_word) > mute_limit) { + i = (uint32_t)(bptr - buffer); + break; + } + + m = (m + 1) & (MAX_TERM - 1); + crc += (crc << 1) + (*bptr++ = read_word); + } + } + + /////////////// handle lossless or hybrid lossy stereo data /////////////// + + else if (!wps->block2buff && !(flags & MONO_DATA)) { + int32_t *eptr = buffer + (sample_count * 2); + + if (flags & HYBRID_FLAG) { + i = sample_count; + + for (bptr = buffer; bptr < eptr; bptr += 2) + if ((bptr [0] = get_word (wps, 0, NULL)) == WORD_EOF || + (bptr [1] = get_word (wps, 1, NULL)) == WORD_EOF) { + i = (uint32_t)(bptr - buffer) / 2; + break; + } + } + else + i = get_words_lossless (wps, buffer, sample_count); + +#ifdef FAST_DECODE + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (((flags & MAG_MASK) >> MAG_LSB) >= 16) + decorr_stereo_pass (dpp, buffer, sample_count); + else if (tcount && dpp [0].term == 17 && dpp [1].term == 17) { + decorr_stereo_pass_1717 (dpp, buffer, sample_count); + tcount--; + dpp++; + } + else if (tcount && dpp [0].term == 17 && dpp [1].term == 18) { + decorr_stereo_pass_1718 (dpp, buffer, sample_count); + tcount--; + dpp++; + } + else if (tcount && dpp [0].term == 18 && dpp [1].term == 18) { + decorr_stereo_pass_1818 (dpp, buffer, sample_count); + tcount--; + dpp++; + } + else if (tcount && dpp [0].term >= 1 && dpp [0].term <= 7 && + dpp [1].term >= 1 && dpp [1].term <= 7) { + decorr_stereo_pass_nn (dpp, buffer, sample_count); + tcount--; + dpp++; + } + else + decorr_stereo_pass_i (dpp, buffer, sample_count); +#else + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + decorr_stereo_pass (dpp, buffer, sample_count); +#endif + + if (flags & JOINT_STEREO) + for (bptr = buffer; bptr < eptr; bptr += 2) { + bptr [0] += (bptr [1] -= (bptr [0] >> 1)); + crc += (crc << 3) + (bptr [0] << 1) + bptr [0] + bptr [1]; + } + else + for (bptr = buffer; bptr < eptr; bptr += 2) + crc += (crc << 3) + (bptr [0] << 1) + bptr [0] + bptr [1]; + + for (bptr = buffer; bptr < eptr; bptr += 16) + if (labs (bptr [0]) > mute_limit || labs (bptr [1]) > mute_limit) { + i = (uint32_t)(bptr - buffer) / 2; + break; + } + + m = sample_count & (MAX_TERM - 1); + } + + /////////////////// handle hybrid lossless mono data //////////////////// + + else if ((flags & HYBRID_FLAG) && (flags & MONO_DATA)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + if ((read_word = get_word (wps, 0, correction)) == WORD_EOF) + break; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam, temp; + int k; + + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + else + sam = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + + dpp->samples_A [1] = dpp->samples_A [0]; + k = 0; + } + else { + sam = dpp->samples_A [m]; + k = (m + dpp->term) & (MAX_TERM - 1); + } + + temp = apply_weight (dpp->weight_A, sam) + read_word; + update_weight (dpp->weight_A, dpp->delta, sam, read_word); + dpp->samples_A [k] = read_word = temp; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & HYBRID_SHAPE) { + int shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + int32_t temp = -apply_weight (shaping_weight, wps->dc.error [0]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [0]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [0] = temp - correction [0]; + } + else + wps->dc.error [0] = -correction [0]; + + read_word += correction [0] - temp; + } + else + read_word += correction [0]; + + crc += (crc << 1) + read_word; + +#ifdef LOSSY_MUTE + if (labs (read_word) > mute_limit) + break; +#endif + *bptr++ = read_word; + } + + //////////////////// handle hybrid lossless stereo data /////////////////// + + else if (wps->block2buff && !(flags & MONO_DATA)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t left, right, left2, right2; + int32_t left_c = 0, right_c = 0; + + if ((left = get_word (wps, 0, correction)) == WORD_EOF || + (right = get_word (wps, 1, correction + 1)) == WORD_EOF) + break; + + if (flags & CROSS_DECORR) { + left_c = left + correction [0]; + right_c = right + correction [1]; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam_A, sam_B; + + if (dpp->term > 0) { + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + } + else { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + } + + left_c += apply_weight (dpp->weight_A, sam_A); + right_c += apply_weight (dpp->weight_B, sam_B); + } + else if (dpp->term == -1) { + left_c += apply_weight (dpp->weight_A, dpp->samples_A [0]); + right_c += apply_weight (dpp->weight_B, left_c); + } + else { + right_c += apply_weight (dpp->weight_B, dpp->samples_B [0]); + + if (dpp->term == -3) + left_c += apply_weight (dpp->weight_A, dpp->samples_A [0]); + else + left_c += apply_weight (dpp->weight_A, right_c); + } + } + + if (flags & JOINT_STEREO) + left_c += (right_c -= (left_c >> 1)); + } + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam_A, sam_B; + + if (dpp->term > 0) { + int k; + + if (dpp->term > MAX_TERM) { + if (dpp->term & 1) { + sam_A = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + sam_B = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + } + else { + sam_A = (3 * dpp->samples_A [0] - dpp->samples_A [1]) >> 1; + sam_B = (3 * dpp->samples_B [0] - dpp->samples_B [1]) >> 1; + } + + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_B [1] = dpp->samples_B [0]; + k = 0; + } + else { + sam_A = dpp->samples_A [m]; + sam_B = dpp->samples_B [m]; + k = (m + dpp->term) & (MAX_TERM - 1); + } + + left2 = apply_weight (dpp->weight_A, sam_A) + left; + right2 = apply_weight (dpp->weight_B, sam_B) + right; + + update_weight (dpp->weight_A, dpp->delta, sam_A, left); + update_weight (dpp->weight_B, dpp->delta, sam_B, right); + + dpp->samples_A [k] = left = left2; + dpp->samples_B [k] = right = right2; + } + else if (dpp->term == -1) { + left2 = left + apply_weight (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], left); + left = left2; + right2 = right + apply_weight (dpp->weight_B, left2); + update_weight_clip (dpp->weight_B, dpp->delta, left2, right); + dpp->samples_A [0] = right = right2; + } + else { + right2 = right + apply_weight (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], right); + right = right2; + + if (dpp->term == -3) { + right2 = dpp->samples_A [0]; + dpp->samples_A [0] = right; + } + + left2 = left + apply_weight (dpp->weight_A, right2); + update_weight_clip (dpp->weight_A, dpp->delta, right2, left); + dpp->samples_B [0] = left = left2; + } + } + + m = (m + 1) & (MAX_TERM - 1); + + if (!(flags & CROSS_DECORR)) { + left_c = left + correction [0]; + right_c = right + correction [1]; + + if (flags & JOINT_STEREO) + left_c += (right_c -= (left_c >> 1)); + } + + if (flags & JOINT_STEREO) + left += (right -= (left >> 1)); + + if (flags & HYBRID_SHAPE) { + int shaping_weight; + int32_t temp; + + correction [0] = left_c - left; + shaping_weight = (wps->dc.shaping_acc [0] += wps->dc.shaping_delta [0]) >> 16; + temp = -apply_weight (shaping_weight, wps->dc.error [0]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [0]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [0] = temp - correction [0]; + } + else + wps->dc.error [0] = -correction [0]; + + left = left_c - temp; + correction [1] = right_c - right; + shaping_weight = (wps->dc.shaping_acc [1] += wps->dc.shaping_delta [1]) >> 16; + temp = -apply_weight (shaping_weight, wps->dc.error [1]); + + if ((flags & NEW_SHAPING) && shaping_weight < 0 && temp) { + if (temp == wps->dc.error [1]) + temp = (temp < 0) ? temp + 1 : temp - 1; + + wps->dc.error [1] = temp - correction [1]; + } + else + wps->dc.error [1] = -correction [1]; + + right = right_c - temp; + } + else { + left = left_c; + right = right_c; + } + +#ifdef LOSSY_MUTE + if (labs (left) > mute_limit || labs (right) > mute_limit) + break; +#endif + crc += (crc << 3) + (left << 1) + left + right; + *bptr++ = left; + *bptr++ = right; + } + else + i = 0; /* this line can't execute, but suppresses compiler warning */ + + if (i != sample_count) { + memset (buffer, 0, sample_count * (flags & MONO_FLAG ? 4 : 8)); + wps->mute_error = TRUE; + i = sample_count; + + if (bs_is_open (&wps->wvxbits)) + bs_close_read (&wps->wvxbits); + } + + if (m) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0 && dpp->term <= MAX_TERM) { + int32_t temp_A [MAX_TERM], temp_B [MAX_TERM]; + int k; + + memcpy (temp_A, dpp->samples_A, sizeof (dpp->samples_A)); + memcpy (temp_B, dpp->samples_B, sizeof (dpp->samples_B)); + + for (k = 0; k < MAX_TERM; k++) { + dpp->samples_A [k] = temp_A [m]; + dpp->samples_B [k] = temp_B [m]; + m = (m + 1) & (MAX_TERM - 1); + } + } + + fixup_samples (wpc, buffer, i); + + if ((flags & FLOAT_DATA) && (wpc->open_flags & OPEN_NORMALIZE)) + WavpackFloatNormalize (buffer, (flags & MONO_DATA) ? i : i * 2, + 127 - wps->float_norm_exp + wpc->norm_offset); + + if (flags & FALSE_STEREO) { + int32_t *dptr = buffer + i * 2; + int32_t *sptr = buffer + i; + int32_t c = i; + + while (c--) { + *--dptr = *--sptr; + *--dptr = *sptr; + } + } + + wps->sample_index += i; + wps->crc = crc; + + return i; +} + +// General function to perform stereo decorrelation pass on specified buffer +// (although since this is the reverse function it might technically be called +// "correlation" instead). This version handles all sample resolutions and +// weight deltas. The dpp->samples_X[] data is *not* returned normalized for +// term values 1-8, so it should be normalized if it is going to be used to +// call this function again. + +static void decorr_stereo_pass (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2); + int m, k; + + switch (dpp->term) { + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam, tmp; + + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + bptr [0] = dpp->samples_A [0] = apply_weight (dpp->weight_A, sam) + (tmp = bptr [0]); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + bptr [1] = dpp->samples_B [0] = apply_weight (dpp->weight_B, sam) + (tmp = bptr [1]); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam, tmp; + + sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); + dpp->samples_A [1] = dpp->samples_A [0]; + bptr [0] = dpp->samples_A [0] = apply_weight (dpp->weight_A, sam) + (tmp = bptr [0]); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); + dpp->samples_B [1] = dpp->samples_B [0]; + bptr [1] = dpp->samples_B [0] = apply_weight (dpp->weight_B, sam) + (tmp = bptr [1]); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam; + + sam = dpp->samples_A [m]; + dpp->samples_A [k] = apply_weight (dpp->weight_A, sam) + bptr [0]; + update_weight (dpp->weight_A, dpp->delta, sam, bptr [0]); + bptr [0] = dpp->samples_A [k]; + + sam = dpp->samples_B [m]; + dpp->samples_B [k] = apply_weight (dpp->weight_B, sam) + bptr [1]; + update_weight (dpp->weight_B, dpp->delta, sam, bptr [1]); + bptr [1] = dpp->samples_B [k]; + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam; + + sam = bptr [0] + apply_weight (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + bptr [0] = sam; + dpp->samples_A [0] = bptr [1] + apply_weight (dpp->weight_B, sam); + update_weight_clip (dpp->weight_B, dpp->delta, sam, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam; + + sam = bptr [1] + apply_weight (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [1] = sam; + dpp->samples_B [0] = bptr [0] + apply_weight (dpp->weight_A, sam); + update_weight_clip (dpp->weight_A, dpp->delta, sam, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam_A, sam_B; + + sam_A = bptr [0] + apply_weight (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + sam_B = bptr [1] + apply_weight (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [0] = dpp->samples_B [0] = sam_A; + bptr [1] = dpp->samples_A [0] = sam_B; + } + + break; + } +} + +#ifdef FAST_DECODE + +// This function is a specialized version of decorr_stereo_pass() that works +// only with lower resolution data (<= 16-bit), but is otherwise identical. + +static void decorr_stereo_pass_i (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2); + int m, k; + + switch (dpp->term) { + case 17: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam, tmp; + + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + bptr [0] = dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam) + (tmp = bptr [0]); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + bptr [1] = dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam) + (tmp = bptr [1]); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + } + + break; + + case 18: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam, tmp; + + sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); + dpp->samples_A [1] = dpp->samples_A [0]; + bptr [0] = dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam) + (tmp = bptr [0]); + update_weight (dpp->weight_A, dpp->delta, sam, tmp); + + sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); + dpp->samples_B [1] = dpp->samples_B [0]; + bptr [1] = dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam) + (tmp = bptr [1]); + update_weight (dpp->weight_B, dpp->delta, sam, tmp); + } + + break; + + default: + for (m = 0, k = dpp->term & (MAX_TERM - 1), bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam; + + sam = dpp->samples_A [m]; + dpp->samples_A [k] = apply_weight_i (dpp->weight_A, sam) + bptr [0]; + update_weight (dpp->weight_A, dpp->delta, sam, bptr [0]); + bptr [0] = dpp->samples_A [k]; + + sam = dpp->samples_B [m]; + dpp->samples_B [k] = apply_weight_i (dpp->weight_B, sam) + bptr [1]; + update_weight (dpp->weight_B, dpp->delta, sam, bptr [1]); + bptr [1] = dpp->samples_B [k]; + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + } + + break; + + case -1: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam; + + sam = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + bptr [0] = sam; + dpp->samples_A [0] = bptr [1] + apply_weight_i (dpp->weight_B, sam); + update_weight_clip (dpp->weight_B, dpp->delta, sam, bptr [1]); + bptr [1] = dpp->samples_A [0]; + } + + break; + + case -2: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam; + + sam = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [1] = sam; + dpp->samples_B [0] = bptr [0] + apply_weight_i (dpp->weight_A, sam); + update_weight_clip (dpp->weight_A, dpp->delta, sam, bptr [0]); + bptr [0] = dpp->samples_B [0]; + } + + break; + + case -3: + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam_A, sam_B; + + sam_A = bptr [0] + apply_weight_i (dpp->weight_A, dpp->samples_A [0]); + update_weight_clip (dpp->weight_A, dpp->delta, dpp->samples_A [0], bptr [0]); + sam_B = bptr [1] + apply_weight_i (dpp->weight_B, dpp->samples_B [0]); + update_weight_clip (dpp->weight_B, dpp->delta, dpp->samples_B [0], bptr [1]); + bptr [0] = dpp->samples_B [0] = sam_A; + bptr [1] = dpp->samples_A [0] = sam_B; + } + + break; + } +} + +// These functions are specialized versions of decorr_stereo_pass() that work +// only with lower resolution data (<= 16-bit) and handle the equivalent of +// *two* decorrelation passes. By combining two passes we save a read and write +// of the sample data and some overhead dealing with buffer pointers and looping. +// +// The cases handled are: +// 17,17 -- standard "fast" mode before version 4.40 +// 17,18 -- standard "fast" mode starting with 4.40 +// 18,18 -- used in the default and higher modes +// [1-7],[1-7] -- common in "high" and "very high" modes + +static void decorr_stereo_pass_1718 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2); + + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam; + + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam) + bptr [0]; + update_weight (dpp->weight_A, dpp->delta, sam, bptr [0]); + + sam = (dpp+1)->samples_A [0] + (((dpp+1)->samples_A [0] - (dpp+1)->samples_A [1]) >> 1); + (dpp+1)->samples_A [1] = (dpp+1)->samples_A [0]; + bptr [0] = (dpp+1)->samples_A [0] = apply_weight_i ((dpp+1)->weight_A, sam) + dpp->samples_A [0]; + update_weight ((dpp+1)->weight_A, (dpp+1)->delta, sam, dpp->samples_A [0]); + + sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam) + bptr [1]; + update_weight (dpp->weight_B, dpp->delta, sam, bptr [1]); + + sam = (dpp+1)->samples_B [0] + (((dpp+1)->samples_B [0] - (dpp+1)->samples_B [1]) >> 1); + (dpp+1)->samples_B [1] = (dpp+1)->samples_B [0]; + bptr [1] = (dpp+1)->samples_B [0] = apply_weight_i ((dpp+1)->weight_B, sam) + dpp->samples_B [0]; + update_weight ((dpp+1)->weight_B, (dpp+1)->delta, sam, dpp->samples_B [0]); + } +} + +static void decorr_stereo_pass_1717 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2); + + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam; + + sam = 2 * dpp->samples_A [0] - dpp->samples_A [1]; + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam) + bptr [0]; + update_weight (dpp->weight_A, dpp->delta, sam, bptr [0]); + + sam = 2 * (dpp+1)->samples_A [0] - (dpp+1)->samples_A [1]; + (dpp+1)->samples_A [1] = (dpp+1)->samples_A [0]; + bptr [0] = (dpp+1)->samples_A [0] = apply_weight_i ((dpp+1)->weight_A, sam) + dpp->samples_A [0]; + update_weight ((dpp+1)->weight_A, (dpp+1)->delta, sam, dpp->samples_A [0]); + + sam = 2 * dpp->samples_B [0] - dpp->samples_B [1]; + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam) + bptr [1]; + update_weight (dpp->weight_B, dpp->delta, sam, bptr [1]); + + sam = 2 * (dpp+1)->samples_B [0] - (dpp+1)->samples_B [1]; + (dpp+1)->samples_B [1] = (dpp+1)->samples_B [0]; + bptr [1] = (dpp+1)->samples_B [0] = apply_weight_i ((dpp+1)->weight_B, sam) + dpp->samples_B [0]; + update_weight ((dpp+1)->weight_B, (dpp+1)->delta, sam, dpp->samples_B [0]); + } +} + +static void decorr_stereo_pass_1818 (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2); + + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t sam; + + sam = dpp->samples_A [0] + ((dpp->samples_A [0] - dpp->samples_A [1]) >> 1); + dpp->samples_A [1] = dpp->samples_A [0]; + dpp->samples_A [0] = apply_weight_i (dpp->weight_A, sam) + bptr [0]; + update_weight (dpp->weight_A, dpp->delta, sam, bptr [0]); + + sam = (dpp+1)->samples_A [0] + (((dpp+1)->samples_A [0] - (dpp+1)->samples_A [1]) >> 1); + (dpp+1)->samples_A [1] = (dpp+1)->samples_A [0]; + bptr [0] = (dpp+1)->samples_A [0] = apply_weight_i ((dpp+1)->weight_A, sam) + dpp->samples_A [0]; + update_weight ((dpp+1)->weight_A, (dpp+1)->delta, sam, dpp->samples_A [0]); + + sam = dpp->samples_B [0] + ((dpp->samples_B [0] - dpp->samples_B [1]) >> 1); + dpp->samples_B [1] = dpp->samples_B [0]; + dpp->samples_B [0] = apply_weight_i (dpp->weight_B, sam) + bptr [1]; + update_weight (dpp->weight_B, dpp->delta, sam, bptr [1]); + + sam = (dpp+1)->samples_B [0] + (((dpp+1)->samples_B [0] - (dpp+1)->samples_B [1]) >> 1); + (dpp+1)->samples_B [1] = (dpp+1)->samples_B [0]; + bptr [1] = (dpp+1)->samples_B [0] = apply_weight_i ((dpp+1)->weight_B, sam) + dpp->samples_B [0]; + update_weight ((dpp+1)->weight_B, (dpp+1)->delta, sam, dpp->samples_B [0]); + } +} + +static void decorr_stereo_pass_nn (struct decorr_pass *dpp, int32_t *buffer, int32_t sample_count) +{ + int32_t *bptr, *eptr = buffer + (sample_count * 2); + int m, k, j; + + m = 0; + k = dpp->term & (MAX_TERM - 1); + j = (dpp+1)->term & (MAX_TERM - 1); + + for (bptr = buffer; bptr < eptr; bptr += 2) { + int32_t tmp; + + dpp->samples_A [k] = apply_weight_i (dpp->weight_A, dpp->samples_A [m]) + (tmp = bptr [0]); + update_weight (dpp->weight_A, dpp->delta, dpp->samples_A [m], tmp); + + bptr [0] = (dpp+1)->samples_A [j] = apply_weight_i ((dpp+1)->weight_A, (dpp+1)->samples_A [m]) + (tmp = dpp->samples_A [k]); + update_weight ((dpp+1)->weight_A, (dpp+1)->delta, (dpp+1)->samples_A [m], tmp); + + dpp->samples_B [k] = apply_weight_i (dpp->weight_B, dpp->samples_B [m]) + (tmp = bptr [1]); + update_weight (dpp->weight_B, dpp->delta, dpp->samples_B [m], tmp); + + bptr [1] = (dpp+1)->samples_B [j] = apply_weight_i ((dpp+1)->weight_B, (dpp+1)->samples_B [m]) + (tmp = dpp->samples_B [k]); + update_weight ((dpp+1)->weight_B, (dpp+1)->delta, (dpp+1)->samples_B [m], tmp); + + m = (m + 1) & (MAX_TERM - 1); + k = (k + 1) & (MAX_TERM - 1); + j = (j + 1) & (MAX_TERM - 1); + } +} + +#endif + +// This is a helper function for unpack_samples() that applies several final +// operations. First, if the data is 32-bit float data, then that conversion +// is done in the float.c module (whether lossy or lossless) and we return. +// Otherwise, if the extended integer data applies, then that operation is +// executed first. If the unpacked data is lossy (and not corrected) then +// it is clipped and shifted in a single operation. Otherwise, if it's +// lossless then the last step is to apply the final shift (if any). + +static void fixup_samples (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count) +{ + WavpackStream *wps = wpc->streams [wpc->current_stream]; + uint32_t flags = wps->wphdr.flags; + int lossy_flag = (flags & HYBRID_FLAG) && !wps->block2buff; + int shift = (flags & SHIFT_MASK) >> SHIFT_LSB; + + if (flags & FLOAT_DATA) { + float_values (wps, buffer, (flags & MONO_DATA) ? sample_count : sample_count * 2); + return; + } + + if (flags & INT32_DATA) { + uint32_t count = (flags & MONO_DATA) ? sample_count : sample_count * 2; + int sent_bits = wps->int32_sent_bits, zeros = wps->int32_zeros; + int ones = wps->int32_ones, dups = wps->int32_dups; + uint32_t data, mask = (1 << sent_bits) - 1; + int32_t *dptr = buffer; + + if (bs_is_open (&wps->wvxbits)) { + uint32_t crc = wps->crc_x; + + while (count--) { +// if (sent_bits) { + getbits (&data, sent_bits, &wps->wvxbits); + *dptr = (*dptr << sent_bits) | (data & mask); +// } + + if (zeros) + *dptr <<= zeros; + else if (ones) + *dptr = ((*dptr + 1) << ones) - 1; + else if (dups) + *dptr = ((*dptr + (*dptr & 1)) << dups) - (*dptr & 1); + + crc = crc * 9 + (*dptr & 0xffff) * 3 + ((*dptr >> 16) & 0xffff); + dptr++; + } + + wps->crc_x = crc; + } + else if (!sent_bits && (zeros + ones + dups)) { + while (lossy_flag && (flags & BYTES_STORED) == 3 && shift < 8) { + if (zeros) + zeros--; + else if (ones) + ones--; + else if (dups) + dups--; + else + break; + + shift++; + } + + while (count--) { + if (zeros) + *dptr <<= zeros; + else if (ones) + *dptr = ((*dptr + 1) << ones) - 1; + else if (dups) + *dptr = ((*dptr + (*dptr & 1)) << dups) - (*dptr & 1); + + dptr++; + } + } + else + shift += zeros + sent_bits + ones + dups; + } + + if (lossy_flag) { + int32_t min_value, max_value, min_shifted, max_shifted; + + switch (flags & BYTES_STORED) { + case 0: + min_shifted = (min_value = -128 >> shift) << shift; + max_shifted = (max_value = 127 >> shift) << shift; + break; + + case 1: + min_shifted = (min_value = -32768 >> shift) << shift; + max_shifted = (max_value = 32767 >> shift) << shift; + break; + + case 2: + min_shifted = (min_value = -8388608 >> shift) << shift; + max_shifted = (max_value = 8388607 >> shift) << shift; + break; + + case 3: default: /* "default" suppresses compiler warning */ + min_shifted = (min_value = (int32_t) 0x80000000 >> shift) << shift; + max_shifted = (max_value = (int32_t) 0x7fffffff >> shift) << shift; + break; + } + + if (!(flags & MONO_DATA)) + sample_count *= 2; + + while (sample_count--) { + if (*buffer < min_value) + *buffer++ = min_shifted; + else if (*buffer > max_value) + *buffer++ = max_shifted; + else + *buffer++ <<= shift; + } + } + else if (shift) { + if (!(flags & MONO_DATA)) + sample_count *= 2; + + while (sample_count--) + *buffer++ <<= shift; + } +} + +// This function checks the crc value(s) for an unpacked block, returning the +// number of actual crc errors detected for the block. The block must be +// completely unpacked before this test is valid. For losslessly unpacked +// blocks of float or extended integer data the extended crc is also checked. +// Note that WavPack's crc is not a CCITT approved polynomial algorithm, but +// is a much simpler method that is virtually as robust for real world data. + +int check_crc_error (WavpackContext *wpc) +{ + int result = 0, stream; + + for (stream = 0; stream < wpc->num_streams; stream++) { + WavpackStream *wps = wpc->streams [stream]; + + if (wps->crc != wps->wphdr.crc) + ++result; + else if (bs_is_open (&wps->wvxbits) && wps->crc_x != wps->crc_wvx) + ++result; + } + + return result; +} + +#endif diff --git a/wavpack-4.5.0/src/unpack3.c b/wavpack-4.5.0/src/unpack3.c new file mode 100644 index 0000000..8308e9b --- /dev/null +++ b/wavpack-4.5.0/src/unpack3.c @@ -0,0 +1,2195 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2006 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// unpack3.c + +// This module provides unpacking for 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. + +#include +#include +#include +#include + +#include "wavpack_local.h" +#include "unpack3.h" + +#define ATTEMPT_ERROR_MUTING + +#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 + +static void unpack_init3 (WavpackStream3 *wps); +static int bs_open_read3 (Bitstream3 *bs, WavpackStreamReader *reader, void *id); +static void bs_close_read3 (Bitstream3 *bs); +#ifndef NO_SEEKING +static void bs_restore3 (Bitstream3 *bs); +#endif + +// 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)) { + 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 = 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)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + else { + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (ChunkHeader)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &ChunkHeader, sizeof (ChunkHeader)); + wpc->wrapper_bytes += sizeof (ChunkHeader); + } + + little_endian_to_native (&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)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + else if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + sizeof (wavhdr)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, &wavhdr, sizeof (wavhdr)); + wpc->wrapper_bytes += sizeof (wavhdr); + } + + little_endian_to_native (&wavhdr, WaveHeader3Format); + + if (ChunkHeader.ckSize > sizeof (wavhdr)) { + uint32_t bytes_to_skip = (ChunkHeader.ckSize + 1 - sizeof (wavhdr)) & ~1L; + + if (bytes_to_skip > 1024 * 1024) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = 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 { + uchar *temp = 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) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + if (wpc->open_flags & OPEN_WRAPPER) { + wpc->wrapper_data = 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 { + uchar *temp = malloc (bytes_to_skip); + wpc->reader->read_bytes (wpc->wv_in, temp, bytes_to_skip); + free (temp); + } + } + } + } + } + else { + 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) { + 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) { + 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)) { + 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)) { + strcpy (error, "not a valid WavPack file!"); + return WavpackCloseFile (wpc); + } + + little_endian_to_native (&wphdr, WavpackHeader3Format); + + // make sure this is a version we know about + + if (strncmp (wphdr.ckID, "wvpk", 4) || wphdr.version < 1 || wphdr.version > 3) { + 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)))) { + 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 = 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) + bs_close_read3 (&wps->wvcbits); + + bs_close_read3 (&wps->wvbits); + + free (wps); + } +} + +static void bs_read3 (Bitstream3 *bs) +{ + uint32_t bytes_read; + + bytes_read = bs->reader->read_bytes (bs->id, bs->buf, bs->bufsiz); + bs->end = bs->buf + bytes_read; + bs->fpos += bytes_read; + + if (bs->end == bs->buf) { + memset (bs->buf, -1, bs->bufsiz); + bs->end += bs->bufsiz; + } + + bs->ptr = bs->buf; +} + +// Open the specified BitStream and associate with the specified file. The +// "bufsiz" field of the structure must be preset with the desired buffer +// size and the file's read pointer must be set to where the desired bit +// data is located. A return value of TRUE indicates an error in +// allocating buffer space. + +static int bs_open_read3 (Bitstream3 *bs, WavpackStreamReader *reader, void *id) +{ + bs->fpos = (bs->reader = reader)->get_pos (bs->id = id); + + if (!bs->buf) + bs->buf = (uchar *) malloc (bs->bufsiz); + + bs->end = bs->buf + bs->bufsiz; + bs->ptr = bs->end - 1; + bs->sr = bs->bc = 0; + bs->error = bs->buf ? 0 : 1; + bs->wrap = bs_read3; + return bs->error; +} + +#ifndef NO_SEEKING + +// 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 + +// This function is called to release any resources used by the BitStream +// and position the file pointer to the first byte past the read bits. + +static void bs_close_read3 (Bitstream3 *bs) +{ + if (bs->buf) { + free (bs->buf); + CLEAR (*bs); + } +} + +static uint32_t bs_unused_bytes (Bitstream3 *bs) +{ + if (bs->bc < 8) { + bs->bc += 8; + bs->ptr++; + } + + return (uint32_t)(bs->end - bs->ptr); +} + +static uchar *bs_unused_data (Bitstream3 *bs) +{ + if (bs->bc < 8) { + bs->bc += 8; + bs->ptr++; + } + + return bs->ptr; +} + +#ifndef NO_UNPACK + +//////////////////////////////// local macros ///////////////////////////////// + +#define apply_weight_n(bits, weight, sample) ((weight * sample + (1 << (bits - 1))) >> bits) + +#define update_weight_n(bits, weight, source, result) \ + if (source && result) { \ + if ((source ^ result) >= 0) { if (weight++ == (1 << bits)) weight--; } \ + else if (weight-- == min_weight) weight++; \ + } + +#define apply_weight24(weight, sample) (((((sample & 0xffff) * weight) >> 7) + \ + (((sample & ~0xffff) >> 7) * weight) + 1) >> 1) + +#define update_weight2(weight, source, result) \ + if (source && result) { \ + if ((source ^ result) >= 0) { if (weight++ == 256) weight--; } \ + else if (weight-- == min_weight) weight++; \ + } + +//////////////////////////////// local tables /////////////////////////////// + +// These three tables specify the characteristics of the decorrelation filters. +// Each term represents one layer of the sequential filter, where positive +// values indicate the relative sample involved from the same channel (1=prev) +// while -1 and -2 indicate cross channel decorrelation (in stereo only). The +// "simple_terms" table is no longer used for writing, but is kept for older +// file decoding. + +static const signed char extreme_terms [] = { 1,1,1,2,4,-1,1,2,3,6,-2,8,5,7,4,1,2,3 }; +static const signed char default_terms [] = { 1,1,1,-1,2,1,-2 }; +static const signed char simple_terms [] = { 1,1,1,1 }; + +// This function initializes everything required to unpack WavPack +// bitstreams and must be called before any unpacking is performed. Note +// that the (WavpackHeader3 *) in the WavpackStream3 struct must be valid. + +static void init_words3 (WavpackStream3 *wps); + +static void unpack_init3 (WavpackStream3 *wps) +{ + int flags = wps->wphdr.flags; + struct decorr_pass *dpp; + int ti; + + CLEAR (wps->decorr_passes); + CLEAR (wps->dc); + + if (flags & EXTREME_DECORR) { + for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (extreme_terms); ti++) + if (extreme_terms [sizeof (extreme_terms) - ti - 1] > 0 || (flags & CROSS_DECORR)) + dpp++->term = extreme_terms [sizeof (extreme_terms) - ti - 1]; + } + else if (flags & NEW_DECORR_FLAG) { + for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (default_terms); ti++) + if (default_terms [sizeof (default_terms) - ti - 1] > 0 || (flags & CROSS_DECORR)) + dpp++->term = default_terms [sizeof (default_terms) - ti - 1]; + } + else + for (dpp = wps->decorr_passes, ti = 0; ti < sizeof (simple_terms); ti++) + dpp++->term = simple_terms [sizeof (simple_terms) - ti - 1]; + + wps->num_terms = (int)(dpp - wps->decorr_passes); + init_words3 (wps); +} + +#ifndef NO_SEEKING + +#define SAVE(destin, item) { memcpy (destin, &item, sizeof (item)); destin = (char *) destin + sizeof (item); } +#define RESTORE(item, source) { memcpy (&item, source, sizeof (item)); source = (char *) source + sizeof (item); } + +// This function returns the size (in bytes) required to save the unpacking +// context. Note that the (WavpackHeader3 *) in the WavpackStream3 struct +// must be valid. + +static int unpack_size (WavpackStream3 *wps) +{ + int flags = wps->wphdr.flags, byte_sum = 0, tcount; + struct decorr_pass *dpp; + + byte_sum += sizeof (wps->wvbits); + + if (flags & WVC_FLAG) + byte_sum += sizeof (wps->wvcbits); + + if (wps->wphdr.version == 3) { + if (wps->wphdr.bits) + byte_sum += sizeof (wps->w4); + else + byte_sum += sizeof (wps->w1); + + byte_sum += sizeof (wps->w3) + sizeof (wps->dc.crc); + } + else + byte_sum += sizeof (wps->w2); + + if (wps->wphdr.bits) + byte_sum += sizeof (wps->dc.error); + else + byte_sum += sizeof (wps->dc.sum_level) + sizeof (wps->dc.left_level) + + sizeof (wps->dc.right_level) + sizeof (wps->dc.diff_level); + + if (flags & OVER_20) + byte_sum += sizeof (wps->dc.last_extra_bits) + sizeof (wps->dc.extra_bits_count); + + if (!(flags & EXTREME_DECORR)) { + byte_sum += sizeof (wps->dc.sample); + byte_sum += sizeof (wps->dc.weight); + } + + if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + byte_sum += sizeof (dpp->samples_A [0]) * dpp->term; + byte_sum += sizeof (dpp->weight_A); + + if (!(flags & MONO_FLAG)) { + byte_sum += sizeof (dpp->samples_B [0]) * dpp->term; + byte_sum += sizeof (dpp->weight_B); + } + } + else { + byte_sum += sizeof (dpp->samples_A [0]) + sizeof (dpp->samples_B [0]); + byte_sum += sizeof (dpp->weight_A) + sizeof (dpp->weight_B); + } + + return byte_sum; +} + +// This function saves the unpacking context at the specified pointer and +// returns the updated pointer. The actual amount of data required can be +// determined beforehand by calling unpack_size() but must be allocated by +// the caller. + +static void *unpack_save (WavpackStream3 *wps, void *destin) +{ + int flags = wps->wphdr.flags, tcount; + struct decorr_pass *dpp; + + SAVE (destin, wps->wvbits); + + if (flags & WVC_FLAG) + SAVE (destin, wps->wvcbits); + + if (wps->wphdr.version == 3) { + if (wps->wphdr.bits) { + SAVE (destin, wps->w4); + } + else { + SAVE (destin, wps->w1); + } + + SAVE (destin, wps->w3); + SAVE (destin, wps->dc.crc); + } + else + SAVE (destin, wps->w2); + + if (wps->wphdr.bits) { + SAVE (destin, wps->dc.error); + } + else { + SAVE (destin, wps->dc.sum_level); + SAVE (destin, wps->dc.left_level); + SAVE (destin, wps->dc.right_level); + SAVE (destin, wps->dc.diff_level); + } + + if (flags & OVER_20) { + SAVE (destin, wps->dc.last_extra_bits); + SAVE (destin, wps->dc.extra_bits_count); + } + + if (!(flags & EXTREME_DECORR)) { + SAVE (destin, wps->dc.sample); + SAVE (destin, wps->dc.weight); + } + + 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; + + SAVE (destin, dpp->weight_A); + + while (count--) { + SAVE (destin, dpp->samples_A [index]); + index = (index + 1) & (MAX_TERM - 1); + } + + if (!(flags & MONO_FLAG)) { + count = dpp->term; + index = wps->dc.m; + + SAVE (destin, dpp->weight_B); + + while (count--) { + SAVE (destin, dpp->samples_B [index]); + index = (index + 1) & (MAX_TERM - 1); + } + } + } + else { + SAVE (destin, dpp->weight_A); + SAVE (destin, dpp->weight_B); + SAVE (destin, dpp->samples_A [0]); + SAVE (destin, dpp->samples_B [0]); + } + + return destin; +} + +// 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; + uchar *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 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 / ((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; +} + + +#endif + +// This monster actually unpacks the WavPack bitstream(s) into the specified +// buffer as longs, and serves as an extension to WavpackUnpackSamples(). +// Note that WavPack files created prior to version 4.0 could only contain 16 +// or 24 bit values, and these values are right-justified in the 32-bit values. +// So, if the original file contained 16-bit values, then the range of the +// returned longs would be +/- 32K. For maximum clarity, the function is +// broken up into segments that handle various modes. This makes for a few +// extra infrequent flag checks, but makes the code easier to follow because +// the nesting does not become so deep. For maximum efficiency, the conversion +// is isolated to tight loops that handle an entire buffer. + +static int32_t FASTCALL get_word1 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_old_word1 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_word2 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_word3 (WavpackStream3 *wps, int chan); +static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *correction); + +int32_t unpack_samples3 (WavpackContext *wpc, int32_t *buffer, uint32_t sample_count) +{ + WavpackStream3 *wps = (WavpackStream3 *) wpc->stream3; + int shift = wps->wphdr.shift, flags = wps->wphdr.flags, min_weight = 0, m = wps->dc.m, tcount; +#ifndef NO_SEEKING + int points_index = wps->sample_index / ((wpc->total_samples >> 8) + 1); +#endif + int32_t min_value, max_value, min_shifted, max_shifted; + int32_t correction [2], crc = wps->dc.crc; + struct decorr_pass *dpp; + int32_t read_word, *bptr; + int32_t sample [2] [2]; + int weight [2] [1]; + uint i; + +#ifdef ATTEMPT_ERROR_MUTING + int32_t mute_limit = (flags & BYTES_3) ? 8388608 : 32768; + int mute_block = 0; + + if (wps->wphdr.bits && !(flags & WVC_FLAG)) { + if (wps->wphdr.version < 3) + mute_limit *= 4; + else + mute_limit *= 2; + } +#endif + + if (wps->sample_index + sample_count > wpc->total_samples) + sample_count = wpc->total_samples - wps->sample_index; + + if (!sample_count) + return 0; + + if (!wps->sample_index) { + unpack_init3 (wps); + + bs_open_read3 (&wps->wvbits, wpc->reader, wpc->wv_in); + + if (wpc->wvc_flag) + bs_open_read3 (&wps->wvcbits, wpc->reader, wpc->wvc_in); + } + +#ifndef NO_SEEKING + if (!wps->index_points [points_index].saved) { + + if (!wps->unpack_data) + wps->unpack_data = (uchar *) malloc (256 * (wps->unpack_size = unpack_size (wps))); + + wps->index_points [points_index].sample_index = wps->sample_index; + unpack_save (wps, wps->unpack_data + points_index * wps->unpack_size); + wps->index_points [points_index].saved = TRUE; + } +#endif + + memcpy (sample, wps->dc.sample, sizeof (sample)); + memcpy (weight, wps->dc.weight, sizeof (weight)); + + if (wps->wphdr.bits) { + if (flags & (NEW_DECORR_FLAG | EXTREME_DECORR)) + min_weight = -256; + } + else + if (flags & NEW_DECORR_FLAG) + min_weight = (flags & EXTREME_DECORR) ? -512 : -256; + + if (flags & BYTES_3) { + min_shifted = (min_value = -8388608 >> shift) << shift; + max_shifted = (max_value = 8388607 >> shift) << shift; + } + else { + min_shifted = (min_value = -32768 >> shift) << shift; + max_shifted = (max_value = 32767 >> shift) << shift; + } + + ///////////////// handle version 3 lossless mono data ///////////////////// + + if (wps->wphdr.version == 3 && !wps->wphdr.bits && (flags & MONO_FLAG)) { + if (flags & FAST_FLAG) { + if (flags & OVER_20) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t temp; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + sample [0] [0] += sample [0] [1] += read_word; + getbits (&temp, 4, &wps->wvbits); + crc = crc * 3 + (temp = (temp & 0xf) + (sample [0] [0] << 4)); + *bptr++ = temp; + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); + *bptr++ = sample [0] [0] << shift; + } + } + else if (flags & HIGH_FLAG) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t temp; + + if (flags & NEW_HIGH_FLAG) { + if ((read_word = get_word1 (wps, 0)) == WORD_EOF) + break; + } + else { + if ((read_word = get_old_word1 (wps, 0)) == WORD_EOF) + break; + } + + if (flags & EXTREME_DECORR) + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam = dpp->samples_A [m]; + + temp = apply_weight_n (9, dpp->weight_A, sam) + read_word; + update_weight_n (9, dpp->weight_A, sam, read_word); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; + } + else + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam = dpp->samples_A [m]; + + temp = apply_weight_n (8, dpp->weight_A, sam) + read_word; + update_weight_n (8, dpp->weight_A, sam, read_word); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&temp, 4, &wps->wvbits); + + if ((temp &= 0xf) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = temp; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (temp = wps->dc.last_extra_bits + (read_word << 4)); + *bptr++ = temp; + } + else { + crc = crc * 3 + read_word; + *bptr++ = read_word << shift; + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + int32_t temp; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + temp = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; + + if ((sample [0] [1] >= 0) == (read_word > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + sample [0] [0] += (sample [0] [1] = temp - sample [0] [0]); + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&temp, 4, &wps->wvbits); + + if ((temp &= 0xf) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = temp; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (*bptr++ = temp = wps->dc.last_extra_bits + (sample [0] [0] << 4)); + } + else { + crc = crc * 3 + sample [0] [0]; + *bptr++ = sample [0] [0] << shift; + } + } + } + + //////////////// handle version 3 lossless stereo data //////////////////// + + else if (wps->wphdr.version == 3 && !wps->wphdr.bits && !(flags & MONO_FLAG)) { + int32_t left_level = wps->dc.left_level, right_level = wps->dc.right_level; + int32_t sum_level = wps->dc.sum_level, diff_level = wps->dc.diff_level; + + if (flags & FAST_FLAG) { + if (flags & OVER_20) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, diff, temp; + + read_word = get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + sum = (read_word << 1) | ((diff = get_word3 (wps, 1)) & 1); + sample [0] [0] += sample [0] [1] += ((sum + diff) >> 1); + sample [1] [0] += sample [1] [1] += ((sum - diff) >> 1); + getbits (&temp, 8, &wps->wvbits); + crc = crc * 3 + (*bptr++ = (sample [0] [0] << 4) + ((temp >> 4) & 0xf)); + crc = crc * 3 + (*bptr++ = (sample [1] [0] << 4) + (temp & 0xf)); + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, diff; + + read_word = get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + sum = (read_word << 1) | ((diff = get_word3 (wps, 1)) & 1); + sample [0] [1] += ((sum + diff) >> 1); + sample [1] [1] += ((sum - diff) >> 1); + crc = crc * 3 + (sample [0] [0] += sample [0] [1]); + crc = crc * 3 + (sample [1] [0] += sample [1] [1]); + *bptr++ = sample [0] [0] << shift; + *bptr++ = sample [1] [0] << shift; + } + } + else if (flags & HIGH_FLAG) { + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, left, right, diff, left2, right2, extra_bits, next_word; + + if (flags & CROSS_DECORR) { + left = get_word1 (wps, 0); + + if (left == WORD_EOF) + break; + + right = get_word1 (wps, 1); + } + else { + if (flags & NEW_HIGH_FLAG) { + read_word = get_word1 (wps, 0); + + if (read_word == WORD_EOF) + break; + + next_word = get_word1 (wps, 1); + + if (right_level > left_level) { + if (left_level + right_level < sum_level + diff_level && right_level < diff_level) { + sum = (right = read_word) + (left = next_word); + diff = left - right; + } + else { + diff = read_word; + + if (sum_level < left_level) { + sum = (next_word << 1) | (diff & 1); + left = (sum + diff) >> 1; + right = (sum - diff) >> 1; + } + else + sum = next_word + (right = (left = next_word) - diff); + } + } + else { + if (left_level + right_level < sum_level + diff_level && left_level < diff_level) { + sum = (left = read_word) + (right = next_word); + diff = left - right; + } + else { + diff = read_word; + + if (sum_level < right_level) { + sum = (next_word << 1) | (diff & 1); + left = (sum + diff) >> 1; + right = (sum - diff) >> 1; + } + else + sum = (left = diff + (right = next_word)) + next_word; + } + } + } + else { + read_word = get_old_word1 (wps, 0); + + if (read_word == WORD_EOF) + break; + + next_word = get_old_word1 (wps, 1); + + if (sum_level <= right_level && sum_level <= left_level) { + sum = (next_word << 1) | (read_word & 1); + left = (sum + read_word) >> 1; + right = (sum - read_word) >> 1; + } + else if (left_level <= right_level) + sum = next_word + (right = (left = next_word) - read_word); + else + sum = next_word + (left = read_word + (right = next_word)); + + diff = left - right; + } + + sum_level = sum_level - (sum_level >> 8) + labs (sum >> 1); + left_level = left_level - (left_level >> 8) + labs (left); + right_level = right_level - (right_level >> 8) + labs (right); + diff_level = diff_level - (diff_level >> 8) + labs (diff); + + if (flags & JOINT_STEREO) { + left = diff; + right = sum >> 1; + } + } + + if (flags & EXTREME_DECORR) { + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; + int k = (m + dpp->term) & (MAX_TERM - 1); + + left2 = apply_weight_n (9, dpp->weight_A, sam_A) + left; + right2 = apply_weight_n (9, dpp->weight_B, sam_B) + right; + + update_weight_n (9, dpp->weight_A, sam_A, left); + update_weight_n (9, dpp->weight_B, sam_B, right); + + dpp->samples_A [k] = left = left2; + dpp->samples_B [k] = right = right2; + } + else if (dpp->term == -1) { + left2 = left + apply_weight_n (9, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (9, dpp->weight_A, dpp->samples_A [0], left); + left = left2; + right2 = right + apply_weight_n (9, dpp->weight_B, left); + update_weight_n (9, dpp->weight_B, left, right); + dpp->samples_A [0] = right = right2; + } + else { + right2 = right + apply_weight_n (9, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (9, dpp->weight_A, dpp->samples_A [0], right); + right = right2; + left2 = left + apply_weight_n (9, dpp->weight_B, right); + update_weight_n (9, dpp->weight_B, right, left); + dpp->samples_A [0] = left = left2; + } + } + else { + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) + if (dpp->term > 0) { + int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; + int k = (m + dpp->term) & (MAX_TERM - 1); + + left2 = apply_weight_n (8, dpp->weight_A, sam_A) + left; + right2 = apply_weight_n (8, dpp->weight_B, sam_B) + right; + + update_weight_n (8, dpp->weight_A, sam_A, left); + update_weight_n (8, dpp->weight_B, sam_B, right); + + dpp->samples_A [k] = left = left2; + dpp->samples_B [k] = right = right2; + } + else if (dpp->term == -1) { + left2 = left + apply_weight_n (8, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (8, dpp->weight_A, dpp->samples_A [0], left); + left = left2; + right2 = right + apply_weight_n (8, dpp->weight_B, left); + update_weight_n (8, dpp->weight_B, left, right); + dpp->samples_A [0] = right = right2; + } + else { + right2 = right + apply_weight_n (8, dpp->weight_A, dpp->samples_A [0]); + update_weight_n (8, dpp->weight_A, dpp->samples_A [0], right); + right = right2; + left2 = left + apply_weight_n (8, dpp->weight_B, right); + update_weight_n (8, dpp->weight_B, right, left); + dpp->samples_A [0] = left = left2; + } + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & JOINT_STEREO) { + sum = (right << 1) | ((diff = left) & 1); + right = (sum - diff) >> 1; + left = (sum + diff) >> 1; + } + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&extra_bits, 8, &wps->wvbits); + + if ((extra_bits &= 0xff) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = extra_bits; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (*bptr++ = left = (left << 4) + (wps->dc.last_extra_bits >> 4)); + crc = crc * 3 + (*bptr++ = right = (right << 4) + (wps->dc.last_extra_bits & 0xf)); + } + else { + crc = crc * 9 + left * 3 + right; + *bptr++ = left << shift; + *bptr++ = right << shift; + } + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, left, right, left2, right2, extra_bits; + + read_word = get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + if (sum_level <= right_level && sum_level <= left_level) { + sum = (get_word3 (wps, 1) << 1) | (read_word & 1); + left = (sum + read_word) >> 1; + right = (sum - read_word) >> 1; + } + else if (left_level <= right_level) { + right = (left = get_word3 (wps, 1)) - read_word; + sum = left + right; + } + else { + left = read_word + (right = get_word3 (wps, 1)); + sum = right + left; + } + + sum_level = sum_level - (sum_level >> 8) + labs (sum >> 1); + left_level = left_level - (left_level >> 8) + labs (left); + right_level = right_level - (right_level >> 8) + labs (right); + + left2 = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + left; + right2 = sample [1] [0] + ((sample [1] [1] * weight [1] [0] + 128) >> 8) + right; + + if ((sample [0] [1] >= 0) == (left > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + if ((sample [1] [1] >= 0) == (right > 0)) { + if (weight [1] [0]++ == 256) + weight [1] [0]--; + } + else if (weight [1] [0]-- == 0) + weight [1] [0]++; + + sample [0] [0] += (sample [0] [1] = left2 - sample [0] [0]); + sample [1] [0] += (sample [1] [1] = right2 - sample [1] [0]); + + if (flags & OVER_20) { + if (wps->dc.extra_bits_count < 8 || !getbit (&wps->wvbits)) { + getbits (&extra_bits, 8, &wps->wvbits); + + if ((extra_bits &= 0xff) != wps->dc.last_extra_bits) { + wps->dc.last_extra_bits = extra_bits; + wps->dc.extra_bits_count = 0; + } + else + ++wps->dc.extra_bits_count; + } + + crc = crc * 3 + (*bptr++ = left2 = (sample [0] [0] << 4) + (wps->dc.last_extra_bits >> 4)); + crc = crc * 3 + (*bptr++ = right2 = (sample [1] [0] << 4) + (wps->dc.last_extra_bits & 0xf)); + } + else { + crc = crc * 9 + sample [0] [0] * 3 + sample [1] [0]; + *bptr++ = sample [0] [0] << shift; + *bptr++ = sample [1] [0] << shift; + } + } + + wps->dc.left_level = left_level; + wps->dc.right_level = right_level; + wps->dc.sum_level = sum_level; + wps->dc.diff_level = diff_level; + } + + //////////////// handle version 3 lossy/hybrid mono data ////////////////// + + else if (wps->wphdr.version == 3 && wps->wphdr.bits && (flags & MONO_FLAG)) { + if (flags & FAST_FLAG) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); + + if (sample [0] [0] < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] < -mute_limit) + mute_block = 1; +#endif + *bptr++ = min_shifted; + } + else if (sample [0] [0] > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] > mute_limit) + mute_block = 1; +#endif + *bptr++ = max_shifted; + } + else + *bptr++ = sample [0] [0] << shift; + } + else if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t temp; + + read_word = (flags & NEW_HIGH_FLAG) ? + get_word4 (wps, 0, correction) : get_word3 (wps, 0); + + if (read_word == WORD_EOF) + break; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam = dpp->samples_A [m]; + + temp = apply_weight24 (dpp->weight_A, sam) + read_word; + update_weight2 (dpp->weight_A, sam, read_word); + dpp->samples_A [(m + dpp->term) & (MAX_TERM - 1)] = read_word = temp; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & WVC_FLAG) { + if (flags & LOSSY_SHAPE) { + crc = crc * 3 + (read_word += correction [0] + wps->dc.error [0]); + wps->dc.error [0] = -correction [0]; + } + else + crc = crc * 3 + (read_word += correction [0]); + + *bptr++ = read_word << shift; + } + else { + crc = crc * 3 + read_word; + + if (read_word < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (read_word < -mute_limit) + mute_block = 1; +#endif + *bptr++ = min_shifted; + } + else if (read_word > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (read_word > mute_limit) + mute_block = 1; +#endif + *bptr++ = max_shifted; + } + else + *bptr++ = read_word << shift; + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t new_sample; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + new_sample = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; + + if ((sample [0] [1] >= 0) == (read_word > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + sample [0] [1] = new_sample - sample [0] [0]; + crc = crc * 3 + (sample [0] [0] = new_sample); + + if (sample [0] [0] < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] < -mute_limit) + mute_block = 1; +#endif + *bptr++ = min_shifted; + } + else if (sample [0] [0] > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] > mute_limit) + mute_block = 1; +#endif + *bptr++ = max_shifted; + } + else + *bptr++ = sample [0] [0] << shift; + } + } + + //////////////// handle version 3 lossy/hybrid stereo data //////////////// + + else if (wps->wphdr.version == 3 && wps->wphdr.bits && !(flags & MONO_FLAG)) { + if (flags & FAST_FLAG) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + crc = crc * 3 + (sample [0] [0] += sample [0] [1] += read_word); + + if (sample [0] [0] < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] < -mute_limit) + mute_block = 1; +#endif + *bptr++ = min_shifted; + } + else if (sample [0] [0] > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] > mute_limit) + mute_block = 1; +#endif + *bptr++ = max_shifted; + } + else + *bptr++ = sample [0] [0] << shift; + + crc = crc * 3 + (sample [1] [0] += sample [1] [1] += get_word3 (wps, 1)); + + if (sample [1] [0] < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [1] [0] < -mute_limit) + mute_block = 1; +#endif + *bptr++ = min_shifted; + } + else if (sample [1] [0] > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [1] [0] > mute_limit) + mute_block = 1; +#endif + *bptr++ = max_shifted; + } + else + *bptr++ = sample [1] [0] << shift; + } + else if (flags & (HIGH_FLAG | NEW_HIGH_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t left, right, left2, right2, sum, diff; + + if (flags & NEW_HIGH_FLAG) { + left = get_word4 (wps, 0, correction); + right = get_word4 (wps, 1, correction + 1); + } + else { + left = get_word3 (wps, 0); + right = get_word3 (wps, 1); + } + + if (left == WORD_EOF) + break; + + for (tcount = wps->num_terms, dpp = wps->decorr_passes; tcount--; dpp++) { + int32_t sam_A = dpp->samples_A [m], sam_B = dpp->samples_B [m]; + int k = (m + dpp->term) & (MAX_TERM - 1); + + left2 = apply_weight24 (dpp->weight_A, sam_A) + left; + update_weight2 (dpp->weight_A, sam_A, left); + dpp->samples_A [k] = left = left2; + + right2 = apply_weight24 (dpp->weight_B, sam_B) + right; + update_weight2 (dpp->weight_B, sam_B, right); + dpp->samples_B [k] = right = right2; + } + + m = (m + 1) & (MAX_TERM - 1); + + if (flags & WVC_FLAG) { + if (flags & LOSSY_SHAPE) { + left += correction [0] + wps->dc.error [0]; + right += correction [1] + wps->dc.error [1]; + wps->dc.error [0] = -correction [0]; + wps->dc.error [1] = -correction [1]; + } + else { + left += correction [0]; + right += correction [1]; + } + } + + if (flags & JOINT_STEREO) { + right = ((sum = (right << 1) | (left & 1)) - (diff = left)) >> 1; + left = (sum + diff) >> 1; + } + + crc = crc * 9 + left * 3 + right; + + if (flags & WVC_FLAG) { + *bptr++ = left << shift; + *bptr++ = right << shift; + } + else { + if (left < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (left < -mute_limit) + mute_block = 1; +#endif + *bptr++ = min_shifted; + } + else if (left > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (left > mute_limit) + mute_block = 1; +#endif + *bptr++ = max_shifted; + } + else + *bptr++ = left << shift; + + if (right < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (right < -mute_limit) + mute_block = 1; +#endif + *bptr++ = min_shifted; + } + else if (right > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (right > mute_limit) + mute_block = 1; +#endif + *bptr++ = max_shifted; + } + else + *bptr++ = right << shift; + } + } + else + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t new_sample; + + if ((read_word = get_word3 (wps, 0)) == WORD_EOF) + break; + + new_sample = sample [0] [0] + ((sample [0] [1] * weight [0] [0] + 128) >> 8) + read_word; + + if ((sample [0] [1] >= 0) == (read_word > 0)) { + if (weight [0] [0]++ == 256) + weight [0] [0]--; + } + else if (weight [0] [0]-- == 0) + weight [0] [0]++; + + sample [0] [1] = new_sample - sample [0] [0]; + crc = crc * 3 + (sample [0] [0] = new_sample); + + read_word = get_word3 (wps, 1); + new_sample = sample [1] [0] + ((sample [1] [1] * weight [1] [0] + 128) >> 8) + read_word; + + if ((sample [1] [1] >= 0) == (read_word > 0)) { + if (weight [1] [0]++ == 256) + weight [1] [0]--; + } + else if (weight [1] [0]-- == 0) + weight [1] [0]++; + + sample [1] [1] = new_sample - sample [1] [0]; + crc = crc * 3 + (sample [1] [0] = new_sample); + + if (sample [0] [0] < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] < -mute_limit) + mute_block = 1; +#endif + *bptr++ = min_shifted; + } + else if (sample [0] [0] > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] > mute_limit) + mute_block = 1; +#endif + *bptr++ = max_shifted; + } + else + *bptr++ = sample [0] [0] << shift; + + if (sample [1] [0] < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [1] [0] < -mute_limit) + mute_block = 1; +#endif + *bptr++ = min_shifted; + } + else if (sample [1] [0] > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [1] [0] > mute_limit) + mute_block = 1; +#endif + *bptr++ = max_shifted; + } + else + *bptr++ = sample [1] [0] << shift; + } + } + + //////////////////// finally, handle version 2 data /////////////////////// + + else if (wps->wphdr.version == 2 && (flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + if ((read_word = get_word2 (wps, 0)) == WORD_EOF) + break; + + sample [0] [0] += sample [0] [1] += read_word; + + if (wps->wphdr.bits) { + if (sample [0] [0] < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] < -mute_limit) + mute_block = 1; +#endif + sample [0] [0] = min_value; + } + else if (sample [0] [0] > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] > mute_limit) + mute_block = 1; +#endif + sample [0] [0] = max_value; + } + } + + *bptr++ = sample [0] [0] << shift; + } + else if (wps->wphdr.version < 3 && !(flags & MONO_FLAG)) + for (bptr = buffer, i = 0; i < sample_count; ++i) { + int32_t sum, diff; + + read_word = get_word2 (wps, 0); + + if (read_word == WORD_EOF) + break; + + sum = (read_word << 1) | ((diff = get_word2 (wps, 1)) & 1); + sample [0] [0] += sample [0] [1] += ((sum + diff) >> 1); + sample [1] [0] += sample [1] [1] += ((sum - diff) >> 1); + + if (wps->wphdr.bits) { + if (sample [0] [0] < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] < -mute_limit) + mute_block = 1; +#endif + sample [0] [0] = min_value; + } + else if (sample [0] [0] > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [0] [0] > mute_limit) + mute_block = 1; +#endif + sample [0] [0] = max_value; + } + + if (sample [1] [0] < min_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [1] [0] < -mute_limit) + mute_block = 1; +#endif + sample [1] [0] = min_value; + } + else if (sample [1] [0] > max_value) { +#ifdef ATTEMPT_ERROR_MUTING + if (sample [1] [0] > mute_limit) + mute_block = 1; +#endif + sample [1] [0] = max_value; + } + } + + *bptr++ = sample [0] [0] << shift; + *bptr++ = sample [1] [0] << shift; + } + else + i = 0; /* can't get here, but suppresses warning */ + +#ifdef ATTEMPT_ERROR_MUTING + if (!wps->wphdr.bits || (flags & WVC_FLAG)) { + int32_t *eptr = buffer + sample_count * ((flags & MONO_FLAG) ? 1 : 2); + + for (bptr = buffer; bptr < eptr; bptr += 3) + if (*bptr > mute_limit || *bptr < -mute_limit) { + mute_block = 1; + break; + } + } + + if (mute_block) + memset (buffer, 0, sizeof (*buffer) * sample_count * ((flags & MONO_FLAG) ? 1 : 2)); +#endif + + if (i && (wps->sample_index += i) == wpc->total_samples) { + + if (wps->wphdr.version == 3 && crc != (wpc->wvc_flag ? wps->wphdr.crc2 : wps->wphdr.crc)) + wpc->crc_errors++; + + if (wpc->open_flags & OPEN_WRAPPER) { + uchar *temp = malloc (1024); + uint32_t bcount; + + if (bs_unused_bytes (&wps->wvbits)) { + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bs_unused_bytes (&wps->wvbits)); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, bs_unused_data (&wps->wvbits), bs_unused_bytes (&wps->wvbits)); + wpc->wrapper_bytes += bs_unused_bytes (&wps->wvbits); + } + + while (1) { + bcount = wpc->reader->read_bytes (wpc->wv_in, temp, sizeof (temp)); + + if (!bcount) + break; + + wpc->wrapper_data = realloc (wpc->wrapper_data, wpc->wrapper_bytes + bcount); + memcpy (wpc->wrapper_data + wpc->wrapper_bytes, temp, bcount); + wpc->wrapper_bytes += bcount; + } + + free (temp); + + if (wpc->wrapper_bytes > 16) { + int c; + + for (c = 0; c < 16 && wpc->wrapper_data [c] == 0xff; ++c); + + if (c == 16) { + memcpy (wpc->wrapper_data, wpc->wrapper_data + 16, wpc->wrapper_bytes - 16); + wpc->wrapper_bytes -= 16; + } + else { + free (wpc->wrapper_data); + wpc->wrapper_data = NULL; + wpc->wrapper_bytes = 0; + } + } + } + } + + memcpy (wps->dc.sample, sample, sizeof (sample)); + memcpy (wps->dc.weight, weight, sizeof (weight)); + wps->dc.crc = crc; + wps->dc.m = m; + + return i; +} + +///////////////////////////// local table storage //////////////////////////// + +extern const uint32_t bitset []; +extern const uint32_t bitmask []; +extern const char nbits_table []; + +// This function initializes everything required to receive words with this +// module and must be called BEFORE any other function in this module. + +static void init_words3 (WavpackStream3 *wps) +{ + CLEAR (wps->w1); + CLEAR (wps->w2); + CLEAR (wps->w3); + CLEAR (wps->w4); + + if (wps->wphdr.flags & MONO_FLAG) + wps->w4.bitrate = wps->wphdr.bits - 768; + else + wps->w4.bitrate = (wps->wphdr.bits / 2) - 768; +} + +// This macro counts the number of bits that are required to specify the +// unsigned 32-bit value, counting from the LSB to the most significant bit +// that is set. Return range is 0 - 32. + +#define count_bits(av) ( \ + (av) < (1 << 8) ? nbits_table [av] : \ + ( \ + (av) < (1L << 16) ? nbits_table [(av) >> 8] + 8 : \ + ((av) < (1L << 24) ? nbits_table [(av) >> 16] + 16 : nbits_table [(av) >> 24] + 24) \ + ) \ +) + +static int32_t FASTCALL get_word1 (WavpackStream3 *wps, int chan) +{ + uint32_t tmp1, tmp2, avalue; + uint ones_count; + int k; + + if ((wps->wphdr.flags & EXTREME_DECORR) && !(wps->wphdr.flags & OVER_20)) { + if (wps->w1.zeros_acc) { + if (--wps->w1.zeros_acc) + return 0; + } + else if (wps->w1.ave_level [0] [0] < 0x20 && wps->w1.ave_level [0] [1] < 0x20) { + int32_t mask; + int cbits; + + for (cbits = 0; cbits < 33 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 33) + return WORD_EOF; + + if (cbits < 2) + wps->w1.zeros_acc = cbits; + else { + for (mask = 1, wps->w1.zeros_acc = 0; --cbits; mask <<= 1) + if (getbit (&wps->wvbits)) + wps->w1.zeros_acc |= mask; + + wps->w1.zeros_acc |= mask; + } + + if (wps->w1.zeros_acc) + return 0; + } + } + + // count consecutive ones in bitstream, > 25 indicates error (or EOF) + + for (ones_count = 0; ones_count < 25 && getbit (&wps->wvbits); ++ones_count); + + if (ones_count == 25) + return WORD_EOF; + + k = (wps->w1.ave_level [0] [chan] + (wps->w1.ave_level [0] [chan] >> 3) + 0x40) >> 7; + k = count_bits (k); + + if (k & ~31) + return WORD_EOF; + + if (ones_count == 0) { + getbits (&avalue, k, &wps->wvbits); + avalue &= bitmask [k]; + } + else { + tmp1 = bitset [k]; + k = (wps->w1.ave_level [1] [chan] + (wps->w1.ave_level [1] [chan] >> 4) + 0x20) >> 6; + k = count_bits (k); + + if (k & ~31) + return WORD_EOF; + + if (ones_count == 1) { + getbits (&avalue, k, &wps->wvbits); + avalue &= bitmask [k]; + } + else { + tmp2 = bitset [k]; + + // If the ones count is exactly 24, then next 24 bits are literal + + if (ones_count == 24) { + getbits (&avalue, 24, &wps->wvbits); + avalue &= 0xffffff; + } + else { + k = (wps->w1.ave_level [2] [chan] + 0x10) >> 5; + k = count_bits (k); + + if (k & ~31) + return WORD_EOF; + + getbits (&avalue, k, &wps->wvbits); + avalue = (avalue & bitmask [k]) + (bitset [k] * (ones_count - 2)); + } + + wps->w1.ave_level [2] [chan] -= ((wps->w1.ave_level [2] [chan] + 0x8) >> 4); + wps->w1.ave_level [2] [chan] += avalue; + avalue += tmp2; + } + + wps->w1.ave_level [1] [chan] -= ((wps->w1.ave_level [1] [chan] + 0x10) >> 5); + wps->w1.ave_level [1] [chan] += avalue; + avalue += tmp1; + } + + wps->w1.ave_level [0] [chan] -= ((wps->w1.ave_level [0] [chan] + 0x20) >> 6); + wps->w1.ave_level [0] [chan] += avalue; + + return (avalue && getbit (&wps->wvbits)) ? -(int32_t)avalue : avalue; +} + +#define NUM_SAMPLES 128 + +static int32_t FASTCALL get_old_word1 (WavpackStream3 *wps, int chan) +{ + uint32_t avalue; + uint bc; + int k; + + if (!wps->w1.index [chan]) { + + int guess_k = (wps->w1.ave_k [chan] + 128) >> 8, ones; + + for (ones = 0; ones < 72 && getbit (&wps->wvbits); ++ones); + + if (ones == 72) + return WORD_EOF; + + if (ones % 3 == 1) + wps->w1.k_value [chan] = guess_k - (ones / 3) - 1; + else + wps->w1.k_value [chan] = guess_k + ones - ((ones + 1) / 3); + + wps->w1.ave_k [chan] -= (wps->w1.ave_k [chan] + 0x10) >> 5; + wps->w1.ave_k [chan] += wps->w1.k_value [chan] << 3; + } + + if (++wps->w1.index [chan] == NUM_SAMPLES) + wps->w1.index [chan] = 0; + + k = wps->w1.k_value [chan]; + getbits (&avalue, k, &wps->wvbits); + + for (bc = 0; bc < 32 && getbit (&wps->wvbits); ++bc); + + if (bc == 32 || (k & ~31)) + return WORD_EOF; + + avalue = (avalue & bitmask [k]) + bitset [k] * bc; + return (avalue && getbit (&wps->wvbits)) ? -(int32_t)avalue : avalue; +} + +static int32_t FASTCALL get_word2 (WavpackStream3 *wps, int chan) +{ + int cbits, delta_dbits, dbits; + int32_t value, mask = 1; + + cbits = 0; + + while (getbit (&wps->wvbits)) + if ((cbits += 2) == 50) + return WORD_EOF; + + if (getbit (&wps->wvbits)) + cbits++; + + if (cbits == 0) + delta_dbits = 0; + else if (cbits & 1) { + delta_dbits = (cbits + 1) / 2; + + if (wps->w2.last_delta_sign [chan] > 0) + delta_dbits *= -1; + + wps->w2.last_delta_sign [chan] = delta_dbits; + } + else { + delta_dbits = cbits / 2; + + if (wps->w2.last_delta_sign [chan] <= 0) + delta_dbits *= -1; + } + + dbits = (wps->w2.last_dbits [chan] += delta_dbits); + + if (dbits < 0 || dbits > 20) + return WORD_EOF; + + if (!dbits) + return 0L; + + if (wps->wphdr.bits) { + for (value = 1L << (dbits - 1); --dbits; mask <<= 1) + if (dbits < wps->wphdr.bits && getbit (&wps->wvbits)) + value |= mask; + } + else + for (value = 1L << (dbits - 1); --dbits; mask <<= 1) + if (getbit (&wps->wvbits)) + value |= mask; + + return getbit (&wps->wvbits) ? -(int32_t)value : value; +} + +static int32_t FASTCALL get_word3 (WavpackStream3 *wps, int chan) +{ + int cbits, delta_dbits, dbits; + int32_t value; + + for (cbits = 0; cbits < 72 && getbit (&wps->wvbits); ++cbits); + + if (cbits == 72) + return WORD_EOF; + + if (cbits || getbit (&wps->wvbits)) + ++cbits; + + if (!((cbits + 1) % 3)) + delta_dbits = (cbits + 1) / 3; + else + delta_dbits = -(cbits - cbits / 3); + + if (chan) { + dbits = (wps->w3.ave_dbits [1] >> 8) + 1 + delta_dbits; + wps->w3.ave_dbits [1] -= (wps->w3.ave_dbits [1] + 0x10) >> 5; + wps->w3.ave_dbits [1] += dbits << 3; + } + else { + dbits = (wps->w3.ave_dbits [0] >> 8) + 1 + delta_dbits; + wps->w3.ave_dbits [0] -= (wps->w3.ave_dbits [0] + 0x10) >> 5; + wps->w3.ave_dbits [0] += dbits << 3; + } + + if (dbits < 0 || dbits > 24) + return WORD_EOF; + + if (!dbits) + return 0L; + + if (wps->wphdr.bits && dbits > wps->wphdr.bits) { + getbits (&value, wps->wphdr.bits, &wps->wvbits); + + if (value & bitset [wps->wphdr.bits - 1]) + return -(int32_t)(value & bitmask [wps->wphdr.bits]) << (dbits - wps->wphdr.bits); + else + return ((value & bitmask [wps->wphdr.bits - 1]) | bitset [wps->wphdr.bits - 1]) << (dbits - wps->wphdr.bits); + } + else { + getbits (&value, dbits, &wps->wvbits); + + if (value & bitset [dbits - 1]) + return -(int32_t)(value & bitmask [dbits]); + else + return (value & bitmask [dbits - 1]) | bitset [dbits - 1]; + } +} + +static int FASTCALL _log2 (uint32_t avalue); + +static int32_t FASTCALL get_word4 (WavpackStream3 *wps, int chan, int32_t *correction) +{ + uint32_t base, ones_count, avalue; + int32_t value, low, mid, high; + int bitcount; + + // count consecutive ones in bitstream, > 25 indicates error (or EOF) + + for (ones_count = 0; ones_count < 25 && getbit (&wps->wvbits); ++ones_count); + + if (ones_count == 25) + return WORD_EOF; + + // if the ones count is exactly 24, then we switch to non-unary method + + if (ones_count == 24) { + int32_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 += 24; + } + + if (!chan) { + int slow_log_0, slow_log_1, balance; + + if (wps->wphdr.flags & MONO_FLAG) { + wps->w4.bits_acc [0] += wps->w4.bitrate + _log2 (wps->w4.fast_level [0]) - _log2 (wps->w4.slow_level [0]) + (3 << 8); + + if (wps->w4.bits_acc [0] < 0) + wps->w4.bits_acc [0] = 0; + } + else { + slow_log_0 = _log2 (wps->w4.slow_level [0]); + slow_log_1 = _log2 (wps->w4.slow_level [1]); + + if (wps->wphdr.flags & JOINT_STEREO) + balance = (slow_log_1 - slow_log_0 + 257) >> 1; + else + balance = (slow_log_1 - slow_log_0 + 1) >> 1; + + wps->w4.bits_acc [0] += wps->w4.bitrate - balance + _log2 (wps->w4.fast_level [0]) - slow_log_0 + (3 << 8); + wps->w4.bits_acc [1] += wps->w4.bitrate + balance + _log2 (wps->w4.fast_level [1]) - slow_log_1 + (3 << 8); + + if (wps->w4.bits_acc [0] + wps->w4.bits_acc [1] < 0) + wps->w4.bits_acc [0] = wps->w4.bits_acc [1] = 0; + else if (wps->w4.bits_acc [0] < 0) { + wps->w4.bits_acc [1] += wps->w4.bits_acc [0]; + wps->w4.bits_acc [0] = 0; + } + else if (wps->w4.bits_acc [1] < 0) { + wps->w4.bits_acc [0] += wps->w4.bits_acc [1]; + wps->w4.bits_acc [1] = 0; + } + } + } + + base = (wps->w4.fast_level [chan] + 48) / 96; + bitcount = wps->w4.bits_acc [chan] >> 8; + wps->w4.bits_acc [chan] &= 0xff; + + if (!base) { + if (ones_count) + high = low = mid = (getbit (&wps->wvbits)) ? -(int32_t)ones_count : ones_count; + else + high = low = mid = 0; + } + else { + mid = (ones_count * 2 + 1) * base; + if (getbit (&wps->wvbits)) mid = -mid; + low = mid - base; + high = mid + base - 1; + + while (bitcount--) { + if (getbit (&wps->wvbits)) + mid = (high + (low = mid) + 1) >> 1; + else + mid = ((high = mid - 1) + low + 1) >> 1; + + if (high == low) + break; + } + } + + wps->w4.fast_level [chan] -= ((wps->w4.fast_level [chan] + 0x10) >> 5); + wps->w4.fast_level [chan] += (avalue = labs (mid)); + wps->w4.slow_level [chan] -= ((wps->w4.slow_level [chan] + 0x80) >> 8); + wps->w4.slow_level [chan] += avalue; + + if (bs_is_open (&wps->wvcbits)) { + + if (high != low) { + uint32_t maxcode = high - low; + int bitcount = count_bits (maxcode); + uint32_t extras = (1L << bitcount) - maxcode - 1; + + getbits (&avalue, bitcount - 1, &wps->wvcbits); + avalue &= bitmask [bitcount - 1]; + + if (avalue >= extras) { + avalue = (avalue << 1) - extras; + + if (getbit (&wps->wvcbits)) + ++avalue; + } + + value = (mid < 0) ? high - avalue : avalue + low; + + if (correction) + *correction = value - mid; + } + else if (correction) + *correction = 0; + } + + return mid; +} + +// This function calculates an approximate base-2 logarithm (with 8 bits of +// fraction) from the supplied value. Using logarithms makes comparing +// signal level values and calculating fractional bitrates much easier. + +static int FASTCALL _log2 (uint32_t avalue) +{ + int dbits; + + if ((avalue += avalue >> 9) < (1 << 8)) { + dbits = nbits_table [avalue]; + return (dbits << 8) + ((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) + ((avalue >> (dbits - 9)) & 0xff); + } +} + +#endif + diff --git a/wavpack-4.5.0/src/unpack3.h b/wavpack-4.5.0/src/unpack3.h new file mode 100644 index 0000000..4461e0c --- /dev/null +++ b/wavpack-4.5.0/src/unpack3.h @@ -0,0 +1,113 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2006 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wavpack3.h + +// This header file contains all the additional definitions required for +// decoding old (versions 1, 2 & 3) WavPack files. + +typedef struct { + ushort FormatTag, NumChannels; + uint32_t SampleRate, BytesPerSecond; + ushort BlockAlign, BitsPerSample; +} WaveHeader3; + +#define WaveHeader3Format "SSLLSS" + +typedef struct { + char ckID [4]; + int32_t ckSize; + short version; + short bits; // added for version 2.00 + short flags, shift; // added for version 3.00 + int32_t total_samples, crc, crc2; + char extension [4], extra_bc, extras [3]; +} WavpackHeader3; + +#define WavpackHeader3Format "4LSSSSLLL4L" + +// these flags added for version 3 + +#undef MONO_FLAG // these definitions changed for WavPack 4.0 +#undef CROSS_DECORR +#undef JOINT_STEREO + +#define MONO_FLAG 1 // not stereo +#define FAST_FLAG 2 // non-adaptive predictor and stereo mode +#define RAW_FLAG 4 // raw mode (no .wav header) +#define CALC_NOISE 8 // calc noise in lossy mode (no longer stored) +#define HIGH_FLAG 0x10 // high quality mode (all modes) +#define BYTES_3 0x20 // files have 3-byte samples +#define OVER_20 0x40 // samples are over 20 bits +#define WVC_FLAG 0x80 // create/use .wvc (no longer stored) +#define LOSSY_SHAPE 0x100 // noise shape (lossy mode only) +#define VERY_FAST_FLAG 0x200 // double fast (no longer stored) +#define NEW_HIGH_FLAG 0x400 // new high quality mode (lossless only) +#define CANCEL_EXTREME 0x800 // cancel EXTREME_DECORR +#define CROSS_DECORR 0x1000 // decorrelate chans (with EXTREME_DECORR flag) +#define NEW_DECORR_FLAG 0x2000 // new high-mode decorrelator +#define JOINT_STEREO 0x4000 // joint stereo (lossy and high lossless) +#define EXTREME_DECORR 0x8000 // extra decorrelation (+ enables other flags) + +#define STORED_FLAGS 0xfd77 // these are only flags that affect unpacking +#define NOT_STORED_FLAGS (~STORED_FLAGS & 0xffff) + +// BitStream stuff (bits.c) + +typedef struct bs3 { + void (*wrap)(struct bs3 *bs); + uchar *buf, *end, *ptr; + uint32_t bufsiz, fpos, sr; + WavpackStreamReader *reader; + int error, bc; + void *id; +} Bitstream3; + +#define K_DEPTH 3 +#define MAX_NTERMS3 18 + +typedef struct { + WavpackHeader3 wphdr; + Bitstream3 wvbits, wvcbits; + uint32_t sample_index; + int num_terms; + +#ifndef NO_SEEKING + struct index_point { + char saved; + uint32_t sample_index; + } index_points [256]; + + uchar *unpack_data; + uint32_t unpack_size; +#endif + + struct { + int32_t sum_level, left_level, right_level, diff_level; + int last_extra_bits, extra_bits_count, m; + int32_t error [2], crc; + int32_t sample [2] [2]; + int weight [2] [1]; + } dc; + + struct decorr_pass decorr_passes [MAX_NTERMS3]; + + struct { + uint index [2], k_value [2], ave_k [2]; + uint32_t zeros_acc, ave_level [K_DEPTH] [2]; + } w1; + + struct { int last_dbits [2], last_delta_sign [2], bit_limit; } w2; + + struct { int ave_dbits [2], bit_limit; } w3; + + struct { + uint32_t fast_level [2], slow_level [2]; + int bits_acc [2], bitrate; + } w4; +} WavpackStream3; diff --git a/wavpack-4.4.1/src/wavpack_local.h b/wavpack-4.5.0/src/wavpack_local.h similarity index 94% rename from wavpack-4.4.1/src/wavpack_local.h rename to wavpack-4.5.0/src/wavpack_local.h index 5e73024..4f8899c 100644 --- a/wavpack-4.4.1/src/wavpack_local.h +++ b/wavpack-4.5.0/src/wavpack_local.h @@ -176,7 +176,7 @@ typedef struct { #define MIN_STREAM_VERS 0x402 // lowest stream version we'll decode #define MAX_STREAM_VERS 0x410 // highest stream version we'll decode or encode -#define CUR_STREAM_VERS 0x406 // stream version we are [normally] writing now +#define CUR_STREAM_VERS 0x407 // stream version we are [normally] writing now //////////////////////////// WavPack Metadata ///////////////////////////////// @@ -248,6 +248,7 @@ typedef struct { #define CONFIG_AUTO_SHAPING 0x4000 // automatic noise shaping #define CONFIG_SHAPE_OVERRIDE 0x8000 // shaping mode specified #define CONFIG_JOINT_OVERRIDE 0x10000 // joint-stereo mode specified +#define CONFIG_DYNAMIC_SHAPING 0x20000 // dynamic noise shaping #define CONFIG_CREATE_EXE 0x40000 // create executable #define CONFIG_CREATE_WVC 0x80000 // create correction file #define CONFIG_OPTIMIZE_WVC 0x100000 // maximize bybrid compression @@ -256,12 +257,17 @@ typedef struct { #define CONFIG_EXTRA_MODE 0x2000000 // extra processing mode #define CONFIG_SKIP_WVX 0x4000000 // no wvx stream w/ floats & big ints #define CONFIG_MD5_CHECKSUM 0x8000000 // compute & store MD5 signature +#define CONFIG_MERGE_BLOCKS 0x10000000 // merge blocks of equal redundancy (for lossyWAV) #define CONFIG_OPTIMIZE_MONO 0x80000000 // optimize for mono streams posing as stereo /* - * These config flags are no longer used (or were never used) although there - * may be WavPack files that have some of these bits set in the config - * metadata structure, so be careful reusing them for something else. + * These config flags were never actually used, or are no longer used, or are + * used for something else now. They may be used in the future for what they + * say, or for something else. WavPack files in the wild *may* have some of + * these bit set in their config flags (with these older meanings), but only + * if the stream version is 0x410 or less than 0x407. Of course, this is not + * very important because once the file has been encoded, the config bits are + * just for information purposes (i.e., they do not affect decoding), * #define CONFIG_ADOBE_MODE 0x100 // "adobe" mode for 32-bit floats #define CONFIG_VERY_FAST_FLAG 0x400 // double fast @@ -352,10 +358,12 @@ typedef struct { struct { int32_t shaping_acc [2], shaping_delta [2], error [2]; double noise_sum, noise_ave, noise_max; + short *shaping_data, *shaping_array; + int32_t shaping_samples; } dc; - struct decorr_pass decorr_passes [MAX_NTERMS]; - WavpackDecorrSpec *decorr_specs; + struct decorr_pass decorr_passes [MAX_NTERMS], analysis_pass; + const WavpackDecorrSpec *decorr_specs; } WavpackStream; // flags for float_flags: @@ -406,7 +414,7 @@ typedef struct { uint32_t filelen, file2len, filepos, file2pos, total_samples, crc_errors, first_flags; int wvc_flag, open_flags, norm_offset, reduced_channels, lossy_blocks, close_files; - uint32_t block_samples, max_samples, acc_samples, initial_index; + uint32_t block_samples, ave_block_samples, block_boundary, max_samples, acc_samples, initial_index; int riff_header_added, riff_header_created; M_Tag m_tag; @@ -650,12 +658,15 @@ int WavpackGetMode (WavpackContext *wpc); #define MODE_VALID_TAG 0x10 #define MODE_HIGH 0x20 #define MODE_FAST 0x40 -#define MODE_EXTRA 0x80 +#define MODE_EXTRA 0x80 // extra mode used, see MODE_XMODE for possible level #define MODE_APETAG 0x100 #define MODE_SFX 0x200 #define MODE_VERY_HIGH 0x400 #define MODE_MD5 0x800 +#define MODE_XMODE 0x7000 // mask for extra level (1-6, 0=unknown) +#define MODE_DNS 0x8000 +char *WavpackGetErrorMessage (WavpackContext *wpc); int WavpackGetVersion (WavpackContext *wpc); uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t samples); uint32_t WavpackGetNumSamples (WavpackContext *wpc); @@ -670,6 +681,7 @@ int WavpackGetBytesPerSample (WavpackContext *wpc); int WavpackGetNumChannels (WavpackContext *wpc); int WavpackGetChannelMask (WavpackContext *wpc); int WavpackGetReducedChannels (WavpackContext *wpc); +int WavpackGetFloatNormExp (WavpackContext *wpc); int WavpackGetMD5Sum (WavpackContext *wpc, uchar data [16]); uint32_t WavpackGetWrapperBytes (WavpackContext *wpc); uchar *WavpackGetWrapperData (WavpackContext *wpc); @@ -700,6 +712,9 @@ void *WavpackGetWrapperLocation (void *first_block, uint32_t *size); void WavpackLittleEndianToNative (void *data, char *format); void WavpackNativeToLittleEndian (void *data, char *format); +uint32_t WavpackGetLibraryVersion (void); +const char *WavpackGetLibraryVersionString (void); + ///////////////////////////// SIMD helper macros ///////////////////////////// #ifdef OPT_MMX @@ -719,10 +734,11 @@ typedef int __v4hi __attribute__ ((__mode__ (__V4HI__))); #define _m_pxor(m1, m2) (__m64) __builtin_ia32_pxor ((__di) m1, (__di) m2) #else typedef int __m64 __attribute__ ((__vector_size__ (8))); -#define _m_paddsw(m1, m2) __builtin_ia32_paddsw (m1, m2) +typedef short __m64_16 __attribute__ ((__vector_size__ (8))); +#define _m_paddsw(m1, m2) (__m64) __builtin_ia32_paddsw ((__m64_16) m1, (__m64_16) m2) #define _m_pand(m1, m2) __builtin_ia32_pand (m1, m2) #define _m_pandn(m1, m2) __builtin_ia32_pandn (m1, m2) -#define _m_pmaddwd(m1, m2) __builtin_ia32_pmaddwd (m1, m2) +#define _m_pmaddwd(m1, m2) __builtin_ia32_pmaddwd ((__m64_16) m1, (__m64_16) m2) #define _m_por(m1, m2) __builtin_ia32_por (m1, m2) #define _m_pxor(m1, m2) __builtin_ia32_pxor (m1, m2) #endif diff --git a/wavpack-4.5.0/src/wavpack_version.h b/wavpack-4.5.0/src/wavpack_version.h new file mode 100644 index 0000000..27e930d --- /dev/null +++ b/wavpack-4.5.0/src/wavpack_version.h @@ -0,0 +1,19 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2006 Conifer Software. // +// All Rights Reserved. // +// Distributed under the BSD Software License (see license.txt) // +//////////////////////////////////////////////////////////////////////////// + +// wavpack_version.h + +#ifndef WAVPACK_VERSION_H +#define WAVPACK_VERSION_H + +#define LIBWAVPACK_MAJOR 4 +#define LIBWAVPACK_MINOR 50 +#define LIBWAVPACK_MICRO 0 +#define LIBWAVPACK_VERSION_STRING "4.50.0" + +#endif diff --git a/wavpack-4.5.0/src/words.c b/wavpack-4.5.0/src/words.c new file mode 100644 index 0000000..600a011 --- /dev/null +++ b/wavpack-4.5.0/src/words.c @@ -0,0 +1,1468 @@ +//////////////////////////////////////////////////////////////////////////// +// **** WAVPACK **** // +// Hybrid Lossless Wavefile Compressor // +// Copyright (c) 1998 - 2006 Conifer Software. // +// All Rights Reserved. // +//////////////////////////////////////////////////////////////////////////// + +// words.c + +// This module provides entropy word encoding and 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 "wavpack_local.h" + +#include +#include + +#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 + +//////////////////////////////// local macros ///////////////////////////////// + +#define LIMIT_ONES 16 // maximum consecutive 1s sent for "div" data + +// these control the time constant "slow_level" which is used for hybrid mode +// that controls bitrate as a function of residual level (HYBRID_BITRATE). +#define SLS 8 +#define SLO ((1 << (SLS - 1))) + +// these control the time constant of the 3 median level breakpoints +#define DIV0 128 // 5/7 of samples +#define DIV1 64 // 10/49 of samples +#define DIV2 32 // 20/343 of samples + +// this macro retrieves the specified median breakpoint (without frac; min = 1) +#define GET_MED(med) (((c->median [med]) >> 4) + 1) + +// These macros update the specified median breakpoints. Note that the median +// is incremented when the sample is higher than the median, else decremented. +// They are designed so that the median will never drop below 1 and the value +// is essentially stationary if there are 2 increments for every 5 decrements. + +#define INC_MED0() (c->median [0] += ((c->median [0] + DIV0) / DIV0) * 5) +#define DEC_MED0() (c->median [0] -= ((c->median [0] + (DIV0-2)) / DIV0) * 2) +#define INC_MED1() (c->median [1] += ((c->median [1] + DIV1) / DIV1) * 5) +#define DEC_MED1() (c->median [1] -= ((c->median [1] + (DIV1-2)) / DIV1) * 2) +#define INC_MED2() (c->median [2] += ((c->median [2] + DIV2) / DIV2) * 5) +#define DEC_MED2() (c->median [2] -= ((c->median [2] + (DIV2-2)) / DIV2) * 2) + +#define count_bits(av) ( \ + (av) < (1 << 8) ? nbits_table [av] : \ + ( \ + (av) < (1L << 16) ? nbits_table [(av) >> 8] + 8 : \ + ((av) < (1L << 24) ? nbits_table [(av) >> 16] + 16 : nbits_table [(av) >> 24] + 24) \ + ) \ +) + +///////////////////////////// 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 uchar 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 uchar 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 +}; + +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 +}; + +///////////////////////////// executable code //////////////////////////////// + +static int FASTCALL mylog2 (uint32_t avalue); + +// 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. + +#ifndef NO_PACK + +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. + +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 mylog2 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) +{ + uchar *byteptr; + int temp; + + byteptr = wpmd->data = malloc (12); + wpmd->id = ID_ENTROPY_VARS; + + *byteptr++ = temp = mylog2 (wps->w.c [0].median [0]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.c [0].median [1]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.c [0].median [2]); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + *byteptr++ = temp = mylog2 (wps->w.c [1].median [0]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.c [1].median [1]); + *byteptr++ = temp >> 8; + *byteptr++ = temp = mylog2 (wps->w.c [1].median [2]); + *byteptr++ = temp >> 8; + } + + wpmd->byte_length = (int32_t)(byteptr - (uchar *) 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 +// mylog2 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) +{ + uchar *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 = log2s (wps->w.c [0].slow_level); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + *byteptr++ = temp = 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 = log2s (wps->w.bitrate_delta [0]); + *byteptr++ = temp >> 8; + + if (!(wps->wphdr.flags & MONO_DATA)) { + *byteptr++ = temp = log2s (wps->w.bitrate_delta [1]); + *byteptr++ = temp >> 8; + } + } + + wpmd->byte_length = (int32_t)(byteptr - (uchar *) wpmd->data); + read_hybrid_profile (wps, wpmd); +} + +#endif + +// 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) +{ + uchar *byteptr = wpmd->data; + + if (wpmd->byte_length != ((wps->wphdr.flags & MONO_DATA) ? 6 : 12)) + return FALSE; + + wps->w.c [0].median [0] = exp2s (byteptr [0] + (byteptr [1] << 8)); + wps->w.c [0].median [1] = exp2s (byteptr [2] + (byteptr [3] << 8)); + wps->w.c [0].median [2] = exp2s (byteptr [4] + (byteptr [5] << 8)); + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->w.c [1].median [0] = exp2s (byteptr [6] + (byteptr [7] << 8)); + wps->w.c [1].median [1] = exp2s (byteptr [8] + (byteptr [9] << 8)); + wps->w.c [1].median [2] = 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) +{ + uchar *byteptr = wpmd->data; + uchar *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 = exp2s (byteptr [0] + (byteptr [1] << 8)); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->w.c [1].slow_level = 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] = exp2s ((short)(byteptr [0] + (byteptr [1] << 8))); + byteptr += 2; + + if (!(wps->wphdr.flags & MONO_DATA)) { + wps->w.bitrate_delta [1] = exp2s ((short)(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. + +static 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 = exp2s (slow_log_0 - bitrate_0 + 0x100); + else + wps->w.c [0].error_limit = 0; + } + else + wps->w.c [0].error_limit = 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 = 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 = exp2s (slow_log_1 - bitrate_1 + 0x100); + else + wps->w.c [1].error_limit = 0; + } + else { + wps->w.c [0].error_limit = exp2s (bitrate_0); + wps->w.c [1].error_limit = exp2s (bitrate_1); + } + } +} + +#ifndef NO_PACK + +// 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 += mylog2 (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 += mylog2 (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. + +void scan_word (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; + + init_words (wps); + + 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 += mylog2 (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 += mylog2 (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; + } +} + +#endif + +#ifndef NO_UNPACK + +static uint32_t FASTCALL 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; + int next8, sign; + int32_t value; + + 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 { + 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; + } + + 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; + 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 += mylog2 (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; + + 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.c [0].median [0] < 2 && !wps->w.holding_zero && !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++ = 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++ = 0; + continue; + } + } + } + + if (wps->w.holding_zero) + ones_count = wps->w.holding_zero = 0; + else { + int next8; + + 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; + } + + 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 (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++ = (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 FASTCALL read_code (Bitstream *bs, uint32_t maxcode) +{ + uint32_t extras, code; + int bitcount; + + if (maxcode < 2) + return maxcode ? getbit (bs) : 0; + + bitcount = count_bits (maxcode); + extras = bitset [bitcount] - maxcode - 1; + + while (bs->bc < bitcount) { + if (++(bs->ptr) == bs->end) + bs->wrap (bs); + + bs->sr |= *(bs->ptr) << bs->bc; + bs->bc += sizeof (*(bs->ptr)) * 8; + } + + if ((code = bs->sr & bitmask [bitcount - 1]) >= extras) + code = (code << 1) - extras + ((bs->sr >> (bitcount - 1)) & 1); + else + bitcount--; + + if (bs->bc > 32) { + bs->bc -= bitcount; + bs->sr = *(bs->ptr) >> (sizeof (*(bs->ptr)) * 8 - bs->bc); + } + else { + bs->sr >>= bitcount; + bs->bc -= bitcount; + } + + return code; +} + +#endif + +// 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. + +static int FASTCALL mylog2 (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. + +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; +} + +// 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 log2s (int32_t value) +{ + return (value < 0) ? -mylog2 (-value) : mylog2 (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 exp2s (int log) +{ + uint32_t value; + + if (log < 0) + return -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; +} diff --git a/wavpack-4.4.1/src/wputils.c b/wavpack-4.5.0/src/wputils.c similarity index 95% rename from wavpack-4.4.1/src/wputils.c rename to wavpack-4.5.0/src/wputils.c index 31c82d0..9afecfd 100644 --- a/wavpack-4.4.1/src/wputils.c +++ b/wavpack-4.5.0/src/wputils.c @@ -55,7 +55,7 @@ static void free_streams (WavpackContext *wpc); ///////////////////////////// local table storage //////////////////////////// -const uint32_t sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050, +static const uint32_t sample_rates [] = { 6000, 8000, 9600, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000, 192000 }; ///////////////////////////// executable code //////////////////////////////// @@ -362,6 +362,8 @@ WavpackContext *WavpackOpenFileInputEx (WavpackStreamReader *reader, void *wv_id // 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) { @@ -382,7 +384,7 @@ int WavpackGetMode (WavpackContext *wpc) if (wpc->config.flags & CONFIG_FLOAT_DATA) mode |= MODE_FLOAT; - if (wpc->config.flags & CONFIG_HIGH_FLAG) { + if (wpc->config.flags & (CONFIG_HIGH_FLAG | CONFIG_VERY_HIGH_FLAG)) { mode |= MODE_HIGH; if ((wpc->config.flags & CONFIG_VERY_HIGH_FLAG) || @@ -394,7 +396,7 @@ int WavpackGetMode (WavpackContext *wpc) mode |= MODE_FAST; if (wpc->config.flags & CONFIG_EXTRA_MODE) - mode |= MODE_EXTRA; + mode |= (MODE_EXTRA | (wpc->config.xmode << 12)); if (wpc->config.flags & CONFIG_CREATE_EXE) mode |= MODE_SFX; @@ -402,6 +404,10 @@ int WavpackGetMode (WavpackContext *wpc) 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 [0] && wpc->streams [0]->wphdr.version >= 0x407) + mode |= MODE_DNS; + #ifndef NO_TAGS if (valid_tag (&wpc->m_tag)) { mode |= MODE_VALID_TAG; @@ -618,6 +624,16 @@ uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t sa offset++; } + else if (offset == num_channels - 1) { + while (samcnt--) { + dst [0] = src [0]; + dst += num_channels; + src += 2; + } + + wpc->crc_errors++; + offset++; + } else { while (samcnt--) { dst [0] = *src++; @@ -628,7 +644,7 @@ uint32_t WavpackUnpackSamples (WavpackContext *wpc, int32_t *buffer, uint32_t sa offset += 2; } - if ((wps->wphdr.flags & FINAL_BLOCK) || wpc->num_streams == MAX_STREAMS) + if ((wps->wphdr.flags & FINAL_BLOCK) || wpc->num_streams == MAX_STREAMS || offset == num_channels) break; else wpc->current_stream++; @@ -891,17 +907,17 @@ static int get_ape_tag_item (M_Tag *m_tag, const char *item, char *value, int si 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) { + for (i = 0; i < m_tag->ape_tag_hdr.item_count && q - p > 8; ++i) { int vsize, flags, isize; vsize = * (int32_t *) p; p += 4; flags = * (int32_t *) p; p += 4; - isize = (int) strlen (p); + isize = (int) strnlen (p, q - p); little_endian_to_native (&vsize, "L"); little_endian_to_native (&flags, "L"); - if (p + isize + vsize + 1 > q) + if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q) break; if (isize && vsize && !stricmp (item, p) && !(flags & 6)) { @@ -1009,17 +1025,17 @@ static int get_ape_tag_item_indexed (M_Tag *m_tag, int index, char *item, int si 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; ++i) { + for (i = 0; i < m_tag->ape_tag_hdr.item_count && index >= 0 && q - p > 8; ++i) { int vsize, flags, isize; vsize = * (int32_t *) p; p += 4; flags = * (int32_t *) p; p += 4; - isize = (int) strlen (p); + isize = (int) strnlen (p, q - p); little_endian_to_native (&vsize, "L"); little_endian_to_native (&flags, "L"); - if (p + isize + vsize + 1 > q) + if (vsize < 0 || vsize > m_tag->ape_tag_hdr.length || p + isize + vsize + 1 > q) break; if (isize && vsize && !(flags & 6) && !index--) { @@ -1190,7 +1206,7 @@ int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_ wpc->config.flags = config->flags; if (config->flags & CONFIG_VERY_HIGH_FLAG) - config->flags |= CONFIG_HIGH_FLAG; + wpc->config.flags |= CONFIG_HIGH_FLAG; if (config->float_norm_exp) { wpc->config.float_norm_exp = config->float_norm_exp; @@ -1317,23 +1333,31 @@ int WavpackPackInit (WavpackContext *wpc) if (wpc->metabytes > 4096) write_metadata_block (wpc); - if (wpc->config.block_samples) - wpc->block_samples = wpc->config.block_samples; - else { - if (wpc->config.flags & CONFIG_HIGH_FLAG) - wpc->block_samples = wpc->config.sample_rate; - else if (!(wpc->config.sample_rate % 2)) - wpc->block_samples = wpc->config.sample_rate / 2; + if (wpc->config.flags & CONFIG_HIGH_FLAG) + wpc->block_samples = wpc->config.sample_rate; + else if (!(wpc->config.sample_rate % 2)) + wpc->block_samples = wpc->config.sample_rate / 2; + else + wpc->block_samples = wpc->config.sample_rate; + + while (wpc->block_samples * wpc->config.num_channels > 150000) + wpc->block_samples /= 2; + + while (wpc->block_samples * wpc->config.num_channels < 40000) + wpc->block_samples *= 2; + + if (wpc->config.block_samples) { + if ((wpc->config.flags & CONFIG_MERGE_BLOCKS) && + wpc->block_samples > (uint32_t) wpc->config.block_samples) { + wpc->block_boundary = wpc->config.block_samples; + wpc->block_samples /= wpc->config.block_samples; + wpc->block_samples *= wpc->config.block_samples; + } else - wpc->block_samples = wpc->config.sample_rate; - - while (wpc->block_samples * wpc->config.num_channels > 150000) - wpc->block_samples /= 2; - - while (wpc->block_samples * wpc->config.num_channels < 40000) - wpc->block_samples *= 2; + wpc->block_samples = wpc->config.block_samples; } + wpc->ave_block_samples = wpc->block_samples; wpc->max_samples = wpc->block_samples + (wpc->block_samples >> 1); for (wpc->current_stream = 0; wpc->streams [wpc->current_stream]; wpc->current_stream++) { @@ -1590,6 +1614,9 @@ static int pack_streams (WavpackContext *wpc, uint32_t block_samples) result = pack_block (wpc, wps->sample_buffer); wps->blockbuff = wps->block2buff = NULL; + if (wps->wphdr.block_samples != block_samples) + block_samples = wps->wphdr.block_samples; + if (!result) { strcpy (wpc->error_message, "output buffer overflowed!"); break; @@ -1625,6 +1652,7 @@ static int pack_streams (WavpackContext *wpc, uint32_t block_samples) } wpc->current_stream = 0; + wpc->ave_block_samples = (wpc->ave_block_samples * 0x7 + block_samples + 0x4) >> 3; wpc->acc_samples -= block_samples; free (outbuff); @@ -1648,11 +1676,19 @@ void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block) little_endian_to_native (first_block, WavpackHeaderFormat); ((WavpackHeader *) first_block)->total_samples = WavpackGetSampleIndex (wpc); + /* note that since the RIFF wrapper will not necessarily be properly aligned, + we copy it into a newly allocated buffer before modifying it */ + if (wpc->riff_header_created) { if (WavpackGetWrapperLocation (first_block, &wrapper_size)) { - RiffChunkHeader *riffhdr = WavpackGetWrapperLocation (first_block, NULL); - ChunkHeader *datahdr = (ChunkHeader *)((char *) riffhdr + wrapper_size - sizeof (ChunkHeader)); uint32_t data_size = WavpackGetSampleIndex (wpc) * WavpackGetNumChannels (wpc) * WavpackGetBytesPerSample (wpc); + RiffChunkHeader *riffhdr; + ChunkHeader *datahdr; + void *wrapper_buff; + + riffhdr = wrapper_buff = malloc (wrapper_size); + memcpy (wrapper_buff, WavpackGetWrapperLocation (first_block, NULL), wrapper_size); + datahdr = (ChunkHeader *)((char *) riffhdr + wrapper_size - sizeof (ChunkHeader)); if (!strncmp (riffhdr->ckID, "RIFF", 4)) { little_endian_to_native (riffhdr, ChunkHeaderFormat); @@ -1665,6 +1701,9 @@ void WavpackUpdateNumSamples (WavpackContext *wpc, void *first_block) datahdr->ckSize = data_size; native_to_little_endian (datahdr, ChunkHeaderFormat); } + + memcpy (WavpackGetWrapperLocation (first_block, NULL), wrapper_buff, wrapper_size); + free (wrapper_buff); } } @@ -1745,7 +1784,7 @@ static void *find_metadata (void *wavpack_block, int desired_id, uint32_t *size) dp += meta_bc; } - return FALSE; + return NULL; } #endif @@ -2013,7 +2052,7 @@ double WavpackGetAverageBitrate (WavpackContext *wpc, int count_wvc) double output_time = (double) wpc->total_samples / wpc->config.sample_rate; double input_size = (double) wpc->filelen + (count_wvc ? wpc->file2len : 0); - if (output_time >= 1.0 && input_size >= 1.0) + if (output_time >= 0.1 && input_size >= 1.0) return input_size * 8.0 / output_time; } @@ -2267,6 +2306,11 @@ static void free_streams (WavpackContext *wpc) 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; + } + if (si) { wpc->num_streams--; free (wpc->streams [si]); @@ -2297,7 +2341,7 @@ static void free_tag (M_Tag *m_tag) { if (m_tag->ape_tag_data) { free (m_tag->ape_tag_data); - m_tag->ape_tag_data = 0; + m_tag->ape_tag_data = NULL; } } @@ -2313,7 +2357,7 @@ static void free_tag (M_Tag *m_tag) static uint32_t read_next_header (WavpackStreamReader *reader, void *id, WavpackHeader *wphdr) { - char buffer [sizeof (*wphdr)], *sp = buffer + sizeof (*wphdr), *ep = sp; + unsigned char buffer [sizeof (*wphdr)], *sp = buffer + sizeof (*wphdr), *ep = sp; uint32_t bytes_skipped = 0; int bleft; @@ -2331,8 +2375,8 @@ static uint32_t read_next_header (WavpackStreamReader *reader, void *id, Wavpack sp = buffer; if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' && - !(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 && - sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff)) { + !(*++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, buffer, sizeof (*wphdr)); little_endian_to_native (wphdr, WavpackHeaderFormat); return bytes_skipped; @@ -2562,7 +2606,7 @@ static int read_wvc_block (WavpackContext *wpc) if (wpc->reader->read_bytes (wpc->wvc_in, wps->block2buff + 32, wphdr.ckSize - 24) != wphdr.ckSize - 24 || (wphdr.flags & UNKNOWN_FLAGS)) { free (wps->block2buff); - wps->block2buff = 0; + wps->block2buff = NULL; wps->wvc_skip = TRUE; wpc->crc_errors++; return FALSE; @@ -2594,7 +2638,7 @@ static int read_wvc_block (WavpackContext *wpc) static uint32_t find_header (WavpackStreamReader *reader, void *id, uint32_t filepos, WavpackHeader *wphdr) { - char *buffer = malloc (BUFSIZE), *sp = buffer, *ep = buffer; + unsigned char *buffer = malloc (BUFSIZE), *sp = buffer, *ep = buffer; if (filepos != (uint32_t) -1 && reader->set_pos_abs (id, filepos)) { free (buffer); @@ -2630,14 +2674,14 @@ static uint32_t find_header (WavpackStreamReader *reader, void *id, uint32_t fil while (sp + 32 <= ep) if (*sp++ == 'w' && *sp == 'v' && *++sp == 'p' && *++sp == 'k' && - !(*++sp & 1) && sp [2] < 16 && !sp [3] && sp [5] == 4 && - sp [4] >= (MIN_STREAM_VERS & 0xff) && sp [4] <= (MAX_STREAM_VERS & 0xff)) { + !(*++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)); little_endian_to_native (wphdr, WavpackHeaderFormat); if (wphdr->block_samples && (wphdr->flags & INITIAL_BLOCK)) { free (buffer); - return reader->get_pos (id) - (ep - sp + 4); + return reader->get_pos (id) - (uint32_t)(ep - sp + 4); } if (wphdr->ckSize > 1024) @@ -2730,6 +2774,7 @@ static uint32_t find_sample (WavpackContext *wpc, void *infile, uint32_t header_ static int load_tag (WavpackContext *wpc) { + int ape_tag_length, ape_tag_items; M_Tag *m_tag = &wpc->m_tag; CLEAR (*m_tag); @@ -2753,17 +2798,20 @@ static int load_tag (WavpackContext *wpc) m_tag->ape_tag_hdr.length < (1024 * 1024) && (m_tag->ape_tag_data = malloc (m_tag->ape_tag_hdr.length)) != NULL) { + ape_tag_items = m_tag->ape_tag_hdr.item_count; + ape_tag_length = m_tag->ape_tag_hdr.length; + if (m_tag->id3_tag.tag_id [0] == 'T') m_tag->tag_file_pos = -(int32_t)sizeof (ID3_Tag); else m_tag->tag_file_pos = 0; - m_tag->tag_file_pos -= m_tag->ape_tag_hdr.length + sizeof (APE_Tag_Hdr); + m_tag->tag_file_pos -= ape_tag_length + sizeof (APE_Tag_Hdr); wpc->reader->set_pos_rel (wpc->wv_in, m_tag->tag_file_pos, SEEK_END); - memset (m_tag->ape_tag_data, 0, m_tag->ape_tag_hdr.length); + memset (m_tag->ape_tag_data, 0, ape_tag_length); - if (wpc->reader->read_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (APE_Tag_Hdr)) != sizeof (APE_Tag_Hdr) || - strncmp (m_tag->ape_tag_hdr.ID, "APETAGEX", 8)) { + if (wpc->reader->read_bytes (wpc->wv_in, &m_tag->ape_tag_hdr, sizeof (APE_Tag_Hdr)) != + sizeof (APE_Tag_Hdr) || strncmp (m_tag->ape_tag_hdr.ID, "APETAGEX", 8)) { free (m_tag->ape_tag_data); CLEAR (*m_tag); return FALSE; // something's wrong... @@ -2771,16 +2819,15 @@ static int load_tag (WavpackContext *wpc) little_endian_to_native (&m_tag->ape_tag_hdr, APE_Tag_Hdr_Format); - if (m_tag->ape_tag_hdr.version != 2000 || !m_tag->ape_tag_hdr.item_count || - m_tag->ape_tag_hdr.length < sizeof (m_tag->ape_tag_hdr) || - m_tag->ape_tag_hdr.length > (1024 * 1024)) { + if (m_tag->ape_tag_hdr.version != 2000 || m_tag->ape_tag_hdr.item_count != ape_tag_items || + m_tag->ape_tag_hdr.length != ape_tag_length) { free (m_tag->ape_tag_data); CLEAR (*m_tag); return FALSE; // something's wrong... } - if (wpc->reader->read_bytes (wpc->wv_in, m_tag->ape_tag_data, m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr)) != - m_tag->ape_tag_hdr.length - sizeof (APE_Tag_Hdr)) { + if (wpc->reader->read_bytes (wpc->wv_in, m_tag->ape_tag_data, + ape_tag_length - sizeof (APE_Tag_Hdr)) != ape_tag_length - sizeof (APE_Tag_Hdr)) { free (m_tag->ape_tag_data); CLEAR (*m_tag); return FALSE; // something's wrong... @@ -2867,14 +2914,14 @@ void WavpackNativeToLittleEndian (void *data, char *format) native_to_little_endian (data, format); } -uint32_t WavpackGetLibraryVersion () +uint32_t WavpackGetLibraryVersion (void) { return (LIBWAVPACK_MAJOR<<16) |(LIBWAVPACK_MINOR<<8) |(LIBWAVPACK_MICRO<<0); } -const char *WavpackGetLibraryVersionString () +const char *WavpackGetLibraryVersionString (void) { return LIBWAVPACK_VERSION_STRING; }