Click here to Skip to main content
15,891,883 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Dear friends,
I am programming in C++ and have a problem with waveout API to run on my PC. Could anybody help me to get the code right to get it work properly please ? I am using VSC++ Express! I have included stdio.h, windows.h, and winmm.lib ! I will apreciated evry help !


C++
#define SOUNDBUFF 65536;
WAVEFORMATEX wf;
WAVEHDR whdr;
HWAVEOUT hWaveOut;
LPSTR lpData;
float clpData[65536];
 
int main(void)
{
 
FILE *f = fopen("c:/JP8080.wav","rb")
fwrite(&clpdata, 2, 1, sizeof(clpdata), f);
 
wf.wFormatTag=WAVE_FORMAT_PCM;
wf.nChannels=2;
wf.nSamplesPerSec=44100;
wf.nAvgBytesPerSec=(44100*4);
wf.nBlockAlign=(2*16)/8;
wf.wBitsPerSample=16;
wf.cbSize=0;

whdr.lpData = clpData;
whdr.dwBufferLength = SOUNDBUFF;
whdr.dwFlags = 0;
whdr.dwLoops = 0;
 
do {
} while (!(whdr.dwFlags & WHDR_DONE));
 
waveOutOpen(&hWaveOut,WAVE_MAPPER,&wf,0,0,CALLBACK_NULL);
waveOutPrepareHeader(hWaveOut,&whdr,sizeof(whdr));
waveOutWrite(hWaveOut,&whdr,sizeof(whdr));
 
do {
} while (!(whdr.dwFlags & WHDR_DONE));
 
waveOutUnprepareHeader(hWaveOut,&whdr,sizeof(whdr));
waveOutClose(hWaveOut);
 
return 0;
}
Posted
Updated 26-Mar-12 2:33am
v2
Comments
Jochen Arndt 26-Mar-12 8:45am    
Please try to compile at least one time to fix the obvious errors (too many parameters for fwrite). Apropos fwrite: I think your intention is to read. There also other serious bugs: The while loops will never terminate.

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.



C++
#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>

typedef struct wavFileHeader
{
    long chunkId;           //"RIFF" (0x52,0x49,0x46,0x46)
    long chunkSize;         // (fileSize - 8)  - could also be thought of as bytes of data in file following this field (bytesRemaining)
    long riffType;          // "WAVE" (0x57415645)
};

typedef struct fmtChunk
{
    long chunkId;                       // "fmt " - (0x666D7420)
    long chunkDataSize;                 // 16 + extra format bytes
    short compressionCode;              // 1 - 65535
    short numChannels;                  // 1 - 65535
    long sampleRate;                    // 1 - 0xFFFFFFFF
    long avgBytesPerSec;                // 1 - 0xFFFFFFFF
    short blockAlign;                   // 1 - 65535
    short significantBitsPerSample;     // 2 - 65535
    short extraFormatBytes;             // 0 - 65535
};

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) //  little endian check for 'RIFF'
    {
        mPtr += 3;
        if (mPtr[0] == 0x20746D66)  // little endian for "fmt "
        {
           // printf("Format chunk found\n");

            tmpPtr = mPtr;
            memcpy(&mFmtChunk, tmpPtr, sizeof(mFmtChunk));
            tmpPtr += 8;
            tmpPtr += mFmtChunk.chunkDataSize;

            mPtr = (long*)tmpPtr;
            if (mPtr[0] == 0x61746164)        // little endian for "data"
            {
            //    printf("Data chunk found\n");

                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:
C++
volatile WAVEHDR wh;

and to cast any use of &wh like so:
C++
(wavehdr_tag*)&wh
 
Share this answer
 
v3
This code is nearly 4 years old already, but I am pleased with it. Its the first example with WaveOut functions that I could get to work.

I needed another modification to make this work.
Some .wav files have an info block that we need to skip.
I had to insert this code just in front of the test for "data" (0x61746164):

if (mPtr[0] == 0x5453494C) {       // little endian for "LIST"
    // skip info chunk
    memcpy(&mDataChunk, tmpPtr, sizeof(mDataChunk));
    tmpPtr = (void*) (((char*) tmpPtr ) + 8 + mDataChunk.chunkDataSize);
    mPtr = (long*)tmpPtr;
}

if (mPtr[0] == 0x61746164)


Also my compiler (Borland CBuilder 6) complained about the syntax of this line:
tmpPtr += 8;

I had to change it to:
tmpPtr = (void*) ((char*) tmpPtr ) + 8;
 
Share this answer
 
v2
Comments
enhzflep 5-Jan-16 11:21am    
A good addition which many will be pleased to have.
I'm glad you found it useful. :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900