mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
initial checkin
This commit is contained in:
246
MAC_SDK/Source/MACLib/APECompress.cpp
Normal file
246
MAC_SDK/Source/MACLib/APECompress.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
#include "All.h"
|
||||
#include "APECompress.h"
|
||||
#include IO_HEADER_FILE
|
||||
#include "APECompressCreate.h"
|
||||
#include "WAVInputSource.h"
|
||||
|
||||
CAPECompress::CAPECompress()
|
||||
{
|
||||
m_nBufferHead = 0;
|
||||
m_nBufferTail = 0;
|
||||
m_nBufferSize = 0;
|
||||
m_bBufferLocked = FALSE;
|
||||
m_bOwnsOutputIO = FALSE;
|
||||
m_pioOutput = NULL;
|
||||
|
||||
m_spAPECompressCreate.Assign(new CAPECompressCreate());
|
||||
|
||||
m_pBuffer = NULL;
|
||||
}
|
||||
|
||||
CAPECompress::~CAPECompress()
|
||||
{
|
||||
SAFE_ARRAY_DELETE(m_pBuffer)
|
||||
|
||||
if (m_bOwnsOutputIO)
|
||||
{
|
||||
SAFE_DELETE(m_pioOutput)
|
||||
}
|
||||
}
|
||||
|
||||
int CAPECompress::Start(const wchar_t * pOutputFilename, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
|
||||
{
|
||||
m_pioOutput = new IO_CLASS_NAME;
|
||||
m_bOwnsOutputIO = TRUE;
|
||||
|
||||
if (m_pioOutput->Create(pOutputFilename) != 0)
|
||||
{
|
||||
return ERROR_INVALID_OUTPUT_FILE;
|
||||
}
|
||||
|
||||
m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
|
||||
pHeaderData, nHeaderBytes);
|
||||
|
||||
SAFE_ARRAY_DELETE(m_pBuffer)
|
||||
m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
|
||||
m_pBuffer = new unsigned char [m_nBufferSize];
|
||||
memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPECompress::StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
|
||||
{
|
||||
m_pioOutput = pioOutput;
|
||||
m_bOwnsOutputIO = FALSE;
|
||||
|
||||
m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
|
||||
pHeaderData, nHeaderBytes);
|
||||
|
||||
SAFE_ARRAY_DELETE(m_pBuffer)
|
||||
m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
|
||||
m_pBuffer = new unsigned char [m_nBufferSize];
|
||||
memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPECompress::GetBufferBytesAvailable()
|
||||
{
|
||||
return m_nBufferSize - m_nBufferTail;
|
||||
}
|
||||
|
||||
int CAPECompress::UnlockBuffer(int nBytesAdded, BOOL bProcess)
|
||||
{
|
||||
if (m_bBufferLocked == FALSE)
|
||||
return ERROR_UNDEFINED;
|
||||
|
||||
m_nBufferTail += nBytesAdded;
|
||||
m_bBufferLocked = FALSE;
|
||||
|
||||
if (bProcess)
|
||||
{
|
||||
int nRetVal = ProcessBuffer();
|
||||
if (nRetVal != 0) { return nRetVal; }
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
unsigned char * CAPECompress::LockBuffer(int * pBytesAvailable)
|
||||
{
|
||||
if (m_pBuffer == NULL) { return NULL; }
|
||||
|
||||
if (m_bBufferLocked)
|
||||
return NULL;
|
||||
|
||||
m_bBufferLocked = TRUE;
|
||||
|
||||
if (pBytesAvailable)
|
||||
*pBytesAvailable = GetBufferBytesAvailable();
|
||||
|
||||
return &m_pBuffer[m_nBufferTail];
|
||||
}
|
||||
|
||||
int CAPECompress::AddData(unsigned char * pData, int nBytes)
|
||||
{
|
||||
if (m_pBuffer == NULL) return ERROR_INSUFFICIENT_MEMORY;
|
||||
|
||||
int nBytesDone = 0;
|
||||
|
||||
while (nBytesDone < nBytes)
|
||||
{
|
||||
// lock the buffer
|
||||
int nBytesAvailable = 0;
|
||||
unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
|
||||
if (pBuffer == NULL || nBytesAvailable <= 0)
|
||||
return ERROR_UNDEFINED;
|
||||
|
||||
// calculate how many bytes to copy and add that much to the buffer
|
||||
int nBytesToProcess = min(nBytesAvailable, nBytes - nBytesDone);
|
||||
memcpy(pBuffer, &pData[nBytesDone], nBytesToProcess);
|
||||
|
||||
// unlock the buffer (fail if not successful)
|
||||
int nRetVal = UnlockBuffer(nBytesToProcess);
|
||||
if (nRetVal != ERROR_SUCCESS)
|
||||
return nRetVal;
|
||||
|
||||
// update our progress
|
||||
nBytesDone += nBytesToProcess;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPECompress::Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes)
|
||||
{
|
||||
RETURN_ON_ERROR(ProcessBuffer(TRUE))
|
||||
return m_spAPECompressCreate->Finish(pTerminatingData, nTerminatingBytes, nWAVTerminatingBytes);
|
||||
}
|
||||
|
||||
int CAPECompress::Kill()
|
||||
{
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPECompress::ProcessBuffer(BOOL bFinalize)
|
||||
{
|
||||
if (m_pBuffer == NULL) { return ERROR_UNDEFINED; }
|
||||
|
||||
try
|
||||
{
|
||||
// process as much as possible
|
||||
int nThreshold = (bFinalize) ? 0 : m_spAPECompressCreate->GetFullFrameBytes();
|
||||
|
||||
while ((m_nBufferTail - m_nBufferHead) >= nThreshold)
|
||||
{
|
||||
int nFrameBytes = min(m_spAPECompressCreate->GetFullFrameBytes(), m_nBufferTail - m_nBufferHead);
|
||||
|
||||
if (nFrameBytes == 0)
|
||||
break;
|
||||
|
||||
int nRetVal = m_spAPECompressCreate->EncodeFrame(&m_pBuffer[m_nBufferHead], nFrameBytes);
|
||||
if (nRetVal != 0) { return nRetVal; }
|
||||
|
||||
m_nBufferHead += nFrameBytes;
|
||||
}
|
||||
|
||||
// shift the buffer
|
||||
if (m_nBufferHead != 0)
|
||||
{
|
||||
int nBytesLeft = m_nBufferTail - m_nBufferHead;
|
||||
|
||||
if (nBytesLeft != 0)
|
||||
memmove(m_pBuffer, &m_pBuffer[m_nBufferHead], nBytesLeft);
|
||||
|
||||
m_nBufferTail -= m_nBufferHead;
|
||||
m_nBufferHead = 0;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPECompress::AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes, int * pBytesAdded)
|
||||
{
|
||||
// error check the parameters
|
||||
if (pInputSource == NULL) return ERROR_BAD_PARAMETER;
|
||||
|
||||
// initialize
|
||||
if (pBytesAdded) *pBytesAdded = 0;
|
||||
|
||||
// lock the buffer
|
||||
int nBytesAvailable = 0;
|
||||
unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
|
||||
if ((pBuffer == NULL) || (nBytesAvailable == 0))
|
||||
return ERROR_INSUFFICIENT_MEMORY;
|
||||
|
||||
// calculate the 'ideal' number of bytes
|
||||
unsigned int nBytesRead = 0;
|
||||
|
||||
int nIdealBytes = m_spAPECompressCreate->GetFullFrameBytes() - (m_nBufferTail - m_nBufferHead);
|
||||
if (nIdealBytes > 0)
|
||||
{
|
||||
// get the data
|
||||
int nBytesToAdd = nBytesAvailable;
|
||||
|
||||
if (nMaxBytes > 0)
|
||||
{
|
||||
if (nBytesToAdd > nMaxBytes) nBytesToAdd = nMaxBytes;
|
||||
}
|
||||
|
||||
if (nBytesToAdd > nIdealBytes) nBytesToAdd = nIdealBytes;
|
||||
|
||||
// always make requests along block boundaries
|
||||
while ((nBytesToAdd % m_wfeInput.nBlockAlign) != 0)
|
||||
nBytesToAdd--;
|
||||
|
||||
int nBlocksToAdd = nBytesToAdd / m_wfeInput.nBlockAlign;
|
||||
|
||||
// get data
|
||||
int nBlocksAdded = 0;
|
||||
int nRetVal = pInputSource->GetData(pBuffer, nBlocksToAdd, &nBlocksAdded);
|
||||
if (nRetVal != 0)
|
||||
return ERROR_IO_READ;
|
||||
else
|
||||
nBytesRead = (nBlocksAdded * m_wfeInput.nBlockAlign);
|
||||
|
||||
// store the bytes read
|
||||
if (pBytesAdded)
|
||||
*pBytesAdded = nBytesRead;
|
||||
}
|
||||
|
||||
// unlock the data and process
|
||||
int nRetVal = UnlockBuffer(nBytesRead, TRUE);
|
||||
if (nRetVal != 0)
|
||||
{
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
56
MAC_SDK/Source/MACLib/APECompress.h
Normal file
56
MAC_SDK/Source/MACLib/APECompress.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#ifndef APE_APECOMPRESS_H
|
||||
#define APE_APECOMPRESS_H
|
||||
|
||||
#include "MACLib.h"
|
||||
class CAPECompressCreate;
|
||||
|
||||
/*************************************************************************************************
|
||||
CAPECompress - uses the CAPECompressHub to provide a simpler compression interface (with buffering, etc)
|
||||
*************************************************************************************************/
|
||||
class CAPECompress : public IAPECompress
|
||||
{
|
||||
public:
|
||||
|
||||
CAPECompress();
|
||||
~CAPECompress();
|
||||
|
||||
// start encoding
|
||||
int Start(const wchar_t * pOutputFilename, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL, const void * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION);
|
||||
int StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL, const void * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION);
|
||||
|
||||
// add data / compress data
|
||||
|
||||
// allows linear, immediate access to the buffer (fast)
|
||||
int GetBufferBytesAvailable();
|
||||
int UnlockBuffer(int nBytesAdded, BOOL bProcess = TRUE);
|
||||
unsigned char * LockBuffer(int * pBytesAvailable);
|
||||
|
||||
// slower, but easier than locking and unlocking (copies data)
|
||||
int AddData(unsigned char * pData, int nBytes);
|
||||
|
||||
// use a CIO (input source) to add data
|
||||
int AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes = -1, int * pBytesAdded = NULL);
|
||||
|
||||
// finish / kill
|
||||
int Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes);
|
||||
int Kill();
|
||||
|
||||
private:
|
||||
|
||||
int ProcessBuffer(BOOL bFinalize = FALSE);
|
||||
|
||||
CSmartPtr<CAPECompressCreate> m_spAPECompressCreate;
|
||||
|
||||
int m_nBufferHead;
|
||||
int m_nBufferTail;
|
||||
int m_nBufferSize;
|
||||
unsigned char * m_pBuffer;
|
||||
BOOL m_bBufferLocked;
|
||||
|
||||
CIO * m_pioOutput;
|
||||
BOOL m_bOwnsOutputIO;
|
||||
WAVEFORMATEX m_wfeInput;
|
||||
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_APECOMPRESS_H
|
||||
126
MAC_SDK/Source/MACLib/APECompressCore.cpp
Normal file
126
MAC_SDK/Source/MACLib/APECompressCore.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
#include "All.h"
|
||||
#include "APECompressCore.h"
|
||||
|
||||
#include "BitArray.h"
|
||||
#include "Prepare.h"
|
||||
#include "NewPredictor.h"
|
||||
|
||||
CAPECompressCore::CAPECompressCore(CIO * pIO, const WAVEFORMATEX * pwfeInput, int nMaxFrameBlocks, int nCompressionLevel)
|
||||
{
|
||||
m_spBitArray.Assign(new CBitArray(pIO));
|
||||
m_spDataX.Assign(new int [nMaxFrameBlocks], TRUE);
|
||||
m_spDataY.Assign(new int [nMaxFrameBlocks], TRUE);
|
||||
m_spTempData.Assign(new int [nMaxFrameBlocks], TRUE);
|
||||
m_spPrepare.Assign(new CPrepare);
|
||||
m_spPredictorX.Assign(new CPredictorCompressNormal(nCompressionLevel));
|
||||
m_spPredictorY.Assign(new CPredictorCompressNormal(nCompressionLevel));
|
||||
|
||||
memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
|
||||
m_nPeakLevel = 0;
|
||||
}
|
||||
|
||||
CAPECompressCore::~CAPECompressCore()
|
||||
{
|
||||
}
|
||||
|
||||
int CAPECompressCore::EncodeFrame(const void * pInputData, int nInputBytes)
|
||||
{
|
||||
// variables
|
||||
const int nInputBlocks = nInputBytes / m_wfeInput.nBlockAlign;
|
||||
int nSpecialCodes = 0;
|
||||
|
||||
// always start a new frame on a byte boundary
|
||||
m_spBitArray->AdvanceToByteBoundary();
|
||||
|
||||
// do the preparation stage
|
||||
RETURN_ON_ERROR(Prepare(pInputData, nInputBytes, &nSpecialCodes))
|
||||
|
||||
m_spPredictorX->Flush();
|
||||
m_spPredictorY->Flush();
|
||||
|
||||
m_spBitArray->FlushState(m_BitArrayStateX);
|
||||
m_spBitArray->FlushState(m_BitArrayStateY);
|
||||
|
||||
m_spBitArray->FlushBitArray();
|
||||
|
||||
if (m_wfeInput.nChannels == 2)
|
||||
{
|
||||
BOOL bEncodeX = TRUE;
|
||||
BOOL bEncodeY = TRUE;
|
||||
|
||||
if ((nSpecialCodes & SPECIAL_FRAME_LEFT_SILENCE) &&
|
||||
(nSpecialCodes & SPECIAL_FRAME_RIGHT_SILENCE))
|
||||
{
|
||||
bEncodeX = FALSE;
|
||||
bEncodeY = FALSE;
|
||||
}
|
||||
|
||||
if (nSpecialCodes & SPECIAL_FRAME_PSEUDO_STEREO)
|
||||
{
|
||||
bEncodeY = FALSE;
|
||||
}
|
||||
|
||||
if (bEncodeX && bEncodeY)
|
||||
{
|
||||
int nLastX = 0;
|
||||
for (int z = 0; z < nInputBlocks; z++)
|
||||
{
|
||||
m_spBitArray->EncodeValue(m_spPredictorY->CompressValue(m_spDataY[z], nLastX), m_BitArrayStateY);
|
||||
m_spBitArray->EncodeValue(m_spPredictorX->CompressValue(m_spDataX[z], m_spDataY[z]), m_BitArrayStateX);
|
||||
|
||||
nLastX = m_spDataX[z];
|
||||
}
|
||||
}
|
||||
else if (bEncodeX)
|
||||
{
|
||||
for (int z = 0; z < nInputBlocks; z++)
|
||||
{
|
||||
RETURN_ON_ERROR(m_spBitArray->EncodeValue(m_spPredictorX->CompressValue(m_spDataX[z]), m_BitArrayStateX))
|
||||
}
|
||||
}
|
||||
else if (bEncodeY)
|
||||
{
|
||||
for (int z = 0; z < nInputBlocks; z++)
|
||||
{
|
||||
RETURN_ON_ERROR(m_spBitArray->EncodeValue(m_spPredictorY->CompressValue(m_spDataY[z]), m_BitArrayStateY))
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_wfeInput.nChannels == 1)
|
||||
{
|
||||
if (!(nSpecialCodes & SPECIAL_FRAME_MONO_SILENCE))
|
||||
{
|
||||
for (int z = 0; z < nInputBlocks; z++)
|
||||
{
|
||||
RETURN_ON_ERROR(m_spBitArray->EncodeValue(m_spPredictorX->CompressValue(m_spDataX[z]), m_BitArrayStateX))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_spBitArray->Finalize();
|
||||
|
||||
// return success
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPECompressCore::Prepare(const void * pInputData, int nInputBytes, int * pSpecialCodes)
|
||||
{
|
||||
// variable declares
|
||||
*pSpecialCodes = 0;
|
||||
unsigned int nCRC = 0;
|
||||
|
||||
// do the preparation
|
||||
RETURN_ON_ERROR(m_spPrepare->Prepare((unsigned char *) pInputData, nInputBytes, &m_wfeInput, m_spDataX, m_spDataY,
|
||||
&nCRC, pSpecialCodes, &m_nPeakLevel))
|
||||
|
||||
// store the CRC
|
||||
RETURN_ON_ERROR(m_spBitArray->EncodeUnsignedLong(nCRC))
|
||||
|
||||
// store any special codes
|
||||
if (*pSpecialCodes != 0)
|
||||
{
|
||||
RETURN_ON_ERROR(m_spBitArray->EncodeUnsignedLong(*pSpecialCodes))
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
41
MAC_SDK/Source/MACLib/APECompressCore.h
Normal file
41
MAC_SDK/Source/MACLib/APECompressCore.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef APE_APECOMPRESSCORE_H
|
||||
#define APE_APECOMPRESSCORE_H
|
||||
|
||||
#include "APECompress.h"
|
||||
#include "BitArray.h"
|
||||
|
||||
class CPrepare;
|
||||
class IPredictorCompress;
|
||||
|
||||
/*************************************************************************************************
|
||||
CAPECompressCore - manages the core of compression and bitstream output
|
||||
*************************************************************************************************/
|
||||
class CAPECompressCore
|
||||
{
|
||||
public:
|
||||
CAPECompressCore(CIO * pIO, const WAVEFORMATEX * pwfeInput, int nMaxFrameBlocks, int nCompressionLevel);
|
||||
~CAPECompressCore();
|
||||
|
||||
int EncodeFrame(const void * pInputData, int nInputBytes);
|
||||
|
||||
CBitArray * GetBitArray() { return m_spBitArray.GetPtr(); }
|
||||
int GetPeakLevel() { return m_nPeakLevel; }
|
||||
|
||||
private:
|
||||
|
||||
int Prepare(const void * pInputData, int nInputBytes, int * pSpecialCodes);
|
||||
|
||||
CSmartPtr<CBitArray> m_spBitArray;
|
||||
CSmartPtr<IPredictorCompress> m_spPredictorX;
|
||||
CSmartPtr<IPredictorCompress> m_spPredictorY;
|
||||
BIT_ARRAY_STATE m_BitArrayStateX;
|
||||
BIT_ARRAY_STATE m_BitArrayStateY;
|
||||
CSmartPtr<int> m_spDataX;
|
||||
CSmartPtr<int> m_spDataY;
|
||||
CSmartPtr<int> m_spTempData;
|
||||
CSmartPtr<CPrepare> m_spPrepare;
|
||||
WAVEFORMATEX m_wfeInput;
|
||||
int m_nPeakLevel;
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_APECOMPRESSCORE_H
|
||||
218
MAC_SDK/Source/MACLib/APECompressCreate.cpp
Normal file
218
MAC_SDK/Source/MACLib/APECompressCreate.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
#include "All.h"
|
||||
#include "IO.h"
|
||||
#include "APECompressCreate.h"
|
||||
|
||||
#include "APECompressCore.h"
|
||||
|
||||
CAPECompressCreate::CAPECompressCreate()
|
||||
{
|
||||
m_nMaxFrames = 0;
|
||||
}
|
||||
|
||||
CAPECompressCreate::~CAPECompressCreate()
|
||||
{
|
||||
}
|
||||
|
||||
int CAPECompressCreate::Start(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
|
||||
{
|
||||
// verify the parameters
|
||||
if (pioOutput == NULL || pwfeInput == NULL)
|
||||
return ERROR_BAD_PARAMETER;
|
||||
|
||||
// verify the wave format
|
||||
if ((pwfeInput->nChannels != 1) && (pwfeInput->nChannels != 2))
|
||||
{
|
||||
return ERROR_INPUT_FILE_UNSUPPORTED_CHANNEL_COUNT;
|
||||
}
|
||||
if ((pwfeInput->wBitsPerSample != 8) && (pwfeInput->wBitsPerSample != 16) && (pwfeInput->wBitsPerSample != 24))
|
||||
{
|
||||
return ERROR_INPUT_FILE_UNSUPPORTED_BIT_DEPTH;
|
||||
}
|
||||
|
||||
// initialize (creates the base classes)
|
||||
m_nSamplesPerFrame = 73728;
|
||||
if (nCompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH)
|
||||
m_nSamplesPerFrame *= 4;
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_INSANE)
|
||||
m_nSamplesPerFrame *= 16;
|
||||
|
||||
m_spIO.Assign(pioOutput, FALSE, FALSE);
|
||||
m_spAPECompressCore.Assign(new CAPECompressCore(m_spIO, pwfeInput, m_nSamplesPerFrame, nCompressionLevel));
|
||||
|
||||
// copy the format
|
||||
memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
|
||||
|
||||
// the compression level
|
||||
m_nCompressionLevel = nCompressionLevel;
|
||||
m_nFrameIndex = 0;
|
||||
m_nLastFrameBlocks = m_nSamplesPerFrame;
|
||||
|
||||
// initialize the file
|
||||
if (nMaxAudioBytes < 0)
|
||||
nMaxAudioBytes = 2147483647;
|
||||
|
||||
uint32 nMaxAudioBlocks = nMaxAudioBytes / pwfeInput->nBlockAlign;
|
||||
int nMaxFrames = nMaxAudioBlocks / m_nSamplesPerFrame;
|
||||
if ((nMaxAudioBlocks % m_nSamplesPerFrame) != 0) nMaxFrames++;
|
||||
|
||||
InitializeFile(m_spIO, &m_wfeInput, nMaxFrames,
|
||||
m_nCompressionLevel, pHeaderData, nHeaderBytes);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPECompressCreate::GetFullFrameBytes()
|
||||
{
|
||||
return m_nSamplesPerFrame * m_wfeInput.nBlockAlign;
|
||||
}
|
||||
|
||||
int CAPECompressCreate::EncodeFrame(const void * pInputData, int nInputBytes)
|
||||
{
|
||||
int nInputBlocks = nInputBytes / m_wfeInput.nBlockAlign;
|
||||
|
||||
if ((nInputBlocks < m_nSamplesPerFrame) && (m_nLastFrameBlocks < m_nSamplesPerFrame))
|
||||
{
|
||||
return -1; // can only pass a smaller frame for the very last time
|
||||
}
|
||||
|
||||
// update the seek table
|
||||
m_spAPECompressCore->GetBitArray()->AdvanceToByteBoundary();
|
||||
int nRetVal = SetSeekByte(m_nFrameIndex, m_spIO->GetPosition() + (m_spAPECompressCore->GetBitArray()->GetCurrentBitIndex() / 8));
|
||||
if (nRetVal != ERROR_SUCCESS)
|
||||
return nRetVal;
|
||||
|
||||
// compress
|
||||
nRetVal = m_spAPECompressCore->EncodeFrame(pInputData, nInputBytes);
|
||||
|
||||
// update stats
|
||||
m_nLastFrameBlocks = nInputBlocks;
|
||||
m_nFrameIndex++;
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPECompressCreate::Finish(const void * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes)
|
||||
{
|
||||
// clear the bit array
|
||||
RETURN_ON_ERROR(m_spAPECompressCore->GetBitArray()->OutputBitArray(TRUE));
|
||||
|
||||
// finalize the file
|
||||
RETURN_ON_ERROR(FinalizeFile(m_spIO, m_nFrameIndex, m_nLastFrameBlocks,
|
||||
pTerminatingData, nTerminatingBytes, nWAVTerminatingBytes, m_spAPECompressCore->GetPeakLevel()));
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPECompressCreate::SetSeekByte(int nFrame, int nByteOffset)
|
||||
{
|
||||
if (nFrame >= m_nMaxFrames) return ERROR_APE_COMPRESS_TOO_MUCH_DATA;
|
||||
m_spSeekTable[nFrame] = nByteOffset;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPECompressCreate::InitializeFile(CIO * pIO, const WAVEFORMATEX * pwfeInput, int nMaxFrames, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
|
||||
{
|
||||
// error check the parameters
|
||||
if (pIO == NULL || pwfeInput == NULL || nMaxFrames <= 0)
|
||||
return ERROR_BAD_PARAMETER;
|
||||
|
||||
APE_DESCRIPTOR APEDescriptor; memset(&APEDescriptor, 0, sizeof(APEDescriptor));
|
||||
APE_HEADER APEHeader; memset(&APEHeader, 0, sizeof(APEHeader));
|
||||
|
||||
// create the descriptor (only fill what we know)
|
||||
APEDescriptor.cID[0] = 'M';
|
||||
APEDescriptor.cID[1] = 'A';
|
||||
APEDescriptor.cID[2] = 'C';
|
||||
APEDescriptor.cID[3] = ' ';
|
||||
APEDescriptor.nVersion = MAC_VERSION_NUMBER;
|
||||
|
||||
APEDescriptor.nDescriptorBytes = sizeof(APEDescriptor);
|
||||
APEDescriptor.nHeaderBytes = sizeof(APEHeader);
|
||||
APEDescriptor.nSeekTableBytes = nMaxFrames * sizeof(unsigned int);
|
||||
APEDescriptor.nHeaderDataBytes = (nHeaderBytes == CREATE_WAV_HEADER_ON_DECOMPRESSION) ? 0 : nHeaderBytes;
|
||||
|
||||
// create the header (only fill what we know now)
|
||||
APEHeader.nBitsPerSample = pwfeInput->wBitsPerSample;
|
||||
APEHeader.nChannels = pwfeInput->nChannels;
|
||||
APEHeader.nSampleRate = pwfeInput->nSamplesPerSec;
|
||||
|
||||
APEHeader.nCompressionLevel = (uint16) nCompressionLevel;
|
||||
APEHeader.nFormatFlags = (nHeaderBytes == CREATE_WAV_HEADER_ON_DECOMPRESSION) ? MAC_FORMAT_FLAG_CREATE_WAV_HEADER : 0;
|
||||
|
||||
APEHeader.nBlocksPerFrame = m_nSamplesPerFrame;
|
||||
|
||||
// write the data to the file
|
||||
unsigned int nBytesWritten = 0;
|
||||
RETURN_ON_ERROR(pIO->Write(&APEDescriptor, sizeof(APEDescriptor), &nBytesWritten))
|
||||
RETURN_ON_ERROR(pIO->Write(&APEHeader, sizeof(APEHeader), &nBytesWritten))
|
||||
|
||||
// write an empty seek table
|
||||
m_spSeekTable.Assign(new uint32 [nMaxFrames], TRUE);
|
||||
if (m_spSeekTable == NULL) { return ERROR_INSUFFICIENT_MEMORY; }
|
||||
ZeroMemory(m_spSeekTable, nMaxFrames * 4);
|
||||
RETURN_ON_ERROR(pIO->Write(m_spSeekTable, (nMaxFrames * 4), &nBytesWritten))
|
||||
m_nMaxFrames = nMaxFrames;
|
||||
|
||||
// write the WAV data
|
||||
if ((pHeaderData != NULL) && (nHeaderBytes > 0) && (nHeaderBytes != CREATE_WAV_HEADER_ON_DECOMPRESSION))
|
||||
{
|
||||
m_spAPECompressCore->GetBitArray()->GetMD5Helper().AddData(pHeaderData, nHeaderBytes);
|
||||
RETURN_ON_ERROR(pIO->Write((void *) pHeaderData, nHeaderBytes, &nBytesWritten))
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int CAPECompressCreate::FinalizeFile(CIO * pIO, int nNumberOfFrames, int nFinalFrameBlocks, const void * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes, int nPeakLevel)
|
||||
{
|
||||
// store the tail position
|
||||
int nTailPosition = pIO->GetPosition();
|
||||
|
||||
// append the terminating data
|
||||
unsigned int nBytesWritten = 0;
|
||||
unsigned int nBytesRead = 0;
|
||||
int nRetVal = 0;
|
||||
if (nTerminatingBytes > 0)
|
||||
{
|
||||
m_spAPECompressCore->GetBitArray()->GetMD5Helper().AddData(pTerminatingData, nTerminatingBytes);
|
||||
if (pIO->Write((void *) pTerminatingData, nTerminatingBytes, &nBytesWritten) != 0) { return ERROR_IO_WRITE; }
|
||||
}
|
||||
|
||||
// go to the beginning and update the information
|
||||
nRetVal = pIO->Seek(0, FILE_BEGIN);
|
||||
|
||||
// get the descriptor
|
||||
APE_DESCRIPTOR APEDescriptor;
|
||||
nRetVal = pIO->Read(&APEDescriptor, sizeof(APEDescriptor), &nBytesRead);
|
||||
if ((nRetVal != 0) || (nBytesRead != sizeof(APEDescriptor))) { return ERROR_IO_READ; }
|
||||
|
||||
// get the header
|
||||
APE_HEADER APEHeader;
|
||||
nRetVal = pIO->Read(&APEHeader, sizeof(APEHeader), &nBytesRead);
|
||||
if (nRetVal != 0 || nBytesRead != sizeof(APEHeader)) { return ERROR_IO_READ; }
|
||||
|
||||
// update the header
|
||||
APEHeader.nFinalFrameBlocks = nFinalFrameBlocks;
|
||||
APEHeader.nTotalFrames = nNumberOfFrames;
|
||||
|
||||
// update the descriptor
|
||||
APEDescriptor.nAPEFrameDataBytes = nTailPosition - (APEDescriptor.nDescriptorBytes + APEDescriptor.nHeaderBytes + APEDescriptor.nSeekTableBytes + APEDescriptor.nHeaderDataBytes);
|
||||
APEDescriptor.nAPEFrameDataBytesHigh = 0;
|
||||
APEDescriptor.nTerminatingDataBytes = nTerminatingBytes;
|
||||
|
||||
// update the MD5
|
||||
m_spAPECompressCore->GetBitArray()->GetMD5Helper().AddData(&APEHeader, sizeof(APEHeader));
|
||||
m_spAPECompressCore->GetBitArray()->GetMD5Helper().AddData(m_spSeekTable, m_nMaxFrames * 4);
|
||||
m_spAPECompressCore->GetBitArray()->GetMD5Helper().GetResult(APEDescriptor.cFileMD5);
|
||||
|
||||
// set the pointer and re-write the updated header and peak level
|
||||
nRetVal = pIO->Seek(0, FILE_BEGIN);
|
||||
if (pIO->Write(&APEDescriptor, sizeof(APEDescriptor), &nBytesWritten) != 0) { return ERROR_IO_WRITE; }
|
||||
if (pIO->Write(&APEHeader, sizeof(APEHeader), &nBytesWritten) != 0) { return ERROR_IO_WRITE; }
|
||||
|
||||
// write the updated seek table
|
||||
if (pIO->Write(m_spSeekTable, m_nMaxFrames * 4, &nBytesWritten) != 0) { return ERROR_IO_WRITE; }
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
43
MAC_SDK/Source/MACLib/APECompressCreate.h
Normal file
43
MAC_SDK/Source/MACLib/APECompressCreate.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef APE_APECOMPRESSCREATE_H
|
||||
#define APE_APECOMPRESSCREATE_H
|
||||
|
||||
#include "APECompress.h"
|
||||
|
||||
class CAPECompressCore;
|
||||
|
||||
class CAPECompressCreate
|
||||
{
|
||||
public:
|
||||
CAPECompressCreate();
|
||||
~CAPECompressCreate();
|
||||
|
||||
int InitializeFile(CIO * pIO, const WAVEFORMATEX * pwfeInput, int nMaxFrames, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes);
|
||||
int FinalizeFile(CIO * pIO, int nNumberOfFrames, int nFinalFrameBlocks, const void * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes, int nPeakLevel);
|
||||
|
||||
int SetSeekByte(int nFrame, int nByteOffset);
|
||||
|
||||
int Start(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL, const void * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION);
|
||||
|
||||
int GetFullFrameBytes();
|
||||
int EncodeFrame(const void * pInputData, int nInputBytes);
|
||||
|
||||
int Finish(const void * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CSmartPtr<uint32> m_spSeekTable;
|
||||
int m_nMaxFrames;
|
||||
|
||||
CSmartPtr<CIO> m_spIO;
|
||||
CSmartPtr<CAPECompressCore> m_spAPECompressCore;
|
||||
|
||||
WAVEFORMATEX m_wfeInput;
|
||||
int m_nCompressionLevel;
|
||||
int m_nSamplesPerFrame;
|
||||
int m_nFrameIndex;
|
||||
int m_nLastFrameBlocks;
|
||||
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_APECOMPRESSCREATE_H
|
||||
479
MAC_SDK/Source/MACLib/APEDecompress.cpp
Normal file
479
MAC_SDK/Source/MACLib/APEDecompress.cpp
Normal file
@@ -0,0 +1,479 @@
|
||||
#include "All.h"
|
||||
#include "APEDecompress.h"
|
||||
|
||||
#include "APEInfo.h"
|
||||
#include "Prepare.h"
|
||||
#include "UnBitArray.h"
|
||||
#include "NewPredictor.h"
|
||||
|
||||
#define DECODE_BLOCK_SIZE 4096
|
||||
|
||||
CAPEDecompress::CAPEDecompress(int * pErrorCode, CAPEInfo * pAPEInfo, int nStartBlock, int nFinishBlock)
|
||||
{
|
||||
*pErrorCode = ERROR_SUCCESS;
|
||||
|
||||
// open / analyze the file
|
||||
m_spAPEInfo.Assign(pAPEInfo);
|
||||
|
||||
// version check (this implementation only works with 3.93 and later files)
|
||||
if (GetInfo(APE_INFO_FILE_VERSION) < 3930)
|
||||
{
|
||||
*pErrorCode = ERROR_UNDEFINED;
|
||||
return;
|
||||
}
|
||||
|
||||
// get format information
|
||||
GetInfo(APE_INFO_WAVEFORMATEX, (int) &m_wfeInput);
|
||||
m_nBlockAlign = GetInfo(APE_INFO_BLOCK_ALIGN);
|
||||
|
||||
// initialize other stuff
|
||||
m_bDecompressorInitialized = FALSE;
|
||||
m_nCurrentFrame = 0;
|
||||
m_nCurrentBlock = 0;
|
||||
m_nCurrentFrameBufferBlock = 0;
|
||||
m_nFrameBufferFinishedBlocks = 0;
|
||||
m_bErrorDecodingCurrentFrame = FALSE;
|
||||
|
||||
// set the "real" start and finish blocks
|
||||
m_nStartBlock = (nStartBlock < 0) ? 0 : min(nStartBlock, GetInfo(APE_INFO_TOTAL_BLOCKS));
|
||||
m_nFinishBlock = (nFinishBlock < 0) ? GetInfo(APE_INFO_TOTAL_BLOCKS) : min(nFinishBlock, GetInfo(APE_INFO_TOTAL_BLOCKS));
|
||||
m_bIsRanged = (m_nStartBlock != 0) || (m_nFinishBlock != GetInfo(APE_INFO_TOTAL_BLOCKS));
|
||||
}
|
||||
|
||||
CAPEDecompress::~CAPEDecompress()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CAPEDecompress::InitializeDecompressor()
|
||||
{
|
||||
// check if we have anything to do
|
||||
if (m_bDecompressorInitialized)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
// update the initialized flag
|
||||
m_bDecompressorInitialized = TRUE;
|
||||
|
||||
// create a frame buffer
|
||||
m_cbFrameBuffer.CreateBuffer((GetInfo(APE_INFO_BLOCKS_PER_FRAME) + DECODE_BLOCK_SIZE) * m_nBlockAlign, m_nBlockAlign * 64);
|
||||
|
||||
// create decoding components
|
||||
m_spUnBitArray.Assign((CUnBitArrayBase *) CreateUnBitArray(this, GetInfo(APE_INFO_FILE_VERSION)));
|
||||
|
||||
if (GetInfo(APE_INFO_FILE_VERSION) >= 3950)
|
||||
{
|
||||
m_spNewPredictorX.Assign(new CPredictorDecompress3950toCurrent(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
|
||||
m_spNewPredictorY.Assign(new CPredictorDecompress3950toCurrent(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spNewPredictorX.Assign(new CPredictorDecompressNormal3930to3950(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
|
||||
m_spNewPredictorY.Assign(new CPredictorDecompressNormal3930to3950(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
|
||||
}
|
||||
|
||||
// seek to the beginning
|
||||
return Seek(0);
|
||||
}
|
||||
|
||||
int CAPEDecompress::GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved)
|
||||
{
|
||||
int nRetVal = ERROR_SUCCESS;
|
||||
if (pBlocksRetrieved) *pBlocksRetrieved = 0;
|
||||
|
||||
// make sure we're initialized
|
||||
RETURN_ON_ERROR(InitializeDecompressor())
|
||||
|
||||
// cap
|
||||
int nBlocksUntilFinish = m_nFinishBlock - m_nCurrentBlock;
|
||||
const int nBlocksToRetrieve = min(nBlocks, nBlocksUntilFinish);
|
||||
|
||||
// get the data
|
||||
unsigned char * pOutputBuffer = (unsigned char *) pBuffer;
|
||||
int nBlocksLeft = nBlocksToRetrieve; int nBlocksThisPass = 1;
|
||||
while ((nBlocksLeft > 0) && (nBlocksThisPass > 0))
|
||||
{
|
||||
// fill up the frame buffer
|
||||
int nDecodeRetVal = FillFrameBuffer();
|
||||
if (nDecodeRetVal != ERROR_SUCCESS)
|
||||
nRetVal = nDecodeRetVal;
|
||||
|
||||
// analyze how much to remove from the buffer
|
||||
const int nFrameBufferBlocks = m_nFrameBufferFinishedBlocks;
|
||||
nBlocksThisPass = min(nBlocksLeft, nFrameBufferBlocks);
|
||||
|
||||
// remove as much as possible
|
||||
if (nBlocksThisPass > 0)
|
||||
{
|
||||
m_cbFrameBuffer.Get(pOutputBuffer, nBlocksThisPass * m_nBlockAlign);
|
||||
pOutputBuffer += nBlocksThisPass * m_nBlockAlign;
|
||||
nBlocksLeft -= nBlocksThisPass;
|
||||
m_nFrameBufferFinishedBlocks -= nBlocksThisPass;
|
||||
}
|
||||
}
|
||||
|
||||
// calculate the blocks retrieved
|
||||
int nBlocksRetrieved = nBlocksToRetrieve - nBlocksLeft;
|
||||
|
||||
// update position
|
||||
m_nCurrentBlock += nBlocksRetrieved;
|
||||
if (pBlocksRetrieved) *pBlocksRetrieved = nBlocksRetrieved;
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPEDecompress::Seek(int nBlockOffset)
|
||||
{
|
||||
RETURN_ON_ERROR(InitializeDecompressor())
|
||||
|
||||
// use the offset
|
||||
nBlockOffset += m_nStartBlock;
|
||||
|
||||
// cap (to prevent seeking too far)
|
||||
if (nBlockOffset >= m_nFinishBlock)
|
||||
nBlockOffset = m_nFinishBlock - 1;
|
||||
if (nBlockOffset < m_nStartBlock)
|
||||
nBlockOffset = m_nStartBlock;
|
||||
|
||||
// seek to the perfect location
|
||||
int nBaseFrame = nBlockOffset / GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nBlocksToSkip = nBlockOffset % GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nBytesToSkip = nBlocksToSkip * m_nBlockAlign;
|
||||
|
||||
m_nCurrentBlock = nBaseFrame * GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
m_nCurrentFrameBufferBlock = nBaseFrame * GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
m_nCurrentFrame = nBaseFrame;
|
||||
m_nFrameBufferFinishedBlocks = 0;
|
||||
m_cbFrameBuffer.Empty();
|
||||
RETURN_ON_ERROR(SeekToFrame(m_nCurrentFrame));
|
||||
|
||||
// skip necessary blocks
|
||||
CSmartPtr<char> spTempBuffer(new char [nBytesToSkip], TRUE);
|
||||
if (spTempBuffer == NULL) return ERROR_INSUFFICIENT_MEMORY;
|
||||
|
||||
int nBlocksRetrieved = 0;
|
||||
GetData(spTempBuffer, nBlocksToSkip, &nBlocksRetrieved);
|
||||
if (nBlocksRetrieved != nBlocksToSkip)
|
||||
return ERROR_UNDEFINED;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Decodes blocks of data
|
||||
*****************************************************************************************/
|
||||
int CAPEDecompress::FillFrameBuffer()
|
||||
{
|
||||
int nRetVal = ERROR_SUCCESS;
|
||||
|
||||
// determine the maximum blocks we can decode
|
||||
// note that we won't do end capping because we can't use data
|
||||
// until EndFrame(...) successfully handles the frame
|
||||
// that means we may decode a little extra in end capping cases
|
||||
// but this allows robust error handling of bad frames
|
||||
int nMaxBlocks = m_cbFrameBuffer.MaxAdd() / m_nBlockAlign;
|
||||
|
||||
// loop and decode data
|
||||
int nBlocksLeft = nMaxBlocks;
|
||||
while (nBlocksLeft > 0)
|
||||
{
|
||||
int nFrameBlocks = GetInfo(APE_INFO_FRAME_BLOCKS, m_nCurrentFrame);
|
||||
if (nFrameBlocks < 0)
|
||||
break;
|
||||
|
||||
int nFrameOffsetBlocks = m_nCurrentFrameBufferBlock % GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nFrameBlocksLeft = nFrameBlocks - nFrameOffsetBlocks;
|
||||
int nBlocksThisPass = min(nFrameBlocksLeft, nBlocksLeft);
|
||||
|
||||
// start the frame if we need to
|
||||
if (nFrameOffsetBlocks == 0)
|
||||
StartFrame();
|
||||
|
||||
// store the frame buffer bytes before we start
|
||||
int nFrameBufferBytes = m_cbFrameBuffer.MaxGet();
|
||||
|
||||
// decode data
|
||||
DecodeBlocksToFrameBuffer(nBlocksThisPass);
|
||||
|
||||
// end the frame if we need to
|
||||
if ((nFrameOffsetBlocks + nBlocksThisPass) >= nFrameBlocks)
|
||||
{
|
||||
EndFrame();
|
||||
if (m_bErrorDecodingCurrentFrame)
|
||||
{
|
||||
// remove any decoded data from the buffer
|
||||
m_cbFrameBuffer.RemoveTail(m_cbFrameBuffer.MaxGet() - nFrameBufferBytes);
|
||||
|
||||
// add silence
|
||||
unsigned char cSilence = (GetInfo(APE_INFO_BITS_PER_SAMPLE) == 8) ? 127 : 0;
|
||||
for (int z = 0; z < nFrameBlocks * m_nBlockAlign; z++)
|
||||
{
|
||||
*m_cbFrameBuffer.GetDirectWritePointer() = cSilence;
|
||||
m_cbFrameBuffer.UpdateAfterDirectWrite(1);
|
||||
}
|
||||
|
||||
// seek to try to synchronize after an error
|
||||
SeekToFrame(m_nCurrentFrame);
|
||||
|
||||
// save the return value
|
||||
nRetVal = ERROR_INVALID_CHECKSUM;
|
||||
}
|
||||
}
|
||||
|
||||
nBlocksLeft -= nBlocksThisPass;
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
void CAPEDecompress::DecodeBlocksToFrameBuffer(int nBlocks)
|
||||
{
|
||||
// decode the samples
|
||||
int nBlocksProcessed = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if (m_wfeInput.nChannels == 2)
|
||||
{
|
||||
if ((m_nSpecialCodes & SPECIAL_FRAME_LEFT_SILENCE) &&
|
||||
(m_nSpecialCodes & SPECIAL_FRAME_RIGHT_SILENCE))
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
|
||||
{
|
||||
m_Prepare.Unprepare(0, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
|
||||
m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
|
||||
}
|
||||
}
|
||||
else if (m_nSpecialCodes & SPECIAL_FRAME_PSEUDO_STEREO)
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
|
||||
{
|
||||
int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
|
||||
m_Prepare.Unprepare(X, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
|
||||
m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_spAPEInfo->GetInfo(APE_INFO_FILE_VERSION) >= 3950)
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
|
||||
{
|
||||
int nY = m_spUnBitArray->DecodeValueRange(m_BitArrayStateY);
|
||||
int nX = m_spUnBitArray->DecodeValueRange(m_BitArrayStateX);
|
||||
int Y = m_spNewPredictorY->DecompressValue(nY, m_nLastX);
|
||||
int X = m_spNewPredictorX->DecompressValue(nX, Y);
|
||||
m_nLastX = X;
|
||||
|
||||
m_Prepare.Unprepare(X, Y, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
|
||||
m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
|
||||
{
|
||||
int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
|
||||
int Y = m_spNewPredictorY->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateY));
|
||||
|
||||
m_Prepare.Unprepare(X, Y, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
|
||||
m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_nSpecialCodes & SPECIAL_FRAME_MONO_SILENCE)
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
|
||||
{
|
||||
m_Prepare.Unprepare(0, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
|
||||
m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
|
||||
{
|
||||
int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
|
||||
m_Prepare.Unprepare(X, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
|
||||
m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
m_bErrorDecodingCurrentFrame = TRUE;
|
||||
}
|
||||
|
||||
m_nCurrentFrameBufferBlock += nBlocks;
|
||||
}
|
||||
|
||||
void CAPEDecompress::StartFrame()
|
||||
{
|
||||
m_nCRC = 0xFFFFFFFF;
|
||||
|
||||
// get the frame header
|
||||
m_nStoredCRC = m_spUnBitArray->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_INT);
|
||||
m_bErrorDecodingCurrentFrame = FALSE;
|
||||
|
||||
// get any 'special' codes if the file uses them (for silence, FALSE stereo, etc.)
|
||||
m_nSpecialCodes = 0;
|
||||
if (GET_USES_SPECIAL_FRAMES(m_spAPEInfo))
|
||||
{
|
||||
if (m_nStoredCRC & 0x80000000)
|
||||
{
|
||||
m_nSpecialCodes = m_spUnBitArray->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_INT);
|
||||
}
|
||||
m_nStoredCRC &= 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
m_spNewPredictorX->Flush();
|
||||
m_spNewPredictorY->Flush();
|
||||
|
||||
m_spUnBitArray->FlushState(m_BitArrayStateX);
|
||||
m_spUnBitArray->FlushState(m_BitArrayStateY);
|
||||
|
||||
m_spUnBitArray->FlushBitArray();
|
||||
|
||||
m_nLastX = 0;
|
||||
}
|
||||
|
||||
void CAPEDecompress::EndFrame()
|
||||
{
|
||||
m_nFrameBufferFinishedBlocks += GetInfo(APE_INFO_FRAME_BLOCKS, m_nCurrentFrame);
|
||||
m_nCurrentFrame++;
|
||||
|
||||
// finalize
|
||||
m_spUnBitArray->Finalize();
|
||||
|
||||
// check the CRC
|
||||
m_nCRC = m_nCRC ^ 0xFFFFFFFF;
|
||||
m_nCRC >>= 1;
|
||||
if (m_nCRC != m_nStoredCRC)
|
||||
m_bErrorDecodingCurrentFrame = TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Seek to the proper frame (if necessary) and do any alignment of the bit array
|
||||
*****************************************************************************************/
|
||||
int CAPEDecompress::SeekToFrame(int nFrameIndex)
|
||||
{
|
||||
int nSeekRemainder = (GetInfo(APE_INFO_SEEK_BYTE, nFrameIndex) - GetInfo(APE_INFO_SEEK_BYTE, 0)) % 4;
|
||||
return m_spUnBitArray->FillAndResetBitArray(GetInfo(APE_INFO_SEEK_BYTE, nFrameIndex) - nSeekRemainder, nSeekRemainder * 8);
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Get information from the decompressor
|
||||
*****************************************************************************************/
|
||||
int CAPEDecompress::GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1, int nParam2)
|
||||
{
|
||||
int nRetVal = 0;
|
||||
BOOL bHandled = TRUE;
|
||||
|
||||
switch (Field)
|
||||
{
|
||||
case APE_DECOMPRESS_CURRENT_BLOCK:
|
||||
nRetVal = m_nCurrentBlock - m_nStartBlock;
|
||||
break;
|
||||
case APE_DECOMPRESS_CURRENT_MS:
|
||||
{
|
||||
int nSampleRate = m_spAPEInfo->GetInfo(APE_INFO_SAMPLE_RATE, 0, 0);
|
||||
if (nSampleRate > 0)
|
||||
nRetVal = int((double(m_nCurrentBlock) * double(1000)) / double(nSampleRate));
|
||||
break;
|
||||
}
|
||||
case APE_DECOMPRESS_TOTAL_BLOCKS:
|
||||
nRetVal = m_nFinishBlock - m_nStartBlock;
|
||||
break;
|
||||
case APE_DECOMPRESS_LENGTH_MS:
|
||||
{
|
||||
int nSampleRate = m_spAPEInfo->GetInfo(APE_INFO_SAMPLE_RATE, 0, 0);
|
||||
if (nSampleRate > 0)
|
||||
nRetVal = int((double(m_nFinishBlock - m_nStartBlock) * double(1000)) / double(nSampleRate));
|
||||
break;
|
||||
}
|
||||
case APE_DECOMPRESS_CURRENT_BITRATE:
|
||||
nRetVal = GetInfo(APE_INFO_FRAME_BITRATE, m_nCurrentFrame);
|
||||
break;
|
||||
case APE_DECOMPRESS_AVERAGE_BITRATE:
|
||||
{
|
||||
if (m_bIsRanged)
|
||||
{
|
||||
// figure the frame range
|
||||
const int nBlocksPerFrame = GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nStartFrame = m_nStartBlock / nBlocksPerFrame;
|
||||
int nFinishFrame = (m_nFinishBlock + nBlocksPerFrame - 1) / nBlocksPerFrame;
|
||||
|
||||
// get the number of bytes in the first and last frame
|
||||
int nTotalBytes = (GetInfo(APE_INFO_FRAME_BYTES, nStartFrame) * (m_nStartBlock % nBlocksPerFrame)) / nBlocksPerFrame;
|
||||
if (nFinishFrame != nStartFrame)
|
||||
nTotalBytes += (GetInfo(APE_INFO_FRAME_BYTES, nFinishFrame) * (m_nFinishBlock % nBlocksPerFrame)) / nBlocksPerFrame;
|
||||
|
||||
// get the number of bytes in between
|
||||
const int nTotalFrames = GetInfo(APE_INFO_TOTAL_FRAMES);
|
||||
for (int nFrame = nStartFrame + 1; (nFrame < nFinishFrame) && (nFrame < nTotalFrames); nFrame++)
|
||||
nTotalBytes += GetInfo(APE_INFO_FRAME_BYTES, nFrame);
|
||||
|
||||
// figure the bitrate
|
||||
int nTotalMS = int((double(m_nFinishBlock - m_nStartBlock) * double(1000)) / double(GetInfo(APE_INFO_SAMPLE_RATE)));
|
||||
if (nTotalMS != 0)
|
||||
nRetVal = (nTotalBytes * 8) / nTotalMS;
|
||||
}
|
||||
else
|
||||
{
|
||||
nRetVal = GetInfo(APE_INFO_AVERAGE_BITRATE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
bHandled = FALSE;
|
||||
}
|
||||
|
||||
if (!bHandled && m_bIsRanged)
|
||||
{
|
||||
bHandled = TRUE;
|
||||
|
||||
switch (Field)
|
||||
{
|
||||
case APE_INFO_WAV_HEADER_BYTES:
|
||||
nRetVal = sizeof(WAVE_HEADER);
|
||||
break;
|
||||
case APE_INFO_WAV_HEADER_DATA:
|
||||
{
|
||||
char * pBuffer = (char *) nParam1;
|
||||
int nMaxBytes = nParam2;
|
||||
|
||||
if (sizeof(WAVE_HEADER) > nMaxBytes)
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WAVEFORMATEX wfeFormat; GetInfo(APE_INFO_WAVEFORMATEX, (int) &wfeFormat, 0);
|
||||
WAVE_HEADER WAVHeader; FillWaveHeader(&WAVHeader,
|
||||
(m_nFinishBlock - m_nStartBlock) * GetInfo(APE_INFO_BLOCK_ALIGN),
|
||||
&wfeFormat, 0);
|
||||
memcpy(pBuffer, &WAVHeader, sizeof(WAVE_HEADER));
|
||||
nRetVal = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_WAV_TERMINATING_BYTES:
|
||||
nRetVal = 0;
|
||||
break;
|
||||
case APE_INFO_WAV_TERMINATING_DATA:
|
||||
nRetVal = 0;
|
||||
break;
|
||||
default:
|
||||
bHandled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (bHandled == FALSE)
|
||||
nRetVal = m_spAPEInfo->GetInfo(Field, nParam1, nParam2);
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
72
MAC_SDK/Source/MACLib/APEDecompress.h
Normal file
72
MAC_SDK/Source/MACLib/APEDecompress.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#ifndef APE_APEDECOMPRESS_H
|
||||
#define APE_APEDECOMPRESS_H
|
||||
|
||||
#include "APEDecompress.h"
|
||||
|
||||
class CUnBitArray;
|
||||
class CPrepare;
|
||||
class CAPEInfo;
|
||||
class IPredictorDecompress;
|
||||
#include "UnBitArrayBase.h"
|
||||
#include "MACLib.h"
|
||||
#include "Prepare.h"
|
||||
#include "CircleBuffer.h"
|
||||
|
||||
class CAPEDecompress : public IAPEDecompress
|
||||
{
|
||||
public:
|
||||
|
||||
CAPEDecompress(int * pErrorCode, CAPEInfo * pAPEInfo, int nStartBlock = -1, int nFinishBlock = -1);
|
||||
~CAPEDecompress();
|
||||
|
||||
int GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved);
|
||||
int Seek(int nBlockOffset);
|
||||
|
||||
int GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1 = 0, int nParam2 = 0);
|
||||
|
||||
protected:
|
||||
|
||||
// file info
|
||||
int m_nBlockAlign;
|
||||
int m_nCurrentFrame;
|
||||
|
||||
// start / finish information
|
||||
int m_nStartBlock;
|
||||
int m_nFinishBlock;
|
||||
int m_nCurrentBlock;
|
||||
BOOL m_bIsRanged;
|
||||
BOOL m_bDecompressorInitialized;
|
||||
|
||||
// decoding tools
|
||||
CPrepare m_Prepare;
|
||||
WAVEFORMATEX m_wfeInput;
|
||||
unsigned int m_nCRC;
|
||||
unsigned int m_nStoredCRC;
|
||||
int m_nSpecialCodes;
|
||||
|
||||
int SeekToFrame(int nFrameIndex);
|
||||
void DecodeBlocksToFrameBuffer(int nBlocks);
|
||||
int FillFrameBuffer();
|
||||
void StartFrame();
|
||||
void EndFrame();
|
||||
int InitializeDecompressor();
|
||||
|
||||
// more decoding components
|
||||
CSmartPtr<CAPEInfo> m_spAPEInfo;
|
||||
CSmartPtr<CUnBitArrayBase> m_spUnBitArray;
|
||||
UNBIT_ARRAY_STATE m_BitArrayStateX;
|
||||
UNBIT_ARRAY_STATE m_BitArrayStateY;
|
||||
|
||||
CSmartPtr<IPredictorDecompress> m_spNewPredictorX;
|
||||
CSmartPtr<IPredictorDecompress> m_spNewPredictorY;
|
||||
|
||||
int m_nLastX;
|
||||
|
||||
// decoding buffer
|
||||
BOOL m_bErrorDecodingCurrentFrame;
|
||||
int m_nCurrentFrameBufferBlock;
|
||||
int m_nFrameBufferFinishedBlocks;
|
||||
CCircleBuffer m_cbFrameBuffer;
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_APEDECOMPRESS_H
|
||||
280
MAC_SDK/Source/MACLib/APEHeader.cpp
Normal file
280
MAC_SDK/Source/MACLib/APEHeader.cpp
Normal file
@@ -0,0 +1,280 @@
|
||||
#include "All.h"
|
||||
#include "APEHeader.h"
|
||||
#include "MACLib.h"
|
||||
#include "APEInfo.h"
|
||||
|
||||
// TODO: should push and pop the file position
|
||||
|
||||
CAPEHeader::CAPEHeader(CIO * pIO)
|
||||
{
|
||||
m_pIO = pIO;
|
||||
}
|
||||
|
||||
CAPEHeader::~CAPEHeader()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CAPEHeader::FindDescriptor(BOOL bSeek)
|
||||
{
|
||||
// store the original location and seek to the beginning
|
||||
int nOriginalFileLocation = m_pIO->GetPosition();
|
||||
m_pIO->Seek(0, FILE_BEGIN);
|
||||
|
||||
// set the default junk bytes to 0
|
||||
int nJunkBytes = 0;
|
||||
|
||||
// skip an ID3v2 tag (which we really don't support anyway...)
|
||||
unsigned int nBytesRead = 0;
|
||||
unsigned char cID3v2Header[10];
|
||||
m_pIO->Read((unsigned char *) cID3v2Header, 10, &nBytesRead);
|
||||
if (cID3v2Header[0] == 'I' && cID3v2Header[1] == 'D' && cID3v2Header[2] == '3')
|
||||
{
|
||||
// why is it so hard to figure the lenght of an ID3v2 tag ?!?
|
||||
unsigned int nLength = *((unsigned int *) &cID3v2Header[6]);
|
||||
|
||||
unsigned int nSyncSafeLength = 0;
|
||||
nSyncSafeLength = (cID3v2Header[6] & 127) << 21;
|
||||
nSyncSafeLength += (cID3v2Header[7] & 127) << 14;
|
||||
nSyncSafeLength += (cID3v2Header[8] & 127) << 7;
|
||||
nSyncSafeLength += (cID3v2Header[9] & 127);
|
||||
|
||||
BOOL bHasTagFooter = FALSE;
|
||||
|
||||
if (cID3v2Header[5] & 16)
|
||||
{
|
||||
bHasTagFooter = TRUE;
|
||||
nJunkBytes = nSyncSafeLength + 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
nJunkBytes = nSyncSafeLength + 10;
|
||||
}
|
||||
|
||||
// error check
|
||||
if (cID3v2Header[5] & 64)
|
||||
{
|
||||
// this ID3v2 length calculator algorithm can't cope with extended headers
|
||||
// we should be ok though, because the scan for the MAC header below should
|
||||
// really do the trick
|
||||
}
|
||||
|
||||
m_pIO->Seek(nJunkBytes, FILE_BEGIN);
|
||||
|
||||
// scan for padding (slow and stupid, but who cares here...)
|
||||
if (!bHasTagFooter)
|
||||
{
|
||||
char cTemp = 0;
|
||||
m_pIO->Read((unsigned char *) &cTemp, 1, &nBytesRead);
|
||||
while (cTemp == 0 && nBytesRead == 1)
|
||||
{
|
||||
nJunkBytes++;
|
||||
m_pIO->Read((unsigned char *) &cTemp, 1, &nBytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_pIO->Seek(nJunkBytes, FILE_BEGIN);
|
||||
|
||||
// scan until we hit the APE_DESCRIPTOR, the end of the file, or 1 MB later
|
||||
unsigned int nGoalID = (' ' << 24) | ('C' << 16) | ('A' << 8) | ('M');
|
||||
unsigned int nReadID = 0;
|
||||
int nRetVal = m_pIO->Read(&nReadID, 4, &nBytesRead);
|
||||
if (nRetVal != 0 || nBytesRead != 4) return ERROR_UNDEFINED;
|
||||
|
||||
nBytesRead = 1;
|
||||
int nScanBytes = 0;
|
||||
while ((nGoalID != nReadID) && (nBytesRead == 1) && (nScanBytes < (1024 * 1024)))
|
||||
{
|
||||
unsigned char cTemp;
|
||||
m_pIO->Read(&cTemp, 1, &nBytesRead);
|
||||
nReadID = (((unsigned int) cTemp) << 24) | (nReadID >> 8);
|
||||
nJunkBytes++;
|
||||
nScanBytes++;
|
||||
}
|
||||
|
||||
if (nGoalID != nReadID)
|
||||
nJunkBytes = -1;
|
||||
|
||||
// seek to the proper place (depending on result and settings)
|
||||
if (bSeek && (nJunkBytes != -1))
|
||||
{
|
||||
// successfully found the start of the file (seek to it and return)
|
||||
m_pIO->Seek(nJunkBytes, FILE_BEGIN);
|
||||
}
|
||||
else
|
||||
{
|
||||
// restore the original file pointer
|
||||
m_pIO->Seek(nOriginalFileLocation, FILE_BEGIN);
|
||||
}
|
||||
|
||||
return nJunkBytes;
|
||||
}
|
||||
|
||||
int CAPEHeader::Analyze(APE_FILE_INFO * pInfo)
|
||||
{
|
||||
// error check
|
||||
if ((m_pIO == NULL) || (pInfo == NULL))
|
||||
return ERROR_INVALID_PARAMETER;
|
||||
|
||||
// variables
|
||||
unsigned int nBytesRead = 0;
|
||||
|
||||
// find the descriptor
|
||||
pInfo->nJunkHeaderBytes = FindDescriptor(TRUE);
|
||||
if (pInfo->nJunkHeaderBytes < 0)
|
||||
return ERROR_UNDEFINED;
|
||||
|
||||
// read the first 8 bytes of the descriptor (ID and version)
|
||||
APE_COMMON_HEADER CommonHeader; memset(&CommonHeader, 0, sizeof(APE_COMMON_HEADER));
|
||||
m_pIO->Read(&CommonHeader, sizeof(APE_COMMON_HEADER), &nBytesRead);
|
||||
|
||||
// make sure we're at the ID
|
||||
if (CommonHeader.cID[0] != 'M' || CommonHeader.cID[1] != 'A' || CommonHeader.cID[2] != 'C' || CommonHeader.cID[3] != ' ')
|
||||
return ERROR_UNDEFINED;
|
||||
|
||||
int nRetVal = ERROR_UNDEFINED;
|
||||
|
||||
if (CommonHeader.nVersion >= 3980)
|
||||
{
|
||||
// current header format
|
||||
nRetVal = AnalyzeCurrent(pInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// legacy support
|
||||
nRetVal = AnalyzeOld(pInfo);
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPEHeader::AnalyzeCurrent(APE_FILE_INFO * pInfo)
|
||||
{
|
||||
// variable declares
|
||||
unsigned int nBytesRead = 0;
|
||||
pInfo->spAPEDescriptor.Assign(new APE_DESCRIPTOR); memset(pInfo->spAPEDescriptor, 0, sizeof(APE_DESCRIPTOR));
|
||||
APE_HEADER APEHeader; memset(&APEHeader, 0, sizeof(APEHeader));
|
||||
|
||||
// read the descriptor
|
||||
m_pIO->Seek(pInfo->nJunkHeaderBytes, FILE_BEGIN);
|
||||
m_pIO->Read(pInfo->spAPEDescriptor, sizeof(APE_DESCRIPTOR), &nBytesRead);
|
||||
|
||||
if ((pInfo->spAPEDescriptor->nDescriptorBytes - nBytesRead) > 0)
|
||||
m_pIO->Seek(pInfo->spAPEDescriptor->nDescriptorBytes - nBytesRead, FILE_CURRENT);
|
||||
|
||||
// read the header
|
||||
m_pIO->Read(&APEHeader, sizeof(APEHeader), &nBytesRead);
|
||||
|
||||
if ((pInfo->spAPEDescriptor->nHeaderBytes - nBytesRead) > 0)
|
||||
m_pIO->Seek(pInfo->spAPEDescriptor->nHeaderBytes - nBytesRead, FILE_CURRENT);
|
||||
|
||||
// fill the APE info structure
|
||||
pInfo->nVersion = int(pInfo->spAPEDescriptor->nVersion);
|
||||
pInfo->nCompressionLevel = int(APEHeader.nCompressionLevel);
|
||||
pInfo->nFormatFlags = int(APEHeader.nFormatFlags);
|
||||
pInfo->nTotalFrames = int(APEHeader.nTotalFrames);
|
||||
pInfo->nFinalFrameBlocks = int(APEHeader.nFinalFrameBlocks);
|
||||
pInfo->nBlocksPerFrame = int(APEHeader.nBlocksPerFrame);
|
||||
pInfo->nChannels = int(APEHeader.nChannels);
|
||||
pInfo->nSampleRate = int(APEHeader.nSampleRate);
|
||||
pInfo->nBitsPerSample = int(APEHeader.nBitsPerSample);
|
||||
pInfo->nBytesPerSample = pInfo->nBitsPerSample / 8;
|
||||
pInfo->nBlockAlign = pInfo->nBytesPerSample * pInfo->nChannels;
|
||||
pInfo->nTotalBlocks = (APEHeader.nTotalFrames == 0) ? 0 : ((APEHeader.nTotalFrames - 1) * pInfo->nBlocksPerFrame) + APEHeader.nFinalFrameBlocks;
|
||||
pInfo->nWAVHeaderBytes = (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER) ? sizeof(WAVE_HEADER) : pInfo->spAPEDescriptor->nHeaderDataBytes;
|
||||
pInfo->nWAVTerminatingBytes = pInfo->spAPEDescriptor->nTerminatingDataBytes;
|
||||
pInfo->nWAVDataBytes = pInfo->nTotalBlocks * pInfo->nBlockAlign;
|
||||
pInfo->nWAVTotalBytes = pInfo->nWAVDataBytes + pInfo->nWAVHeaderBytes + pInfo->nWAVTerminatingBytes;
|
||||
pInfo->nAPETotalBytes = m_pIO->GetSize();
|
||||
pInfo->nLengthMS = int((double(pInfo->nTotalBlocks) * double(1000)) / double(pInfo->nSampleRate));
|
||||
pInfo->nAverageBitrate = (pInfo->nLengthMS <= 0) ? 0 : int((double(pInfo->nAPETotalBytes) * double(8)) / double(pInfo->nLengthMS));
|
||||
pInfo->nDecompressedBitrate = (pInfo->nBlockAlign * pInfo->nSampleRate * 8) / 1000;
|
||||
pInfo->nSeekTableElements = pInfo->spAPEDescriptor->nSeekTableBytes / 4;
|
||||
|
||||
// get the seek tables (really no reason to get the whole thing if there's extra)
|
||||
pInfo->spSeekByteTable.Assign(new uint32 [pInfo->nSeekTableElements], TRUE);
|
||||
if (pInfo->spSeekByteTable == NULL) { return ERROR_UNDEFINED; }
|
||||
|
||||
m_pIO->Read((unsigned char *) pInfo->spSeekByteTable.GetPtr(), 4 * pInfo->nSeekTableElements, &nBytesRead);
|
||||
|
||||
// get the wave header
|
||||
if (!(APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER))
|
||||
{
|
||||
pInfo->spWaveHeaderData.Assign(new unsigned char [pInfo->nWAVHeaderBytes], TRUE);
|
||||
if (pInfo->spWaveHeaderData == NULL) { return ERROR_UNDEFINED; }
|
||||
m_pIO->Read((unsigned char *) pInfo->spWaveHeaderData, pInfo->nWAVHeaderBytes, &nBytesRead);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPEHeader::AnalyzeOld(APE_FILE_INFO * pInfo)
|
||||
{
|
||||
// variable declares
|
||||
unsigned int nBytesRead = 0;
|
||||
|
||||
// read the MAC header from the file
|
||||
APE_HEADER_OLD APEHeader;
|
||||
m_pIO->Seek(pInfo->nJunkHeaderBytes, FILE_BEGIN);
|
||||
m_pIO->Read((unsigned char *) &APEHeader, sizeof(APEHeader), &nBytesRead);
|
||||
|
||||
// fail on 0 length APE files (catches non-finalized APE files)
|
||||
if (APEHeader.nTotalFrames == 0)
|
||||
return ERROR_UNDEFINED;
|
||||
|
||||
int nPeakLevel = -1;
|
||||
if (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL)
|
||||
m_pIO->Read((unsigned char *) &nPeakLevel, 4, &nBytesRead);
|
||||
|
||||
if (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS)
|
||||
m_pIO->Read((unsigned char *) &pInfo->nSeekTableElements, 4, &nBytesRead);
|
||||
else
|
||||
pInfo->nSeekTableElements = APEHeader.nTotalFrames;
|
||||
|
||||
// fill the APE info structure
|
||||
pInfo->nVersion = int(APEHeader.nVersion);
|
||||
pInfo->nCompressionLevel = int(APEHeader.nCompressionLevel);
|
||||
pInfo->nFormatFlags = int(APEHeader.nFormatFlags);
|
||||
pInfo->nTotalFrames = int(APEHeader.nTotalFrames);
|
||||
pInfo->nFinalFrameBlocks = int(APEHeader.nFinalFrameBlocks);
|
||||
pInfo->nBlocksPerFrame = ((APEHeader.nVersion >= 3900) || ((APEHeader.nVersion >= 3800) && (APEHeader.nCompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH))) ? 73728 : 9216;
|
||||
if ((APEHeader.nVersion >= 3950)) pInfo->nBlocksPerFrame = 73728 * 4;
|
||||
pInfo->nChannels = int(APEHeader.nChannels);
|
||||
pInfo->nSampleRate = int(APEHeader.nSampleRate);
|
||||
pInfo->nBitsPerSample = (pInfo->nFormatFlags & MAC_FORMAT_FLAG_8_BIT) ? 8 : ((pInfo->nFormatFlags & MAC_FORMAT_FLAG_24_BIT) ? 24 : 16);
|
||||
pInfo->nBytesPerSample = pInfo->nBitsPerSample / 8;
|
||||
pInfo->nBlockAlign = pInfo->nBytesPerSample * pInfo->nChannels;
|
||||
pInfo->nTotalBlocks = (APEHeader.nTotalFrames == 0) ? 0 : ((APEHeader.nTotalFrames - 1) * pInfo->nBlocksPerFrame) + APEHeader.nFinalFrameBlocks;
|
||||
pInfo->nWAVHeaderBytes = (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER) ? sizeof(WAVE_HEADER) : APEHeader.nHeaderBytes;
|
||||
pInfo->nWAVTerminatingBytes = int(APEHeader.nTerminatingBytes);
|
||||
pInfo->nWAVDataBytes = pInfo->nTotalBlocks * pInfo->nBlockAlign;
|
||||
pInfo->nWAVTotalBytes = pInfo->nWAVDataBytes + pInfo->nWAVHeaderBytes + pInfo->nWAVTerminatingBytes;
|
||||
pInfo->nAPETotalBytes = m_pIO->GetSize();
|
||||
pInfo->nLengthMS = int((double(pInfo->nTotalBlocks) * double(1000)) / double(pInfo->nSampleRate));
|
||||
pInfo->nAverageBitrate = (pInfo->nLengthMS <= 0) ? 0 : int((double(pInfo->nAPETotalBytes) * double(8)) / double(pInfo->nLengthMS));
|
||||
pInfo->nDecompressedBitrate = (pInfo->nBlockAlign * pInfo->nSampleRate * 8) / 1000;
|
||||
|
||||
// get the wave header
|
||||
if (!(APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER))
|
||||
{
|
||||
pInfo->spWaveHeaderData.Assign(new unsigned char [APEHeader.nHeaderBytes], TRUE);
|
||||
if (pInfo->spWaveHeaderData == NULL) { return ERROR_UNDEFINED; }
|
||||
m_pIO->Read((unsigned char *) pInfo->spWaveHeaderData, APEHeader.nHeaderBytes, &nBytesRead);
|
||||
}
|
||||
|
||||
// get the seek tables (really no reason to get the whole thing if there's extra)
|
||||
pInfo->spSeekByteTable.Assign(new uint32 [pInfo->nSeekTableElements], TRUE);
|
||||
if (pInfo->spSeekByteTable == NULL) { return ERROR_UNDEFINED; }
|
||||
|
||||
m_pIO->Read((unsigned char *) pInfo->spSeekByteTable.GetPtr(), 4 * pInfo->nSeekTableElements, &nBytesRead);
|
||||
|
||||
if (APEHeader.nVersion <= 3800)
|
||||
{
|
||||
pInfo->spSeekBitTable.Assign(new unsigned char [pInfo->nSeekTableElements], TRUE);
|
||||
if (pInfo->spSeekBitTable == NULL) { return ERROR_UNDEFINED; }
|
||||
|
||||
m_pIO->Read((unsigned char *) pInfo->spSeekBitTable, pInfo->nSeekTableElements, &nBytesRead);
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
57
MAC_SDK/Source/MACLib/APEHeader.h
Normal file
57
MAC_SDK/Source/MACLib/APEHeader.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#ifndef APE_HEADER_H
|
||||
#define APE_HEADER_H
|
||||
|
||||
/*****************************************************************************************
|
||||
APE header that all APE files have in common (old and new)
|
||||
*****************************************************************************************/
|
||||
struct APE_COMMON_HEADER
|
||||
{
|
||||
char cID[4]; // should equal 'MAC '
|
||||
uint16 nVersion; // version number * 1000 (3.81 = 3810)
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
APE header structure for old APE files (3.97 and earlier)
|
||||
*****************************************************************************************/
|
||||
struct APE_HEADER_OLD
|
||||
{
|
||||
char cID[4]; // should equal 'MAC '
|
||||
uint16 nVersion; // version number * 1000 (3.81 = 3810)
|
||||
uint16 nCompressionLevel; // the compression level
|
||||
uint16 nFormatFlags; // any format flags (for future use)
|
||||
uint16 nChannels; // the number of channels (1 or 2)
|
||||
uint32 nSampleRate; // the sample rate (typically 44100)
|
||||
uint32 nHeaderBytes; // the bytes after the MAC header that compose the WAV header
|
||||
uint32 nTerminatingBytes; // the bytes after that raw data (for extended info)
|
||||
uint32 nTotalFrames; // the number of frames in the file
|
||||
uint32 nFinalFrameBlocks; // the number of samples in the final frame
|
||||
};
|
||||
|
||||
struct APE_FILE_INFO;
|
||||
class CIO;
|
||||
|
||||
/*****************************************************************************************
|
||||
CAPEHeader - makes managing APE headers a little smoother (and the format change as of 3.98)
|
||||
*****************************************************************************************/
|
||||
class CAPEHeader
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
CAPEHeader(CIO * pIO);
|
||||
~CAPEHeader();
|
||||
|
||||
int Analyze(APE_FILE_INFO * pInfo);
|
||||
|
||||
protected:
|
||||
|
||||
int AnalyzeCurrent(APE_FILE_INFO * pInfo);
|
||||
int AnalyzeOld(APE_FILE_INFO * pInfo);
|
||||
|
||||
int FindDescriptor(BOOL bSeek);
|
||||
|
||||
CIO * m_pIO;
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_HEADER_H
|
||||
|
||||
361
MAC_SDK/Source/MACLib/APEInfo.cpp
Normal file
361
MAC_SDK/Source/MACLib/APEInfo.cpp
Normal file
@@ -0,0 +1,361 @@
|
||||
/*****************************************************************************************
|
||||
CAPEInfo:
|
||||
-a class to make working with APE files and getting information about them simple
|
||||
*****************************************************************************************/
|
||||
#include "All.h"
|
||||
#include "APEInfo.h"
|
||||
#include IO_HEADER_FILE
|
||||
#include "APECompress.h"
|
||||
#include "APEHeader.h"
|
||||
|
||||
/*****************************************************************************************
|
||||
Construction
|
||||
*****************************************************************************************/
|
||||
CAPEInfo::CAPEInfo(int * pErrorCode, const wchar_t * pFilename, CAPETag * pTag)
|
||||
{
|
||||
*pErrorCode = ERROR_SUCCESS;
|
||||
CloseFile();
|
||||
|
||||
// open the file
|
||||
m_spIO.Assign(new IO_CLASS_NAME);
|
||||
|
||||
if (m_spIO->Open(pFilename) != 0)
|
||||
{
|
||||
CloseFile();
|
||||
*pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return;
|
||||
}
|
||||
|
||||
// get the file information
|
||||
if (GetFileInformation(TRUE) != 0)
|
||||
{
|
||||
CloseFile();
|
||||
*pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return;
|
||||
}
|
||||
|
||||
// get the tag (do this second so that we don't do it on failure)
|
||||
if (pTag == NULL)
|
||||
{
|
||||
// we don't want to analyze right away for non-local files
|
||||
// since a single I/O object is shared, we can't tag and read at the same time (i.e. in multiple threads)
|
||||
BOOL bAnalyzeNow = TRUE;
|
||||
if ((wcsnicmp(pFilename, L"http://", 7) == 0) || (wcsnicmp(pFilename, L"m01p://", 7) == 0))
|
||||
bAnalyzeNow = FALSE;
|
||||
|
||||
m_spAPETag.Assign(new CAPETag(m_spIO, bAnalyzeNow));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spAPETag.Assign(pTag);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CAPEInfo::CAPEInfo(int * pErrorCode, CIO * pIO, CAPETag * pTag)
|
||||
{
|
||||
*pErrorCode = ERROR_SUCCESS;
|
||||
CloseFile();
|
||||
|
||||
m_spIO.Assign(pIO, FALSE, FALSE);
|
||||
|
||||
// get the file information
|
||||
if (GetFileInformation(TRUE) != 0)
|
||||
{
|
||||
CloseFile();
|
||||
*pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return;
|
||||
}
|
||||
|
||||
// get the tag (do this second so that we don't do it on failure)
|
||||
if (pTag == NULL)
|
||||
m_spAPETag.Assign(new CAPETag(m_spIO, TRUE));
|
||||
else
|
||||
m_spAPETag.Assign(pTag);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
Destruction
|
||||
*****************************************************************************************/
|
||||
CAPEInfo::~CAPEInfo()
|
||||
{
|
||||
CloseFile();
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Close the file
|
||||
*****************************************************************************************/
|
||||
int CAPEInfo::CloseFile()
|
||||
{
|
||||
m_spIO.Delete();
|
||||
m_APEFileInfo.spWaveHeaderData.Delete();
|
||||
m_APEFileInfo.spSeekBitTable.Delete();
|
||||
m_APEFileInfo.spSeekByteTable.Delete();
|
||||
m_APEFileInfo.spAPEDescriptor.Delete();
|
||||
|
||||
m_spAPETag.Delete();
|
||||
|
||||
// re-initialize variables
|
||||
m_APEFileInfo.nSeekTableElements = 0;
|
||||
m_bHasFileInformationLoaded = FALSE;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Get the file information about the file
|
||||
*****************************************************************************************/
|
||||
int CAPEInfo::GetFileInformation(BOOL bGetTagInformation)
|
||||
{
|
||||
// quit if there is no simple file
|
||||
if (m_spIO == NULL) { return -1; }
|
||||
|
||||
// quit if the file information has already been loaded
|
||||
if (m_bHasFileInformationLoaded) { return ERROR_SUCCESS; }
|
||||
|
||||
// use a CAPEHeader class to help us analyze the file
|
||||
CAPEHeader APEHeader(m_spIO);
|
||||
int nRetVal = APEHeader.Analyze(&m_APEFileInfo);
|
||||
|
||||
// update our internal state
|
||||
if (nRetVal == ERROR_SUCCESS)
|
||||
m_bHasFileInformationLoaded = TRUE;
|
||||
|
||||
// return
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Primary query function
|
||||
*****************************************************************************************/
|
||||
int CAPEInfo::GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1, int nParam2)
|
||||
{
|
||||
int nRetVal = -1;
|
||||
|
||||
switch (Field)
|
||||
{
|
||||
case APE_INFO_FILE_VERSION:
|
||||
nRetVal = m_APEFileInfo.nVersion;
|
||||
break;
|
||||
case APE_INFO_COMPRESSION_LEVEL:
|
||||
nRetVal = m_APEFileInfo.nCompressionLevel;
|
||||
break;
|
||||
case APE_INFO_FORMAT_FLAGS:
|
||||
nRetVal = m_APEFileInfo.nFormatFlags;
|
||||
break;
|
||||
case APE_INFO_SAMPLE_RATE:
|
||||
nRetVal = m_APEFileInfo.nSampleRate;
|
||||
break;
|
||||
case APE_INFO_BITS_PER_SAMPLE:
|
||||
nRetVal = m_APEFileInfo.nBitsPerSample;
|
||||
break;
|
||||
case APE_INFO_BYTES_PER_SAMPLE:
|
||||
nRetVal = m_APEFileInfo.nBytesPerSample;
|
||||
break;
|
||||
case APE_INFO_CHANNELS:
|
||||
nRetVal = m_APEFileInfo.nChannels;
|
||||
break;
|
||||
case APE_INFO_BLOCK_ALIGN:
|
||||
nRetVal = m_APEFileInfo.nBlockAlign;
|
||||
break;
|
||||
case APE_INFO_BLOCKS_PER_FRAME:
|
||||
nRetVal = m_APEFileInfo.nBlocksPerFrame;
|
||||
break;
|
||||
case APE_INFO_FINAL_FRAME_BLOCKS:
|
||||
nRetVal = m_APEFileInfo.nFinalFrameBlocks;
|
||||
break;
|
||||
case APE_INFO_TOTAL_FRAMES:
|
||||
nRetVal = m_APEFileInfo.nTotalFrames;
|
||||
break;
|
||||
case APE_INFO_WAV_HEADER_BYTES:
|
||||
nRetVal = m_APEFileInfo.nWAVHeaderBytes;
|
||||
break;
|
||||
case APE_INFO_WAV_TERMINATING_BYTES:
|
||||
nRetVal = m_APEFileInfo.nWAVTerminatingBytes;
|
||||
break;
|
||||
case APE_INFO_WAV_DATA_BYTES:
|
||||
nRetVal = m_APEFileInfo.nWAVDataBytes;
|
||||
break;
|
||||
case APE_INFO_WAV_TOTAL_BYTES:
|
||||
nRetVal = m_APEFileInfo.nWAVTotalBytes;
|
||||
break;
|
||||
case APE_INFO_APE_TOTAL_BYTES:
|
||||
nRetVal = m_APEFileInfo.nAPETotalBytes;
|
||||
break;
|
||||
case APE_INFO_TOTAL_BLOCKS:
|
||||
nRetVal = m_APEFileInfo.nTotalBlocks;
|
||||
break;
|
||||
case APE_INFO_LENGTH_MS:
|
||||
nRetVal = m_APEFileInfo.nLengthMS;
|
||||
break;
|
||||
case APE_INFO_AVERAGE_BITRATE:
|
||||
nRetVal = m_APEFileInfo.nAverageBitrate;
|
||||
break;
|
||||
case APE_INFO_FRAME_BITRATE:
|
||||
{
|
||||
int nFrame = nParam1;
|
||||
|
||||
nRetVal = 0;
|
||||
|
||||
int nFrameBytes = GetInfo(APE_INFO_FRAME_BYTES, nFrame);
|
||||
int nFrameBlocks = GetInfo(APE_INFO_FRAME_BLOCKS, nFrame);
|
||||
if ((nFrameBytes > 0) && (nFrameBlocks > 0) && m_APEFileInfo.nSampleRate > 0)
|
||||
{
|
||||
int nFrameMS = (nFrameBlocks * 1000) / m_APEFileInfo.nSampleRate;
|
||||
if (nFrameMS != 0)
|
||||
{
|
||||
nRetVal = (nFrameBytes * 8) / nFrameMS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_DECOMPRESSED_BITRATE:
|
||||
nRetVal = m_APEFileInfo.nDecompressedBitrate;
|
||||
break;
|
||||
case APE_INFO_PEAK_LEVEL:
|
||||
nRetVal = -1; // no longer supported
|
||||
break;
|
||||
case APE_INFO_SEEK_BIT:
|
||||
{
|
||||
int nFrame = nParam1;
|
||||
if (GET_FRAMES_START_ON_BYTES_BOUNDARIES(this))
|
||||
{
|
||||
nRetVal = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nFrame < 0 || nFrame >= m_APEFileInfo.nTotalFrames)
|
||||
nRetVal = 0;
|
||||
else
|
||||
nRetVal = m_APEFileInfo.spSeekBitTable[nFrame];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_SEEK_BYTE:
|
||||
{
|
||||
int nFrame = nParam1;
|
||||
if (nFrame < 0 || nFrame >= m_APEFileInfo.nTotalFrames)
|
||||
nRetVal = 0;
|
||||
else
|
||||
nRetVal = m_APEFileInfo.spSeekByteTable[nFrame] + m_APEFileInfo.nJunkHeaderBytes;
|
||||
break;
|
||||
}
|
||||
case APE_INFO_WAV_HEADER_DATA:
|
||||
{
|
||||
char * pBuffer = (char *) nParam1;
|
||||
int nMaxBytes = nParam2;
|
||||
|
||||
if (m_APEFileInfo.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER)
|
||||
{
|
||||
if (sizeof(WAVE_HEADER) > nMaxBytes)
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WAVEFORMATEX wfeFormat; GetInfo(APE_INFO_WAVEFORMATEX, (int) &wfeFormat, 0);
|
||||
WAVE_HEADER WAVHeader; FillWaveHeader(&WAVHeader, m_APEFileInfo.nWAVDataBytes, &wfeFormat,
|
||||
m_APEFileInfo.nWAVTerminatingBytes);
|
||||
memcpy(pBuffer, &WAVHeader, sizeof(WAVE_HEADER));
|
||||
nRetVal = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_APEFileInfo.nWAVHeaderBytes > nMaxBytes)
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pBuffer, m_APEFileInfo.spWaveHeaderData, m_APEFileInfo.nWAVHeaderBytes);
|
||||
nRetVal = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_WAV_TERMINATING_DATA:
|
||||
{
|
||||
char * pBuffer = (char *) nParam1;
|
||||
int nMaxBytes = nParam2;
|
||||
|
||||
if (m_APEFileInfo.nWAVTerminatingBytes > nMaxBytes)
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_APEFileInfo.nWAVTerminatingBytes > 0)
|
||||
{
|
||||
// variables
|
||||
int nOriginalFileLocation = m_spIO->GetPosition();
|
||||
unsigned int nBytesRead = 0;
|
||||
|
||||
// check for a tag
|
||||
m_spIO->Seek(-(m_spAPETag->GetTagBytes() + m_APEFileInfo.nWAVTerminatingBytes), FILE_END);
|
||||
m_spIO->Read(pBuffer, m_APEFileInfo.nWAVTerminatingBytes, &nBytesRead);
|
||||
|
||||
// restore the file pointer
|
||||
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
|
||||
}
|
||||
nRetVal = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_WAVEFORMATEX:
|
||||
{
|
||||
WAVEFORMATEX * pWaveFormatEx = (WAVEFORMATEX *) nParam1;
|
||||
FillWaveFormatEx(pWaveFormatEx, m_APEFileInfo.nSampleRate, m_APEFileInfo.nBitsPerSample, m_APEFileInfo.nChannels);
|
||||
nRetVal = 0;
|
||||
break;
|
||||
}
|
||||
case APE_INFO_IO_SOURCE:
|
||||
nRetVal = (int) m_spIO.GetPtr();
|
||||
break;
|
||||
case APE_INFO_FRAME_BYTES:
|
||||
{
|
||||
int nFrame = nParam1;
|
||||
|
||||
// bound-check the frame index
|
||||
if ((nFrame < 0) || (nFrame >= m_APEFileInfo.nTotalFrames))
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nFrame != (m_APEFileInfo.nTotalFrames - 1))
|
||||
nRetVal = GetInfo(APE_INFO_SEEK_BYTE, nFrame + 1) - GetInfo(APE_INFO_SEEK_BYTE, nFrame);
|
||||
else
|
||||
nRetVal = m_spIO->GetSize() - m_spAPETag->GetTagBytes() - m_APEFileInfo.nWAVTerminatingBytes - GetInfo(APE_INFO_SEEK_BYTE, nFrame);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_FRAME_BLOCKS:
|
||||
{
|
||||
int nFrame = nParam1;
|
||||
|
||||
// bound-check the frame index
|
||||
if ((nFrame < 0) || (nFrame >= m_APEFileInfo.nTotalFrames))
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nFrame != (m_APEFileInfo.nTotalFrames - 1))
|
||||
nRetVal = m_APEFileInfo.nBlocksPerFrame;
|
||||
else
|
||||
nRetVal = m_APEFileInfo.nFinalFrameBlocks;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_TAG:
|
||||
nRetVal = (int) m_spAPETag.GetPtr();
|
||||
break;
|
||||
case APE_INTERNAL_INFO:
|
||||
nRetVal = (int) &m_APEFileInfo;
|
||||
break;
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
100
MAC_SDK/Source/MACLib/APEInfo.h
Normal file
100
MAC_SDK/Source/MACLib/APEInfo.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*****************************************************************************************
|
||||
APEInfo.h
|
||||
Copyright (C) 2000 by Matthew T. Ashland All Rights Reserved.
|
||||
|
||||
Simple method for working with APE files... it encapsulates reading, writing and getting
|
||||
file information. Just create a CAPEInfo class, call OpenFile(), and use the class methods
|
||||
to do whatever you need... the destructor will take care of any cleanup
|
||||
|
||||
Notes:
|
||||
-Most all functions return 0 upon success, and some error code (other than 0) on
|
||||
failure. However, all of the file functions that are wrapped from the Win32 API
|
||||
return 0 on failure and some other number on success. This applies to ReadFile,
|
||||
WriteFile, SetFilePointer, etc...
|
||||
|
||||
WARNING:
|
||||
-This class driven system for using Monkey's Audio is still in development, so
|
||||
I can't make any guarantees that the classes and libraries won't change before
|
||||
everything gets finalized. Use them at your own risk
|
||||
*****************************************************************************************/
|
||||
|
||||
#ifndef APE_APEINFO_H
|
||||
#define APE_APEINFO_H
|
||||
|
||||
#include "IO.h"
|
||||
#include "APETag.h"
|
||||
#include "MACLib.h"
|
||||
|
||||
/*****************************************************************************************
|
||||
APE_FILE_INFO - structure which describes most aspects of an APE file
|
||||
(used internally for speed and ease)
|
||||
*****************************************************************************************/
|
||||
struct APE_FILE_INFO
|
||||
{
|
||||
int nVersion; // file version number * 1000 (3.93 = 3930)
|
||||
int nCompressionLevel; // the compression level
|
||||
int nFormatFlags; // format flags
|
||||
int nTotalFrames; // the total number frames (frames are used internally)
|
||||
int nBlocksPerFrame; // the samples in a frame (frames are used internally)
|
||||
int nFinalFrameBlocks; // the number of samples in the final frame
|
||||
int nChannels; // audio channels
|
||||
int nSampleRate; // audio samples per second
|
||||
int nBitsPerSample; // audio bits per sample
|
||||
int nBytesPerSample; // audio bytes per sample
|
||||
int nBlockAlign; // audio block align (channels * bytes per sample)
|
||||
int nWAVHeaderBytes; // header bytes of the original WAV
|
||||
int nWAVDataBytes; // data bytes of the original WAV
|
||||
int nWAVTerminatingBytes; // terminating bytes of the original WAV
|
||||
int nWAVTotalBytes; // total bytes of the original WAV
|
||||
int nAPETotalBytes; // total bytes of the APE file
|
||||
int nTotalBlocks; // the total number audio blocks
|
||||
int nLengthMS; // the length in milliseconds
|
||||
int nAverageBitrate; // the kbps (i.e. 637 kpbs)
|
||||
int nDecompressedBitrate; // the kbps of the decompressed audio (i.e. 1440 kpbs for CD audio)
|
||||
int nJunkHeaderBytes; // used for ID3v2, etc.
|
||||
int nSeekTableElements; // the number of elements in the seek table(s)
|
||||
|
||||
CSmartPtr<uint32> spSeekByteTable; // the seek table (byte)
|
||||
CSmartPtr<unsigned char> spSeekBitTable; // the seek table (bits -- legacy)
|
||||
CSmartPtr<unsigned char> spWaveHeaderData; // the pre-audio header data
|
||||
CSmartPtr<APE_DESCRIPTOR> spAPEDescriptor; // the descriptor (only with newer files)
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Helper macros (sort of hacky)
|
||||
*****************************************************************************************/
|
||||
#define GET_USES_CRC(APE_INFO) (((APE_INFO)->GetInfo(APE_INFO_FORMAT_FLAGS) & MAC_FORMAT_FLAG_CRC) ? TRUE : FALSE)
|
||||
#define GET_FRAMES_START_ON_BYTES_BOUNDARIES(APE_INFO) (((APE_INFO)->GetInfo(APE_INFO_FILE_VERSION) > 3800) ? TRUE : FALSE)
|
||||
#define GET_USES_SPECIAL_FRAMES(APE_INFO) (((APE_INFO)->GetInfo(APE_INFO_FILE_VERSION) > 3820) ? TRUE : FALSE)
|
||||
#define GET_IO(APE_INFO) ((CIO *) (APE_INFO)->GetInfo(APE_INFO_IO_SOURCE))
|
||||
#define GET_TAG(APE_INFO) ((CAPETag *) (APE_INFO)->GetInfo(APE_INFO_TAG))
|
||||
|
||||
/*****************************************************************************************
|
||||
CAPEInfo - use this for all work with APE files
|
||||
*****************************************************************************************/
|
||||
class CAPEInfo
|
||||
{
|
||||
public:
|
||||
|
||||
// construction and destruction
|
||||
CAPEInfo(int * pErrorCode, const wchar_t * pFilename, CAPETag * pTag = NULL);
|
||||
CAPEInfo(int * pErrorCode, CIO * pIO, CAPETag * pTag = NULL);
|
||||
virtual ~CAPEInfo();
|
||||
|
||||
// query for information
|
||||
int GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1 = 0, int nParam2 = 0);
|
||||
|
||||
private:
|
||||
|
||||
// internal functions
|
||||
int GetFileInformation(BOOL bGetTagInformation = TRUE);
|
||||
int CloseFile();
|
||||
|
||||
// internal variables
|
||||
BOOL m_bHasFileInformationLoaded;
|
||||
CSmartPtr<CIO> m_spIO;
|
||||
CSmartPtr<CAPETag> m_spAPETag;
|
||||
APE_FILE_INFO m_APEFileInfo;
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_APEINFO_H
|
||||
120
MAC_SDK/Source/MACLib/APELink.cpp
Normal file
120
MAC_SDK/Source/MACLib/APELink.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
#include "All.h"
|
||||
#include "APELink.h"
|
||||
#include "CharacterHelper.h"
|
||||
#include IO_HEADER_FILE
|
||||
|
||||
#define APE_LINK_HEADER "[Monkey's Audio Image Link File]"
|
||||
#define APE_LINK_IMAGE_FILE_TAG "Image File="
|
||||
#define APE_LINK_START_BLOCK_TAG "Start Block="
|
||||
#define APE_LINK_FINISH_BLOCK_TAG "Finish Block="
|
||||
|
||||
CAPELink::CAPELink(const str_utf16 * pFilename)
|
||||
{
|
||||
// empty
|
||||
m_bIsLinkFile = FALSE;
|
||||
m_nStartBlock = 0;
|
||||
m_nFinishBlock = 0;
|
||||
m_cImageFilename[0] = 0;
|
||||
|
||||
// open the file
|
||||
IO_CLASS_NAME ioLinkFile;
|
||||
if (ioLinkFile.Open(pFilename) == ERROR_SUCCESS)
|
||||
{
|
||||
// create a buffer
|
||||
CSmartPtr<char> spBuffer(new char [1024], TRUE);
|
||||
|
||||
// fill the buffer from the file and null terminate it
|
||||
unsigned int nBytesRead = 0;
|
||||
ioLinkFile.Read(spBuffer.GetPtr(), 1023, &nBytesRead);
|
||||
spBuffer[nBytesRead] = 0;
|
||||
|
||||
// call the other constructor (uses a buffer instead of opening the file)
|
||||
ParseData(spBuffer, pFilename);
|
||||
}
|
||||
}
|
||||
|
||||
CAPELink::CAPELink(const char * pData, const str_utf16 * pFilename)
|
||||
{
|
||||
ParseData(pData, pFilename);
|
||||
}
|
||||
|
||||
CAPELink::~CAPELink()
|
||||
{
|
||||
}
|
||||
|
||||
void CAPELink::ParseData(const char * pData, const str_utf16 * pFilename)
|
||||
{
|
||||
// empty
|
||||
m_bIsLinkFile = FALSE;
|
||||
m_nStartBlock = 0;
|
||||
m_nFinishBlock = 0;
|
||||
m_cImageFilename[0] = 0;
|
||||
|
||||
if (pData != NULL)
|
||||
{
|
||||
// parse out the information
|
||||
char * pHeader = (char*)strstr(pData, APE_LINK_HEADER);
|
||||
char * pImageFile = (char*)strstr(pData, APE_LINK_IMAGE_FILE_TAG);
|
||||
char * pStartBlock = (char*)strstr(pData, APE_LINK_START_BLOCK_TAG);
|
||||
char * pFinishBlock = (char*)strstr(pData, APE_LINK_FINISH_BLOCK_TAG);
|
||||
|
||||
if (pHeader && pImageFile && pStartBlock && pFinishBlock)
|
||||
{
|
||||
if ((_strnicmp(pHeader, APE_LINK_HEADER, strlen(APE_LINK_HEADER)) == 0) &&
|
||||
(_strnicmp(pImageFile, APE_LINK_IMAGE_FILE_TAG, strlen(APE_LINK_IMAGE_FILE_TAG)) == 0) &&
|
||||
(_strnicmp(pStartBlock, APE_LINK_START_BLOCK_TAG, strlen(APE_LINK_START_BLOCK_TAG)) == 0) &&
|
||||
(_strnicmp(pFinishBlock, APE_LINK_FINISH_BLOCK_TAG, strlen(APE_LINK_FINISH_BLOCK_TAG)) == 0))
|
||||
{
|
||||
// get the start and finish blocks
|
||||
m_nStartBlock = atoi(&pStartBlock[strlen(APE_LINK_START_BLOCK_TAG)]);
|
||||
m_nFinishBlock = atoi(&pFinishBlock[strlen(APE_LINK_FINISH_BLOCK_TAG)]);
|
||||
|
||||
// get the path
|
||||
char cImageFile[MAX_PATH + 1]; int nIndex = 0;
|
||||
char * pImageCharacter = &pImageFile[strlen(APE_LINK_IMAGE_FILE_TAG)];
|
||||
while ((*pImageCharacter != 0) && (*pImageCharacter != '\r') && (*pImageCharacter != '\n'))
|
||||
cImageFile[nIndex++] = *pImageCharacter++;
|
||||
cImageFile[nIndex] = 0;
|
||||
|
||||
CSmartPtr<str_utf16> spImageFileUTF16(GetUTF16FromUTF8((UCHAR *) cImageFile), TRUE);
|
||||
|
||||
// process the path
|
||||
if (wcsrchr(spImageFileUTF16, '\\') == NULL)
|
||||
{
|
||||
str_utf16 cImagePath[MAX_PATH + 1];
|
||||
wcscpy(cImagePath, pFilename);
|
||||
wcscpy(wcsrchr(cImagePath, '\\') + 1, spImageFileUTF16);
|
||||
wcscpy(m_cImageFilename, cImagePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
wcscpy(m_cImageFilename, spImageFileUTF16);
|
||||
}
|
||||
|
||||
// this is a valid link file
|
||||
m_bIsLinkFile = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CAPELink::GetStartBlock()
|
||||
{
|
||||
return m_nStartBlock;
|
||||
}
|
||||
|
||||
int CAPELink::GetFinishBlock()
|
||||
{
|
||||
return m_nFinishBlock;
|
||||
}
|
||||
|
||||
const str_utf16 * CAPELink::GetImageFilename()
|
||||
{
|
||||
return m_cImageFilename;
|
||||
}
|
||||
|
||||
BOOL CAPELink::GetIsLinkFile()
|
||||
{
|
||||
return m_bIsLinkFile;
|
||||
}
|
||||
|
||||
30
MAC_SDK/Source/MACLib/APELink.h
Normal file
30
MAC_SDK/Source/MACLib/APELink.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef APE_APELINK_H
|
||||
#define APE_APELINK_H
|
||||
|
||||
#include "IO.h"
|
||||
#include "APEInfo.h"
|
||||
|
||||
class CAPELink
|
||||
{
|
||||
public:
|
||||
|
||||
CAPELink(const str_utf16 * pFilename);
|
||||
CAPELink(const char * pData, const str_utf16 * pFilename);
|
||||
~CAPELink();
|
||||
|
||||
BOOL GetIsLinkFile();
|
||||
int GetStartBlock();
|
||||
int GetFinishBlock();
|
||||
const wchar_t * GetImageFilename();
|
||||
|
||||
protected:
|
||||
|
||||
BOOL m_bIsLinkFile;
|
||||
int m_nStartBlock;
|
||||
int m_nFinishBlock;
|
||||
str_utf16 m_cImageFilename[MAX_PATH];
|
||||
|
||||
void ParseData(const char * pData, const str_utf16 * pFilename);
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_APELINK_H
|
||||
426
MAC_SDK/Source/MACLib/APESimple.cpp
Normal file
426
MAC_SDK/Source/MACLib/APESimple.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
#include "All.h"
|
||||
#include "APEInfo.h"
|
||||
#include "APECompress.h"
|
||||
#include "APEDecompress.h"
|
||||
#include "WAVInputSource.h"
|
||||
#include IO_HEADER_FILE
|
||||
#include "MACProgressHelper.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "MD5.h"
|
||||
#include "CharacterHelper.h"
|
||||
|
||||
#define UNMAC_DECODER_OUTPUT_NONE 0
|
||||
#define UNMAC_DECODER_OUTPUT_WAV 1
|
||||
#define UNMAC_DECODER_OUTPUT_APE 2
|
||||
|
||||
#define BLOCKS_PER_DECODE 9216
|
||||
|
||||
int DecompressCore(const str_utf16 * pInputFilename, const str_utf16 * pOutputFilename, int nOutputMode, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
||||
|
||||
/*****************************************************************************************
|
||||
ANSI wrappers
|
||||
*****************************************************************************************/
|
||||
int __stdcall CompressFile(const str_ansi * pInputFilename, const str_ansi * pOutputFilename, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
CSmartPtr<str_utf16> spInputFile(GetUTF16FromANSI(pInputFilename), TRUE);
|
||||
CSmartPtr<str_utf16> spOutputFile(GetUTF16FromANSI(pOutputFilename), TRUE);
|
||||
return CompressFileW(spInputFile, spOutputFile, nCompressionLevel, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
}
|
||||
|
||||
int __stdcall DecompressFile(const str_ansi * pInputFilename, const str_ansi * pOutputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
CSmartPtr<str_utf16> spInputFile(GetUTF16FromANSI(pInputFilename), TRUE);
|
||||
CSmartPtr<str_utf16> spOutputFile(GetUTF16FromANSI(pOutputFilename), TRUE);
|
||||
return DecompressFileW(spInputFile, pOutputFilename ? spOutputFile : NULL, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
}
|
||||
|
||||
int __stdcall ConvertFile(const str_ansi * pInputFilename, const str_ansi * pOutputFilename, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
CSmartPtr<str_utf16> spInputFile(GetUTF16FromANSI(pInputFilename), TRUE);
|
||||
CSmartPtr<str_utf16> spOutputFile(GetUTF16FromANSI(pOutputFilename), TRUE);
|
||||
return ConvertFileW(spInputFile, spOutputFile, nCompressionLevel, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
}
|
||||
|
||||
int __stdcall VerifyFile(const str_ansi * pInputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag, BOOL bQuickVerifyIfPossible)
|
||||
{
|
||||
CSmartPtr<str_utf16> spInputFile(GetUTF16FromANSI(pInputFilename), TRUE);
|
||||
return VerifyFileW(spInputFile, pPercentageDone, ProgressCallback, pKillFlag, FALSE);
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Compress file
|
||||
*****************************************************************************************/
|
||||
int __stdcall CompressFileW(const str_utf16 * pInputFilename, const str_utf16 * pOutputFilename, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
// declare the variables
|
||||
int nFunctionRetVal = ERROR_SUCCESS;
|
||||
WAVEFORMATEX WaveFormatEx;
|
||||
CSmartPtr<CMACProgressHelper> spMACProgressHelper;
|
||||
CSmartPtr<unsigned char> spBuffer;
|
||||
CSmartPtr<IAPECompress> spAPECompress;
|
||||
|
||||
try
|
||||
{
|
||||
// create the input source
|
||||
int nRetVal = ERROR_UNDEFINED;
|
||||
int nAudioBlocks = 0; int nHeaderBytes = 0; int nTerminatingBytes = 0;
|
||||
CSmartPtr<CInputSource> spInputSource(CreateInputSource(pInputFilename, &WaveFormatEx, &nAudioBlocks,
|
||||
&nHeaderBytes, &nTerminatingBytes, &nRetVal));
|
||||
|
||||
if ((spInputSource == NULL) || (nRetVal != ERROR_SUCCESS))
|
||||
throw nRetVal;
|
||||
|
||||
// create the compressor
|
||||
spAPECompress.Assign(CreateIAPECompress());
|
||||
if (spAPECompress == NULL) throw ERROR_UNDEFINED;
|
||||
|
||||
// figure the audio bytes
|
||||
int nAudioBytes = nAudioBlocks * WaveFormatEx.nBlockAlign;
|
||||
|
||||
// start the encoder
|
||||
if (nHeaderBytes > 0) spBuffer.Assign(new unsigned char [nHeaderBytes], TRUE);
|
||||
THROW_ON_ERROR(spInputSource->GetHeaderData(spBuffer.GetPtr()))
|
||||
THROW_ON_ERROR(spAPECompress->Start(pOutputFilename, &WaveFormatEx, nAudioBytes,
|
||||
nCompressionLevel, spBuffer.GetPtr(), nHeaderBytes));
|
||||
|
||||
spBuffer.Delete();
|
||||
|
||||
// set-up the progress
|
||||
spMACProgressHelper.Assign(new CMACProgressHelper(nAudioBytes, pPercentageDone, ProgressCallback, pKillFlag));
|
||||
|
||||
// master loop
|
||||
int nBytesLeft = nAudioBytes;
|
||||
|
||||
while (nBytesLeft > 0)
|
||||
{
|
||||
int nBytesAdded = 0;
|
||||
THROW_ON_ERROR(spAPECompress->AddDataFromInputSource(spInputSource.GetPtr(), nBytesLeft, &nBytesAdded))
|
||||
|
||||
nBytesLeft -= nBytesAdded;
|
||||
|
||||
// update the progress
|
||||
spMACProgressHelper->UpdateProgress(nAudioBytes - nBytesLeft);
|
||||
|
||||
// process the kill flag
|
||||
if (spMACProgressHelper->ProcessKillFlag(TRUE) != ERROR_SUCCESS)
|
||||
throw(ERROR_USER_STOPPED_PROCESSING);
|
||||
}
|
||||
|
||||
// finalize the file
|
||||
if (nTerminatingBytes > 0) spBuffer.Assign(new unsigned char [nTerminatingBytes], TRUE);
|
||||
THROW_ON_ERROR(spInputSource->GetTerminatingData(spBuffer.GetPtr()));
|
||||
THROW_ON_ERROR(spAPECompress->Finish(spBuffer.GetPtr(), nTerminatingBytes, nTerminatingBytes))
|
||||
|
||||
// update the progress to 100%
|
||||
spMACProgressHelper->UpdateProgressComplete();
|
||||
}
|
||||
catch(int nErrorCode)
|
||||
{
|
||||
nFunctionRetVal = (nErrorCode == 0) ? ERROR_UNDEFINED : nErrorCode;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
nFunctionRetVal = ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
// kill the compressor if we failed
|
||||
if ((nFunctionRetVal != 0) && (spAPECompress != NULL))
|
||||
spAPECompress->Kill();
|
||||
|
||||
// return
|
||||
return nFunctionRetVal;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
Verify file
|
||||
*****************************************************************************************/
|
||||
int __stdcall VerifyFileW(const str_utf16 * pInputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag, BOOL bQuickVerifyIfPossible)
|
||||
{
|
||||
// error check the function parameters
|
||||
if (pInputFilename == NULL)
|
||||
{
|
||||
return ERROR_INVALID_FUNCTION_PARAMETER;
|
||||
}
|
||||
|
||||
|
||||
// return value
|
||||
int nRetVal = ERROR_UNDEFINED;
|
||||
|
||||
// see if we can quick verify
|
||||
if (bQuickVerifyIfPossible)
|
||||
{
|
||||
CSmartPtr<IAPEDecompress> spAPEDecompress;
|
||||
try
|
||||
{
|
||||
int nFunctionRetVal = ERROR_SUCCESS;
|
||||
|
||||
spAPEDecompress.Assign(CreateIAPEDecompress(pInputFilename, &nFunctionRetVal));
|
||||
if (spAPEDecompress == NULL || nFunctionRetVal != ERROR_SUCCESS) throw(nFunctionRetVal);
|
||||
|
||||
APE_FILE_INFO * pInfo = (APE_FILE_INFO *) spAPEDecompress->GetInfo(APE_INTERNAL_INFO);
|
||||
if ((pInfo->nVersion < 3980) || (pInfo->spAPEDescriptor == NULL))
|
||||
throw(ERROR_UPSUPPORTED_FILE_VERSION);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
bQuickVerifyIfPossible = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
// if we can and should quick verify, then do it
|
||||
if (bQuickVerifyIfPossible)
|
||||
{
|
||||
// variable declares
|
||||
int nFunctionRetVal = ERROR_SUCCESS;
|
||||
unsigned int nBytesRead = 0;
|
||||
CSmartPtr<IAPEDecompress> spAPEDecompress;
|
||||
|
||||
// run the quick verify
|
||||
try
|
||||
{
|
||||
spAPEDecompress.Assign(CreateIAPEDecompress(pInputFilename, &nFunctionRetVal));
|
||||
if (spAPEDecompress == NULL || nFunctionRetVal != ERROR_SUCCESS) throw(nFunctionRetVal);
|
||||
|
||||
CMD5Helper MD5Helper;
|
||||
|
||||
CIO * pIO = GET_IO(spAPEDecompress);
|
||||
APE_FILE_INFO * pInfo = (APE_FILE_INFO *) spAPEDecompress->GetInfo(APE_INTERNAL_INFO);
|
||||
|
||||
if ((pInfo->nVersion < 3980) || (pInfo->spAPEDescriptor == NULL))
|
||||
throw(ERROR_UPSUPPORTED_FILE_VERSION);
|
||||
|
||||
int nHead = pInfo->nJunkHeaderBytes + pInfo->spAPEDescriptor->nDescriptorBytes;
|
||||
int nStart = nHead + pInfo->spAPEDescriptor->nHeaderBytes + pInfo->spAPEDescriptor->nSeekTableBytes;
|
||||
|
||||
pIO->Seek(nHead, FILE_BEGIN);
|
||||
int nHeadBytes = nStart - nHead;
|
||||
CSmartPtr<unsigned char> spHeadBuffer(new unsigned char [nHeadBytes], TRUE);
|
||||
if ((pIO->Read(spHeadBuffer, nHeadBytes, &nBytesRead) != ERROR_SUCCESS) || (nHeadBytes != int(nBytesRead)))
|
||||
throw(ERROR_IO_READ);
|
||||
|
||||
int nBytesLeft = pInfo->spAPEDescriptor->nHeaderDataBytes + pInfo->spAPEDescriptor->nAPEFrameDataBytes + pInfo->spAPEDescriptor->nTerminatingDataBytes;
|
||||
CSmartPtr<unsigned char> spBuffer(new unsigned char [16384], TRUE);
|
||||
nBytesRead = 1;
|
||||
while ((nBytesLeft > 0) && (nBytesRead > 0))
|
||||
{
|
||||
int nBytesToRead = min(16384, nBytesLeft);
|
||||
if (pIO->Read(spBuffer, nBytesToRead, &nBytesRead) != ERROR_SUCCESS)
|
||||
throw(ERROR_IO_READ);
|
||||
|
||||
MD5Helper.AddData(spBuffer, nBytesRead);
|
||||
nBytesLeft -= nBytesRead;
|
||||
}
|
||||
|
||||
if (nBytesLeft != 0)
|
||||
throw(ERROR_IO_READ);
|
||||
|
||||
MD5Helper.AddData(spHeadBuffer, nHeadBytes);
|
||||
|
||||
unsigned char cResult[16];
|
||||
MD5Helper.GetResult(cResult);
|
||||
|
||||
if (memcmp(cResult, pInfo->spAPEDescriptor->cFileMD5, 16) != 0)
|
||||
nFunctionRetVal = ERROR_INVALID_CHECKSUM;
|
||||
|
||||
}
|
||||
catch(int nErrorCode)
|
||||
{
|
||||
nFunctionRetVal = (nErrorCode == 0) ? ERROR_UNDEFINED : nErrorCode;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
nFunctionRetVal = ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
// return value
|
||||
nRetVal = nFunctionRetVal;
|
||||
}
|
||||
else
|
||||
{
|
||||
nRetVal = DecompressCore(pInputFilename, NULL, UNMAC_DECODER_OUTPUT_NONE, -1, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
}
|
||||
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Decompress file
|
||||
*****************************************************************************************/
|
||||
int __stdcall DecompressFileW(const str_utf16 * pInputFilename, const str_utf16 * pOutputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
if (pOutputFilename == NULL)
|
||||
return VerifyFileW(pInputFilename, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
else
|
||||
return DecompressCore(pInputFilename, pOutputFilename, UNMAC_DECODER_OUTPUT_WAV, -1, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Convert file
|
||||
*****************************************************************************************/
|
||||
int __stdcall ConvertFileW(const str_utf16 * pInputFilename, const str_utf16 * pOutputFilename, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
return DecompressCore(pInputFilename, pOutputFilename, UNMAC_DECODER_OUTPUT_APE, nCompressionLevel, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Decompress a file using the specified output method
|
||||
*****************************************************************************************/
|
||||
int DecompressCore(const str_utf16 * pInputFilename, const str_utf16 * pOutputFilename, int nOutputMode, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
// error check the function parameters
|
||||
if (pInputFilename == NULL)
|
||||
{
|
||||
return ERROR_INVALID_FUNCTION_PARAMETER;
|
||||
}
|
||||
|
||||
// variable declares
|
||||
int nFunctionRetVal = ERROR_SUCCESS;
|
||||
CSmartPtr<IO_CLASS_NAME> spioOutput;
|
||||
CSmartPtr<IAPECompress> spAPECompress;
|
||||
CSmartPtr<IAPEDecompress> spAPEDecompress;
|
||||
CSmartPtr<unsigned char> spTempBuffer;
|
||||
CSmartPtr<CMACProgressHelper> spMACProgressHelper;
|
||||
WAVEFORMATEX wfeInput;
|
||||
|
||||
try
|
||||
{
|
||||
// create the decoder
|
||||
spAPEDecompress.Assign(CreateIAPEDecompress(pInputFilename, &nFunctionRetVal));
|
||||
if (spAPEDecompress == NULL || nFunctionRetVal != ERROR_SUCCESS) throw(nFunctionRetVal);
|
||||
|
||||
// get the input format
|
||||
THROW_ON_ERROR(spAPEDecompress->GetInfo(APE_INFO_WAVEFORMATEX, (int) &wfeInput))
|
||||
|
||||
// allocate space for the header
|
||||
spTempBuffer.Assign(new unsigned char [spAPEDecompress->GetInfo(APE_INFO_WAV_HEADER_BYTES)], TRUE);
|
||||
if (spTempBuffer == NULL) throw(ERROR_INSUFFICIENT_MEMORY);
|
||||
|
||||
// get the header
|
||||
THROW_ON_ERROR(spAPEDecompress->GetInfo(APE_INFO_WAV_HEADER_DATA, (int) spTempBuffer.GetPtr(), spAPEDecompress->GetInfo(APE_INFO_WAV_HEADER_BYTES)));
|
||||
|
||||
// initialize the output
|
||||
if (nOutputMode == UNMAC_DECODER_OUTPUT_WAV)
|
||||
{
|
||||
// create the file
|
||||
spioOutput.Assign(new IO_CLASS_NAME); THROW_ON_ERROR(spioOutput->Create(pOutputFilename))
|
||||
|
||||
// output the header
|
||||
THROW_ON_ERROR(WriteSafe(spioOutput, spTempBuffer, spAPEDecompress->GetInfo(APE_INFO_WAV_HEADER_BYTES)));
|
||||
}
|
||||
else if (nOutputMode == UNMAC_DECODER_OUTPUT_APE)
|
||||
{
|
||||
// quit if there is nothing to do
|
||||
if (spAPEDecompress->GetInfo(APE_INFO_FILE_VERSION) == MAC_VERSION_NUMBER && spAPEDecompress->GetInfo(APE_INFO_COMPRESSION_LEVEL) == nCompressionLevel)
|
||||
throw(ERROR_SKIPPED);
|
||||
|
||||
// create and start the compressor
|
||||
spAPECompress.Assign(CreateIAPECompress());
|
||||
THROW_ON_ERROR(spAPECompress->Start(pOutputFilename, &wfeInput, spAPEDecompress->GetInfo(APE_DECOMPRESS_TOTAL_BLOCKS) * spAPEDecompress->GetInfo(APE_INFO_BLOCK_ALIGN),
|
||||
nCompressionLevel, spTempBuffer, spAPEDecompress->GetInfo(APE_INFO_WAV_HEADER_BYTES)))
|
||||
}
|
||||
|
||||
// allocate space for decompression
|
||||
spTempBuffer.Assign(new unsigned char [spAPEDecompress->GetInfo(APE_INFO_BLOCK_ALIGN) * BLOCKS_PER_DECODE], TRUE);
|
||||
if (spTempBuffer == NULL) throw(ERROR_INSUFFICIENT_MEMORY);
|
||||
|
||||
int nBlocksLeft = spAPEDecompress->GetInfo(APE_DECOMPRESS_TOTAL_BLOCKS);
|
||||
|
||||
// create the progress helper
|
||||
spMACProgressHelper.Assign(new CMACProgressHelper(nBlocksLeft / BLOCKS_PER_DECODE, pPercentageDone, ProgressCallback, pKillFlag));
|
||||
|
||||
// main decoding loop
|
||||
while (nBlocksLeft > 0)
|
||||
{
|
||||
// decode data
|
||||
int nBlocksDecoded = -1;
|
||||
int nRetVal = spAPEDecompress->GetData((char *) spTempBuffer.GetPtr(), BLOCKS_PER_DECODE, &nBlocksDecoded);
|
||||
if (nRetVal != ERROR_SUCCESS)
|
||||
throw(ERROR_INVALID_CHECKSUM);
|
||||
|
||||
// handle the output
|
||||
if (nOutputMode == UNMAC_DECODER_OUTPUT_WAV)
|
||||
{
|
||||
unsigned int nBytesToWrite = (nBlocksDecoded * spAPEDecompress->GetInfo(APE_INFO_BLOCK_ALIGN));
|
||||
unsigned int nBytesWritten = 0;
|
||||
int nRetVal = spioOutput->Write(spTempBuffer, nBytesToWrite, &nBytesWritten);
|
||||
if ((nRetVal != 0) || (nBytesToWrite != nBytesWritten))
|
||||
throw(ERROR_IO_WRITE);
|
||||
}
|
||||
else if (nOutputMode == UNMAC_DECODER_OUTPUT_APE)
|
||||
{
|
||||
THROW_ON_ERROR(spAPECompress->AddData(spTempBuffer, nBlocksDecoded * spAPEDecompress->GetInfo(APE_INFO_BLOCK_ALIGN)))
|
||||
}
|
||||
|
||||
// update amount remaining
|
||||
nBlocksLeft -= nBlocksDecoded;
|
||||
|
||||
// update progress and kill flag
|
||||
spMACProgressHelper->UpdateProgress();
|
||||
if (spMACProgressHelper->ProcessKillFlag(TRUE) != 0)
|
||||
throw(ERROR_USER_STOPPED_PROCESSING);
|
||||
}
|
||||
|
||||
// terminate the output
|
||||
if (nOutputMode == UNMAC_DECODER_OUTPUT_WAV)
|
||||
{
|
||||
// write any terminating WAV data
|
||||
if (spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES) > 0)
|
||||
{
|
||||
spTempBuffer.Assign(new unsigned char[spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES)], TRUE);
|
||||
if (spTempBuffer == NULL) throw(ERROR_INSUFFICIENT_MEMORY);
|
||||
THROW_ON_ERROR(spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_DATA, (int) spTempBuffer.GetPtr(), spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES)))
|
||||
|
||||
unsigned int nBytesToWrite = spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES);
|
||||
unsigned int nBytesWritten = 0;
|
||||
int nRetVal = spioOutput->Write(spTempBuffer, nBytesToWrite, &nBytesWritten);
|
||||
if ((nRetVal != 0) || (nBytesToWrite != nBytesWritten))
|
||||
throw(ERROR_IO_WRITE);
|
||||
}
|
||||
}
|
||||
else if (nOutputMode == UNMAC_DECODER_OUTPUT_APE)
|
||||
{
|
||||
// write the WAV data and any tag
|
||||
int nTagBytes = GET_TAG(spAPEDecompress)->GetTagBytes();
|
||||
BOOL bHasTag = (nTagBytes > 0);
|
||||
int nTerminatingBytes = nTagBytes;
|
||||
nTerminatingBytes += spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES);
|
||||
|
||||
if (nTerminatingBytes > 0)
|
||||
{
|
||||
spTempBuffer.Assign(new unsigned char[nTerminatingBytes], TRUE);
|
||||
if (spTempBuffer == NULL) throw(ERROR_INSUFFICIENT_MEMORY);
|
||||
|
||||
THROW_ON_ERROR(spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_DATA, (int) spTempBuffer.GetPtr(), nTerminatingBytes))
|
||||
|
||||
if (bHasTag)
|
||||
{
|
||||
unsigned int nBytesRead = 0;
|
||||
THROW_ON_ERROR(GET_IO(spAPEDecompress)->Seek(-(nTagBytes), FILE_END))
|
||||
THROW_ON_ERROR(GET_IO(spAPEDecompress)->Read(&spTempBuffer[spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES)], nTagBytes, &nBytesRead))
|
||||
}
|
||||
|
||||
THROW_ON_ERROR(spAPECompress->Finish(spTempBuffer, nTerminatingBytes, spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES)));
|
||||
}
|
||||
else
|
||||
{
|
||||
THROW_ON_ERROR(spAPECompress->Finish(NULL, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// fire the "complete" progress notification
|
||||
spMACProgressHelper->UpdateProgressComplete();
|
||||
}
|
||||
catch(int nErrorCode)
|
||||
{
|
||||
nFunctionRetVal = (nErrorCode == 0) ? ERROR_UNDEFINED : nErrorCode;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
nFunctionRetVal = ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
// return
|
||||
return nFunctionRetVal;
|
||||
}
|
||||
743
MAC_SDK/Source/MACLib/APETag.cpp
Normal file
743
MAC_SDK/Source/MACLib/APETag.cpp
Normal file
@@ -0,0 +1,743 @@
|
||||
#include "All.h"
|
||||
#include "ID3Genres.h"
|
||||
#include "APETag.h"
|
||||
#include "CharacterHelper.h"
|
||||
#include "IO.h"
|
||||
#include IO_HEADER_FILE
|
||||
|
||||
/*****************************************************************************************
|
||||
CAPETagField
|
||||
*****************************************************************************************/
|
||||
|
||||
CAPETagField::CAPETagField(const str_utf16 * pFieldName, const void * pFieldValue, int nFieldBytes, int nFlags)
|
||||
{
|
||||
// field name
|
||||
m_spFieldNameUTF16.Assign(new str_utf16 [wcslen(pFieldName) + 1], TRUE);
|
||||
memcpy(m_spFieldNameUTF16, pFieldName, (wcslen(pFieldName) + 1) * sizeof(str_utf16));
|
||||
|
||||
// data (we'll always allocate two extra bytes and memset to 0 so we're safely NULL terminated)
|
||||
m_nFieldValueBytes = max(nFieldBytes, 0);
|
||||
m_spFieldValue.Assign(new char [m_nFieldValueBytes + 2], TRUE);
|
||||
memset(m_spFieldValue, 0, m_nFieldValueBytes + 2);
|
||||
if (m_nFieldValueBytes > 0)
|
||||
memcpy(m_spFieldValue, pFieldValue, m_nFieldValueBytes);
|
||||
|
||||
// flags
|
||||
m_nFieldFlags = nFlags;
|
||||
}
|
||||
|
||||
CAPETagField::~CAPETagField()
|
||||
{
|
||||
}
|
||||
|
||||
int CAPETagField::GetFieldSize()
|
||||
{
|
||||
CSmartPtr<char> spFieldNameANSI(GetANSIFromUTF16(m_spFieldNameUTF16), TRUE);
|
||||
return (strlen(spFieldNameANSI) + 1) + m_nFieldValueBytes + 4 + 4;
|
||||
}
|
||||
|
||||
const str_utf16 * CAPETagField::GetFieldName()
|
||||
{
|
||||
return m_spFieldNameUTF16;
|
||||
}
|
||||
|
||||
const char * CAPETagField::GetFieldValue()
|
||||
{
|
||||
return m_spFieldValue;
|
||||
}
|
||||
|
||||
int CAPETagField::GetFieldValueSize()
|
||||
{
|
||||
return m_nFieldValueBytes;
|
||||
}
|
||||
|
||||
int CAPETagField::GetFieldFlags()
|
||||
{
|
||||
return m_nFieldFlags;
|
||||
}
|
||||
|
||||
int CAPETagField::SaveField(char * pBuffer)
|
||||
{
|
||||
*((int *) pBuffer) = m_nFieldValueBytes;
|
||||
pBuffer += 4;
|
||||
*((int *) pBuffer) = m_nFieldFlags;
|
||||
pBuffer += 4;
|
||||
|
||||
CSmartPtr<char> spFieldNameANSI((char *) GetANSIFromUTF16(m_spFieldNameUTF16), TRUE);
|
||||
strcpy(pBuffer, spFieldNameANSI);
|
||||
pBuffer += strlen(spFieldNameANSI) + 1;
|
||||
|
||||
memcpy(pBuffer, m_spFieldValue, m_nFieldValueBytes);
|
||||
|
||||
return GetFieldSize();
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
CAPETag
|
||||
*****************************************************************************************/
|
||||
|
||||
CAPETag::CAPETag(const str_utf16 * pFilename, BOOL bAnalyze)
|
||||
{
|
||||
m_spIO.Assign(new IO_CLASS_NAME);
|
||||
m_spIO->Open(pFilename);
|
||||
|
||||
m_bAnalyzed = FALSE;
|
||||
m_nFields = 0;
|
||||
m_nTagBytes = 0;
|
||||
m_bIgnoreReadOnly = FALSE;
|
||||
|
||||
if (bAnalyze)
|
||||
{
|
||||
Analyze();
|
||||
}
|
||||
}
|
||||
|
||||
CAPETag::CAPETag(CIO * pIO, BOOL bAnalyze)
|
||||
{
|
||||
m_spIO.Assign(pIO, FALSE, FALSE); // we don't own the IO source
|
||||
m_bAnalyzed = FALSE;
|
||||
m_nFields = 0;
|
||||
m_nTagBytes = 0;
|
||||
|
||||
if (bAnalyze)
|
||||
{
|
||||
Analyze();
|
||||
}
|
||||
}
|
||||
|
||||
CAPETag::~CAPETag()
|
||||
{
|
||||
ClearFields();
|
||||
}
|
||||
|
||||
int CAPETag::GetTagBytes()
|
||||
{
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
|
||||
return m_nTagBytes;
|
||||
}
|
||||
|
||||
CAPETagField * CAPETag::GetTagField(int nIndex)
|
||||
{
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
|
||||
if ((nIndex >= 0) && (nIndex < m_nFields))
|
||||
{
|
||||
return m_aryFields[nIndex];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CAPETag::Save(BOOL bUseOldID3)
|
||||
{
|
||||
if (Remove(FALSE) != ERROR_SUCCESS)
|
||||
return -1;
|
||||
|
||||
if (m_nFields == 0) { return ERROR_SUCCESS; }
|
||||
|
||||
int nRetVal = -1;
|
||||
|
||||
if (bUseOldID3 == FALSE)
|
||||
{
|
||||
int z = 0;
|
||||
|
||||
// calculate the size of the whole tag
|
||||
int nFieldBytes = 0;
|
||||
for (z = 0; z < m_nFields; z++)
|
||||
nFieldBytes += m_aryFields[z]->GetFieldSize();
|
||||
|
||||
// sort the fields
|
||||
SortFields();
|
||||
|
||||
// build the footer
|
||||
APE_TAG_FOOTER APETagFooter(m_nFields, nFieldBytes);
|
||||
|
||||
// make a buffer for the tag
|
||||
int nTotalTagBytes = APETagFooter.GetTotalTagBytes();
|
||||
CSmartPtr<char> spRawTag(new char [nTotalTagBytes], TRUE);
|
||||
|
||||
// save the fields
|
||||
int nLocation = 0;
|
||||
for (z = 0; z < m_nFields; z++)
|
||||
nLocation += m_aryFields[z]->SaveField(&spRawTag[nLocation]);
|
||||
|
||||
// add the footer to the buffer
|
||||
memcpy(&spRawTag[nLocation], &APETagFooter, APE_TAG_FOOTER_BYTES);
|
||||
nLocation += APE_TAG_FOOTER_BYTES;
|
||||
|
||||
// dump the tag to the I/O source
|
||||
nRetVal = WriteBufferToEndOfIO(spRawTag, nTotalTagBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// build the ID3 tag
|
||||
ID3_TAG ID3Tag;
|
||||
CreateID3Tag(&ID3Tag);
|
||||
nRetVal = WriteBufferToEndOfIO(&ID3Tag, sizeof(ID3_TAG));
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPETag::WriteBufferToEndOfIO(void * pBuffer, int nBytes)
|
||||
{
|
||||
int nOriginalPosition = m_spIO->GetPosition();
|
||||
|
||||
unsigned int nBytesWritten = 0;
|
||||
m_spIO->Seek(0, FILE_END);
|
||||
|
||||
int nRetVal = m_spIO->Write(pBuffer, nBytes, &nBytesWritten);
|
||||
|
||||
m_spIO->Seek(nOriginalPosition, FILE_BEGIN);
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPETag::Analyze()
|
||||
{
|
||||
// clean-up
|
||||
ID3_TAG ID3Tag;
|
||||
ClearFields();
|
||||
m_nTagBytes = 0;
|
||||
|
||||
m_bAnalyzed = TRUE;
|
||||
|
||||
// store the original location
|
||||
int nOriginalPosition = m_spIO->GetPosition();
|
||||
|
||||
// check for a tag
|
||||
unsigned int nBytesRead;
|
||||
int nRetVal;
|
||||
m_bHasID3Tag = FALSE;
|
||||
m_bHasAPETag = FALSE;
|
||||
m_nAPETagVersion = -1;
|
||||
m_spIO->Seek(-ID3_TAG_BYTES, FILE_END);
|
||||
nRetVal = m_spIO->Read((unsigned char *) &ID3Tag, sizeof(ID3_TAG), &nBytesRead);
|
||||
|
||||
if ((nBytesRead == sizeof(ID3_TAG)) && (nRetVal == 0))
|
||||
{
|
||||
if (ID3Tag.Header[0] == 'T' && ID3Tag.Header[1] == 'A' && ID3Tag.Header[2] == 'G')
|
||||
{
|
||||
m_bHasID3Tag = TRUE;
|
||||
m_nTagBytes += ID3_TAG_BYTES;
|
||||
}
|
||||
}
|
||||
|
||||
// set the fields
|
||||
if (m_bHasID3Tag)
|
||||
{
|
||||
SetFieldID3String(APE_TAG_FIELD_ARTIST, ID3Tag.Artist, 30);
|
||||
SetFieldID3String(APE_TAG_FIELD_ALBUM, ID3Tag.Album, 30);
|
||||
SetFieldID3String(APE_TAG_FIELD_TITLE, ID3Tag.Title, 30);
|
||||
SetFieldID3String(APE_TAG_FIELD_COMMENT, ID3Tag.Comment, 28);
|
||||
SetFieldID3String(APE_TAG_FIELD_YEAR, ID3Tag.Year, 4);
|
||||
|
||||
char cTemp[16]; sprintf(cTemp, "%d", ID3Tag.Track);
|
||||
SetFieldString(APE_TAG_FIELD_TRACK, cTemp, FALSE);
|
||||
|
||||
if ((ID3Tag.Genre == GENRE_UNDEFINED) || (ID3Tag.Genre >= GENRE_COUNT))
|
||||
SetFieldString(APE_TAG_FIELD_GENRE, APE_TAG_GENRE_UNDEFINED);
|
||||
else
|
||||
SetFieldString(APE_TAG_FIELD_GENRE, g_ID3Genre[ID3Tag.Genre]);
|
||||
}
|
||||
|
||||
// try loading the APE tag
|
||||
if (m_bHasID3Tag == FALSE)
|
||||
{
|
||||
APE_TAG_FOOTER APETagFooter;
|
||||
m_spIO->Seek(-int(APE_TAG_FOOTER_BYTES), FILE_END);
|
||||
nRetVal = m_spIO->Read((unsigned char *) &APETagFooter, APE_TAG_FOOTER_BYTES, &nBytesRead);
|
||||
if ((nBytesRead == APE_TAG_FOOTER_BYTES) && (nRetVal == 0))
|
||||
{
|
||||
if (APETagFooter.GetIsValid(FALSE))
|
||||
{
|
||||
m_bHasAPETag = TRUE;
|
||||
m_nAPETagVersion = APETagFooter.GetVersion();
|
||||
|
||||
int nRawFieldBytes = APETagFooter.GetFieldBytes();
|
||||
m_nTagBytes += APETagFooter.GetTotalTagBytes();
|
||||
|
||||
CSmartPtr<char> spRawTag(new char [nRawFieldBytes], TRUE);
|
||||
m_spIO->Seek(-(APETagFooter.GetTotalTagBytes() - APETagFooter.GetFieldsOffset()), FILE_END);
|
||||
nRetVal = m_spIO->Read((unsigned char *) spRawTag.GetPtr(), nRawFieldBytes, &nBytesRead);
|
||||
|
||||
if ((nRetVal == 0) && (nRawFieldBytes == int(nBytesRead)))
|
||||
{
|
||||
// parse out the raw fields
|
||||
int nLocation = 0;
|
||||
for (int z = 0; z < APETagFooter.GetNumberFields(); z++)
|
||||
{
|
||||
int nMaximumFieldBytes = nRawFieldBytes - nLocation;
|
||||
|
||||
int nBytes = 0;
|
||||
if (LoadField(&spRawTag[nLocation], nMaximumFieldBytes, &nBytes) != ERROR_SUCCESS)
|
||||
{
|
||||
// if LoadField(...) fails, it means that the tag is corrupt (accidently or intentionally)
|
||||
// we'll just bail out -- leaving the fields we've already set
|
||||
break;
|
||||
}
|
||||
nLocation += nBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restore the file pointer
|
||||
m_spIO->Seek(nOriginalPosition, FILE_BEGIN);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPETag::ClearFields()
|
||||
{
|
||||
for (int z = 0; z < m_nFields; z++)
|
||||
{
|
||||
SAFE_DELETE(m_aryFields[z])
|
||||
}
|
||||
|
||||
m_nFields = 0;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPETag::GetTagFieldIndex(const str_utf16 * pFieldName)
|
||||
{
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
if (pFieldName == NULL) return -1;
|
||||
|
||||
for (int z = 0; z < m_nFields; z++)
|
||||
{
|
||||
if (wcsicmp(m_aryFields[z]->GetFieldName(), pFieldName) == 0)
|
||||
return z;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
CAPETagField * CAPETag::GetTagField(const str_utf16 * pFieldName)
|
||||
{
|
||||
int nIndex = GetTagFieldIndex(pFieldName);
|
||||
return (nIndex != -1) ? m_aryFields[nIndex] : NULL;
|
||||
}
|
||||
|
||||
int CAPETag::GetFieldString(const str_utf16 * pFieldName, str_ansi * pBuffer, int * pBufferCharacters, BOOL bUTF8Encode)
|
||||
{
|
||||
int nOriginalCharacters = *pBufferCharacters;
|
||||
str_utf16 * pUTF16 = new str_utf16 [*pBufferCharacters + 1];
|
||||
pUTF16[0] = 0;
|
||||
|
||||
int nRetVal = GetFieldString(pFieldName, pUTF16, pBufferCharacters);
|
||||
if (nRetVal == ERROR_SUCCESS)
|
||||
{
|
||||
CSmartPtr<str_ansi> spANSI(bUTF8Encode ? (str_ansi *) GetUTF8FromUTF16(pUTF16) : GetANSIFromUTF16(pUTF16), TRUE);
|
||||
if (int(strlen(spANSI)) > nOriginalCharacters)
|
||||
{
|
||||
memset(pBuffer, 0, nOriginalCharacters * sizeof(str_ansi));
|
||||
*pBufferCharacters = 0;
|
||||
nRetVal = ERROR_UNDEFINED;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(pBuffer, spANSI);
|
||||
*pBufferCharacters = strlen(spANSI);
|
||||
}
|
||||
}
|
||||
|
||||
delete [] pUTF16;
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
|
||||
int CAPETag::GetFieldString(const str_utf16 * pFieldName, str_utf16 * pBuffer, int * pBufferCharacters)
|
||||
{
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
|
||||
int nRetVal = ERROR_UNDEFINED;
|
||||
|
||||
if (*pBufferCharacters > 0)
|
||||
{
|
||||
CAPETagField * pAPETagField = GetTagField(pFieldName);
|
||||
if (pAPETagField == NULL)
|
||||
{
|
||||
// the field doesn't exist -- return an empty string
|
||||
memset(pBuffer, 0, *pBufferCharacters * sizeof(str_utf16));
|
||||
*pBufferCharacters = 0;
|
||||
}
|
||||
else if (pAPETagField->GetIsUTF8Text() || (m_nAPETagVersion < 2000))
|
||||
{
|
||||
// get the value in UTF-16 format
|
||||
CSmartPtr<str_utf16> spUTF16;
|
||||
if (m_nAPETagVersion >= 2000)
|
||||
spUTF16.Assign(GetUTF16FromUTF8((str_utf8 *) pAPETagField->GetFieldValue()), TRUE);
|
||||
else
|
||||
spUTF16.Assign(GetUTF16FromANSI(pAPETagField->GetFieldValue()), TRUE);
|
||||
|
||||
// get the number of characters
|
||||
int nCharacters = (wcslen(spUTF16) + 1);
|
||||
if (nCharacters > *pBufferCharacters)
|
||||
{
|
||||
// we'll fail here, because it's not clear what would get returned (null termination, size, etc.)
|
||||
// and we really don't want to cause buffer overruns on the client side
|
||||
*pBufferCharacters = nCharacters;
|
||||
}
|
||||
else
|
||||
{
|
||||
// just copy in
|
||||
*pBufferCharacters = nCharacters;
|
||||
memcpy(pBuffer, spUTF16.GetPtr(), *pBufferCharacters * sizeof(str_utf16));
|
||||
nRetVal = ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// memset the whole buffer to NULL (so everything left over is NULL terminated)
|
||||
memset(pBuffer, 0, *pBufferCharacters * sizeof(str_utf16));
|
||||
|
||||
// do a binary dump (need to convert from wchar's to bytes)
|
||||
int nBufferBytes = (*pBufferCharacters - 1) * sizeof(str_utf16);
|
||||
nRetVal = GetFieldBinary(pFieldName, pBuffer, &nBufferBytes);
|
||||
*pBufferCharacters = (nBufferBytes / sizeof(str_utf16)) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPETag::GetFieldBinary(const str_utf16 * pFieldName, void * pBuffer, int * pBufferBytes)
|
||||
{
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
|
||||
int nRetVal = ERROR_UNDEFINED;
|
||||
|
||||
if (*pBufferBytes > 0)
|
||||
{
|
||||
CAPETagField * pAPETagField = GetTagField(pFieldName);
|
||||
if (pAPETagField == NULL)
|
||||
{
|
||||
memset(pBuffer, 0, *pBufferBytes);
|
||||
*pBufferBytes = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pAPETagField->GetFieldValueSize() > *pBufferBytes)
|
||||
{
|
||||
// we'll fail here, because partial data may be worse than no data
|
||||
memset(pBuffer, 0, *pBufferBytes);
|
||||
*pBufferBytes = pAPETagField->GetFieldValueSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
// memcpy
|
||||
*pBufferBytes = pAPETagField->GetFieldValueSize();
|
||||
memcpy(pBuffer, pAPETagField->GetFieldValue(), *pBufferBytes);
|
||||
nRetVal = ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPETag::CreateID3Tag(ID3_TAG * pID3Tag)
|
||||
{
|
||||
// error check
|
||||
if (pID3Tag == NULL) { return -1; }
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
if (m_nFields == 0) { return -1; }
|
||||
|
||||
// empty
|
||||
ZeroMemory(pID3Tag, ID3_TAG_BYTES);
|
||||
|
||||
// header
|
||||
pID3Tag->Header[0] = 'T'; pID3Tag->Header[1] = 'A'; pID3Tag->Header[2] = 'G';
|
||||
|
||||
// standard fields
|
||||
GetFieldID3String(APE_TAG_FIELD_ARTIST, pID3Tag->Artist, 30);
|
||||
GetFieldID3String(APE_TAG_FIELD_ALBUM, pID3Tag->Album, 30);
|
||||
GetFieldID3String(APE_TAG_FIELD_TITLE, pID3Tag->Title, 30);
|
||||
GetFieldID3String(APE_TAG_FIELD_COMMENT, pID3Tag->Comment, 28);
|
||||
GetFieldID3String(APE_TAG_FIELD_YEAR, pID3Tag->Year, 4);
|
||||
|
||||
// track number
|
||||
str_utf16 cBuffer[256] = { 0 }; int nBufferCharacters = 255;
|
||||
GetFieldString(APE_TAG_FIELD_TRACK, cBuffer, &nBufferCharacters);
|
||||
pID3Tag->Track = (unsigned char) _wtoi(cBuffer);
|
||||
|
||||
// genre
|
||||
cBuffer[0] = 0; nBufferCharacters = 255;
|
||||
GetFieldString(APE_TAG_FIELD_GENRE, cBuffer, &nBufferCharacters);
|
||||
|
||||
// convert the genre string to an index
|
||||
pID3Tag->Genre = 255;
|
||||
int nGenreIndex = 0;
|
||||
BOOL bFound = FALSE;
|
||||
while ((nGenreIndex < GENRE_COUNT) && (bFound == FALSE))
|
||||
{
|
||||
if (_wcsicmp(cBuffer, g_ID3Genre[nGenreIndex]) == 0)
|
||||
{
|
||||
pID3Tag->Genre = nGenreIndex;
|
||||
bFound = TRUE;
|
||||
}
|
||||
|
||||
nGenreIndex++;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPETag::LoadField(const char * pBuffer, int nMaximumBytes, int * pBytes)
|
||||
{
|
||||
// set bytes to 0
|
||||
if (pBytes) *pBytes = 0;
|
||||
|
||||
// size and flags
|
||||
int nLocation = 0;
|
||||
int nFieldValueSize = *((int *) &pBuffer[nLocation]);
|
||||
nLocation += 4;
|
||||
int nFieldFlags = *((int *) &pBuffer[nLocation]);
|
||||
nLocation += 4;
|
||||
|
||||
// safety check (so we can't get buffer overflow attacked)
|
||||
int nMaximumRead = nMaximumBytes - 8 - nFieldValueSize;
|
||||
BOOL bSafe = TRUE;
|
||||
for (int z = 0; (z < nMaximumRead) && (bSafe == TRUE); z++)
|
||||
{
|
||||
int nCharacter = pBuffer[nLocation + z];
|
||||
if (nCharacter == 0)
|
||||
break;
|
||||
if ((nCharacter < 0x20) || (nCharacter > 0x7E))
|
||||
bSafe = FALSE;
|
||||
}
|
||||
if (bSafe == FALSE)
|
||||
return -1;
|
||||
|
||||
// name
|
||||
int nNameCharacters = strlen(&pBuffer[nLocation]);
|
||||
CSmartPtr<str_utf8> spNameUTF8(new str_utf8 [nNameCharacters + 1], TRUE);
|
||||
memcpy(spNameUTF8, &pBuffer[nLocation], (nNameCharacters + 1) * sizeof(str_utf8));
|
||||
nLocation += nNameCharacters + 1;
|
||||
CSmartPtr<str_utf16> spNameUTF16(GetUTF16FromUTF8(spNameUTF8.GetPtr()), TRUE);
|
||||
|
||||
// value
|
||||
CSmartPtr<char> spFieldBuffer(new char [nFieldValueSize], TRUE);
|
||||
memcpy(spFieldBuffer, &pBuffer[nLocation], nFieldValueSize);
|
||||
nLocation += nFieldValueSize;
|
||||
|
||||
// update the bytes
|
||||
if (pBytes) *pBytes = nLocation;
|
||||
|
||||
// set
|
||||
return SetFieldBinary(spNameUTF16.GetPtr(), spFieldBuffer, nFieldValueSize, nFieldFlags);
|
||||
}
|
||||
|
||||
int CAPETag::SetFieldString(const str_utf16 * pFieldName, const str_utf16 * pFieldValue)
|
||||
{
|
||||
// remove if empty
|
||||
if ((pFieldValue == NULL) || (wcslen(pFieldValue) <= 0))
|
||||
return RemoveField(pFieldName);
|
||||
|
||||
// UTF-8 encode the value and call the UTF-8 SetField(...)
|
||||
CSmartPtr<str_utf8> spFieldValueUTF8(GetUTF8FromUTF16((str_utf16 *) pFieldValue), TRUE);
|
||||
return SetFieldString(pFieldName, (const char *) spFieldValueUTF8.GetPtr(), TRUE);
|
||||
}
|
||||
|
||||
int CAPETag::SetFieldString(const str_utf16 * pFieldName, const char * pFieldValue, BOOL bAlreadyUTF8Encoded)
|
||||
{
|
||||
// remove if empty
|
||||
if ((pFieldValue == NULL) || (strlen(pFieldValue) <= 0))
|
||||
return RemoveField(pFieldName);
|
||||
|
||||
// get the length and call the binary SetField(...)
|
||||
if (bAlreadyUTF8Encoded == FALSE)
|
||||
{
|
||||
CSmartPtr<char> spUTF8((char *) GetUTF8FromANSI(pFieldValue), TRUE);
|
||||
int nFieldBytes = strlen(spUTF8.GetPtr());
|
||||
return SetFieldBinary(pFieldName, spUTF8.GetPtr(), nFieldBytes, TAG_FIELD_FLAG_DATA_TYPE_TEXT_UTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nFieldBytes = strlen(pFieldValue);
|
||||
return SetFieldBinary(pFieldName, pFieldValue, nFieldBytes, TAG_FIELD_FLAG_DATA_TYPE_TEXT_UTF8);
|
||||
}
|
||||
}
|
||||
|
||||
int CAPETag::SetFieldBinary(const str_utf16 * pFieldName, const void * pFieldValue, int nFieldBytes, int nFieldFlags)
|
||||
{
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
if (pFieldName == NULL) return -1;
|
||||
|
||||
// check to see if we're trying to remove the field (by setting it to NULL or an empty string)
|
||||
BOOL bRemoving = (pFieldValue == NULL) || (nFieldBytes <= 0);
|
||||
|
||||
// get the index
|
||||
int nFieldIndex = GetTagFieldIndex(pFieldName);
|
||||
if (nFieldIndex != -1)
|
||||
{
|
||||
// existing field
|
||||
|
||||
// fail if we're read-only (and not ignoring the read-only flag)
|
||||
if ((m_bIgnoreReadOnly == FALSE) && (m_aryFields[nFieldIndex]->GetIsReadOnly()))
|
||||
return -1;
|
||||
|
||||
// erase the existing field
|
||||
SAFE_DELETE(m_aryFields[nFieldIndex])
|
||||
|
||||
if (bRemoving)
|
||||
{
|
||||
return RemoveField(nFieldIndex);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bRemoving)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
nFieldIndex = m_nFields;
|
||||
m_nFields++;
|
||||
}
|
||||
|
||||
// create the field and add it to the field array
|
||||
m_aryFields[nFieldIndex] = new CAPETagField(pFieldName, pFieldValue, nFieldBytes, nFieldFlags);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPETag::RemoveField(int nIndex)
|
||||
{
|
||||
if ((nIndex >= 0) && (nIndex < m_nFields))
|
||||
{
|
||||
SAFE_DELETE(m_aryFields[nIndex])
|
||||
memmove(&m_aryFields[nIndex], &m_aryFields[nIndex + 1], (256 - nIndex - 1) * sizeof(CAPETagField *));
|
||||
m_nFields--;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CAPETag::RemoveField(const str_utf16 * pFieldName)
|
||||
{
|
||||
return RemoveField(GetTagFieldIndex(pFieldName));
|
||||
}
|
||||
|
||||
int CAPETag::Remove(BOOL bUpdate)
|
||||
{
|
||||
// variables
|
||||
unsigned int nBytesRead = 0;
|
||||
int nRetVal = 0;
|
||||
int nOriginalPosition = m_spIO->GetPosition();
|
||||
|
||||
BOOL bID3Removed = TRUE;
|
||||
BOOL bAPETagRemoved = TRUE;
|
||||
|
||||
BOOL bFailedToRemove = FALSE;
|
||||
|
||||
while (bID3Removed || bAPETagRemoved)
|
||||
{
|
||||
bID3Removed = FALSE;
|
||||
bAPETagRemoved = FALSE;
|
||||
|
||||
// ID3 tag
|
||||
if (m_spIO->GetSize() > ID3_TAG_BYTES)
|
||||
{
|
||||
char cTagHeader[3];
|
||||
m_spIO->Seek(-ID3_TAG_BYTES, FILE_END);
|
||||
nRetVal = m_spIO->Read(cTagHeader, 3, &nBytesRead);
|
||||
if ((nRetVal == 0) && (nBytesRead == 3))
|
||||
{
|
||||
if (strncmp(cTagHeader, "TAG", 3) == 0)
|
||||
{
|
||||
m_spIO->Seek(-ID3_TAG_BYTES, FILE_END);
|
||||
if (m_spIO->SetEOF() != 0)
|
||||
bFailedToRemove = TRUE;
|
||||
else
|
||||
bID3Removed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// APE Tag
|
||||
if (m_spIO->GetSize() > APE_TAG_FOOTER_BYTES && bFailedToRemove == FALSE)
|
||||
{
|
||||
APE_TAG_FOOTER APETagFooter;
|
||||
m_spIO->Seek(-int(APE_TAG_FOOTER_BYTES), FILE_END);
|
||||
nRetVal = m_spIO->Read(&APETagFooter, APE_TAG_FOOTER_BYTES, &nBytesRead);
|
||||
if ((nRetVal == 0) && (nBytesRead == APE_TAG_FOOTER_BYTES))
|
||||
{
|
||||
if (APETagFooter.GetIsValid(TRUE))
|
||||
{
|
||||
m_spIO->Seek(-APETagFooter.GetTotalTagBytes(), FILE_END);
|
||||
|
||||
if (m_spIO->SetEOF() != 0)
|
||||
bFailedToRemove = TRUE;
|
||||
else
|
||||
bAPETagRemoved = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_spIO->Seek(nOriginalPosition, FILE_BEGIN);
|
||||
|
||||
if (bUpdate && bFailedToRemove == FALSE)
|
||||
{
|
||||
Analyze();
|
||||
}
|
||||
|
||||
return bFailedToRemove ? -1 : 0;
|
||||
}
|
||||
|
||||
int CAPETag::SetFieldID3String(const str_utf16 * pFieldName, const char * pFieldValue, int nBytes)
|
||||
{
|
||||
// allocate a buffer and terminate it
|
||||
CSmartPtr<str_ansi> spBuffer(new str_ansi [nBytes + 1], TRUE);
|
||||
spBuffer[nBytes] = 0;
|
||||
|
||||
// make a capped copy of the string
|
||||
memcpy(spBuffer.GetPtr(), pFieldValue, nBytes);
|
||||
|
||||
// remove trailing white-space
|
||||
char * pEnd = &spBuffer[nBytes];
|
||||
while (((*pEnd == ' ') || (*pEnd == 0)) && pEnd >= &spBuffer[0]) { *pEnd-- = 0; }
|
||||
|
||||
// set the field
|
||||
SetFieldString(pFieldName, spBuffer, FALSE);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPETag::GetFieldID3String(const str_utf16 * pFieldName, char * pBuffer, int nBytes)
|
||||
{
|
||||
int nBufferCharacters = 255; str_utf16 cBuffer[256] = {0};
|
||||
GetFieldString(pFieldName, cBuffer, &nBufferCharacters);
|
||||
|
||||
CSmartPtr<str_ansi> spBufferANSI(GetANSIFromUTF16(cBuffer), TRUE);
|
||||
|
||||
memset(pBuffer, 0, nBytes);
|
||||
strncpy(pBuffer, spBufferANSI.GetPtr(), nBytes);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPETag::SortFields()
|
||||
{
|
||||
// sort the tag fields by size (so that the smallest fields are at the front of the tag)
|
||||
qsort(m_aryFields, m_nFields, sizeof(CAPETagField *), CompareFields);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPETag::CompareFields(const void * pA, const void * pB)
|
||||
{
|
||||
CAPETagField * pFieldA = *((CAPETagField **) pA);
|
||||
CAPETagField * pFieldB = *((CAPETagField **) pB);
|
||||
|
||||
return (pFieldA->GetFieldSize() - pFieldB->GetFieldSize());
|
||||
}
|
||||
293
MAC_SDK/Source/MACLib/APETag.h
Normal file
293
MAC_SDK/Source/MACLib/APETag.h
Normal file
@@ -0,0 +1,293 @@
|
||||
#ifndef APE_APETAG_H
|
||||
#define APE_APETAG_H
|
||||
|
||||
class CIO;
|
||||
|
||||
/*****************************************************************************************
|
||||
APETag version history / supported formats
|
||||
|
||||
1.0 (1000) - Original APE tag spec. Fully supported by this code.
|
||||
2.0 (2000) - Refined APE tag spec (better streaming support, UTF encoding). Fully supported by this code.
|
||||
|
||||
Notes:
|
||||
- also supports reading of ID3v1.1 tags
|
||||
- all saving done in the APE Tag format using CURRENT_APE_TAG_VERSION
|
||||
*****************************************************************************************/
|
||||
|
||||
/*****************************************************************************************
|
||||
APETag layout
|
||||
|
||||
1) Header - APE_TAG_FOOTER (optional) (32 bytes)
|
||||
2) Fields (array):
|
||||
Value Size (4 bytes)
|
||||
Flags (4 bytes)
|
||||
Field Name (? ANSI bytes -- requires NULL terminator -- in range of 0x20 (space) to 0x7E (tilde))
|
||||
Value ([Value Size] bytes)
|
||||
3) Footer - APE_TAG_FOOTER (32 bytes)
|
||||
*****************************************************************************************/
|
||||
|
||||
/*****************************************************************************************
|
||||
Notes
|
||||
|
||||
-When saving images, store the filename (no directory -- i.e. Cover.jpg) in UTF-8 followed
|
||||
by a null terminator, followed by the image data.
|
||||
*****************************************************************************************/
|
||||
|
||||
/*****************************************************************************************
|
||||
The version of the APE tag
|
||||
*****************************************************************************************/
|
||||
#define CURRENT_APE_TAG_VERSION 2000
|
||||
|
||||
/*****************************************************************************************
|
||||
"Standard" APE tag fields
|
||||
*****************************************************************************************/
|
||||
#define APE_TAG_FIELD_TITLE L"Title"
|
||||
#define APE_TAG_FIELD_ARTIST L"Artist"
|
||||
#define APE_TAG_FIELD_ALBUM L"Album"
|
||||
#define APE_TAG_FIELD_COMMENT L"Comment"
|
||||
#define APE_TAG_FIELD_YEAR L"Year"
|
||||
#define APE_TAG_FIELD_TRACK L"Track"
|
||||
#define APE_TAG_FIELD_GENRE L"Genre"
|
||||
#define APE_TAG_FIELD_COVER_ART_FRONT L"Cover Art (front)"
|
||||
#define APE_TAG_FIELD_NOTES L"Notes"
|
||||
#define APE_TAG_FIELD_LYRICS L"Lyrics"
|
||||
#define APE_TAG_FIELD_COPYRIGHT L"Copyright"
|
||||
#define APE_TAG_FIELD_BUY_URL L"Buy URL"
|
||||
#define APE_TAG_FIELD_ARTIST_URL L"Artist URL"
|
||||
#define APE_TAG_FIELD_PUBLISHER_URL L"Publisher URL"
|
||||
#define APE_TAG_FIELD_FILE_URL L"File URL"
|
||||
#define APE_TAG_FIELD_COPYRIGHT_URL L"Copyright URL"
|
||||
#define APE_TAG_FIELD_MJ_METADATA L"Media Jukebox Metadata"
|
||||
#define APE_TAG_FIELD_TOOL_NAME L"Tool Name"
|
||||
#define APE_TAG_FIELD_TOOL_VERSION L"Tool Version"
|
||||
#define APE_TAG_FIELD_PEAK_LEVEL L"Peak Level"
|
||||
#define APE_TAG_FIELD_REPLAY_GAIN_RADIO L"Replay Gain (radio)"
|
||||
#define APE_TAG_FIELD_REPLAY_GAIN_ALBUM L"Replay Gain (album)"
|
||||
#define APE_TAG_FIELD_COMPOSER L"Composer"
|
||||
#define APE_TAG_FIELD_KEYWORDS L"Keywords"
|
||||
|
||||
/*****************************************************************************************
|
||||
Standard APE tag field values
|
||||
*****************************************************************************************/
|
||||
#define APE_TAG_GENRE_UNDEFINED L"Undefined"
|
||||
|
||||
/*****************************************************************************************
|
||||
ID3 v1.1 tag
|
||||
*****************************************************************************************/
|
||||
#define ID3_TAG_BYTES 128
|
||||
struct ID3_TAG
|
||||
{
|
||||
char Header[3]; // should equal 'TAG'
|
||||
char Title[30]; // title
|
||||
char Artist[30]; // artist
|
||||
char Album[30]; // album
|
||||
char Year[4]; // year
|
||||
char Comment[29]; // comment
|
||||
unsigned char Track; // track
|
||||
unsigned char Genre; // genre
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Footer (and header) flags
|
||||
*****************************************************************************************/
|
||||
#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31)
|
||||
#define APE_TAG_FLAG_CONTAINS_FOOTER (1 << 30)
|
||||
#define APE_TAG_FLAG_IS_HEADER (1 << 29)
|
||||
|
||||
#define APE_TAG_FLAGS_DEFAULT (APE_TAG_FLAG_CONTAINS_FOOTER)
|
||||
|
||||
/*****************************************************************************************
|
||||
Tag field flags
|
||||
*****************************************************************************************/
|
||||
#define TAG_FIELD_FLAG_READ_ONLY (1 << 0)
|
||||
|
||||
#define TAG_FIELD_FLAG_DATA_TYPE_MASK (6)
|
||||
#define TAG_FIELD_FLAG_DATA_TYPE_TEXT_UTF8 (0 << 1)
|
||||
#define TAG_FIELD_FLAG_DATA_TYPE_BINARY (1 << 1)
|
||||
#define TAG_FIELD_FLAG_DATA_TYPE_EXTERNAL_INFO (2 << 1)
|
||||
#define TAG_FIELD_FLAG_DATA_TYPE_RESERVED (3 << 1)
|
||||
|
||||
/*****************************************************************************************
|
||||
The footer at the end of APE tagged files (can also optionally be at the front of the tag)
|
||||
*****************************************************************************************/
|
||||
#define APE_TAG_FOOTER_BYTES 32
|
||||
|
||||
class APE_TAG_FOOTER
|
||||
{
|
||||
protected:
|
||||
|
||||
char m_cID[8]; // should equal 'APETAGEX'
|
||||
int m_nVersion; // equals CURRENT_APE_TAG_VERSION
|
||||
int m_nSize; // the complete size of the tag, including this footer (excludes header)
|
||||
int m_nFields; // the number of fields in the tag
|
||||
int m_nFlags; // the tag flags
|
||||
char m_cReserved[8]; // reserved for later use (must be zero)
|
||||
|
||||
public:
|
||||
|
||||
APE_TAG_FOOTER(int nFields = 0, int nFieldBytes = 0)
|
||||
{
|
||||
memcpy(m_cID, "APETAGEX", 8);
|
||||
memset(m_cReserved, 0, 8);
|
||||
m_nFields = nFields;
|
||||
m_nFlags = APE_TAG_FLAGS_DEFAULT;
|
||||
m_nSize = nFieldBytes + APE_TAG_FOOTER_BYTES;
|
||||
m_nVersion = CURRENT_APE_TAG_VERSION;
|
||||
}
|
||||
|
||||
int GetTotalTagBytes() { return m_nSize + (GetHasHeader() ? APE_TAG_FOOTER_BYTES : 0); }
|
||||
int GetFieldBytes() { return m_nSize - APE_TAG_FOOTER_BYTES; }
|
||||
int GetFieldsOffset() { return GetHasHeader() ? APE_TAG_FOOTER_BYTES : 0; }
|
||||
int GetNumberFields() { return m_nFields; }
|
||||
BOOL GetHasHeader() { return (m_nFlags & APE_TAG_FLAG_CONTAINS_HEADER) ? TRUE : FALSE; }
|
||||
BOOL GetIsHeader() { return (m_nFlags & APE_TAG_FLAG_IS_HEADER) ? TRUE : FALSE; }
|
||||
int GetVersion() { return m_nVersion; }
|
||||
|
||||
BOOL GetIsValid(BOOL bAllowHeader)
|
||||
{
|
||||
BOOL bValid = (strncmp(m_cID, "APETAGEX", 8) == 0) &&
|
||||
(m_nVersion <= CURRENT_APE_TAG_VERSION) &&
|
||||
(m_nFields <= 65536) &&
|
||||
(GetFieldBytes() <= (1024 * 1024 * 16));
|
||||
|
||||
if (bValid && (bAllowHeader == FALSE) && GetIsHeader())
|
||||
bValid = FALSE;
|
||||
|
||||
return bValid ? TRUE : FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
CAPETagField class (an APE tag is an array of these)
|
||||
*****************************************************************************************/
|
||||
class CAPETagField
|
||||
{
|
||||
public:
|
||||
|
||||
// create a tag field (use nFieldBytes = -1 for null-terminated strings)
|
||||
CAPETagField(const str_utf16 * pFieldName, const void * pFieldValue, int nFieldBytes = -1, int nFlags = 0);
|
||||
|
||||
// destructor
|
||||
~CAPETagField();
|
||||
|
||||
// gets the size of the entire field in bytes (name, value, and metadata)
|
||||
int GetFieldSize();
|
||||
|
||||
// get the name of the field
|
||||
const str_utf16 * GetFieldName();
|
||||
|
||||
// get the value of the field
|
||||
const char * GetFieldValue();
|
||||
|
||||
// get the size of the value (in bytes)
|
||||
int GetFieldValueSize();
|
||||
|
||||
// get any special flags
|
||||
int GetFieldFlags();
|
||||
|
||||
// output the entire field to a buffer (GetFieldSize() bytes)
|
||||
int SaveField(char * pBuffer);
|
||||
|
||||
// checks to see if the field is read-only
|
||||
BOOL GetIsReadOnly() { return (m_nFieldFlags & TAG_FIELD_FLAG_READ_ONLY) ? TRUE : FALSE; }
|
||||
BOOL GetIsUTF8Text() { return ((m_nFieldFlags & TAG_FIELD_FLAG_DATA_TYPE_MASK) == TAG_FIELD_FLAG_DATA_TYPE_TEXT_UTF8) ? TRUE : FALSE; }
|
||||
|
||||
// set helpers (use with EXTREME caution)
|
||||
void SetFieldFlags(int nFlags) { m_nFieldFlags = nFlags; }
|
||||
|
||||
private:
|
||||
|
||||
CSmartPtr<str_utf16> m_spFieldNameUTF16;
|
||||
CSmartPtr<char> m_spFieldValue;
|
||||
int m_nFieldFlags;
|
||||
int m_nFieldValueBytes;
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
CAPETag class
|
||||
*****************************************************************************************/
|
||||
class CAPETag
|
||||
{
|
||||
public:
|
||||
|
||||
// create an APE tag
|
||||
// bAnalyze determines whether it will analyze immediately or on the first request
|
||||
// be careful with multiple threads / file pointer movement if you don't analyze immediately
|
||||
CAPETag(CIO * pIO, BOOL bAnalyze = TRUE);
|
||||
CAPETag(const str_utf16 * pFilename, BOOL bAnalyze = TRUE);
|
||||
|
||||
// destructor
|
||||
~CAPETag();
|
||||
|
||||
// save the tag to the I/O source (bUseOldID3 forces it to save as an ID3v1.1 tag instead of an APE tag)
|
||||
int Save(BOOL bUseOldID3 = FALSE);
|
||||
|
||||
// removes any tags from the file (bUpdate determines whether is should re-analyze after removing the tag)
|
||||
int Remove(BOOL bUpdate = TRUE);
|
||||
|
||||
// sets the value of a field (use nFieldBytes = -1 for null terminated strings)
|
||||
// note: using NULL or "" for a string type will remove the field
|
||||
int SetFieldString(const str_utf16 * pFieldName, const str_utf16 * pFieldValue);
|
||||
int SetFieldString(const str_utf16 * pFieldName, const char * pFieldValue, BOOL bAlreadyUTF8Encoded);
|
||||
int SetFieldBinary(const str_utf16 * pFieldName, const void * pFieldValue, int nFieldBytes, int nFieldFlags);
|
||||
|
||||
// gets the value of a field (returns -1 and an empty buffer if the field doesn't exist)
|
||||
int GetFieldBinary(const str_utf16 * pFieldName, void * pBuffer, int * pBufferBytes);
|
||||
int GetFieldString(const str_utf16 * pFieldName, str_utf16 * pBuffer, int * pBufferCharacters);
|
||||
int GetFieldString(const str_utf16 * pFieldName, str_ansi * pBuffer, int * pBufferCharacters, BOOL bUTF8Encode = FALSE);
|
||||
|
||||
// remove a specific field
|
||||
int RemoveField(const str_utf16 * pFieldName);
|
||||
int RemoveField(int nIndex);
|
||||
|
||||
// clear all the fields
|
||||
int ClearFields();
|
||||
|
||||
// get the total tag bytes in the file from the last analyze
|
||||
// need to call Save() then Analyze() to update any changes
|
||||
int GetTagBytes();
|
||||
|
||||
// fills in an ID3_TAG using the current fields (useful for quickly converting the tag)
|
||||
int CreateID3Tag(ID3_TAG * pID3Tag);
|
||||
|
||||
// see whether the file has an ID3 or APE tag
|
||||
BOOL GetHasID3Tag() { if (m_bAnalyzed == FALSE) { Analyze(); } return m_bHasID3Tag; }
|
||||
BOOL GetHasAPETag() { if (m_bAnalyzed == FALSE) { Analyze(); } return m_bHasAPETag; }
|
||||
int GetAPETagVersion() { return GetHasAPETag() ? m_nAPETagVersion : -1; }
|
||||
|
||||
// gets a desired tag field (returns NULL if not found)
|
||||
// again, be careful, because this a pointer to the actual field in this class
|
||||
CAPETagField * GetTagField(const str_utf16 * pFieldName);
|
||||
CAPETagField * GetTagField(int nIndex);
|
||||
|
||||
// options
|
||||
void SetIgnoreReadOnly(BOOL bIgnoreReadOnly) { m_bIgnoreReadOnly = bIgnoreReadOnly; }
|
||||
|
||||
private:
|
||||
|
||||
// private functions
|
||||
int Analyze();
|
||||
int GetTagFieldIndex(const str_utf16 * pFieldName);
|
||||
int WriteBufferToEndOfIO(void * pBuffer, int nBytes);
|
||||
int LoadField(const char * pBuffer, int nMaximumBytes, int * pBytes);
|
||||
int SortFields();
|
||||
static int CompareFields(const void * pA, const void * pB);
|
||||
|
||||
// helper set / get field functions
|
||||
int SetFieldID3String(const str_utf16 * pFieldName, const char * pFieldValue, int nBytes);
|
||||
int GetFieldID3String(const str_utf16 * pFieldName, char * pBuffer, int nBytes);
|
||||
|
||||
// private data
|
||||
CSmartPtr<CIO> m_spIO;
|
||||
BOOL m_bAnalyzed;
|
||||
int m_nTagBytes;
|
||||
int m_nFields;
|
||||
CAPETagField * m_aryFields[256];
|
||||
BOOL m_bHasAPETag;
|
||||
int m_nAPETagVersion;
|
||||
BOOL m_bHasID3Tag;
|
||||
BOOL m_bIgnoreReadOnly;
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_APETAG_H
|
||||
|
||||
12
MAC_SDK/Source/MACLib/Assembly/Assembly.h
Normal file
12
MAC_SDK/Source/MACLib/Assembly/Assembly.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#ifndef APE_ASSEMBLY_H
|
||||
#define APE_ASSEMBLY_H
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void Adapt(short * pM, const short * pAdapt, int nDirection, int nOrder);
|
||||
int CalculateDotProduct(const short * pA, const short * pB, int nOrder);
|
||||
BOOL GetMMXAvailable();
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_ASSEMBLY_H
|
||||
|
||||
181
MAC_SDK/Source/MACLib/Assembly/Assembly.nas
Normal file
181
MAC_SDK/Source/MACLib/Assembly/Assembly.nas
Normal file
@@ -0,0 +1,181 @@
|
||||
|
||||
%include "Tools.inc"
|
||||
|
||||
segment_code
|
||||
|
||||
;
|
||||
; void Adapt ( short* pM, const short* pAdapt, int nDirection, int nOrder )
|
||||
;
|
||||
; [esp+16] nOrder
|
||||
; [esp+12] nDirection
|
||||
; [esp+ 8] pAdapt
|
||||
; [esp+ 4] pM
|
||||
; [esp+ 0] Return Address
|
||||
|
||||
align 16
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
proc Adapt
|
||||
|
||||
mov eax, [esp + 4] ; pM
|
||||
mov ecx, [esp + 8] ; pAdapt
|
||||
mov edx, [esp + 16] ; nOrder
|
||||
shr edx, 4
|
||||
|
||||
cmp dword [esp + 12], byte 0 ; nDirection
|
||||
jle short AdaptSub
|
||||
|
||||
AdaptAddLoop:
|
||||
movq mm0, [eax]
|
||||
paddw mm0, [ecx]
|
||||
movq [eax], mm0
|
||||
movq mm1, [eax + 8]
|
||||
paddw mm1, [ecx + 8]
|
||||
movq [eax + 8], mm1
|
||||
movq mm2, [eax + 16]
|
||||
paddw mm2, [ecx + 16]
|
||||
movq [eax + 16], mm2
|
||||
movq mm3, [eax + 24]
|
||||
paddw mm3, [ecx + 24]
|
||||
movq [eax + 24], mm3
|
||||
add eax, byte 32
|
||||
add ecx, byte 32
|
||||
dec edx
|
||||
jnz AdaptAddLoop
|
||||
|
||||
emms
|
||||
ret
|
||||
|
||||
align 16
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
AdaptSub: je short AdaptDone
|
||||
|
||||
AdaptSubLoop:
|
||||
movq mm0, [eax]
|
||||
psubw mm0, [ecx]
|
||||
movq [eax], mm0
|
||||
movq mm1, [eax + 8]
|
||||
psubw mm1, [ecx + 8]
|
||||
movq [eax + 8], mm1
|
||||
movq mm2, [eax + 16]
|
||||
psubw mm2, [ecx + 16]
|
||||
movq [eax + 16], mm2
|
||||
movq mm3, [eax + 24]
|
||||
psubw mm3, [ecx + 24]
|
||||
movq [eax + 24], mm3
|
||||
add eax, byte 32
|
||||
add ecx, byte 32
|
||||
dec edx
|
||||
jnz AdaptSubLoop
|
||||
|
||||
emms
|
||||
AdaptDone:
|
||||
|
||||
endproc
|
||||
|
||||
;
|
||||
; int CalculateDotProduct ( const short* pA, const short* pB, int nOrder )
|
||||
;
|
||||
; [esp+12] nOrder
|
||||
; [esp+ 8] pB
|
||||
; [esp+ 4] pA
|
||||
; [esp+ 0] Return Address
|
||||
|
||||
align 16
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
proc CalculateDotProduct
|
||||
|
||||
mov eax, [esp + 4] ; pA
|
||||
mov ecx, [esp + 8] ; pB
|
||||
mov edx, [esp + 12] ; nOrder
|
||||
shr edx, 4
|
||||
pxor mm7, mm7
|
||||
|
||||
loopDot: movq mm0, [eax]
|
||||
pmaddwd mm0, [ecx]
|
||||
paddd mm7, mm0
|
||||
movq mm1, [eax + 8]
|
||||
pmaddwd mm1, [ecx + 8]
|
||||
paddd mm7, mm1
|
||||
movq mm2, [eax + 16]
|
||||
pmaddwd mm2, [ecx + 16]
|
||||
paddd mm7, mm2
|
||||
movq mm3, [eax + 24]
|
||||
pmaddwd mm3, [ecx + 24]
|
||||
add eax, byte 32
|
||||
add ecx, byte 32
|
||||
paddd mm7, mm3
|
||||
dec edx
|
||||
jnz loopDot
|
||||
|
||||
movq mm6, mm7
|
||||
psrlq mm7, 32
|
||||
paddd mm6, mm7
|
||||
movd [esp + 4], mm6
|
||||
emms
|
||||
mov eax, [esp + 4]
|
||||
endproc
|
||||
|
||||
|
||||
;
|
||||
; BOOL GetMMXAvailable ( void );
|
||||
;
|
||||
|
||||
proc GetMMXAvailable
|
||||
pushad
|
||||
pushfd
|
||||
pop eax
|
||||
mov ecx, eax
|
||||
xor eax, 0x200000
|
||||
push eax
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
cmp eax, ecx
|
||||
jz short return ; no CPUID command, so no MMX
|
||||
|
||||
mov eax,1
|
||||
CPUID
|
||||
test edx,0x800000
|
||||
return: popad
|
||||
setnz al
|
||||
and eax, byte 1
|
||||
endproc
|
||||
|
||||
end
|
||||
BIN
MAC_SDK/Source/MACLib/Assembly/Assembly.obj
Normal file
BIN
MAC_SDK/Source/MACLib/Assembly/Assembly.obj
Normal file
Binary file not shown.
180
MAC_SDK/Source/MACLib/Assembly/Assembly64.bak
Normal file
180
MAC_SDK/Source/MACLib/Assembly/Assembly64.bak
Normal file
@@ -0,0 +1,180 @@
|
||||
|
||||
%include "Tools64.inc"
|
||||
|
||||
segment_code
|
||||
|
||||
;
|
||||
; void Adapt ( short* pM, const short* pAdapt, int nDirection, int nOrder )
|
||||
;
|
||||
; r9d nOrder
|
||||
; r8d nDirection
|
||||
; rdx pAdapt
|
||||
; rcx pM
|
||||
; [esp+ 0] Return Address
|
||||
|
||||
align 16
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
proc Adapt
|
||||
|
||||
shr r9d, 4
|
||||
|
||||
cmp r8d, byte 0 ; nDirection
|
||||
jle short AdaptSub
|
||||
|
||||
AdaptAddLoop:
|
||||
movq mm0, [rcx]
|
||||
paddw mm0, [rdx]
|
||||
movq [rcx], mm0
|
||||
movq mm1, [rcx + 8]
|
||||
paddw mm1, [rdx + 8]
|
||||
movq [rcx + 8], mm1
|
||||
movq mm2, [rcx + 16]
|
||||
paddw mm2, [rdx + 16]
|
||||
movq [rcx + 16], mm2
|
||||
movq mm3, [rcx + 24]
|
||||
paddw mm3, [rdx + 24]
|
||||
movq [rcx + 24], mm3
|
||||
add rcx, byte 32
|
||||
add rdx, byte 32
|
||||
dec r9d
|
||||
jnz AdaptAddLoop
|
||||
|
||||
emms
|
||||
ret
|
||||
|
||||
align 16
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
AdaptSub: je short AdaptDone
|
||||
|
||||
AdaptSubLoop:
|
||||
movq mm0, [rcx]
|
||||
psubw mm0, [rdx]
|
||||
movq [rcx], mm0
|
||||
movq mm1, [rcx + 8]
|
||||
psubw mm1, [rdx + 8]
|
||||
movq [rcx + 8], mm1
|
||||
movq mm2, [rcx + 16]
|
||||
psubw mm2, [rdx + 16]
|
||||
movq [rcx + 16], mm2
|
||||
movq mm3, [rcx + 24]
|
||||
psubw mm3, [rdx + 24]
|
||||
movq [rcx + 24], mm3
|
||||
add rcx, byte 32
|
||||
add rdx, byte 32
|
||||
dec r9d
|
||||
jnz AdaptSubLoop
|
||||
|
||||
emms
|
||||
AdaptDone:
|
||||
|
||||
endproc
|
||||
|
||||
;
|
||||
; int CalculateDotProduct ( const short* pA, const short* pB, int nOrder )
|
||||
;
|
||||
; [esp+12] nOrder
|
||||
; [esp+ 8] pB
|
||||
; [esp+ 4] pA
|
||||
; [esp+ 0] Return Address
|
||||
|
||||
align 16
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
proc CalculateDotProduct
|
||||
|
||||
shr r8d, 4
|
||||
pxor mm7, mm7
|
||||
|
||||
loopDot: movq mm0, [rcx] ;pA
|
||||
pmaddwd mm0, [rdx] ;pB
|
||||
paddd mm7, mm0
|
||||
movq mm1, [rcx + 8]
|
||||
pmaddwd mm1, [rdx + 8]
|
||||
paddd mm7, mm1
|
||||
movq mm2, [rcx + 16]
|
||||
pmaddwd mm2, [rdx + 16]
|
||||
paddd mm7, mm2
|
||||
movq mm3, [rcx + 24]
|
||||
pmaddwd mm3, [rdx + 24]
|
||||
add rcx, byte 32
|
||||
add rdx, byte 32
|
||||
paddd mm7, mm3
|
||||
dec r8d
|
||||
jnz loopDot
|
||||
|
||||
movq mm6, mm7
|
||||
psrlq mm7, 32
|
||||
paddd mm6, mm7
|
||||
movd eax, mm6
|
||||
emms
|
||||
endproc
|
||||
|
||||
|
||||
;
|
||||
; BOOL GetMMXAvailable ( void );
|
||||
;
|
||||
|
||||
proc GetMMXAvailable
|
||||
push rax
|
||||
push rcx
|
||||
push rdx
|
||||
push rbx
|
||||
pushfq
|
||||
pop rax
|
||||
mov rcx, rax
|
||||
xor rax, 0x200000
|
||||
push rax
|
||||
popfq
|
||||
pushfq
|
||||
pop rax
|
||||
cmp rax, rcx
|
||||
jz short return ; no CPUID command, so no MMX
|
||||
|
||||
mov rax,1
|
||||
CPUID
|
||||
test rdx,0x800000
|
||||
return: pop rbx
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rax
|
||||
setnz al
|
||||
and eax, byte 1
|
||||
endproc
|
||||
|
||||
end
|
||||
240
MAC_SDK/Source/MACLib/Assembly/Assembly64.nas
Normal file
240
MAC_SDK/Source/MACLib/Assembly/Assembly64.nas
Normal file
@@ -0,0 +1,240 @@
|
||||
|
||||
%include "Tools64.inc"
|
||||
|
||||
segment_code
|
||||
|
||||
;
|
||||
; void Adapt ( short* pM, const short* pAdapt, int nDirection, int nOrder )
|
||||
;
|
||||
; r9d nOrder
|
||||
; r8d nDirection
|
||||
; rdx pAdapt
|
||||
; rcx pM
|
||||
; [esp+ 0] Return Address
|
||||
|
||||
align 16
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
proc Adapt
|
||||
|
||||
shr r9d, 4
|
||||
|
||||
cmp r8d, byte 0 ; nDirection
|
||||
jle short AdaptSub
|
||||
|
||||
AdaptAddLoop:
|
||||
movq mm0, [rcx]
|
||||
paddw mm0, [rdx]
|
||||
movq [rcx], mm0
|
||||
movq mm1, [rcx + 8]
|
||||
paddw mm1, [rdx + 8]
|
||||
movq [rcx + 8], mm1
|
||||
movq mm2, [rcx + 16]
|
||||
paddw mm2, [rdx + 16]
|
||||
movq [rcx + 16], mm2
|
||||
movq mm3, [rcx + 24]
|
||||
paddw mm3, [rdx + 24]
|
||||
movq [rcx + 24], mm3
|
||||
add rcx, byte 32
|
||||
add rdx, byte 32
|
||||
dec r9d
|
||||
jnz AdaptAddLoop
|
||||
|
||||
emms
|
||||
ret
|
||||
|
||||
align 16
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
AdaptSub: je short AdaptDone
|
||||
|
||||
AdaptSubLoop:
|
||||
movq mm0, [rcx]
|
||||
psubw mm0, [rdx]
|
||||
movq [rcx], mm0
|
||||
movq mm1, [rcx + 8]
|
||||
psubw mm1, [rdx + 8]
|
||||
movq [rcx + 8], mm1
|
||||
movq mm2, [rcx + 16]
|
||||
psubw mm2, [rdx + 16]
|
||||
movq [rcx + 16], mm2
|
||||
movq mm3, [rcx + 24]
|
||||
psubw mm3, [rdx + 24]
|
||||
movq [rcx + 24], mm3
|
||||
add rcx, byte 32
|
||||
add rdx, byte 32
|
||||
dec r9d
|
||||
jnz AdaptSubLoop
|
||||
|
||||
emms
|
||||
AdaptDone:
|
||||
|
||||
endproc
|
||||
|
||||
;
|
||||
; int CalculateDotProduct ( const short* pA, const short* pB, int nOrder )
|
||||
;
|
||||
; [esp+12] nOrder
|
||||
; [esp+ 8] pB
|
||||
; [esp+ 4] pA
|
||||
; [esp+ 0] Return Address
|
||||
|
||||
align 16
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
proc CalculateDotProduct
|
||||
|
||||
shr r8d, 4
|
||||
pxor mm7, mm7
|
||||
|
||||
loopDot: movq mm0, [rcx] ;pA
|
||||
pmaddwd mm0, [rdx] ;pB
|
||||
paddd mm7, mm0
|
||||
movq mm1, [rcx + 8]
|
||||
pmaddwd mm1, [rdx + 8]
|
||||
paddd mm7, mm1
|
||||
movq mm2, [rcx + 16]
|
||||
pmaddwd mm2, [rdx + 16]
|
||||
paddd mm7, mm2
|
||||
movq mm3, [rcx + 24]
|
||||
pmaddwd mm3, [rdx + 24]
|
||||
add rcx, byte 32
|
||||
add rdx, byte 32
|
||||
paddd mm7, mm3
|
||||
dec r8d
|
||||
jnz loopDot
|
||||
|
||||
movq mm6, mm7
|
||||
psrlq mm7, 32
|
||||
paddd mm6, mm7
|
||||
movd eax, mm6
|
||||
emms
|
||||
endproc
|
||||
|
||||
;
|
||||
; int CalculateDotProduct ( const short* pA, const short* pB, int nOrder )
|
||||
;
|
||||
; [esp+12] nOrder
|
||||
; [esp+ 8] pB
|
||||
; [esp+ 4] pA
|
||||
; [esp+ 0] Return Address
|
||||
|
||||
align 16
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
proc CalculateDotProductXMM
|
||||
|
||||
shr r8d, 4
|
||||
pxor xmm7, xmm7
|
||||
|
||||
loopDotXMM: movdqu xmm0, [rcx] ;pA
|
||||
pmaddwd xmm0, [rdx] ;pB
|
||||
paddd xmm7, xmm0
|
||||
movdqu xmm1, [rcx + 16]
|
||||
pmaddwd xmm1, [rdx + 16]
|
||||
; paddd xmm7, xmm1
|
||||
; movq xmm2, [rcx + 32]
|
||||
; pmaddwd xmm2, [rdx + 32]
|
||||
; paddd xmm7, mm2
|
||||
; movq xmm3, [rcx + 48]
|
||||
; pmaddwd xmm3, [rdx + 48]
|
||||
add rcx, byte 32
|
||||
add rdx, byte 32
|
||||
; paddd xmm7, xmm3
|
||||
paddd xmm7, xmm1
|
||||
dec r8d
|
||||
jnz loopDotXMM
|
||||
|
||||
movq xmm5, xmm7
|
||||
psrldq xmm5, 16
|
||||
movq xmm4, xmm5
|
||||
psrlq xmm5, 32
|
||||
movq xmm6, xmm7
|
||||
psrlq xmm7, 32
|
||||
paddd xmm6, xmm4
|
||||
paddd xmm6, xmm5
|
||||
paddd xmm6, xmm7
|
||||
movd eax, xmm6
|
||||
emms
|
||||
endproc
|
||||
|
||||
|
||||
;
|
||||
; BOOL GetMMXAvailable ( void );
|
||||
;
|
||||
|
||||
proc GetMMXAvailable
|
||||
push rax
|
||||
push rcx
|
||||
push rdx
|
||||
push rbx
|
||||
pushfq
|
||||
pop rax
|
||||
mov rcx, rax
|
||||
xor rax, 0x200000
|
||||
push rax
|
||||
popfq
|
||||
pushfq
|
||||
pop rax
|
||||
cmp rax, rcx
|
||||
jz short return ; no CPUID command, so no MMX
|
||||
|
||||
mov rax,1
|
||||
CPUID
|
||||
test rdx,0x800000
|
||||
return: pop rbx
|
||||
pop rdx
|
||||
pop rcx
|
||||
pop rax
|
||||
setnz al
|
||||
and eax, byte 1
|
||||
endproc
|
||||
|
||||
; end
|
||||
BIN
MAC_SDK/Source/MACLib/Assembly/Assembly64.obj
Normal file
BIN
MAC_SDK/Source/MACLib/Assembly/Assembly64.obj
Normal file
Binary file not shown.
117
MAC_SDK/Source/MACLib/Assembly/Tools.inc
Normal file
117
MAC_SDK/Source/MACLib/Assembly/Tools.inc
Normal file
@@ -0,0 +1,117 @@
|
||||
;
|
||||
; (C) Ururi 1999
|
||||
;
|
||||
|
||||
BITS 32
|
||||
|
||||
%ifdef WIN32
|
||||
%define _NAMING
|
||||
%define segment_code segment .text align=32 class=CODE use32
|
||||
%define segment_data segment .data align=32 class=DATA use32
|
||||
%ifdef __BORLANDC__
|
||||
%define segment_bss segment .data align=32 class=DATA use32
|
||||
%else
|
||||
%define segment_bss segment .bss align=32 class=DATA use32
|
||||
%endif
|
||||
|
||||
%elifdef AOUT
|
||||
%define _NAMING
|
||||
%define segment_code segment .text
|
||||
%define segment_data segment .data
|
||||
%define segment_bss segment .bss
|
||||
|
||||
%else
|
||||
%define segment_code segment .text align=32 class=CODE use32
|
||||
%define segment_data segment .data align=32 class=DATA use32
|
||||
%define segment_bss segment .bss align=32 class=DATA use32
|
||||
%endif
|
||||
|
||||
%define pmov movq
|
||||
%define pmovd movd
|
||||
|
||||
%define pupldq punpckldq
|
||||
%define puphdq punpckhdq
|
||||
%define puplwd punpcklwd
|
||||
%define puphwd punpckhwd
|
||||
|
||||
%imacro globaldef 1
|
||||
%ifdef _NAMING
|
||||
%define %1 _%1
|
||||
%endif
|
||||
global %1
|
||||
%endmacro
|
||||
|
||||
%imacro externdef 1
|
||||
%ifdef _NAMING
|
||||
%define %1 _%1
|
||||
%endif
|
||||
extern %1
|
||||
%endmacro
|
||||
|
||||
%imacro proc 1
|
||||
%push proc
|
||||
global _%1
|
||||
global %1
|
||||
_%1:
|
||||
%1:
|
||||
%assign %$STACK 0
|
||||
%assign %$STACKN 0
|
||||
%assign %$ARG 4
|
||||
%endmacro
|
||||
|
||||
%imacro endproc 0
|
||||
%ifnctx proc
|
||||
%error expected 'proc' before 'endproc'.
|
||||
%else
|
||||
%if %$STACK > 0
|
||||
add esp, %$STACK
|
||||
%endif
|
||||
|
||||
%if %$STACK <> (-%$STACKN)
|
||||
%error STACKLEVEL mismatch check 'local', 'alloc', 'pushd', 'popd'
|
||||
%endif
|
||||
|
||||
ret
|
||||
%pop
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
%idefine sp(a) esp+%$STACK+a
|
||||
|
||||
%imacro arg 1
|
||||
%00 equ %$ARG
|
||||
%assign %$ARG %$ARG+%1
|
||||
%endmacro
|
||||
|
||||
%imacro local 1
|
||||
%assign %$STACKN %$STACKN-%1
|
||||
%00 equ %$STACKN
|
||||
%endmacro
|
||||
|
||||
%imacro alloc 0
|
||||
sub esp, (-%$STACKN)-%$STACK
|
||||
%assign %$STACK (-%$STACKN)
|
||||
%endmacro
|
||||
|
||||
%imacro pushd 1-*
|
||||
%rep %0
|
||||
push %1
|
||||
%assign %$STACK %$STACK+4
|
||||
%rotate 1
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
%imacro popd 1-*
|
||||
%rep %0
|
||||
%rotate -1
|
||||
pop %1
|
||||
%assign %$STACK %$STACK-4
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
%macro algn 1
|
||||
align 16
|
||||
%rep (65536-%1) & 15
|
||||
nop
|
||||
%endrep
|
||||
%endm
|
||||
119
MAC_SDK/Source/MACLib/Assembly/Tools64.inc
Normal file
119
MAC_SDK/Source/MACLib/Assembly/Tools64.inc
Normal file
@@ -0,0 +1,119 @@
|
||||
;
|
||||
; (C) Ururi 1999
|
||||
;
|
||||
|
||||
BITS 64
|
||||
|
||||
CPU X64
|
||||
|
||||
%ifdef WIN32
|
||||
%define _NAMING
|
||||
%define segment_code segment .text align=32 class=CODE use32
|
||||
%define segment_data segment .data align=32 class=DATA use32
|
||||
%ifdef __BORLANDC__
|
||||
%define segment_bss segment .data align=32 class=DATA use32
|
||||
%else
|
||||
%define segment_bss segment .bss align=32 class=DATA use32
|
||||
%endif
|
||||
|
||||
%elifdef AOUT
|
||||
%define _NAMING
|
||||
%define segment_code segment .text
|
||||
%define segment_data segment .data
|
||||
%define segment_bss segment .bss
|
||||
|
||||
%else
|
||||
%define segment_code segment .text align=32 class=CODE use32
|
||||
%define segment_data segment .data align=32 class=DATA use32
|
||||
%define segment_bss segment .bss align=32 class=DATA use32
|
||||
%endif
|
||||
|
||||
%define pmov movq
|
||||
%define pmovd movd
|
||||
|
||||
%define pupldq punpckldq
|
||||
%define puphdq punpckhdq
|
||||
%define puplwd punpcklwd
|
||||
%define puphwd punpckhwd
|
||||
|
||||
%imacro globaldef 1
|
||||
%ifdef _NAMING
|
||||
%define %1 _%1
|
||||
%endif
|
||||
global %1
|
||||
%endmacro
|
||||
|
||||
%imacro externdef 1
|
||||
%ifdef _NAMING
|
||||
%define %1 _%1
|
||||
%endif
|
||||
extern %1
|
||||
%endmacro
|
||||
|
||||
%imacro proc 1
|
||||
%push proc
|
||||
global _%1
|
||||
global %1
|
||||
_%1:
|
||||
%1:
|
||||
%assign %$STACK 0
|
||||
%assign %$STACKN 0
|
||||
%assign %$ARG 4
|
||||
%endmacro
|
||||
|
||||
%imacro endproc 0
|
||||
%ifnctx proc
|
||||
%error expected 'proc' before 'endproc'.
|
||||
%else
|
||||
%if %$STACK > 0
|
||||
add esp, %$STACK
|
||||
%endif
|
||||
|
||||
%if %$STACK <> (-%$STACKN)
|
||||
%error STACKLEVEL mismatch check 'local', 'alloc', 'pushd', 'popd'
|
||||
%endif
|
||||
|
||||
ret
|
||||
%pop
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
%idefine sp(a) esp+%$STACK+a
|
||||
|
||||
%imacro arg 1
|
||||
%00 equ %$ARG
|
||||
%assign %$ARG %$ARG+%1
|
||||
%endmacro
|
||||
|
||||
%imacro local 1
|
||||
%assign %$STACKN %$STACKN-%1
|
||||
%00 equ %$STACKN
|
||||
%endmacro
|
||||
|
||||
%imacro alloc 0
|
||||
sub esp, (-%$STACKN)-%$STACK
|
||||
%assign %$STACK (-%$STACKN)
|
||||
%endmacro
|
||||
|
||||
%imacro pushd 1-*
|
||||
%rep %0
|
||||
push %1
|
||||
%assign %$STACK %$STACK+4
|
||||
%rotate 1
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
%imacro popd 1-*
|
||||
%rep %0
|
||||
%rotate -1
|
||||
pop %1
|
||||
%assign %$STACK %$STACK-4
|
||||
%endrep
|
||||
%endmacro
|
||||
|
||||
%macro algn 1
|
||||
align 16
|
||||
%rep (65536-%1) & 15
|
||||
nop
|
||||
%endrep
|
||||
%endm
|
||||
41
MAC_SDK/Source/MACLib/Assembly/hhh
Normal file
41
MAC_SDK/Source/MACLib/Assembly/hhh
Normal file
@@ -0,0 +1,41 @@
|
||||
usage: nasm [-@ response file] [-o outfile] [-f format] [-l listfile]
|
||||
[options...] [--] filename
|
||||
or nasm -v for version info
|
||||
|
||||
-t assemble in SciTech TASM compatible mode
|
||||
-g generate debug information in selected format.
|
||||
-E (or -e) preprocess only (writes output to stdout by default)
|
||||
-a don't preprocess (assemble only)
|
||||
-M generate Makefile dependencies on stdout
|
||||
-MG d:o, missing files assumed generated
|
||||
|
||||
-Z<file> redirect error messages to file
|
||||
-s redirect error messages to stdout
|
||||
|
||||
-F format select a debugging format
|
||||
|
||||
-I<path> adds a pathname to the include file path
|
||||
-O<digit> optimize branch offsets (-O0 disables, default)
|
||||
-P<file> pre-includes a file
|
||||
-D<macro>[=<value>] pre-defines a macro
|
||||
-U<macro> undefines a macro
|
||||
-X<format> specifies error reporting format (gnu or vc)
|
||||
-w+foo enables warning foo (equiv. -Wfoo)
|
||||
-w-foo disable warning foo (equiv. -Wno-foo)
|
||||
Warnings:
|
||||
error treat warnings as errors (default off)
|
||||
macro-params macro calls with wrong parameter count (default on)
|
||||
macro-selfref cyclic macro references (default off)
|
||||
macro-defaults macros with more default than optional parameters (default on)
|
||||
orphan-labels labels alone on lines without trailing `:' (default on)
|
||||
number-overflow numeric constants does not fit in 64 bits (default on)
|
||||
gnu-elf-extensions using 8- or 16-bit relocation in ELF32, a GNU extension (default off)
|
||||
float-overflow floating point overflow (default on)
|
||||
float-denorm floating point denormal (default off)
|
||||
float-underflow floating point underflow (default off)
|
||||
float-toolong too many digits in floating-point number (default on)
|
||||
|
||||
response files should contain command line parameters, one per line.
|
||||
|
||||
For a list of valid output formats, use -hf.
|
||||
For a list of debug formats, use -f <form> -y.
|
||||
434
MAC_SDK/Source/MACLib/BitArray.cpp
Normal file
434
MAC_SDK/Source/MACLib/BitArray.cpp
Normal file
@@ -0,0 +1,434 @@
|
||||
/************************************************************************************
|
||||
Includes
|
||||
************************************************************************************/
|
||||
#include "All.h"
|
||||
#include "BitArray.h"
|
||||
#include "MD5.h"
|
||||
|
||||
/************************************************************************************
|
||||
Declares
|
||||
************************************************************************************/
|
||||
#define BIT_ARRAY_ELEMENTS (4096) // the number of elements in the bit array (4 MB)
|
||||
#define BIT_ARRAY_BYTES (BIT_ARRAY_ELEMENTS * 4) // the number of bytes in the bit array
|
||||
#define BIT_ARRAY_BITS (BIT_ARRAY_BYTES * 8) // the number of bits in the bit array
|
||||
|
||||
#define MAX_ELEMENT_BITS 128
|
||||
#define REFILL_BIT_THRESHOLD (BIT_ARRAY_BITS - MAX_ELEMENT_BITS)
|
||||
|
||||
#define CODE_BITS 32
|
||||
#define TOP_VALUE ((unsigned int) 1 << (CODE_BITS - 1))
|
||||
#define SHIFT_BITS (CODE_BITS - 9)
|
||||
#define EXTRA_BITS ((CODE_BITS - 2) % 8 + 1)
|
||||
#define BOTTOM_VALUE (TOP_VALUE >> 8)
|
||||
|
||||
/************************************************************************************
|
||||
Lookup tables
|
||||
************************************************************************************/
|
||||
const uint32 K_SUM_MIN_BOUNDARY[32] = {0,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,0,0,0,0};
|
||||
|
||||
#define MODEL_ELEMENTS 64
|
||||
#define RANGE_OVERFLOW_TOTAL_WIDTH 65536
|
||||
#define RANGE_OVERFLOW_SHIFT 16
|
||||
|
||||
const uint32 RANGE_TOTAL[64] = {0,19578,36160,48417,56323,60899,63265,64435,64971,65232,65351,65416,65447,65466,65476,65482,65485,65488,65490,65491,65492,65493,65494,65495,65496,65497,65498,65499,65500,65501,65502,65503,65504,65505,65506,65507,65508,65509,65510,65511,65512,65513,65514,65515,65516,65517,65518,65519,65520,65521,65522,65523,65524,65525,65526,65527,65528,65529,65530,65531,65532,65533,65534,65535,};
|
||||
const uint32 RANGE_WIDTH[64] = {19578,16582,12257,7906,4576,2366,1170,536,261,119,65,31,19,10,6,3,3,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,};
|
||||
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
int g_aryOverflows[256] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
int g_nTotalOverflow = 0;
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
Constructor
|
||||
************************************************************************************/
|
||||
CBitArray::CBitArray(CIO *pIO)
|
||||
{
|
||||
// allocate memory for the bit array
|
||||
m_pBitArray = new uint32 [BIT_ARRAY_ELEMENTS];
|
||||
memset(m_pBitArray, 0, BIT_ARRAY_BYTES);
|
||||
|
||||
// initialize other variables
|
||||
m_nCurrentBitIndex = 0;
|
||||
m_pIO = pIO;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Destructor
|
||||
************************************************************************************/
|
||||
CBitArray::~CBitArray()
|
||||
{
|
||||
// free the bit array
|
||||
SAFE_ARRAY_DELETE(m_pBitArray)
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
OutputRangeTable();
|
||||
#endif
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Output the bit array via the CIO (typically saves to disk)
|
||||
************************************************************************************/
|
||||
int CBitArray::OutputBitArray(BOOL bFinalize)
|
||||
{
|
||||
// write the entire file to disk
|
||||
unsigned int nBytesWritten = 0;
|
||||
unsigned int nBytesToWrite = 0;
|
||||
unsigned int nRetVal = 0;
|
||||
|
||||
if (bFinalize)
|
||||
{
|
||||
nBytesToWrite = ((m_nCurrentBitIndex >> 5) * 4) + 4;
|
||||
|
||||
m_MD5.AddData(m_pBitArray, nBytesToWrite);
|
||||
|
||||
RETURN_ON_ERROR(m_pIO->Write(m_pBitArray, nBytesToWrite, &nBytesWritten))
|
||||
|
||||
// reset the bit pointer
|
||||
m_nCurrentBitIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nBytesToWrite = (m_nCurrentBitIndex >> 5) * 4;
|
||||
|
||||
m_MD5.AddData(m_pBitArray, nBytesToWrite);
|
||||
|
||||
RETURN_ON_ERROR(m_pIO->Write(m_pBitArray, nBytesToWrite, &nBytesWritten))
|
||||
|
||||
// move the last value to the front of the bit array
|
||||
m_pBitArray[0] = m_pBitArray[m_nCurrentBitIndex >> 5];
|
||||
m_nCurrentBitIndex = (m_nCurrentBitIndex & 31);
|
||||
|
||||
// zero the rest of the memory (may not need the +1 because of frame byte alignment)
|
||||
memset(&m_pBitArray[1], 0, min(nBytesToWrite + 1, BIT_ARRAY_BYTES - 1));
|
||||
}
|
||||
|
||||
// return a success
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Range coding macros -- ugly, but outperform inline's (every cycle counts here)
|
||||
************************************************************************************/
|
||||
#define PUTC(VALUE) m_pBitArray[m_nCurrentBitIndex >> 5] |= ((VALUE) & 0xFF) << (24 - (m_nCurrentBitIndex & 31)); m_nCurrentBitIndex += 8;
|
||||
#define PUTC_NOCAP(VALUE) m_pBitArray[m_nCurrentBitIndex >> 5] |= (VALUE) << (24 - (m_nCurrentBitIndex & 31)); m_nCurrentBitIndex += 8;
|
||||
|
||||
#define NORMALIZE_RANGE_CODER \
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE) \
|
||||
{ \
|
||||
if (m_RangeCoderInfo.low < (0xFF << SHIFT_BITS)) \
|
||||
{ \
|
||||
PUTC(m_RangeCoderInfo.buffer); \
|
||||
for ( ; m_RangeCoderInfo.help; m_RangeCoderInfo.help--) { PUTC_NOCAP(0xFF); } \
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.low >> SHIFT_BITS); \
|
||||
} \
|
||||
else if (m_RangeCoderInfo.low & TOP_VALUE) \
|
||||
{ \
|
||||
PUTC(m_RangeCoderInfo.buffer + 1); \
|
||||
m_nCurrentBitIndex += (m_RangeCoderInfo.help * 8); \
|
||||
m_RangeCoderInfo.help = 0; \
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.low >> SHIFT_BITS); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
m_RangeCoderInfo.help++; \
|
||||
} \
|
||||
\
|
||||
m_RangeCoderInfo.low = (m_RangeCoderInfo.low << 8) & (TOP_VALUE - 1); \
|
||||
m_RangeCoderInfo.range <<= 8; \
|
||||
}
|
||||
|
||||
#define ENCODE_FAST(RANGE_WIDTH, RANGE_TOTAL, SHIFT) \
|
||||
NORMALIZE_RANGE_CODER \
|
||||
const int nTemp = m_RangeCoderInfo.range >> (SHIFT); \
|
||||
m_RangeCoderInfo.range = nTemp * (RANGE_WIDTH); \
|
||||
m_RangeCoderInfo.low += nTemp * (RANGE_TOTAL);
|
||||
|
||||
#define ENCODE_DIRECT(VALUE, SHIFT) \
|
||||
NORMALIZE_RANGE_CODER \
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range >> (SHIFT); \
|
||||
m_RangeCoderInfo.low += m_RangeCoderInfo.range * (VALUE);
|
||||
|
||||
/************************************************************************************
|
||||
Directly encode bits to the bitstream
|
||||
************************************************************************************/
|
||||
int CBitArray::EncodeBits(unsigned int nValue, int nBits)
|
||||
{
|
||||
// make sure there is room for the data
|
||||
// this is a little slower than ensuring a huge block to start with, but it's safer
|
||||
if (m_nCurrentBitIndex > REFILL_BIT_THRESHOLD)
|
||||
{
|
||||
RETURN_ON_ERROR(OutputBitArray())
|
||||
}
|
||||
|
||||
ENCODE_DIRECT(nValue, nBits);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Encodes an unsigned int to the bit array (no rice coding)
|
||||
************************************************************************************/
|
||||
int CBitArray::EncodeUnsignedLong(unsigned int n)
|
||||
{
|
||||
// make sure there are at least 8 bytes in the buffer
|
||||
if (m_nCurrentBitIndex > (BIT_ARRAY_BYTES - 8))
|
||||
{
|
||||
RETURN_ON_ERROR(OutputBitArray())
|
||||
}
|
||||
|
||||
// encode the value
|
||||
uint32 nBitArrayIndex = m_nCurrentBitIndex >> 5;
|
||||
int nBitIndex = m_nCurrentBitIndex & 31;
|
||||
|
||||
if (nBitIndex == 0)
|
||||
{
|
||||
m_pBitArray[nBitArrayIndex] = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pBitArray[nBitArrayIndex] |= n >> nBitIndex;
|
||||
m_pBitArray[nBitArrayIndex + 1] = n << (32 - nBitIndex);
|
||||
}
|
||||
|
||||
m_nCurrentBitIndex += 32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Advance to a byte boundary (for frame alignment)
|
||||
************************************************************************************/
|
||||
void CBitArray::AdvanceToByteBoundary()
|
||||
{
|
||||
while (m_nCurrentBitIndex % 8)
|
||||
m_nCurrentBitIndex++;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Encode a value
|
||||
************************************************************************************/
|
||||
int CBitArray::EncodeValue(int nEncode, BIT_ARRAY_STATE & BitArrayState)
|
||||
{
|
||||
// make sure there is room for the data
|
||||
// this is a little slower than ensuring a huge block to start with, but it's safer
|
||||
if (m_nCurrentBitIndex > REFILL_BIT_THRESHOLD)
|
||||
{
|
||||
RETURN_ON_ERROR(OutputBitArray())
|
||||
}
|
||||
|
||||
// convert to unsigned
|
||||
nEncode = (nEncode > 0) ? nEncode * 2 - 1 : -nEncode * 2;
|
||||
|
||||
int nOriginalKSum = BitArrayState.nKSum;
|
||||
|
||||
// get the working k
|
||||
int nTempK = (BitArrayState.k) ? BitArrayState.k - 1 : 0;
|
||||
|
||||
// update nKSum
|
||||
BitArrayState.nKSum += ((nEncode + 1) / 2) - ((BitArrayState.nKSum + 16) >> 5);
|
||||
|
||||
// update k
|
||||
if (BitArrayState.nKSum < K_SUM_MIN_BOUNDARY[BitArrayState.k])
|
||||
BitArrayState.k--;
|
||||
else if (BitArrayState.nKSum >= K_SUM_MIN_BOUNDARY[BitArrayState.k + 1])
|
||||
BitArrayState.k++;
|
||||
|
||||
// figure the pivot value
|
||||
int nPivotValue = max(nOriginalKSum / 32, 1);
|
||||
int nOverflow = nEncode / nPivotValue;
|
||||
int nBase = nEncode - (nOverflow * nPivotValue);
|
||||
|
||||
// store the overflow
|
||||
if (nOverflow < (MODEL_ELEMENTS - 1))
|
||||
{
|
||||
ENCODE_FAST(RANGE_WIDTH[nOverflow], RANGE_TOTAL[nOverflow], RANGE_OVERFLOW_SHIFT);
|
||||
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
g_aryOverflows[nOverflow]++;
|
||||
g_nTotalOverflow++;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// store the "special" overflow (tells that perfect k is encoded next)
|
||||
ENCODE_FAST(RANGE_WIDTH[MODEL_ELEMENTS - 1], RANGE_TOTAL[MODEL_ELEMENTS - 1], RANGE_OVERFLOW_SHIFT);
|
||||
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
g_aryOverflows[MODEL_ELEMENTS - 1]++;
|
||||
g_nTotalOverflow++;
|
||||
#endif
|
||||
|
||||
// code the overflow using straight bits
|
||||
ENCODE_DIRECT((nOverflow >> 16) & 0xFFFF, 16);
|
||||
ENCODE_DIRECT(nOverflow & 0xFFFF, 16);
|
||||
}
|
||||
|
||||
// code the base
|
||||
{
|
||||
if (nPivotValue >= (1 << 16))
|
||||
{
|
||||
int nPivotValueBits = 0;
|
||||
while ((nPivotValue >> nPivotValueBits) > 0) { nPivotValueBits++; }
|
||||
int nSplitFactor = 1 << (nPivotValueBits - 16);
|
||||
|
||||
// we know that base is smaller than pivot coming into this
|
||||
// however, after we divide both by an integer, they could be the same
|
||||
// we account by adding one to the pivot, but this hurts compression
|
||||
// by (1 / nSplitFactor) -- therefore we maximize the split factor
|
||||
// that gets one added to it
|
||||
|
||||
// encode the pivot as two pieces
|
||||
int nPivotValueA = (nPivotValue / nSplitFactor) + 1;
|
||||
int nPivotValueB = nSplitFactor;
|
||||
|
||||
int nBaseA = nBase / nSplitFactor;
|
||||
int nBaseB = nBase % nSplitFactor;
|
||||
|
||||
{
|
||||
NORMALIZE_RANGE_CODER
|
||||
const int nTemp = m_RangeCoderInfo.range / nPivotValueA;
|
||||
m_RangeCoderInfo.range = nTemp;
|
||||
m_RangeCoderInfo.low += nTemp * nBaseA;
|
||||
}
|
||||
|
||||
{
|
||||
NORMALIZE_RANGE_CODER
|
||||
const int nTemp = m_RangeCoderInfo.range / nPivotValueB;
|
||||
m_RangeCoderInfo.range = nTemp;
|
||||
m_RangeCoderInfo.low += nTemp * nBaseB;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
NORMALIZE_RANGE_CODER
|
||||
const int nTemp = m_RangeCoderInfo.range / nPivotValue;
|
||||
m_RangeCoderInfo.range = nTemp;
|
||||
m_RangeCoderInfo.low += nTemp * nBase;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Flush
|
||||
************************************************************************************/
|
||||
void CBitArray::FlushBitArray()
|
||||
{
|
||||
// advance to a byte boundary (for alignment)
|
||||
AdvanceToByteBoundary();
|
||||
|
||||
// the range coder
|
||||
m_RangeCoderInfo.low = 0; // full code range
|
||||
m_RangeCoderInfo.range = TOP_VALUE;
|
||||
m_RangeCoderInfo.buffer = 0;
|
||||
m_RangeCoderInfo.help = 0; // no bytes to follow
|
||||
}
|
||||
|
||||
void CBitArray::FlushState(BIT_ARRAY_STATE & BitArrayState)
|
||||
{
|
||||
// k and ksum
|
||||
BitArrayState.k = 10;
|
||||
BitArrayState.nKSum = (1 << BitArrayState.k) * 16;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Finalize
|
||||
************************************************************************************/
|
||||
void CBitArray::Finalize()
|
||||
{
|
||||
NORMALIZE_RANGE_CODER
|
||||
|
||||
unsigned int nTemp = (m_RangeCoderInfo.low >> SHIFT_BITS) + 1;
|
||||
|
||||
if (nTemp > 0xFF) // we have a carry
|
||||
{
|
||||
PUTC(m_RangeCoderInfo.buffer + 1);
|
||||
for ( ; m_RangeCoderInfo.help; m_RangeCoderInfo.help--)
|
||||
{
|
||||
PUTC(0);
|
||||
}
|
||||
}
|
||||
else // no carry
|
||||
{
|
||||
PUTC(m_RangeCoderInfo.buffer);
|
||||
for ( ; m_RangeCoderInfo.help; m_RangeCoderInfo.help--)
|
||||
{
|
||||
PUTC(((unsigned char) 0xFF));
|
||||
}
|
||||
}
|
||||
|
||||
// we must output these bytes so the decoder can properly work at the end of the stream
|
||||
PUTC(nTemp & 0xFF);
|
||||
PUTC(0);
|
||||
PUTC(0);
|
||||
PUTC(0);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Build a range table (for development / debugging)
|
||||
************************************************************************************/
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
void CBitArray::OutputRangeTable()
|
||||
{
|
||||
int z;
|
||||
|
||||
if (g_nTotalOverflow == 0) return;
|
||||
|
||||
int nTotal = 0;
|
||||
int aryWidth[256]; ZeroMemory(aryWidth, 256 * 4);
|
||||
for (z = 0; z < MODEL_ELEMENTS; z++)
|
||||
{
|
||||
aryWidth[z] = int(((float(g_aryOverflows[z]) * float(65536)) + (g_nTotalOverflow / 2)) / float(g_nTotalOverflow));
|
||||
if (aryWidth[z] == 0) aryWidth[z] = 1;
|
||||
nTotal += aryWidth[z];
|
||||
}
|
||||
|
||||
z = 0;
|
||||
while (nTotal > 65536)
|
||||
{
|
||||
if (aryWidth[z] != 1)
|
||||
{
|
||||
aryWidth[z]--;
|
||||
nTotal--;
|
||||
}
|
||||
z++;
|
||||
if (z == MODEL_ELEMENTS) z = 0;
|
||||
}
|
||||
|
||||
z = 0;
|
||||
while (nTotal < 65536)
|
||||
{
|
||||
aryWidth[z++]++;
|
||||
nTotal++;
|
||||
if (z == MODEL_ELEMENTS) z = 0;
|
||||
}
|
||||
|
||||
int aryTotal[256]; ZeroMemory(aryTotal, 256 * 4);
|
||||
for (z = 0; z < MODEL_ELEMENTS; z++)
|
||||
{
|
||||
for (int q = 0; q < z; q++)
|
||||
{
|
||||
aryTotal[z] += aryWidth[q];
|
||||
}
|
||||
}
|
||||
|
||||
TCHAR buf[1024];
|
||||
_stprintf(buf, _T("const uint32 RANGE_TOTAL[%d] = {"), MODEL_ELEMENTS);
|
||||
ODS(buf);
|
||||
for (z = 0; z < MODEL_ELEMENTS; z++)
|
||||
{
|
||||
_stprintf(buf, _T("%d,"), aryTotal[z]);
|
||||
OutputDebugString(buf);
|
||||
}
|
||||
ODS(_T("};\n"));
|
||||
|
||||
_stprintf(buf, _T("const uint32 RANGE_WIDTH[%d] = {"), MODEL_ELEMENTS);
|
||||
ODS(buf);
|
||||
for (z = 0; z < MODEL_ELEMENTS; z++)
|
||||
{
|
||||
_stprintf(buf, _T("%d,"), aryWidth[z]);
|
||||
OutputDebugString(buf);
|
||||
}
|
||||
ODS(_T("};\n\n"));
|
||||
}
|
||||
#endif // #ifdef BUILD_RANGE_TABLE
|
||||
62
MAC_SDK/Source/MACLib/BitArray.h
Normal file
62
MAC_SDK/Source/MACLib/BitArray.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef APE_BITARRAY_H
|
||||
#define APE_BITARRAY_H
|
||||
|
||||
#include "IO.h"
|
||||
#include "MD5.h"
|
||||
|
||||
//#define BUILD_RANGE_TABLE
|
||||
|
||||
struct RANGE_CODER_STRUCT_COMPRESS
|
||||
{
|
||||
unsigned int low; // low end of interval
|
||||
unsigned int range; // length of interval
|
||||
unsigned int help; // bytes_to_follow resp. intermediate value
|
||||
unsigned char buffer; // buffer for input / output
|
||||
};
|
||||
|
||||
struct BIT_ARRAY_STATE
|
||||
{
|
||||
uint32 k;
|
||||
uint32 nKSum;
|
||||
};
|
||||
|
||||
class CBitArray
|
||||
{
|
||||
public:
|
||||
|
||||
// construction / destruction
|
||||
CBitArray(CIO *pIO);
|
||||
~CBitArray();
|
||||
|
||||
// encoding
|
||||
int EncodeUnsignedLong(unsigned int n);
|
||||
int EncodeValue(int nEncode, BIT_ARRAY_STATE & BitArrayState);
|
||||
int EncodeBits(unsigned int nValue, int nBits);
|
||||
|
||||
// output (saving)
|
||||
int OutputBitArray(BOOL bFinalize = FALSE);
|
||||
|
||||
// other functions
|
||||
void Finalize();
|
||||
void AdvanceToByteBoundary();
|
||||
inline uint32 GetCurrentBitIndex() { return m_nCurrentBitIndex; }
|
||||
void FlushState(BIT_ARRAY_STATE & BitArrayState);
|
||||
void FlushBitArray();
|
||||
inline CMD5Helper & GetMD5Helper() { return m_MD5; }
|
||||
|
||||
private:
|
||||
|
||||
// data members
|
||||
uint32 * m_pBitArray;
|
||||
CIO * m_pIO;
|
||||
uint32 m_nCurrentBitIndex;
|
||||
RANGE_CODER_STRUCT_COMPRESS m_RangeCoderInfo;
|
||||
CMD5Helper m_MD5;
|
||||
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
void OutputRangeTable();
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_BITARRAY_H
|
||||
157
MAC_SDK/Source/MACLib/MACLib.cpp
Normal file
157
MAC_SDK/Source/MACLib/MACLib.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
#include "All.h"
|
||||
#include "MACLib.h"
|
||||
|
||||
#include "APECompress.h"
|
||||
#include "APECompressCreate.h"
|
||||
#include "APECompressCore.h"
|
||||
#include "APECompress.h"
|
||||
#include "APEDecompress.h"
|
||||
#include "APEInfo.h"
|
||||
#include "APELink.h"
|
||||
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
#include "Old/APEDecompressOld.h"
|
||||
#endif
|
||||
|
||||
IAPEDecompress * CreateIAPEDecompressCore(CAPEInfo * pAPEInfo, int nStartBlock, int nFinishBlock, int * pErrorCode)
|
||||
{
|
||||
IAPEDecompress * pAPEDecompress = NULL;
|
||||
if (pAPEInfo != NULL && *pErrorCode == ERROR_SUCCESS)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pAPEInfo->GetInfo(APE_INFO_FILE_VERSION) >= 3930)
|
||||
pAPEDecompress = new CAPEDecompress(pErrorCode, pAPEInfo, nStartBlock, nFinishBlock);
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
else
|
||||
pAPEDecompress = new CAPEDecompressOld(pErrorCode, pAPEInfo, nStartBlock, nFinishBlock);
|
||||
#endif
|
||||
|
||||
if (pAPEDecompress == NULL || *pErrorCode != ERROR_SUCCESS)
|
||||
{
|
||||
SAFE_DELETE(pAPEDecompress)
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
SAFE_DELETE(pAPEDecompress)
|
||||
*pErrorCode = ERROR_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
return pAPEDecompress;
|
||||
}
|
||||
|
||||
IAPEDecompress * __stdcall CreateIAPEDecompress(const str_utf16 * pFilename, int * pErrorCode)
|
||||
{
|
||||
// error check the parameters
|
||||
if ((pFilename == NULL) || (wcslen(pFilename) == 0))
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// variables
|
||||
int nErrorCode = ERROR_UNDEFINED;
|
||||
CAPEInfo * pAPEInfo = NULL;
|
||||
int nStartBlock = -1; int nFinishBlock = -1;
|
||||
|
||||
// get the extension
|
||||
const str_utf16 * pExtension = &pFilename[wcslen(pFilename)];
|
||||
while ((pExtension > pFilename) && (*pExtension != '.'))
|
||||
pExtension--;
|
||||
|
||||
// take the appropriate action (based on the extension)
|
||||
if (wcsicmp(pExtension, L".apl") == 0)
|
||||
{
|
||||
// "link" file (.apl linked large APE file)
|
||||
CAPELink APELink(pFilename);
|
||||
if (APELink.GetIsLinkFile())
|
||||
{
|
||||
pAPEInfo = new CAPEInfo(&nErrorCode, APELink.GetImageFilename(), new CAPETag(pFilename, TRUE));
|
||||
nStartBlock = APELink.GetStartBlock(); nFinishBlock = APELink.GetFinishBlock();
|
||||
}
|
||||
}
|
||||
else if ((wcsicmp(pExtension, L".mac") == 0) || (wcsicmp(pExtension, L".ape") == 0))
|
||||
{
|
||||
// plain .ape file
|
||||
pAPEInfo = new CAPEInfo(&nErrorCode, pFilename);
|
||||
}
|
||||
|
||||
// fail if we couldn't get the file information
|
||||
if (pAPEInfo == NULL)
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// create and return
|
||||
IAPEDecompress * pAPEDecompress = CreateIAPEDecompressCore(pAPEInfo, nStartBlock, nFinishBlock, &nErrorCode);
|
||||
if (pErrorCode) *pErrorCode = nErrorCode;
|
||||
return pAPEDecompress;
|
||||
}
|
||||
|
||||
IAPEDecompress * __stdcall CreateIAPEDecompressEx(CIO * pIO, int * pErrorCode)
|
||||
{
|
||||
int nErrorCode = ERROR_UNDEFINED;
|
||||
CAPEInfo * pAPEInfo = new CAPEInfo(&nErrorCode, pIO);
|
||||
IAPEDecompress * pAPEDecompress = CreateIAPEDecompressCore(pAPEInfo, -1, -1, &nErrorCode);
|
||||
if (pErrorCode) *pErrorCode = nErrorCode;
|
||||
return pAPEDecompress;
|
||||
}
|
||||
|
||||
|
||||
IAPEDecompress * __stdcall CreateIAPEDecompressEx2(CAPEInfo * pAPEInfo, int nStartBlock, int nFinishBlock, int * pErrorCode)
|
||||
{
|
||||
int nErrorCode = ERROR_SUCCESS;
|
||||
IAPEDecompress * pAPEDecompress = CreateIAPEDecompressCore(pAPEInfo, nStartBlock, nFinishBlock, &nErrorCode);
|
||||
if (pErrorCode) *pErrorCode = nErrorCode;
|
||||
return pAPEDecompress;
|
||||
}
|
||||
|
||||
IAPECompress * __stdcall CreateIAPECompress(int * pErrorCode)
|
||||
{
|
||||
if (pErrorCode)
|
||||
*pErrorCode = ERROR_SUCCESS;
|
||||
|
||||
return new CAPECompress();
|
||||
}
|
||||
|
||||
int __stdcall FillWaveFormatEx(WAVEFORMATEX * pWaveFormatEx, int nSampleRate, int nBitsPerSample, int nChannels)
|
||||
{
|
||||
pWaveFormatEx->cbSize = 0;
|
||||
pWaveFormatEx->nSamplesPerSec = nSampleRate;
|
||||
pWaveFormatEx->wBitsPerSample = nBitsPerSample;
|
||||
pWaveFormatEx->nChannels = nChannels;
|
||||
pWaveFormatEx->wFormatTag = 1;
|
||||
|
||||
pWaveFormatEx->nBlockAlign = (pWaveFormatEx->wBitsPerSample / 8) * pWaveFormatEx->nChannels;
|
||||
pWaveFormatEx->nAvgBytesPerSec = pWaveFormatEx->nBlockAlign * pWaveFormatEx->nSamplesPerSec;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int __stdcall FillWaveHeader(WAVE_HEADER * pWAVHeader, int nAudioBytes, WAVEFORMATEX * pWaveFormatEx, int nTerminatingBytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
// RIFF header
|
||||
memcpy(pWAVHeader->cRIFFHeader, "RIFF", 4);
|
||||
pWAVHeader->nRIFFBytes = (nAudioBytes + 44) - 8 + nTerminatingBytes;
|
||||
|
||||
// format header
|
||||
memcpy(pWAVHeader->cDataTypeID, "WAVE", 4);
|
||||
memcpy(pWAVHeader->cFormatHeader, "fmt ", 4);
|
||||
|
||||
// the format chunk is the first 16 bytes of a waveformatex
|
||||
pWAVHeader->nFormatBytes = 16;
|
||||
memcpy(&pWAVHeader->nFormatTag, pWaveFormatEx, 16);
|
||||
|
||||
// the data header
|
||||
memcpy(pWAVHeader->cDataHeader, "data", 4);
|
||||
pWAVHeader->nDataBytes = nAudioBytes;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
catch(...) { return ERROR_UNDEFINED; }
|
||||
}
|
||||
462
MAC_SDK/Source/MACLib/MACLib.dsp
Normal file
462
MAC_SDK/Source/MACLib/MACLib.dsp
Normal file
@@ -0,0 +1,462 @@
|
||||
# Microsoft Developer Studio Project File - Name="MACLib" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Static Library" 0x0104
|
||||
|
||||
CFG=MACLib - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "MACLib.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "MACLib.mak" CFG="MACLib - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "MACLib - Win32 Release" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE "MACLib - Win32 Debug" (based on "Win32 (x86) Static Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""$/Monkey's Audio/MACLib", SCAAAAAA"
|
||||
# PROP Scc_LocalPath "."
|
||||
CPP=cl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "MACLib - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
|
||||
# ADD CPP /nologo /G6 /MT /W3 /GX /Ox /Ot /Og /Oi /Ob2 /I "..\Shared" /D "WIN32" /D "NDEBUG" /D "_LIB" /D "_UNICODE" /D "UNICODE" /FR /YX"all.h" /FD /c
|
||||
# SUBTRACT CPP /Oa
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
# Begin Special Build Tool
|
||||
ProjDir=.
|
||||
SOURCE="$(InputPath)"
|
||||
PreLink_Desc=Building assembly...
|
||||
PreLink_Cmds=cd $(ProjDir)\Assembly nasmw -d WIN32 -f win32 -o Assembly.obj Assembly.nas
|
||||
# End Special Build Tool
|
||||
|
||||
!ELSEIF "$(CFG)" == "MACLib - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\Shared" /D "WIN32" /D "_DEBUG" /D "_LIB" /D "_UNICODE" /D "UNICODE" /FD /GZ /c
|
||||
# SUBTRACT CPP /YX
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LIB32=link.exe -lib
|
||||
# ADD BASE LIB32 /nologo
|
||||
# ADD LIB32 /nologo
|
||||
# Begin Special Build Tool
|
||||
ProjDir=.
|
||||
SOURCE="$(InputPath)"
|
||||
PreLink_Desc=Building assembly...
|
||||
PreLink_Cmds=cd $(ProjDir)\Assembly nasmw -d WIN32 -f win32 -o Assembly.obj Assembly.nas
|
||||
# End Special Build Tool
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "MACLib - Win32 Release"
|
||||
# Name "MACLib - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Group "Compress"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APECompress.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APECompressCore.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APECompressCreate.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\BitArray.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Decompress"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Group "Old"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\Old\Anti-Predictor.cpp"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\AntiPredictorExtraHigh.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\AntiPredictorFast.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\AntiPredictorHigh.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\AntiPredictorNormal.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\APEDecompressCore.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\APEDecompressOld.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\UnBitArrayOld.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\UnMAC.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APEDecompress.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\UnBitArray.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\UnBitArrayBase.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Info"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APEHeader.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APEInfo.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APELink.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APETag.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\WAVInputSource.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Tools"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Group "IO"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\StdLibFileIO.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\WinFileIO.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\CharacterHelper.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\CircleBuffer.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\GlobalFunctions.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\MACProgressHelper.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\MD5.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Prepare.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Prediction"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Group "Filters"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\NNFilter.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\NewPredictor.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APESimple.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\MACLib.cpp
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Group "Compress (h)"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APECompress.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APECompressCore.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APECompressCreate.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\BitArray.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Decompress (h)"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Group "Old (h)"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=".\Old\Anti-Predictor.h"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\APEDecompressCore.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\APEDecompressOld.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\UnBitArrayOld.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Old\UnMAC.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APEDecompress.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\UnBitArray.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\UnBitArrayBase.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Info (h)"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APEHeader.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APEInfo.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APELink.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\APETag.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\WAVInputSource.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Tools (h)"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Group "IO (h)"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\IO.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\StdLibFileIO.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\WinFileIO.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\CharacterHelper.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\CircleBuffer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\GlobalFunctions.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\MACProgressHelper.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\md5.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\NoWindows.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Prepare.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\SmartPtr.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Prediction (h)"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Group "Filters (h)"
|
||||
|
||||
# PROP Default_Filter ""
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\NNFilter.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\RollBuffer.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\ScaledFirstOrderFilter.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\NewPredictor.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Predictor.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Shared\All.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Assembly\Assembly.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\MACLib.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\Credits.txt
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\History.txt
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE="..\To Do.txt"
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\Assembly\Assembly.obj
|
||||
# End Source File
|
||||
# End Target
|
||||
# End Project
|
||||
450
MAC_SDK/Source/MACLib/MACLib.h
Normal file
450
MAC_SDK/Source/MACLib/MACLib.h
Normal file
@@ -0,0 +1,450 @@
|
||||
/*****************************************************************************************
|
||||
Monkey's Audio MACLib.h (include for using MACLib.lib in your projects)
|
||||
Copyright (C) 2000-2003 by Matthew T. Ashland All Rights Reserved.
|
||||
|
||||
Overview:
|
||||
|
||||
There are two main interfaces... create one (using CreateIAPExxx) and go to town:
|
||||
|
||||
IAPECompress - for creating APE files
|
||||
IAPEDecompress - for decompressing and analyzing APE files
|
||||
|
||||
Note(s):
|
||||
|
||||
Unless otherwise specified, functions return ERROR_SUCCESS (0) on success and an
|
||||
error code on failure.
|
||||
|
||||
The terminology "Sample" refers to a single sample value, and "Block" refers
|
||||
to a collection of "Channel" samples. For simplicity, MAC typically uses blocks
|
||||
everywhere so that channel mis-alignment cannot happen. (i.e. on a CD, a sample is
|
||||
2 bytes and a block is 4 bytes ([2 bytes per sample] * [2 channels] = 4 bytes))
|
||||
|
||||
Questions / Suggestions:
|
||||
|
||||
Please direct questions or comments to the Monkey's Audio developers board:
|
||||
http://www.monkeysaudio.com/cgi-bin/YaBB/YaBB.cgi -> Developers
|
||||
or, if necessary, matt @ monkeysaudio.com
|
||||
*****************************************************************************************/
|
||||
|
||||
#ifndef APE_MACLIB_H
|
||||
#define APE_MACLIB_H
|
||||
|
||||
/*************************************************************************************************
|
||||
APE File Format Overview: (pieces in order -- only valid for the latest version APE files)
|
||||
|
||||
JUNK - any amount of "junk" before the APE_DESCRIPTOR (so people that put ID3v2 tags on the files aren't hosed)
|
||||
APE_DESCRIPTOR - defines the sizes (and offsets) of all the pieces, as well as the MD5 checksum
|
||||
APE_HEADER - describes all of the necessary information about the APE file
|
||||
SEEK TABLE - the table that represents seek offsets [optional]
|
||||
HEADER DATA - the pre-audio data from the original file [optional]
|
||||
APE FRAMES - the actual compressed audio (broken into frames for seekability)
|
||||
TERMINATING DATA - the post-audio data from the original file [optional]
|
||||
TAG - describes all the properties of the file [optional]
|
||||
|
||||
Notes:
|
||||
|
||||
Junk:
|
||||
|
||||
This block may not be supported in the future, so don't write any software that adds meta data
|
||||
before the APE_DESCRIPTOR. Please use the APE Tag for any meta data.
|
||||
|
||||
Seek Table:
|
||||
|
||||
A 32-bit unsigned integer array of offsets from the header to the frame data. May become "delta"
|
||||
values someday to better suit huge files.
|
||||
|
||||
MD5 Hash:
|
||||
|
||||
Since the header is the last part written to an APE file, you must calculate the MD5 checksum out of order.
|
||||
So, you first calculate from the tail of the seek table to the end of the terminating data.
|
||||
Then, go back and do from the end of the descriptor to the tail of the seek table.
|
||||
You may wish to just cache the header data when starting and run it last, so you don't
|
||||
need to seek back in the I/O.
|
||||
*************************************************************************************************/
|
||||
|
||||
/*****************************************************************************************
|
||||
Defines
|
||||
*****************************************************************************************/
|
||||
#define COMPRESSION_LEVEL_FAST 1000
|
||||
#define COMPRESSION_LEVEL_NORMAL 2000
|
||||
#define COMPRESSION_LEVEL_HIGH 3000
|
||||
#define COMPRESSION_LEVEL_EXTRA_HIGH 4000
|
||||
#define COMPRESSION_LEVEL_INSANE 5000
|
||||
|
||||
#define MAC_FORMAT_FLAG_8_BIT 1 // is 8-bit [OBSOLETE]
|
||||
#define MAC_FORMAT_FLAG_CRC 2 // uses the new CRC32 error detection [OBSOLETE]
|
||||
#define MAC_FORMAT_FLAG_HAS_PEAK_LEVEL 4 // uint32 nPeakLevel after the header [OBSOLETE]
|
||||
#define MAC_FORMAT_FLAG_24_BIT 8 // is 24-bit [OBSOLETE]
|
||||
#define MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS 16 // has the number of seek elements after the peak level
|
||||
#define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // create the wave header on decompression (not stored)
|
||||
|
||||
#define CREATE_WAV_HEADER_ON_DECOMPRESSION -1
|
||||
#define MAX_AUDIO_BYTES_UNKNOWN -1
|
||||
|
||||
typedef void (__stdcall * APE_PROGRESS_CALLBACK) (int);
|
||||
|
||||
/*****************************************************************************************
|
||||
WAV header structure
|
||||
*****************************************************************************************/
|
||||
struct WAVE_HEADER
|
||||
{
|
||||
// RIFF header
|
||||
char cRIFFHeader[4];
|
||||
unsigned int nRIFFBytes;
|
||||
|
||||
// data type
|
||||
char cDataTypeID[4];
|
||||
|
||||
// wave format
|
||||
char cFormatHeader[4];
|
||||
unsigned int nFormatBytes;
|
||||
|
||||
unsigned short nFormatTag;
|
||||
unsigned short nChannels;
|
||||
unsigned int nSamplesPerSec;
|
||||
unsigned int nAvgBytesPerSec;
|
||||
unsigned short nBlockAlign;
|
||||
unsigned short nBitsPerSample;
|
||||
|
||||
// data chunk header
|
||||
char cDataHeader[4];
|
||||
unsigned int nDataBytes;
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
APE_DESCRIPTOR structure (file header that describes lengths, offsets, etc.)
|
||||
*****************************************************************************************/
|
||||
struct APE_DESCRIPTOR
|
||||
{
|
||||
char cID[4]; // should equal 'MAC '
|
||||
uint16 nVersion; // version number * 1000 (3.81 = 3810)
|
||||
|
||||
uint32 nDescriptorBytes; // the number of descriptor bytes (allows later expansion of this header)
|
||||
uint32 nHeaderBytes; // the number of header APE_HEADER bytes
|
||||
uint32 nSeekTableBytes; // the number of bytes of the seek table
|
||||
uint32 nHeaderDataBytes; // the number of header data bytes (from original file)
|
||||
uint32 nAPEFrameDataBytes; // the number of bytes of APE frame data
|
||||
uint32 nAPEFrameDataBytesHigh; // the high order number of APE frame data bytes
|
||||
uint32 nTerminatingDataBytes; // the terminating data of the file (not including tag data)
|
||||
|
||||
uint8 cFileMD5[16]; // the MD5 hash of the file (see notes for usage... it's a littly tricky)
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
APE_HEADER structure (describes the format, duration, etc. of the APE file)
|
||||
*****************************************************************************************/
|
||||
struct APE_HEADER
|
||||
{
|
||||
uint16 nCompressionLevel; // the compression level (see defines I.E. COMPRESSION_LEVEL_FAST)
|
||||
uint16 nFormatFlags; // any format flags (for future use)
|
||||
|
||||
uint32 nBlocksPerFrame; // the number of audio blocks in one frame
|
||||
uint32 nFinalFrameBlocks; // the number of audio blocks in the final frame
|
||||
uint32 nTotalFrames; // the total number of frames
|
||||
|
||||
uint16 nBitsPerSample; // the bits per sample (typically 16)
|
||||
uint16 nChannels; // the number of channels (1 or 2)
|
||||
uint32 nSampleRate; // the sample rate (typically 44100)
|
||||
};
|
||||
|
||||
/*************************************************************************************************
|
||||
Classes (fully defined elsewhere)
|
||||
*************************************************************************************************/
|
||||
class CIO;
|
||||
class CInputSource;
|
||||
class CAPEInfo;
|
||||
|
||||
/*************************************************************************************************
|
||||
IAPEDecompress fields - used when querying for information
|
||||
|
||||
Note(s):
|
||||
-the distinction between APE_INFO_XXXX and APE_DECOMPRESS_XXXX is that the first is querying the APE
|
||||
information engine, and the other is querying the decompressor, and since the decompressor can be
|
||||
a range of an APE file (for APL), differences will arise. Typically, use the APE_DECOMPRESS_XXXX
|
||||
fields when querying for info about the length, etc. so APL will work properly.
|
||||
(i.e. (APE_INFO_TOTAL_BLOCKS != APE_DECOMPRESS_TOTAL_BLOCKS) for APL files)
|
||||
*************************************************************************************************/
|
||||
enum APE_DECOMPRESS_FIELDS
|
||||
{
|
||||
APE_INFO_FILE_VERSION = 1000, // version of the APE file * 1000 (3.93 = 3930) [ignored, ignored]
|
||||
APE_INFO_COMPRESSION_LEVEL = 1001, // compression level of the APE file [ignored, ignored]
|
||||
APE_INFO_FORMAT_FLAGS = 1002, // format flags of the APE file [ignored, ignored]
|
||||
APE_INFO_SAMPLE_RATE = 1003, // sample rate (Hz) [ignored, ignored]
|
||||
APE_INFO_BITS_PER_SAMPLE = 1004, // bits per sample [ignored, ignored]
|
||||
APE_INFO_BYTES_PER_SAMPLE = 1005, // number of bytes per sample [ignored, ignored]
|
||||
APE_INFO_CHANNELS = 1006, // channels [ignored, ignored]
|
||||
APE_INFO_BLOCK_ALIGN = 1007, // block alignment [ignored, ignored]
|
||||
APE_INFO_BLOCKS_PER_FRAME = 1008, // number of blocks in a frame (frames are used internally) [ignored, ignored]
|
||||
APE_INFO_FINAL_FRAME_BLOCKS = 1009, // blocks in the final frame (frames are used internally) [ignored, ignored]
|
||||
APE_INFO_TOTAL_FRAMES = 1010, // total number frames (frames are used internally) [ignored, ignored]
|
||||
APE_INFO_WAV_HEADER_BYTES = 1011, // header bytes of the decompressed WAV [ignored, ignored]
|
||||
APE_INFO_WAV_TERMINATING_BYTES = 1012, // terminating bytes of the decompressed WAV [ignored, ignored]
|
||||
APE_INFO_WAV_DATA_BYTES = 1013, // data bytes of the decompressed WAV [ignored, ignored]
|
||||
APE_INFO_WAV_TOTAL_BYTES = 1014, // total bytes of the decompressed WAV [ignored, ignored]
|
||||
APE_INFO_APE_TOTAL_BYTES = 1015, // total bytes of the APE file [ignored, ignored]
|
||||
APE_INFO_TOTAL_BLOCKS = 1016, // total blocks of audio data [ignored, ignored]
|
||||
APE_INFO_LENGTH_MS = 1017, // length in ms (1 sec = 1000 ms) [ignored, ignored]
|
||||
APE_INFO_AVERAGE_BITRATE = 1018, // average bitrate of the APE [ignored, ignored]
|
||||
APE_INFO_FRAME_BITRATE = 1019, // bitrate of specified APE frame [frame index, ignored]
|
||||
APE_INFO_DECOMPRESSED_BITRATE = 1020, // bitrate of the decompressed WAV [ignored, ignored]
|
||||
APE_INFO_PEAK_LEVEL = 1021, // peak audio level (obsolete) (-1 is unknown) [ignored, ignored]
|
||||
APE_INFO_SEEK_BIT = 1022, // bit offset [frame index, ignored]
|
||||
APE_INFO_SEEK_BYTE = 1023, // byte offset [frame index, ignored]
|
||||
APE_INFO_WAV_HEADER_DATA = 1024, // error code [buffer *, max bytes]
|
||||
APE_INFO_WAV_TERMINATING_DATA = 1025, // error code [buffer *, max bytes]
|
||||
APE_INFO_WAVEFORMATEX = 1026, // error code [waveformatex *, ignored]
|
||||
APE_INFO_IO_SOURCE = 1027, // I/O source (CIO *) [ignored, ignored]
|
||||
APE_INFO_FRAME_BYTES = 1028, // bytes (compressed) of the frame [frame index, ignored]
|
||||
APE_INFO_FRAME_BLOCKS = 1029, // blocks in a given frame [frame index, ignored]
|
||||
APE_INFO_TAG = 1030, // point to tag (CAPETag *) [ignored, ignored]
|
||||
|
||||
APE_DECOMPRESS_CURRENT_BLOCK = 2000, // current block location [ignored, ignored]
|
||||
APE_DECOMPRESS_CURRENT_MS = 2001, // current millisecond location [ignored, ignored]
|
||||
APE_DECOMPRESS_TOTAL_BLOCKS = 2002, // total blocks in the decompressors range [ignored, ignored]
|
||||
APE_DECOMPRESS_LENGTH_MS = 2003, // total blocks in the decompressors range [ignored, ignored]
|
||||
APE_DECOMPRESS_CURRENT_BITRATE = 2004, // current bitrate [ignored, ignored]
|
||||
APE_DECOMPRESS_AVERAGE_BITRATE = 2005, // average bitrate (works with ranges) [ignored, ignored]
|
||||
|
||||
APE_INTERNAL_INFO = 3000, // for internal use -- don't use (returns APE_FILE_INFO *) [ignored, ignored]
|
||||
};
|
||||
|
||||
/*************************************************************************************************
|
||||
IAPEDecompress - interface for working with existing APE files (decoding, seeking, analyzing, etc.)
|
||||
*************************************************************************************************/
|
||||
class IAPEDecompress
|
||||
{
|
||||
public:
|
||||
|
||||
// destructor (needed so implementation's destructor will be called)
|
||||
virtual ~IAPEDecompress() {}
|
||||
|
||||
/*********************************************************************************************
|
||||
* Decompress / Seek
|
||||
*********************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GetData(...) - gets raw decompressed audio
|
||||
//
|
||||
// Parameters:
|
||||
// char * pBuffer
|
||||
// a pointer to a buffer to put the data into
|
||||
// int nBlocks
|
||||
// the number of audio blocks desired (see note at intro about blocks vs. samples)
|
||||
// int * pBlocksRetrieved
|
||||
// the number of blocks actually retrieved (could be less at end of file or on critical failure)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved) = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Seek(...) - seeks
|
||||
//
|
||||
// Parameters:
|
||||
// int nBlockOffset
|
||||
// the block to seek to (see note at intro about blocks vs. samples)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int Seek(int nBlockOffset) = 0;
|
||||
|
||||
/*********************************************************************************************
|
||||
* Get Information
|
||||
*********************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GetInfo(...) - get information about the APE file or the state of the decompressor
|
||||
//
|
||||
// Parameters:
|
||||
// APE_DECOMPRESS_FIELDS Field
|
||||
// the field we're querying (see APE_DECOMPRESS_FIELDS above for more info)
|
||||
// int nParam1
|
||||
// generic parameter... usage is listed in APE_DECOMPRESS_FIELDS
|
||||
// int nParam2
|
||||
// generic parameter... usage is listed in APE_DECOMPRESS_FIELDS
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1 = 0, int nParam2 = 0) = 0;
|
||||
};
|
||||
|
||||
/*************************************************************************************************
|
||||
IAPECompress - interface for creating APE files
|
||||
|
||||
Usage:
|
||||
|
||||
To create an APE file, you Start(...), then add data (in a variety of ways), then Finish(...)
|
||||
*************************************************************************************************/
|
||||
class IAPECompress
|
||||
{
|
||||
public:
|
||||
|
||||
// destructor (needed so implementation's destructor will be called)
|
||||
virtual ~IAPECompress() {}
|
||||
|
||||
/*********************************************************************************************
|
||||
* Start
|
||||
*********************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Start(...) / StartEx(...) - starts encoding
|
||||
//
|
||||
// Parameters:
|
||||
// CIO * pioOutput / const str_utf16 * pFilename
|
||||
// the output... either a filename or an I/O source
|
||||
// WAVEFORMATEX * pwfeInput
|
||||
// format of the audio to encode (use FillWaveFormatEx() if necessary)
|
||||
// int nMaxAudioBytes
|
||||
// the absolute maximum audio bytes that will be encoded... encoding fails with a
|
||||
// ERROR_APE_COMPRESS_TOO_MUCH_DATA if you attempt to encode more than specified here
|
||||
// (if unknown, use MAX_AUDIO_BYTES_UNKNOWN to allocate as much storage in the seek table as
|
||||
// possible... limit is then 2 GB of data (~4 hours of CD music)... this wastes around
|
||||
// 30kb, so only do it if completely necessary)
|
||||
// int nCompressionLevel
|
||||
// the compression level for the APE file (fast - extra high)
|
||||
// (note: extra-high is much slower for little gain)
|
||||
// const void * pHeaderData
|
||||
// a pointer to a buffer containing the WAV header (data before the data block in the WAV)
|
||||
// (note: use NULL for on-the-fly encoding... see next parameter)
|
||||
// int nHeaderBytes
|
||||
// number of bytes in the header data buffer (use CREATE_WAV_HEADER_ON_DECOMPRESSION and
|
||||
// NULL for the pHeaderData and MAC will automatically create the appropriate WAV header
|
||||
// on decompression)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual int Start(const str_utf16 * pOutputFilename, const WAVEFORMATEX * pwfeInput,
|
||||
int nMaxAudioBytes = MAX_AUDIO_BYTES_UNKNOWN, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL,
|
||||
const void * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION) = 0;
|
||||
|
||||
virtual int StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput,
|
||||
int nMaxAudioBytes = MAX_AUDIO_BYTES_UNKNOWN, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL,
|
||||
const void * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION) = 0;
|
||||
|
||||
/*********************************************************************************************
|
||||
* Add / Compress Data
|
||||
* - there are 3 ways to add data:
|
||||
* 1) simple call AddData(...)
|
||||
* 2) lock MAC's buffer, copy into it, and unlock (LockBuffer(...) / UnlockBuffer(...))
|
||||
* 3) from an I/O source (AddDataFromInputSource(...))
|
||||
*********************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AddData(...) - adds data to the encoder
|
||||
//
|
||||
// Parameters:
|
||||
// unsigned char * pData
|
||||
// a pointer to a buffer containing the raw audio data
|
||||
// int nBytes
|
||||
// the number of bytes in the buffer
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int AddData(unsigned char * pData, int nBytes) = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GetBufferBytesAvailable(...) - returns the number of bytes available in the buffer
|
||||
// (helpful when locking)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int GetBufferBytesAvailable() = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// LockBuffer(...) - locks MAC's buffer so we can copy into it
|
||||
//
|
||||
// Parameters:
|
||||
// int * pBytesAvailable
|
||||
// returns the number of bytes available in the buffer (DO NOT COPY MORE THAN THIS IN)
|
||||
//
|
||||
// Return:
|
||||
// pointer to the buffer (add at that location)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual unsigned char * LockBuffer(int * pBytesAvailable) = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// UnlockBuffer(...) - releases the buffer
|
||||
//
|
||||
// Parameters:
|
||||
// int nBytesAdded
|
||||
// the number of bytes copied into the buffer
|
||||
// BOOL bProcess
|
||||
// whether MAC should process as much as possible of the buffer
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int UnlockBuffer(int nBytesAdded, BOOL bProcess = TRUE) = 0;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AddDataFromInputSource(...) - use a CInputSource (input source) to add data
|
||||
//
|
||||
// Parameters:
|
||||
// CInputSource * pInputSource
|
||||
// a pointer to the input source
|
||||
// int nMaxBytes
|
||||
// the maximum number of bytes to let MAC add (-1 if MAC can add any amount)
|
||||
// int * pBytesAdded
|
||||
// returns the number of bytes added from the I/O source
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes = -1, int * pBytesAdded = NULL) = 0;
|
||||
|
||||
/*********************************************************************************************
|
||||
* Finish / Kill
|
||||
*********************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Finish(...) - ends encoding and finalizes the file
|
||||
//
|
||||
// Parameters:
|
||||
// unsigned char * pTerminatingData
|
||||
// a pointer to a buffer containing the information to place at the end of the APE file
|
||||
// (comprised of the WAV terminating data (data after the data block in the WAV) followed
|
||||
// by any tag information)
|
||||
// int nTerminatingBytes
|
||||
// number of bytes in the terminating data buffer
|
||||
// int nWAVTerminatingBytes
|
||||
// the number of bytes of the terminating data buffer that should be appended to a decoded
|
||||
// WAV file (it's basically nTerminatingBytes - the bytes that make up the tag)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes) = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Kill(...) - stops encoding and deletes the output file
|
||||
// --- NOT CURRENTLY IMPLEMENTED ---
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int Kill() = 0;
|
||||
};
|
||||
|
||||
/*************************************************************************************************
|
||||
Functions to create the interfaces
|
||||
|
||||
Usage:
|
||||
Interface creation returns a NULL pointer on failure (and fills error code if it was passed in)
|
||||
|
||||
Usage example:
|
||||
int nErrorCode;
|
||||
IAPEDecompress * pAPEDecompress = CreateIAPEDecompress("c:\\1.ape", &nErrorCode);
|
||||
if (pAPEDecompress == NULL)
|
||||
{
|
||||
// failure... nErrorCode will have specific code
|
||||
}
|
||||
|
||||
*************************************************************************************************/
|
||||
extern "C"
|
||||
{
|
||||
IAPEDecompress * __stdcall CreateIAPEDecompress(const str_utf16 * pFilename, int * pErrorCode = NULL);
|
||||
IAPEDecompress * __stdcall CreateIAPEDecompressEx(CIO * pIO, int * pErrorCode = NULL);
|
||||
IAPEDecompress * __stdcall CreateIAPEDecompressEx2(CAPEInfo * pAPEInfo, int nStartBlock = -1, int nFinishBlock = -1, int * pErrorCode = NULL);
|
||||
IAPECompress * __stdcall CreateIAPECompress(int * pErrorCode = NULL);
|
||||
}
|
||||
|
||||
/*************************************************************************************************
|
||||
Simple functions - see the SDK sample projects for usage examples
|
||||
*************************************************************************************************/
|
||||
extern "C"
|
||||
{
|
||||
// process whole files
|
||||
DLLEXPORT int __stdcall CompressFile(const str_ansi * pInputFilename, const str_ansi * pOutputFilename, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL, int * pPercentageDone = NULL, APE_PROGRESS_CALLBACK ProgressCallback = 0, int * pKillFlag = NULL);
|
||||
DLLEXPORT int __stdcall DecompressFile(const str_ansi * pInputFilename, const str_ansi * pOutputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
||||
DLLEXPORT int __stdcall ConvertFile(const str_ansi * pInputFilename, const str_ansi * pOutputFilename, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
||||
DLLEXPORT int __stdcall VerifyFile(const str_ansi * pInputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
||||
|
||||
DLLEXPORT int __stdcall CompressFileW(const str_utf16 * pInputFilename, const str_utf16 * pOutputFilename, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL, int * pPercentageDone = NULL, APE_PROGRESS_CALLBACK ProgressCallback = 0, int * pKillFlag = NULL);
|
||||
DLLEXPORT int __stdcall DecompressFileW(const str_utf16 * pInputFilename, const str_utf16 * pOutputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
||||
DLLEXPORT int __stdcall ConvertFileW(const str_utf16 * pInputFilename, const str_utf16 * pOutputFilename, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
||||
DLLEXPORT int __stdcall VerifyFileW(const str_utf16 * pInputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag, BOOL bQuickVerifyIfPossible = FALSE);
|
||||
|
||||
// helper functions
|
||||
DLLEXPORT int __stdcall FillWaveFormatEx(WAVEFORMATEX * pWaveFormatEx, int nSampleRate = 44100, int nBitsPerSample = 16, int nChannels = 2);
|
||||
DLLEXPORT int __stdcall FillWaveHeader(WAVE_HEADER * pWAVHeader, int nAudioBytes, WAVEFORMATEX * pWaveFormatEx, int nTerminatingBytes = 0);
|
||||
}
|
||||
|
||||
#endif // #ifndef APE_MACLIB_H
|
||||
34
MAC_SDK/Source/MACLib/MACLib.sln
Normal file
34
MAC_SDK/Source/MACLib/MACLib.sln
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MACLib", "MACLib.vcproj", "{0B9C97D4-61B8-4294-A1DF-BA90752A1779}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Sample 2", "..\..\Decompress\Sample 2\Sample 2.vcproj", "{E7B72EF2-1C5A-45EF-BA35-6094BCF560B1}"
|
||||
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
|
||||
{0B9C97D4-61B8-4294-A1DF-BA90752A1779}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0B9C97D4-61B8-4294-A1DF-BA90752A1779}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0B9C97D4-61B8-4294-A1DF-BA90752A1779}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0B9C97D4-61B8-4294-A1DF-BA90752A1779}.Debug|x64.Build.0 = Debug|x64
|
||||
{0B9C97D4-61B8-4294-A1DF-BA90752A1779}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0B9C97D4-61B8-4294-A1DF-BA90752A1779}.Release|Win32.Build.0 = Release|Win32
|
||||
{0B9C97D4-61B8-4294-A1DF-BA90752A1779}.Release|x64.ActiveCfg = Release|x64
|
||||
{0B9C97D4-61B8-4294-A1DF-BA90752A1779}.Release|x64.Build.0 = Release|x64
|
||||
{E7B72EF2-1C5A-45EF-BA35-6094BCF560B1}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E7B72EF2-1C5A-45EF-BA35-6094BCF560B1}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E7B72EF2-1C5A-45EF-BA35-6094BCF560B1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E7B72EF2-1C5A-45EF-BA35-6094BCF560B1}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E7B72EF2-1C5A-45EF-BA35-6094BCF560B1}.Release|Win32.Build.0 = Release|Win32
|
||||
{E7B72EF2-1C5A-45EF-BA35-6094BCF560B1}.Release|x64.ActiveCfg = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
2183
MAC_SDK/Source/MACLib/MACLib.vcproj
Normal file
2183
MAC_SDK/Source/MACLib/MACLib.vcproj
Normal file
File diff suppressed because it is too large
Load Diff
1019
MAC_SDK/Source/MACLib/MACLib.vcproj.7.10.old
Normal file
1019
MAC_SDK/Source/MACLib/MACLib.vcproj.7.10.old
Normal file
File diff suppressed because it is too large
Load Diff
82
MAC_SDK/Source/MACLib/MACProgressHelper.cpp
Normal file
82
MAC_SDK/Source/MACLib/MACProgressHelper.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "All.h"
|
||||
#include "MACProgressHelper.h"
|
||||
|
||||
CMACProgressHelper::CMACProgressHelper(int nTotalSteps, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
m_pKillFlag = pKillFlag;
|
||||
|
||||
m_bUseCallback = FALSE;
|
||||
if (ProgressCallback != NULL)
|
||||
{
|
||||
m_bUseCallback = TRUE;
|
||||
m_CallbackFunction = ProgressCallback;
|
||||
}
|
||||
|
||||
m_pPercentageDone = pPercentageDone;
|
||||
|
||||
m_nTotalSteps = nTotalSteps;
|
||||
m_nCurrentStep = 0;
|
||||
m_nLastCallbackFiredPercentageDone = 0;
|
||||
|
||||
UpdateProgress(0);
|
||||
}
|
||||
|
||||
CMACProgressHelper::~CMACProgressHelper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CMACProgressHelper::UpdateProgress(int nCurrentStep, BOOL bForceUpdate)
|
||||
{
|
||||
// update the step
|
||||
if (nCurrentStep == -1)
|
||||
m_nCurrentStep++;
|
||||
else
|
||||
m_nCurrentStep = nCurrentStep;
|
||||
|
||||
// figure the percentage done
|
||||
float fPercentageDone = float(m_nCurrentStep) / float(max(m_nTotalSteps, 1));
|
||||
int nPercentageDone = (int) (fPercentageDone * 1000 * 100);
|
||||
if (nPercentageDone > 100000) nPercentageDone = 100000;
|
||||
|
||||
// update the percent done pointer
|
||||
if (m_pPercentageDone)
|
||||
{
|
||||
*m_pPercentageDone = nPercentageDone;
|
||||
}
|
||||
|
||||
// fire the callback
|
||||
if (m_bUseCallback)
|
||||
{
|
||||
if (bForceUpdate || (nPercentageDone - m_nLastCallbackFiredPercentageDone) >= 1000)
|
||||
{
|
||||
m_CallbackFunction(nPercentageDone);
|
||||
m_nLastCallbackFiredPercentageDone = nPercentageDone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CMACProgressHelper::ProcessKillFlag(BOOL bSleep)
|
||||
{
|
||||
// process any messages (allows repaint, etc.)
|
||||
if (bSleep)
|
||||
{
|
||||
PUMP_MESSAGE_LOOP
|
||||
}
|
||||
|
||||
if (m_pKillFlag)
|
||||
{
|
||||
while (*m_pKillFlag == KILL_FLAG_PAUSE)
|
||||
{
|
||||
SLEEP(50);
|
||||
PUMP_MESSAGE_LOOP
|
||||
}
|
||||
|
||||
if ((*m_pKillFlag != KILL_FLAG_CONTINUE) && (*m_pKillFlag != KILL_FLAG_PAUSE))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
37
MAC_SDK/Source/MACLib/MACProgressHelper.h
Normal file
37
MAC_SDK/Source/MACLib/MACProgressHelper.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef APE_MACPROGRESSHELPER_H
|
||||
#define APE_MACPROGRESSHELPER_H
|
||||
|
||||
#define KILL_FLAG_CONTINUE 0
|
||||
#define KILL_FLAG_PAUSE -1
|
||||
#define KILL_FLAG_STOP 1
|
||||
|
||||
typedef void (__stdcall * APE_PROGRESS_CALLBACK) (int);
|
||||
|
||||
class CMACProgressHelper
|
||||
{
|
||||
public:
|
||||
|
||||
CMACProgressHelper(int nTotalSteps, int *pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int *pKillFlag);
|
||||
virtual ~CMACProgressHelper();
|
||||
|
||||
void UpdateProgress(int nCurrentStep = -1, BOOL bForceUpdate = FALSE);
|
||||
void UpdateProgressComplete() { UpdateProgress(m_nTotalSteps, TRUE); }
|
||||
|
||||
int ProcessKillFlag(BOOL bSleep = TRUE);
|
||||
|
||||
private:
|
||||
|
||||
BOOL m_bUseCallback;
|
||||
APE_PROGRESS_CALLBACK m_CallbackFunction;
|
||||
|
||||
int *m_pPercentageDone;
|
||||
|
||||
int m_nTotalSteps;
|
||||
int m_nCurrentStep;
|
||||
int m_nLastCallbackFiredPercentageDone;
|
||||
|
||||
int *m_pKillFlag;
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_MACPROGRESSHELPER_H
|
||||
|
||||
264
MAC_SDK/Source/MACLib/MD5.cpp
Normal file
264
MAC_SDK/Source/MACLib/MD5.cpp
Normal file
@@ -0,0 +1,264 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm".
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include "All.h"
|
||||
#include <string.h>
|
||||
#include "MD5.h"
|
||||
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
/*
|
||||
* Block copy and convert byte order to little-endian.
|
||||
* dst must be 32bit aligned.
|
||||
* Length is the number of 32bit words
|
||||
*/
|
||||
static void
|
||||
CopyToLittleEndian ( uint32_t* dst,
|
||||
const uint8_t* src,
|
||||
size_t length )
|
||||
{
|
||||
for ( ; length--; src += 4; dst++ ) {
|
||||
*dst = (( (uint32_t) src [3] ) << 24) |
|
||||
(( (uint32_t) src [2] ) << 16) |
|
||||
(( (uint32_t) src [1] ) << 8) |
|
||||
(( (uint32_t) src [0] ) << 0);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Assembler versions of __MD5Transform, MD5Init and MD5Update
|
||||
currently exist for x86 and little-endian ARM.
|
||||
For other targets, we need to use the C versions below.
|
||||
*/
|
||||
|
||||
#if !(defined (__i386__) || ((defined (__arm__) && (__BYTE_ORDER == __LITTLE_ENDIAN))))
|
||||
|
||||
/*
|
||||
Initialise the MD5 context.
|
||||
*/
|
||||
void
|
||||
MD5Init ( MD5_CTX* context )
|
||||
{
|
||||
context -> count [0] = 0;
|
||||
context -> count [1] = 0;
|
||||
|
||||
context -> state [0] = 0x67452301; /* Load magic constants. */
|
||||
context -> state [1] = 0xefcdab89;
|
||||
context -> state [2] = 0x98badcfe;
|
||||
context -> state [3] = 0x10325476;
|
||||
}
|
||||
|
||||
#define ROTATE_LEFT(x, n) ((x << n) | (x >> (32-n)))
|
||||
|
||||
#define F(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define G(x, y, z) (y ^ (z & (x ^ y)))
|
||||
#define H(x, y, z) (x ^ y ^ z)
|
||||
#define I(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
#define FF(a, b, c, d, x, s, ac) { (a) += F (b, c, d) + (x) + (uint32_t)(ac); (a) = ROTATE_LEFT (a, s); (a) += (b); }
|
||||
#define GG(a, b, c, d, x, s, ac) { (a) += G (b, c, d) + (x) + (uint32_t)(ac); (a) = ROTATE_LEFT (a, s); (a) += (b); }
|
||||
#define HH(a, b, c, d, x, s, ac) { (a) += H (b, c, d) + (x) + (uint32_t)(ac); (a) = ROTATE_LEFT (a, s); (a) += (b); }
|
||||
#define II(a, b, c, d, x, s, ac) { (a) += I (b, c, d) + (x) + (uint32_t)(ac); (a) = ROTATE_LEFT (a, s); (a) += (b); }
|
||||
|
||||
static void
|
||||
__MD5Transform ( uint32_t state [4],
|
||||
const uint8_t* in,
|
||||
int repeat )
|
||||
{
|
||||
const uint32_t* x;
|
||||
uint32_t a = state [0];
|
||||
uint32_t b = state [1];
|
||||
uint32_t c = state [2];
|
||||
uint32_t d = state [3];
|
||||
|
||||
for ( ; repeat; repeat-- ) {
|
||||
uint32_t tempBuffer [16];
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
|
||||
CopyToLittleEndian (tempBuffer, in, 16);
|
||||
x = tempBuffer;
|
||||
#else
|
||||
if ( (unsigned int)in & 3 ) {
|
||||
memcpy ( tempBuffer, in, 64 );
|
||||
x = tempBuffer;
|
||||
}
|
||||
else {
|
||||
x = (const uint32_t*) in;
|
||||
}
|
||||
#endif
|
||||
|
||||
FF (a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */ /* Round 1 */
|
||||
FF (d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
|
||||
|
||||
GG (a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */ /* Round 2 */
|
||||
GG (d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], 9, 0x02441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
|
||||
GG (b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
HH (a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */ /* Round 3 */
|
||||
HH (d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], 23, 0x04881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
|
||||
|
||||
II (a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */ /* Round 4 */
|
||||
II (d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
|
||||
|
||||
state [0] = a = a + state [0];
|
||||
state [1] = b = b + state [1];
|
||||
state [2] = c = c + state [2];
|
||||
state [3] = d = d + state [3];
|
||||
|
||||
in += 64;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
MD5 block update operation:
|
||||
Process another sub-string of the message and update the context.
|
||||
*/
|
||||
|
||||
void
|
||||
MD5Update ( MD5_CTX* context,
|
||||
const uint8_t* input,
|
||||
size_t inputBytes )
|
||||
{
|
||||
int byteIndex;
|
||||
unsigned int partLen;
|
||||
int len;
|
||||
int i;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
byteIndex = (context -> count[0] >> 3) & 0x3F;
|
||||
|
||||
/* Update number of bits: count += 8 * inputBytes */
|
||||
if ( (context -> count [0] += inputBytes << 3) < (inputBytes << 3) )
|
||||
context -> count [1]++;
|
||||
context -> count [1] += inputBytes >> (32 - 3);
|
||||
|
||||
partLen = (64 - byteIndex);
|
||||
|
||||
/* Transform as many times as possible. */
|
||||
if ( inputBytes >= partLen ) {
|
||||
memcpy ( context -> buffer + byteIndex, input, partLen );
|
||||
__MD5Transform ( context -> state, (const uint8_t*) context -> buffer, 1 );
|
||||
len = ( inputBytes - partLen ) >> 6;
|
||||
__MD5Transform ( context -> state, input + partLen, len );
|
||||
i = partLen + (len << 6);
|
||||
byteIndex = 0;
|
||||
}
|
||||
else {
|
||||
i = 0;
|
||||
}
|
||||
|
||||
/* Buffer remaining input */
|
||||
memcpy ( (context -> buffer) + byteIndex, input + i, inputBytes - i );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
MD5Final ( uint8_t digest [16],
|
||||
MD5_CTX* context )
|
||||
{
|
||||
static uint8_t finalBlock [64];
|
||||
uint32_t bits [2];
|
||||
int byteIndex;
|
||||
int finalBlockLength;
|
||||
|
||||
byteIndex = (context -> count[0] >> 3) & 0x3F;
|
||||
finalBlockLength = (byteIndex < 56 ? 56 : 120) - byteIndex;
|
||||
finalBlock[0] = 0x80;
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
CopyToLittleEndian ( bits, (const uint8_t*) context -> count, 2 );
|
||||
#else
|
||||
memcpy ( bits, context->count, 8 );
|
||||
#endif
|
||||
|
||||
MD5Update ( context, finalBlock, finalBlockLength );
|
||||
MD5Update ( context, (const uint8_t*) bits, 8 );
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
CopyToLittleEndian ( (uint32_t*) digest, (const uint8_t*) context -> state, 4 );
|
||||
#else
|
||||
memcpy ( digest, context -> state, 16 );
|
||||
#endif
|
||||
|
||||
memset ( context, 0, sizeof (*context) );
|
||||
}
|
||||
|
||||
95
MAC_SDK/Source/MACLib/MultichannelNNFilter.h
Normal file
95
MAC_SDK/Source/MACLib/MultichannelNNFilter.h
Normal file
@@ -0,0 +1,95 @@
|
||||
#ifndef APE_MULTICHANNEL_NNFILTER_H
|
||||
#define APE_MULTICHANNEL_NNFILTER_H
|
||||
|
||||
#include "NNFilter.h"
|
||||
|
||||
class CMultichannelNNFilter
|
||||
{
|
||||
public:
|
||||
|
||||
CMultichannelNNFilter(int nOrder1, int nOrder2, int nShift)
|
||||
{
|
||||
m_pNNFilterA = new CNNFilter(nOrder1 + nOrder2, 11, 3980);
|
||||
m_pNNFilterB = new CNNFilter(nOrder1 + nOrder2, 11, 3980);
|
||||
|
||||
m_rbA.Create(NN_WINDOW_ELEMENTS, nOrder1 + nOrder2 + 1);
|
||||
m_rbB.Create(NN_WINDOW_ELEMENTS, nOrder1 + nOrder2 + 1);
|
||||
|
||||
m_nShift = nShift;
|
||||
|
||||
m_nOrder1 = nOrder1;
|
||||
}
|
||||
|
||||
|
||||
~CMultichannelNNFilter()
|
||||
{
|
||||
SAFE_DELETE(m_pNNFilterA)
|
||||
SAFE_DELETE(m_pNNFilterB)
|
||||
}
|
||||
|
||||
void Flush()
|
||||
{
|
||||
m_pNNFilterA->Flush();
|
||||
m_pNNFilterB->Flush();
|
||||
|
||||
m_rbA.Flush();
|
||||
m_rbB.Flush();
|
||||
|
||||
}
|
||||
|
||||
inline void Compress(int & nA, int & nB)
|
||||
{
|
||||
if (m_nShift <= 0)
|
||||
return;
|
||||
|
||||
m_rbA[0] = GetSaturatedShortFromInt(nA); m_rbB[0] = GetSaturatedShortFromInt(nB);
|
||||
m_rbA[-m_nOrder1 - 1] = m_rbB[-1]; m_rbB[-m_nOrder1 - 1] = m_rbA[0];
|
||||
|
||||
nA -= (m_pNNFilterA->GetPrediction(&m_rbA[-1]) >> m_nShift);
|
||||
nB -= (m_pNNFilterB->GetPrediction(&m_rbB[-1]) >> m_nShift);
|
||||
|
||||
m_pNNFilterA->AdaptAfterPrediction(&m_rbA[-1], -m_nOrder1, nA);
|
||||
m_pNNFilterB->AdaptAfterPrediction(&m_rbB[-1], -m_nOrder1, nB);
|
||||
|
||||
m_rbA.IncrementSafe(); m_rbB.IncrementSafe();
|
||||
}
|
||||
|
||||
inline void Decompress(int & nA, int & nB)
|
||||
{
|
||||
if (m_nShift <= 0)
|
||||
return;
|
||||
|
||||
m_rbA[-m_nOrder1 - 1] = m_rbB[-1];
|
||||
int nOutputA = nA + (m_pNNFilterA->GetPrediction(&m_rbA[-1]) >> m_nShift);
|
||||
m_rbA[0] = GetSaturatedShortFromInt(nOutputA);
|
||||
|
||||
m_rbB[-m_nOrder1 - 1] = m_rbA[0];
|
||||
int nOutputB = nB + (m_pNNFilterB->GetPrediction(&m_rbB[-1]) >> m_nShift);
|
||||
m_rbB[0] = GetSaturatedShortFromInt(nOutputB);
|
||||
|
||||
m_pNNFilterA->AdaptAfterPrediction(&m_rbA[-1], -m_nOrder1, nA);
|
||||
m_pNNFilterB->AdaptAfterPrediction(&m_rbB[-1], -m_nOrder1, nB);
|
||||
|
||||
m_rbA.IncrementSafe(); m_rbB.IncrementSafe();
|
||||
|
||||
nA = nOutputA; nB = nOutputB;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
CNNFilter * m_pNNFilterA;
|
||||
CNNFilter * m_pNNFilterB;
|
||||
|
||||
int m_nShift;
|
||||
int m_nOrder1;
|
||||
|
||||
CRollBuffer<short> m_rbA;
|
||||
CRollBuffer<short> m_rbB;
|
||||
|
||||
inline short GetSaturatedShortFromInt(int nValue) const
|
||||
{
|
||||
return short((nValue == short(nValue)) ? nValue : (nValue >> 31) ^ 0x7FFF);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_MULTICHANNEL_NNFILTER_H
|
||||
168
MAC_SDK/Source/MACLib/NNFilter.cpp
Normal file
168
MAC_SDK/Source/MACLib/NNFilter.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
#include "All.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "NNFilter.h"
|
||||
#include "Assembly/Assembly.h"
|
||||
|
||||
CNNFilter::CNNFilter(int nOrder, int nShift, int nVersion)
|
||||
{
|
||||
if ((nOrder <= 0) || ((nOrder % 16) != 0)) throw(1);
|
||||
m_nOrder = nOrder;
|
||||
m_nShift = nShift;
|
||||
m_nVersion = nVersion;
|
||||
|
||||
m_bMMXAvailable = GetMMXAvailable();
|
||||
|
||||
m_rbInput.Create(NN_WINDOW_ELEMENTS, m_nOrder);
|
||||
m_rbDeltaM.Create(NN_WINDOW_ELEMENTS, m_nOrder);
|
||||
m_paryM = new short [m_nOrder];
|
||||
|
||||
#ifdef NN_TEST_MMX
|
||||
srand(GetTickCount());
|
||||
#endif
|
||||
}
|
||||
|
||||
CNNFilter::~CNNFilter()
|
||||
{
|
||||
SAFE_ARRAY_DELETE(m_paryM)
|
||||
}
|
||||
|
||||
void CNNFilter::Flush()
|
||||
{
|
||||
memset(&m_paryM[0], 0, m_nOrder * sizeof(short));
|
||||
m_rbInput.Flush();
|
||||
m_rbDeltaM.Flush();
|
||||
m_nRunningAverage = 0;
|
||||
}
|
||||
|
||||
int CNNFilter::Compress(int nInput)
|
||||
{
|
||||
// convert the input to a short and store it
|
||||
m_rbInput[0] = GetSaturatedShortFromInt(nInput);
|
||||
|
||||
// figure a dot product
|
||||
int nDotProduct;
|
||||
if (m_bMMXAvailable)
|
||||
nDotProduct = CalculateDotProduct(&m_rbInput[-m_nOrder], &m_paryM[0], m_nOrder);
|
||||
else
|
||||
nDotProduct = CalculateDotProductNoMMX(&m_rbInput[-m_nOrder], &m_paryM[0], m_nOrder);
|
||||
|
||||
// calculate the output
|
||||
int nOutput = nInput - ((nDotProduct + (1 << (m_nShift - 1))) >> m_nShift);
|
||||
|
||||
// adapt
|
||||
if (m_bMMXAvailable)
|
||||
Adapt(&m_paryM[0], &m_rbDeltaM[-m_nOrder], -nOutput, m_nOrder);
|
||||
else
|
||||
AdaptNoMMX(&m_paryM[0], &m_rbDeltaM[-m_nOrder], nOutput, m_nOrder);
|
||||
|
||||
int nTempABS = abs(nInput);
|
||||
|
||||
if (nTempABS > (m_nRunningAverage * 3))
|
||||
m_rbDeltaM[0] = ((nInput >> 25) & 64) - 32;
|
||||
else if (nTempABS > (m_nRunningAverage * 4) / 3)
|
||||
m_rbDeltaM[0] = ((nInput >> 26) & 32) - 16;
|
||||
else if (nTempABS > 0)
|
||||
m_rbDeltaM[0] = ((nInput >> 27) & 16) - 8;
|
||||
else
|
||||
m_rbDeltaM[0] = 0;
|
||||
|
||||
m_nRunningAverage += (nTempABS - m_nRunningAverage) / 16;
|
||||
|
||||
m_rbDeltaM[-1] >>= 1;
|
||||
m_rbDeltaM[-2] >>= 1;
|
||||
m_rbDeltaM[-8] >>= 1;
|
||||
|
||||
// increment and roll if necessary
|
||||
m_rbInput.IncrementSafe();
|
||||
m_rbDeltaM.IncrementSafe();
|
||||
|
||||
return nOutput;
|
||||
}
|
||||
|
||||
int CNNFilter::Decompress(int nInput)
|
||||
{
|
||||
// figure a dot product
|
||||
int nDotProduct;
|
||||
|
||||
if (m_bMMXAvailable)
|
||||
nDotProduct = CalculateDotProduct(&m_rbInput[-m_nOrder], &m_paryM[0], m_nOrder);
|
||||
else
|
||||
nDotProduct = CalculateDotProductNoMMX(&m_rbInput[-m_nOrder], &m_paryM[0], m_nOrder);
|
||||
|
||||
// adapt
|
||||
if (m_bMMXAvailable)
|
||||
Adapt(&m_paryM[0], &m_rbDeltaM[-m_nOrder], -nInput, m_nOrder);
|
||||
else
|
||||
AdaptNoMMX(&m_paryM[0], &m_rbDeltaM[-m_nOrder], nInput, m_nOrder);
|
||||
|
||||
// store the output value
|
||||
int nOutput = nInput + ((nDotProduct + (1 << (m_nShift - 1))) >> m_nShift);
|
||||
|
||||
// update the input buffer
|
||||
m_rbInput[0] = GetSaturatedShortFromInt(nOutput);
|
||||
|
||||
if (m_nVersion >= 3980)
|
||||
{
|
||||
int nTempABS = abs(nOutput);
|
||||
|
||||
if (nTempABS > (m_nRunningAverage * 3))
|
||||
m_rbDeltaM[0] = ((nOutput >> 25) & 64) - 32;
|
||||
else if (nTempABS > (m_nRunningAverage * 4) / 3)
|
||||
m_rbDeltaM[0] = ((nOutput >> 26) & 32) - 16;
|
||||
else if (nTempABS > 0)
|
||||
m_rbDeltaM[0] = ((nOutput >> 27) & 16) - 8;
|
||||
else
|
||||
m_rbDeltaM[0] = 0;
|
||||
|
||||
m_nRunningAverage += (nTempABS - m_nRunningAverage) / 16;
|
||||
|
||||
m_rbDeltaM[-1] >>= 1;
|
||||
m_rbDeltaM[-2] >>= 1;
|
||||
m_rbDeltaM[-8] >>= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rbDeltaM[0] = (nOutput == 0) ? 0 : ((nOutput >> 28) & 8) - 4;
|
||||
m_rbDeltaM[-4] >>= 1;
|
||||
m_rbDeltaM[-8] >>= 1;
|
||||
}
|
||||
|
||||
// increment and roll if necessary
|
||||
m_rbInput.IncrementSafe();
|
||||
m_rbDeltaM.IncrementSafe();
|
||||
|
||||
return nOutput;
|
||||
}
|
||||
|
||||
void CNNFilter::AdaptNoMMX(short * pM, short * pAdapt, int nDirection, int nOrder)
|
||||
{
|
||||
nOrder >>= 4;
|
||||
|
||||
if (nDirection < 0)
|
||||
{
|
||||
while (nOrder--)
|
||||
{
|
||||
EXPAND_16_TIMES(*pM++ += *pAdapt++;)
|
||||
}
|
||||
}
|
||||
else if (nDirection > 0)
|
||||
{
|
||||
while (nOrder--)
|
||||
{
|
||||
EXPAND_16_TIMES(*pM++ -= *pAdapt++;)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CNNFilter::CalculateDotProductNoMMX(short * pA, short * pB, int nOrder)
|
||||
{
|
||||
int nDotProduct = 0;
|
||||
nOrder >>= 4;
|
||||
|
||||
while (nOrder--)
|
||||
{
|
||||
EXPAND_16_TIMES(nDotProduct += *pA++ * *pB++;)
|
||||
}
|
||||
|
||||
return nDotProduct;
|
||||
}
|
||||
42
MAC_SDK/Source/MACLib/NNFilter.h
Normal file
42
MAC_SDK/Source/MACLib/NNFilter.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef APE_NNFILTER_H
|
||||
#define APE_NNFILTER_H
|
||||
|
||||
#include "RollBuffer.h"
|
||||
#define NN_WINDOW_ELEMENTS 512
|
||||
//#define NN_TEST_MMX
|
||||
|
||||
class CNNFilter
|
||||
{
|
||||
public:
|
||||
|
||||
CNNFilter(int nOrder, int nShift, int nVersion);
|
||||
~CNNFilter();
|
||||
|
||||
int Compress(int nInput);
|
||||
int Decompress(int nInput);
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
|
||||
int m_nOrder;
|
||||
int m_nShift;
|
||||
int m_nVersion;
|
||||
BOOL m_bMMXAvailable;
|
||||
int m_nRunningAverage;
|
||||
|
||||
CRollBuffer<short> m_rbInput;
|
||||
CRollBuffer<short> m_rbDeltaM;
|
||||
|
||||
short * m_paryM;
|
||||
// short * m_paryM_ptr;
|
||||
|
||||
inline short GetSaturatedShortFromInt(int nValue) const
|
||||
{
|
||||
return short((nValue == short(nValue)) ? nValue : (nValue >> 31) ^ 0x7FFF);
|
||||
}
|
||||
|
||||
inline int CalculateDotProductNoMMX(short * pA, short * pB, int nOrder);
|
||||
inline void AdaptNoMMX(short * pM, short * pAdapt, int nDirection, int nOrder);
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_NNFILTER_H
|
||||
408
MAC_SDK/Source/MACLib/NewPredictor.cpp
Normal file
408
MAC_SDK/Source/MACLib/NewPredictor.cpp
Normal file
@@ -0,0 +1,408 @@
|
||||
#include "All.h"
|
||||
#include "APECompress.h"
|
||||
#include "NewPredictor.h"
|
||||
|
||||
/*****************************************************************************************
|
||||
CPredictorCompressNormal
|
||||
*****************************************************************************************/
|
||||
CPredictorCompressNormal::CPredictorCompressNormal(int nCompressionLevel)
|
||||
: IPredictorCompress(nCompressionLevel)
|
||||
{
|
||||
if (nCompressionLevel == COMPRESSION_LEVEL_FAST)
|
||||
{
|
||||
m_pNNFilter = NULL;
|
||||
m_pNNFilter1 = NULL;
|
||||
m_pNNFilter2 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_NORMAL)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(16, 11, MAC_VERSION_NUMBER);
|
||||
m_pNNFilter1 = NULL;
|
||||
m_pNNFilter2 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_HIGH)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(64, 11, MAC_VERSION_NUMBER);
|
||||
m_pNNFilter1 = NULL;
|
||||
m_pNNFilter2 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(256, 13, MAC_VERSION_NUMBER);
|
||||
m_pNNFilter1 = new CNNFilter(32, 10, MAC_VERSION_NUMBER);
|
||||
m_pNNFilter2 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_INSANE)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(1024 + 256, 15, MAC_VERSION_NUMBER);
|
||||
m_pNNFilter1 = new CNNFilter(256, 13, MAC_VERSION_NUMBER);
|
||||
m_pNNFilter2 = new CNNFilter(16, 11, MAC_VERSION_NUMBER);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw(1);
|
||||
}
|
||||
}
|
||||
|
||||
CPredictorCompressNormal::~CPredictorCompressNormal()
|
||||
{
|
||||
SAFE_DELETE(m_pNNFilter)
|
||||
SAFE_DELETE(m_pNNFilter1)
|
||||
SAFE_DELETE(m_pNNFilter2)
|
||||
}
|
||||
|
||||
int CPredictorCompressNormal::Flush()
|
||||
{
|
||||
if (m_pNNFilter) m_pNNFilter->Flush();
|
||||
if (m_pNNFilter1) m_pNNFilter1->Flush();
|
||||
if (m_pNNFilter2) m_pNNFilter2->Flush();
|
||||
|
||||
m_rbPrediction.Flush();
|
||||
m_rbAdapt.Flush();
|
||||
m_Stage1FilterA.Flush(); m_Stage1FilterB.Flush();
|
||||
|
||||
memset(m_aryM, 0, sizeof(m_aryM));
|
||||
|
||||
int * paryM = &m_aryM[8];
|
||||
paryM[0] = 360;
|
||||
paryM[-1] = 317;
|
||||
paryM[-2] = -109;
|
||||
paryM[-3] = 98;
|
||||
|
||||
m_nCurrentIndex = 0;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CPredictorCompressNormal::CompressValue(int nA, int nB)
|
||||
{
|
||||
// roll the buffers if necessary
|
||||
if (m_nCurrentIndex == WINDOW_BLOCKS)
|
||||
{
|
||||
m_rbPrediction.Roll(); m_rbAdapt.Roll();
|
||||
m_nCurrentIndex = 0;
|
||||
}
|
||||
|
||||
// stage 1: simple, non-adaptive order 1 prediction
|
||||
nA = m_Stage1FilterA.Compress(nA);
|
||||
nB = m_Stage1FilterB.Compress(nB);
|
||||
|
||||
// stage 2: adaptive offset filter(s)
|
||||
m_rbPrediction[0] = nA;
|
||||
m_rbPrediction[-2] = m_rbPrediction[-1] - m_rbPrediction[-2];
|
||||
|
||||
m_rbPrediction[-5] = nB;
|
||||
m_rbPrediction[-6] = m_rbPrediction[-5] - m_rbPrediction[-6];
|
||||
|
||||
int * paryM = &m_aryM[8];
|
||||
|
||||
int nPredictionA = (m_rbPrediction[-1] * paryM[0]) + (m_rbPrediction[-2] * paryM[-1]) + (m_rbPrediction[-3] * paryM[-2]) + (m_rbPrediction[-4] * paryM[-3]);
|
||||
int nPredictionB = (m_rbPrediction[-5] * paryM[-4]) + (m_rbPrediction[-6] * paryM[-5]) + (m_rbPrediction[-7] * paryM[-6]) + (m_rbPrediction[-8] * paryM[-7]) + (m_rbPrediction[-9] * paryM[-8]);
|
||||
|
||||
int nOutput = nA - ((nPredictionA + (nPredictionB >> 1)) >> 10);
|
||||
|
||||
// adapt
|
||||
m_rbAdapt[0] = (m_rbPrediction[-1]) ? ((m_rbPrediction[-1] >> 30) & 2) - 1 : 0;
|
||||
m_rbAdapt[-1] = (m_rbPrediction[-2]) ? ((m_rbPrediction[-2] >> 30) & 2) - 1 : 0;
|
||||
m_rbAdapt[-4] = (m_rbPrediction[-5]) ? ((m_rbPrediction[-5] >> 30) & 2) - 1 : 0;
|
||||
m_rbAdapt[-5] = (m_rbPrediction[-6]) ? ((m_rbPrediction[-6] >> 30) & 2) - 1 : 0;
|
||||
|
||||
if (nOutput > 0)
|
||||
{
|
||||
int * pM = &paryM[-8]; int * pAdapt = &m_rbAdapt[-8];
|
||||
EXPAND_9_TIMES(*pM++ -= *pAdapt++;)
|
||||
}
|
||||
else if (nOutput < 0)
|
||||
{
|
||||
int * pM = &paryM[-8]; int * pAdapt = &m_rbAdapt[-8];
|
||||
EXPAND_9_TIMES(*pM++ += *pAdapt++;)
|
||||
}
|
||||
|
||||
// stage 3: NNFilters
|
||||
if (m_pNNFilter)
|
||||
{
|
||||
nOutput = m_pNNFilter->Compress(nOutput);
|
||||
|
||||
if (m_pNNFilter1)
|
||||
{
|
||||
nOutput = m_pNNFilter1->Compress(nOutput);
|
||||
|
||||
if (m_pNNFilter2)
|
||||
nOutput = m_pNNFilter2->Compress(nOutput);
|
||||
}
|
||||
}
|
||||
|
||||
m_rbPrediction.IncrementFast(); m_rbAdapt.IncrementFast();
|
||||
m_nCurrentIndex++;
|
||||
|
||||
return nOutput;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
CPredictorDecompressNormal3930to3950
|
||||
*****************************************************************************************/
|
||||
CPredictorDecompressNormal3930to3950::CPredictorDecompressNormal3930to3950(int nCompressionLevel, int nVersion)
|
||||
: IPredictorDecompress(nCompressionLevel, nVersion)
|
||||
{
|
||||
m_pBuffer[0] = new int [HISTORY_ELEMENTS + WINDOW_BLOCKS];
|
||||
|
||||
if (nCompressionLevel == COMPRESSION_LEVEL_FAST)
|
||||
{
|
||||
m_pNNFilter = NULL;
|
||||
m_pNNFilter1 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_NORMAL)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(16, 11, nVersion);
|
||||
m_pNNFilter1 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_HIGH)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(64, 11, nVersion);
|
||||
m_pNNFilter1 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(256, 13, nVersion);
|
||||
m_pNNFilter1 = new CNNFilter(32, 10, nVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw(1);
|
||||
}
|
||||
}
|
||||
|
||||
CPredictorDecompressNormal3930to3950::~CPredictorDecompressNormal3930to3950()
|
||||
{
|
||||
SAFE_DELETE(m_pNNFilter)
|
||||
SAFE_DELETE(m_pNNFilter1)
|
||||
SAFE_ARRAY_DELETE(m_pBuffer[0])
|
||||
}
|
||||
|
||||
int CPredictorDecompressNormal3930to3950::Flush()
|
||||
{
|
||||
if (m_pNNFilter) m_pNNFilter->Flush();
|
||||
if (m_pNNFilter1) m_pNNFilter1->Flush();
|
||||
|
||||
ZeroMemory(m_pBuffer[0], (HISTORY_ELEMENTS + 1) * sizeof(int));
|
||||
ZeroMemory(&m_aryM[0], M_COUNT * sizeof(int));
|
||||
|
||||
m_aryM[0] = 360;
|
||||
m_aryM[1] = 317;
|
||||
m_aryM[2] = -109;
|
||||
m_aryM[3] = 98;
|
||||
|
||||
m_pInputBuffer = &m_pBuffer[0][HISTORY_ELEMENTS];
|
||||
|
||||
m_nLastValue = 0;
|
||||
m_nCurrentIndex = 0;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CPredictorDecompressNormal3930to3950::DecompressValue(int nInput, int)
|
||||
{
|
||||
if (m_nCurrentIndex == WINDOW_BLOCKS)
|
||||
{
|
||||
// copy forward and adjust pointers
|
||||
memcpy(&m_pBuffer[0][0], &m_pBuffer[0][WINDOW_BLOCKS], HISTORY_ELEMENTS * sizeof(int));
|
||||
m_pInputBuffer = &m_pBuffer[0][HISTORY_ELEMENTS];
|
||||
|
||||
m_nCurrentIndex = 0;
|
||||
}
|
||||
|
||||
// stage 2: NNFilter
|
||||
if (m_pNNFilter1)
|
||||
nInput = m_pNNFilter1->Decompress(nInput);
|
||||
if (m_pNNFilter)
|
||||
nInput = m_pNNFilter->Decompress(nInput);
|
||||
|
||||
// stage 1: multiple predictors (order 2 and offset 1)
|
||||
|
||||
int p1 = m_pInputBuffer[-1];
|
||||
int p2 = m_pInputBuffer[-1] - m_pInputBuffer[-2];
|
||||
int p3 = m_pInputBuffer[-2] - m_pInputBuffer[-3];
|
||||
int p4 = m_pInputBuffer[-3] - m_pInputBuffer[-4];
|
||||
|
||||
m_pInputBuffer[0] = nInput + (((p1 * m_aryM[0]) + (p2 * m_aryM[1]) + (p3 * m_aryM[2]) + (p4 * m_aryM[3])) >> 9);
|
||||
|
||||
if (nInput > 0)
|
||||
{
|
||||
m_aryM[0] -= ((p1 >> 30) & 2) - 1;
|
||||
m_aryM[1] -= ((p2 >> 30) & 2) - 1;
|
||||
m_aryM[2] -= ((p3 >> 30) & 2) - 1;
|
||||
m_aryM[3] -= ((p4 >> 30) & 2) - 1;
|
||||
}
|
||||
else if (nInput < 0)
|
||||
{
|
||||
m_aryM[0] += ((p1 >> 30) & 2) - 1;
|
||||
m_aryM[1] += ((p2 >> 30) & 2) - 1;
|
||||
m_aryM[2] += ((p3 >> 30) & 2) - 1;
|
||||
m_aryM[3] += ((p4 >> 30) & 2) - 1;
|
||||
}
|
||||
|
||||
int nRetVal = m_pInputBuffer[0] + ((m_nLastValue * 31) >> 5);
|
||||
m_nLastValue = nRetVal;
|
||||
|
||||
m_nCurrentIndex++;
|
||||
m_pInputBuffer++;
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
CPredictorDecompress3950toCurrent
|
||||
*****************************************************************************************/
|
||||
CPredictorDecompress3950toCurrent::CPredictorDecompress3950toCurrent(int nCompressionLevel, int nVersion)
|
||||
: IPredictorDecompress(nCompressionLevel, nVersion)
|
||||
{
|
||||
m_nVersion = nVersion;
|
||||
|
||||
if (nCompressionLevel == COMPRESSION_LEVEL_FAST)
|
||||
{
|
||||
m_pNNFilter = NULL;
|
||||
m_pNNFilter1 = NULL;
|
||||
m_pNNFilter2 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_NORMAL)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(16, 11, nVersion);
|
||||
m_pNNFilter1 = NULL;
|
||||
m_pNNFilter2 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_HIGH)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(64, 11, nVersion);
|
||||
m_pNNFilter1 = NULL;
|
||||
m_pNNFilter2 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(256, 13, nVersion);
|
||||
m_pNNFilter1 = new CNNFilter(32, 10, nVersion);
|
||||
m_pNNFilter2 = NULL;
|
||||
}
|
||||
else if (nCompressionLevel == COMPRESSION_LEVEL_INSANE)
|
||||
{
|
||||
m_pNNFilter = new CNNFilter(1024 + 256, 15, MAC_VERSION_NUMBER);
|
||||
m_pNNFilter1 = new CNNFilter(256, 13, MAC_VERSION_NUMBER);
|
||||
m_pNNFilter2 = new CNNFilter(16, 11, MAC_VERSION_NUMBER);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw(1);
|
||||
}
|
||||
}
|
||||
|
||||
CPredictorDecompress3950toCurrent::~CPredictorDecompress3950toCurrent()
|
||||
{
|
||||
SAFE_DELETE(m_pNNFilter)
|
||||
SAFE_DELETE(m_pNNFilter1)
|
||||
SAFE_DELETE(m_pNNFilter2)
|
||||
}
|
||||
|
||||
int CPredictorDecompress3950toCurrent::Flush()
|
||||
{
|
||||
if (m_pNNFilter) m_pNNFilter->Flush();
|
||||
if (m_pNNFilter1) m_pNNFilter1->Flush();
|
||||
if (m_pNNFilter2) m_pNNFilter2->Flush();
|
||||
|
||||
ZeroMemory(m_aryMA, sizeof(m_aryMA));
|
||||
ZeroMemory(m_aryMB, sizeof(m_aryMB));
|
||||
|
||||
m_rbPredictionA.Flush();
|
||||
m_rbPredictionB.Flush();
|
||||
m_rbAdaptA.Flush();
|
||||
m_rbAdaptB.Flush();
|
||||
|
||||
m_aryMA[0] = 360;
|
||||
m_aryMA[1] = 317;
|
||||
m_aryMA[2] = -109;
|
||||
m_aryMA[3] = 98;
|
||||
|
||||
m_Stage1FilterA.Flush();
|
||||
m_Stage1FilterB.Flush();
|
||||
|
||||
m_nLastValueA = 0;
|
||||
|
||||
m_nCurrentIndex = 0;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CPredictorDecompress3950toCurrent::DecompressValue(int nA, int nB)
|
||||
{
|
||||
if (m_nCurrentIndex == WINDOW_BLOCKS)
|
||||
{
|
||||
// copy forward and adjust pointers
|
||||
m_rbPredictionA.Roll(); m_rbPredictionB.Roll();
|
||||
m_rbAdaptA.Roll(); m_rbAdaptB.Roll();
|
||||
|
||||
m_nCurrentIndex = 0;
|
||||
}
|
||||
|
||||
// stage 2: NNFilter
|
||||
if (m_pNNFilter2)
|
||||
nA = m_pNNFilter2->Decompress(nA);
|
||||
if (m_pNNFilter1)
|
||||
nA = m_pNNFilter1->Decompress(nA);
|
||||
if (m_pNNFilter)
|
||||
nA = m_pNNFilter->Decompress(nA);
|
||||
|
||||
// stage 1: multiple predictors (order 2 and offset 1)
|
||||
m_rbPredictionA[0] = m_nLastValueA;
|
||||
m_rbPredictionA[-1] = m_rbPredictionA[0] - m_rbPredictionA[-1];
|
||||
|
||||
m_rbPredictionB[0] = m_Stage1FilterB.Compress(nB);
|
||||
m_rbPredictionB[-1] = m_rbPredictionB[0] - m_rbPredictionB[-1];
|
||||
|
||||
int nPredictionA = (m_rbPredictionA[0] * m_aryMA[0]) + (m_rbPredictionA[-1] * m_aryMA[1]) + (m_rbPredictionA[-2] * m_aryMA[2]) + (m_rbPredictionA[-3] * m_aryMA[3]);
|
||||
int nPredictionB = (m_rbPredictionB[0] * m_aryMB[0]) + (m_rbPredictionB[-1] * m_aryMB[1]) + (m_rbPredictionB[-2] * m_aryMB[2]) + (m_rbPredictionB[-3] * m_aryMB[3]) + (m_rbPredictionB[-4] * m_aryMB[4]);
|
||||
|
||||
int nCurrentA = nA + ((nPredictionA + (nPredictionB >> 1)) >> 10);
|
||||
|
||||
m_rbAdaptA[0] = (m_rbPredictionA[0]) ? ((m_rbPredictionA[0] >> 30) & 2) - 1 : 0;
|
||||
m_rbAdaptA[-1] = (m_rbPredictionA[-1]) ? ((m_rbPredictionA[-1] >> 30) & 2) - 1 : 0;
|
||||
|
||||
m_rbAdaptB[0] = (m_rbPredictionB[0]) ? ((m_rbPredictionB[0] >> 30) & 2) - 1 : 0;
|
||||
m_rbAdaptB[-1] = (m_rbPredictionB[-1]) ? ((m_rbPredictionB[-1] >> 30) & 2) - 1 : 0;
|
||||
|
||||
if (nA > 0)
|
||||
{
|
||||
m_aryMA[0] -= m_rbAdaptA[0];
|
||||
m_aryMA[1] -= m_rbAdaptA[-1];
|
||||
m_aryMA[2] -= m_rbAdaptA[-2];
|
||||
m_aryMA[3] -= m_rbAdaptA[-3];
|
||||
|
||||
m_aryMB[0] -= m_rbAdaptB[0];
|
||||
m_aryMB[1] -= m_rbAdaptB[-1];
|
||||
m_aryMB[2] -= m_rbAdaptB[-2];
|
||||
m_aryMB[3] -= m_rbAdaptB[-3];
|
||||
m_aryMB[4] -= m_rbAdaptB[-4];
|
||||
}
|
||||
else if (nA < 0)
|
||||
{
|
||||
m_aryMA[0] += m_rbAdaptA[0];
|
||||
m_aryMA[1] += m_rbAdaptA[-1];
|
||||
m_aryMA[2] += m_rbAdaptA[-2];
|
||||
m_aryMA[3] += m_rbAdaptA[-3];
|
||||
|
||||
m_aryMB[0] += m_rbAdaptB[0];
|
||||
m_aryMB[1] += m_rbAdaptB[-1];
|
||||
m_aryMB[2] += m_rbAdaptB[-2];
|
||||
m_aryMB[3] += m_rbAdaptB[-3];
|
||||
m_aryMB[4] += m_rbAdaptB[-4];
|
||||
}
|
||||
|
||||
int nRetVal = m_Stage1FilterA.Decompress(nCurrentA);
|
||||
m_nLastValueA = nCurrentA;
|
||||
|
||||
m_rbPredictionA.IncrementFast(); m_rbPredictionB.IncrementFast();
|
||||
m_rbAdaptA.IncrementFast(); m_rbAdaptB.IncrementFast();
|
||||
|
||||
m_nCurrentIndex++;
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
111
MAC_SDK/Source/MACLib/NewPredictor.h
Normal file
111
MAC_SDK/Source/MACLib/NewPredictor.h
Normal file
@@ -0,0 +1,111 @@
|
||||
#ifndef APE_NEWPREDICTOR_H
|
||||
#define APE_NEWPREDICTOR_H
|
||||
|
||||
#include "Predictor.h"
|
||||
|
||||
#include "RollBuffer.h"
|
||||
#include "NNFilter.h"
|
||||
#include "ScaledFirstOrderFilter.h"
|
||||
|
||||
/*************************************************************************************************
|
||||
Functions to create the interfaces
|
||||
*************************************************************************************************/
|
||||
IPredictorCompress * __stdcall CreateIPredictorCompress();
|
||||
IPredictorDecompress * __stdcall CreateIPredictorDecompress();
|
||||
|
||||
#define WINDOW_BLOCKS 512
|
||||
|
||||
#define BUFFER_COUNT 1
|
||||
#define HISTORY_ELEMENTS 8
|
||||
#define M_COUNT 8
|
||||
|
||||
class CPredictorCompressNormal : public IPredictorCompress
|
||||
{
|
||||
public:
|
||||
CPredictorCompressNormal(int nCompressionLevel);
|
||||
virtual ~CPredictorCompressNormal();
|
||||
|
||||
int CompressValue(int nA, int nB = 0);
|
||||
int Flush();
|
||||
|
||||
protected:
|
||||
|
||||
// buffer information
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 10> m_rbPrediction;
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 9> m_rbAdapt;
|
||||
|
||||
CScaledFirstOrderFilter<31, 5> m_Stage1FilterA;
|
||||
CScaledFirstOrderFilter<31, 5> m_Stage1FilterB;
|
||||
|
||||
// adaption
|
||||
int m_aryM[9];
|
||||
|
||||
// other
|
||||
int m_nCurrentIndex;
|
||||
CNNFilter * m_pNNFilter;
|
||||
CNNFilter * m_pNNFilter1;
|
||||
CNNFilter * m_pNNFilter2;
|
||||
};
|
||||
|
||||
class CPredictorDecompressNormal3930to3950 : public IPredictorDecompress
|
||||
{
|
||||
public:
|
||||
CPredictorDecompressNormal3930to3950(int nCompressionLevel, int nVersion);
|
||||
virtual ~CPredictorDecompressNormal3930to3950();
|
||||
|
||||
int DecompressValue(int nInput, int);
|
||||
int Flush();
|
||||
|
||||
protected:
|
||||
|
||||
// buffer information
|
||||
int * m_pBuffer[BUFFER_COUNT];
|
||||
|
||||
// adaption
|
||||
int m_aryM[M_COUNT];
|
||||
|
||||
// buffer pointers
|
||||
int * m_pInputBuffer;
|
||||
|
||||
// other
|
||||
int m_nCurrentIndex;
|
||||
int m_nLastValue;
|
||||
CNNFilter * m_pNNFilter;
|
||||
CNNFilter * m_pNNFilter1;
|
||||
};
|
||||
|
||||
class CPredictorDecompress3950toCurrent : public IPredictorDecompress
|
||||
{
|
||||
public:
|
||||
CPredictorDecompress3950toCurrent(int nCompressionLevel, int nVersion);
|
||||
virtual ~CPredictorDecompress3950toCurrent();
|
||||
|
||||
int DecompressValue(int nA, int nB = 0);
|
||||
int Flush();
|
||||
|
||||
protected:
|
||||
|
||||
// adaption
|
||||
int m_aryMA[M_COUNT];
|
||||
int m_aryMB[M_COUNT];
|
||||
|
||||
// buffer pointers
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbPredictionA;
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbPredictionB;
|
||||
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbAdaptA;
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbAdaptB;
|
||||
|
||||
CScaledFirstOrderFilter<31, 5> m_Stage1FilterA;
|
||||
CScaledFirstOrderFilter<31, 5> m_Stage1FilterB;
|
||||
|
||||
// other
|
||||
int m_nCurrentIndex;
|
||||
int m_nLastValueA;
|
||||
int m_nVersion;
|
||||
CNNFilter * m_pNNFilter;
|
||||
CNNFilter * m_pNNFilter1;
|
||||
CNNFilter * m_pNNFilter2;
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_NEWPREDICTOR_H
|
||||
178
MAC_SDK/Source/MACLib/Old/APEDecompressCore.cpp
Normal file
178
MAC_SDK/Source/MACLib/Old/APEDecompressCore.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#include "All.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
#include "UnMAC.h"
|
||||
#include "APEDecompressCore.h"
|
||||
#include "../APEInfo.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "../UnBitArrayBase.h"
|
||||
#include "Anti-Predictor.h"
|
||||
#include "UnMAC.h"
|
||||
#include "../Prepare.h"
|
||||
#include "../UnBitArray.h"
|
||||
#include "../Assembly/Assembly.h"
|
||||
|
||||
CAPEDecompressCore::CAPEDecompressCore(CIO * pIO, IAPEDecompress * pAPEDecompress)
|
||||
{
|
||||
m_pAPEDecompress = pAPEDecompress;
|
||||
|
||||
// initialize the bit array
|
||||
m_pUnBitArray = CreateUnBitArray(pAPEDecompress, pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION));
|
||||
|
||||
if (m_pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION) >= 3930)
|
||||
throw(0);
|
||||
|
||||
m_pAntiPredictorX = CreateAntiPredictor(pAPEDecompress->GetInfo(APE_INFO_COMPRESSION_LEVEL), pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION));
|
||||
m_pAntiPredictorY = CreateAntiPredictor(pAPEDecompress->GetInfo(APE_INFO_COMPRESSION_LEVEL), pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION));
|
||||
|
||||
m_pDataX = new int [pAPEDecompress->GetInfo(APE_INFO_BLOCKS_PER_FRAME) + 16];
|
||||
m_pDataY = new int [pAPEDecompress->GetInfo(APE_INFO_BLOCKS_PER_FRAME) + 16];
|
||||
m_pTempData = new int [pAPEDecompress->GetInfo(APE_INFO_BLOCKS_PER_FRAME) + 16];
|
||||
|
||||
m_nBlocksProcessed = 0;
|
||||
|
||||
// check to see if MMX is available
|
||||
m_bMMXAvailable = GetMMXAvailable();
|
||||
}
|
||||
|
||||
CAPEDecompressCore::~CAPEDecompressCore()
|
||||
{
|
||||
SAFE_DELETE(m_pUnBitArray)
|
||||
|
||||
SAFE_DELETE(m_pAntiPredictorX)
|
||||
SAFE_DELETE(m_pAntiPredictorY)
|
||||
|
||||
SAFE_ARRAY_DELETE(m_pDataX)
|
||||
SAFE_ARRAY_DELETE(m_pDataY)
|
||||
SAFE_ARRAY_DELETE(m_pTempData)
|
||||
}
|
||||
|
||||
void CAPEDecompressCore::GenerateDecodedArrays(int nBlocks, int nSpecialCodes, int nFrameIndex, int nCPULoadBalancingFactor)
|
||||
{
|
||||
CUnBitArray * pBitArray = (CUnBitArray *) m_pUnBitArray;
|
||||
|
||||
if (m_pAPEDecompress->GetInfo(APE_INFO_CHANNELS) == 2)
|
||||
{
|
||||
if ((nSpecialCodes & SPECIAL_FRAME_LEFT_SILENCE) && (nSpecialCodes & SPECIAL_FRAME_RIGHT_SILENCE))
|
||||
{
|
||||
memset(m_pDataX, 0, nBlocks * 4);
|
||||
memset(m_pDataY, 0, nBlocks * 4);
|
||||
}
|
||||
else if (nSpecialCodes & SPECIAL_FRAME_PSEUDO_STEREO)
|
||||
{
|
||||
GenerateDecodedArray(m_pDataX, nBlocks, nFrameIndex, m_pAntiPredictorX, nCPULoadBalancingFactor);
|
||||
memset(m_pDataY, 0, nBlocks * 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
GenerateDecodedArray(m_pDataX, nBlocks, nFrameIndex, m_pAntiPredictorX, nCPULoadBalancingFactor);
|
||||
GenerateDecodedArray(m_pDataY, nBlocks, nFrameIndex, m_pAntiPredictorY, nCPULoadBalancingFactor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nSpecialCodes & SPECIAL_FRAME_LEFT_SILENCE)
|
||||
{
|
||||
memset(m_pDataX, 0, nBlocks * 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
GenerateDecodedArray(m_pDataX, nBlocks, nFrameIndex, m_pAntiPredictorX, nCPULoadBalancingFactor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CAPEDecompressCore::GenerateDecodedArray(int * Input_Array, uint32 Number_of_Elements, int Frame_Index, CAntiPredictor *pAntiPredictor, int CPULoadBalancingFactor)
|
||||
{
|
||||
const int nFrameBytes = m_pAPEDecompress->GetInfo(APE_INFO_FRAME_BYTES, Frame_Index);
|
||||
|
||||
// run the prediction sequence
|
||||
switch (m_pAPEDecompress->GetInfo(APE_INFO_COMPRESSION_LEVEL))
|
||||
{
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_FAST
|
||||
case COMPRESSION_LEVEL_FAST:
|
||||
if (m_pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION) < 3320)
|
||||
{
|
||||
m_pUnBitArray->GenerateArray(m_pTempData, Number_of_Elements, nFrameBytes);
|
||||
pAntiPredictor->AntiPredict(m_pTempData, Input_Array, Number_of_Elements);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pUnBitArray->GenerateArray(Input_Array, Number_of_Elements, nFrameBytes);
|
||||
pAntiPredictor->AntiPredict(Input_Array, NULL, Number_of_Elements);
|
||||
}
|
||||
|
||||
break;
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_FAST
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_NORMAL
|
||||
|
||||
case COMPRESSION_LEVEL_NORMAL:
|
||||
{
|
||||
// get the array from the bitstream
|
||||
m_pUnBitArray->GenerateArray(m_pTempData, Number_of_Elements, nFrameBytes);
|
||||
pAntiPredictor->AntiPredict(m_pTempData, Input_Array, Number_of_Elements);
|
||||
break;
|
||||
}
|
||||
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_NORMAL
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_HIGH
|
||||
case COMPRESSION_LEVEL_HIGH:
|
||||
// get the array from the bitstream
|
||||
m_pUnBitArray->GenerateArray(m_pTempData, Number_of_Elements, nFrameBytes);
|
||||
pAntiPredictor->AntiPredict(m_pTempData, Input_Array, Number_of_Elements);
|
||||
break;
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_HIGH
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
case COMPRESSION_LEVEL_EXTRA_HIGH:
|
||||
|
||||
unsigned int aryCoefficientsA[64], aryCoefficientsB[64], nNumberOfCoefficients;
|
||||
|
||||
#define GET_COEFFICIENTS(NumberOfCoefficientsBits, ValueBits) \
|
||||
nNumberOfCoefficients = m_pUnBitArray->DecodeValue(DECODE_VALUE_METHOD_X_BITS, NumberOfCoefficientsBits); \
|
||||
for (unsigned int z = 0; z <= nNumberOfCoefficients; z++) \
|
||||
{ \
|
||||
aryCoefficientsA[z] = m_pUnBitArray->DecodeValue(DECODE_VALUE_METHOD_X_BITS, ValueBits); \
|
||||
aryCoefficientsB[z] = m_pUnBitArray->DecodeValue(DECODE_VALUE_METHOD_X_BITS, ValueBits); \
|
||||
} \
|
||||
|
||||
if (m_pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION) < 3320)
|
||||
{
|
||||
GET_COEFFICIENTS(4, 6)
|
||||
m_pUnBitArray->GenerateArray(m_pTempData, Number_of_Elements, nFrameBytes);
|
||||
((CAntiPredictorExtraHigh0000To3320 *) pAntiPredictor)->AntiPredict(m_pTempData, Input_Array, Number_of_Elements, nNumberOfCoefficients, &aryCoefficientsA[0], &aryCoefficientsB[0]);
|
||||
}
|
||||
else if (m_pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION) < 3600)
|
||||
{
|
||||
GET_COEFFICIENTS(3, 5)
|
||||
m_pUnBitArray->GenerateArray(m_pTempData, Number_of_Elements, nFrameBytes);
|
||||
((CAntiPredictorExtraHigh3320To3600 *) pAntiPredictor)->AntiPredict(m_pTempData, Input_Array, Number_of_Elements, nNumberOfCoefficients, &aryCoefficientsA[0], &aryCoefficientsB[0]);
|
||||
}
|
||||
else if (m_pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION) < 3700)
|
||||
{
|
||||
GET_COEFFICIENTS(3, 6)
|
||||
m_pUnBitArray->GenerateArray(m_pTempData, Number_of_Elements, nFrameBytes);
|
||||
((CAntiPredictorExtraHigh3600To3700 *) pAntiPredictor)->AntiPredict(m_pTempData, Input_Array, Number_of_Elements, nNumberOfCoefficients, &aryCoefficientsA[0], &aryCoefficientsB[0]);
|
||||
}
|
||||
else if (m_pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION) < 3800)
|
||||
{
|
||||
GET_COEFFICIENTS(3, 6)
|
||||
m_pUnBitArray->GenerateArray(m_pTempData, Number_of_Elements, nFrameBytes);
|
||||
((CAntiPredictorExtraHigh3700To3800 *) pAntiPredictor)->AntiPredict(m_pTempData, Input_Array, Number_of_Elements, nNumberOfCoefficients, &aryCoefficientsA[0], &aryCoefficientsB[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pUnBitArray->GenerateArray(m_pTempData, Number_of_Elements, nFrameBytes);
|
||||
((CAntiPredictorExtraHigh3800ToCurrent *) pAntiPredictor)->AntiPredict(m_pTempData, Input_Array, Number_of_Elements, m_bMMXAvailable, CPULoadBalancingFactor, m_pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION));
|
||||
}
|
||||
|
||||
break;
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifdef BACKWARDS_COMPATIBILITY
|
||||
37
MAC_SDK/Source/MACLib/Old/APEDecompressCore.h
Normal file
37
MAC_SDK/Source/MACLib/Old/APEDecompressCore.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef APE_DECOMPRESS_CORE_H
|
||||
#define APE_DECOMPRESS_CORE_H
|
||||
|
||||
class CAPEDecompressCore
|
||||
{
|
||||
public:
|
||||
|
||||
CAPEDecompressCore(CIO * pIO, IAPEDecompress * pAPEDecompress);
|
||||
~CAPEDecompressCore();
|
||||
|
||||
void GenerateDecodedArrays(int nBlocks, int nSpecialCodes, int nFrameIndex, int nCPULoadBalancingFactor);
|
||||
void GenerateDecodedArray(int *Input_Array, uint32 Number_of_Elements, int Frame_Index, CAntiPredictor *pAntiPredictor, int CPULoadBalancingFactor = 0);
|
||||
|
||||
int * GetDataX() { return m_pDataX; }
|
||||
int * GetDataY() { return m_pDataY; }
|
||||
|
||||
CUnBitArrayBase * GetUnBitArrray() { return m_pUnBitArray; }
|
||||
|
||||
int * m_pTempData;
|
||||
int * m_pDataX;
|
||||
int * m_pDataY;
|
||||
|
||||
CAntiPredictor * m_pAntiPredictorX;
|
||||
CAntiPredictor * m_pAntiPredictorY;
|
||||
|
||||
CUnBitArrayBase * m_pUnBitArray;
|
||||
BIT_ARRAY_STATE m_BitArrayStateX;
|
||||
BIT_ARRAY_STATE m_BitArrayStateY;
|
||||
|
||||
IAPEDecompress * m_pAPEDecompress;
|
||||
|
||||
BOOL m_bMMXAvailable;
|
||||
int m_nBlocksProcessed;
|
||||
};
|
||||
|
||||
|
||||
#endif // #ifndef APE_DECOMPRESS_CORE_H
|
||||
279
MAC_SDK/Source/MACLib/Old/APEDecompressOld.cpp
Normal file
279
MAC_SDK/Source/MACLib/Old/APEDecompressOld.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
#include "All.h"
|
||||
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
#include "UnMAC.h"
|
||||
#include "APEDecompressOld.h"
|
||||
#include "../APEInfo.h"
|
||||
|
||||
CAPEDecompressOld::CAPEDecompressOld(int * pErrorCode, CAPEInfo * pAPEInfo, int nStartBlock, int nFinishBlock)
|
||||
{
|
||||
*pErrorCode = ERROR_SUCCESS;
|
||||
|
||||
// open / analyze the file
|
||||
m_spAPEInfo.Assign(pAPEInfo);
|
||||
|
||||
// version check (this implementation only works with 3.92 and earlier files)
|
||||
if (GetInfo(APE_INFO_FILE_VERSION) > 3920)
|
||||
{
|
||||
*pErrorCode = ERROR_UNDEFINED;
|
||||
return;
|
||||
}
|
||||
|
||||
// create the buffer
|
||||
m_nBlockAlign = GetInfo(APE_INFO_BLOCK_ALIGN);
|
||||
|
||||
// initialize other stuff
|
||||
m_nBufferTail = 0;
|
||||
m_bDecompressorInitialized = FALSE;
|
||||
m_nCurrentFrame = 0;
|
||||
m_nCurrentBlock = 0;
|
||||
|
||||
// set the "real" start and finish blocks
|
||||
m_nStartBlock = (nStartBlock < 0) ? 0 : min(nStartBlock, GetInfo(APE_INFO_TOTAL_BLOCKS));
|
||||
m_nFinishBlock = (nFinishBlock < 0) ? GetInfo(APE_INFO_TOTAL_BLOCKS) : min(nFinishBlock, GetInfo(APE_INFO_TOTAL_BLOCKS));
|
||||
m_bIsRanged = (m_nStartBlock != 0) || (m_nFinishBlock != GetInfo(APE_INFO_TOTAL_BLOCKS));
|
||||
}
|
||||
|
||||
CAPEDecompressOld::~CAPEDecompressOld()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CAPEDecompressOld::InitializeDecompressor()
|
||||
{
|
||||
// check if we have anything to do
|
||||
if (m_bDecompressorInitialized)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
// initialize the decoder
|
||||
RETURN_ON_ERROR(m_UnMAC.Initialize(this))
|
||||
|
||||
int nMaximumDecompressedFrameBytes = m_nBlockAlign * GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nTotalBufferBytes = max(65536, (nMaximumDecompressedFrameBytes + 16) * 2);
|
||||
m_spBuffer.Assign(new char [nTotalBufferBytes], TRUE);
|
||||
if (m_spBuffer == NULL)
|
||||
return ERROR_INSUFFICIENT_MEMORY;
|
||||
|
||||
// update the initialized flag
|
||||
m_bDecompressorInitialized = TRUE;
|
||||
|
||||
// seek to the beginning
|
||||
return Seek(0);
|
||||
}
|
||||
|
||||
int CAPEDecompressOld::GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved)
|
||||
{
|
||||
if (pBlocksRetrieved) *pBlocksRetrieved = 0;
|
||||
|
||||
RETURN_ON_ERROR(InitializeDecompressor())
|
||||
|
||||
// cap
|
||||
int nBlocksUntilFinish = m_nFinishBlock - m_nCurrentBlock;
|
||||
nBlocks = min(nBlocks, nBlocksUntilFinish);
|
||||
|
||||
int nBlocksRetrieved = 0;
|
||||
|
||||
// fulfill as much of the request as possible
|
||||
int nTotalBytesNeeded = nBlocks * m_nBlockAlign;
|
||||
int nBytesLeft = nTotalBytesNeeded;
|
||||
int nBlocksDecoded = 1;
|
||||
|
||||
while (nBytesLeft > 0 && nBlocksDecoded > 0)
|
||||
{
|
||||
// empty the buffer
|
||||
int nBytesAvailable = m_nBufferTail;
|
||||
int nIntialBytes = min(nBytesLeft, nBytesAvailable);
|
||||
if (nIntialBytes > 0)
|
||||
{
|
||||
memcpy(&pBuffer[nTotalBytesNeeded - nBytesLeft], &m_spBuffer[0], nIntialBytes);
|
||||
|
||||
if ((m_nBufferTail - nIntialBytes) > 0)
|
||||
memmove(&m_spBuffer[0], &m_spBuffer[nIntialBytes], m_nBufferTail - nIntialBytes);
|
||||
|
||||
nBytesLeft -= nIntialBytes;
|
||||
m_nBufferTail -= nIntialBytes;
|
||||
|
||||
}
|
||||
|
||||
// decode more
|
||||
if (nBytesLeft > 0)
|
||||
{
|
||||
nBlocksDecoded = m_UnMAC.DecompressFrame((unsigned char *) &m_spBuffer[m_nBufferTail], m_nCurrentFrame++, 0);
|
||||
if (nBlocksDecoded == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
m_nBufferTail += (nBlocksDecoded * m_nBlockAlign);
|
||||
}
|
||||
}
|
||||
|
||||
nBlocksRetrieved = (nTotalBytesNeeded - nBytesLeft) / m_nBlockAlign;
|
||||
|
||||
// update the position
|
||||
m_nCurrentBlock += nBlocksRetrieved;
|
||||
|
||||
if (pBlocksRetrieved) *pBlocksRetrieved = nBlocksRetrieved;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPEDecompressOld::Seek(int nBlockOffset)
|
||||
{
|
||||
RETURN_ON_ERROR(InitializeDecompressor())
|
||||
|
||||
// use the offset
|
||||
nBlockOffset += m_nStartBlock;
|
||||
|
||||
// cap (to prevent seeking too far)
|
||||
if (nBlockOffset >= m_nFinishBlock)
|
||||
nBlockOffset = m_nFinishBlock - 1;
|
||||
if (nBlockOffset < m_nStartBlock)
|
||||
nBlockOffset = m_nStartBlock;
|
||||
|
||||
// flush the buffer
|
||||
m_nBufferTail = 0;
|
||||
|
||||
// seek to the perfect location
|
||||
int nBaseFrame = nBlockOffset / GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nBlocksToSkip = nBlockOffset % GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nBytesToSkip = nBlocksToSkip * m_nBlockAlign;
|
||||
|
||||
// skip necessary blocks
|
||||
int nMaximumDecompressedFrameBytes = m_nBlockAlign * GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
char *pTempBuffer = new char [nMaximumDecompressedFrameBytes + 16];
|
||||
ZeroMemory(pTempBuffer, nMaximumDecompressedFrameBytes + 16);
|
||||
|
||||
m_nCurrentFrame = nBaseFrame;
|
||||
|
||||
int nBlocksDecoded = m_UnMAC.DecompressFrame((unsigned char *) pTempBuffer, m_nCurrentFrame++, 0);
|
||||
|
||||
if (nBlocksDecoded == -1)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nBytesToKeep = (nBlocksDecoded * m_nBlockAlign) - nBytesToSkip;
|
||||
memcpy(&m_spBuffer[m_nBufferTail], &pTempBuffer[nBytesToSkip], nBytesToKeep);
|
||||
m_nBufferTail += nBytesToKeep;
|
||||
|
||||
delete [] pTempBuffer;
|
||||
|
||||
|
||||
m_nCurrentBlock = nBlockOffset;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPEDecompressOld::GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1, int nParam2)
|
||||
{
|
||||
int nRetVal = 0;
|
||||
BOOL bHandled = TRUE;
|
||||
|
||||
switch (Field)
|
||||
{
|
||||
case APE_DECOMPRESS_CURRENT_BLOCK:
|
||||
nRetVal = m_nCurrentBlock - m_nStartBlock;
|
||||
break;
|
||||
case APE_DECOMPRESS_CURRENT_MS:
|
||||
{
|
||||
int nSampleRate = m_spAPEInfo->GetInfo(APE_INFO_SAMPLE_RATE, 0, 0);
|
||||
if (nSampleRate > 0)
|
||||
nRetVal = int((double(m_nCurrentBlock) * double(1000)) / double(nSampleRate));
|
||||
break;
|
||||
}
|
||||
case APE_DECOMPRESS_TOTAL_BLOCKS:
|
||||
nRetVal = m_nFinishBlock - m_nStartBlock;
|
||||
break;
|
||||
case APE_DECOMPRESS_LENGTH_MS:
|
||||
{
|
||||
int nSampleRate = m_spAPEInfo->GetInfo(APE_INFO_SAMPLE_RATE, 0, 0);
|
||||
if (nSampleRate > 0)
|
||||
nRetVal = int((double(m_nFinishBlock - m_nStartBlock) * double(1000)) / double(nSampleRate));
|
||||
break;
|
||||
}
|
||||
case APE_DECOMPRESS_CURRENT_BITRATE:
|
||||
nRetVal = GetInfo(APE_INFO_FRAME_BITRATE, m_nCurrentFrame);
|
||||
break;
|
||||
case APE_DECOMPRESS_AVERAGE_BITRATE:
|
||||
{
|
||||
if (m_bIsRanged)
|
||||
{
|
||||
// figure the frame range
|
||||
const int nBlocksPerFrame = GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nStartFrame = m_nStartBlock / nBlocksPerFrame;
|
||||
int nFinishFrame = (m_nFinishBlock + nBlocksPerFrame - 1) / nBlocksPerFrame;
|
||||
|
||||
// get the number of bytes in the first and last frame
|
||||
int nTotalBytes = (GetInfo(APE_INFO_FRAME_BYTES, nStartFrame) * (m_nStartBlock % nBlocksPerFrame)) / nBlocksPerFrame;
|
||||
if (nFinishFrame != nStartFrame)
|
||||
nTotalBytes += (GetInfo(APE_INFO_FRAME_BYTES, nFinishFrame) * (m_nFinishBlock % nBlocksPerFrame)) / nBlocksPerFrame;
|
||||
|
||||
// get the number of bytes in between
|
||||
const int nTotalFrames = GetInfo(APE_INFO_TOTAL_FRAMES);
|
||||
for (int nFrame = nStartFrame + 1; (nFrame < nFinishFrame) && (nFrame < nTotalFrames); nFrame++)
|
||||
nTotalBytes += GetInfo(APE_INFO_FRAME_BYTES, nFrame);
|
||||
|
||||
// figure the bitrate
|
||||
int nTotalMS = int((double(m_nFinishBlock - m_nStartBlock) * double(1000)) / double(GetInfo(APE_INFO_SAMPLE_RATE)));
|
||||
if (nTotalMS != 0)
|
||||
nRetVal = (nTotalBytes * 8) / nTotalMS;
|
||||
}
|
||||
else
|
||||
{
|
||||
nRetVal = GetInfo(APE_INFO_AVERAGE_BITRATE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
bHandled = FALSE;
|
||||
}
|
||||
|
||||
if (!bHandled && m_bIsRanged)
|
||||
{
|
||||
bHandled = TRUE;
|
||||
|
||||
switch (Field)
|
||||
{
|
||||
case APE_INFO_WAV_HEADER_BYTES:
|
||||
nRetVal = sizeof(WAVE_HEADER);
|
||||
break;
|
||||
case APE_INFO_WAV_HEADER_DATA:
|
||||
{
|
||||
char * pBuffer = (char *) nParam1;
|
||||
int nMaxBytes = nParam2;
|
||||
|
||||
if (sizeof(WAVE_HEADER) > nMaxBytes)
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WAVEFORMATEX wfeFormat; GetInfo(APE_INFO_WAVEFORMATEX, (int) &wfeFormat, 0);
|
||||
WAVE_HEADER WAVHeader; FillWaveHeader(&WAVHeader,
|
||||
(m_nFinishBlock - m_nStartBlock) * GetInfo(APE_INFO_BLOCK_ALIGN),
|
||||
&wfeFormat, 0);
|
||||
memcpy(pBuffer, &WAVHeader, sizeof(WAVE_HEADER));
|
||||
nRetVal = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_WAV_TERMINATING_BYTES:
|
||||
nRetVal = 0;
|
||||
break;
|
||||
case APE_INFO_WAV_TERMINATING_DATA:
|
||||
nRetVal = 0;
|
||||
break;
|
||||
default:
|
||||
bHandled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (bHandled == FALSE)
|
||||
nRetVal = m_spAPEInfo->GetInfo(Field, nParam1, nParam2);
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
#endif // #ifdef BACKWARDS_COMPATIBILITY
|
||||
43
MAC_SDK/Source/MACLib/Old/APEDecompressOld.h
Normal file
43
MAC_SDK/Source/MACLib/Old/APEDecompressOld.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifndef _apedecompressold_h_
|
||||
#define _apedecompressold_h_
|
||||
|
||||
#include "../APEDecompress.h"
|
||||
#include "UnMAC.h"
|
||||
|
||||
class CAPEDecompressOld : public IAPEDecompress
|
||||
{
|
||||
public:
|
||||
CAPEDecompressOld(int * pErrorCode, CAPEInfo * pAPEInfo, int nStartBlock = -1, int nFinishBlock = -1);
|
||||
~CAPEDecompressOld();
|
||||
|
||||
int GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved);
|
||||
int Seek(int nBlockOffset);
|
||||
|
||||
int GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1 = 0, int nParam2 = 0);
|
||||
|
||||
protected:
|
||||
|
||||
// buffer
|
||||
CSmartPtr<char> m_spBuffer;
|
||||
int m_nBufferTail;
|
||||
|
||||
// file info
|
||||
int m_nBlockAlign;
|
||||
int m_nCurrentFrame;
|
||||
|
||||
// start / finish information
|
||||
int m_nStartBlock;
|
||||
int m_nFinishBlock;
|
||||
int m_nCurrentBlock;
|
||||
BOOL m_bIsRanged;
|
||||
|
||||
// decoding tools
|
||||
CUnMAC m_UnMAC;
|
||||
CSmartPtr<CAPEInfo> m_spAPEInfo;
|
||||
|
||||
BOOL m_bDecompressorInitialized;
|
||||
int InitializeDecompressor();
|
||||
};
|
||||
|
||||
#endif //_apedecompressold_h_
|
||||
|
||||
394
MAC_SDK/Source/MACLib/Old/Anti-Predictor.cpp
Normal file
394
MAC_SDK/Source/MACLib/Old/Anti-Predictor.cpp
Normal file
@@ -0,0 +1,394 @@
|
||||
#include "All.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
#include "../MACLib.h"
|
||||
#include "Anti-Predictor.h"
|
||||
|
||||
CAntiPredictor * CreateAntiPredictor(int nCompressionLevel, int nVersion)
|
||||
{
|
||||
CAntiPredictor *pAntiPredictor = NULL;
|
||||
|
||||
switch (nCompressionLevel)
|
||||
{
|
||||
#ifdef ENABLE_COMPRESSION_MODE_FAST
|
||||
case COMPRESSION_LEVEL_FAST:
|
||||
if (nVersion < 3320)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorFast0000To3320;
|
||||
}
|
||||
else
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorFast3320ToCurrent;
|
||||
}
|
||||
break;
|
||||
#endif //ENABLE_COMPRESSION_MODE_FAST
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_NORMAL
|
||||
|
||||
case COMPRESSION_LEVEL_NORMAL:
|
||||
if (nVersion < 3320)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorNormal0000To3320;
|
||||
}
|
||||
else if (nVersion < 3800)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorNormal3320To3800;
|
||||
}
|
||||
else
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorNormal3800ToCurrent;
|
||||
}
|
||||
break;
|
||||
|
||||
#endif //ENABLE_COMPRESSION_MODE_NORMAL
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_HIGH
|
||||
case COMPRESSION_LEVEL_HIGH:
|
||||
if (nVersion < 3320)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorHigh0000To3320;
|
||||
}
|
||||
else if (nVersion < 3600)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorHigh3320To3600;
|
||||
}
|
||||
else if (nVersion < 3700)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorHigh3600To3700;
|
||||
}
|
||||
else if (nVersion < 3800)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorHigh3700To3800;
|
||||
}
|
||||
else
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorHigh3800ToCurrent;
|
||||
}
|
||||
break;
|
||||
#endif //ENABLE_COMPRESSION_MODE_HIGH
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
case COMPRESSION_LEVEL_EXTRA_HIGH:
|
||||
if (nVersion < 3320)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorExtraHigh0000To3320;
|
||||
}
|
||||
else if (nVersion < 3600)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorExtraHigh3320To3600;
|
||||
}
|
||||
else if (nVersion < 3700)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorExtraHigh3600To3700;
|
||||
}
|
||||
else if (nVersion < 3800)
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorExtraHigh3700To3800;
|
||||
}
|
||||
else
|
||||
{
|
||||
pAntiPredictor = (CAntiPredictor *) new CAntiPredictorExtraHigh3800ToCurrent;
|
||||
}
|
||||
break;
|
||||
#endif //ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
}
|
||||
|
||||
return pAntiPredictor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
CAntiPredictor::CAntiPredictor()
|
||||
{
|
||||
}
|
||||
|
||||
CAntiPredictor::~CAntiPredictor()
|
||||
{
|
||||
}
|
||||
|
||||
void CAntiPredictor::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void CAntiPredictorOffset::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, int Offset, int DeltaM)
|
||||
{
|
||||
|
||||
memcpy(pOutputArray, pInputArray, Offset * 4);
|
||||
|
||||
int *ip = &pInputArray[Offset];
|
||||
int *ipo = &pOutputArray[0];
|
||||
int *op = &pOutputArray[Offset];
|
||||
int m = 0;
|
||||
|
||||
for (; op < &pOutputArray[NumberOfElements]; ip++, ipo++, op++)
|
||||
{
|
||||
*op = *ip + ((*ipo * m) >> 12);
|
||||
|
||||
(*ipo ^ *ip) > 0 ? m += DeltaM : m -= DeltaM;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
|
||||
int CAntiPredictorExtraHighHelper::ConventionalDotProduct(short *bip, short *bbm, short *pIPAdaptFactor, int op, int nNumberOfIterations)
|
||||
{
|
||||
// dot product
|
||||
int nDotProduct = 0;
|
||||
short *pMaxBBM = &bbm[nNumberOfIterations];
|
||||
|
||||
if (op == 0)
|
||||
{
|
||||
while(bbm < pMaxBBM)
|
||||
{
|
||||
EXPAND_32_TIMES(nDotProduct += *bip++ * *bbm++;)
|
||||
}
|
||||
}
|
||||
else if (op > 0)
|
||||
{
|
||||
while(bbm < pMaxBBM)
|
||||
{
|
||||
EXPAND_32_TIMES(nDotProduct += *bip++ * *bbm; *bbm++ += *pIPAdaptFactor++;)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while(bbm < pMaxBBM)
|
||||
{
|
||||
EXPAND_32_TIMES(nDotProduct += *bip++ * *bbm; *bbm++ -= *pIPAdaptFactor++;)
|
||||
}
|
||||
}
|
||||
|
||||
// use the dot product
|
||||
return nDotProduct;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_ASSEMBLY
|
||||
|
||||
#define MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_HEAD \
|
||||
__asm movq mm0, [esi] \
|
||||
__asm add esi, 8 \
|
||||
__asm movq mm1, [esi] \
|
||||
__asm add esi, 8 \
|
||||
__asm movq mm2, [esi] \
|
||||
__asm add esi, 8 \
|
||||
\
|
||||
__asm movq mm3, [edi] \
|
||||
__asm add edi, 8 \
|
||||
__asm movq mm4, [edi] \
|
||||
__asm add edi, 8 \
|
||||
__asm movq mm5, [edi] \
|
||||
__asm sub edi, 16 \
|
||||
\
|
||||
__asm pmaddwd mm0, mm3 \
|
||||
__asm pmaddwd mm1, mm4 \
|
||||
__asm pmaddwd mm2, mm5 \
|
||||
\
|
||||
__asm paddd mm7, mm0 \
|
||||
__asm paddd mm7, mm1 \
|
||||
__asm paddd mm7, mm2 \
|
||||
|
||||
|
||||
#define MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD \
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_HEAD \
|
||||
\
|
||||
__asm paddw mm3, DWORD PTR [eax] \
|
||||
__asm movq [edi], mm3 \
|
||||
__asm add eax, 8 \
|
||||
__asm add edi, 8 \
|
||||
__asm paddw mm4, DWORD PTR [eax] \
|
||||
__asm movq [edi], mm4 \
|
||||
__asm add eax, 8 \
|
||||
__asm add edi, 8 \
|
||||
__asm paddw mm5, DWORD PTR [eax] \
|
||||
__asm movq [edi], mm5 \
|
||||
__asm add eax, 8 \
|
||||
__asm add edi, 8
|
||||
|
||||
#define MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT \
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_HEAD \
|
||||
\
|
||||
__asm psubw mm3, DWORD PTR [eax] \
|
||||
__asm movq [edi], mm3 \
|
||||
__asm add eax, 8 \
|
||||
__asm add edi, 8 \
|
||||
__asm psubw mm4, DWORD PTR [eax] \
|
||||
__asm movq [edi], mm4 \
|
||||
__asm add eax, 8 \
|
||||
__asm add edi, 8 \
|
||||
__asm psubw mm5, DWORD PTR [eax] \
|
||||
__asm movq [edi], mm5 \
|
||||
__asm add eax, 8 \
|
||||
__asm add edi, 8
|
||||
|
||||
int CAntiPredictorExtraHighHelper::MMXDotProduct(short *bip, short *bbm, short *pIPAdaptFactor, int op, int nNumberOfIterations)
|
||||
{
|
||||
int nDotProduct;
|
||||
nNumberOfIterations = (nNumberOfIterations / 128);
|
||||
|
||||
if (op > 0)
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push eax
|
||||
|
||||
mov eax, DWORD PTR [pIPAdaptFactor]
|
||||
|
||||
push esi
|
||||
push edi
|
||||
|
||||
mov esi, DWORD PTR bip[0]
|
||||
mov edi, DWORD PTR bbm[0]
|
||||
|
||||
pxor mm7, mm7
|
||||
|
||||
LBL_ADD_AGAIN:
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// process 8 mm registers full
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_ADD
|
||||
|
||||
// fill the registers
|
||||
movq mm0, [esi]
|
||||
add esi, 8
|
||||
movq mm1, [esi]
|
||||
add esi, 8
|
||||
|
||||
movq mm3, [edi]
|
||||
add edi, 8
|
||||
movq mm4, [edi]
|
||||
sub edi, 8
|
||||
|
||||
pmaddwd mm0, mm3
|
||||
pmaddwd mm1, mm4
|
||||
|
||||
paddd mm7, mm0
|
||||
paddd mm7, mm1
|
||||
|
||||
paddw mm3, DWORD PTR [eax]
|
||||
movq [edi], mm3
|
||||
add eax, 8
|
||||
add edi, 8
|
||||
paddw mm4, DWORD PTR [eax]
|
||||
movq [edi], mm4
|
||||
add eax, 8
|
||||
add edi, 8
|
||||
|
||||
sub nNumberOfIterations, 1
|
||||
cmp nNumberOfIterations, 0
|
||||
jg LBL_ADD_AGAIN
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// clean-up
|
||||
///////////////////////////////////////////////////////////////
|
||||
// mm7 has the final dot-product (split into two dwords)
|
||||
movq mm6, mm7
|
||||
psrlq mm7, 32
|
||||
paddd mm6, mm7
|
||||
movd nDotProduct, mm6
|
||||
|
||||
pop edi
|
||||
pop esi
|
||||
pop eax
|
||||
emms
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
__asm
|
||||
{
|
||||
push eax
|
||||
|
||||
mov eax, DWORD PTR [pIPAdaptFactor]
|
||||
|
||||
push esi
|
||||
push edi
|
||||
|
||||
mov esi, DWORD PTR bip[0]
|
||||
mov edi, DWORD PTR bbm[0]
|
||||
|
||||
pxor mm7, mm7
|
||||
|
||||
LBL_SUBTRACT_AGAIN:
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
// process 8 mm registers full
|
||||
/////////////////////////////////////////////////////////
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT
|
||||
MMX_DOT_PRODUCT_3800_TO_CURRENT_PROCESS_CHUNK_SUBTRACT
|
||||
|
||||
// fill the registers
|
||||
movq mm0, [esi]
|
||||
add esi, 8
|
||||
movq mm1, [esi]
|
||||
add esi, 8
|
||||
|
||||
movq mm3, [edi]
|
||||
add edi, 8
|
||||
movq mm4, [edi]
|
||||
sub edi, 8
|
||||
|
||||
pmaddwd mm0, mm3
|
||||
pmaddwd mm1, mm4
|
||||
|
||||
paddd mm7, mm0
|
||||
paddd mm7, mm1
|
||||
|
||||
psubw mm3, DWORD PTR [eax]
|
||||
movq [edi], mm3
|
||||
add eax, 8
|
||||
add edi, 8
|
||||
psubw mm4, DWORD PTR [eax]
|
||||
movq [edi], mm4
|
||||
add eax, 8
|
||||
add edi, 8
|
||||
|
||||
sub nNumberOfIterations, 1
|
||||
cmp nNumberOfIterations, 0
|
||||
jg LBL_SUBTRACT_AGAIN
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// clean-up
|
||||
///////////////////////////////////////////////////////////////
|
||||
// mm7 has the final dot-product (split into two dwords)
|
||||
movq mm6, mm7
|
||||
psrlq mm7, 32
|
||||
paddd mm6, mm7
|
||||
movd nDotProduct, mm6
|
||||
|
||||
pop edi
|
||||
pop esi
|
||||
pop eax
|
||||
emms
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return nDotProduct;
|
||||
}
|
||||
|
||||
#endif // #ifdef ENABLE_ASSEMBLY
|
||||
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
|
||||
#endif // #ifdef BACKWARDS_COMPATIBILITY
|
||||
253
MAC_SDK/Source/MACLib/Old/Anti-Predictor.h
Normal file
253
MAC_SDK/Source/MACLib/Old/Anti-Predictor.h
Normal file
@@ -0,0 +1,253 @@
|
||||
#ifndef APE_ANTIPREDICTOR_H
|
||||
#define APE_ANTIPREDICTOR_H
|
||||
|
||||
class CAntiPredictor;
|
||||
|
||||
CAntiPredictor * CreateAntiPredictor(int nCompressionLevel, int nVersion);
|
||||
|
||||
/*****************************************************************************************
|
||||
Base class for all anti-predictors
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictor
|
||||
{
|
||||
public:
|
||||
|
||||
// construction/destruction
|
||||
CAntiPredictor();
|
||||
~CAntiPredictor();
|
||||
|
||||
// functions
|
||||
virtual void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Offset anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorOffset : public CAntiPredictor
|
||||
{
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, int Offset, int DeltaM);
|
||||
};
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_FAST
|
||||
|
||||
/*****************************************************************************************
|
||||
Fast anti-predictor (from original 'fast' mode...updated for version 3.32)
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorFast0000To3320 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Fast anti-predictor (new 'fast' mode release with version 3.32)
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorFast3320ToCurrent : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_FAST
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_NORMAL
|
||||
/*****************************************************************************************
|
||||
Normal anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorNormal0000To3320 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Normal anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorNormal3320To3800 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Normal anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorNormal3800ToCurrent : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_NORMAL
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_HIGH
|
||||
|
||||
/*****************************************************************************************
|
||||
High anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorHigh0000To3320 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
High anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorHigh3320To3600 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
High anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorHigh3600To3700 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
High anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorHigh3700To3800 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
High anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorHigh3800ToCurrent : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements);
|
||||
|
||||
};
|
||||
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_HIGH
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high helper
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorExtraHighHelper
|
||||
{
|
||||
public:
|
||||
int ConventionalDotProduct(short *bip, short *bbm, short *pIPAdaptFactor, int op, int nNumberOfIterations);
|
||||
|
||||
#ifdef ENABLE_ASSEMBLY
|
||||
int MMXDotProduct(short *bip, short *bbm, short *pIPAdaptFactor, int op, int nNumberOfIterations);
|
||||
#endif // #ifdef ENABLE_ASSEMBLY
|
||||
};
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorExtraHigh0000To3320 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, int Iterations, unsigned int *pOffsetValueArrayA, unsigned int *pOffsetValueArrayB);
|
||||
|
||||
private:
|
||||
void AntiPredictorOffset(int* Input_Array, int* Output_Array, int Number_of_Elements, int g, int dm, int Max_Order);
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorExtraHigh3320To3600 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, int Iterations, unsigned int *pOffsetValueArrayA, unsigned int *pOffsetValueArrayB);
|
||||
|
||||
private:
|
||||
void AntiPredictorOffset(int* Input_Array, int* Output_Array, int Number_of_Elements, int g, int dm, int Max_Order);
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorExtraHigh3600To3700 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, int Iterations, unsigned int *pOffsetValueArrayA, unsigned int *pOffsetValueArrayB);
|
||||
|
||||
private:
|
||||
void AntiPredictorOffset(int* Input_Array, int* Output_Array, int Number_of_Elements, int g1, int g2, int Max_Order);
|
||||
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorExtraHigh3700To3800 : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, int Iterations, unsigned int *pOffsetValueArrayA, unsigned int *pOffsetValueArrayB);
|
||||
|
||||
private:
|
||||
void AntiPredictorOffset(int* Input_Array, int* Output_Array, int Number_of_Elements, int g1, int g2, int Max_Order);
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high anti-predictor
|
||||
*****************************************************************************************/
|
||||
class CAntiPredictorExtraHigh3800ToCurrent : public CAntiPredictor {
|
||||
|
||||
public:
|
||||
|
||||
// functions
|
||||
void AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, BOOL bMMXAvailable, int CPULoadBalancingFactor, int nVersion);
|
||||
};
|
||||
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
|
||||
#endif // #ifndef APE_ANTIPREDICTOR_H
|
||||
330
MAC_SDK/Source/MACLib/Old/AntiPredictorExtraHigh.cpp
Normal file
330
MAC_SDK/Source/MACLib/Old/AntiPredictorExtraHigh.cpp
Normal file
@@ -0,0 +1,330 @@
|
||||
#include "All.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
#include "Anti-Predictor.h"
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high 0000 to 3320 implementation
|
||||
*****************************************************************************************/
|
||||
void CAntiPredictorExtraHigh0000To3320::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, int Iterations, unsigned int *pOffsetValueArrayA, unsigned int *pOffsetValueArrayB) {
|
||||
for (int z = Iterations; z >= 0; z--){
|
||||
AntiPredictorOffset(pInputArray, pOutputArray, NumberOfElements, pOffsetValueArrayB[z], -1, 64);
|
||||
AntiPredictorOffset(pOutputArray, pInputArray, NumberOfElements, pOffsetValueArrayA[z], 1, 64);
|
||||
}
|
||||
|
||||
CAntiPredictorHigh0000To3320 AntiPredictor;
|
||||
AntiPredictor.AntiPredict(pInputArray, pOutputArray, NumberOfElements);
|
||||
}
|
||||
|
||||
void CAntiPredictorExtraHigh0000To3320::AntiPredictorOffset(int* Input_Array, int* Output_Array, int Number_of_Elements, int g, int dm, int Max_Order)
|
||||
{
|
||||
int q;
|
||||
|
||||
if ((g==0) || (Number_of_Elements <= Max_Order)) {
|
||||
memcpy(Output_Array, Input_Array, Number_of_Elements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(Output_Array, Input_Array, Max_Order * 4);
|
||||
|
||||
int m = 512;
|
||||
|
||||
if (dm > 0)
|
||||
for (q = Max_Order; q < Number_of_Elements; q++) {
|
||||
Output_Array[q] = Input_Array[q] + (Output_Array[q - g] >> 3);
|
||||
}
|
||||
|
||||
else
|
||||
for (q = Max_Order; q < Number_of_Elements; q++) {
|
||||
Output_Array[q] = Input_Array[q] - (Output_Array[q - g] >> 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high 3320 to 3600 implementation
|
||||
*****************************************************************************************/
|
||||
void CAntiPredictorExtraHigh3320To3600::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, int Iterations, unsigned int *pOffsetValueArrayA, unsigned int *pOffsetValueArrayB)
|
||||
{
|
||||
for (int z = Iterations; z >= 0; z--)
|
||||
{
|
||||
AntiPredictorOffset(pInputArray, pOutputArray, NumberOfElements, pOffsetValueArrayB[z], -1, 32);
|
||||
AntiPredictorOffset(pOutputArray, pInputArray, NumberOfElements, pOffsetValueArrayA[z], 1, 32);
|
||||
}
|
||||
|
||||
CAntiPredictorHigh0000To3320 AntiPredictor;
|
||||
AntiPredictor.AntiPredict(pInputArray, pOutputArray, NumberOfElements);
|
||||
}
|
||||
|
||||
|
||||
void CAntiPredictorExtraHigh3320To3600::AntiPredictorOffset(int* Input_Array, int* Output_Array, int Number_of_Elements, int g, int dm, int Max_Order)
|
||||
{
|
||||
|
||||
int q;
|
||||
|
||||
if ((g==0) || (Number_of_Elements <= Max_Order)) {
|
||||
memcpy(Output_Array, Input_Array, Number_of_Elements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(Output_Array, Input_Array, Max_Order * 4);
|
||||
|
||||
int m = 512;
|
||||
|
||||
if (dm > 0)
|
||||
for (q = Max_Order; q < Number_of_Elements; q++) {
|
||||
Output_Array[q] = Input_Array[q] + ((Output_Array[q - g] * m) >> 12);
|
||||
(Input_Array[q] ^ Output_Array[q - g]) > 0 ? m += 8 : m -= 8;
|
||||
}
|
||||
|
||||
else
|
||||
for (q = Max_Order; q < Number_of_Elements; q++) {
|
||||
Output_Array[q] = Input_Array[q] - ((Output_Array[q - g] * m) >> 12);
|
||||
(Input_Array[q] ^ Output_Array[q - g]) > 0 ? m -= 8 : m += 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high 3600 to 3700 implementation
|
||||
*****************************************************************************************/
|
||||
void CAntiPredictorExtraHigh3600To3700::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, int Iterations, unsigned int *pOffsetValueArrayA, unsigned int *pOffsetValueArrayB) {
|
||||
for (int z = Iterations; z >= 0; ){
|
||||
|
||||
AntiPredictorOffset(pInputArray, pOutputArray, NumberOfElements, pOffsetValueArrayA[z], pOffsetValueArrayB[z], 64);
|
||||
z--;
|
||||
|
||||
if (z >= 0) {
|
||||
AntiPredictorOffset(pOutputArray, pInputArray, NumberOfElements, pOffsetValueArrayA[z], pOffsetValueArrayB[z], 64);
|
||||
z--;
|
||||
}
|
||||
else {
|
||||
memcpy(pInputArray, pOutputArray, NumberOfElements * 4);
|
||||
goto Exit_Loop;
|
||||
z--;
|
||||
}
|
||||
}
|
||||
|
||||
Exit_Loop:
|
||||
CAntiPredictorHigh3600To3700 AntiPredictor;
|
||||
AntiPredictor.AntiPredict(pInputArray, pOutputArray, NumberOfElements);
|
||||
}
|
||||
|
||||
void CAntiPredictorExtraHigh3600To3700::AntiPredictorOffset(int* Input_Array, int* Output_Array, int Number_of_Elements, int g1, int g2, int Max_Order) {
|
||||
int q;
|
||||
|
||||
if ((g1==0) || (g2==0) || (Number_of_Elements <= Max_Order)) {
|
||||
memcpy(Output_Array, Input_Array, Number_of_Elements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(Output_Array, Input_Array, Max_Order * 4);
|
||||
|
||||
int m = 64;
|
||||
int m2 = 64;
|
||||
|
||||
for (q = Max_Order; q < Number_of_Elements; q++) {
|
||||
Output_Array[q] = Input_Array[q] + ((Output_Array[q - g1] * m) >> 9) - ((Output_Array[q - g2] * m2) >> 9);
|
||||
(Input_Array[q] ^ Output_Array[q - g1]) > 0 ? m++ : m--;
|
||||
(Input_Array[q] ^ Output_Array[q - g2]) > 0 ? m2-- : m2++;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high 3700 to 3800 implementation
|
||||
*****************************************************************************************/
|
||||
void CAntiPredictorExtraHigh3700To3800::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, int Iterations, unsigned int *pOffsetValueArrayA, unsigned int *pOffsetValueArrayB) {
|
||||
for (int z = Iterations; z >= 0; ) {
|
||||
|
||||
AntiPredictorOffset(pInputArray, pOutputArray, NumberOfElements, pOffsetValueArrayA[z], pOffsetValueArrayB[z], 64);
|
||||
z--;
|
||||
|
||||
if (z >= 0) {
|
||||
AntiPredictorOffset(pOutputArray, pInputArray, NumberOfElements, pOffsetValueArrayA[z], pOffsetValueArrayB[z], 64);
|
||||
z--;
|
||||
}
|
||||
else {
|
||||
memcpy(pInputArray, pOutputArray, NumberOfElements * 4);
|
||||
goto Exit_Loop;
|
||||
z--;
|
||||
}
|
||||
}
|
||||
|
||||
Exit_Loop:
|
||||
CAntiPredictorHigh3700To3800 AntiPredictor;
|
||||
AntiPredictor.AntiPredict(pInputArray, pOutputArray, NumberOfElements);
|
||||
|
||||
}
|
||||
|
||||
void CAntiPredictorExtraHigh3700To3800::AntiPredictorOffset(int* Input_Array, int* Output_Array, int Number_of_Elements, int g1, int g2, int Max_Order) {
|
||||
int q;
|
||||
|
||||
if ((g1==0) || (g2==0) || (Number_of_Elements <= Max_Order)) {
|
||||
memcpy(Output_Array, Input_Array, Number_of_Elements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(Output_Array, Input_Array, Max_Order * 4);
|
||||
|
||||
int m = 64;
|
||||
int m2 = 64;
|
||||
|
||||
for (q = Max_Order; q < Number_of_Elements; q++) {
|
||||
Output_Array[q] = Input_Array[q] + ((Output_Array[q - g1] * m) >> 9) - ((Output_Array[q - g2] * m2) >> 9);
|
||||
(Input_Array[q] ^ Output_Array[q - g1]) > 0 ? m++ : m--;
|
||||
(Input_Array[q] ^ Output_Array[q - g2]) > 0 ? m2-- : m2++;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Extra high 3800 to Current
|
||||
*****************************************************************************************/
|
||||
void CAntiPredictorExtraHigh3800ToCurrent::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements, BOOL bMMXAvailable, int CPULoadBalancingFactor, int nVersion)
|
||||
{
|
||||
const int nFilterStageElements = (nVersion < 3830) ? 128 : 256;
|
||||
const int nFilterStageShift = (nVersion < 3830) ? 11 : 12;
|
||||
const int nMaxElements = (nVersion < 3830) ? 134 : 262;
|
||||
const int nFirstElement = (nVersion < 3830) ? 128 : 256;
|
||||
const int nStageCShift = (nVersion < 3830) ? 10 : 11;
|
||||
|
||||
//short frame handling
|
||||
if (NumberOfElements < nMaxElements) {
|
||||
memcpy(pOutputArray, pInputArray, NumberOfElements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
//make the first five samples identical in both arrays
|
||||
memcpy(pOutputArray, pInputArray, nFirstElement * 4);
|
||||
|
||||
//variable declares and initializations
|
||||
//short bm[nFirstElement]; memset(bm, 0, nFirstElement * 2);
|
||||
short bm[256]; memset(bm, 0, 256 * 2);
|
||||
int m2 = 64, m3 = 115, m4 = 64, m5 = 740, m6 = 0;
|
||||
int p4 = pInputArray[nFirstElement - 1];
|
||||
int p3 = (pInputArray[nFirstElement - 1] - pInputArray[nFirstElement - 2]) << 1;
|
||||
int p2 = pInputArray[nFirstElement - 1] + ((pInputArray[nFirstElement - 3] - pInputArray[nFirstElement - 2]) << 3);// - pInputArray[3] + pInputArray[2];
|
||||
int *op = &pOutputArray[nFirstElement];
|
||||
int *ip = &pInputArray[nFirstElement];
|
||||
int IPP2 = ip[-2];
|
||||
int IPP1 = ip[-1];
|
||||
int p7 = 2 * ip[-1] - ip[-2];
|
||||
int opp = op[-1];
|
||||
int Original;
|
||||
CAntiPredictorExtraHighHelper Helper;
|
||||
|
||||
//undo the initial prediction stuff
|
||||
int q; // loop variable
|
||||
for (q = 1; q < nFirstElement; q++) {
|
||||
pOutputArray[q] += pOutputArray[q - 1];
|
||||
}
|
||||
|
||||
//pump the primary loop
|
||||
short *IPAdaptFactor = (short *) calloc(NumberOfElements, 2);
|
||||
short *IPShort = (short *) calloc(NumberOfElements, 2);
|
||||
for (q = 0; q < nFirstElement; q++) {
|
||||
IPAdaptFactor[q] = ((pInputArray[q] >> 30) & 2) - 1;
|
||||
IPShort[q] = short(pInputArray[q]);
|
||||
}
|
||||
|
||||
int FM[9]; memset(&FM[0], 0, 9 * 4);
|
||||
int FP[9]; memset(&FP[0], 0, 9 * 4);
|
||||
|
||||
for (q = nFirstElement; op < &pOutputArray[NumberOfElements]; op++, ip++, q++) {
|
||||
//CPU load-balancing
|
||||
if (CPULoadBalancingFactor > 0) {
|
||||
if ((q % CPULoadBalancingFactor) == 0) { SLEEP(1); }
|
||||
}
|
||||
|
||||
if (nVersion >= 3830)
|
||||
{
|
||||
int *pFP = &FP[8];
|
||||
int *pFM = &FM[8];
|
||||
int nDotProduct = 0;
|
||||
FP[0] = ip[0];
|
||||
|
||||
if (FP[0] == 0)
|
||||
{
|
||||
EXPAND_8_TIMES(nDotProduct += *pFP * *pFM--; *pFP-- = *(pFP - 1);)
|
||||
}
|
||||
else if (FP[0] > 0)
|
||||
{
|
||||
EXPAND_8_TIMES(nDotProduct += *pFP * *pFM; *pFM-- += ((*pFP >> 30) & 2) - 1; *pFP-- = *(pFP - 1);)
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPAND_8_TIMES(nDotProduct += *pFP * *pFM; *pFM-- -= ((*pFP >> 30) & 2) - 1; *pFP-- = *(pFP - 1);)
|
||||
}
|
||||
|
||||
*ip -= nDotProduct >> 9;
|
||||
}
|
||||
|
||||
Original = *ip;
|
||||
|
||||
IPShort[q] = short(*ip);
|
||||
IPAdaptFactor[q] = ((ip[0] >> 30) & 2) - 1;
|
||||
|
||||
#ifdef ENABLE_ASSEMBLY
|
||||
if (bMMXAvailable && (Original != 0))
|
||||
{
|
||||
*ip -= (Helper.MMXDotProduct(&IPShort[q-nFirstElement], &bm[0], &IPAdaptFactor[q-nFirstElement], Original, nFilterStageElements) >> nFilterStageShift);
|
||||
}
|
||||
else
|
||||
{
|
||||
*ip -= (Helper.ConventionalDotProduct(&IPShort[q-nFirstElement], &bm[0], &IPAdaptFactor[q-nFirstElement], Original, nFilterStageElements) >> nFilterStageShift);
|
||||
}
|
||||
#else
|
||||
*ip -= (Helper.ConventionalDotProduct(&IPShort[q-nFirstElement], &bm[0], &IPAdaptFactor[q-nFirstElement], Original, nFilterStageElements) >> nFilterStageShift);
|
||||
#endif
|
||||
|
||||
IPShort[q] = short(*ip);
|
||||
IPAdaptFactor[q] = ((ip[0] >> 30) & 2) - 1;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
*op = *ip + (((p2 * m2) + (p3 * m3) + (p4 * m4)) >> 11);
|
||||
|
||||
if (*ip > 0) {
|
||||
m2 -= ((p2 >> 30) & 2) - 1;
|
||||
m3 -= ((p3 >> 28) & 8) - 4;
|
||||
m4 -= ((p4 >> 28) & 8) - 4;
|
||||
}
|
||||
else if (*ip < 0) {
|
||||
m2 += ((p2 >> 30) & 2) - 1;
|
||||
m3 += ((p3 >> 28) & 8) - 4;
|
||||
m4 += ((p4 >> 28) & 8) - 4;
|
||||
}
|
||||
|
||||
|
||||
p2 = *op + ((IPP2 - p4) << 3);
|
||||
p3 = (*op - p4) << 1;
|
||||
IPP2 = p4;
|
||||
p4 = *op;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
*op += (((p7 * m5) - (opp * m6)) >> nStageCShift);
|
||||
|
||||
if (p4 > 0) {
|
||||
m5 -= ((p7 >> 29) & 4) - 2;
|
||||
m6 += ((opp >> 30) & 2) - 1;
|
||||
}
|
||||
else if (p4 < 0) {
|
||||
m5 += ((p7 >> 29) & 4) - 2;
|
||||
m6 -= ((opp >> 30) & 2) - 1;
|
||||
}
|
||||
|
||||
p7 = 2 * *op - opp;
|
||||
opp = *op;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
*op += ((op[-1] * 31) >> 5);
|
||||
|
||||
}
|
||||
|
||||
free(IPAdaptFactor);
|
||||
free(IPShort);
|
||||
}
|
||||
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
|
||||
#endif // #ifdef BACKWARDS_COMPATIBILITY
|
||||
88
MAC_SDK/Source/MACLib/Old/AntiPredictorFast.cpp
Normal file
88
MAC_SDK/Source/MACLib/Old/AntiPredictorFast.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
#include "All.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
#include "Anti-Predictor.h"
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_FAST
|
||||
|
||||
void CAntiPredictorFast0000To3320::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements) {
|
||||
|
||||
//short frame handling
|
||||
if (NumberOfElements < 32) {
|
||||
memcpy(pOutputArray, pInputArray, NumberOfElements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
//the initial
|
||||
pOutputArray[0] = pInputArray[0];
|
||||
pOutputArray[1] = pInputArray[1] + pOutputArray[0];
|
||||
pOutputArray[2] = pInputArray[2] + pOutputArray[1];
|
||||
pOutputArray[3] = pInputArray[3] + pOutputArray[2];
|
||||
pOutputArray[4] = pInputArray[4] + pOutputArray[3];
|
||||
pOutputArray[5] = pInputArray[5] + pOutputArray[4];
|
||||
pOutputArray[6] = pInputArray[6] + pOutputArray[5];
|
||||
pOutputArray[7] = pInputArray[7] + pOutputArray[6];
|
||||
|
||||
//the rest
|
||||
int p, pw;
|
||||
int m = 4000;
|
||||
int *ip, *op, *op1;
|
||||
|
||||
op1 = &pOutputArray[7];
|
||||
p = (*op1 * 2) - pOutputArray[6];
|
||||
pw = (p * m) >> 12;
|
||||
|
||||
for (op = &pOutputArray[8], ip = &pInputArray[8]; ip < &pInputArray[NumberOfElements]; ip++, op++, op1++) {
|
||||
*op = *ip + pw;
|
||||
|
||||
|
||||
//adjust m
|
||||
if (*ip > 0)
|
||||
m += (p > 0) ? 4 : -4;
|
||||
else if (*ip < 0)
|
||||
m += (p > 0) ? -4 : 4;
|
||||
|
||||
p = (*op * 2) - *op1;
|
||||
pw = (p * m) >> 12;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///////note: no output - overwrites input/////////////////
|
||||
void CAntiPredictorFast3320ToCurrent::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements) {
|
||||
|
||||
//short frame handling
|
||||
if (NumberOfElements < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
//variable declares
|
||||
int p;
|
||||
int m = 375;
|
||||
int *ip;
|
||||
int IP2 = pInputArray[1];
|
||||
int IP3 = pInputArray[0];
|
||||
int OP1 = pInputArray[1];
|
||||
|
||||
//the decompression loop (order 2 followed by order 1)
|
||||
for (ip = &pInputArray[2]; ip < &pInputArray[NumberOfElements]; ip++) {
|
||||
|
||||
//make a prediction for order 2
|
||||
p = IP2 + IP2 - IP3;
|
||||
|
||||
//rollback the values
|
||||
IP3 = IP2;
|
||||
IP2 = *ip + ((p * m) >> 9);
|
||||
|
||||
//adjust m for the order 2
|
||||
(*ip ^ p) > 0 ? m++ : m--;
|
||||
|
||||
//set the output value
|
||||
*ip = IP2 + OP1;
|
||||
OP1 = *ip;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_FAST
|
||||
|
||||
#endif // #ifdef BACKWARDS_COMPATIBILITY
|
||||
484
MAC_SDK/Source/MACLib/Old/AntiPredictorHigh.cpp
Normal file
484
MAC_SDK/Source/MACLib/Old/AntiPredictorHigh.cpp
Normal file
@@ -0,0 +1,484 @@
|
||||
#include "All.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
#include "Anti-Predictor.h"
|
||||
|
||||
#ifdef ENABLE_COMPRESSION_MODE_HIGH
|
||||
|
||||
void CAntiPredictorHigh0000To3320::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements)
|
||||
{
|
||||
// variable declares
|
||||
int p, pw;
|
||||
int q;
|
||||
int m;
|
||||
|
||||
// short frame handling
|
||||
if (NumberOfElements < 32)
|
||||
{
|
||||
memcpy(pOutputArray, pInputArray, NumberOfElements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// order 5
|
||||
////////////////////////////////////////
|
||||
memcpy(pOutputArray, pInputArray, 32);
|
||||
|
||||
// initialize values
|
||||
m = 0;
|
||||
|
||||
for (q = 8; q < NumberOfElements; q++)
|
||||
{
|
||||
p = (5 * pOutputArray[q - 1]) - (10 * pOutputArray[q - 2]) + (12 * pOutputArray[q - 3]) - (7 * pOutputArray[q - 4]) + pOutputArray[q - 5];
|
||||
|
||||
pw = (p * m) >> 12;
|
||||
|
||||
pOutputArray[q] = pInputArray[q] + pw;
|
||||
|
||||
// adjust m
|
||||
if (pInputArray[q] > 0)
|
||||
(p > 0) ? m += 1 : m -= 1;
|
||||
else if (pInputArray[q] < 0)
|
||||
(p > 0) ? m -= 1 : m += 1;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// order 4
|
||||
///////////////////////////////////////
|
||||
memcpy(pInputArray, pOutputArray, 32);
|
||||
m = 0;
|
||||
|
||||
for (q = 8; q < NumberOfElements; q++)
|
||||
{
|
||||
p = (4 * pInputArray[q - 1]) - (6 * pInputArray[q - 2]) + (4 * pInputArray[q - 3]) - pInputArray[q - 4];
|
||||
pw = (p * m) >> 12;
|
||||
|
||||
pInputArray[q] = pOutputArray[q] + pw;
|
||||
|
||||
// adjust m
|
||||
if (pOutputArray[q] > 0)
|
||||
(p > 0) ? m += 2 : m -= 2;
|
||||
else if (pOutputArray[q] < 0)
|
||||
(p > 0) ? m -= 2 : m += 2;
|
||||
}
|
||||
|
||||
CAntiPredictorNormal0000To3320 AntiPredictor;
|
||||
AntiPredictor.AntiPredict(pInputArray, pOutputArray, NumberOfElements);
|
||||
}
|
||||
|
||||
void CAntiPredictorHigh3320To3600::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements)
|
||||
{
|
||||
// short frame handling
|
||||
if (NumberOfElements < 8)
|
||||
{
|
||||
memcpy(pOutputArray, pInputArray, NumberOfElements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
// do the offset anti-prediction
|
||||
CAntiPredictorOffset AntiPredictorOffset;
|
||||
AntiPredictorOffset.AntiPredict(pInputArray, pOutputArray, NumberOfElements, 2, 12);
|
||||
AntiPredictorOffset.AntiPredict(pOutputArray, pInputArray, NumberOfElements, 3, 12);
|
||||
|
||||
AntiPredictorOffset.AntiPredict(pInputArray, pOutputArray, NumberOfElements, 4, 12);
|
||||
AntiPredictorOffset.AntiPredict(pOutputArray, pInputArray, NumberOfElements, 5, 12);
|
||||
|
||||
AntiPredictorOffset.AntiPredict(pInputArray, pOutputArray, NumberOfElements, 6, 12);
|
||||
AntiPredictorOffset.AntiPredict(pOutputArray, pInputArray, NumberOfElements, 7, 12);
|
||||
|
||||
// use the normal mode
|
||||
CAntiPredictorNormal3320To3800 AntiPredictor;
|
||||
AntiPredictor.AntiPredict(pInputArray, pOutputArray, NumberOfElements);
|
||||
}
|
||||
|
||||
void CAntiPredictorHigh3600To3700::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements)
|
||||
{
|
||||
// variable declares
|
||||
int q;
|
||||
|
||||
// short frame handling
|
||||
if (NumberOfElements < 16)
|
||||
{
|
||||
memcpy(pOutputArray, pInputArray, NumberOfElements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
// make the first five samples identical in both arrays
|
||||
memcpy(pOutputArray, pInputArray, 13 * 4);
|
||||
|
||||
// initialize values
|
||||
int bm1 = 0;
|
||||
int bm2 = 0;
|
||||
int bm3 = 0;
|
||||
int bm4 = 0;
|
||||
int bm5 = 0;
|
||||
int bm6 = 0;
|
||||
int bm7 = 0;
|
||||
int bm8 = 0;
|
||||
int bm9 = 0;
|
||||
int bm10 = 0;
|
||||
int bm11 = 0;
|
||||
int bm12 = 0;
|
||||
int bm13 = 0;
|
||||
|
||||
int m2 = 64;
|
||||
|
||||
int m3 = 28;
|
||||
int m4 = 16;
|
||||
int OP0;
|
||||
int OP1 = pOutputArray[12];
|
||||
int p4 = pInputArray[12];
|
||||
int p3 = (pInputArray[12] - pInputArray[11]) << 1;
|
||||
int p2 = pInputArray[12] + ((pInputArray[10] - pInputArray[11]) << 3);// - pInputArray[3] + pInputArray[2];
|
||||
int bp1 = pOutputArray[12];
|
||||
int bp2 = pOutputArray[11];
|
||||
int bp3 = pOutputArray[10];
|
||||
int bp4 = pOutputArray[9];
|
||||
int bp5 = pOutputArray[8];
|
||||
int bp6 = pOutputArray[7];
|
||||
int bp7 = pOutputArray[6];
|
||||
int bp8 = pOutputArray[5];
|
||||
int bp9 = pOutputArray[4];
|
||||
int bp10 = pOutputArray[3];
|
||||
int bp11 = pOutputArray[2];
|
||||
int bp12 = pOutputArray[1];
|
||||
int bp13 = pOutputArray[0];
|
||||
|
||||
for (q = 13; q < NumberOfElements; q++)
|
||||
{
|
||||
pInputArray[q] = pInputArray[q] - 1;
|
||||
OP0 = (pInputArray[q] - ((bp1 * bm1) >> 8) + ((bp2 * bm2) >> 8) - ((bp3 * bm3) >> 8) - ((bp4 * bm4) >> 8) - ((bp5 * bm5) >> 8) - ((bp6 * bm6) >> 8) - ((bp7 * bm7) >> 8) - ((bp8 * bm8) >> 8) - ((bp9 * bm9) >> 8) + ((bp10 * bm10) >> 8) + ((bp11 * bm11) >> 8) + ((bp12 * bm12) >> 8) + ((bp13 * bm13) >> 8));
|
||||
|
||||
if (pInputArray[q] > 0)
|
||||
{
|
||||
bm1 -= bp1 > 0 ? 1 : -1;
|
||||
bm2 += bp2 >= 0 ? 1 : -1;
|
||||
bm3 -= bp3 > 0 ? 1 : -1;
|
||||
bm4 -= bp4 >= 0 ? 1 : -1;
|
||||
bm5 -= bp5 > 0 ? 1 : -1;
|
||||
bm6 -= bp6 >= 0 ? 1 : -1;
|
||||
bm7 -= bp7 > 0 ? 1 : -1;
|
||||
bm8 -= bp8 >= 0 ? 1 : -1;
|
||||
bm9 -= bp9 > 0 ? 1 : -1;
|
||||
bm10 += bp10 >= 0 ? 1 : -1;
|
||||
bm11 += bp11 > 0 ? 1 : -1;
|
||||
bm12 += bp12 >= 0 ? 1 : -1;
|
||||
bm13 += bp13 > 0 ? 1 : -1;
|
||||
}
|
||||
else if (pInputArray[q] < 0)
|
||||
{
|
||||
bm1 -= bp1 <= 0 ? 1 : -1;
|
||||
bm2 += bp2 < 0 ? 1 : -1;
|
||||
bm3 -= bp3 <= 0 ? 1 : -1;
|
||||
bm4 -= bp4 < 0 ? 1 : -1;
|
||||
bm5 -= bp5 <= 0 ? 1 : -1;
|
||||
bm6 -= bp6 < 0 ? 1 : -1;
|
||||
bm7 -= bp7 <= 0 ? 1 : -1;
|
||||
bm8 -= bp8 < 0 ? 1 : -1;
|
||||
bm9 -= bp9 <= 0 ? 1 : -1;
|
||||
bm10 += bp10 < 0 ? 1 : -1;
|
||||
bm11 += bp11 <= 0 ? 1 : -1;
|
||||
bm12 += bp12 < 0 ? 1 : -1;
|
||||
bm13 += bp13 <= 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
bp13 = bp12;
|
||||
bp12 = bp11;
|
||||
bp11 = bp10;
|
||||
bp10 = bp9;
|
||||
bp9 = bp8;
|
||||
bp8 = bp7;
|
||||
bp7 = bp6;
|
||||
bp6 = bp5;
|
||||
bp5 = bp4;
|
||||
bp4 = bp3;
|
||||
bp3 = bp2;
|
||||
bp2 = bp1;
|
||||
bp1 = OP0;
|
||||
|
||||
pInputArray[q] = OP0 + ((p2 * m2) >> 11) + ((p3 * m3) >> 9) + ((p4 * m4) >> 9);
|
||||
|
||||
if (OP0 > 0)
|
||||
{
|
||||
m2 -= p2 > 0 ? -1 : 1;
|
||||
m3 -= p3 > 0 ? -1 : 1;
|
||||
m4 -= p4 > 0 ? -1 : 1;
|
||||
}
|
||||
else if (OP0 < 0)
|
||||
{
|
||||
m2 -= p2 > 0 ? 1 : -1;
|
||||
m3 -= p3 > 0 ? 1 : -1;
|
||||
m4 -= p4 > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
p2 = pInputArray[q] + ((pInputArray[q - 2] - pInputArray[q - 1]) << 3);
|
||||
p3 = (pInputArray[q] - pInputArray[q - 1]) << 1;
|
||||
p4 = pInputArray[q];
|
||||
pOutputArray[q] = pInputArray[q];// + ((p3 * m3) >> 9);
|
||||
}
|
||||
|
||||
m4 = 370;
|
||||
int m5 = 3900;
|
||||
|
||||
pOutputArray[1] = pInputArray[1] + pOutputArray[0];
|
||||
pOutputArray[2] = pInputArray[2] + pOutputArray[1];
|
||||
pOutputArray[3] = pInputArray[3] + pOutputArray[2];
|
||||
pOutputArray[4] = pInputArray[4] + pOutputArray[3];
|
||||
pOutputArray[5] = pInputArray[5] + pOutputArray[4];
|
||||
pOutputArray[6] = pInputArray[6] + pOutputArray[5];
|
||||
pOutputArray[7] = pInputArray[7] + pOutputArray[6];
|
||||
pOutputArray[8] = pInputArray[8] + pOutputArray[7];
|
||||
pOutputArray[9] = pInputArray[9] + pOutputArray[8];
|
||||
pOutputArray[10] = pInputArray[10] + pOutputArray[9];
|
||||
pOutputArray[11] = pInputArray[11] + pOutputArray[10];
|
||||
pOutputArray[12] = pInputArray[12] + pOutputArray[11];
|
||||
|
||||
p4 = (2 * pInputArray[12]) - pInputArray[11];
|
||||
int p6 = 0;
|
||||
int p5 = pOutputArray[12];
|
||||
int IP0, IP1;
|
||||
int m6 = 0;
|
||||
|
||||
IP1 = pInputArray[12];
|
||||
for (q = 13; q < NumberOfElements; q++)
|
||||
{
|
||||
IP0 = pOutputArray[q] + ((p4 * m4) >> 9) - ((p6 * m6) >> 10);
|
||||
(pOutputArray[q] ^ p4) >= 0 ? m4++ : m4--;
|
||||
(pOutputArray[q] ^ p6) >= 0 ? m6-- : m6++;
|
||||
p4 = (2 * IP0) - IP1;
|
||||
p6 = IP0;
|
||||
|
||||
pOutputArray[q] = IP0 + ((p5 * 31) >> 5);
|
||||
p5 = pOutputArray[q];
|
||||
|
||||
IP1 = IP0;
|
||||
}
|
||||
}
|
||||
|
||||
void CAntiPredictorHigh3700To3800::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements)
|
||||
{
|
||||
// the frame to start prediction on
|
||||
#define FIRST_ELEMENT 16
|
||||
|
||||
int x = 100;
|
||||
int y = -25;
|
||||
|
||||
// short frame handling
|
||||
if (NumberOfElements < 20)
|
||||
{
|
||||
memcpy(pOutputArray, pInputArray, NumberOfElements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
// make the first five samples identical in both arrays
|
||||
memcpy(pOutputArray, pInputArray, FIRST_ELEMENT * 4);
|
||||
|
||||
// variable declares and initializations
|
||||
int bm[FIRST_ELEMENT]; memset(bm, 0, FIRST_ELEMENT * 4);
|
||||
int m2 = 64, m3 = 115, m4 = 64, m5 = 740, m6 = 0;
|
||||
int p4 = pInputArray[FIRST_ELEMENT - 1];
|
||||
int p3 = (pInputArray[FIRST_ELEMENT - 1] - pInputArray[FIRST_ELEMENT - 2]) << 1;
|
||||
int p2 = pInputArray[FIRST_ELEMENT - 1] + ((pInputArray[FIRST_ELEMENT - 3] - pInputArray[FIRST_ELEMENT - 2]) << 3);// - pInputArray[3] + pInputArray[2];
|
||||
int *op = &pOutputArray[FIRST_ELEMENT];
|
||||
int *ip = &pInputArray[FIRST_ELEMENT];
|
||||
int IPP2 = ip[-2];
|
||||
int IPP1 = ip[-1];
|
||||
int p7 = 2 * ip[-1] - ip[-2];
|
||||
int opp = op[-1];
|
||||
int Original;
|
||||
|
||||
// undo the initial prediction stuff
|
||||
for (int q = 1; q < FIRST_ELEMENT; q++) {
|
||||
pOutputArray[q] += pOutputArray[q - 1];
|
||||
}
|
||||
|
||||
// pump the primary loop
|
||||
for (;op < &pOutputArray[NumberOfElements]; op++, ip++) {
|
||||
|
||||
Original = *ip - 1;
|
||||
*ip = Original - (((ip[-1] * bm[0]) + (ip[-2] * bm[1]) + (ip[-3] * bm[2]) + (ip[-4] * bm[3]) + (ip[-5] * bm[4]) + (ip[-6] * bm[5]) + (ip[-7] * bm[6]) + (ip[-8] * bm[7]) + (ip[-9] * bm[8]) + (ip[-10] * bm[9]) + (ip[-11] * bm[10]) + (ip[-12] * bm[11]) + (ip[-13] * bm[12]) + (ip[-14] * bm[13]) + (ip[-15] * bm[14]) + (ip[-16] * bm[15])) >> 8);
|
||||
|
||||
if (Original > 0)
|
||||
{
|
||||
bm[0] -= ip[-1] > 0 ? 1 : -1;
|
||||
bm[1] += ((unsigned int(ip[-2]) >> 30) & 2) - 1;
|
||||
bm[2] -= ip[-3] > 0 ? 1 : -1;
|
||||
bm[3] += ((unsigned int(ip[-4]) >> 30) & 2) - 1;
|
||||
bm[4] -= ip[-5] > 0 ? 1 : -1;
|
||||
bm[5] += ((unsigned int(ip[-6]) >> 30) & 2) - 1;
|
||||
bm[6] -= ip[-7] > 0 ? 1 : -1;
|
||||
bm[7] += ((unsigned int(ip[-8]) >> 30) & 2) - 1;
|
||||
bm[8] -= ip[-9] > 0 ? 1 : -1;
|
||||
bm[9] += ((unsigned int(ip[-10]) >> 30) & 2) - 1;
|
||||
bm[10] -= ip[-11] > 0 ? 1 : -1;
|
||||
bm[11] += ((unsigned int(ip[-12]) >> 30) & 2) - 1;
|
||||
bm[12] -= ip[-13] > 0 ? 1 : -1;
|
||||
bm[13] += ((unsigned int(ip[-14]) >> 30) & 2) - 1;
|
||||
bm[14] -= ip[-15] > 0 ? 1 : -1;
|
||||
bm[15] += ((unsigned int(ip[-16]) >> 30) & 2) - 1;
|
||||
}
|
||||
else if (Original < 0)
|
||||
{
|
||||
bm[0] -= ip[-1] <= 0 ? 1 : -1;
|
||||
bm[1] -= ((unsigned int(ip[-2]) >> 30) & 2) - 1;
|
||||
bm[2] -= ip[-3] <= 0 ? 1 : -1;
|
||||
bm[3] -= ((unsigned int(ip[-4]) >> 30) & 2) - 1;
|
||||
bm[4] -= ip[-5] <= 0 ? 1 : -1;
|
||||
bm[5] -= ((unsigned int(ip[-6]) >> 30) & 2) - 1;
|
||||
bm[6] -= ip[-7] <= 0 ? 1 : -1;
|
||||
bm[7] -= ((unsigned int(ip[-8]) >> 30) & 2) - 1;
|
||||
bm[8] -= ip[-9] <= 0 ? 1 : -1;
|
||||
bm[9] -= ((unsigned int(ip[-10]) >> 30) & 2) - 1;
|
||||
bm[10] -= ip[-11] <= 0 ? 1 : -1;
|
||||
bm[11] -= ((unsigned int(ip[-12]) >> 30) & 2) - 1;
|
||||
bm[12] -= ip[-13] <= 0 ? 1 : -1;
|
||||
bm[13] -= ((unsigned int(ip[-14]) >> 30) & 2) - 1;
|
||||
bm[14] -= ip[-15] <= 0 ? 1 : -1;
|
||||
bm[15] -= ((unsigned int(ip[-16]) >> 30) & 2) - 1;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
*op = *ip + (((p2 * m2) + (p3 * m3) + (p4 * m4)) >> 11);
|
||||
|
||||
if (*ip > 0)
|
||||
{
|
||||
m2 -= p2 > 0 ? -1 : 1;
|
||||
m3 -= p3 > 0 ? -4 : 4;
|
||||
m4 -= p4 > 0 ? -4 : 4;
|
||||
}
|
||||
else if (*ip < 0)
|
||||
{
|
||||
m2 -= p2 > 0 ? 1 : -1;
|
||||
m3 -= p3 > 0 ? 4 : -4;
|
||||
m4 -= p4 > 0 ? 4 : -4;
|
||||
}
|
||||
|
||||
p4 = *op;
|
||||
p2 = p4 + ((IPP2 - IPP1) << 3);
|
||||
p3 = (p4 - IPP1) << 1;
|
||||
|
||||
IPP2 = IPP1;
|
||||
IPP1 = p4;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
*op += (((p7 * m5) - (opp * m6)) >> 10);
|
||||
|
||||
(IPP1 ^ p7) >= 0 ? m5+=2 : m5-=2;
|
||||
(IPP1 ^ opp) >= 0 ? m6-- : m6++;
|
||||
|
||||
p7 = 2 * *op - opp;
|
||||
opp = *op;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
*op += ((op[-1] * 31) >> 5);
|
||||
}
|
||||
}
|
||||
|
||||
void CAntiPredictorHigh3800ToCurrent::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements)
|
||||
{
|
||||
// the frame to start prediction on
|
||||
#define FIRST_ELEMENT 16
|
||||
|
||||
// short frame handling
|
||||
if (NumberOfElements < 20)
|
||||
{
|
||||
memcpy(pOutputArray, pInputArray, NumberOfElements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
// make the first five samples identical in both arrays
|
||||
memcpy(pOutputArray, pInputArray, FIRST_ELEMENT * 4);
|
||||
|
||||
// variable declares and initializations
|
||||
int bm[FIRST_ELEMENT]; memset(bm, 0, FIRST_ELEMENT * 4);
|
||||
int m2 = 64, m3 = 115, m4 = 64, m5 = 740, m6 = 0;
|
||||
int p4 = pInputArray[FIRST_ELEMENT - 1];
|
||||
int p3 = (pInputArray[FIRST_ELEMENT - 1] - pInputArray[FIRST_ELEMENT - 2]) << 1;
|
||||
int p2 = pInputArray[FIRST_ELEMENT - 1] + ((pInputArray[FIRST_ELEMENT - 3] - pInputArray[FIRST_ELEMENT - 2]) << 3);// - pInputArray[3] + pInputArray[2];
|
||||
int *op = &pOutputArray[FIRST_ELEMENT];
|
||||
int *ip = &pInputArray[FIRST_ELEMENT];
|
||||
int IPP2 = ip[-2];
|
||||
int IPP1 = ip[-1];
|
||||
int p7 = 2 * ip[-1] - ip[-2];
|
||||
int opp = op[-1];
|
||||
|
||||
// undo the initial prediction stuff
|
||||
for (int q = 1; q < FIRST_ELEMENT; q++)
|
||||
{
|
||||
pOutputArray[q] += pOutputArray[q - 1];
|
||||
}
|
||||
|
||||
// pump the primary loop
|
||||
for (;op < &pOutputArray[NumberOfElements]; op++, ip++)
|
||||
{
|
||||
|
||||
unsigned int *pip = (unsigned int *) &ip[-FIRST_ELEMENT];
|
||||
int *pbm = &bm[0];
|
||||
int nDotProduct = 0;
|
||||
|
||||
if (*ip > 0)
|
||||
{
|
||||
EXPAND_16_TIMES(nDotProduct += *pip * *pbm; *pbm++ += ((*pip++ >> 30) & 2) - 1;)
|
||||
}
|
||||
else if (*ip < 0)
|
||||
{
|
||||
EXPAND_16_TIMES(nDotProduct += *pip * *pbm; *pbm++ -= ((*pip++ >> 30) & 2) - 1;)
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPAND_16_TIMES(nDotProduct += *pip++ * *pbm++;)
|
||||
}
|
||||
|
||||
*ip -= (nDotProduct >> 9);
|
||||
|
||||
/////////////////////////////////////////////
|
||||
*op = *ip + (((p2 * m2) + (p3 * m3) + (p4 * m4)) >> 11);
|
||||
|
||||
if (*ip > 0)
|
||||
{
|
||||
m2 -= ((p2 >> 30) & 2) - 1;
|
||||
m3 -= ((p3 >> 28) & 8) - 4;
|
||||
m4 -= ((p4 >> 28) & 8) - 4;
|
||||
|
||||
}
|
||||
else if (*ip < 0)
|
||||
{
|
||||
m2 += ((p2 >> 30) & 2) - 1;
|
||||
m3 += ((p3 >> 28) & 8) - 4;
|
||||
m4 += ((p4 >> 28) & 8) - 4;
|
||||
}
|
||||
|
||||
|
||||
p2 = *op + ((IPP2 - p4) << 3);
|
||||
p3 = (*op - p4) << 1;
|
||||
IPP2 = p4;
|
||||
p4 = *op;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
*op += (((p7 * m5) - (opp * m6)) >> 10);
|
||||
|
||||
if (p4 > 0)
|
||||
{
|
||||
m5 -= ((p7 >> 29) & 4) - 2;
|
||||
m6 += ((opp >> 30) & 2) - 1;
|
||||
}
|
||||
else if (p4 < 0)
|
||||
{
|
||||
m5 += ((p7 >> 29) & 4) - 2;
|
||||
m6 -= ((opp >> 30) & 2) - 1;
|
||||
}
|
||||
|
||||
p7 = 2 * *op - opp;
|
||||
opp = *op;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
*op += ((op[-1] * 31) >> 5);
|
||||
}
|
||||
|
||||
#undef FIRST_ELEMENT
|
||||
}
|
||||
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_HIGH
|
||||
|
||||
#endif // #ifdef BACKWARDS_COMPATIBILITY
|
||||
262
MAC_SDK/Source/MACLib/Old/AntiPredictorNormal.cpp
Normal file
262
MAC_SDK/Source/MACLib/Old/AntiPredictorNormal.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
#include "All.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
#include "Anti-Predictor.h"
|
||||
#ifdef ENABLE_COMPRESSION_MODE_NORMAL
|
||||
|
||||
void CAntiPredictorNormal0000To3320::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements)
|
||||
{
|
||||
// variable declares
|
||||
int *ip, *op, *op1, *op2;
|
||||
int p, pw;
|
||||
int m;
|
||||
|
||||
// short frame handling
|
||||
if (NumberOfElements < 32)
|
||||
{
|
||||
memcpy(pOutputArray, pInputArray, NumberOfElements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
// order 3
|
||||
////////////////////////////////////////
|
||||
memcpy(pOutputArray, pInputArray, 32);
|
||||
|
||||
// initialize values
|
||||
m = 300;
|
||||
op = &pOutputArray[8];
|
||||
op1 = &pOutputArray[7];
|
||||
op2 = &pOutputArray[6];
|
||||
|
||||
// make the first prediction
|
||||
p = (pOutputArray[7] * 3) - (pOutputArray[6] * 3) + pOutputArray[5];
|
||||
pw = (p * m) >> 12;
|
||||
|
||||
// loop through the array
|
||||
for (ip = &pInputArray[8]; ip < &pInputArray[NumberOfElements]; ip++, op++, op1++, op2++) {
|
||||
|
||||
// figure the output value
|
||||
*op = *ip + pw;
|
||||
|
||||
// adjust m
|
||||
if (*ip > 0)
|
||||
m += (p > 0) ? 4 : -4;
|
||||
else if (*ip < 0)
|
||||
m += (p > 0) ? -4 : 4;
|
||||
|
||||
// make the next prediction
|
||||
p = (*op * 3) - (*op1 * 3) + *op2;
|
||||
pw = (p * m) >> 12;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////
|
||||
// order 2
|
||||
///////////////////////////////////////
|
||||
memcpy(pInputArray, pOutputArray, 32);
|
||||
m = 3000;
|
||||
|
||||
op1 = &pInputArray[7];
|
||||
p = (*op1 * 2) - pInputArray[6];
|
||||
pw = (p * m) >> 12;
|
||||
|
||||
for (op = &pInputArray[8], ip = &pOutputArray[8]; ip < &pOutputArray[NumberOfElements]; ip++, op++, op1++)
|
||||
{
|
||||
*op = *ip + pw;
|
||||
|
||||
// adjust m
|
||||
if (*ip > 0)
|
||||
m += (p > 0) ? 12 : -12;
|
||||
else if (*ip < 0)
|
||||
m += (p > 0) ? -12 : 12;
|
||||
|
||||
p = (*op * 2) - *op1;
|
||||
pw = (p * m) >> 12;
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// order 1
|
||||
///////////////////////////////////////
|
||||
pOutputArray[0] = pInputArray[0];
|
||||
pOutputArray[1] = pInputArray[1] + pOutputArray[0];
|
||||
pOutputArray[2] = pInputArray[2] + pOutputArray[1];
|
||||
pOutputArray[3] = pInputArray[3] + pOutputArray[2];
|
||||
pOutputArray[4] = pInputArray[4] + pOutputArray[3];
|
||||
pOutputArray[5] = pInputArray[5] + pOutputArray[4];
|
||||
pOutputArray[6] = pInputArray[6] + pOutputArray[5];
|
||||
pOutputArray[7] = pInputArray[7] + pOutputArray[6];
|
||||
|
||||
m = 3900;
|
||||
|
||||
p = pOutputArray[7];
|
||||
pw = (p * m) >> 12;
|
||||
|
||||
for (op = &pOutputArray[8], ip = &pInputArray[8]; ip < &pInputArray[NumberOfElements]; ip++, op++) {
|
||||
*op = *ip + pw;
|
||||
|
||||
// adjust m
|
||||
if (*ip > 0)
|
||||
m += (p > 0) ? 1 : -1;
|
||||
else if (*ip < 0)
|
||||
m += (p > 0) ? -1 : 1;
|
||||
|
||||
p = *op;
|
||||
pw = (p * m) >> 12;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void CAntiPredictorNormal3320To3800::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements)
|
||||
{
|
||||
// variable declares
|
||||
int q;
|
||||
|
||||
// short frame handling
|
||||
if (NumberOfElements < 8)
|
||||
{
|
||||
memcpy(pOutputArray, pInputArray, NumberOfElements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
// make the first five samples identical in both arrays
|
||||
memcpy(pOutputArray, pInputArray, 20);
|
||||
|
||||
// initialize values
|
||||
int m1 = 0;
|
||||
int m2 = 64;
|
||||
int m3 = 28;
|
||||
int OP0;
|
||||
int OP1 = pOutputArray[4];
|
||||
|
||||
int p3 = (3 * (pOutputArray[4] - pOutputArray[3])) + pOutputArray[2];
|
||||
int p2 = pInputArray[4] + ((pInputArray[2] - pInputArray[3]) << 3) - pInputArray[1] + pInputArray[0];
|
||||
int p1 = pOutputArray[4];
|
||||
|
||||
for (q = 5; q < NumberOfElements; q++)
|
||||
{
|
||||
OP0 = pInputArray[q] + ((p1 * m1) >> 8);
|
||||
(pInputArray[q] ^ p1) > 0 ? m1++ : m1--;
|
||||
p1 = OP0;
|
||||
|
||||
pInputArray[q] = OP0 + ((p2 * m2) >> 11);
|
||||
(OP0 ^ p2) > 0 ? m2++ : m2--;
|
||||
p2 = pInputArray[q] + ((pInputArray[q - 2] - pInputArray[q - 1]) << 3) - pInputArray[q - 3] + pInputArray[q - 4];
|
||||
|
||||
pOutputArray[q] = pInputArray[q] + ((p3 * m3) >> 9);
|
||||
(pInputArray[q] ^ p3) > 0 ? m3++ : m3--;
|
||||
p3 = (3 * (pOutputArray[q] - pOutputArray[q - 1])) + pOutputArray[q - 2];
|
||||
}
|
||||
|
||||
int m4 = 370;
|
||||
int m5 = 3900;
|
||||
|
||||
pOutputArray[1] = pInputArray[1] + pOutputArray[0];
|
||||
pOutputArray[2] = pInputArray[2] + pOutputArray[1];
|
||||
pOutputArray[3] = pInputArray[3] + pOutputArray[2];
|
||||
pOutputArray[4] = pInputArray[4] + pOutputArray[3];
|
||||
|
||||
int p4 = (2 * pInputArray[4]) - pInputArray[3];
|
||||
int p5 = pOutputArray[4];
|
||||
int IP0, IP1;
|
||||
|
||||
IP1 = pInputArray[4];
|
||||
for (q = 5; q < NumberOfElements; q++)
|
||||
{
|
||||
IP0 = pOutputArray[q] + ((p4 * m4) >> 9);
|
||||
(pOutputArray[q] ^ p4) > 0 ? m4++ : m4--;
|
||||
p4 = (2 * IP0) - IP1;
|
||||
|
||||
pOutputArray[q] = IP0 + ((p5 * m5) >> 12);
|
||||
(IP0 ^ p5) > 0 ? m5++ : m5--;
|
||||
p5 = pOutputArray[q];
|
||||
|
||||
IP1 = IP0;
|
||||
}
|
||||
}
|
||||
|
||||
void CAntiPredictorNormal3800ToCurrent::AntiPredict(int *pInputArray, int *pOutputArray, int NumberOfElements)
|
||||
{
|
||||
// the frame to start prediction on
|
||||
#define FIRST_ELEMENT 4
|
||||
|
||||
// short frame handling
|
||||
if (NumberOfElements < 8)
|
||||
{
|
||||
memcpy(pOutputArray, pInputArray, NumberOfElements * 4);
|
||||
return;
|
||||
}
|
||||
|
||||
// make the first five samples identical in both arrays
|
||||
memcpy(pOutputArray, pInputArray, FIRST_ELEMENT * 4);
|
||||
|
||||
// variable declares and initializations
|
||||
int m2 = 64, m3 = 115, m4 = 64, m5 = 740, m6 = 0;
|
||||
int p4 = pInputArray[FIRST_ELEMENT - 1];
|
||||
int p3 = (pInputArray[FIRST_ELEMENT - 1] - pInputArray[FIRST_ELEMENT - 2]) << 1;
|
||||
int p2 = pInputArray[FIRST_ELEMENT - 1] + ((pInputArray[FIRST_ELEMENT - 3] - pInputArray[FIRST_ELEMENT - 2]) << 3);// - pInputArray[3] + pInputArray[2];
|
||||
int *op = &pOutputArray[FIRST_ELEMENT];
|
||||
int *ip = &pInputArray[FIRST_ELEMENT];
|
||||
int IPP2 = ip[-2];
|
||||
int p7 = 2 * ip[-1] - ip[-2];
|
||||
int opp = op[-1];
|
||||
|
||||
// undo the initial prediction stuff
|
||||
for (int q = 1; q < FIRST_ELEMENT; q++) {
|
||||
pOutputArray[q] += pOutputArray[q - 1];
|
||||
}
|
||||
|
||||
// pump the primary loop
|
||||
for (; op < &pOutputArray[NumberOfElements]; op++, ip++) {
|
||||
|
||||
register int o = *op, i = *ip;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
o = i + (((p2 * m2) + (p3 * m3) + (p4 * m4)) >> 11);
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
m2 -= ((p2 >> 30) & 2) - 1;
|
||||
m3 -= ((p3 >> 28) & 8) - 4;
|
||||
m4 -= ((p4 >> 28) & 8) - 4;
|
||||
|
||||
}
|
||||
else if (i < 0)
|
||||
{
|
||||
m2 += ((p2 >> 30) & 2) - 1;
|
||||
m3 += ((p3 >> 28) & 8) - 4;
|
||||
m4 += ((p4 >> 28) & 8) - 4;
|
||||
}
|
||||
|
||||
|
||||
p2 = o + ((IPP2 - p4) << 3);
|
||||
p3 = (o - p4) << 1;
|
||||
IPP2 = p4;
|
||||
p4 = o;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
o += (((p7 * m5) - (opp * m6)) >> 10);
|
||||
|
||||
if (p4 > 0)
|
||||
{
|
||||
m5 -= ((p7 >> 29) & 4) - 2;
|
||||
m6 += ((opp >> 30) & 2) - 1;
|
||||
}
|
||||
else if (p4 < 0)
|
||||
{
|
||||
m5 += ((p7 >> 29) & 4) - 2;
|
||||
m6 -= ((opp >> 30) & 2) - 1;
|
||||
}
|
||||
|
||||
p7 = 2 * o - opp;
|
||||
opp = o;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
*op = o + ((op[-1] * 31) >> 5);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifdef ENABLE_COMPRESSION_MODE_NORMAL
|
||||
|
||||
#endif // #ifdef BACKWARDS_COMPATIBILITY
|
||||
353
MAC_SDK/Source/MACLib/Old/UnBitArrayOld.cpp
Normal file
353
MAC_SDK/Source/MACLib/Old/UnBitArrayOld.cpp
Normal file
@@ -0,0 +1,353 @@
|
||||
#include "All.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
#include "../APEInfo.h"
|
||||
#include "UnBitarrayOld.h"
|
||||
#include "../BitArray.h"
|
||||
|
||||
const uint32 K_SUM_MIN_BOUNDARY_OLD[32] = {0,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,0,0,0,0,0,0};
|
||||
const uint32 K_SUM_MAX_BOUNDARY_OLD[32] = {128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,0,0,0,0,0,0,0};
|
||||
const uint32 Powers_of_Two[32] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648};
|
||||
const uint32 Powers_of_Two_Reversed[32] = {2147483648,1073741824,536870912,268435456,134217728,67108864,33554432,16777216,8388608,4194304,2097152,1048576,524288,262144,131072,65536,32768,16384,8192,4096,2048,1024,512,256,128,64,32,16,8,4,2,1};
|
||||
const uint32 Powers_of_Two_Minus_One[33] = {0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535,131071,262143,524287,1048575,2097151,4194303,8388607,16777215,33554431,67108863,134217727,268435455,536870911,1073741823,2147483647,4294967295};
|
||||
const uint32 Powers_of_Two_Minus_One_Reversed[33] = {4294967295,2147483647,1073741823,536870911,268435455,134217727,67108863,33554431,16777215,8388607,4194303,2097151,1048575,524287,262143,131071,65535,32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0};
|
||||
|
||||
const uint32 K_SUM_MIN_BOUNDARY[32] = {0,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,0,0,0,0};
|
||||
const uint32 K_SUM_MAX_BOUNDARY[32] = {32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,0,0,0,0,0};
|
||||
|
||||
/***********************************************************************************
|
||||
Construction
|
||||
***********************************************************************************/
|
||||
CUnBitArrayOld::CUnBitArrayOld(IAPEDecompress * pAPEDecompress, int nVersion)
|
||||
{
|
||||
int nBitArrayBytes = 262144;
|
||||
|
||||
// calculate the bytes
|
||||
if (nVersion <= 3880)
|
||||
{
|
||||
int nMaxFrameBytes = (pAPEDecompress->GetInfo(APE_INFO_BLOCKS_PER_FRAME) * 50) / 8;
|
||||
nBitArrayBytes = 65536;
|
||||
while (nBitArrayBytes < nMaxFrameBytes)
|
||||
{
|
||||
nBitArrayBytes <<= 1;
|
||||
}
|
||||
|
||||
nBitArrayBytes = max(nBitArrayBytes, 262144);
|
||||
}
|
||||
else if (nVersion <= 3890)
|
||||
{
|
||||
nBitArrayBytes = 65536;
|
||||
}
|
||||
else
|
||||
{
|
||||
// error
|
||||
}
|
||||
|
||||
CreateHelper(GET_IO(pAPEDecompress), nBitArrayBytes, nVersion);
|
||||
|
||||
// set the refill threshold
|
||||
if (m_nVersion <= 3880)
|
||||
m_nRefillBitThreshold = (m_nBits - (16384 * 8));
|
||||
else
|
||||
m_nRefillBitThreshold = (m_nBits - 512);
|
||||
}
|
||||
|
||||
CUnBitArrayOld::~CUnBitArrayOld()
|
||||
{
|
||||
SAFE_ARRAY_DELETE(m_pBitArray)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// Gets the number of m_nBits of data left in the m_nCurrentBitIndex array
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
uint32 CUnBitArrayOld::GetBitsRemaining()
|
||||
{
|
||||
return (m_nElements * 32 - m_nCurrentBitIndex);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// Gets a rice value from the array
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
uint32 CUnBitArrayOld::DecodeValueRiceUnsigned(uint32 k)
|
||||
{
|
||||
// variable declares
|
||||
uint32 v;
|
||||
|
||||
// plug through the string of 0's (the overflow)
|
||||
uint32 BitInitial = m_nCurrentBitIndex;
|
||||
while (!(m_pBitArray[m_nCurrentBitIndex >> 5] & Powers_of_Two_Reversed[m_nCurrentBitIndex++ & 31])) {}
|
||||
|
||||
// if k = 0, your done
|
||||
if (k == 0)
|
||||
return (m_nCurrentBitIndex - BitInitial - 1);
|
||||
|
||||
// put the overflow value into v
|
||||
v = (m_nCurrentBitIndex - BitInitial - 1) << k;
|
||||
|
||||
return v | DecodeValueXBits(k);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// Get the optimal k for a given value
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
__inline uint32 CUnBitArrayOld::Get_K(uint32 x)
|
||||
{
|
||||
if (x == 0) return 0;
|
||||
|
||||
uint32 k = 0;
|
||||
while (x >= Powers_of_Two[++k]) {}
|
||||
return k;
|
||||
}
|
||||
|
||||
unsigned int CUnBitArrayOld::DecodeValue(DECODE_VALUE_METHOD DecodeMethod, int nParam1, int nParam2)
|
||||
{
|
||||
switch (DecodeMethod)
|
||||
{
|
||||
case DECODE_VALUE_METHOD_UNSIGNED_INT:
|
||||
return DecodeValueXBits(32);
|
||||
case DECODE_VALUE_METHOD_UNSIGNED_RICE:
|
||||
return DecodeValueRiceUnsigned(nParam1);
|
||||
case DECODE_VALUE_METHOD_X_BITS:
|
||||
return DecodeValueXBits(nParam1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
// Generates an array from the m_nCurrentBitIndexarray
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
void CUnBitArrayOld::GenerateArrayOld(int* Output_Array, uint32 Number_of_Elements, int Minimum_nCurrentBitIndex_Array_Bytes) {
|
||||
|
||||
//variable declarations
|
||||
uint32 K_Sum;
|
||||
uint32 q;
|
||||
uint32 kmin, kmax;
|
||||
uint32 k;
|
||||
uint32 Max;
|
||||
int *p1, *p2;
|
||||
|
||||
// fill bit array if necessary
|
||||
// could use seek information to determine what the max was...
|
||||
uint32 Max_Bits_Needed = Number_of_Elements * 50;
|
||||
|
||||
if (Minimum_nCurrentBitIndex_Array_Bytes > 0)
|
||||
{
|
||||
// this is actually probably double what is really needed
|
||||
// we can only calculate the space needed for both arrays in multichannel
|
||||
Max_Bits_Needed = ((Minimum_nCurrentBitIndex_Array_Bytes + 4) * 8);
|
||||
}
|
||||
|
||||
if (Max_Bits_Needed > GetBitsRemaining())
|
||||
FillBitArray();
|
||||
|
||||
// decode the first 5 elements (all k = 10)
|
||||
Max = (Number_of_Elements < 5) ? Number_of_Elements : 5;
|
||||
for (q = 0; q < Max; q++)
|
||||
{
|
||||
Output_Array[q] = DecodeValueRiceUnsigned(10);
|
||||
}
|
||||
|
||||
// quit if that was all
|
||||
if (Number_of_Elements <= 5)
|
||||
{
|
||||
for (p2 = &Output_Array[0]; p2 < &Output_Array[Number_of_Elements]; p2++)
|
||||
*p2 = (*p2 & 1) ? (*p2 >> 1) + 1 : -(*p2 >> 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// update k and K_Sum
|
||||
K_Sum = Output_Array[0] + Output_Array[1] + Output_Array[2] + Output_Array[3] + Output_Array[4];
|
||||
k = Get_K(K_Sum / 10);
|
||||
|
||||
// work through the rest of the elements before the primary loop
|
||||
Max = (Number_of_Elements < 64) ? Number_of_Elements : 64;
|
||||
for (q = 5; q < Max; q++)
|
||||
{
|
||||
Output_Array[q] = DecodeValueRiceUnsigned(k);
|
||||
K_Sum += Output_Array[q];
|
||||
k = Get_K(K_Sum / (q + 1) / 2);
|
||||
}
|
||||
|
||||
// quit if that was all
|
||||
if (Number_of_Elements <= 64)
|
||||
{
|
||||
for (p2 = &Output_Array[0]; p2 < &Output_Array[Number_of_Elements]; p2++)
|
||||
*p2 = (*p2 & 1) ? (*p2 >> 1) + 1 : -(*p2 >> 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// set all of the variables up for the primary loop
|
||||
uint32 v, Bit_Array_Index;
|
||||
k = Get_K(K_Sum >> 7);
|
||||
kmin = K_SUM_MIN_BOUNDARY_OLD[k];
|
||||
kmax = K_SUM_MAX_BOUNDARY_OLD[k];
|
||||
p1 = &Output_Array[64]; p2 = &Output_Array[0];
|
||||
|
||||
// the primary loop
|
||||
for (p1 = &Output_Array[64], p2 = &Output_Array[0]; p1 < &Output_Array[Number_of_Elements]; p1++, p2++)
|
||||
{
|
||||
// plug through the string of 0's (the overflow)
|
||||
uint32 Bit_Initial = m_nCurrentBitIndex;
|
||||
while (!(m_pBitArray[m_nCurrentBitIndex >> 5] & Powers_of_Two_Reversed[m_nCurrentBitIndex++ & 31])) {}
|
||||
|
||||
// if k = 0, your done
|
||||
if (k == 0)
|
||||
{
|
||||
v = (m_nCurrentBitIndex - Bit_Initial - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// put the overflow value into v
|
||||
v = (m_nCurrentBitIndex - Bit_Initial - 1) << k;
|
||||
|
||||
// store the bit information and incement the bit pointer by 'k'
|
||||
Bit_Array_Index = m_nCurrentBitIndex >> 5;
|
||||
unsigned int Bit_Index = m_nCurrentBitIndex & 31;
|
||||
m_nCurrentBitIndex += k;
|
||||
|
||||
// figure the extra bits on the left and the left value
|
||||
int Left_Extra_Bits = (32 - k) - Bit_Index;
|
||||
unsigned int Left_Value = m_pBitArray[Bit_Array_Index] & Powers_of_Two_Minus_One_Reversed[Bit_Index];
|
||||
|
||||
if (Left_Extra_Bits >= 0)
|
||||
v |= (Left_Value >> Left_Extra_Bits);
|
||||
else
|
||||
v |= (Left_Value << -Left_Extra_Bits) | (m_pBitArray[Bit_Array_Index + 1] >> (32 + Left_Extra_Bits));
|
||||
}
|
||||
|
||||
*p1 = v;
|
||||
K_Sum += *p1 - *p2;
|
||||
|
||||
// convert *p2 to unsigned
|
||||
*p2 = (*p2 % 2) ? (*p2 >> 1) + 1 : -(*p2 >> 1);
|
||||
|
||||
// adjust k if necessary
|
||||
if ((K_Sum < kmin) || (K_Sum >= kmax))
|
||||
{
|
||||
if (K_Sum < kmin)
|
||||
while (K_Sum < K_SUM_MIN_BOUNDARY_OLD[--k]) {}
|
||||
else
|
||||
while (K_Sum >= K_SUM_MAX_BOUNDARY_OLD[++k]) {}
|
||||
|
||||
kmax = K_SUM_MAX_BOUNDARY_OLD[k];
|
||||
kmin = K_SUM_MIN_BOUNDARY_OLD[k];
|
||||
}
|
||||
}
|
||||
|
||||
for (; p2 < &Output_Array[Number_of_Elements]; p2++)
|
||||
*p2 = (*p2 & 1) ? (*p2 >> 1) + 1 : -(*p2 >> 1);
|
||||
}
|
||||
|
||||
void CUnBitArrayOld::GenerateArray(int *pOutputArray, int nElements, int nBytesRequired)
|
||||
{
|
||||
if (m_nVersion < 3860)
|
||||
{
|
||||
GenerateArrayOld(pOutputArray, nElements, nBytesRequired);
|
||||
}
|
||||
else if (m_nVersion <= 3890)
|
||||
{
|
||||
GenerateArrayRice(pOutputArray, nElements, nBytesRequired);
|
||||
}
|
||||
else
|
||||
{
|
||||
// error
|
||||
}
|
||||
}
|
||||
|
||||
void CUnBitArrayOld::GenerateArrayRice(int* Output_Array, uint32 Number_of_Elements, int Minimum_nCurrentBitIndex_Array_Bytes)
|
||||
{
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// decode the bit array
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
k = 10;
|
||||
K_Sum = 1024 * 16;
|
||||
|
||||
if (m_nVersion <= 3880)
|
||||
{
|
||||
// the primary loop
|
||||
for (int *p1 = &Output_Array[0]; p1 < &Output_Array[Number_of_Elements]; p1++)
|
||||
{
|
||||
*p1 = DecodeValueNew(FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// the primary loop
|
||||
for (int *p1 = &Output_Array[0]; p1 < &Output_Array[Number_of_Elements]; p1++)
|
||||
{
|
||||
*p1 = DecodeValueNew(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__inline int CUnBitArrayOld::DecodeValueNew(BOOL bCapOverflow)
|
||||
{
|
||||
// make sure there is room for the data
|
||||
// this is a little slower than ensuring a huge block to start with, but it's safer
|
||||
if (m_nCurrentBitIndex > m_nRefillBitThreshold)
|
||||
{
|
||||
FillBitArray();
|
||||
}
|
||||
|
||||
unsigned int v;
|
||||
|
||||
// plug through the string of 0's (the overflow)
|
||||
uint32 Bit_Initial = m_nCurrentBitIndex;
|
||||
while (!(m_pBitArray[m_nCurrentBitIndex >> 5] & Powers_of_Two_Reversed[m_nCurrentBitIndex++ & 31])) {}
|
||||
|
||||
int nOverflow = (m_nCurrentBitIndex - Bit_Initial - 1);
|
||||
|
||||
if (bCapOverflow)
|
||||
{
|
||||
while (nOverflow >= 16)
|
||||
{
|
||||
k += 4;
|
||||
nOverflow -= 16;
|
||||
}
|
||||
}
|
||||
|
||||
// if k = 0, your done
|
||||
if (k != 0)
|
||||
{
|
||||
// put the overflow value into v
|
||||
v = nOverflow << k;
|
||||
|
||||
// store the bit information and incement the bit pointer by 'k'
|
||||
unsigned int Bit_Array_Index = m_nCurrentBitIndex >> 5;
|
||||
unsigned int Bit_Index = m_nCurrentBitIndex & 31;
|
||||
m_nCurrentBitIndex += k;
|
||||
|
||||
// figure the extra bits on the left and the left value
|
||||
int Left_Extra_Bits = (32 - k) - Bit_Index;
|
||||
unsigned int Left_Value = m_pBitArray[Bit_Array_Index] & Powers_of_Two_Minus_One_Reversed[Bit_Index];
|
||||
|
||||
if (Left_Extra_Bits >= 0)
|
||||
{
|
||||
v |= (Left_Value >> Left_Extra_Bits);
|
||||
}
|
||||
else
|
||||
{
|
||||
v |= (Left_Value << -Left_Extra_Bits) | (m_pBitArray[Bit_Array_Index + 1] >> (32 + Left_Extra_Bits));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
v = nOverflow;
|
||||
}
|
||||
|
||||
// update K_Sum
|
||||
K_Sum += v - ((K_Sum + 8) >> 4);
|
||||
|
||||
// update k
|
||||
if (K_Sum < K_SUM_MIN_BOUNDARY[k])
|
||||
k--;
|
||||
else if (K_Sum >= K_SUM_MAX_BOUNDARY[k])
|
||||
k++;
|
||||
|
||||
// convert to unsigned and save
|
||||
return (v & 1) ? (v >> 1) + 1 : -(int(v >> 1));
|
||||
}
|
||||
|
||||
#endif // #ifdef BACKWARDS_COMPATIBILITY
|
||||
46
MAC_SDK/Source/MACLib/Old/UnBitArrayOld.h
Normal file
46
MAC_SDK/Source/MACLib/Old/UnBitArrayOld.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef APE_UNBITARRAY_OLD_H
|
||||
#define APE_UNBITARRAY_OLD_H
|
||||
|
||||
#include "All.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
#include "../UnBitArrayBase.h"
|
||||
|
||||
class IAPEDecompress;
|
||||
|
||||
// decodes 0000 up to and including 3890
|
||||
class CUnBitArrayOld : public CUnBitArrayBase
|
||||
{
|
||||
public:
|
||||
|
||||
// construction/destruction
|
||||
CUnBitArrayOld(IAPEDecompress *pAPEDecompress, int nVersion);
|
||||
~CUnBitArrayOld();
|
||||
|
||||
// functions
|
||||
void GenerateArray(int *pOutputArray, int nElements, int nBytesRequired = -1);
|
||||
unsigned int DecodeValue(DECODE_VALUE_METHOD DecodeMethod, int nParam1 = 0, int nParam2 = 0);
|
||||
|
||||
private:
|
||||
|
||||
void GenerateArrayOld(int* pOutputArray, uint32 NumberOfElements, int MinimumBitArrayBytes);
|
||||
void GenerateArrayRice(int* pOutputArray, uint32 NumberOfElements, int MinimumBitArrayBytes);
|
||||
|
||||
uint32 DecodeValueRiceUnsigned(uint32 k);
|
||||
|
||||
// data
|
||||
uint32 k;
|
||||
uint32 K_Sum;
|
||||
uint32 m_nRefillBitThreshold;
|
||||
|
||||
// functions
|
||||
__inline int DecodeValueNew(BOOL bCapOverflow);
|
||||
uint32 GetBitsRemaining();
|
||||
__inline uint32 Get_K(uint32 x);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // #ifndef APE_UNBITARRAY_OLD_H
|
||||
|
||||
|
||||
261
MAC_SDK/Source/MACLib/Old/UnMAC.cpp
Normal file
261
MAC_SDK/Source/MACLib/Old/UnMAC.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
/*****************************************************************************************
|
||||
UnMAC.cpp
|
||||
Copyright (C) 2000-2001 by Matthew T. Ashland All Rights Reserved.
|
||||
|
||||
CUnMAC - the main hub for decompression (manages all of the other components)
|
||||
|
||||
Notes:
|
||||
-none
|
||||
*****************************************************************************************/
|
||||
|
||||
/*****************************************************************************************
|
||||
Includes
|
||||
*****************************************************************************************/
|
||||
#include "All.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
#include "../APEInfo.h"
|
||||
#include "UnMAC.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "../UnBitArrayBase.h"
|
||||
#include "Anti-Predictor.h"
|
||||
#include "../Prepare.h"
|
||||
#include "../UnBitArray.h"
|
||||
#include "../NewPredictor.h"
|
||||
#include "APEDecompressCore.h"
|
||||
|
||||
/*****************************************************************************************
|
||||
CUnMAC class construction
|
||||
*****************************************************************************************/
|
||||
CUnMAC::CUnMAC()
|
||||
{
|
||||
// initialize member variables
|
||||
m_bInitialized = FALSE;
|
||||
m_LastDecodedFrameIndex = -1;
|
||||
m_pAPEDecompress = NULL;
|
||||
|
||||
m_pAPEDecompressCore = NULL;
|
||||
m_pPrepare = NULL;
|
||||
|
||||
m_nBlocksProcessed = 0;
|
||||
m_nCRC = 0;
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
CUnMAC class destruction
|
||||
*****************************************************************************************/
|
||||
CUnMAC::~CUnMAC()
|
||||
{
|
||||
// uninitialize the decoder in case it isn't already
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Initialize
|
||||
*****************************************************************************************/
|
||||
int CUnMAC::Initialize(IAPEDecompress *pAPEDecompress)
|
||||
{
|
||||
// uninitialize if it is currently initialized
|
||||
if (m_bInitialized)
|
||||
Uninitialize();
|
||||
|
||||
if (pAPEDecompress == NULL)
|
||||
{
|
||||
Uninitialize();
|
||||
return ERROR_INITIALIZING_UNMAC;
|
||||
}
|
||||
|
||||
// set the member pointer to the IAPEDecompress class
|
||||
m_pAPEDecompress = pAPEDecompress;
|
||||
|
||||
// set the last decode frame to -1 so it forces a seek on start
|
||||
m_LastDecodedFrameIndex = -1;
|
||||
|
||||
m_pAPEDecompressCore = new CAPEDecompressCore(GET_IO(pAPEDecompress), pAPEDecompress);
|
||||
m_pPrepare = new CPrepare;
|
||||
|
||||
// set the initialized flag to TRUE
|
||||
m_bInitialized = TRUE;
|
||||
|
||||
m_pAPEDecompress->GetInfo(APE_INFO_WAVEFORMATEX, (int) &m_wfeInput);
|
||||
|
||||
// return a successful value
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Uninitialize
|
||||
*****************************************************************************************/
|
||||
int CUnMAC::Uninitialize()
|
||||
{
|
||||
if (m_bInitialized)
|
||||
{
|
||||
SAFE_DELETE(m_pAPEDecompressCore)
|
||||
SAFE_DELETE(m_pPrepare)
|
||||
|
||||
// clear the APE info pointer
|
||||
m_pAPEDecompress = NULL;
|
||||
|
||||
// set the last decoded frame again
|
||||
m_LastDecodedFrameIndex = -1;
|
||||
|
||||
// set the initialized flag to FALSE
|
||||
m_bInitialized = FALSE;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Decompress frame
|
||||
*****************************************************************************************/
|
||||
int CUnMAC::DecompressFrame(unsigned char *pOutputData, int32 FrameIndex, int CPULoadBalancingFactor)
|
||||
{
|
||||
return DecompressFrameOld(pOutputData, FrameIndex, CPULoadBalancingFactor);
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Seek to the proper frame (if necessary) and do any alignment of the bit array
|
||||
*****************************************************************************************/
|
||||
int CUnMAC::SeekToFrame(int FrameIndex)
|
||||
{
|
||||
if (GET_FRAMES_START_ON_BYTES_BOUNDARIES(m_pAPEDecompress))
|
||||
{
|
||||
if ((m_LastDecodedFrameIndex == -1) || ((FrameIndex - 1) != m_LastDecodedFrameIndex))
|
||||
{
|
||||
int SeekRemainder = (m_pAPEDecompress->GetInfo(APE_INFO_SEEK_BYTE, FrameIndex) - m_pAPEDecompress->GetInfo(APE_INFO_SEEK_BYTE, 0)) % 4;
|
||||
m_pAPEDecompressCore->GetUnBitArrray()->FillAndResetBitArray(m_pAPEDecompress->GetInfo(APE_INFO_SEEK_BYTE, FrameIndex) - SeekRemainder, SeekRemainder * 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pAPEDecompressCore->GetUnBitArrray()->AdvanceToByteBoundary();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m_LastDecodedFrameIndex == -1) || ((FrameIndex - 1) != m_LastDecodedFrameIndex))
|
||||
{
|
||||
m_pAPEDecompressCore->GetUnBitArrray()->FillAndResetBitArray(m_pAPEDecompress->GetInfo(APE_INFO_SEEK_BYTE, FrameIndex), m_pAPEDecompress->GetInfo(APE_INFO_SEEK_BIT, FrameIndex));
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Old code for frame decompression
|
||||
*****************************************************************************************/
|
||||
int CUnMAC::DecompressFrameOld(unsigned char *pOutputData, int32 FrameIndex, int CPULoadBalancingFactor)
|
||||
{
|
||||
// error check the parameters (too high of a frame index, etc.)
|
||||
if (FrameIndex >= m_pAPEDecompress->GetInfo(APE_INFO_TOTAL_FRAMES)) { return ERROR_SUCCESS; }
|
||||
|
||||
// get the number of samples in the frame
|
||||
int nBlocks = 0;
|
||||
nBlocks = ((FrameIndex + 1) >= m_pAPEDecompress->GetInfo(APE_INFO_TOTAL_FRAMES)) ? m_pAPEDecompress->GetInfo(APE_INFO_FINAL_FRAME_BLOCKS) : m_pAPEDecompress->GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
if (nBlocks == 0)
|
||||
return -1; // nothing to do (file must be zero length) (have to return error)
|
||||
|
||||
// take care of seeking and frame alignment
|
||||
if (SeekToFrame(FrameIndex) != 0) { return -1; }
|
||||
|
||||
// get the checksum
|
||||
unsigned int nSpecialCodes = 0;
|
||||
uint32 nStoredCRC = 0;
|
||||
|
||||
if (GET_USES_CRC(m_pAPEDecompress) == FALSE)
|
||||
{
|
||||
nStoredCRC = m_pAPEDecompressCore->GetUnBitArrray()->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_RICE, 30);
|
||||
if (nStoredCRC == 0)
|
||||
{
|
||||
nSpecialCodes = SPECIAL_FRAME_LEFT_SILENCE | SPECIAL_FRAME_RIGHT_SILENCE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nStoredCRC = m_pAPEDecompressCore->GetUnBitArrray()->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_INT);
|
||||
|
||||
// get any 'special' codes if the file uses them (for silence, FALSE stereo, etc.)
|
||||
nSpecialCodes = 0;
|
||||
if (GET_USES_SPECIAL_FRAMES(m_pAPEDecompress))
|
||||
{
|
||||
if (nStoredCRC & 0x80000000)
|
||||
{
|
||||
nSpecialCodes = m_pAPEDecompressCore->GetUnBitArrray()->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_INT);
|
||||
}
|
||||
nStoredCRC &= 0x7FFFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
// the CRC that will be figured during decompression
|
||||
uint32 CRC = 0xFFFFFFFF;
|
||||
|
||||
// decompress and convert from (x,y) -> (l,r)
|
||||
// sort of int and ugly.... sorry
|
||||
if (m_pAPEDecompress->GetInfo(APE_INFO_CHANNELS) == 2)
|
||||
{
|
||||
m_pAPEDecompressCore->GenerateDecodedArrays(nBlocks, nSpecialCodes, FrameIndex, CPULoadBalancingFactor);
|
||||
|
||||
WAVEFORMATEX WaveFormatEx; m_pAPEDecompress->GetInfo(APE_INFO_WAVEFORMATEX, (int) &WaveFormatEx);
|
||||
m_pPrepare->UnprepareOld(m_pAPEDecompressCore->GetDataX(), m_pAPEDecompressCore->GetDataY(), nBlocks, &WaveFormatEx,
|
||||
pOutputData, (unsigned int *) &CRC, (int *) &nSpecialCodes, m_pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION));
|
||||
}
|
||||
else if (m_pAPEDecompress->GetInfo(APE_INFO_CHANNELS) == 1)
|
||||
{
|
||||
m_pAPEDecompressCore->GenerateDecodedArrays(nBlocks, nSpecialCodes, FrameIndex, CPULoadBalancingFactor);
|
||||
|
||||
WAVEFORMATEX WaveFormatEx; m_pAPEDecompress->GetInfo(APE_INFO_WAVEFORMATEX, (int) &WaveFormatEx);
|
||||
m_pPrepare->UnprepareOld(m_pAPEDecompressCore->GetDataX(), NULL, nBlocks, &WaveFormatEx,
|
||||
pOutputData, (unsigned int *) &CRC, (int *) &nSpecialCodes, m_pAPEDecompress->GetInfo(APE_INFO_FILE_VERSION));
|
||||
}
|
||||
|
||||
if (GET_USES_SPECIAL_FRAMES(m_pAPEDecompress))
|
||||
{
|
||||
CRC >>= 1;
|
||||
}
|
||||
|
||||
// check the CRC
|
||||
if (GET_USES_CRC(m_pAPEDecompress) == FALSE)
|
||||
{
|
||||
uint32 nChecksum = CalculateOldChecksum(m_pAPEDecompressCore->GetDataX(), m_pAPEDecompressCore->GetDataY(), m_pAPEDecompress->GetInfo(APE_INFO_CHANNELS), nBlocks);
|
||||
if (nChecksum != nStoredCRC)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (CRC != nStoredCRC)
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_LastDecodedFrameIndex = FrameIndex;
|
||||
return nBlocks;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
Figures the old checksum using the X,Y data
|
||||
*****************************************************************************************/
|
||||
uint32 CUnMAC::CalculateOldChecksum(int *pDataX, int *pDataY, int nChannels, int nBlocks)
|
||||
{
|
||||
uint32 nChecksum = 0;
|
||||
|
||||
if (nChannels == 2)
|
||||
{
|
||||
for (int z = 0; z < nBlocks; z++)
|
||||
{
|
||||
int R = pDataX[z] - (pDataY[z] / 2);
|
||||
int L = R + pDataY[z];
|
||||
nChecksum += (labs(R) + labs(L));
|
||||
}
|
||||
}
|
||||
else if (nChannels == 1)
|
||||
{
|
||||
for (int z = 0; z < nBlocks; z++)
|
||||
nChecksum += labs(pDataX[z]);
|
||||
}
|
||||
|
||||
return nChecksum;
|
||||
}
|
||||
|
||||
#endif // #ifdef BACKWARDS_COMPATIBILITY
|
||||
69
MAC_SDK/Source/MACLib/Old/UnMAC.h
Normal file
69
MAC_SDK/Source/MACLib/Old/UnMAC.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*****************************************************************************************
|
||||
UnMAC.h
|
||||
Copyright (C) 2000-2001 by Matthew T. Ashland All Rights Reserved.
|
||||
|
||||
Methods for decompressing or verifying APE files
|
||||
|
||||
Notes:
|
||||
-none
|
||||
*****************************************************************************************/
|
||||
|
||||
#ifndef APE_UNMAC_H
|
||||
#define APE_UNMAC_H
|
||||
|
||||
#include "../BitArray.h"
|
||||
#include "../UnBitArrayBase.h"
|
||||
|
||||
class CAntiPredictor;
|
||||
class CPrepare;
|
||||
class CAPEDecompressCore;
|
||||
class CPredictorBase;
|
||||
class IPredictorDecompress;
|
||||
class IAPEDecompress;
|
||||
|
||||
/*****************************************************************************************
|
||||
CUnMAC class... a class that allows decoding on a frame-by-frame basis
|
||||
*****************************************************************************************/
|
||||
class CUnMAC
|
||||
{
|
||||
public:
|
||||
|
||||
// construction/destruction
|
||||
CUnMAC();
|
||||
~CUnMAC();
|
||||
|
||||
// functions
|
||||
int Initialize(IAPEDecompress *pAPEDecompress);
|
||||
int Uninitialize();
|
||||
int DecompressFrame(unsigned char *pOutputData, int32 FrameIndex, int CPULoadBalancingFactor = 0);
|
||||
|
||||
int SeekToFrame(int FrameIndex);
|
||||
|
||||
private:
|
||||
|
||||
// data members
|
||||
BOOL m_bInitialized;
|
||||
int m_LastDecodedFrameIndex;
|
||||
IAPEDecompress * m_pAPEDecompress;
|
||||
CPrepare * m_pPrepare;
|
||||
|
||||
CAPEDecompressCore * m_pAPEDecompressCore;
|
||||
|
||||
// functions
|
||||
void GenerateDecodedArrays(int nBlocks, int nSpecialCodes, int nFrameIndex, int nCPULoadBalancingFactor);
|
||||
void GenerateDecodedArray(int *Input_Array, uint32 Number_of_Elements, int Frame_Index, CAntiPredictor *pAntiPredictor, int CPULoadBalancingFactor = 0);
|
||||
|
||||
int CreateAntiPredictors(int nCompressionLevel, int nVersion);
|
||||
|
||||
int DecompressFrameOld(unsigned char *pOutputData, int32 FrameIndex, int CPULoadBalancingFactor);
|
||||
uint32 CalculateOldChecksum(int *pDataX, int *pDataY, int nChannels, int nBlocks);
|
||||
|
||||
public:
|
||||
|
||||
int m_nBlocksProcessed;
|
||||
unsigned int m_nCRC;
|
||||
unsigned int m_nStoredCRC;
|
||||
WAVEFORMATEX m_wfeInput;
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_UNMAC_H
|
||||
30
MAC_SDK/Source/MACLib/Predictor.h
Normal file
30
MAC_SDK/Source/MACLib/Predictor.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef APE_PREDICTOR_H
|
||||
#define APE_PREDICTOR_H
|
||||
|
||||
/*************************************************************************************************
|
||||
IPredictorCompress - the interface for compressing (predicting) data
|
||||
*************************************************************************************************/
|
||||
class IPredictorCompress
|
||||
{
|
||||
public:
|
||||
IPredictorCompress(int nCompressionLevel) {}
|
||||
virtual ~IPredictorCompress() {}
|
||||
|
||||
virtual int CompressValue(int nA, int nB = 0) = 0;
|
||||
virtual int Flush() = 0;
|
||||
};
|
||||
|
||||
/*************************************************************************************************
|
||||
IPredictorDecompress - the interface for decompressing (un-predicting) data
|
||||
*************************************************************************************************/
|
||||
class IPredictorDecompress
|
||||
{
|
||||
public:
|
||||
IPredictorDecompress(int nCompressionLevel, int nVersion) {}
|
||||
virtual ~IPredictorDecompress() {}
|
||||
|
||||
virtual int DecompressValue(int nA, int nB = 0) = 0;
|
||||
virtual int Flush() = 0;
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_PREDICTOR_H
|
||||
510
MAC_SDK/Source/MACLib/Prepare.cpp
Normal file
510
MAC_SDK/Source/MACLib/Prepare.cpp
Normal file
@@ -0,0 +1,510 @@
|
||||
#include "All.h"
|
||||
#include "Prepare.h"
|
||||
|
||||
const uint32 CRC32_TABLE[256] = {0,1996959894,3993919788,2567524794,124634137,1886057615,3915621685,2657392035,249268274,2044508324,3772115230,2547177864,162941995,2125561021,3887607047,2428444049,498536548,1789927666,4089016648,2227061214,450548861,1843258603,4107580753,2211677639,325883990,1684777152,4251122042,2321926636,335633487,1661365465,4195302755,2366115317,997073096,1281953886,3579855332,2724688242,1006888145,1258607687,3524101629,2768942443,901097722,1119000684,3686517206,2898065728,853044451,1172266101,3705015759,2882616665,651767980,1373503546,3369554304,3218104598,565507253,1454621731,3485111705,3099436303,671266974,1594198024,3322730930,2970347812,795835527,1483230225,3244367275,3060149565,1994146192,31158534,2563907772,4023717930,1907459465,112637215,2680153253,3904427059,2013776290,251722036,2517215374,3775830040,2137656763,141376813,2439277719,3865271297,1802195444,476864866,2238001368,
|
||||
4066508878,1812370925,453092731,2181625025,4111451223,1706088902,314042704,2344532202,4240017532,1658658271,366619977,2362670323,4224994405,1303535960,984961486,2747007092,3569037538,1256170817,1037604311,2765210733,3554079995,1131014506,879679996,2909243462,3663771856,1141124467,855842277,2852801631,3708648649,1342533948,654459306,3188396048,3373015174,1466479909,544179635,3110523913,3462522015,1591671054,702138776,2966460450,3352799412,1504918807,783551873,3082640443,3233442989,3988292384,2596254646,62317068,1957810842,3939845945,2647816111,81470997,1943803523,3814918930,2489596804,225274430,2053790376,3826175755,2466906013,167816743,2097651377,4027552580,2265490386,503444072,1762050814,4150417245,2154129355,426522225,1852507879,4275313526,2312317920,282753626,1742555852,4189708143,2394877945,397917763,1622183637,3604390888,2714866558,953729732,1340076626,3518719985,2797360999,1068828381,1219638859,3624741850,
|
||||
2936675148,906185462,1090812512,3747672003,2825379669,829329135,1181335161,3412177804,3160834842,628085408,1382605366,3423369109,3138078467,570562233,1426400815,3317316542,2998733608,733239954,1555261956,3268935591,3050360625,752459403,1541320221,2607071920,3965973030,1969922972,40735498,2617837225,3943577151,1913087877,83908371,2512341634,3803740692,2075208622,213261112,2463272603,3855990285,2094854071,198958881,2262029012,4057260610,1759359992,534414190,2176718541,4139329115,1873836001,414664567,2282248934,4279200368,1711684554,285281116,2405801727,4167216745,1634467795,376229701,2685067896,3608007406,1308918612,956543938,2808555105,3495958263,1231636301,1047427035,2932959818,3654703836,1088359270,936918000,2847714899,3736837829,1202900863,817233897,3183342108,3401237130,1404277552,615818150,3134207493,3453421203,1423857449,601450431,3009837614,3294710456,1567103746,711928724,3020668471,3272380065,1510334235,755167117};
|
||||
|
||||
int CPrepare::Prepare(const unsigned char * pRawData, int nBytes, const WAVEFORMATEX * pWaveFormatEx, int * pOutputX, int *pOutputY, unsigned int *pCRC, int *pSpecialCodes, int *pPeakLevel)
|
||||
{
|
||||
// error check the parameters
|
||||
if (pRawData == NULL || pWaveFormatEx == NULL)
|
||||
return ERROR_BAD_PARAMETER;
|
||||
|
||||
// initialize the pointers that got passed in
|
||||
*pCRC = 0xFFFFFFFF;
|
||||
*pSpecialCodes = 0;
|
||||
|
||||
// variables
|
||||
uint32 CRC = 0xFFFFFFFF;
|
||||
const int nTotalBlocks = nBytes / pWaveFormatEx->nBlockAlign;
|
||||
int R,L;
|
||||
|
||||
// the prepare code
|
||||
|
||||
if (pWaveFormatEx->wBitsPerSample == 8)
|
||||
{
|
||||
if (pWaveFormatEx->nChannels == 2)
|
||||
{
|
||||
for (int nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
R = (int) (*((unsigned char *) pRawData) - 128);
|
||||
L = (int) (*((unsigned char *) (pRawData + 1)) - 128);
|
||||
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
// check the peak
|
||||
if (labs(L) > *pPeakLevel)
|
||||
*pPeakLevel = labs(L);
|
||||
if (labs(R) > *pPeakLevel)
|
||||
*pPeakLevel = labs(R);
|
||||
|
||||
// convert to x,y
|
||||
pOutputY[nBlockIndex] = L - R;
|
||||
pOutputX[nBlockIndex] = R + (pOutputY[nBlockIndex] / 2);
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->nChannels == 1)
|
||||
{
|
||||
for (int nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
R = (int) (*((unsigned char *) pRawData) - 128);
|
||||
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
// check the peak
|
||||
if (labs(R) > *pPeakLevel)
|
||||
*pPeakLevel = labs(R);
|
||||
|
||||
// convert to x,y
|
||||
pOutputX[nBlockIndex] = R;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 24)
|
||||
{
|
||||
if (pWaveFormatEx->nChannels == 2)
|
||||
{
|
||||
for (int nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
uint32 nTemp = 0;
|
||||
|
||||
nTemp |= (*pRawData << 0);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 8);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 16);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
if (nTemp & 0x800000)
|
||||
R = (int) (nTemp & 0x7FFFFF) - 0x800000;
|
||||
else
|
||||
R = (int) (nTemp & 0x7FFFFF);
|
||||
|
||||
nTemp = 0;
|
||||
|
||||
nTemp |= (*pRawData << 0);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 8);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 16);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
if (nTemp & 0x800000)
|
||||
L = (int) (nTemp & 0x7FFFFF) - 0x800000;
|
||||
else
|
||||
L = (int) (nTemp & 0x7FFFFF);
|
||||
|
||||
// check the peak
|
||||
if (labs(L) > *pPeakLevel)
|
||||
*pPeakLevel = labs(L);
|
||||
if (labs(R) > *pPeakLevel)
|
||||
*pPeakLevel = labs(R);
|
||||
|
||||
// convert to x,y
|
||||
pOutputY[nBlockIndex] = L - R;
|
||||
pOutputX[nBlockIndex] = R + (pOutputY[nBlockIndex] / 2);
|
||||
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->nChannels == 1)
|
||||
{
|
||||
for (int nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
uint32 nTemp = 0;
|
||||
|
||||
nTemp |= (*pRawData << 0);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 8);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 16);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
if (nTemp & 0x800000)
|
||||
R = (int) (nTemp & 0x7FFFFF) - 0x800000;
|
||||
else
|
||||
R = (int) (nTemp & 0x7FFFFF);
|
||||
|
||||
// check the peak
|
||||
if (labs(R) > *pPeakLevel)
|
||||
*pPeakLevel = labs(R);
|
||||
|
||||
// convert to x,y
|
||||
pOutputX[nBlockIndex] = R;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pWaveFormatEx->nChannels == 2)
|
||||
{
|
||||
int LPeak = 0;
|
||||
int RPeak = 0;
|
||||
int nBlockIndex = 0;
|
||||
for (nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
|
||||
R = (int) *((int16 *) pRawData);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
L = (int) *((int16 *) pRawData);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
// check the peak
|
||||
if (labs(L) > LPeak)
|
||||
LPeak = labs(L);
|
||||
if (labs(R) > RPeak)
|
||||
RPeak = labs(R);
|
||||
|
||||
// convert to x,y
|
||||
pOutputY[nBlockIndex] = L - R;
|
||||
pOutputX[nBlockIndex] = R + (pOutputY[nBlockIndex] / 2);
|
||||
}
|
||||
|
||||
if (LPeak == 0) { *pSpecialCodes |= SPECIAL_FRAME_LEFT_SILENCE; }
|
||||
if (RPeak == 0) { *pSpecialCodes |= SPECIAL_FRAME_RIGHT_SILENCE; }
|
||||
if (max(LPeak, RPeak) > *pPeakLevel)
|
||||
{
|
||||
*pPeakLevel = max(LPeak, RPeak);
|
||||
}
|
||||
|
||||
// check for pseudo-stereo files
|
||||
nBlockIndex = 0;
|
||||
while (pOutputY[nBlockIndex++] == 0)
|
||||
{
|
||||
if (nBlockIndex == (nBytes / 4))
|
||||
{
|
||||
*pSpecialCodes |= SPECIAL_FRAME_PSEUDO_STEREO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (pWaveFormatEx->nChannels == 1)
|
||||
{
|
||||
int nPeak = 0;
|
||||
for (int nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
R = (int) *((int16 *) pRawData);
|
||||
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
// check the peak
|
||||
if (labs(R) > nPeak)
|
||||
nPeak = labs(R);
|
||||
|
||||
//convert to x,y
|
||||
pOutputX[nBlockIndex] = R;
|
||||
}
|
||||
|
||||
if (nPeak > *pPeakLevel)
|
||||
*pPeakLevel = nPeak;
|
||||
if (nPeak == 0) { *pSpecialCodes |= SPECIAL_FRAME_MONO_SILENCE; }
|
||||
}
|
||||
}
|
||||
|
||||
CRC = CRC ^ 0xFFFFFFFF;
|
||||
|
||||
// add the special code
|
||||
CRC >>= 1;
|
||||
|
||||
if (*pSpecialCodes != 0)
|
||||
{
|
||||
CRC |= (1 << 31);
|
||||
}
|
||||
|
||||
*pCRC = CRC;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void CPrepare::Unprepare(int X, int Y, const WAVEFORMATEX * pWaveFormatEx, unsigned char * pOutput, unsigned int * pCRC)
|
||||
{
|
||||
#define CALCULATE_CRC_BYTE *pCRC = (*pCRC >> 8) ^ CRC32_TABLE[(*pCRC & 0xFF) ^ *pOutput++];
|
||||
// decompress and convert from (x,y) -> (l,r)
|
||||
// sort of long and ugly.... sorry
|
||||
|
||||
if (pWaveFormatEx->nChannels == 2)
|
||||
{
|
||||
if (pWaveFormatEx->wBitsPerSample == 16)
|
||||
{
|
||||
// get the right and left values
|
||||
int nR = X - (Y / 2);
|
||||
int nL = nR + Y;
|
||||
|
||||
// error check (for overflows)
|
||||
if ((nR < -32768) || (nR > 32767) || (nL < -32768) || (nL > 32767))
|
||||
{
|
||||
throw(-1);
|
||||
}
|
||||
|
||||
*(int16 *) pOutput = (int16) nR;
|
||||
CALCULATE_CRC_BYTE
|
||||
CALCULATE_CRC_BYTE
|
||||
|
||||
*(int16 *) pOutput = (int16) nL;
|
||||
CALCULATE_CRC_BYTE
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 8)
|
||||
{
|
||||
unsigned char R = (X - (Y / 2) + 128);
|
||||
*pOutput = R;
|
||||
CALCULATE_CRC_BYTE
|
||||
*pOutput = (unsigned char) (R + Y);
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 24)
|
||||
{
|
||||
int32 RV, LV;
|
||||
|
||||
RV = X - (Y / 2);
|
||||
LV = RV + Y;
|
||||
|
||||
uint32 nTemp = 0;
|
||||
if (RV < 0)
|
||||
nTemp = ((uint32) (RV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (uint32) RV;
|
||||
|
||||
*pOutput = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
*pOutput = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
*pOutput = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
|
||||
nTemp = 0;
|
||||
if (LV < 0)
|
||||
nTemp = ((uint32) (LV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (uint32) LV;
|
||||
|
||||
*pOutput = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
|
||||
*pOutput = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
|
||||
*pOutput = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->nChannels == 1)
|
||||
{
|
||||
if (pWaveFormatEx->wBitsPerSample == 16)
|
||||
{
|
||||
int16 R = X;
|
||||
|
||||
*(int16 *) pOutput = (int16) R;
|
||||
CALCULATE_CRC_BYTE
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 8)
|
||||
{
|
||||
unsigned char R = X + 128;
|
||||
*pOutput = R;
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 24)
|
||||
{
|
||||
int32 RV = X;
|
||||
|
||||
uint32 nTemp = 0;
|
||||
if (RV < 0)
|
||||
nTemp = ((uint32) (RV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (uint32) RV;
|
||||
|
||||
*pOutput = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
*pOutput = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
*pOutput = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
int CPrepare::UnprepareOld(int *pInputX, int *pInputY, int nBlocks, const WAVEFORMATEX *pWaveFormatEx, unsigned char *pRawData, unsigned int *pCRC, int *pSpecialCodes, int nFileVersion)
|
||||
{
|
||||
// the CRC that will be figured during decompression
|
||||
uint32 CRC = 0xFFFFFFFF;
|
||||
|
||||
// decompress and convert from (x,y) -> (l,r)
|
||||
// sort of int and ugly.... sorry
|
||||
if (pWaveFormatEx->nChannels == 2)
|
||||
{
|
||||
// convert the x,y data to raw data
|
||||
if (pWaveFormatEx->wBitsPerSample == 16)
|
||||
{
|
||||
int16 R;
|
||||
unsigned char *Buffer = &pRawData[0];
|
||||
int *pX = pInputX;
|
||||
int *pY = pInputY;
|
||||
|
||||
for (; pX < &pInputX[nBlocks]; pX++, pY++)
|
||||
{
|
||||
R = *pX - (*pY / 2);
|
||||
|
||||
*(int16 *) Buffer = (int16) R;
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*(int16 *) Buffer = (int16) R + *pY;
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 8)
|
||||
{
|
||||
unsigned char *R = (unsigned char *) &pRawData[0];
|
||||
unsigned char *L = (unsigned char *) &pRawData[1];
|
||||
|
||||
if (nFileVersion > 3830)
|
||||
{
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++, L+=2, R+=2)
|
||||
{
|
||||
*R = (unsigned char) (pInputX[SampleIndex] - (pInputY[SampleIndex] / 2) + 128);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *R];
|
||||
*L = (unsigned char) (*R + pInputY[SampleIndex]);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *L];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++, L+=2, R+=2)
|
||||
{
|
||||
*R = (unsigned char) (pInputX[SampleIndex] - (pInputY[SampleIndex] / 2));
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *R];
|
||||
*L = (unsigned char) (*R + pInputY[SampleIndex]);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *L];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 24)
|
||||
{
|
||||
unsigned char *Buffer = (unsigned char *) &pRawData[0];
|
||||
int32 RV, LV;
|
||||
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++)
|
||||
{
|
||||
RV = pInputX[SampleIndex] - (pInputY[SampleIndex] / 2);
|
||||
LV = RV + pInputY[SampleIndex];
|
||||
|
||||
uint32 nTemp = 0;
|
||||
if (RV < 0)
|
||||
nTemp = ((uint32) (RV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (uint32) RV;
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
nTemp = 0;
|
||||
if (LV < 0)
|
||||
nTemp = ((uint32) (LV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (uint32) LV;
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->nChannels == 1)
|
||||
{
|
||||
// convert to raw data
|
||||
if (pWaveFormatEx->wBitsPerSample == 8)
|
||||
{
|
||||
unsigned char *R = (unsigned char *) &pRawData[0];
|
||||
|
||||
if (nFileVersion > 3830)
|
||||
{
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++, R++)
|
||||
{
|
||||
*R = pInputX[SampleIndex] + 128;
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *R];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++, R++)
|
||||
{
|
||||
*R = (unsigned char) (pInputX[SampleIndex]);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *R];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 24)
|
||||
{
|
||||
|
||||
unsigned char *Buffer = (unsigned char *) &pRawData[0];
|
||||
int32 RV;
|
||||
for (int SampleIndex = 0; SampleIndex<nBlocks; SampleIndex++)
|
||||
{
|
||||
RV = pInputX[SampleIndex];
|
||||
|
||||
uint32 nTemp = 0;
|
||||
if (RV < 0)
|
||||
nTemp = ((uint32) (RV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (uint32) RV;
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *Buffer = &pRawData[0];
|
||||
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++)
|
||||
{
|
||||
*(int16 *) Buffer = (int16) (pInputX[SampleIndex]);
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
CRC = (CRC >> 8) ^ CRC32_TABLE[(CRC & 0xFF) ^ *Buffer++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CRC = CRC ^ 0xFFFFFFFF;
|
||||
|
||||
*pCRC = CRC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // #ifdef BACKWARDS_COMPATIBILITY
|
||||
38
MAC_SDK/Source/MACLib/Prepare.h
Normal file
38
MAC_SDK/Source/MACLib/Prepare.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef APE_PREPARE_H
|
||||
#define APE_PREPARE_H
|
||||
|
||||
#define SPECIAL_FRAME_MONO_SILENCE 1
|
||||
#define SPECIAL_FRAME_LEFT_SILENCE 1
|
||||
#define SPECIAL_FRAME_RIGHT_SILENCE 2
|
||||
#define SPECIAL_FRAME_PSEUDO_STEREO 4
|
||||
|
||||
/*****************************************************************************
|
||||
Manage the preparation stage of compression and decompression
|
||||
|
||||
Tasks:
|
||||
|
||||
1) convert data to 32-bit
|
||||
2) convert L,R to X,Y
|
||||
3) calculate the CRC
|
||||
4) do simple analysis
|
||||
5) check for the peak value
|
||||
*****************************************************************************/
|
||||
|
||||
class IPredictorDecompress;
|
||||
|
||||
class CPrepare
|
||||
{
|
||||
public:
|
||||
|
||||
int Prepare(const unsigned char * pRawData, int nBytes, const WAVEFORMATEX * pWaveFormatEx, int * pOutputX, int * pOutputY, unsigned int * pCRC, int * pSpecialCodes, int * pPeakLevel);
|
||||
void Unprepare(int X, int Y, const WAVEFORMATEX * pWaveFormatEx, unsigned char * pOutput, unsigned int * pCRC);
|
||||
|
||||
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
int UnprepareOld(int * pInputX, int *pInputY, int nBlocks, const WAVEFORMATEX * pWaveFormatEx, unsigned char * pRawData, unsigned int * pCRC, int * pSpecialCodes, int nFileVersion);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // #ifndef APE_PREPARE_H
|
||||
31
MAC_SDK/Source/MACLib/ScaledFirstOrderFilter.h
Normal file
31
MAC_SDK/Source/MACLib/ScaledFirstOrderFilter.h
Normal file
@@ -0,0 +1,31 @@
|
||||
#ifndef APE_SCALEDFIRSTORDERFILTER_H
|
||||
#define APE_SCALEDFIRSTORDERFILTER_H
|
||||
|
||||
template <int MULTIPLY, int SHIFT> class CScaledFirstOrderFilter
|
||||
{
|
||||
public:
|
||||
|
||||
__inline void Flush()
|
||||
{
|
||||
m_nLastValue = 0;
|
||||
}
|
||||
|
||||
__inline int Compress(const int nInput)
|
||||
{
|
||||
int nRetVal = nInput - ((m_nLastValue * MULTIPLY) >> SHIFT);
|
||||
m_nLastValue = nInput;
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
__inline int Decompress(const int nInput)
|
||||
{
|
||||
m_nLastValue = nInput + ((m_nLastValue * MULTIPLY) >> SHIFT);
|
||||
return m_nLastValue;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
int m_nLastValue;
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_SCALEDFIRSTORDERFILTER_H
|
||||
178
MAC_SDK/Source/MACLib/StartFilter.h
Normal file
178
MAC_SDK/Source/MACLib/StartFilter.h
Normal file
@@ -0,0 +1,178 @@
|
||||
#ifndef APE_START_FILTER_H
|
||||
#define APE_START_FILTER_H
|
||||
|
||||
class CStartFilter
|
||||
{
|
||||
public:
|
||||
|
||||
CStartFilter()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
~CStartFilter()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Flush()
|
||||
{
|
||||
m_rbInputA.Flush();
|
||||
m_rbInputB.Flush();
|
||||
|
||||
memset(m_aryMA, 0, sizeof(m_aryMA));
|
||||
memset(m_aryMB, 0, sizeof(m_aryMB));
|
||||
|
||||
m_Stage1FilterA1.Flush();
|
||||
m_Stage1FilterA2.Flush();
|
||||
m_Stage1FilterA3.Flush();
|
||||
|
||||
m_Stage1FilterB1.Flush();
|
||||
m_Stage1FilterB2.Flush();
|
||||
m_Stage1FilterB3.Flush();
|
||||
}
|
||||
|
||||
void Compress(int & nA, int & nB)
|
||||
{
|
||||
/*
|
||||
nA = m_Stage1FilterA1.Compress(nA);
|
||||
nA = m_Stage1FilterA2.Compress(nA);
|
||||
nA = m_Stage1FilterA3.Compress(nA);
|
||||
|
||||
nB = m_Stage1FilterB1.Compress(nB);
|
||||
nB = m_Stage1FilterB2.Compress(nB);
|
||||
nB = m_Stage1FilterB3.Compress(nB);
|
||||
return;
|
||||
//*/
|
||||
|
||||
nA = m_Stage1FilterA1.Compress(nA);
|
||||
nA = m_Stage1FilterA2.Compress(nA);
|
||||
// nA = m_Stage1FilterA3.Compress(nA);
|
||||
|
||||
nB = m_Stage1FilterB1.Compress(nB);
|
||||
nB = m_Stage1FilterB2.Compress(nB);
|
||||
|
||||
//int nTemp = nA; nA = nB; nB = nTemp;
|
||||
// nB = m_Stage1FilterB3.Compress(nB);
|
||||
|
||||
// nA = nA - nB;
|
||||
// nB = nB + (nA / 2);
|
||||
|
||||
|
||||
// return;
|
||||
|
||||
m_rbInputA[0] = nA; m_rbInputB[0] = nB;
|
||||
|
||||
{
|
||||
int nPrediction1 = m_rbInputA[-1];
|
||||
int nPrediction2 = m_rbInputA[-2];
|
||||
int nPrediction3 = m_rbInputA[-1] - m_rbInputA[-2];
|
||||
int nPrediction4 = m_rbInputB[-1];
|
||||
|
||||
int nTotalPrediction = (nPrediction1 * m_aryMA[0]) + (nPrediction2 * m_aryMA[1])
|
||||
+ (nPrediction3 * m_aryMA[2]) + (nPrediction4 * m_aryMA[3]);
|
||||
int nOutput = nA - (nTotalPrediction >> 13);
|
||||
|
||||
if (nOutput > 0)
|
||||
{
|
||||
m_aryMA[0] -= 2*((nPrediction1) ? ((nPrediction1 >> 30) & 2) - 1 : 0);
|
||||
m_aryMA[1] -= (nPrediction2) ? ((nPrediction2 >> 30) & 2) - 1 : 0;
|
||||
m_aryMA[2] -= (nPrediction3) ? ((nPrediction3 >> 30) & 2) - 1 : 0;
|
||||
m_aryMA[3] -= 1*((nPrediction4) ? ((nPrediction4 >> 30) & 2) - 1 : 0);
|
||||
}
|
||||
else if (nOutput < 0)
|
||||
{
|
||||
m_aryMA[0] += 2*((nPrediction1) ? ((nPrediction1 >> 30) & 2) - 1 : 0);
|
||||
m_aryMA[1] += (nPrediction2) ? ((nPrediction2 >> 30) & 2) - 1 : 0;
|
||||
m_aryMA[2] += (nPrediction3) ? ((nPrediction3 >> 30) & 2) - 1 : 0;
|
||||
m_aryMA[3] += 1*((nPrediction4) ? ((nPrediction4 >> 30) & 2) - 1 : 0);
|
||||
}
|
||||
|
||||
nA = nOutput;
|
||||
}
|
||||
{
|
||||
int nPrediction1 = m_rbInputB[-1];
|
||||
int nPrediction2 = m_rbInputB[-2];
|
||||
int nPrediction3 = 0;//m_rbInputB[-1] - m_rbInputB[-2];
|
||||
int nPrediction4 = m_rbInputA[0];
|
||||
|
||||
int nTotalPrediction = (nPrediction1 * m_aryMB[0]) + (nPrediction2 * m_aryMB[1])
|
||||
+ (nPrediction3 * m_aryMB[2]) + (nPrediction4 * m_aryMB[3]);
|
||||
int nOutput = nB - (nTotalPrediction >> 13);
|
||||
|
||||
if (nOutput > 0)
|
||||
{
|
||||
m_aryMB[0] -= 2*((nPrediction1) ? ((nPrediction1 >> 30) & 2) - 1 : 0);
|
||||
m_aryMB[1] -= (nPrediction2) ? ((nPrediction2 >> 30) & 2) - 1 : 0;
|
||||
m_aryMB[2] -= (nPrediction3) ? ((nPrediction3 >> 30) & 2) - 1 : 0;
|
||||
m_aryMB[3] -= 1*((nPrediction4) ? ((nPrediction4 >> 30) & 2) - 1 : 0);
|
||||
}
|
||||
else if (nOutput < 0)
|
||||
{
|
||||
m_aryMB[0] += 2*((nPrediction1) ? ((nPrediction1 >> 30) & 2) - 1 : 0);
|
||||
m_aryMB[1] += (nPrediction2) ? ((nPrediction2 >> 30) & 2) - 1 : 0;
|
||||
m_aryMB[2] += (nPrediction3) ? ((nPrediction3 >> 30) & 2) - 1 : 0;
|
||||
m_aryMB[3] += 1*((nPrediction4) ? ((nPrediction4 >> 30) & 2) - 1 : 0);
|
||||
}
|
||||
|
||||
nB = nOutput;
|
||||
}
|
||||
|
||||
|
||||
m_rbInputA.IncrementSafe();
|
||||
m_rbInputB.IncrementSafe();
|
||||
|
||||
|
||||
/*
|
||||
// nInput = m_Filter1.Compress(nInput);
|
||||
|
||||
m_rbInput[0] = nInput;
|
||||
|
||||
int nPrediction1 = m_rbInput[-1];
|
||||
int nPrediction2 = (2 * m_rbInput[-1]) - m_rbInput[-2];
|
||||
int nPrediction3 = m_rbInput[-1] - m_rbInput[-2];
|
||||
int nPrediction4 = m_nLastOutput;
|
||||
|
||||
int nTotalPrediction = ((nPrediction1) * m_aryM[0]) + (nPrediction2 * m_aryM[1])
|
||||
+ ((nPrediction3 >> 1) * m_aryM[2]) + (nPrediction4 * m_aryM[3]);
|
||||
int nOutput = nInput - (nTotalPrediction >> 13);
|
||||
|
||||
if (nOutput > 0)
|
||||
{
|
||||
m_aryM[0] -= (nPrediction1) ? ((nPrediction1 >> 30) & 2) - 1 : 0;
|
||||
m_aryM[1] -= (nPrediction2) ? ((nPrediction2 >> 30) & 2) - 1 : 0;
|
||||
m_aryM[2] -= (nPrediction3) ? ((nPrediction3 >> 30) & 2) - 1 : 0;
|
||||
m_aryM[3] -= (nPrediction4) ? ((nPrediction4 >> 30) & 2) - 1 : 0;
|
||||
}
|
||||
else if (nOutput < 0)
|
||||
{
|
||||
m_aryM[0] += (nPrediction1) ? ((nPrediction1 >> 30) & 2) - 1 : 0;
|
||||
m_aryM[1] += (nPrediction2) ? ((nPrediction2 >> 30) & 2) - 1 : 0;
|
||||
m_aryM[2] += (nPrediction3) ? ((nPrediction3 >> 30) & 2) - 1 : 0;
|
||||
m_aryM[3] += (nPrediction4) ? ((nPrediction4 >> 30) & 2) - 1 : 0;
|
||||
}
|
||||
|
||||
m_nLastOutput = nOutput;
|
||||
m_rbInput.IncrementSafe();
|
||||
|
||||
return nOutput;
|
||||
//*/
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
CScaledFirstOrderFilter<31, 5> m_Stage1FilterA1;
|
||||
CScaledFirstOrderFilter<24, 5> m_Stage1FilterA2;
|
||||
CScaledFirstOrderFilter<7, 5> m_Stage1FilterA3;
|
||||
|
||||
CScaledFirstOrderFilter<31, 5> m_Stage1FilterB1;
|
||||
CScaledFirstOrderFilter<24, 5> m_Stage1FilterB2;
|
||||
CScaledFirstOrderFilter<7, 5> m_Stage1FilterB3;
|
||||
|
||||
CRollBufferFast<int, 256, 4> m_rbInputA;
|
||||
CRollBufferFast<int, 256, 4> m_rbInputB;
|
||||
int m_aryMA[8]; int m_aryMB[8];
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_START_FILTER_H
|
||||
293
MAC_SDK/Source/MACLib/UnBitArray.cpp
Normal file
293
MAC_SDK/Source/MACLib/UnBitArray.cpp
Normal file
@@ -0,0 +1,293 @@
|
||||
#include "All.h"
|
||||
#include "APEInfo.h"
|
||||
#include "UnBitArray.h"
|
||||
#include "BitArray.h"
|
||||
|
||||
const uint32 POWERS_OF_TWO_MINUS_ONE_REVERSED[33] = {4294967295,2147483647,1073741823,536870911,268435455,134217727,67108863,33554431,16777215,8388607,4194303,2097151,1048575,524287,262143,131071,65535,32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0};
|
||||
|
||||
const uint32 K_SUM_MIN_BOUNDARY[32] = {0,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648,0,0,0,0};
|
||||
|
||||
const uint32 RANGE_TOTAL_1[65] = {0,14824,28224,39348,47855,53994,58171,60926,62682,63786,64463,64878,65126,65276,65365,65419,65450,65469,65480,65487,65491,65493,65494,65495,65496,65497,65498,65499,65500,65501,65502,65503,65504,65505,65506,65507,65508,65509,65510,65511,65512,65513,65514,65515,65516,65517,65518,65519,65520,65521,65522,65523,65524,65525,65526,65527,65528,65529,65530,65531,65532,65533,65534,65535,65536};
|
||||
const uint32 RANGE_WIDTH_1[64] = {14824,13400,11124,8507,6139,4177,2755,1756,1104,677,415,248,150,89,54,31,19,11,7,4,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
|
||||
|
||||
const uint32 RANGE_TOTAL_2[65] = {0,19578,36160,48417,56323,60899,63265,64435,64971,65232,65351,65416,65447,65466,65476,65482,65485,65488,65490,65491,65492,65493,65494,65495,65496,65497,65498,65499,65500,65501,65502,65503,65504,65505,65506,65507,65508,65509,65510,65511,65512,65513,65514,65515,65516,65517,65518,65519,65520,65521,65522,65523,65524,65525,65526,65527,65528,65529,65530,65531,65532,65533,65534,65535,65536};
|
||||
const uint32 RANGE_WIDTH_2[64] = {19578,16582,12257,7906,4576,2366,1170,536,261,119,65,31,19,10,6,3,3,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,};
|
||||
|
||||
#define RANGE_OVERFLOW_TOTAL_WIDTH 65536
|
||||
#define RANGE_OVERFLOW_SHIFT 16
|
||||
|
||||
#define CODE_BITS 32
|
||||
#define TOP_VALUE ((unsigned int ) 1 << (CODE_BITS - 1))
|
||||
#define SHIFT_BITS (CODE_BITS - 9)
|
||||
#define EXTRA_BITS ((CODE_BITS - 2) % 8 + 1)
|
||||
#define BOTTOM_VALUE (TOP_VALUE >> 8)
|
||||
|
||||
#define MODEL_ELEMENTS 64
|
||||
|
||||
/***********************************************************************************
|
||||
Construction
|
||||
***********************************************************************************/
|
||||
CUnBitArray::CUnBitArray(CIO * pIO, int nVersion)
|
||||
{
|
||||
CreateHelper(pIO, 16384, nVersion);
|
||||
m_nFlushCounter = 0;
|
||||
m_nFinalizeCounter = 0;
|
||||
}
|
||||
|
||||
CUnBitArray::~CUnBitArray()
|
||||
{
|
||||
SAFE_ARRAY_DELETE(m_pBitArray)
|
||||
}
|
||||
|
||||
unsigned int CUnBitArray::DecodeValue(DECODE_VALUE_METHOD DecodeMethod, int nParam1, int nParam2)
|
||||
{
|
||||
switch (DecodeMethod)
|
||||
{
|
||||
case DECODE_VALUE_METHOD_UNSIGNED_INT:
|
||||
return DecodeValueXBits(32);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CUnBitArray::GenerateArray(int * pOutputArray, int nElements, int nBytesRequired)
|
||||
{
|
||||
GenerateArrayRange(pOutputArray, nElements);
|
||||
}
|
||||
|
||||
__inline unsigned char CUnBitArray::GetC()
|
||||
{
|
||||
unsigned char nValue = (unsigned char) (m_pBitArray[m_nCurrentBitIndex >> 5] >> (24 - (m_nCurrentBitIndex & 31)));
|
||||
m_nCurrentBitIndex += 8;
|
||||
return nValue;
|
||||
}
|
||||
|
||||
__inline int CUnBitArray::RangeDecodeFast(int nShift)
|
||||
{
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE)
|
||||
{
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.buffer << 8) | ((m_pBitArray[m_nCurrentBitIndex >> 5] >> (24 - (m_nCurrentBitIndex & 31))) & 0xFF);
|
||||
m_nCurrentBitIndex += 8;
|
||||
m_RangeCoderInfo.low = (m_RangeCoderInfo.low << 8) | ((m_RangeCoderInfo.buffer >> 1) & 0xFF);
|
||||
m_RangeCoderInfo.range <<= 8;
|
||||
}
|
||||
|
||||
// decode
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range >> nShift;
|
||||
return m_RangeCoderInfo.low / m_RangeCoderInfo.range;
|
||||
}
|
||||
|
||||
__inline int CUnBitArray::RangeDecodeFastWithUpdate(int nShift)
|
||||
{
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE)
|
||||
{
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.buffer << 8) | ((m_pBitArray[m_nCurrentBitIndex >> 5] >> (24 - (m_nCurrentBitIndex & 31))) & 0xFF);
|
||||
m_nCurrentBitIndex += 8;
|
||||
m_RangeCoderInfo.low = (m_RangeCoderInfo.low << 8) | ((m_RangeCoderInfo.buffer >> 1) & 0xFF);
|
||||
m_RangeCoderInfo.range <<= 8;
|
||||
}
|
||||
|
||||
// decode
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range >> nShift;
|
||||
int nRetVal = m_RangeCoderInfo.low / m_RangeCoderInfo.range;
|
||||
m_RangeCoderInfo.low -= m_RangeCoderInfo.range * nRetVal;
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CUnBitArray::DecodeValueRange(UNBIT_ARRAY_STATE & BitArrayState)
|
||||
{
|
||||
// make sure there is room for the data
|
||||
// this is a little slower than ensuring a huge block to start with, but it's safer
|
||||
if (m_nCurrentBitIndex > m_nRefillBitThreshold)
|
||||
{
|
||||
FillBitArray();
|
||||
}
|
||||
|
||||
int nValue = 0;
|
||||
|
||||
if (m_nVersion >= 3990)
|
||||
{
|
||||
// figure the pivot value
|
||||
int nPivotValue = max(BitArrayState.nKSum / 32, 1);
|
||||
|
||||
// get the overflow
|
||||
int nOverflow = 0;
|
||||
{
|
||||
// decode
|
||||
int nRangeTotal = RangeDecodeFast(RANGE_OVERFLOW_SHIFT);
|
||||
|
||||
// lookup the symbol (must be a faster way than this)
|
||||
while (nRangeTotal >= RANGE_TOTAL_2[nOverflow + 1]) { nOverflow++; }
|
||||
|
||||
// update
|
||||
m_RangeCoderInfo.low -= m_RangeCoderInfo.range * RANGE_TOTAL_2[nOverflow];
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range * RANGE_WIDTH_2[nOverflow];
|
||||
|
||||
// get the working k
|
||||
if (nOverflow == (MODEL_ELEMENTS - 1))
|
||||
{
|
||||
nOverflow = RangeDecodeFastWithUpdate(16);
|
||||
nOverflow <<= 16;
|
||||
nOverflow |= RangeDecodeFastWithUpdate(16);
|
||||
}
|
||||
}
|
||||
|
||||
// get the value
|
||||
int nBase = 0;
|
||||
{
|
||||
int nShift = 0;
|
||||
if (nPivotValue >= (1 << 16))
|
||||
{
|
||||
int nPivotValueBits = 0;
|
||||
while ((nPivotValue >> nPivotValueBits) > 0) { nPivotValueBits++; }
|
||||
int nSplitFactor = 1 << (nPivotValueBits - 16);
|
||||
|
||||
int nPivotValueA = (nPivotValue / nSplitFactor) + 1;
|
||||
int nPivotValueB = nSplitFactor;
|
||||
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE)
|
||||
{
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.buffer << 8) | ((m_pBitArray[m_nCurrentBitIndex >> 5] >> (24 - (m_nCurrentBitIndex & 31))) & 0xFF);
|
||||
m_nCurrentBitIndex += 8;
|
||||
m_RangeCoderInfo.low = (m_RangeCoderInfo.low << 8) | ((m_RangeCoderInfo.buffer >> 1) & 0xFF);
|
||||
m_RangeCoderInfo.range <<= 8;
|
||||
}
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range / nPivotValueA;
|
||||
int nBaseA = m_RangeCoderInfo.low / m_RangeCoderInfo.range;
|
||||
m_RangeCoderInfo.low -= m_RangeCoderInfo.range * nBaseA;
|
||||
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE)
|
||||
{
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.buffer << 8) | ((m_pBitArray[m_nCurrentBitIndex >> 5] >> (24 - (m_nCurrentBitIndex & 31))) & 0xFF);
|
||||
m_nCurrentBitIndex += 8;
|
||||
m_RangeCoderInfo.low = (m_RangeCoderInfo.low << 8) | ((m_RangeCoderInfo.buffer >> 1) & 0xFF);
|
||||
m_RangeCoderInfo.range <<= 8;
|
||||
}
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range / nPivotValueB;
|
||||
int nBaseB = m_RangeCoderInfo.low / m_RangeCoderInfo.range;
|
||||
m_RangeCoderInfo.low -= m_RangeCoderInfo.range * nBaseB;
|
||||
|
||||
nBase = nBaseA * nSplitFactor + nBaseB;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE)
|
||||
{
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.buffer << 8) | ((m_pBitArray[m_nCurrentBitIndex >> 5] >> (24 - (m_nCurrentBitIndex & 31))) & 0xFF);
|
||||
m_nCurrentBitIndex += 8;
|
||||
m_RangeCoderInfo.low = (m_RangeCoderInfo.low << 8) | ((m_RangeCoderInfo.buffer >> 1) & 0xFF);
|
||||
m_RangeCoderInfo.range <<= 8;
|
||||
}
|
||||
|
||||
// decode
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range / nPivotValue;
|
||||
int nBaseLower = m_RangeCoderInfo.low / m_RangeCoderInfo.range;
|
||||
m_RangeCoderInfo.low -= m_RangeCoderInfo.range * nBaseLower;
|
||||
|
||||
nBase = nBaseLower;
|
||||
}
|
||||
}
|
||||
|
||||
// build the value
|
||||
nValue = nBase + (nOverflow * nPivotValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// decode
|
||||
int nRangeTotal = RangeDecodeFast(RANGE_OVERFLOW_SHIFT);
|
||||
|
||||
// lookup the symbol (must be a faster way than this)
|
||||
int nOverflow = 0;
|
||||
while (nRangeTotal >= RANGE_TOTAL_1[nOverflow + 1]) { nOverflow++; }
|
||||
|
||||
// update
|
||||
m_RangeCoderInfo.low -= m_RangeCoderInfo.range * RANGE_TOTAL_1[nOverflow];
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range * RANGE_WIDTH_1[nOverflow];
|
||||
|
||||
// get the working k
|
||||
int nTempK;
|
||||
if (nOverflow == (MODEL_ELEMENTS - 1))
|
||||
{
|
||||
nTempK = RangeDecodeFastWithUpdate(5);
|
||||
nOverflow = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nTempK = (BitArrayState.k < 1) ? 0 : BitArrayState.k - 1;
|
||||
}
|
||||
|
||||
// figure the extra bits on the left and the left value
|
||||
if (nTempK <= 16 || m_nVersion < 3910)
|
||||
{
|
||||
nValue = RangeDecodeFastWithUpdate(nTempK);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nX1 = RangeDecodeFastWithUpdate(16);
|
||||
int nX2 = RangeDecodeFastWithUpdate(nTempK - 16);
|
||||
nValue = nX1 | (nX2 << 16);
|
||||
}
|
||||
|
||||
// build the value and output it
|
||||
nValue += (nOverflow << nTempK);
|
||||
}
|
||||
|
||||
// update nKSum
|
||||
BitArrayState.nKSum += ((nValue + 1) / 2) - ((BitArrayState.nKSum + 16) >> 5);
|
||||
|
||||
// update k
|
||||
if (BitArrayState.nKSum < K_SUM_MIN_BOUNDARY[BitArrayState.k])
|
||||
BitArrayState.k--;
|
||||
else if (BitArrayState.nKSum >= K_SUM_MIN_BOUNDARY[BitArrayState.k + 1])
|
||||
BitArrayState.k++;
|
||||
|
||||
// output the value (converted to signed)
|
||||
return (nValue & 1) ? (nValue >> 1) + 1 : -(nValue >> 1);
|
||||
}
|
||||
|
||||
void CUnBitArray::FlushState(UNBIT_ARRAY_STATE & BitArrayState)
|
||||
{
|
||||
BitArrayState.k = 10;
|
||||
BitArrayState.nKSum = (1 << BitArrayState.k) * 16;
|
||||
}
|
||||
|
||||
void CUnBitArray::FlushBitArray()
|
||||
{
|
||||
AdvanceToByteBoundary();
|
||||
m_nCurrentBitIndex += 8; // ignore the first byte... (slows compression too much to not output this dummy byte)
|
||||
m_RangeCoderInfo.buffer = GetC();
|
||||
m_RangeCoderInfo.low = m_RangeCoderInfo.buffer >> (8 - EXTRA_BITS);
|
||||
m_RangeCoderInfo.range = (unsigned int) 1 << EXTRA_BITS;
|
||||
|
||||
m_nRefillBitThreshold = (m_nBits - 512);
|
||||
}
|
||||
|
||||
void CUnBitArray::Finalize()
|
||||
{
|
||||
// normalize
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE)
|
||||
{
|
||||
m_nCurrentBitIndex += 8;
|
||||
m_RangeCoderInfo.range <<= 8;
|
||||
}
|
||||
|
||||
// used to back-pedal the last two bytes out
|
||||
// this should never have been a problem because we've outputted and normalized beforehand
|
||||
// but stopped doing it as of 3.96 in case it accounted for rare decompression failures
|
||||
if (m_nVersion <= 3950)
|
||||
m_nCurrentBitIndex -= 16;
|
||||
}
|
||||
|
||||
void CUnBitArray::GenerateArrayRange(int * pOutputArray, int nElements)
|
||||
{
|
||||
UNBIT_ARRAY_STATE BitArrayState;
|
||||
FlushState(BitArrayState);
|
||||
FlushBitArray();
|
||||
|
||||
for (int z = 0; z < nElements; z++)
|
||||
{
|
||||
pOutputArray[z] = DecodeValueRange(BitArrayState);
|
||||
}
|
||||
|
||||
Finalize();
|
||||
}
|
||||
51
MAC_SDK/Source/MACLib/UnBitArray.h
Normal file
51
MAC_SDK/Source/MACLib/UnBitArray.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef APE_UNBITARRAY_H
|
||||
#define APE_UNBITARRAY_H
|
||||
|
||||
#include "UnBitArrayBase.h"
|
||||
|
||||
class IAPEDecompress;
|
||||
|
||||
struct RANGE_CODER_STRUCT_DECOMPRESS
|
||||
{
|
||||
unsigned int low; // low end of interval
|
||||
unsigned int range; // length of interval
|
||||
unsigned int buffer; // buffer for input/output
|
||||
};
|
||||
|
||||
class CUnBitArray : public CUnBitArrayBase
|
||||
{
|
||||
public:
|
||||
|
||||
// construction/destruction
|
||||
CUnBitArray(CIO * pIO, int nVersion);
|
||||
~CUnBitArray();
|
||||
|
||||
unsigned int DecodeValue(DECODE_VALUE_METHOD DecodeMethod, int nParam1 = 0, int nParam2 = 0);
|
||||
|
||||
void GenerateArray(int * pOutputArray, int nElements, int nBytesRequired = -1);
|
||||
|
||||
int DecodeValueRange(UNBIT_ARRAY_STATE & BitArrayState);
|
||||
|
||||
void FlushState(UNBIT_ARRAY_STATE & BitArrayState);
|
||||
void FlushBitArray();
|
||||
void Finalize();
|
||||
|
||||
private:
|
||||
|
||||
void GenerateArrayRange(int * pOutputArray, int nElements);
|
||||
|
||||
// data
|
||||
int m_nFlushCounter;
|
||||
int m_nFinalizeCounter;
|
||||
|
||||
RANGE_CODER_STRUCT_DECOMPRESS m_RangeCoderInfo;
|
||||
|
||||
uint32 m_nRefillBitThreshold;
|
||||
|
||||
// functions
|
||||
inline int RangeDecodeFast(int nShift);
|
||||
inline int RangeDecodeFastWithUpdate(int nShift);
|
||||
inline unsigned char GetC();
|
||||
};
|
||||
|
||||
#endif // #ifndef APE_UNBITARRAY_H
|
||||
112
MAC_SDK/Source/MACLib/UnBitArrayBase.cpp
Normal file
112
MAC_SDK/Source/MACLib/UnBitArrayBase.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "All.h"
|
||||
#include "UnBitArrayBase.h"
|
||||
#include "APEInfo.h"
|
||||
#include "UnBitArray.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
#include "Old/APEDecompressOld.h"
|
||||
#include "Old/UnBitArrayOld.h"
|
||||
#endif
|
||||
|
||||
const uint32 POWERS_OF_TWO_MINUS_ONE[33] = {0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535,131071,262143,524287,1048575,2097151,4194303,8388607,16777215,33554431,67108863,134217727,268435455,536870911,1073741823,2147483647,4294967295};
|
||||
|
||||
CUnBitArrayBase * CreateUnBitArray(IAPEDecompress * pAPEDecompress, int nVersion)
|
||||
{
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
if (nVersion >= 3900)
|
||||
return (CUnBitArrayBase * ) new CUnBitArray(GET_IO(pAPEDecompress), nVersion);
|
||||
else
|
||||
return (CUnBitArrayBase * ) new CUnBitArrayOld(pAPEDecompress, nVersion);
|
||||
#else
|
||||
return (CUnBitArrayBase * ) new CUnBitArray(GET_IO(pAPEDecompress), nVersion);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CUnBitArrayBase::AdvanceToByteBoundary()
|
||||
{
|
||||
int nMod = m_nCurrentBitIndex % 8;
|
||||
if (nMod != 0) { m_nCurrentBitIndex += 8 - nMod; }
|
||||
}
|
||||
|
||||
uint32 CUnBitArrayBase::DecodeValueXBits(uint32 nBits)
|
||||
{
|
||||
// get more data if necessary
|
||||
if ((m_nCurrentBitIndex + nBits) >= m_nBits)
|
||||
FillBitArray();
|
||||
|
||||
// variable declares
|
||||
uint32 nLeftBits = 32 - (m_nCurrentBitIndex & 31);
|
||||
uint32 nBitArrayIndex = m_nCurrentBitIndex >> 5;
|
||||
m_nCurrentBitIndex += nBits;
|
||||
|
||||
// if their isn't an overflow to the right value, get the value and exit
|
||||
if (nLeftBits >= nBits)
|
||||
return (m_pBitArray[nBitArrayIndex] & (POWERS_OF_TWO_MINUS_ONE[nLeftBits])) >> (nLeftBits - nBits);
|
||||
|
||||
// must get the "split" value from left and right
|
||||
int nRightBits = nBits - nLeftBits;
|
||||
|
||||
uint32 nLeftValue = ((m_pBitArray[nBitArrayIndex] & POWERS_OF_TWO_MINUS_ONE[nLeftBits]) << nRightBits);
|
||||
uint32 nRightValue = (m_pBitArray[nBitArrayIndex + 1] >> (32 - nRightBits));
|
||||
return (nLeftValue | nRightValue);
|
||||
}
|
||||
|
||||
int CUnBitArrayBase::FillAndResetBitArray(int nFileLocation, int nNewBitIndex)
|
||||
{
|
||||
// reset the bit index
|
||||
m_nCurrentBitIndex = nNewBitIndex;
|
||||
|
||||
// seek if necessary
|
||||
if (nFileLocation != -1)
|
||||
{
|
||||
if (m_pIO->Seek(nFileLocation, FILE_BEGIN) != 0)
|
||||
return ERROR_IO_READ;
|
||||
}
|
||||
|
||||
// read the new data into the bit array
|
||||
unsigned int nBytesRead = 0;
|
||||
if (m_pIO->Read(((unsigned char *) m_pBitArray), m_nBytes, &nBytesRead) != 0)
|
||||
return ERROR_IO_READ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CUnBitArrayBase::FillBitArray()
|
||||
{
|
||||
// get the bit array index
|
||||
uint32 nBitArrayIndex = m_nCurrentBitIndex >> 5;
|
||||
|
||||
// move the remaining data to the front
|
||||
memmove((void *) (m_pBitArray), (const void *) (m_pBitArray + nBitArrayIndex), m_nBytes - (nBitArrayIndex * 4));
|
||||
|
||||
// read the new data
|
||||
int nBytesToRead = nBitArrayIndex * 4;
|
||||
unsigned int nBytesRead = 0;
|
||||
int nRetVal = m_pIO->Read((unsigned char *) (m_pBitArray + m_nElements - nBitArrayIndex), nBytesToRead, &nBytesRead);
|
||||
|
||||
// adjust the m_Bit pointer
|
||||
m_nCurrentBitIndex = m_nCurrentBitIndex & 31;
|
||||
|
||||
// return
|
||||
return (nRetVal == 0) ? 0 : ERROR_IO_READ;
|
||||
}
|
||||
|
||||
int CUnBitArrayBase::CreateHelper(CIO * pIO, int nBytes, int nVersion)
|
||||
{
|
||||
// check the parameters
|
||||
if ((pIO == NULL) || (nBytes <= 0)) { return ERROR_BAD_PARAMETER; }
|
||||
|
||||
// save the size
|
||||
m_nElements = nBytes / 4;
|
||||
m_nBytes = m_nElements * 4;
|
||||
m_nBits = m_nBytes * 8;
|
||||
|
||||
// set the variables
|
||||
m_pIO = pIO;
|
||||
m_nVersion = nVersion;
|
||||
m_nCurrentBitIndex = 0;
|
||||
|
||||
// create the bitarray
|
||||
m_pBitArray = new uint32 [m_nElements];
|
||||
|
||||
return (m_pBitArray != NULL) ? 0 : ERROR_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
59
MAC_SDK/Source/MACLib/UnBitArrayBase.h
Normal file
59
MAC_SDK/Source/MACLib/UnBitArrayBase.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef APE_UNBITARRAYBASE_H
|
||||
#define APE_UNBITARRAYBASE_H
|
||||
|
||||
class IAPEDecompress;
|
||||
class CIO;
|
||||
|
||||
struct UNBIT_ARRAY_STATE
|
||||
{
|
||||
uint32 k;
|
||||
uint32 nKSum;
|
||||
};
|
||||
|
||||
enum DECODE_VALUE_METHOD
|
||||
{
|
||||
DECODE_VALUE_METHOD_UNSIGNED_INT,
|
||||
DECODE_VALUE_METHOD_UNSIGNED_RICE,
|
||||
DECODE_VALUE_METHOD_X_BITS
|
||||
};
|
||||
|
||||
class CUnBitArrayBase
|
||||
{
|
||||
public:
|
||||
|
||||
// virtual destructor
|
||||
virtual ~CUnBitArrayBase() {}
|
||||
|
||||
// functions
|
||||
virtual int FillBitArray();
|
||||
virtual int FillAndResetBitArray(int nFileLocation = -1, int nNewBitIndex = 0);
|
||||
|
||||
virtual void GenerateArray(int * pOutputArray, int nElements, int nBytesRequired = -1) {}
|
||||
virtual unsigned int DecodeValue(DECODE_VALUE_METHOD DecodeMethod, int nParam1 = 0, int nParam2 = 0) { return 0; }
|
||||
|
||||
virtual void AdvanceToByteBoundary();
|
||||
|
||||
virtual int DecodeValueRange(UNBIT_ARRAY_STATE & BitArrayState) { return 0; }
|
||||
virtual void FlushState(UNBIT_ARRAY_STATE & BitArrayState) {}
|
||||
virtual void FlushBitArray() {}
|
||||
virtual void Finalize() {}
|
||||
|
||||
protected:
|
||||
|
||||
virtual int CreateHelper(CIO * pIO, int nBytes, int nVersion);
|
||||
virtual uint32 DecodeValueXBits(uint32 nBits);
|
||||
|
||||
uint32 m_nElements;
|
||||
uint32 m_nBytes;
|
||||
uint32 m_nBits;
|
||||
|
||||
int m_nVersion;
|
||||
CIO * m_pIO;
|
||||
|
||||
uint32 m_nCurrentBitIndex;
|
||||
uint32 * m_pBitArray;
|
||||
};
|
||||
|
||||
CUnBitArrayBase * CreateUnBitArray(IAPEDecompress * pAPEDecompress, int nVersion);
|
||||
|
||||
#endif // #ifndef APE_UNBITARRAYBASE_H
|
||||
279
MAC_SDK/Source/MACLib/WAVInputSource.cpp
Normal file
279
MAC_SDK/Source/MACLib/WAVInputSource.cpp
Normal file
@@ -0,0 +1,279 @@
|
||||
#include "All.h"
|
||||
#include "WAVInputSource.h"
|
||||
#include IO_HEADER_FILE
|
||||
#include "MACLib.h"
|
||||
#include "GlobalFunctions.h"
|
||||
|
||||
struct RIFF_HEADER
|
||||
{
|
||||
char cRIFF[4]; // the characters 'RIFF' indicating that it's a RIFF file
|
||||
unsigned long nBytes; // the number of bytes following this header
|
||||
};
|
||||
|
||||
struct DATA_TYPE_ID_HEADER
|
||||
{
|
||||
char cDataTypeID[4]; // should equal 'WAVE' for a WAV file
|
||||
};
|
||||
|
||||
struct WAV_FORMAT_HEADER
|
||||
{
|
||||
unsigned short nFormatTag; // the format of the WAV...should equal 1 for a PCM file
|
||||
unsigned short nChannels; // the number of channels
|
||||
unsigned long nSamplesPerSecond; // the number of samples per second
|
||||
unsigned long nBytesPerSecond; // the bytes per second
|
||||
unsigned short nBlockAlign; // block alignment
|
||||
unsigned short nBitsPerSample; // the number of bits per sample
|
||||
};
|
||||
|
||||
struct RIFF_CHUNK_HEADER
|
||||
{
|
||||
char cChunkLabel[4]; // should equal "data" indicating the data chunk
|
||||
unsigned long nChunkBytes; // the bytes of the chunk
|
||||
};
|
||||
|
||||
|
||||
CInputSource * CreateInputSource(const wchar_t * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
|
||||
{
|
||||
// error check the parameters
|
||||
if ((pSourceName == NULL) || (wcslen(pSourceName) == 0))
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// get the extension
|
||||
const wchar_t * pExtension = &pSourceName[wcslen(pSourceName)];
|
||||
while ((pExtension > pSourceName) && (*pExtension != '.'))
|
||||
pExtension--;
|
||||
|
||||
// create the proper input source
|
||||
if (wcsicmp(pExtension, L".wav") == 0)
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_SUCCESS;
|
||||
return new CWAVInputSource(pSourceName, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CWAVInputSource::CWAVInputSource(CIO * pIO, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
|
||||
: CInputSource(pIO, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode)
|
||||
{
|
||||
m_bIsValid = FALSE;
|
||||
|
||||
if (pIO == NULL || pwfeSource == NULL)
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
m_spIO.Assign(pIO, FALSE, FALSE);
|
||||
|
||||
int nRetVal = AnalyzeSource();
|
||||
if (nRetVal == ERROR_SUCCESS)
|
||||
{
|
||||
// fill in the parameters
|
||||
if (pwfeSource) memcpy(pwfeSource, &m_wfeSource, sizeof(WAVEFORMATEX));
|
||||
if (pTotalBlocks) *pTotalBlocks = m_nDataBytes / m_wfeSource.nBlockAlign;
|
||||
if (pHeaderBytes) *pHeaderBytes = m_nHeaderBytes;
|
||||
if (pTerminatingBytes) *pTerminatingBytes = m_nTerminatingBytes;
|
||||
|
||||
m_bIsValid = TRUE;
|
||||
}
|
||||
|
||||
if (pErrorCode) *pErrorCode = nRetVal;
|
||||
}
|
||||
|
||||
CWAVInputSource::CWAVInputSource(const wchar_t * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
|
||||
: CInputSource(pSourceName, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode)
|
||||
{
|
||||
m_bIsValid = FALSE;
|
||||
|
||||
if (pSourceName == NULL || pwfeSource == NULL)
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
m_spIO.Assign(new IO_CLASS_NAME);
|
||||
if (m_spIO->Open(pSourceName) != ERROR_SUCCESS)
|
||||
{
|
||||
m_spIO.Delete();
|
||||
if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return;
|
||||
}
|
||||
|
||||
int nRetVal = AnalyzeSource();
|
||||
if (nRetVal == ERROR_SUCCESS)
|
||||
{
|
||||
// fill in the parameters
|
||||
if (pwfeSource) memcpy(pwfeSource, &m_wfeSource, sizeof(WAVEFORMATEX));
|
||||
if (pTotalBlocks) *pTotalBlocks = m_nDataBytes / m_wfeSource.nBlockAlign;
|
||||
if (pHeaderBytes) *pHeaderBytes = m_nHeaderBytes;
|
||||
if (pTerminatingBytes) *pTerminatingBytes = m_nTerminatingBytes;
|
||||
|
||||
m_bIsValid = TRUE;
|
||||
}
|
||||
|
||||
if (pErrorCode) *pErrorCode = nRetVal;
|
||||
}
|
||||
|
||||
CWAVInputSource::~CWAVInputSource()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
int CWAVInputSource::AnalyzeSource()
|
||||
{
|
||||
// seek to the beginning (just in case)
|
||||
m_spIO->Seek(0, FILE_BEGIN);
|
||||
|
||||
// get the file size
|
||||
m_nFileBytes = m_spIO->GetSize();
|
||||
|
||||
// get the RIFF header
|
||||
RIFF_HEADER RIFFHeader;
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFHeader, sizeof(RIFFHeader)))
|
||||
|
||||
// make sure the RIFF header is valid
|
||||
if (!(RIFFHeader.cRIFF[0] == 'R' && RIFFHeader.cRIFF[1] == 'I' && RIFFHeader.cRIFF[2] == 'F' && RIFFHeader.cRIFF[3] == 'F'))
|
||||
return ERROR_INVALID_INPUT_FILE;
|
||||
|
||||
// read the data type header
|
||||
DATA_TYPE_ID_HEADER DataTypeIDHeader;
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &DataTypeIDHeader, sizeof(DataTypeIDHeader)))
|
||||
|
||||
// make sure it's the right data type
|
||||
if (!(DataTypeIDHeader.cDataTypeID[0] == 'W' && DataTypeIDHeader.cDataTypeID[1] == 'A' && DataTypeIDHeader.cDataTypeID[2] == 'V' && DataTypeIDHeader.cDataTypeID[3] == 'E'))
|
||||
return ERROR_INVALID_INPUT_FILE;
|
||||
|
||||
// find the 'fmt ' chunk
|
||||
RIFF_CHUNK_HEADER RIFFChunkHeader;
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
||||
|
||||
while (!(RIFFChunkHeader.cChunkLabel[0] == 'f' && RIFFChunkHeader.cChunkLabel[1] == 'm' && RIFFChunkHeader.cChunkLabel[2] == 't' && RIFFChunkHeader.cChunkLabel[3] == ' '))
|
||||
{
|
||||
// move the file pointer to the end of this chunk
|
||||
m_spIO->Seek(RIFFChunkHeader.nChunkBytes, FILE_CURRENT);
|
||||
|
||||
// check again for the data chunk
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
||||
}
|
||||
|
||||
// read the format info
|
||||
WAV_FORMAT_HEADER WAVFormatHeader;
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &WAVFormatHeader, sizeof(WAVFormatHeader)))
|
||||
|
||||
// error check the header to see if we support it
|
||||
if (WAVFormatHeader.nFormatTag != 1)
|
||||
return ERROR_INVALID_INPUT_FILE;
|
||||
|
||||
// copy the format information to the WAVEFORMATEX passed in
|
||||
FillWaveFormatEx(&m_wfeSource, WAVFormatHeader.nSamplesPerSecond, WAVFormatHeader.nBitsPerSample, WAVFormatHeader.nChannels);
|
||||
|
||||
// skip over any extra data in the header
|
||||
int nWAVFormatHeaderExtra = RIFFChunkHeader.nChunkBytes - sizeof(WAVFormatHeader);
|
||||
if (nWAVFormatHeaderExtra < 0)
|
||||
return ERROR_INVALID_INPUT_FILE;
|
||||
else
|
||||
m_spIO->Seek(nWAVFormatHeaderExtra, FILE_CURRENT);
|
||||
|
||||
// find the data chunk
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
||||
|
||||
while (!(RIFFChunkHeader.cChunkLabel[0] == 'd' && RIFFChunkHeader.cChunkLabel[1] == 'a' && RIFFChunkHeader.cChunkLabel[2] == 't' && RIFFChunkHeader.cChunkLabel[3] == 'a'))
|
||||
{
|
||||
// move the file pointer to the end of this chunk
|
||||
m_spIO->Seek(RIFFChunkHeader.nChunkBytes, FILE_CURRENT);
|
||||
|
||||
// check again for the data chunk
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
||||
}
|
||||
|
||||
// we're at the data block
|
||||
m_nHeaderBytes = m_spIO->GetPosition();
|
||||
m_nDataBytes = RIFFChunkHeader.nChunkBytes;
|
||||
if (m_nDataBytes < 0)
|
||||
m_nDataBytes = m_nFileBytes - m_nHeaderBytes;
|
||||
|
||||
// make sure the data bytes is a whole number of blocks
|
||||
if ((m_nDataBytes % m_wfeSource.nBlockAlign) != 0)
|
||||
return ERROR_INVALID_INPUT_FILE;
|
||||
|
||||
// calculate the terminating byts
|
||||
m_nTerminatingBytes = m_nFileBytes - m_nDataBytes - m_nHeaderBytes;
|
||||
|
||||
// we made it this far, everything must be cool
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CWAVInputSource::GetData(unsigned char * pBuffer, int nBlocks, int * pBlocksRetrieved)
|
||||
{
|
||||
if (!m_bIsValid) return ERROR_UNDEFINED;
|
||||
|
||||
int nBytes = (m_wfeSource.nBlockAlign * nBlocks);
|
||||
unsigned int nBytesRead = 0;
|
||||
|
||||
if (m_spIO->Read(pBuffer, nBytes, &nBytesRead) != ERROR_SUCCESS)
|
||||
return ERROR_IO_READ;
|
||||
|
||||
if (pBlocksRetrieved) *pBlocksRetrieved = (nBytesRead / m_wfeSource.nBlockAlign);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CWAVInputSource::GetHeaderData(unsigned char * pBuffer)
|
||||
{
|
||||
if (!m_bIsValid) return ERROR_UNDEFINED;
|
||||
|
||||
int nRetVal = ERROR_SUCCESS;
|
||||
|
||||
if (m_nHeaderBytes > 0)
|
||||
{
|
||||
int nOriginalFileLocation = m_spIO->GetPosition();
|
||||
|
||||
m_spIO->Seek(0, FILE_BEGIN);
|
||||
|
||||
unsigned int nBytesRead = 0;
|
||||
int nReadRetVal = m_spIO->Read(pBuffer, m_nHeaderBytes, &nBytesRead);
|
||||
|
||||
if ((nReadRetVal != ERROR_SUCCESS) || (m_nHeaderBytes != int(nBytesRead)))
|
||||
{
|
||||
nRetVal = ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CWAVInputSource::GetTerminatingData(unsigned char * pBuffer)
|
||||
{
|
||||
if (!m_bIsValid) return ERROR_UNDEFINED;
|
||||
|
||||
int nRetVal = ERROR_SUCCESS;
|
||||
|
||||
if (m_nTerminatingBytes > 0)
|
||||
{
|
||||
int nOriginalFileLocation = m_spIO->GetPosition();
|
||||
|
||||
m_spIO->Seek(-m_nTerminatingBytes, FILE_END);
|
||||
|
||||
unsigned int nBytesRead = 0;
|
||||
int nReadRetVal = m_spIO->Read(pBuffer, m_nTerminatingBytes, &nBytesRead);
|
||||
|
||||
if ((nReadRetVal != ERROR_SUCCESS) || (m_nTerminatingBytes != int(nBytesRead)))
|
||||
{
|
||||
nRetVal = ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
64
MAC_SDK/Source/MACLib/WAVInputSource.h
Normal file
64
MAC_SDK/Source/MACLib/WAVInputSource.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef APE_WAVINPUTSOURCE_H
|
||||
#define APE_WAVINPUTSOURCE_H
|
||||
|
||||
#include "IO.h"
|
||||
|
||||
/*************************************************************************************
|
||||
CInputSource - base input format class (allows multiple format support)
|
||||
*************************************************************************************/
|
||||
class CInputSource
|
||||
{
|
||||
public:
|
||||
|
||||
// construction / destruction
|
||||
CInputSource(CIO * pIO, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode = NULL) { }
|
||||
CInputSource(const wchar_t * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode = NULL) { }
|
||||
virtual ~CInputSource() { }
|
||||
|
||||
// get data
|
||||
virtual int GetData(unsigned char * pBuffer, int nBlocks, int * pBlocksRetrieved) = 0;
|
||||
|
||||
// get header / terminating data
|
||||
virtual int GetHeaderData(unsigned char * pBuffer) = 0;
|
||||
virtual int GetTerminatingData(unsigned char * pBuffer) = 0;
|
||||
};
|
||||
|
||||
/*************************************************************************************
|
||||
CWAVInputSource - wraps working with WAV files (could be extended to any format)
|
||||
*************************************************************************************/
|
||||
class CWAVInputSource : public CInputSource
|
||||
{
|
||||
public:
|
||||
|
||||
// construction / destruction
|
||||
CWAVInputSource(CIO * pIO, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode = NULL);
|
||||
CWAVInputSource(const wchar_t * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode = NULL);
|
||||
~CWAVInputSource();
|
||||
|
||||
// get data
|
||||
int GetData(unsigned char * pBuffer, int nBlocks, int * pBlocksRetrieved);
|
||||
|
||||
// get header / terminating data
|
||||
int GetHeaderData(unsigned char * pBuffer);
|
||||
int GetTerminatingData(unsigned char * pBuffer);
|
||||
|
||||
private:
|
||||
|
||||
int AnalyzeSource();
|
||||
|
||||
CSmartPtr<CIO> m_spIO;
|
||||
|
||||
WAVEFORMATEX m_wfeSource;
|
||||
int m_nHeaderBytes;
|
||||
int m_nDataBytes;
|
||||
int m_nTerminatingBytes;
|
||||
int m_nFileBytes;
|
||||
BOOL m_bIsValid;
|
||||
};
|
||||
|
||||
/*************************************************************************************
|
||||
Input souce creation
|
||||
*************************************************************************************/
|
||||
CInputSource * CreateInputSource(const wchar_t * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode = NULL);
|
||||
|
||||
#endif // #ifndef APE_WAVINPUTSOURCE_H
|
||||
79
MAC_SDK/Source/MACLib/md5.h
Normal file
79
MAC_SDK/Source/MACLib/md5.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved.
|
||||
*
|
||||
* License to copy and use this software is granted provided that it is identified
|
||||
* as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
* mentioning or referencing this software or this function.
|
||||
*
|
||||
* License is also granted to make and use derivative works provided that such
|
||||
* works are identified as "derived from the RSA Data Security, Inc. MD5 Message-
|
||||
* Digest Algorithm" in all material mentioning or referencing the derived work.
|
||||
*
|
||||
* RSA Data Security, Inc. makes no representations concerning either the
|
||||
* merchantability of this software or the suitability of this software for any
|
||||
* particular purpose. It is provided "as is" without express or implied warranty
|
||||
* of any kind. These notices must be retained in any copies of any part of this
|
||||
* documentation and/or software.
|
||||
*/
|
||||
|
||||
#ifndef MD5SUM_MD5_H
|
||||
#define MD5SUM_MD5_H
|
||||
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
/*
|
||||
* Define the MD5 context structure
|
||||
* Please DO NOT change the order or contents of the structure as various assembler files depend on it !!
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint32_t state [ 4]; /* state (ABCD) */
|
||||
uint32_t count [ 2]; /* number of bits, modulo 2^64 (least sig word first) */
|
||||
uint8_t buffer [64]; /* input buffer for incomplete buffer data */
|
||||
} MD5_CTX;
|
||||
|
||||
void MD5Init ( MD5_CTX* ctx );
|
||||
void MD5Update ( MD5_CTX* ctx, const uint8_t* buf, size_t len );
|
||||
void MD5Final ( uint8_t digest [16], MD5_CTX* ctx );
|
||||
|
||||
class CMD5Helper
|
||||
{
|
||||
public:
|
||||
|
||||
CMD5Helper(BOOL bInitialize = TRUE)
|
||||
{
|
||||
if (bInitialize)
|
||||
Initialize();
|
||||
}
|
||||
|
||||
BOOL Initialize()
|
||||
{
|
||||
memset(&m_MD5Context, 0, sizeof(m_MD5Context));
|
||||
MD5Init(&m_MD5Context);
|
||||
m_nTotalBytes = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
inline void AddData(const void * pData, int nBytes)
|
||||
{
|
||||
MD5Update(&m_MD5Context, (const unsigned char *) pData, nBytes);
|
||||
m_nTotalBytes += nBytes;
|
||||
}
|
||||
|
||||
BOOL GetResult(unsigned char cResult[16])
|
||||
{
|
||||
memset(cResult, 0, 16);
|
||||
MD5Final(cResult, &m_MD5Context);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
MD5_CTX m_MD5Context;
|
||||
BOOL m_bStopped;
|
||||
int m_nTotalBytes;
|
||||
};
|
||||
|
||||
|
||||
#endif /* MD5SUM_MD5_H */
|
||||
Reference in New Issue
Block a user