#include "stdafx.h"
#include <mmsystem.h> // waveOutxxx
#include <io.h> // fileLength
#include "VocPlay.h"
CVocPlayer::CVocPlayer()
:pData(NULL), hWaveOut(0), boPlaying(false)
{
}
CVocPlayer::~CVocPlayer()
{
if ( boPlaying )
Clear();
}
void CVocPlayer::Play( const CString &rcFileName, CWnd *pCallbackWnd )
{
Clear();
// Decode the file
FILEINFO sFileInfo;
Decode( rcFileName, &sFileInfo );
// Prepare a WAVEFORMATEX required for opening the device driver
WAVEFORMATEX sWaveFormat;
sWaveFormat.wFormatTag = WAVE_FORMAT_PCM;
sWaveFormat.nChannels = sFileInfo.ucChannels;
sWaveFormat.nSamplesPerSec = sFileInfo.lSamplesPerSeconds;
sWaveFormat.nAvgBytesPerSec = sFileInfo.lSamplesPerSeconds;
sWaveFormat.nBlockAlign = 1;
sWaveFormat.wBitsPerSample = sFileInfo.ucBitsPerSample;
sWaveFormat.cbSize = sizeof(WAVEFORMATEX);
// Try to open the device driver
MMRESULT Result = waveOutOpen( &hWaveOut, WAVE_MAPPER, &sWaveFormat,
(ULONG)pCallbackWnd->m_hWnd, 0,
CALLBACK_WINDOW );
if ( Result != MMSYSERR_NOERROR )
{
hWaveOut = 0;
return;
}
// Prepare the header
sWaveHdr.lpData = pData;
sWaveHdr.dwBufferLength = sFileInfo.lTotalLength;
sWaveHdr.dwFlags = 0;
sWaveHdr.dwLoops = 0;
waveOutPrepareHeader( hWaveOut, &sWaveHdr, sizeof(sWaveHdr) );
// Play the file
boPlaying = true;
waveOutWrite( hWaveOut, &sWaveHdr, sizeof(sWaveHdr) );
}
void CVocPlayer::Clear()
{
if ( !boPlaying )
return;
waveOutUnprepareHeader( hWaveOut, &sWaveHdr, sizeof(sWaveHdr) );
delete [] pData;
pData = NULL;
waveOutClose( hWaveOut );
boPlaying = false;
}
void CVocPlayer::Decode( const CString &rcFileName, FILEINFO *psFileInfo )
{
// Open the file and allocate the memory
FILE *pFile = fopen( rcFileName, "rb" );
long lFileLength = _filelength( _fileno(pFile) );
pData = new char[ lFileLength ];
char *pDataPos = pData;
// Place the file pointer at the beginning of the data
fseek( pFile, 0x1A, SEEK_SET );
BYTE bType;
signed long int lLen;
do
{
// Read the block type
fread( &bType, sizeof(bType), 1, pFile );
lLen = 0;
switch( bType )
{
case 1:
{
fread( &lLen, 3, 1, pFile );
lLen -= 2; // Remove Time Constant and File Format bytes
fread( &psFileInfo->usTimeConstant, 1, 1, pFile );
fread( &psFileInfo->usFileFormat, 1, 1, pFile );
// For the moment, it's a plain 8-bit mono file
psFileInfo->ucBitsPerSample = 8;
psFileInfo->ucChannels = 1;
psFileInfo->lSamplesPerSeconds = 1000000 /
(256-(psFileInfo->usTimeConstant % 256));
// Store this sample in memory
fread( pDataPos, lLen, 1, pFile );
pDataPos += lLen;
break;
}
case 8:
{
fseek( pFile, 3, SEEK_CUR ); // Skip the length
fread( &psFileInfo->usTimeConstant, 2, 1, pFile );
fread( &psFileInfo->usFileFormat, 1, 1, pFile );
fread( &psFileInfo->ucChannels, 1, 1, pFile );
// Block of type 8 is always followed by a block of type 1
fread( &bType, sizeof(bType), 1, pFile );
fread( &lLen, 3, 1, pFile );
lLen -= 2; // Remove Time Constant and File Format bytes
fseek( pFile, 2, SEEK_CUR ); // Skip T.C. and F.F.
psFileInfo->ucBitsPerSample = 8;
psFileInfo->ucChannels++;
psFileInfo->usTimeConstant >>= 8;
psFileInfo->lSamplesPerSeconds = 1000000 /
(256-(psFileInfo->usTimeConstant % 256));
// Store this sample in memory
fread( pDataPos, lLen, 1, pFile );
pDataPos += lLen;
break;
}
case 9:
{
fread( &lLen, 3, 1, pFile );
lLen -= 12;
fread( &psFileInfo->lSamplesPerSeconds, 4, 1, pFile );
fread( &psFileInfo->ucBitsPerSample, 1, 1, pFile );
fread( &psFileInfo->ucChannels, 1, 1, pFile );
fread( &psFileInfo->usFileFormat, 2, 1, pFile );
// Store this sample in memory
fread( pDataPos, lLen, 1, pFile );
pDataPos += lLen;
break;
}
};
} while ( bType != 0 );
psFileInfo->lTotalLength = pDataPos-pData;
fclose( pFile );
}