1#include "All.h"
2#include "APECompress.h"
3#include IO_HEADER_FILE
4#include "APECompressCreate.h"
5#include "WAVInputSource.h"
6
7CAPECompress::CAPECompress()
8{
9    m_nBufferHead        = 0;
10    m_nBufferTail        = 0;
11    m_nBufferSize        = 0;
12    m_bBufferLocked        = FALSE;
13    m_bOwnsOutputIO        = FALSE;
14    m_pioOutput            = NULL;
15
16    m_spAPECompressCreate.Assign(new CAPECompressCreate());
17
18    m_pBuffer = NULL;
19}
20
21CAPECompress::~CAPECompress()
22{
23    SAFE_ARRAY_DELETE(m_pBuffer)
24
25    if (m_bOwnsOutputIO)
26    {
27        SAFE_DELETE(m_pioOutput)
28    }
29}
30
31int CAPECompress::Start(const char* pOutputFilename, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
32{
33    m_pioOutput = new IO_CLASS_NAME;
34    m_bOwnsOutputIO = TRUE;
35
36    if (m_pioOutput->Create(pOutputFilename) != 0)
37    {
38        return ERROR_INVALID_OUTPUT_FILE;
39    }
40
41    m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
42        pHeaderData, nHeaderBytes);
43
44    SAFE_ARRAY_DELETE(m_pBuffer)
45    m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
46    m_pBuffer = new unsigned char [m_nBufferSize];
47    memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
48
49    return ERROR_SUCCESS;
50}
51
52int CAPECompress::StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const void * pHeaderData, int nHeaderBytes)
53{
54    m_pioOutput = pioOutput;
55    m_bOwnsOutputIO = FALSE;
56
57    m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
58        pHeaderData, nHeaderBytes);
59
60    SAFE_ARRAY_DELETE(m_pBuffer)
61    m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
62    m_pBuffer = new unsigned char [m_nBufferSize];
63    memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
64
65    return ERROR_SUCCESS;
66}
67
68int CAPECompress::GetBufferBytesAvailable()
69{
70    return m_nBufferSize - m_nBufferTail;
71}
72
73int CAPECompress::UnlockBuffer(int nBytesAdded, BOOL bProcess)
74{
75    if (m_bBufferLocked == FALSE)
76        return ERROR_UNDEFINED;
77
78    m_nBufferTail += nBytesAdded;
79    m_bBufferLocked = FALSE;
80
81    if (bProcess)
82    {
83        int nRetVal = ProcessBuffer();
84        if (nRetVal != 0) { return nRetVal; }
85    }
86
87    return ERROR_SUCCESS;
88}
89
90unsigned char * CAPECompress::LockBuffer(int * pBytesAvailable)
91{
92    if (m_pBuffer == NULL) { return NULL; }
93
94    if (m_bBufferLocked)
95        return NULL;
96
97    m_bBufferLocked = TRUE;
98
99    if (pBytesAvailable)
100        *pBytesAvailable = GetBufferBytesAvailable();
101
102    return &m_pBuffer[m_nBufferTail];
103}
104
105int CAPECompress::AddData(unsigned char * pData, int nBytes)
106{
107    if (m_pBuffer == NULL) return ERROR_INSUFFICIENT_MEMORY;
108
109    int nBytesDone = 0;
110
111    while (nBytesDone < nBytes)
112    {
113        // lock the buffer
114        int nBytesAvailable = 0;
115        unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
116        if (pBuffer == NULL || nBytesAvailable <= 0)
117            return ERROR_UNDEFINED;
118
119        // calculate how many bytes to copy and add that much to the buffer
120        int nBytesToProcess = min(nBytesAvailable, nBytes - nBytesDone);
121        memcpy(pBuffer, &pData[nBytesDone], nBytesToProcess);
122
123        // unlock the buffer (fail if not successful)
124        int nRetVal = UnlockBuffer(nBytesToProcess);
125        if (nRetVal != ERROR_SUCCESS)
126                return nRetVal;
127
128        // update our progress
129        nBytesDone += nBytesToProcess;
130    }
131
132    return ERROR_SUCCESS;
133}
134
135int CAPECompress::Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes)
136{
137    RETURN_ON_ERROR(ProcessBuffer(TRUE))
138    return m_spAPECompressCreate->Finish(pTerminatingData, nTerminatingBytes, nWAVTerminatingBytes);
139}
140
141int CAPECompress::Kill()
142{
143    return ERROR_SUCCESS;
144}
145
146int CAPECompress::ProcessBuffer(BOOL bFinalize)
147{
148    if (m_pBuffer == NULL) { return ERROR_UNDEFINED; }
149
150    try
151    {
152        // process as much as possible
153        int nThreshold = (bFinalize) ? 0 : m_spAPECompressCreate->GetFullFrameBytes();
154
155        while ((m_nBufferTail - m_nBufferHead) >= nThreshold)
156        {
157            int nFrameBytes = min(m_spAPECompressCreate->GetFullFrameBytes(), m_nBufferTail - m_nBufferHead);
158
159            if (nFrameBytes == 0)
160                break;
161
162            int nRetVal = m_spAPECompressCreate->EncodeFrame(&m_pBuffer[m_nBufferHead], nFrameBytes);
163            if (nRetVal != 0) { return nRetVal; }
164
165            m_nBufferHead += nFrameBytes;
166        }
167
168        // shift the buffer
169        if (m_nBufferHead != 0)
170        {
171            int nBytesLeft = m_nBufferTail - m_nBufferHead;
172
173            if (nBytesLeft != 0)
174                memmove(m_pBuffer, &m_pBuffer[m_nBufferHead], nBytesLeft);
175
176            m_nBufferTail -= m_nBufferHead;
177            m_nBufferHead = 0;
178        }
179    }
180    catch(...)
181    {
182        return ERROR_UNDEFINED;
183    }
184
185    return ERROR_SUCCESS;
186}
187
188int CAPECompress::AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes, int * pBytesAdded)
189{
190    // error check the parameters
191    if (pInputSource == NULL) return ERROR_BAD_PARAMETER;
192
193    // initialize
194    if (pBytesAdded) *pBytesAdded = 0;
195
196    // lock the buffer
197    int nBytesAvailable = 0;
198    unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
199    if ((pBuffer == NULL) || (nBytesAvailable == 0))
200        return ERROR_INSUFFICIENT_MEMORY;
201
202    // calculate the 'ideal' number of bytes
203    unsigned int nBytesRead = 0;
204
205    int nIdealBytes = m_spAPECompressCreate->GetFullFrameBytes() - (m_nBufferTail - m_nBufferHead);
206    if (nIdealBytes > 0)
207    {
208        // get the data
209        int nBytesToAdd = nBytesAvailable;
210
211        if (nMaxBytes > 0)
212        {
213            if (nBytesToAdd > nMaxBytes) nBytesToAdd = nMaxBytes;
214        }
215
216        if (nBytesToAdd > nIdealBytes) nBytesToAdd = nIdealBytes;
217
218        // always make requests along block boundaries
219        while ((nBytesToAdd % m_wfeInput.nBlockAlign) != 0)
220            nBytesToAdd--;
221
222        int nBlocksToAdd = nBytesToAdd / m_wfeInput.nBlockAlign;
223
224        // get data
225        int nBlocksAdded = 0;
226        int nRetVal = pInputSource->GetData(pBuffer, nBlocksToAdd, &nBlocksAdded);
227        if (nRetVal != 0)
228            return ERROR_IO_READ;
229        else
230            nBytesRead = (nBlocksAdded * m_wfeInput.nBlockAlign);
231
232        // store the bytes read
233        if (pBytesAdded)
234            *pBytesAdded = nBytesRead;
235    }
236
237    // unlock the data and process
238    int nRetVal = UnlockBuffer(nBytesRead, TRUE);
239    if (nRetVal != 0)
240    {
241        return nRetVal;
242    }
243
244    return ERROR_SUCCESS;
245}
246
247