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