Code:
#include <windows.h>
#include <stdbool.h>
#define MAXBUFFSIZE 44100
#define WM_PLYBCKERR (WM_USER+1)
#define WM_ENDPLAY (WM_USER+2)
#define FLAG_RTHR 0x00000001
#define FLAG_STHR 0xFFFFFFFE
#define FLAG_PLAY 0x00000002
#define FLAG_STOP 0xFFFFFFFD
#define FLAG_REST 0x00000004
#define FLAG_STAR 0xFFFFFFFB
#define FLAG_DONE 0x00000008
#define FLAG_NDON 0xFFFFFFF7
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
typedef struct _wave_struct {
WAVEFORMATEX wsFormat;
PBYTE FileData;
LPWAVEHDR Hdrs;
unsigned int HdrC;
} WAVE_STRUCT, *PWAVE_STRUCT;
typedef struct _wave_file_hdr {
char wfhSign[4];
unsigned int wfhChnkSize;
char wfhFormat[4];
char wfhSubChnk1ID[4];
unsigned int wfhSubChnk1Size;
unsigned short wfhAudFormat;
unsigned short wfhChannels;
unsigned int wfhSampPerSec;
unsigned int wfhAvgBytesPerSec;
unsigned short wfhBlockAlign;
unsigned short wfhBitsPerSamp;
char wfhSubChnk2Sign[4];
unsigned int wfhSubChnk2Size;
} WAVE_FILE_HDR, *PWAVE_FILE_HDR;
typedef HANDLE THREAD;
typedef struct _thr_data {
THREAD Thr;
WAVE_STRUCT ws;
HWAVEOUT wOut;
unsigned int Flags;
char *wLoc;
HWND hwndPar;
ULONG ID;
} THREAD_DATA, *PTHREAD_DATA;
CRITICAL_SECTION wCrit;
bool LoadWaveFile(PWAVE_STRUCT ws,char *Loc){
if(!ws||!Loc){
SetLastError(ERROR_INVALID_PARAMETER);
return false;
}
WAVE_FILE_HDR Head = {{0,0,0,0},0,{0,0,0,0},{0,0,0,0},0,0,0,0,0,0,0,{0,0,0,0},0};
DWORD Read = 0, i = 0;
PBYTE wPoint = 0;
HANDLE wFile = CreateFile(Loc,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
if(wFile==INVALID_HANDLE_VALUE) return false;
if(!ReadFile(wFile,&Head,sizeof(Head),&Read,NULL)){
CloseHandle(wFile);
return false;
}
if(Head.wfhSign[0] != 'R' || Head.wfhSign[1] != 'I' || Head.wfhSign[2] != 'F' || Head.wfhSign[3] != 'F'){
SetLastError(ERROR_NOT_SUPPORTED);
CloseHandle(wFile);
return false;
}
if(Head.wfhFormat[0] != 'W' || Head.wfhFormat[1] != 'A' || Head.wfhFormat[2] != 'V' || Head.wfhFormat[3] != 'E'){
CloseHandle(wFile);
SetLastError(ERROR_NOT_SUPPORTED);
return false;
}
if(Head.wfhAudFormat!=WAVE_FORMAT_PCM){
CloseHandle(wFile);
SetLastError(ERROR_NOT_SUPPORTED);
return false;
}
Read = 1 + (Head.wfhChnkSize-36) / MAXBUFFSIZE;
ws->Hdrs = (WAVEHDR*)malloc(Read*sizeof(WAVEHDR)+(Head.wfhChnkSize-36));
ZeroMemory(ws->Hdrs,Read*sizeof(WAVEHDR)+(Head.wfhChnkSize-36));
if(!ws->Hdrs){
CloseHandle(wFile);
SetLastError(ERROR_OUTOFMEMORY);
return false;
}
ws->FileData = (PBYTE)ws->Hdrs+Read*sizeof(WAVEHDR);
ws->HdrC = Read;
ReadFile(wFile,ws->FileData,Head.wfhChnkSize-36,&Read,NULL);
if(Read!=(Head.wfhChnkSize-36)){
free(ws->Hdrs);
CloseHandle(wFile);
free(ws->FileData);
return false;
}
ws->wsFormat.wFormatTag = WAVE_FORMAT_PCM;
ws->wsFormat.nChannels = Head.wfhChannels;
ws->wsFormat.nSamplesPerSec = Head.wfhSampPerSec;
ws->wsFormat.nAvgBytesPerSec = Head.wfhAvgBytesPerSec;
ws->wsFormat.nBlockAlign = Head.wfhBlockAlign;
ws->wsFormat.wBitsPerSample = Head.wfhBitsPerSamp;
ws->wsFormat.cbSize = 0;
CloseHandle(wFile);
wPoint = ws->FileData;
for(i=0;i<ws->HdrC-1;i++){
ws->Hdrs[i].lpData = wPoint;
ws->Hdrs[i].dwBufferLength = MAXBUFFSIZE;
wPoint += MAXBUFFSIZE;
}
ws->Hdrs[ws->HdrC-1].lpData = wPoint;
ws->Hdrs[ws->HdrC-1].dwBufferLength = (Head.wfhChnkSize-36) % MAXBUFFSIZE;
SetLastError(ERROR_SUCCESS);
return true;
}
void CALLBACK waveyProc(HWAVEOUT hwo,UINT uMsg,DWORD dwInstance,DWORD Param1,DWORD Param2){
if(uMsg==WOM_DONE){
unsigned int *Flags = (unsigned int*)dwInstance;
EnterCriticalSection(&wCrit);
*Flags |= FLAG_DONE;
LeaveCriticalSection(&wCrit);
}
return;
}
ULONG WINAPI PlayThr(volatile PTHREAD_DATA pThrDat){
MMRESULT mRes = MMSYSERR_NOERROR;
unsigned int Pos = 0;
if(!LoadWaveFile(&pThrDat->ws,pThrDat->wLoc)){
PostMessage(pThrDat->hwndPar,WM_PLYBCKERR,0,GetLastError());
ExitThread(0);
}
mRes = waveOutOpen(&pThrDat->wOut,WAVE_MAPPER,&pThrDat->ws.wsFormat,(DWORD_PTR)waveyProc,(DWORD_PTR)&pThrDat->Flags,CALLBACK_FUNCTION);
if(mRes!=MMSYSERR_NOERROR){
PostMessage(pThrDat->hwndPar,WM_PLYBCKERR,0,mRes);
free(pThrDat->ws.Hdrs);
ExitThread(0);
}
for(Pos=0;Pos<pThrDat->ws.HdrC;Pos++) waveOutPrepareHeader(pThrDat->wOut,&pThrDat->ws.Hdrs[Pos],sizeof(WAVEHDR));
Pos = 0;
waveOutWrite(pThrDat->wOut,&pThrDat->ws.Hdrs[Pos],sizeof(WAVEHDR));
while(pThrDat->Flags & FLAG_RTHR){
while(pThrDat->Flags & FLAG_PLAY){
if(pThrDat->Flags & FLAG_DONE){
Pos++;
if(Pos == pThrDat->ws.HdrC){
pThrDat->Flags &= FLAG_STOP;
Pos = 0;
}else{
waveOutWrite(pThrDat->wOut,&pThrDat->ws.Hdrs[Pos],sizeof(WAVEHDR));
}
pThrDat->Flags &= FLAG_NDON;
}
Sleep(10);
}
if(pThrDat->Flags & FLAG_REST){
Pos = 0;
pThrDat->Flags &= FLAG_STAR;
pThrDat->Flags |= FLAG_PLAY;
}
Sleep(250);
}
for(Pos=0;Pos<pThrDat->ws.HdrC;Pos++) waveOutUnprepareHeader(pThrDat->wOut,&pThrDat->ws.Hdrs[Pos],sizeof(WAVEHDR));
free(pThrDat->ws.Hdrs);
waveOutClose(pThrDat->wOut);
PostMessage(pThrDat->hwndPar,WM_ENDPLAY,0,0);
ExitThread(0);
}
char szClassName[ ] = "WavePlayer";
char err[512];
char *wLoc = NULL;
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nFunsterStil){
HWND hwnd;
MSG messages;
WNDCLASSEX wincl;
if(!SLen(lpszArgument)){
ErrorBox(NULL,"No sound file specified!");
return 0;
}else{
wLoc = lpszArgument;
}
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof(WNDCLASSEX);
wincl.hIcon = LoadIcon (NULL,IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL,IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL,IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
if(!RegisterClassEx(&wincl)) return 0;
hwnd = CreateWindowEx(
0,
szClassName,
"Wavey",
WS_OVERLAPPEDWINDOW|WS_VISIBLE,
CW_USEDEFAULT,
CW_USEDEFAULT,
400,
400,
NULL,
NULL,
hThisInstance,
NULL);
while(GetMessage(&messages,NULL,0,0)){
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
THREAD_DATA ThrData = {NULL,{{0,0,0,0,0,0,0},NULL,NULL,0},NULL,0,NULL};
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
switch (message){
case WM_CREATE: ;
ThrData.hwndPar = hwnd;
ThrData.wLoc = wLoc;
ThrData.Flags = FLAG_PLAY|FLAG_RTHR;
ThrData.Thr = CreateThread(NULL,1024,(LPTHREAD_START_ROUTINE)PlayThr,&ThrData,0,&ThrData.ID);
if(!ThrData.Thr){
ErrorBox(hwnd,"Unable to initialize playback thread!");
PostQuitMessage(0);
}
InitializeCriticalSection(&wCrit);
break;
case WM_LBUTTONDOWN: ;
if(ThrData.Thr){
if(ThrData.Flags & FLAG_PLAY){
ThrData.Flags &= FLAG_STOP;
}else{
ThrData.Flags |= FLAG_PLAY;
}
}
break;
case WM_RBUTTONDOWN: ;
if(ThrData.Thr){
if(ThrData.Flags & FLAG_PLAY){
ThrData.Flags &= FLAG_STOP;
}
ThrData.Flags |= FLAG_REST;
}
break;
case WM_PLYBCKERR: ;
sprintf(err,"Playback Error:\n(0x%X)",lParam);
ErrorBox(hwnd,err);
CloseHandle(ThrData.Thr);
break;
case WM_CLOSE: ;
if(ThrData.Thr){
ThrData.Flags &= FLAG_STOP;
ThrData.Flags &= FLAG_STHR;
break;
}
PostQuitMessage(0);
break;
case WM_ENDPLAY: ;
DestroyWindow(hwnd);
CloseHandle(ThrData.Thr);
break;
case WM_DESTROY: ;
DeleteCriticalSection(&wCrit);
PostQuitMessage(0);
break;
default: ;
return DefWindowProc (hwnd, message, wParam, lParam);
}
return ERROR_SUCCESS;
}
I'ts only supposed to play .wav files passed in the command line, and I'm compiling this program on Windows using the Bloodshed DevC++ IDE. I based this off an example from