/***********************************************************************
* wavelib.c
*
* Audio Library
*
*
* Supports .WAV files, Very Simplistic Parser
*
*
* Toby Opferman Copyright (c) 2003
*
***********************************************************************/
#include <windows.h>
#include <mmsystem.h>
#include <wavelib.h>
/***********************************************************************
* Internal Structures
***********************************************************************/
typedef struct {
UCHAR IdentifierString[4];
DWORD dwLength;
} RIFF_CHUNK, *PRIFF_CHUNK;
typedef struct {
WORD wFormatTag; // Format category
WORD wChannels; // Number of channels
DWORD dwSamplesPerSec; // Sampling rate
DWORD dwAvgBytesPerSec; // For buffer estimation
WORD wBlockAlign; // Data block size
WORD wBitsPerSample;
} WAVE_FILE_HEADER, *PWAVE_FILE_HEADER;
typedef struct _wave_sample {
WAVEFORMATEX WaveFormatEx;
char *pSampleData;
UINT Index;
UINT Size;
DWORD dwId;
DWORD bPlaying;
struct _wave_sample *pNext;
} WAVE_SAMPLE, *PWAVE_SAMPLE;
#define SAMPLE_SIZE (2*2*2000)
typedef struct {
HWAVEOUT hWaveOut;
HANDLE hEvent;
HANDLE hThread;
WAVE_SAMPLE WaveSample;
BOOL bWaveShouldDie;
WAVEHDR WaveHdr[8];
char AudioBuffer[8][SAMPLE_SIZE];
BOOL bPaused;
} WAVELIB, *PWAVELIB;
/***********************************************************************
* Internal Functions
***********************************************************************/
void CALLBACK WaveLib_WaveOutputCallback(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
BOOL WaveLib_OpenWaveSample(CHAR *pFileName, PWAVE_SAMPLE pWaveSample);
void WaveLib_WaveOpen(HWAVEOUT hWaveOut, PWAVELIB pWaveLib);
void WaveLib_WaveDone(HWAVEOUT hWaveOut, PWAVELIB pWaveLib);
DWORD WINAPI WaveLib_AudioThread(PVOID pDataInput);
void WaveLib_CreateThread(PWAVELIB pWaveLib);
void WaveLib_SetupAudio(PWAVELIB pWaveLib);
void WaveLib_WaveClose(HWAVEOUT hWaveOut, PWAVELIB pWaveLib);
void WaveLib_AudioBuffer(PWAVELIB pWaveLib, UINT Index);
/***********************************************************************
* WaveLib_Init
*
* Audio!
*
* Parameters
*
*
* Return Value
* Handle To This Audio Session
*
***********************************************************************/
HWAVELIB WaveLib_Init(PCHAR pWaveFile, BOOL bPause)
{
PWAVELIB pWaveLib = NULL;
if(pWaveLib = (PWAVELIB)LocalAlloc(LMEM_ZEROINIT, sizeof(WAVELIB)))
{
pWaveLib->bPaused = bPause;
if(WaveLib_OpenWaveSample(pWaveFile, &pWaveLib->WaveSample))
{
if(waveOutOpen(&pWaveLib->hWaveOut, WAVE_MAPPER, &pWaveLib->WaveSample.WaveFormatEx, (ULONG)WaveLib_WaveOutputCallback, (ULONG)pWaveLib, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
{
WaveLib_UnInit((HWAVELIB)pWaveLib);
pWaveLib = NULL;
}
else
{
if(pWaveLib->bPaused)
{
waveOutPause(pWaveLib->hWaveOut);
}
WaveLib_CreateThread(pWaveLib);
}
}
else
{
WaveLib_UnInit((HWAVELIB)pWaveLib);
pWaveLib = NULL;
}
}
return (HWAVELIB)pWaveLib;
}
/***********************************************************************
* WaveLib_Pause
*
* Audio!
*
* Parameters
*
*
* Return Value
* Handle To This Audio Session
*
***********************************************************************/
void WaveLib_Pause(HWAVELIB hWaveLib, BOOL bPause)
{
PWAVELIB pWaveLib = (PWAVELIB)hWaveLib;
pWaveLib->bPaused = bPause;
if(pWaveLib->bPaused)
{
waveOutPause(pWaveLib->hWaveOut);
}
else
{
waveOutRestart(pWaveLib->hWaveOut);
}
}
/***********************************************************************
* WaveLib_Init
*
* Audio!
*
* Parameters
*
*
* Return Value
* Handle To This Audio Session
*
***********************************************************************/
void WaveLib_UnInit(HWAVELIB hWaveLib)
{
PWAVELIB pWaveLib = (PWAVELIB)hWaveLib;
if(pWaveLib)
{
if(pWaveLib->hThread)
{
pWaveLib->bWaveShouldDie = TRUE;
SetEvent(pWaveLib->hEvent);
WaitForSingleObject(pWaveLib->hThread, INFINITE);
CloseHandle(pWaveLib->hEvent);
CloseHandle(pWaveLib->hThread);
}
if(pWaveLib->hWaveOut)
{
waveOutClose(pWaveLib->hWaveOut);
}
if(pWaveLib->WaveSample.pSampleData)
{
LocalFree(pWaveLib->WaveSample.pSampleData);
}
LocalFree(pWaveLib);
}
}
/***********************************************************************
* WaveLib_WaveOutputCallback
*
* Audio Callback
*
* Parameters
*
*
* Return Value
* Handle To This Audio Session
*
***********************************************************************/
void CALLBACK WaveLib_WaveOutputCallback(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
PWAVELIB pWaveLib = (PWAVELIB)dwInstance;
switch(uMsg)
{
case WOM_OPEN:
WaveLib_WaveOpen(hwo, pWaveLib);
break;
case WOM_DONE:
WaveLib_WaveDone(hwo, pWaveLib);
break;
case WOM_CLOSE:
WaveLib_WaveClose(hwo, pWaveLib);
break;
}
}
/***********************************************************************
* WaveLib_WaveOpen
*
* Audio Callback
*
* Parameters
*
*
* Return Value
* Handle To This Audio Session
*
***********************************************************************/
void WaveLib_WaveOpen(HWAVEOUT hWaveOut, PWAVELIB pWaveLib)
{
// Do Nothing
}
/***********************************************************************
* WaveLib_WaveDone
*
* Audio Callback
*
* Parameters
*
*
* Return Value
* Handle To This Audio Session
*
***********************************************************************/
void WaveLib_WaveDone(HWAVEOUT hWaveOut, PWAVELIB pWaveLib)
{
SetEvent(pWaveLib->hEvent);
}
/***********************************************************************
* WaveLib_WaveClose
*
* Audio Callback
*
* Parameters
*
*
* Return Value
* Handle To This Audio Session
*
***********************************************************************/
void WaveLib_WaveClose(HWAVEOUT hWaveOut, PWAVELIB pWaveLib)
{
// Do Nothing
}
/***********************************************************************
* WaveLib_OpenWaveFile
*
* Audio Callback
*
* Parameters
*
*
* Return Value
* Handle To This Audio Session
*
***********************************************************************/
BOOL WaveLib_OpenWaveSample(CHAR *pFileName, PWAVE_SAMPLE pWaveSample)
{
BOOL bSampleLoaded = FALSE;
HANDLE hFile;
RIFF_CHUNK RiffChunk = {0};
DWORD dwBytes, dwReturnValue;
WAVE_FILE_HEADER WaveFileHeader;
DWORD dwIncrementBytes;
if(hFile = CreateFile(pFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL))
{
char szIdentifier[5] = {0};
SetFilePointer(hFile, 12, NULL