xref: /haiku/src/add-ons/media/plugins/ape_reader/MAClib/APECompressCore.cpp (revision be878f60874196f746f336f235797c8efa25004e)
1 #include "All.h"
2 #include "APECompressCore.h"
3 
4 #include "BitArray.h"
5 #include "Prepare.h"
6 #include "NewPredictor.h"
7 
CAPECompressCore(CIO * pIO,const WAVEFORMATEX * pwfeInput,int nMaxFrameBlocks,int nCompressionLevel)8 CAPECompressCore::CAPECompressCore(CIO * pIO, const WAVEFORMATEX * pwfeInput, int nMaxFrameBlocks, int nCompressionLevel)
9 {
10     m_spBitArray.Assign(new CBitArray(pIO));
11     m_spDataX.Assign(new int [nMaxFrameBlocks], TRUE);
12     m_spDataY.Assign(new int [nMaxFrameBlocks], TRUE);
13     m_spTempData.Assign(new int [nMaxFrameBlocks], TRUE);
14     m_spPrepare.Assign(new CPrepare);
15     m_spPredictorX.Assign(new CPredictorCompressNormal(nCompressionLevel));
16     m_spPredictorY.Assign(new CPredictorCompressNormal(nCompressionLevel));
17 
18     memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
19     m_nPeakLevel = 0;
20 }
21 
~CAPECompressCore()22 CAPECompressCore::~CAPECompressCore()
23 {
24 }
25 
EncodeFrame(const void * pInputData,int nInputBytes)26 int CAPECompressCore::EncodeFrame(const void * pInputData, int nInputBytes)
27 {
28     // variables
29     const int nInputBlocks = nInputBytes / m_wfeInput.nBlockAlign;
30     int nSpecialCodes = 0;
31 
32     // always start a new frame on a byte boundary
33     m_spBitArray->AdvanceToByteBoundary();
34 
35     // do the preparation stage
36     RETURN_ON_ERROR(Prepare(pInputData, nInputBytes, &nSpecialCodes))
37 
38     m_spPredictorX->Flush();
39     m_spPredictorY->Flush();
40 
41     m_spBitArray->FlushState(m_BitArrayStateX);
42     m_spBitArray->FlushState(m_BitArrayStateY);
43 
44     m_spBitArray->FlushBitArray();
45 
46     if (m_wfeInput.nChannels == 2)
47     {
48         BOOL bEncodeX = TRUE;
49         BOOL bEncodeY = TRUE;
50 
51         if ((nSpecialCodes & SPECIAL_FRAME_LEFT_SILENCE) &&
52             (nSpecialCodes & SPECIAL_FRAME_RIGHT_SILENCE))
53         {
54             bEncodeX = FALSE;
55             bEncodeY = FALSE;
56         }
57 
58         if (nSpecialCodes & SPECIAL_FRAME_PSEUDO_STEREO)
59         {
60             bEncodeY = FALSE;
61         }
62 
63         if (bEncodeX && bEncodeY)
64         {
65             int nLastX = 0;
66             for (int z = 0; z < nInputBlocks; z++)
67             {
68                 m_spBitArray->EncodeValue(m_spPredictorY->CompressValue(m_spDataY[z], nLastX), m_BitArrayStateY);
69                 m_spBitArray->EncodeValue(m_spPredictorX->CompressValue(m_spDataX[z], m_spDataY[z]), m_BitArrayStateX);
70 
71                 nLastX = m_spDataX[z];
72             }
73         }
74         else if (bEncodeX)
75         {
76             for (int z = 0; z < nInputBlocks; z++)
77             {
78                 RETURN_ON_ERROR(m_spBitArray->EncodeValue(m_spPredictorX->CompressValue(m_spDataX[z]), m_BitArrayStateX))
79             }
80         }
81         else if (bEncodeY)
82         {
83             for (int z = 0; z < nInputBlocks; z++)
84             {
85                 RETURN_ON_ERROR(m_spBitArray->EncodeValue(m_spPredictorY->CompressValue(m_spDataY[z]), m_BitArrayStateY))
86             }
87         }
88     }
89     else if (m_wfeInput.nChannels == 1)
90     {
91         if (!(nSpecialCodes & SPECIAL_FRAME_MONO_SILENCE))
92         {
93             for (int z = 0; z < nInputBlocks; z++)
94             {
95                 RETURN_ON_ERROR(m_spBitArray->EncodeValue(m_spPredictorX->CompressValue(m_spDataX[z]), m_BitArrayStateX))
96             }
97         }
98     }
99 
100     m_spBitArray->Finalize();
101 
102     // return success
103     return 0;
104 }
105 
Prepare(const void * pInputData,int nInputBytes,int * pSpecialCodes)106 int CAPECompressCore::Prepare(const void * pInputData, int nInputBytes, int * pSpecialCodes)
107 {
108     // variable declares
109     *pSpecialCodes = 0;
110     unsigned int nCRC = 0;
111 
112     // do the preparation
113     RETURN_ON_ERROR(m_spPrepare->Prepare((unsigned char *) pInputData, nInputBytes, &m_wfeInput, m_spDataX, m_spDataY,
114         &nCRC, pSpecialCodes, &m_nPeakLevel))
115 
116     // store the CRC
117     RETURN_ON_ERROR(m_spBitArray->EncodeUnsignedLong(nCRC))
118 
119     // store any special codes
120     if (*pSpecialCodes != 0)
121     {
122         RETURN_ON_ERROR(m_spBitArray->EncodeUnsignedLong(*pSpecialCodes))
123     }
124 
125     return 0;
126 }
127