// Modified slightly from source code from http://www.pocketpcdn.com/articles/multiplewaves.html // // Revision history: // October 11, 2008 - (Johan Sanneblad) Added error handling if file could not be read properly // #include #include #define OFFSET_FORMATTAG 20 #define OFFSET_CHANNELS 22 #define OFFSET_SAMPLESPERSEC 24 #define OFFSET_AVGBYTESPERSEC 28 #define OFFSET_BLOCKALIGN 32 #define OFFSET_BITSPERSAMPLE 34 #define OFFSET_WAVEDATA 44 #define HEADER_SIZE OFFSET_WAVEDATA class CWaveFile { char *lpfile; int file_size; WAVEFORMATEX wfex; HWAVEOUT hwo; public: WAVEHDR* Play(bool loop); void Stop(WAVEHDR *whdr); CWaveFile(LPCTSTR szFileName); ~CWaveFile(); }; void CALLBACK WaveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { switch(uMsg) { case WOM_OPEN: break; case WOM_DONE: { WAVEHDR* whdr = (WAVEHDR*)((size_t)dwParam1); if(whdr->dwUser) waveOutWrite(hwo, whdr, sizeof(WAVEHDR)); else { waveOutUnprepareHeader(hwo, whdr, sizeof(WAVEHDR)); delete whdr; } } break; case WOM_CLOSE: break; } } CWaveFile::CWaveFile(LPCTSTR szFileName) { // Member variable initialization lpfile = NULL; file_size = 0; memset(&wfex, 0, sizeof(WAVEFORMATEX)); memset(&hwo, 0, sizeof(HWAVEOUT)); FILE *f; // Structure to load the file into memory // Open and read the wave file f = _tfopen(szFileName, _T("rb")); if(!f) // Error, file not found. return; // Determine the file size fseek(f, 0, SEEK_END); file_size = ftell(f); // Rewind the pointer to the begginning so we can read it fseek(f, 0, SEEK_SET); // Request enough memory to store the entire file lpfile = new char[file_size]; // 'Copy' the file to memory fread(lpfile, 1, file_size, f); // Close the file, we won't need it anymore fclose(f); // Fill WAVEFORMATEX with the data from the file wfex.wFormatTag = *((WORD* )(lpfile + OFFSET_FORMATTAG )); wfex.nChannels = *((WORD* )(lpfile + OFFSET_CHANNELS )); wfex.nSamplesPerSec = *((DWORD*)(lpfile + OFFSET_SAMPLESPERSEC )); wfex.nAvgBytesPerSec = *((DWORD*)(lpfile + OFFSET_AVGBYTESPERSEC)); wfex.nBlockAlign = *((WORD* )(lpfile + OFFSET_BLOCKALIGN )); wfex.wBitsPerSample = *((WORD* )(lpfile + OFFSET_BITSPERSAMPLE )); return; } CWaveFile::~CWaveFile() { if (lpfile) { waveOutClose(hwo); delete [] lpfile; } } WAVEHDR* CWaveFile::Play(bool loop=false) { if (!lpfile) return NULL; WAVEHDR *whdr = new WAVEHDR; ZeroMemory((void*)whdr, sizeof(WAVEHDR)); whdr->lpData = lpfile+HEADER_SIZE; whdr->dwBufferLength = file_size-HEADER_SIZE; whdr->dwUser = (DWORD)loop; // Find a waveOut device and open it for(UINT devid = 0; devid < waveOutGetNumDevs(); devid++) { if(devid == waveOutGetNumDevs()) // Error, no free devices found return NULL; if(waveOutOpen(&hwo, WAVE_MAPPER, &wfex, (DWORD)(size_t)WaveOutProc, 0, CALLBACK_FUNCTION) == MMSYSERR_NOERROR) // Usable device found, stop searching break; } if(waveOutPrepareHeader(hwo, whdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) return NULL; if(waveOutWrite(hwo, whdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) return NULL; // Return the pointer to the WAVEHDR we used here return whdr; } void CWaveFile::Stop(WAVEHDR *whdr) { if (!lpfile) return; if(whdr) whdr->dwUser = (DWORD)false; }