1 #include "All.h"
2 #include "WAVInputSource.h"
3 #include IO_HEADER_FILE
4 #include "MACLib.h"
5 #include "GlobalFunctions.h"
6
7 struct 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
13 struct DATA_TYPE_ID_HEADER
14 {
15 char cDataTypeID[4]; // should equal 'WAVE' for a WAV file
16 };
17
18 struct 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
28 struct 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
CreateInputSource(const char * pSourceName,WAVEFORMATEX * pwfeSource,int * pTotalBlocks,int * pHeaderBytes,int * pTerminatingBytes,int * pErrorCode)35 CInputSource * __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
CWAVInputSource(CIO * pIO,WAVEFORMATEX * pwfeSource,int * pTotalBlocks,int * pHeaderBytes,int * pTerminatingBytes,int * pErrorCode)64 CWAVInputSource::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
CWAVInputSource(const char * pSourceName,WAVEFORMATEX * pwfeSource,int * pTotalBlocks,int * pHeaderBytes,int * pTerminatingBytes,int * pErrorCode)92 CWAVInputSource::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
~CWAVInputSource()126 CWAVInputSource::~CWAVInputSource()
127 {
128
129
130 }
131
AnalyzeSource()132 int 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
GetData(unsigned char * pBuffer,int nBlocks,int * pBlocksRetrieved)216 int 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
GetHeaderData(unsigned char * pBuffer)231 int 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
GetTerminatingData(unsigned char * pBuffer)257 int 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