#include "All.h"
#include "WAVInputSource.h"
#include IO_HEADER_FILE
#include "MACLib.h"
#include "GlobalFunctions.h"
struct RIFF_HEADER
{
char cRIFF[4];
unsigned long nBytes;
};
struct DATA_TYPE_ID_HEADER
{
char cDataTypeID[4];
};
struct WAV_FORMAT_HEADER
{
unsigned short nFormatTag;
unsigned short nChannels;
unsigned long nSamplesPerSecond;
unsigned long nBytesPerSecond;
unsigned short nBlockAlign;
unsigned short nBitsPerSample;
};
struct RIFF_CHUNK_HEADER
{
char cChunkLabel[4];
unsigned long nChunkBytes;
};
CInputSource * __stdcall CreateInputSource(const char* pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
{
if ((pSourceName == NULL) || (wcslen(pSourceName) == 0))
{
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
return NULL;
}
const char* pExtension = &pSourceName[wcslen(pSourceName)];
while ((pExtension > pSourceName) && (*pExtension != '.'))
pExtension--;
if (pErrorCode) *pErrorCode = ERROR_SUCCESS;
return new CWAVInputSource(pSourceName, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode);
}
CWAVInputSource::CWAVInputSource(CIO * pIO, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
: CInputSource(pIO, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode)
{
m_bIsValid = FALSE;
if (pIO == NULL || pwfeSource == NULL)
{
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
return;
}
m_spIO.Assign(pIO, FALSE, FALSE);
int nRetVal = AnalyzeSource();
if (nRetVal == ERROR_SUCCESS)
{
if (pwfeSource) memcpy(pwfeSource, &m_wfeSource, sizeof(WAVEFORMATEX));
if (pTotalBlocks) *pTotalBlocks = m_nDataBytes / m_wfeSource.nBlockAlign;
if (pHeaderBytes) *pHeaderBytes = m_nHeaderBytes;
if (pTerminatingBytes) *pTerminatingBytes = m_nTerminatingBytes;
m_bIsValid = TRUE;
}
if (pErrorCode) *pErrorCode = nRetVal;
}
CWAVInputSource::CWAVInputSource(const char* pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
: CInputSource(pSourceName, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode)
{
m_bIsValid = FALSE;
if (pSourceName == NULL || pwfeSource == NULL)
{
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
return;
}
m_spIO.Assign(new IO_CLASS_NAME);
if (m_spIO->Open(pSourceName) != ERROR_SUCCESS)
{
m_spIO.Delete();
if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
return;
}
int nRetVal = AnalyzeSource();
if (nRetVal == ERROR_SUCCESS)
{
if (pwfeSource) memcpy(pwfeSource, &m_wfeSource, sizeof(WAVEFORMATEX));
if (pTotalBlocks) *pTotalBlocks = m_nDataBytes / m_wfeSource.nBlockAlign;
if (pHeaderBytes) *pHeaderBytes = m_nHeaderBytes;
if (pTerminatingBytes) *pTerminatingBytes = m_nTerminatingBytes;
m_bIsValid = TRUE;
}
if (pErrorCode) *pErrorCode = nRetVal;
}
CWAVInputSource::~CWAVInputSource()
{
}
int CWAVInputSource::AnalyzeSource()
{
m_spIO->Seek(0, FILE_BEGIN);
m_nFileBytes = m_spIO->GetSize();
RIFF_HEADER RIFFHeader;
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFHeader, sizeof(RIFFHeader)))
if (!(RIFFHeader.cRIFF[0] == 'R' && RIFFHeader.cRIFF[1] == 'I' && RIFFHeader.cRIFF[2] == 'F' && RIFFHeader.cRIFF[3] == 'F'))
return ERROR_INVALID_INPUT_FILE;
DATA_TYPE_ID_HEADER DataTypeIDHeader;
RETURN_ON_ERROR(ReadSafe(m_spIO, &DataTypeIDHeader, sizeof(DataTypeIDHeader)))
if (!(DataTypeIDHeader.cDataTypeID[0] == 'W' && DataTypeIDHeader.cDataTypeID[1] == 'A' && DataTypeIDHeader.cDataTypeID[2] == 'V' && DataTypeIDHeader.cDataTypeID[3] == 'E'))
return ERROR_INVALID_INPUT_FILE;
RIFF_CHUNK_HEADER RIFFChunkHeader;
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
while (!(RIFFChunkHeader.cChunkLabel[0] == 'f' && RIFFChunkHeader.cChunkLabel[1] == 'm' && RIFFChunkHeader.cChunkLabel[2] == 't' && RIFFChunkHeader.cChunkLabel[3] == ' '))
{
m_spIO->Seek(RIFFChunkHeader.nChunkBytes, FILE_CURRENT);
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
}
WAV_FORMAT_HEADER WAVFormatHeader;
RETURN_ON_ERROR(ReadSafe(m_spIO, &WAVFormatHeader, sizeof(WAVFormatHeader)))
if (WAVFormatHeader.nFormatTag != 1)
return ERROR_INVALID_INPUT_FILE;
FillWaveFormatEx(&m_wfeSource, WAVFormatHeader.nSamplesPerSecond, WAVFormatHeader.nBitsPerSample, WAVFormatHeader.nChannels);
int nWAVFormatHeaderExtra = RIFFChunkHeader.nChunkBytes - sizeof(WAVFormatHeader);
if (nWAVFormatHeaderExtra < 0)
return ERROR_INVALID_INPUT_FILE;
else
m_spIO->Seek(nWAVFormatHeaderExtra, FILE_CURRENT);
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
while (!(RIFFChunkHeader.cChunkLabel[0] == 'd' && RIFFChunkHeader.cChunkLabel[1] == 'a' && RIFFChunkHeader.cChunkLabel[2] == 't' && RIFFChunkHeader.cChunkLabel[3] == 'a'))
{
m_spIO->Seek(RIFFChunkHeader.nChunkBytes, FILE_CURRENT);
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
}
m_nHeaderBytes = m_spIO->GetPosition();
m_nDataBytes = RIFFChunkHeader.nChunkBytes;
if (m_nDataBytes < 0)
m_nDataBytes = m_nFileBytes - m_nHeaderBytes;
if ((m_nDataBytes % m_wfeSource.nBlockAlign) != 0)
return ERROR_INVALID_INPUT_FILE;
m_nTerminatingBytes = m_nFileBytes - m_nDataBytes - m_nHeaderBytes;
return ERROR_SUCCESS;
}
int CWAVInputSource::GetData(unsigned char * pBuffer, int nBlocks, int * pBlocksRetrieved)
{
if (!m_bIsValid) return ERROR_UNDEFINED;
int nBytes = (m_wfeSource.nBlockAlign * nBlocks);
unsigned int nBytesRead = 0;
if (m_spIO->Read(pBuffer, nBytes, &nBytesRead) != ERROR_SUCCESS)
return ERROR_IO_READ;
if (pBlocksRetrieved) *pBlocksRetrieved = (nBytesRead / m_wfeSource.nBlockAlign);
return ERROR_SUCCESS;
}
int CWAVInputSource::GetHeaderData(unsigned char * pBuffer)
{
if (!m_bIsValid) return ERROR_UNDEFINED;
int nRetVal = ERROR_SUCCESS;
if (m_nHeaderBytes > 0)
{
int nOriginalFileLocation = m_spIO->GetPosition();
m_spIO->Seek(0, FILE_BEGIN);
unsigned int nBytesRead = 0;
int nReadRetVal = m_spIO->Read(pBuffer, m_nHeaderBytes, &nBytesRead);
if ((nReadRetVal != ERROR_SUCCESS) || (m_nHeaderBytes != int(nBytesRead)))
{
nRetVal = ERROR_UNDEFINED;
}
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
}
return nRetVal;
}
int CWAVInputSource::GetTerminatingData(unsigned char * pBuffer)
{
if (!m_bIsValid) return ERROR_UNDEFINED;
int nRetVal = ERROR_SUCCESS;
if (m_nTerminatingBytes > 0)
{
int nOriginalFileLocation = m_spIO->GetPosition();
m_spIO->Seek(-m_nTerminatingBytes, FILE_END);
unsigned int nBytesRead = 0;
int nReadRetVal = m_spIO->Read(pBuffer, m_nTerminatingBytes, &nBytesRead);
if ((nReadRetVal != ERROR_SUCCESS) || (m_nTerminatingBytes != int(nBytesRead)))
{
nRetVal = ERROR_UNDEFINED;
}
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
}
return nRetVal;
}