1#include <algorithm>
2
3#include "All.h"
4#include "APEDecompress.h"
5#include "APEInfo.h"
6#include "Prepare.h"
7#include "UnBitArray.h"
8#include "NewPredictor.h"
9
10#define DECODE_BLOCK_SIZE        4096
11
12CAPEDecompress::CAPEDecompress(int * pErrorCode, CAPEInfo * pAPEInfo, int nStartBlock, int nFinishBlock)
13{
14    *pErrorCode = ERROR_SUCCESS;
15
16    // open / analyze the file
17    m_spAPEInfo.Assign(pAPEInfo);
18
19    // version check (this implementation only works with 3.93 and later files)
20    if (GetInfo(APE_INFO_FILE_VERSION) < 3930)
21    {
22        *pErrorCode = ERROR_UNDEFINED;
23        return;
24    }
25
26    // get format information
27    GetInfo(APE_INFO_WAVEFORMATEX, (int) &m_wfeInput);
28    m_nBlockAlign = GetInfo(APE_INFO_BLOCK_ALIGN);
29
30    // initialize other stuff
31    m_bDecompressorInitialized = FALSE;
32    m_nCurrentFrame = 0;
33    m_nCurrentBlock = 0;
34    m_nCurrentFrameBufferBlock = 0;
35    m_nFrameBufferFinishedBlocks = 0;
36    m_bErrorDecodingCurrentFrame = FALSE;
37
38    // set the "real" start and finish blocks
39    m_nStartBlock = (nStartBlock < 0)
40		? 0 : min(nStartBlock, GetInfo(APE_INFO_TOTAL_BLOCKS));
41    m_nFinishBlock = (nFinishBlock < 0)
42		? GetInfo(APE_INFO_TOTAL_BLOCKS)
43		: min(nFinishBlock, GetInfo(APE_INFO_TOTAL_BLOCKS));
44    m_bIsRanged = (m_nStartBlock != 0) || (m_nFinishBlock != GetInfo(APE_INFO_TOTAL_BLOCKS));
45}
46
47CAPEDecompress::~CAPEDecompress()
48{
49
50}
51
52int CAPEDecompress::InitializeDecompressor()
53{
54    // check if we have anything to do
55    if (m_bDecompressorInitialized)
56        return ERROR_SUCCESS;
57
58    // update the initialized flag
59    m_bDecompressorInitialized = TRUE;
60
61    // create a frame buffer
62    m_cbFrameBuffer.CreateBuffer((GetInfo(APE_INFO_BLOCKS_PER_FRAME) + DECODE_BLOCK_SIZE) * m_nBlockAlign, m_nBlockAlign * 64);
63
64    // create decoding components
65    m_spUnBitArray.Assign((CUnBitArrayBase *) CreateUnBitArray(this, GetInfo(APE_INFO_FILE_VERSION)));
66
67    if (GetInfo(APE_INFO_FILE_VERSION) >= 3950)
68    {
69        m_spNewPredictorX.Assign(new CPredictorDecompress3950toCurrent(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
70        m_spNewPredictorY.Assign(new CPredictorDecompress3950toCurrent(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
71    }
72    else
73    {
74        m_spNewPredictorX.Assign(new CPredictorDecompressNormal3930to3950(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
75        m_spNewPredictorY.Assign(new CPredictorDecompressNormal3930to3950(GetInfo(APE_INFO_COMPRESSION_LEVEL), GetInfo(APE_INFO_FILE_VERSION)));
76    }
77
78    // seek to the beginning
79    return Seek(0);
80}
81
82int CAPEDecompress::GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved)
83{
84    int nRetVal = ERROR_SUCCESS;
85    if (pBlocksRetrieved) *pBlocksRetrieved = 0;
86
87    // make sure we're initialized
88    RETURN_ON_ERROR(InitializeDecompressor())
89
90    // cap
91    int nBlocksUntilFinish = m_nFinishBlock - m_nCurrentBlock;
92    const int nBlocksToRetrieve = min(nBlocks, nBlocksUntilFinish);
93
94    // get the data
95    unsigned char * pOutputBuffer = (unsigned char *) pBuffer;
96    int nBlocksLeft = nBlocksToRetrieve; int nBlocksThisPass = 1;
97    while ((nBlocksLeft > 0) && (nBlocksThisPass > 0))
98    {
99        // fill up the frame buffer
100        int nDecodeRetVal = FillFrameBuffer();
101        if (nDecodeRetVal != ERROR_SUCCESS)
102            nRetVal = nDecodeRetVal;
103
104        // analyze how much to remove from the buffer
105        const int nFrameBufferBlocks = m_nFrameBufferFinishedBlocks;
106        nBlocksThisPass = min(nBlocksLeft, nFrameBufferBlocks);
107
108        // remove as much as possible
109        if (nBlocksThisPass > 0)
110        {
111            m_cbFrameBuffer.Get(pOutputBuffer, nBlocksThisPass * m_nBlockAlign);
112            pOutputBuffer += nBlocksThisPass * m_nBlockAlign;
113            nBlocksLeft -= nBlocksThisPass;
114            m_nFrameBufferFinishedBlocks -= nBlocksThisPass;
115        }
116    }
117
118    // calculate the blocks retrieved
119    int nBlocksRetrieved = nBlocksToRetrieve - nBlocksLeft;
120
121    // update position
122    m_nCurrentBlock += nBlocksRetrieved;
123    if (pBlocksRetrieved) *pBlocksRetrieved = nBlocksRetrieved;
124
125    return nRetVal;
126}
127
128int CAPEDecompress::Seek(int nBlockOffset)
129{
130    RETURN_ON_ERROR(InitializeDecompressor())
131
132    // use the offset
133    nBlockOffset += m_nStartBlock;
134
135    // cap (to prevent seeking too far)
136    if (nBlockOffset >= m_nFinishBlock)
137        nBlockOffset = m_nFinishBlock - 1;
138    if (nBlockOffset < m_nStartBlock)
139        nBlockOffset = m_nStartBlock;
140
141    // seek to the perfect location
142    int nBaseFrame = nBlockOffset / GetInfo(APE_INFO_BLOCKS_PER_FRAME);
143    int nBlocksToSkip = nBlockOffset % GetInfo(APE_INFO_BLOCKS_PER_FRAME);
144    int nBytesToSkip = nBlocksToSkip * m_nBlockAlign;
145
146    m_nCurrentBlock = nBaseFrame * GetInfo(APE_INFO_BLOCKS_PER_FRAME);
147    m_nCurrentFrameBufferBlock = nBaseFrame * GetInfo(APE_INFO_BLOCKS_PER_FRAME);
148    m_nCurrentFrame = nBaseFrame;
149    m_nFrameBufferFinishedBlocks = 0;
150    m_cbFrameBuffer.Empty();
151    RETURN_ON_ERROR(SeekToFrame(m_nCurrentFrame));
152
153    // skip necessary blocks
154    CSmartPtr<char> spTempBuffer(new char [nBytesToSkip], TRUE);
155    if (spTempBuffer == NULL) return ERROR_INSUFFICIENT_MEMORY;
156
157    int nBlocksRetrieved = 0;
158    GetData(spTempBuffer, nBlocksToSkip, &nBlocksRetrieved);
159    if (nBlocksRetrieved != nBlocksToSkip)
160        return ERROR_UNDEFINED;
161
162    return ERROR_SUCCESS;
163}
164
165/*****************************************************************************************
166Decodes blocks of data
167*****************************************************************************************/
168int CAPEDecompress::FillFrameBuffer()
169{
170    int nRetVal = ERROR_SUCCESS;
171
172     // determine the maximum blocks we can decode
173    // note that we won't do end capping because we can't use data
174    // until EndFrame(...) successfully handles the frame
175    // that means we may decode a little extra in end capping cases
176    // but this allows robust error handling of bad frames
177    int nMaxBlocks = m_cbFrameBuffer.MaxAdd() / m_nBlockAlign;
178
179    // loop and decode data
180    int nBlocksLeft = nMaxBlocks;
181    while (nBlocksLeft > 0)
182    {
183        int nFrameBlocks = GetInfo(APE_INFO_FRAME_BLOCKS, m_nCurrentFrame);
184        if (nFrameBlocks < 0)
185            break;
186
187        int nFrameOffsetBlocks = m_nCurrentFrameBufferBlock % GetInfo(APE_INFO_BLOCKS_PER_FRAME);
188        int nFrameBlocksLeft = nFrameBlocks - nFrameOffsetBlocks;
189        int nBlocksThisPass = min(nFrameBlocksLeft, nBlocksLeft);
190
191        // start the frame if we need to
192        if (nFrameOffsetBlocks == 0)
193            StartFrame();
194
195        // store the frame buffer bytes before we start
196        int nFrameBufferBytes = m_cbFrameBuffer.MaxGet();
197
198        // decode data
199        DecodeBlocksToFrameBuffer(nBlocksThisPass);
200
201        // end the frame if we need to
202        if ((nFrameOffsetBlocks + nBlocksThisPass) >= nFrameBlocks)
203        {
204            EndFrame();
205            if (m_bErrorDecodingCurrentFrame)
206            {
207                // remove any decoded data from the buffer
208                m_cbFrameBuffer.RemoveTail(m_cbFrameBuffer.MaxGet() - nFrameBufferBytes);
209
210                // add silence
211                unsigned char cSilence = (GetInfo(APE_INFO_BITS_PER_SAMPLE) == 8) ? 127 : 0;
212                for (int z = 0; z < nFrameBlocks * m_nBlockAlign; z++)
213                {
214                    *m_cbFrameBuffer.GetDirectWritePointer() = cSilence;
215                    m_cbFrameBuffer.UpdateAfterDirectWrite(1);
216                }
217
218                // seek to try to synchronize after an error
219                SeekToFrame(m_nCurrentFrame);
220
221                // save the return value
222                nRetVal = ERROR_INVALID_CHECKSUM;
223            }
224        }
225
226        nBlocksLeft -= nBlocksThisPass;
227    }
228
229    return nRetVal;
230}
231
232void CAPEDecompress::DecodeBlocksToFrameBuffer(int nBlocks)
233{
234    // decode the samples
235    int nBlocksProcessed = 0;
236
237    try
238    {
239        if (m_wfeInput.nChannels == 2)
240        {
241            if ((m_nSpecialCodes & SPECIAL_FRAME_LEFT_SILENCE) &&
242                (m_nSpecialCodes & SPECIAL_FRAME_RIGHT_SILENCE))
243            {
244                for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
245                {
246                    m_Prepare.Unprepare(0, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
247                    m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
248                }
249            }
250            else if (m_nSpecialCodes & SPECIAL_FRAME_PSEUDO_STEREO)
251            {
252                for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
253                {
254                    int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
255                    m_Prepare.Unprepare(X, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
256                    m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
257                }
258            }
259            else
260            {
261                if (m_spAPEInfo->GetInfo(APE_INFO_FILE_VERSION) >= 3950)
262                {
263                    for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
264                    {
265                        int nY = m_spUnBitArray->DecodeValueRange(m_BitArrayStateY);
266                        int nX = m_spUnBitArray->DecodeValueRange(m_BitArrayStateX);
267                        int Y = m_spNewPredictorY->DecompressValue(nY, m_nLastX);
268                        int X = m_spNewPredictorX->DecompressValue(nX, Y);
269                        m_nLastX = X;
270
271                        m_Prepare.Unprepare(X, Y, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
272                        m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
273                    }
274                }
275                else
276                {
277                    for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
278                    {
279                        int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
280                        int Y = m_spNewPredictorY->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateY));
281
282                        m_Prepare.Unprepare(X, Y, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
283                        m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
284                    }
285                }
286            }
287        }
288        else
289        {
290            if (m_nSpecialCodes & SPECIAL_FRAME_MONO_SILENCE)
291            {
292                for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
293                {
294                    m_Prepare.Unprepare(0, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
295                    m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
296                }
297            }
298            else
299            {
300                for (nBlocksProcessed = 0; nBlocksProcessed < nBlocks; nBlocksProcessed++)
301                {
302                    int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
303                    m_Prepare.Unprepare(X, 0, &m_wfeInput, m_cbFrameBuffer.GetDirectWritePointer(), &m_nCRC);
304                    m_cbFrameBuffer.UpdateAfterDirectWrite(m_nBlockAlign);
305                }
306            }
307        }
308    }
309    catch(...)
310    {
311        m_bErrorDecodingCurrentFrame = TRUE;
312    }
313
314    m_nCurrentFrameBufferBlock += nBlocks;
315}
316
317void CAPEDecompress::StartFrame()
318{
319    m_nCRC = 0xFFFFFFFF;
320
321    // get the frame header
322    m_nStoredCRC = m_spUnBitArray->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_INT);
323    m_bErrorDecodingCurrentFrame = FALSE;
324
325    // get any 'special' codes if the file uses them (for silence, FALSE stereo, etc.)
326    m_nSpecialCodes = 0;
327    if (GET_USES_SPECIAL_FRAMES(m_spAPEInfo))
328    {
329        if (m_nStoredCRC & 0x80000000)
330        {
331            m_nSpecialCodes = m_spUnBitArray->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_INT);
332        }
333        m_nStoredCRC &= 0x7FFFFFFF;
334    }
335
336    m_spNewPredictorX->Flush();
337    m_spNewPredictorY->Flush();
338
339    m_spUnBitArray->FlushState(m_BitArrayStateX);
340    m_spUnBitArray->FlushState(m_BitArrayStateY);
341
342    m_spUnBitArray->FlushBitArray();
343
344    m_nLastX = 0;
345}
346
347void CAPEDecompress::EndFrame()
348{
349    m_nFrameBufferFinishedBlocks += GetInfo(APE_INFO_FRAME_BLOCKS, m_nCurrentFrame);
350    m_nCurrentFrame++;
351
352    // finalize
353    m_spUnBitArray->Finalize();
354
355    // check the CRC
356    m_nCRC = m_nCRC ^ 0xFFFFFFFF;
357    m_nCRC >>= 1;
358    if (m_nCRC != m_nStoredCRC)
359        m_bErrorDecodingCurrentFrame = TRUE;
360}
361
362/*****************************************************************************************
363Seek to the proper frame (if necessary) and do any alignment of the bit array
364*****************************************************************************************/
365int CAPEDecompress::SeekToFrame(int nFrameIndex)
366{
367    int nSeekRemainder = (GetInfo(APE_INFO_SEEK_BYTE, nFrameIndex) - GetInfo(APE_INFO_SEEK_BYTE, 0)) % 4;
368    return m_spUnBitArray->FillAndResetBitArray(GetInfo(APE_INFO_SEEK_BYTE, nFrameIndex) - nSeekRemainder, nSeekRemainder * 8);
369}
370
371/*****************************************************************************************
372Get information from the decompressor
373*****************************************************************************************/
374int CAPEDecompress::GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1, int nParam2)
375{
376    int nRetVal = 0;
377    BOOL bHandled = TRUE;
378
379    switch (Field)
380    {
381    case APE_DECOMPRESS_CURRENT_BLOCK:
382        nRetVal = m_nCurrentBlock - m_nStartBlock;
383        break;
384    case APE_DECOMPRESS_CURRENT_MS:
385    {
386        int nSampleRate = m_spAPEInfo->GetInfo(APE_INFO_SAMPLE_RATE, 0, 0);
387        if (nSampleRate > 0)
388            nRetVal = int((double(m_nCurrentBlock) * double(1000)) / double(nSampleRate));
389        break;
390    }
391    case APE_DECOMPRESS_TOTAL_BLOCKS:
392        nRetVal = m_nFinishBlock - m_nStartBlock;
393        break;
394    case APE_DECOMPRESS_LENGTH_MS:
395    {
396        int nSampleRate = m_spAPEInfo->GetInfo(APE_INFO_SAMPLE_RATE, 0, 0);
397        if (nSampleRate > 0)
398            nRetVal = int((double(m_nFinishBlock - m_nStartBlock) * double(1000)) / double(nSampleRate));
399        break;
400    }
401    case APE_DECOMPRESS_CURRENT_BITRATE:
402        nRetVal = GetInfo(APE_INFO_FRAME_BITRATE, m_nCurrentFrame);
403        break;
404    case APE_DECOMPRESS_AVERAGE_BITRATE:
405    {
406        if (m_bIsRanged)
407        {
408            // figure the frame range
409            const int nBlocksPerFrame = GetInfo(APE_INFO_BLOCKS_PER_FRAME);
410            int nStartFrame = m_nStartBlock / nBlocksPerFrame;
411            int nFinishFrame = (m_nFinishBlock + nBlocksPerFrame - 1) / nBlocksPerFrame;
412
413            // get the number of bytes in the first and last frame
414            int nTotalBytes = (GetInfo(APE_INFO_FRAME_BYTES, nStartFrame) * (m_nStartBlock % nBlocksPerFrame)) / nBlocksPerFrame;
415            if (nFinishFrame != nStartFrame)
416                nTotalBytes += (GetInfo(APE_INFO_FRAME_BYTES, nFinishFrame) * (m_nFinishBlock % nBlocksPerFrame)) / nBlocksPerFrame;
417
418            // get the number of bytes in between
419            const int nTotalFrames = GetInfo(APE_INFO_TOTAL_FRAMES);
420            for (int nFrame = nStartFrame + 1; (nFrame < nFinishFrame) && (nFrame < nTotalFrames); nFrame++)
421                nTotalBytes += GetInfo(APE_INFO_FRAME_BYTES, nFrame);
422
423            // figure the bitrate
424            int nTotalMS = int((double(m_nFinishBlock - m_nStartBlock) * double(1000)) / double(GetInfo(APE_INFO_SAMPLE_RATE)));
425            if (nTotalMS != 0)
426                nRetVal = (nTotalBytes * 8) / nTotalMS;
427        }
428        else
429        {
430            nRetVal = GetInfo(APE_INFO_AVERAGE_BITRATE);
431        }
432
433        break;
434    }
435    default:
436        bHandled = FALSE;
437    }
438
439    if (!bHandled && m_bIsRanged)
440    {
441        bHandled = TRUE;
442
443        switch (Field)
444        {
445        case APE_INFO_WAV_HEADER_BYTES:
446            nRetVal = sizeof(WAVE_HEADER);
447            break;
448        case APE_INFO_WAV_HEADER_DATA:
449        {
450            char * pBuffer = (char *) nParam1;
451            int nMaxBytes = nParam2;
452
453            if (sizeof(WAVE_HEADER) > static_cast<uint32>(nMaxBytes))
454            {
455                nRetVal = -1;
456            }
457            else
458            {
459                WAVEFORMATEX wfeFormat; GetInfo(APE_INFO_WAVEFORMATEX, (int) &wfeFormat, 0);
460                WAVE_HEADER WAVHeader; FillWaveHeader(&WAVHeader,
461                    (m_nFinishBlock - m_nStartBlock) * GetInfo(APE_INFO_BLOCK_ALIGN),
462                    &wfeFormat,    0);
463                memcpy(pBuffer, &WAVHeader, sizeof(WAVE_HEADER));
464                nRetVal = 0;
465            }
466            break;
467        }
468        case APE_INFO_WAV_TERMINATING_BYTES:
469            nRetVal = 0;
470            break;
471        case APE_INFO_WAV_TERMINATING_DATA:
472            nRetVal = 0;
473            break;
474        default:
475            bHandled = FALSE;
476        }
477    }
478
479    if (bHandled == FALSE)
480        nRetVal = m_spAPEInfo->GetInfo(Field, nParam1, nParam2);
481
482    return nRetVal;
483}
484