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 66ed3a9..0000000 Binary files a/WavPackDotNet/WavPack/libwavpack.lib and /dev/null differ diff --git a/WavPackDotNet/WavPackDotNet.cpp b/WavPackDotNet/WavPackDotNet.cpp index 885b11f..8d919a7 100644 --- a/WavPackDotNet/WavPackDotNet.cpp +++ b/WavPackDotNet/WavPackDotNet.cpp @@ -36,15 +36,8 @@ using namespace APETagsDotNet; #include #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; }