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 35 CInputSource * __stdcall CreateInputSource(const wchar_t * 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 wchar_t * 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 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 92 CWAVInputSource::CWAVInputSource(const wchar_t * 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 126 CWAVInputSource::~CWAVInputSource() 127 { 128 129 130 } 131 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 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 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 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