1#include "All.h"
2#include "WAVInputSource.h"
3#include IO_HEADER_FILE
4#include "MACLib.h"
5#include "GlobalFunctions.h"
6
7struct RIFF_HEADER
8{
9    char cRIFF[4];            // the characters 'RIFF' indicating that it's a RIFF file
10    unsigned long nBytes;    // the number of bytes following this header
11};
12
13struct DATA_TYPE_ID_HEADER
14{
15    char cDataTypeID[4];    // should equal 'WAVE' for a WAV file
16};
17
18struct WAV_FORMAT_HEADER
19{
20    unsigned short nFormatTag;            // the format of the WAV...should equal 1 for a PCM file
21    unsigned short nChannels;            // the number of channels
22    unsigned long nSamplesPerSecond;    // the number of samples per second
23    unsigned long nBytesPerSecond;        // the bytes per second
24    unsigned short nBlockAlign;            // block alignment
25    unsigned short nBitsPerSample;        // the number of bits per sample
26};
27
28struct RIFF_CHUNK_HEADER
29{
30    char cChunkLabel[4];        // should equal "data" indicating the data chunk
31    unsigned long nChunkBytes;  // the bytes of the chunk
32};
33
34
35CInputSource * __stdcall	CreateInputSource(const char* pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
36{
37    // error check the parameters
38    if ((pSourceName == NULL) || (wcslen(pSourceName) == 0))
39    {
40        if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
41        return NULL;
42    }
43
44    // get the extension
45    const char* pExtension = &pSourceName[wcslen(pSourceName)];
46    while ((pExtension > pSourceName) && (*pExtension != '.'))
47        pExtension--;
48
49    // create the proper input source
50    // SHINTA -->
51//    if (wcsicmp(pExtension, L".wav") == 0)
52//    {
53        if (pErrorCode) *pErrorCode = ERROR_SUCCESS;
54        return new CWAVInputSource(pSourceName, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode);
55//    }
56//    else
57//    {
58//        if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
59//        return NULL;
60//    }
61	// <-- SHINTA
62}
63
64CWAVInputSource::CWAVInputSource(CIO * pIO, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
65    : CInputSource(pIO, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode)
66{
67    m_bIsValid = FALSE;
68
69    if (pIO == NULL || pwfeSource == NULL)
70    {
71        if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
72        return;
73    }
74
75    m_spIO.Assign(pIO, FALSE, FALSE);
76
77    int nRetVal = AnalyzeSource();
78    if (nRetVal == ERROR_SUCCESS)
79    {
80        // fill in the parameters
81        if (pwfeSource) memcpy(pwfeSource, &m_wfeSource, sizeof(WAVEFORMATEX));
82        if (pTotalBlocks) *pTotalBlocks = m_nDataBytes / m_wfeSource.nBlockAlign;
83        if (pHeaderBytes) *pHeaderBytes = m_nHeaderBytes;
84        if (pTerminatingBytes) *pTerminatingBytes = m_nTerminatingBytes;
85
86        m_bIsValid = TRUE;
87    }
88
89    if (pErrorCode) *pErrorCode = nRetVal;
90}
91
92CWAVInputSource::CWAVInputSource(const char* pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
93    : CInputSource(pSourceName, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode)
94{
95    m_bIsValid = FALSE;
96
97    if (pSourceName == NULL || pwfeSource == NULL)
98    {
99        if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
100        return;
101    }
102
103    m_spIO.Assign(new IO_CLASS_NAME);
104    if (m_spIO->Open(pSourceName) != ERROR_SUCCESS)
105    {
106        m_spIO.Delete();
107        if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
108        return;
109    }
110
111    int nRetVal = AnalyzeSource();
112    if (nRetVal == ERROR_SUCCESS)
113    {
114        // fill in the parameters
115        if (pwfeSource) memcpy(pwfeSource, &m_wfeSource, sizeof(WAVEFORMATEX));
116        if (pTotalBlocks) *pTotalBlocks = m_nDataBytes / m_wfeSource.nBlockAlign;
117        if (pHeaderBytes) *pHeaderBytes = m_nHeaderBytes;
118        if (pTerminatingBytes) *pTerminatingBytes = m_nTerminatingBytes;
119
120        m_bIsValid = TRUE;
121    }
122
123    if (pErrorCode) *pErrorCode = nRetVal;
124}
125
126CWAVInputSource::~CWAVInputSource()
127{
128
129
130}
131
132int CWAVInputSource::AnalyzeSource()
133{
134    // seek to the beginning (just in case)
135    m_spIO->Seek(0, FILE_BEGIN);
136
137    // get the file size
138    m_nFileBytes = m_spIO->GetSize();
139
140    // get the RIFF header
141    RIFF_HEADER RIFFHeader;
142    RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFHeader, sizeof(RIFFHeader)))
143
144    // make sure the RIFF header is valid
145    if (!(RIFFHeader.cRIFF[0] == 'R' && RIFFHeader.cRIFF[1] == 'I' && RIFFHeader.cRIFF[2] == 'F' && RIFFHeader.cRIFF[3] == 'F'))
146        return ERROR_INVALID_INPUT_FILE;
147
148    // read the data type header
149    DATA_TYPE_ID_HEADER DataTypeIDHeader;
150    RETURN_ON_ERROR(ReadSafe(m_spIO, &DataTypeIDHeader, sizeof(DataTypeIDHeader)))
151
152    // make sure it's the right data type
153    if (!(DataTypeIDHeader.cDataTypeID[0] == 'W' && DataTypeIDHeader.cDataTypeID[1] == 'A' && DataTypeIDHeader.cDataTypeID[2] == 'V' && DataTypeIDHeader.cDataTypeID[3] == 'E'))
154        return ERROR_INVALID_INPUT_FILE;
155
156    // find the 'fmt ' chunk
157    RIFF_CHUNK_HEADER RIFFChunkHeader;
158    RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
159
160    while (!(RIFFChunkHeader.cChunkLabel[0] == 'f' && RIFFChunkHeader.cChunkLabel[1] == 'm' && RIFFChunkHeader.cChunkLabel[2] == 't' && RIFFChunkHeader.cChunkLabel[3] == ' '))
161    {
162        // move the file pointer to the end of this chunk
163        m_spIO->Seek(RIFFChunkHeader.nChunkBytes, FILE_CURRENT);
164
165        // check again for the data chunk
166        RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
167    }
168
169    // read the format info
170    WAV_FORMAT_HEADER WAVFormatHeader;
171    RETURN_ON_ERROR(ReadSafe(m_spIO, &WAVFormatHeader, sizeof(WAVFormatHeader)))
172
173    // error check the header to see if we support it
174    if (WAVFormatHeader.nFormatTag != 1)
175        return ERROR_INVALID_INPUT_FILE;
176
177    // copy the format information to the WAVEFORMATEX passed in
178    FillWaveFormatEx(&m_wfeSource, WAVFormatHeader.nSamplesPerSecond, WAVFormatHeader.nBitsPerSample, WAVFormatHeader.nChannels);
179
180    // skip over any extra data in the header
181    int nWAVFormatHeaderExtra = RIFFChunkHeader.nChunkBytes - sizeof(WAVFormatHeader);
182    if (nWAVFormatHeaderExtra < 0)
183        return ERROR_INVALID_INPUT_FILE;
184    else
185        m_spIO->Seek(nWAVFormatHeaderExtra, FILE_CURRENT);
186
187    // find the data chunk
188    RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
189
190    while (!(RIFFChunkHeader.cChunkLabel[0] == 'd' && RIFFChunkHeader.cChunkLabel[1] == 'a' && RIFFChunkHeader.cChunkLabel[2] == 't' && RIFFChunkHeader.cChunkLabel[3] == 'a'))
191    {
192        // move the file pointer to the end of this chunk
193        m_spIO->Seek(RIFFChunkHeader.nChunkBytes, FILE_CURRENT);
194
195        // check again for the data chunk
196        RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
197    }
198
199    // we're at the data block
200    m_nHeaderBytes = m_spIO->GetPosition();
201    m_nDataBytes = RIFFChunkHeader.nChunkBytes;
202    if (m_nDataBytes < 0)
203        m_nDataBytes = m_nFileBytes - m_nHeaderBytes;
204
205    // make sure the data bytes is a whole number of blocks
206    if ((m_nDataBytes % m_wfeSource.nBlockAlign) != 0)
207        return ERROR_INVALID_INPUT_FILE;
208
209    // calculate the terminating byts
210    m_nTerminatingBytes = m_nFileBytes - m_nDataBytes - m_nHeaderBytes;
211
212    // we made it this far, everything must be cool
213    return ERROR_SUCCESS;
214}
215
216int CWAVInputSource::GetData(unsigned char * pBuffer, int nBlocks, int * pBlocksRetrieved)
217{
218    if (!m_bIsValid) return ERROR_UNDEFINED;
219
220    int nBytes = (m_wfeSource.nBlockAlign * nBlocks);
221    unsigned int nBytesRead = 0;
222
223    if (m_spIO->Read(pBuffer, nBytes, &nBytesRead) != ERROR_SUCCESS)
224        return ERROR_IO_READ;
225
226    if (pBlocksRetrieved) *pBlocksRetrieved = (nBytesRead / m_wfeSource.nBlockAlign);
227
228    return ERROR_SUCCESS;
229}
230
231int CWAVInputSource::GetHeaderData(unsigned char * pBuffer)
232{
233    if (!m_bIsValid) return ERROR_UNDEFINED;
234
235    int nRetVal = ERROR_SUCCESS;
236
237    if (m_nHeaderBytes > 0)
238    {
239        int nOriginalFileLocation = m_spIO->GetPosition();
240
241        m_spIO->Seek(0, FILE_BEGIN);
242
243        unsigned int nBytesRead = 0;
244        int nReadRetVal = m_spIO->Read(pBuffer, m_nHeaderBytes, &nBytesRead);
245
246        if ((nReadRetVal != ERROR_SUCCESS) || (m_nHeaderBytes != int(nBytesRead)))
247        {
248            nRetVal = ERROR_UNDEFINED;
249        }
250
251        m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
252    }
253
254    return nRetVal;
255}
256
257int CWAVInputSource::GetTerminatingData(unsigned char * pBuffer)
258{
259    if (!m_bIsValid) return ERROR_UNDEFINED;
260
261    int nRetVal = ERROR_SUCCESS;
262
263    if (m_nTerminatingBytes > 0)
264    {
265        int nOriginalFileLocation = m_spIO->GetPosition();
266
267        m_spIO->Seek(-m_nTerminatingBytes, FILE_END);
268
269        unsigned int nBytesRead = 0;
270        int nReadRetVal = m_spIO->Read(pBuffer, m_nTerminatingBytes, &nBytesRead);
271
272        if ((nReadRetVal != ERROR_SUCCESS) || (m_nTerminatingBytes != int(nBytesRead)))
273        {
274            nRetVal = ERROR_UNDEFINED;
275        }
276
277        m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
278    }
279
280    return nRetVal;
281}
282