Before I write anything else, let me state that this is a perfect example of HOW NOT TO CODE!! (but it does function for the 2 files I tested with - surprisingly)
I've written this in much the same way I wrote everything when I was 16 - it's all Dog 'n' Bird..... Rough-Rough, Cheap-Cheap
I should note that 1 of the empty do while loops IS needed. - We're just continually polling to see if WaveOutWrite has set the WHDR_DONE bit in wh.dwFlags
However, you should be aware that the WAV format holds so much more than just raw data - it holds information needed for playback, it may also include compression and a plethora of other things.
I whipped this up using:
http://www.sonicspot.com/guide/wavefiles.html[
^]
And of course, MSDN..
This code is created on a system with Win7. Please, adjust the path to the wav file accordingly.
#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>
typedef struct wavFileHeader
{
long chunkId; long chunkSize; long riffType; };
typedef struct fmtChunk
{
long chunkId; long chunkDataSize; short compressionCode; short numChannels; long sampleRate; long avgBytesPerSec; short blockAlign; short significantBitsPerSample; short extraFormatBytes; };
typedef struct wavChunk
{
long chunkId;
long chunkDataSize;
};
char *readFileData(char *szFilename, long &dataLengthOut)
{
FILE *fp = fopen(szFilename, "rb");
long len;
char *buffer;
fseek(fp, 0, SEEK_END);
len = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = (char*) calloc(1, len+1);
fread(buffer, 1, len, fp);
fclose(fp);
dataLengthOut = len;
return buffer;
}
void parseWav(char *data)
{
long *mPtr;
void *tmpPtr;
char *buffer;
WAVEFORMATEX wf;
WAVEHDR wh;
HWAVEOUT hWaveOut;
fmtChunk mFmtChunk;
wavChunk mDataChunk;
mPtr = (long*)data;
if ( mPtr[0] == 0x46464952) {
mPtr += 3;
if (mPtr[0] == 0x20746D66) {
tmpPtr = mPtr;
memcpy(&mFmtChunk, tmpPtr, sizeof(mFmtChunk));
tmpPtr += 8;
tmpPtr += mFmtChunk.chunkDataSize;
mPtr = (long*)tmpPtr;
if (mPtr[0] == 0x61746164) {
tmpPtr = mPtr;
memcpy(&mDataChunk, tmpPtr, sizeof(mDataChunk));
mPtr += 2;
buffer = (char*) malloc(mDataChunk.chunkDataSize);
memcpy(buffer, mPtr, mDataChunk.chunkDataSize);
printf("sampleRate: %d\n", mFmtChunk.sampleRate);
wf.wFormatTag = mFmtChunk.compressionCode;
wf.nChannels = mFmtChunk.numChannels;
wf.nSamplesPerSec = mFmtChunk.sampleRate;
wf.nAvgBytesPerSec = mFmtChunk.avgBytesPerSec;
wf.nBlockAlign = mFmtChunk.blockAlign;
wf.wBitsPerSample = mFmtChunk.significantBitsPerSample;
wf.cbSize = mFmtChunk.extraFormatBytes;
wh.lpData = buffer;
wh.dwBufferLength = mDataChunk.chunkDataSize;
wh.dwFlags = 0;
wh.dwLoops = 0;
waveOutOpen(&hWaveOut,WAVE_MAPPER,&wf,0,0,CALLBACK_NULL);
waveOutPrepareHeader(hWaveOut,&wh,sizeof(wh));
waveOutWrite(hWaveOut,&wh,sizeof(wh));
do {}
while (!(wh.dwFlags & WHDR_DONE));
waveOutUnprepareHeader(hWaveOut,&wh,sizeof(wh));
waveOutClose(hWaveOut);
free(buffer);
}
}
}
else
printf("INvalid WAV\n");
}
int main()
{
char *filename = "c:/windows/media/tada.wav";
char *buffer;
long fileSize;
buffer = readFileData(filename, fileSize);
parseWav(buffer);
free(buffer);
return 0;
}
EDIT: I just played with this code some more, discovering much to my horror - that the program hung after playing the sound when the release version was run -(never flicked it over from being a debug build)
It seems that the compiler was optimizing the empty do while loop - not realizing that code outside of my source was going to modify wh.dwFlags
The solution was to add the volatile keyword thusly:
volatile WAVEHDR wh;
and to cast any use of &wh like so:
(wavehdr_tag*)&wh