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
CAPEDecompress(int * pErrorCode,CAPEInfo * pAPEInfo,int nStartBlock,int nFinishBlock)12 CAPEDecompress::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
~CAPEDecompress()47 CAPEDecompress::~CAPEDecompress()
48 {
49
50 }
51
InitializeDecompressor()52 int 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
GetData(char * pBuffer,int nBlocks,int * pBlocksRetrieved)82 int 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
Seek(int nBlockOffset)128 int 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 /*****************************************************************************************
166 Decodes blocks of data
167 *****************************************************************************************/
FillFrameBuffer()168 int 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
DecodeBlocksToFrameBuffer(int nBlocks)232 void 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
StartFrame()317 void 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
EndFrame()347 void 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 /*****************************************************************************************
363 Seek to the proper frame (if necessary) and do any alignment of the bit array
364 *****************************************************************************************/
SeekToFrame(int nFrameIndex)365 int 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 /*****************************************************************************************
372 Get information from the decompressor
373 *****************************************************************************************/
GetInfo(APE_DECOMPRESS_FIELDS Field,int nParam1,int nParam2)374 int 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