Click here to Skip to main content
15,921,622 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.

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. :)
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 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