• (2 Pages)
  • +
  • 1
  • 2

Sound Recorder using the low level Windows API in C++ Recorder with wave visualisation Rate Topic: -----

#1 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 762
  • View blog
  • Posts: 2,218
  • Joined: 20-March 10

Posted 03 January 2011 - 04:28 PM

*
POPULAR

Sound Recorder in C++


Using the Low Level Windows API



FINAL VERSION

In this tutorial we will build a sound recorder program with wave visualisation and hopefullly end with
something like this :-

Posted Image

I have used Microsoft Visual Studio 2010 for this build it will not build under MinGW/gcc
without a few alterations to the code although I have built this in CodeBlocks/MinGW.

If required I will release a gcc version of this program.

First of all we start with declaring a few headers and constants.



#include <CommDlg.h>
#include <MMSystem.h>
#include <fstream>
#include <cstdlib>
#include "resource.h"

using namespace std;
//Globals for sound wave visualistion
int number, length, byte_samp, byte_sec, bit_samp;
static int sampleRate = 11025;
const int NUMPTS = 11025 * 10;
bool mono = TRUE;
bool PLAY = FALSE;
errno_t wavfile;
char * filename;
int s_rate = 11025;
double limit = 10000.0;
FILE * stream;
/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Declare procedures */
int readSample(int number,bool leftchannel);
void SaveWavFile(char *FileName, PWAVEHDR WaveHeader);
void Wav(char *c, HWND hWnd);
/*  Make the class name into a global variable  */
char szAppName[ ] = "Recorder";





next we define WinMain


// **********
// Windows Main Function.
// - Here starts our program
int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nCmdShow)
{

    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szAppName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = "APP_MENU";                 /*menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szAppName,         /* Classname */
               szAppName,       /* Title Text */
               WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               430,                 /* The programs width */
               300,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /*use class menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}




Next we have our callback function, this function processes messages sent to the window.

/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HWND RecButton;
    static HWND PlyButton;
    static HWND StpButton;
    static HMENU hMenu;
    static HPEN hPen;
    static BOOL         bRecording, bPlaying,bEnding, bTerminating ;
    static DWORD        dwDataLength, dwRepetitions = 1 ;
    static HWAVEIN      hWaveIn ;
    static HWAVEOUT     hWaveOut ;
    static PBYTE        pBuffer1, pBuffer2, pSaveBuffer, pNewBuffer ;
    static PWAVEHDR     pWaveHdr1, pWaveHdr2 ;
    static TCHAR        szOpenError[] = TEXT ("Error opening waveform audio!");
    static TCHAR        szMemError [] = TEXT ("Error allocating memory!") ;
    static WAVEFORMATEX waveform ;

    hMenu = GetMenu (hwnd);
    HDC hDC;
    POINT pt [NUM];
    BOOL fSuccess = FALSE;

    switch (message)                  /* handle the messages */
    {
    case WM_CREATE:
        RecButton = CreateWindow ( TEXT ("button"),"RECORD",WS_VISIBLE|WS_CHILD|ES_LEFT|1,7,175,100,25,hwnd,(HMENU) IDC_RECORD,((LPCREATESTRUCT) lParam) -> hInstance,NULL);
        PlyButton = CreateWindow ( TEXT ("button"),"PLAY",WS_VISIBLE|WS_CHILD|ES_LEFT|1,157,175,100,25,hwnd,(HMENU) IDC_PLAY,((LPCREATESTRUCT) lParam) -> hInstance,NULL);
        StpButton = CreateWindow ( TEXT ("button"),"STOP",WS_VISIBLE|WS_CHILD|ES_LEFT|1,314,175,100,25,hwnd,(HMENU) IDC_STOP,((LPCREATESTRUCT) lParam) -> hInstance,NULL);
        EnableWindow (PlyButton, FALSE) ;
        EnableWindow (StpButton, FALSE)  ;

        pWaveHdr1 =  reinterpret_cast <PWAVEHDR> ( malloc (sizeof (WAVEHDR)) );
        pWaveHdr2 = reinterpret_cast <PWAVEHDR> ( malloc (sizeof (WAVEHDR)) ) ;
        // Allocate memory for save buffer

        pSaveBuffer = reinterpret_cast <PBYTE> ( malloc (1) ) ;
		 
        return 0;



This creates a menu and a few buttons the play button is set to disabled or grayed out
and so is the stop button.

we also allocate memory for the save buffer and the Wave Headers pWaveHdr1 and pWaveHdr2 at this point.

next up we look at how we paint our window.

case WM_PAINT:
        PAINTSTRUCT 	ps;
        hDC = BeginPaint(hwnd, &ps);

        if (hDC)
        {
            RECT rc;
            rc.top = 35;
			rc.left = 0;
			rc.bottom = 145;
			rc.right = 425;
			FillRect(hDC,&rc,(HBRUSH)(COLOR_WINDOW+2));
            if (PLAY==TRUE)
            {
		FillRect(hDC,&rc,(HBRUSH)(COLOR_WINDOW+2));
                hPen = CreatePen(PS_SOLID,1,RGB(0,200,0));
                SelectObject(hDC, hPen);

                SetMapMode(hDC, MM_ISOTROPIC);
                SetWindowExtEx(hDC, 400, 300, NULL);
                SetViewportExtEx(hDC,200, 180, NULL);
                SetViewportOrgEx(hDC, 0, 0, NULL);

                int sample=0;
                int i=1;
                int num = 60000;
                sample= readSample(i, TRUE);
                // scale the sample

                pt[i].x =i/20;
                pt[i].y = (int) ((sample)*1.5);
                MoveToEx (hDC,pt[i].x,pt[i].y,NULL);
                while (i<num && sample!=(int)0xefffffff)
                {
                    // scale the sample

                    pt[i].x = i/20;
                    pt[i].y = (int) ((sample)*1.5);

                    LineTo(hDC, pt[i].x,pt[i].y);
                    i++;
                    sample= readSample(i, TRUE);

                }


            }
            DeleteObject(hPen);
            DeleteDC(hDC);
            
			EndPaint(hwnd, &ps);

        }
        return 0;



First we Use a FillRect command to create a black box
which will hold our wave visualisation.

If the variable PLAY is true we draw the wave visualisation graph,
with CreatePen we make a lime green pen to draw with.

Then we set the Map Mode to something useful.

Then we start to draw our sample which is only a few seconds long
through our readSample function which we will discuss next.

//start of wave visualisation process

int readSample(int number,bool leftchannel)
{

    /*
      Reads sample number, returns it as an int, if
      this.mono==false we look at the leftchannel bool
      to determine which to return.

      number is in the range [0,length/byte_samp]

      returns 0xefffffff on failure
    */

    if (number>=0 && number<length/byte_samp)
    {
        // go to beginning of the file
        rewind(stream);

        // we start reading at sample_number * sample_size + header length
        int offset = number * 1 + 44;

        // unless this is a stereo file and the rightchannel is requested.
        if (!mono && !leftchannel)
        {
        offset += byte_samp/2;
        }

        // read this many bytes;
        int amount;
        amount=byte_samp;

        fseek(stream,offset,SEEK_CUR);
        short sample = 0;
        fread((void *)&sample,1,amount,stream);

        return sample;
    }
    else
    {
        // return 0xefffffff if failed
        return (int)0xefffffff;
    }
}


This function returns an int through the variable sample
for success or if failure returns 0xefffffff.
We use rewind to position the file pointer at the beginning of 'stream'.

Then we begin reading at the sample number times (1+44)
this is because the data in the canonical wave format is held there at this point.

The Canonical Wave Format.

Posted Image

1. The characters "RIFF" indiciate the RIFF header. RIFF stands for Resource Interchange File Format.
2. The sizeof the file being read or recorded.
3. The "WAVE" characters indicate its a .wav file.
4. The "fmt " characters specify that this is the section of the file describing the format specifically.
5. The size of the WAVEFORMATEX data to follow
6. # WAVEFORMATEX (shown below)

a.wFormatTag, only PCM data is supported in this sample
b. nChannels, Number of channels in (1 for mono, 2 for stereo)
c. nSamplesPerSec, Sample rate of the waveform in samples per second
d. nAvgBytesPerSec, Average bytes per second which can be used to determine the
time-wise length of the audio
e. nBlockAlign, Specifies how each audio block must be aligned in bytes
f. wBitsPerSample, How many bits represent a single sample (typically 8 or 16)
7. The "data" characters specify that the audio data is next in the file.
8. The length of the data in bytes.
9. PCM DATA. The actual sound data.

readSample references values in Wav function.
which we will discuss next.

// Read the temporary wav file
void Wav(char *c, HWND hWnd)
{

    filename = new char[strlen(c)+1];
    strcpy_s(filename,strlen(c)+1,c);
    // open filepointer readonly
    wavfile = fopen_s(&stream,filename,"r");
    if (stream==NULL)
    {
        MessageBox(hWnd, "Could not open " + (char)filename,"Error", MB_OK);

    }
    else
    {
        // declare a char buff to store some values in
        char *buff = new char[5];
        buff[4]='\0';
        // read the first 4 bytes
        fread((void *)buff,1,4,stream);
        // the first four bytes should be 'RIFF'
        if (strcmp((char *)buff,"RIFF")==0)
        {

            // read byte 8,9,10 and 11
            fseek(stream,4,SEEK_CUR);
            fread((void *)buff,1,4,stream);
            // this should read "WAVE"
            if (strcmp((char *)buff,"WAVE")==0)
            {
                // read byte 12,13,14,15
                fread((void *)buff,1,4,stream);
                // this should read "fmt "
                if (strcmp((char *)buff,"fmt ")==0)
                {
                    fseek(stream,20,SEEK_CUR);
                    // final one read byte 36,37,38,39
                    fread((void *)buff,1,4,stream);
                    if (strcmp((char *)buff,"data")==0)
                    {


                        // Now we know it is a wav file, rewind the stream
                        rewind(stream);
                        // now is it mono or stereo ?
                        fseek(stream,22,SEEK_CUR);
                        fread((void *)buff,1,2,stream);
                        if (buff[0]==0x02)
                        {
                            mono=false;
                        }
                        else
                        {
                            mono=true;
                        }
                        // read the sample rate
                        fread((void *)&s_rate,1,4,stream);
                        fread((void *)&byte_sec,1,4,stream);
                        byte_samp=0;
                        fread((void *)&byte_samp,1,2,stream);
                        bit_samp=0;
                        fread((void *)&bit_samp,1,2,stream);
                        fseek(stream,4,SEEK_CUR);
                        fread((void *)&length,1,4,stream);
                    }
                }
            }
        }
        delete buff;

    }
}



hWnd and c are passed to the wav function
filename then holds the value of c.

a file is then opened.If this is NULL a Messagebox is displayed informing the user of the error.
if the file is not null.
it is checked for being a .wav file.

The things checked are :-
1. The "RIFF" characters
2. The "WAVE" characters
3. "fmt " characters
4. "data" characters

These have been discussed in the canonical wave format section.

next the sample rate, bytes per second,the byte sample, the bit sample and the length of the sample is read.

The byte sample and the length of the sample are used in the readSample function.

Next up is this message handler which is activated when a waveform-audio input device is opened.

case MM_WIM_OPEN:
        // Shrink down the save buffer

        pSaveBuffer = reinterpret_cast <PBYTE>(realloc (pSaveBuffer, 1)) ;




        // Add the buffers

        waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;

        // Begin sampling

        bRecording = TRUE ;
        bEnding = FALSE ;
        dwDataLength = 0 ;
        waveInStart (hWaveIn) ;
        return TRUE ;




first we shrink down the savebuffer to one byte.
then we add the Wave buffers pWaveHdr1 and pWaveHdr2 to hWaveIn which is the handle to the waveform-audio input device.

Then we start the sampling process
the flag bRecording is set to true.
bEnding is set to false

waveInStart is called with hWaveIn which is the handle to the waveform-audio input device,
this starts the recording process.

Next This message handleer is triggered when waveform-audio data is present in the input buffer and the buffer is being returned to the application.

case MM_WIM_DATA:

        // Reallocate save buffer memory

        pNewBuffer = reinterpret_cast <PBYTE> (realloc (pSaveBuffer, dwDataLength +
                                               ((PWAVEHDR) lParam)->dwBytesRecorded)) ;

        if (pNewBuffer == NULL)
        {
            waveInClose (hWaveIn) ;

            MessageBox (hwnd, szMemError, szAppName,
                        MB_ICONEXCLAMATION | MB_OK) ;
            return TRUE ;
        }

        pSaveBuffer = pNewBuffer ;
        CopyMemory (pSaveBuffer + dwDataLength, ((PWAVEHDR) lParam)->lpData,
                    ((PWAVEHDR) lParam)->dwBytesRecorded) ;

        dwDataLength += ((PWAVEHDR) lParam)->dwBytesRecorded ;

        if (bEnding)
        {
            waveInClose (hWaveIn) ;
            return TRUE ;
        }

        // Send out a new buffer

        waveInAddBuffer (hWaveIn, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ;
        return TRUE ;



basically reallocates memory for the save buffer and sends out a new buffer triggered by waveInReset function.

case MM_WIM_CLOSE:
        // Free the buffer memory

        waveInUnprepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveInUnprepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;

        free (pBuffer1) ;
        free (pBuffer2) ;

        // Enable and disable buttons
        if (dwDataLength > 0)
        {
            EnableWindow (PlyButton,   TRUE)  ;
        }
        bRecording = FALSE ;

        if (bTerminating)
            SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;

        return TRUE 


message triggered by waveInClose function or when the waveform-audio input device is closed.

case MM_WOM_OPEN:

        // Set up header

        pWaveHdr1->lpData          = reinterpret_cast <CHAR*>(pSaveBuffer) ;
        pWaveHdr1->dwBufferLength  = dwDataLength ;
        pWaveHdr1->dwBytesRecorded = 0 ;
        pWaveHdr1->dwUser          = 0 ;
        pWaveHdr1->dwFlags         = WHDR_BEGINLOOP | WHDR_ENDLOOP ;
        pWaveHdr1->dwLoops         = dwRepetitions ;
        pWaveHdr1->lpNext          = NULL ;
        pWaveHdr1->reserved        = 0 ;

        // Prepare and write

        waveOutPrepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveOutWrite (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;

        bEnding = FALSE ;
        bPlaying = TRUE ;
        return TRUE ;



opposite of MM_WOM_CLOSE and sent when a .wav file is playing back, sets and prepares the wave header then writes the wave header to the audio output device.

 case MM_WOM_DONE:

        waveOutUnprepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveOutClose (hWaveOut) ;
        EnableWindow (PlyButton, TRUE);
        return TRUE ;

    case MM_WOM_CLOSE:

        dwRepetitions = 1 ;
        bPlaying = FALSE ;

        return TRUE ;


case MM_WOM_DONE Unprepares header closes the audio output device and resets the PLAY button to on.
case MM_WOM_CLOSE just concerns itself with the setting of flags.

Windows Message Commands

case WM_COMMAND:

        switch (wParam)
        {


        case APP_SAVE:
        {

            char szFileName[MAX_PATH] = "";
            OPENFILENAME ofn;
            ZeroMemory(&ofn, sizeof(ofn));

            ofn.lStructSize= sizeof(ofn);
            ofn.hwndOwner = hwnd;
            ofn.lpstrFilter = "Wave Files(*.wav)\0*.wav\0";
            ofn.lpstrFile = szFileName;
            ofn.nMaxFile = MAX_PATH;
            ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT;
            ofn.lpstrDefExt = "wav";
            if (GetSaveFileName(&ofn))
            {
                if (szFileName)
                {
                    SaveWavFile(szFileName,pWaveHdr1);
                }
            }
        }
        break ;




This sets up a Common Dialog to save a .wav file, ofn.flags are set to OFN_EXPLORER | OFN_OVERWRITEPROMPT this asks the user if he/she wants to overwrite the new file if a file by that name already exists.

It calls the SaveWavFile function to save the actual wave file.

 case APP_EXIT:
        {
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            //cleanup before closing
            _fcloseall();
            fSuccess= DeleteFile(TEXT("temp.wav"));
        }
        break ;



This piece of code exits the app.
it closes all open streams and deletes the temporary .wav file "temp.wav"

 case IDC_RECORD:
        {
            EnableWindow (RecButton, FALSE) ;
            EnableWindow (PlyButton, FALSE) ;
            EnableWindow (StpButton, TRUE)  ;
            waveOutReset (hWaveOut) ;
            waveInReset (hWaveIn) ;
            pBuffer1=reinterpret_cast <PBYTE> (malloc(INP_BUFFER_SIZE) );
            pBuffer2= reinterpret_cast <PBYTE> ( malloc(INP_BUFFER_SIZE) );

            if (!pBuffer1 || !pBuffer2)
            {
                if (pBuffer1) free (pBuffer1) ;
                if (pBuffer2) free (pBuffer2) ;
                MessageBox (hwnd, szMemError, szAppName,
                            MB_ICONEXCLAMATION | MB_OK) ;
                return TRUE ;
            }
            // Open waveform audio for input

            waveform.wFormatTag      = WAVE_FORMAT_PCM ;
            waveform.nChannels       = 1 ;
            waveform.nSamplesPerSec  = 11025 ;
            waveform.nAvgBytesPerSec = 11025 ;
            waveform.nBlockAlign     = 1 ;
            waveform.wBitsPerSample  = 8 ;
            waveform.cbSize          = 0 ;

            if (waveInOpen (&hWaveIn, WAVE_MAPPER, &waveform,
                            (DWORD) hwnd, 0, CALLBACK_WINDOW))
            {
                free (pBuffer1) ;
                free (pBuffer2) ;
            }
            // Set up headers and prepare them

            pWaveHdr1->lpData          =reinterpret_cast <CHAR*>( pBuffer1 ) ;
            pWaveHdr1->dwBufferLength  = INP_BUFFER_SIZE ;
            pWaveHdr1->dwBytesRecorded = 0 ;
            pWaveHdr1->dwUser          = 0 ;
            pWaveHdr1->dwFlags         = 0 ;
            pWaveHdr1->dwLoops         = 1 ;
            pWaveHdr1->lpNext          = NULL ;
            pWaveHdr1->reserved        = 0 ;

            waveInPrepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;

            pWaveHdr2->lpData          = reinterpret_cast <CHAR*>(pBuffer2 ) ;
            pWaveHdr2->dwBufferLength  = INP_BUFFER_SIZE ;
            pWaveHdr2->dwBytesRecorded = 0 ;
            pWaveHdr2->dwUser          = 0 ;
            pWaveHdr2->dwFlags         = 0 ;
            pWaveHdr2->dwLoops         = 1 ;
            pWaveHdr2->lpNext          = NULL ;
            pWaveHdr2->reserved        = 0 ;

            waveInPrepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
        }
        break ;



The above is our code for the record button.
The RECORD button itself is disabled along with the PLAY button the STOP button is enabled.
Memory is allocated for pBuffer1 and pBuffer2.
If you have run out of memory or memory cannot be allocated a messagebox is displayed with the nature of the error.
Next we set up the wave headers pWaveHdr1 and pWaveHdr2 and call the function
waveInPrepareHeader to prepare for waveform audio input.

case IDC_STOP:
        {

            _fcloseall();
            EnableWindow (RecButton, TRUE) ;
            EnableWindow (StpButton, FALSE) ;
            EnableWindow (PlyButton, TRUE);
            bEnding = TRUE ;
            SaveWavFile("temp.wav",pWaveHdr1);

        }



This is the code for the STOP button first we close all streams that are opened.
enable the RECORD and PLAY buttons and disable the STOP button.

The Flag bEnding is set to true and then the temporary file "temp.wav" is saved
using the SaveWavFile Function.

 case IDC_PLAY:
        {
            // play wav file
            bPlaying = TRUE;

            EnableWindow (PlyButton, FALSE);
            waveform.wFormatTag      = WAVE_FORMAT_PCM ;
            waveform.nChannels       = 1 ;
            waveform.nSamplesPerSec  = 11025 ;
            waveform.nAvgBytesPerSec = 11025 ;
            waveform.nBlockAlign     = 1 ;
            waveform.wBitsPerSample  = 8 ;
            waveform.cbSize          = 0 ;
            waveInReset (hWaveIn) ;
            waveOutReset (hWaveOut) ;
            if (waveOutOpen (&hWaveOut, WAVE_MAPPER, &waveform,
                             (DWORD) hwnd, 0, CALLBACK_WINDOW))
            {

                MessageBox (hwnd, szOpenError, szAppName,
                            MB_ICONEXCLAMATION | MB_OK) ;
            }





            Wav("temp.wav", hwnd);
            



            RECT rc;
            GetClientRect(hwnd, &rc);
            PLAY = TRUE;
            InvalidateRect(hwnd,&rc,TRUE);
        }
        break ;
        }
        break ;



The above code sets the flag bPlaying to true.
It disables the PLAY button.
Prepares the waveform for playing
if it cant open the audio output device it displays a Messsage Box with the Error.
It then calls the Wav function which loads the temporary wave file "temp.wav".

The flag PLAY is set to true and a refresh of the window is forced by InvalidateRect.

void SaveWavFile(char *FileName, PWAVEHDR WaveHeader)
{
    fstream myFile (FileName, fstream::out | fstream::binary);

    int chunksize,pcmsize,NumSamples,subchunk1size;
    int audioFormat = 1;
    int numChannels = 1;
    int bitsPerSample = 8;



    NumSamples = ((long) (NUMPTS/sampleRate) * 1000);
    pcmsize = sizeof(PCMWAVEFORMAT);


    subchunk1size= 16;
    int byteRate = sampleRate*numChannels*bitsPerSample/8;
    int blockAlign = numChannels*bitsPerSample/8;
    int subchunk2size = WaveHeader->dwBufferLength*numChannels;
    chunksize = (36 + subchunk2size);
    // write the wav file per the wav file format
    myFile.seekp (0, ios::beg);
    myFile.write ("RIFF", 4);					// chunk id
    myFile.write ((char*) &chunksize, 4);	        	// chunk size (36 + SubChunk2Size))
    myFile.write ("WAVE", 4);					// format
    myFile.write ("fmt ", 4);					// subchunk1ID
    myFile.write ((char*) &subchunk1size, 4);			// subchunk1size (16 for PCM)
    myFile.write ((char*) &audioFormat, 2);			// AudioFormat (1 for PCM)
    myFile.write ((char*) &numChannels, 2);			// NumChannels
    myFile.write ((char*) &sampleRate, 4);			// sample rate
    myFile.write ((char*) &byteRate, 4);			// byte rate (SampleRate * NumChannels * BitsPerSample/8)
    myFile.write ((char*) &blockAlign, 2);			// block align (NumChannels * BitsPerSample/8)
    myFile.write ((char*) &bitsPerSample, 2);			// bits per sample
    myFile.write ("data", 4);					// subchunk2ID
    myFile.write ((char*) &subchunk2size, 4);			// subchunk2size (NumSamples * NumChannels * BitsPerSample/8)

    myFile.write (WaveHeader->lpData,WaveHeader->dwBufferLength);	// data
    myFile.close();
}




Finally we have the SavWavFile Function this opens a fstream object called myFile
the file is saved as according to the table in the Canonical Wave format section.

First "RIFF" is written, then the chunksize is written this is (36+ Bufferlength*number of channels(in this case 1)) next "WAVE" is written to determine which type of RIFF file it is.
Then "fmt" is written next subchunk1size is written in this case it is 16 for PCM.
Audio format is written next in this case it is 1 for PCM, next numchannels is written in this case it 1 once again.
The sample rate is the next thing to be written in this case it is 11025.
The Byte rate is now written to the file which is the SampleRate * NumChannels * BitsPerSample/8
BitsPerSample can be either 16 or 8 in this case its 8.
The Block alignment is written next which is NumChannels * BitsPerSample/8.
BitsPerSample is now written which is '8' which I havepreviously mentioned.
"data" is now written to the file to mark the start of the data portion of the .wav file.
subchunk2size is now written which is (NumSamples * NumChannels * BitsPerSample/8).
Lastly the actual sample data is written to the .wav file and the file is closed.

For completeness I will now post the projects main files the .cpp the .h and the .rc files.
Then I will go into detail about which Libraries to include.

recorder.cpp

#include <CommDlg.h>
#include <MMSystem.h>
#include <fstream>
#include <cstdlib>
#include "resource.h"

using namespace std;
//Globals for sound wave visualistion
int number, length, byte_samp, byte_sec, bit_samp;
static int sampleRate = 11025;
const int NUMPTS = 11025 * 10;
bool mono = TRUE;
bool PLAY = FALSE;
errno_t wavfile;
char * filename;
int s_rate = 11025;
double limit = 10000.0;
FILE * stream;
/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Declare procedures */
int readSample(int number,bool leftchannel);
void SaveWavFile(char *FileName, PWAVEHDR WaveHeader);
void Wav(char *c, HWND hWnd);
/*  Make the class name into a global variable  */
char szAppName[ ] = "Recorder";

// **********
// Windows Main Function.
// - Here starts our program
int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nCmdShow)
{

    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szAppName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = "APP_MENU";                 /*menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szAppName,         /* Classname */
               szAppName,       /* Title Text */
               WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               430,                 /* The programs width */
               300,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /*use class menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}



/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HWND RecButton;
    static HWND PlyButton;
    static HWND StpButton;
    static HMENU hMenu;
    static HPEN hPen;
    static BOOL         bRecording, bPlaying,bEnding, bTerminating ;
    static DWORD        dwDataLength, dwRepetitions = 1 ;
    static HWAVEIN      hWaveIn ;
    static HWAVEOUT     hWaveOut ;
    static PBYTE        pBuffer1, pBuffer2, pSaveBuffer, pNewBuffer ;
    static PWAVEHDR     pWaveHdr1, pWaveHdr2 ;
    static TCHAR        szOpenError[] = TEXT ("Error opening waveform audio!");
    static TCHAR        szMemError [] = TEXT ("Error allocating memory!") ;
    static WAVEFORMATEX waveform ;

    hMenu = GetMenu (hwnd);
    HDC hDC;
    POINT pt [NUM];
    BOOL fSuccess = FALSE;

    switch (message)                  /* handle the messages */
    {
    case WM_CREATE:
        RecButton = CreateWindow ( TEXT ("button"),"RECORD",WS_VISIBLE|WS_CHILD|ES_LEFT|1,7,175,100,25,hwnd,(HMENU) IDC_RECORD,((LPCREATESTRUCT) lParam) -> hInstance,NULL);
        PlyButton = CreateWindow ( TEXT ("button"),"PLAY",WS_VISIBLE|WS_CHILD|ES_LEFT|1,157,175,100,25,hwnd,(HMENU) IDC_PLAY,((LPCREATESTRUCT) lParam) -> hInstance,NULL);
        StpButton = CreateWindow ( TEXT ("button"),"STOP",WS_VISIBLE|WS_CHILD|ES_LEFT|1,314,175,100,25,hwnd,(HMENU) IDC_STOP,((LPCREATESTRUCT) lParam) -> hInstance,NULL);
        EnableWindow (PlyButton, FALSE) ;
        EnableWindow (StpButton, FALSE)  ;

        pWaveHdr1 =  reinterpret_cast <PWAVEHDR> ( malloc (sizeof (WAVEHDR)) );
        pWaveHdr2 = reinterpret_cast <PWAVEHDR> ( malloc (sizeof (WAVEHDR)) ) ;
        // Allocate memory for save buffer

        pSaveBuffer = reinterpret_cast <PBYTE> ( malloc (1) ) ;
		 
        return 0;

    case WM_PAINT:
        PAINTSTRUCT 	ps;
        hDC = BeginPaint(hwnd, &ps);

        if (hDC)
        {
            RECT rc;
            rc.top = 35;
			rc.left = 0;
			rc.bottom = 145;
			rc.right = 425;
			FillRect(hDC,&rc,(HBRUSH)(COLOR_WINDOW+2));
            if (PLAY==TRUE)
            {
				FillRect(hDC,&rc,(HBRUSH)(COLOR_WINDOW+2));
                hPen = CreatePen(PS_SOLID,1,RGB(0,200,0));
                SelectObject(hDC, hPen);

                SetMapMode(hDC, MM_ISOTROPIC);
                SetWindowExtEx(hDC, 400, 300, NULL);
                SetViewportExtEx(hDC,200, 180, NULL);
                SetViewportOrgEx(hDC, 0, 0, NULL);

                int sample=0;
                int i=1;
                int num = 60000;
                sample= readSample(i, TRUE);
                // scale the sample

                pt[i].x =i/20;
                pt[i].y = (int) ((sample)*1.5);
                MoveToEx (hDC,pt[i].x,pt[i].y,NULL);
                while (i<num && sample!=(int)0xefffffff)
                {
                    // scale the sample

                    pt[i].x = i/20;
                    pt[i].y = (int) ((sample)*1.5);

                    LineTo(hDC, pt[i].x,pt[i].y);
                    i++;
                    sample= readSample(i, TRUE);

                }


            }
            DeleteObject(hPen);
            DeleteDC(hDC);
            
			EndPaint(hwnd, &ps);

        }
        return 0;

    case MM_WIM_OPEN:
        // Shrink down the save buffer

        pSaveBuffer = reinterpret_cast <PBYTE>(realloc (pSaveBuffer, 1)) ;




        // Add the buffers

        waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;

        // Begin sampling

        bRecording = TRUE ;
        bEnding = FALSE ;
        dwDataLength = 0 ;
        waveInStart (hWaveIn) ;
        return TRUE ;




    case MM_WIM_DATA:

        // Reallocate save buffer memory

        pNewBuffer = reinterpret_cast <PBYTE> (realloc (pSaveBuffer, dwDataLength +
                                               ((PWAVEHDR) lParam)->dwBytesRecorded)) ;

        if (pNewBuffer == NULL)
        {
            waveInClose (hWaveIn) ;

            MessageBox (hwnd, szMemError, szAppName,
                        MB_ICONEXCLAMATION | MB_OK) ;
            return TRUE ;
        }

        pSaveBuffer = pNewBuffer ;
        CopyMemory (pSaveBuffer + dwDataLength, ((PWAVEHDR) lParam)->lpData,
                    ((PWAVEHDR) lParam)->dwBytesRecorded) ;

        dwDataLength += ((PWAVEHDR) lParam)->dwBytesRecorded ;

        if (bEnding)
        {
            waveInClose (hWaveIn) ;
            return TRUE ;
        }

        // Send out a new buffer

        waveInAddBuffer (hWaveIn, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ;
        return TRUE ;

    case MM_WIM_CLOSE:
        // Free the buffer memory

        waveInUnprepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveInUnprepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;

        free (pBuffer1) ;
        free (pBuffer2) ;

        // Enable and disable buttons
        if (dwDataLength > 0)
        {
            EnableWindow (PlyButton,   TRUE)  ;
        }
        bRecording = FALSE ;

        if (bTerminating)
            SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;

        return TRUE ;

    case MM_WOM_OPEN:

        // Set up header

        pWaveHdr1->lpData          = reinterpret_cast <CHAR*>(pSaveBuffer) ;
        pWaveHdr1->dwBufferLength  = dwDataLength ;
        pWaveHdr1->dwBytesRecorded = 0 ;
        pWaveHdr1->dwUser          = 0 ;
        pWaveHdr1->dwFlags         = WHDR_BEGINLOOP | WHDR_ENDLOOP ;
        pWaveHdr1->dwLoops         = dwRepetitions ;
        pWaveHdr1->lpNext          = NULL ;
        pWaveHdr1->reserved        = 0 ;

        // Prepare and write

        waveOutPrepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveOutWrite (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;

        bEnding = FALSE ;
        bPlaying = TRUE ;
        return TRUE ;

    case MM_WOM_DONE:

        waveOutUnprepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveOutClose (hWaveOut) ;
        EnableWindow (PlyButton, TRUE);
        return TRUE ;

    case MM_WOM_CLOSE:

        dwRepetitions = 1 ;
        bPlaying = FALSE ;

        return TRUE ;





    case WM_COMMAND:

        switch (wParam)
        {


        case APP_SAVE:
        {

            char szFileName[MAX_PATH] = "";
            OPENFILENAME ofn;
            ZeroMemory(&ofn, sizeof(ofn));

            ofn.lStructSize= sizeof(ofn);
            ofn.hwndOwner = hwnd;
            ofn.lpstrFilter = "Wave Files(*.wav)\0*.wav\0";
            ofn.lpstrFile = szFileName;
            ofn.nMaxFile = MAX_PATH;
            ofn.Flags = OFN_EXPLORER | OFN_OVERWRITEPROMPT;
            ofn.lpstrDefExt = "wav";
            if (GetSaveFileName(&ofn))
            {
                if (szFileName)
                {
                    SaveWavFile(szFileName,pWaveHdr1);
                }
            }
        }
        break ;

        case APP_EXIT:
        {
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            //cleanup before closing
            _fcloseall();
            fSuccess= DeleteFile(TEXT("temp.wav"));
        }
        break ;

        case IDC_RECORD:
        {
            EnableWindow (RecButton, FALSE) ;
            EnableWindow (PlyButton, FALSE) ;
            EnableWindow (StpButton, TRUE)  ;
            waveOutReset (hWaveOut) ;
            waveInReset (hWaveIn) ;
            pBuffer1=reinterpret_cast <PBYTE> (malloc(INP_BUFFER_SIZE) );
            pBuffer2= reinterpret_cast <PBYTE> ( malloc(INP_BUFFER_SIZE) );

            if (!pBuffer1 || !pBuffer2)
            {
                if (pBuffer1) free (pBuffer1) ;
                if (pBuffer2) free (pBuffer2) ;
                MessageBox (hwnd, szMemError, szAppName,
                            MB_ICONEXCLAMATION | MB_OK) ;
                return TRUE ;
            }
            // Open waveform audio for input

            waveform.wFormatTag      = WAVE_FORMAT_PCM ;
            waveform.nChannels       = 1 ;
            waveform.nSamplesPerSec  = 11025 ;
            waveform.nAvgBytesPerSec = 11025 ;
            waveform.nBlockAlign     = 1 ;
            waveform.wBitsPerSample  = 8 ;
            waveform.cbSize          = 0 ;

            if (waveInOpen (&hWaveIn, WAVE_MAPPER, &waveform,
                            (DWORD) hwnd, 0, CALLBACK_WINDOW))
            {
                free (pBuffer1) ;
                free (pBuffer2) ;
            }
            // Set up headers and prepare them

            pWaveHdr1->lpData          =reinterpret_cast <CHAR*>( pBuffer1 ) ;
            pWaveHdr1->dwBufferLength  = INP_BUFFER_SIZE ;
            pWaveHdr1->dwBytesRecorded = 0 ;
            pWaveHdr1->dwUser          = 0 ;
            pWaveHdr1->dwFlags         = 0 ;
            pWaveHdr1->dwLoops         = 1 ;
            pWaveHdr1->lpNext          = NULL ;
            pWaveHdr1->reserved        = 0 ;

            waveInPrepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;

            pWaveHdr2->lpData          = reinterpret_cast <CHAR*>(pBuffer2 ) ;
            pWaveHdr2->dwBufferLength  = INP_BUFFER_SIZE ;
            pWaveHdr2->dwBytesRecorded = 0 ;
            pWaveHdr2->dwUser          = 0 ;
            pWaveHdr2->dwFlags         = 0 ;
            pWaveHdr2->dwLoops         = 1 ;
            pWaveHdr2->lpNext          = NULL ;
            pWaveHdr2->reserved        = 0 ;

            waveInPrepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
        }
        break ;

        case IDC_STOP:
        {

            _fcloseall();
            EnableWindow (RecButton, TRUE) ;
            EnableWindow (StpButton, FALSE) ;
            EnableWindow (PlyButton, TRUE);
            bEnding = TRUE ;
            SaveWavFile("temp.wav",pWaveHdr1);

        }
        break ;

        case IDC_PLAY:
        {
            // play wav file
            bPlaying = TRUE;

            EnableWindow (PlyButton, FALSE);
            waveform.wFormatTag      = WAVE_FORMAT_PCM ;
            waveform.nChannels       = 1 ;
            waveform.nSamplesPerSec  = 11025 ;
            waveform.nAvgBytesPerSec = 11025 ;
            waveform.nBlockAlign     = 1 ;
            waveform.wBitsPerSample  = 8 ;
            waveform.cbSize          = 0 ;
            waveInReset (hWaveIn) ;
            waveOutReset (hWaveOut) ;
            if (waveOutOpen (&hWaveOut, WAVE_MAPPER, &waveform,
                             (DWORD) hwnd, 0, CALLBACK_WINDOW))
            {

                MessageBox (hwnd, szOpenError, szAppName,
                            MB_ICONEXCLAMATION | MB_OK) ;
            }





            Wav("temp.wav", hwnd);
           




            RECT rc;
            GetClientRect(hwnd, &rc);
            PLAY = TRUE;
            InvalidateRect(hwnd,&rc,TRUE);
        }
        break ;
        }
        break ;

    case WM_DESTROY:
        PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
        //cleanup before closing
        _fcloseall();
        fSuccess= DeleteFile(TEXT("temp.wav"));
        break;




    default:                      /* for messages that we don't deal with */
        return DefWindowProc (hwnd, message, wParam, lParam);
    }



    return 0;
}

//start of wave visualisation process

int readSample(int number,bool leftchannel)
{

    /*
      Reads sample number, returns it as an int, if
      this.mono==false we look at the leftchannel bool
      to determine which to return.

      number is in the range [0,length/byte_samp]

      returns 0xefffffff on failure
    */

    if (number>=0 && number<length/byte_samp)
    {
        // go to beginning of the file
        rewind(stream);

        // we start reading at sample_number * sample_size + header length
        int offset = number * 1 + 44;

        // unless this is a stereo file and the rightchannel is requested.
        if (!mono && !leftchannel)
        {
        offset += byte_samp/2;
        }

        // read this many bytes;
        int amount;
        amount=byte_samp;

        fseek(stream,offset,SEEK_CUR);
        short sample = 0;
        fread((void *)&sample,1,amount,stream);

        return sample;
    }
    else
    {
        // return 0xefffffff if failed
        return (int)0xefffffff;
    }
}
// Read the temporary wav file
void Wav(char *c, HWND hWnd)
{

    filename = new char[strlen(c)+1];
    strcpy_s(filename,strlen(c)+1,c);
    // open filepointer readonly
    wavfile = fopen_s(&stream,filename,"r");
    if (stream==NULL)
    {
        MessageBox(hWnd, "Could not open " + (char)filename,"Error", MB_OK);

    }
    else
    {
        // declare a char buff to store some values in
        char *buff = new char[5];
        buff[4]='\0';
        // read the first 4 bytes
        fread((void *)buff,1,4,stream);
        // the first four bytes should be 'RIFF'
        if (strcmp((char *)buff,"RIFF")==0)
        {

            // read byte 8,9,10 and 11
            fseek(stream,4,SEEK_CUR);
            fread((void *)buff,1,4,stream);
            // this should read "WAVE"
            if (strcmp((char *)buff,"WAVE")==0)
            {
                // read byte 12,13,14,15
                fread((void *)buff,1,4,stream);
                // this should read "fmt "
                if (strcmp((char *)buff,"fmt ")==0)
                {
                    fseek(stream,20,SEEK_CUR);
                    // final one read byte 36,37,38,39
                    fread((void *)buff,1,4,stream);
                    if (strcmp((char *)buff,"data")==0)
                    {


                        // Now we know it is a wav file, rewind the stream
                        rewind(stream);
                        // now is it mono or stereo ?
                        fseek(stream,22,SEEK_CUR);
                        fread((void *)buff,1,2,stream);
                        if (buff[0]==0x02)
                        {
                            mono=false;
                        }
                        else
                        {
                            mono=true;
                        }
                        // read the sample rate
                        fread((void *)&s_rate,1,4,stream);
                        fread((void *)&byte_sec,1,4,stream);
                        byte_samp=0;
                        fread((void *)&byte_samp,1,2,stream);
                        bit_samp=0;
                        fread((void *)&bit_samp,1,2,stream);
                        fseek(stream,4,SEEK_CUR);
                        fread((void *)&length,1,4,stream);
                    }
                }
            }
        }
        delete buff;

    }
}

void SaveWavFile(char *FileName, PWAVEHDR WaveHeader)
{
    fstream myFile (FileName, fstream::out | fstream::binary);

    int chunksize,pcmsize,NumSamples,subchunk1size;
    int audioFormat = 1;
    int numChannels = 1;
    int bitsPerSample = 8;



    NumSamples = ((long) (NUMPTS/sampleRate) * 1000);
    pcmsize = sizeof(PCMWAVEFORMAT);


    subchunk1size= 16;
    int byteRate = sampleRate*numChannels*bitsPerSample/8;
    int blockAlign = numChannels*bitsPerSample/8;
    int subchunk2size = WaveHeader->dwBufferLength*numChannels;
    chunksize = (36 + subchunk2size);
    // write the wav file per the wav file format
    myFile.seekp (0, ios::beg);
    myFile.write ("RIFF", 4);					// chunk id
    myFile.write ((char*) &chunksize, 4);	        	// chunk size (36 + SubChunk2Size))
    myFile.write ("WAVE", 4);					// format
    myFile.write ("fmt ", 4);					// subchunk1ID
    myFile.write ((char*) &subchunk1size, 4);			// subchunk1size (16 for PCM)
    myFile.write ((char*) &audioFormat, 2);			// AudioFormat (1 for PCM)
    myFile.write ((char*) &numChannels, 2);			// NumChannels
    myFile.write ((char*) &sampleRate, 4);			// sample rate
    myFile.write ((char*) &byteRate, 4);			// byte rate (SampleRate * NumChannels * BitsPerSample/8)
    myFile.write ((char*) &blockAlign, 2);			// block align (NumChannels * BitsPerSample/8)
    myFile.write ((char*) &bitsPerSample, 2);			// bits per sample
    myFile.write ("data", 4);					// subchunk2ID
    myFile.write ((char*) &subchunk2size, 4);			// subchunk2size (NumSamples * NumChannels * BitsPerSample/8)

    myFile.write (WaveHeader->lpData,WaveHeader->dwBufferLength);	// data
    myFile.close();
}




resource.h

#ifndef RESOURCE_H_INCLUDED
#define RESOURCE_H_INCLUDED
#include <windows.h>

#define INP_BUFFER_SIZE 16384
#define IDC_RECORD 1
#define IDC_PLAY 2
#define IDC_STOP 3
#define NUM 20000
//defines for menu
#define APP_SAVE 1003
#define APP_EXIT  1004

#endif // RESOURCE_H_INCLUDED



resource.rc

//MENU
//CREATION
#include "resource.h"
#include "afxres.h"



APP_MENU MENU DISCARDABLE
BEGIN
    POPUP "&File"
    BEGIN

        MENUITEM "&Save",           APP_SAVE
        MENUITEM "&Exit",           APP_EXIT
   END
END



In Visual Studio 2010 to link to the Libraries :-
WinMM.Lib;
kernel32.lib;
user32.lib;
comdlg32.lib

which are required to build the project
GoTo Project -> Properties
(or press ALT + F7)
then GoTo Linker->Input -> Additional Dependancies
and then add the above libraries as shown.



References


Programming Windows Fifth Edition by Charles Petzold.

MSDN

(If anyone wants a MinGW/gcc friendly version please ask as I have one built)

Is This A Good Question/Topic? 6
  • +

Replies To: Sound Recorder using the low level Windows API in C++

#2 koolkoder  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 1
  • Joined: 13-October 11

Posted 28 February 2012 - 02:20 PM

Nice tutorial, I have been wondering how to do this for a while. You mentioned you had a GCC version available? Would you mind posting it, I am more familiar with GCC than I am with Visual Studio. Thank you very much!
Was This Post Helpful? 0
  • +
  • -

#3 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 762
  • View blog
  • Posts: 2,218
  • Joined: 20-March 10

Posted 29 February 2012 - 10:38 AM

Hi KoolKoder,

Thanks for the reply funnily enough you are only the second
person to ask for this...

I would have thought there would have been more

Anyway here you go...

Main.cpp

#include "resource.h"

#include <mmsystem.h>
#include <fstream>
#include<iostream>
#include <cstdlib>
#include <math.h>
#include <errno.h>

using namespace std;
//Globals for sound wave visualistion
int number, length, byte_samp, byte_sec, bit_samp;
bool mono = TRUE;
bool PLAY = FALSE;
//errno_t wavfile;
char * filename;
int s_rate = 11025;
double limit = 5000.0;
FILE * stream;
/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Declare procedures */
int readSample(int number,bool leftchannel);
void Wav(char *c);
/*  Make the class name into a global variable  */
char szAppName[ ] = "Recorder";

// **********
// Windows Main Function.
// - Here starts our program
int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nCmdShow)
{

    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szAppName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = "APP_MENU";                 /*menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default colour as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szAppName,         /* Classname */
               szAppName,       /* Title Text */
               WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               430,                 /* The programs width */
               315,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /*use class menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nCmdShow);

    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}



/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    static HWND RecButton;
    static HWND PlyButton;
    static HWND StpButton;
    static HMENU hMenu;
    static HPEN hPen;
    static BOOL         bRecording, bPlaying,bEnding, bTerminating ;
    static DWORD        dwDataLength, dwRepetitions = 1 ;
    static HWAVEIN      hWaveIn ;
    static HWAVEOUT     hWaveOut ;
    static PBYTE        pBuffer1, pBuffer2, pSaveBuffer, pNewBuffer ;
    static PWAVEHDR     pWaveHdr1, pWaveHdr2 ;
    static TCHAR        szOpenError[] = TEXT ("Error opening waveform audio!");
    static TCHAR        szMemError [] = TEXT ("Error allocating memory!") ;
    static WAVEFORMATEX waveform ;
    static int sampleRate = 11025;
    const int NUMPTS = 11025 * 10;
    hMenu = GetMenu (hwnd);
    HDC hDC;
    POINT pt [NUM];
    switch (message)                  /* handle the messages */
    {
    case WM_CREATE:
        RecButton = CreateWindow ( TEXT ("button"),"RECORD",WS_VISIBLE|WS_CHILD|ES_LEFT|1,7,175,100,25,hwnd,(HMENU) IDC_RECORD,((LPCREATESTRUCT) lParam) -> hInstance,NULL);
        PlyButton = CreateWindow ( TEXT ("button"),"PLAY",WS_VISIBLE|WS_CHILD|ES_LEFT|1,157,175,100,25,hwnd,(HMENU) IDC_PLAY,((LPCREATESTRUCT) lParam) -> hInstance,NULL);
        StpButton = CreateWindow ( TEXT ("button"),"STOP",WS_VISIBLE|WS_CHILD|ES_LEFT|1,314,175,100,25,hwnd,(HMENU) IDC_STOP,((LPCREATESTRUCT) lParam) -> hInstance,NULL);
        EnableWindow (PlyButton, FALSE) ;
        EnableWindow (StpButton, FALSE)  ;

        pWaveHdr1 =  reinterpret_cast <PWAVEHDR> ( malloc (sizeof (WAVEHDR)) );
        pWaveHdr2 = reinterpret_cast <PWAVEHDR> ( malloc (sizeof (WAVEHDR)) ) ;
        // Allocate memory for save buffer

        pSaveBuffer = reinterpret_cast <PBYTE> ( malloc (1) ) ;
        return 0;

    case WM_PAINT:
        PAINTSTRUCT 	ps;
        hDC = BeginPaint(hwnd, &ps);

        if (hDC)
        {
            RECT rc;
            rc.top = 15;
			rc.left = 0;
			rc.bottom = 165;
			rc.right = 425;
			FillRect(hDC,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
            if (PLAY==TRUE)
            {
                FillRect(hDC,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
                Wav("temp.wav");
                hPen = CreatePen(PS_SOLID,1,RGB(0,200,0));
                SelectObject(hDC, hPen);

                SetMapMode(hDC, MM_ISOTROPIC);
                SetWindowExtEx(hDC, 430, 315, NULL);
                SetViewportExtEx(hDC,200, 200, NULL);
                SetViewportOrgEx(hDC, 0, 0, NULL);

                int sample=0;
                int i=1;
                int num = 20000;
                sample= readSample(i, TRUE);
                // scale the sample

                pt[i].x =i/20;
                pt[i].y = (int) ((sample)*2);
                MoveToEx (hDC,pt[i].x,pt[i].y,NULL);
                while (i<num && sample!=(int)0xefffffff)
                {
                    // scale the sample

                    pt[i].x = i/20;
                    pt[i].y = (int) ((sample)*2);

                    LineTo(hDC, pt[i].x,pt[i].y);
                    i++;
                    sample= readSample(i, TRUE);

                }


            }
            DeleteObject(hPen);
            DeleteDC(hDC);
            EndPaint(hwnd, &ps);

        }
        return 0;

    case MM_WIM_OPEN:
        // Shrink down the save buffer

        pSaveBuffer = reinterpret_cast <PBYTE>(realloc (pSaveBuffer, 1)) ;




        // Add the buffers

        waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;

        // Begin sampling

        bRecording = TRUE ;
        bEnding = FALSE ;
        dwDataLength = 0 ;
        waveInStart (hWaveIn) ;
        return TRUE ;




    case MM_WIM_DATA:

        // Reallocate save buffer memory

        pNewBuffer = reinterpret_cast <PBYTE> (realloc (pSaveBuffer, dwDataLength +
                                               ((PWAVEHDR) lParam)->dwBytesRecorded)) ;

        if (pNewBuffer == NULL)
        {
            waveInClose (hWaveIn) ;

            MessageBox (hwnd, szMemError, szAppName,
                        MB_ICONEXCLAMATION | MB_OK) ;
            return TRUE ;
        }

        pSaveBuffer = pNewBuffer ;
        CopyMemory (pSaveBuffer + dwDataLength, ((PWAVEHDR) lParam)->lpData,
                    ((PWAVEHDR) lParam)->dwBytesRecorded) ;

        dwDataLength += ((PWAVEHDR) lParam)->dwBytesRecorded ;

        if (bEnding)
        {
            waveInClose (hWaveIn) ;
            return TRUE ;
        }

        // Send out a new buffer

        waveInAddBuffer (hWaveIn, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ;
        return TRUE ;

    case MM_WIM_CLOSE:
        // Free the buffer memory

        waveInUnprepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveInUnprepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;

        free (pBuffer1) ;
        free (pBuffer2) ;

        // Enable and disable buttons
        if (dwDataLength > 0)
        {
            EnableWindow (PlyButton,   TRUE)  ;
        }
        bRecording = FALSE ;

        if (bTerminating)
            SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;

        return TRUE ;

    case MM_WOM_OPEN:

        // Set up header

        pWaveHdr1->lpData          = reinterpret_cast <CHAR*>(pSaveBuffer) ;
        pWaveHdr1->dwBufferLength  = dwDataLength ;
        pWaveHdr1->dwBytesRecorded = 0 ;
        pWaveHdr1->dwUser          = 0 ;
        pWaveHdr1->dwFlags         = WHDR_BEGINLOOP | WHDR_ENDLOOP ;
        pWaveHdr1->dwLoops         = dwRepetitions ;
        pWaveHdr1->lpNext          = NULL ;
        pWaveHdr1->reserved        = 0 ;

        // Prepare and write

        waveOutPrepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveOutWrite (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;

        bEnding = FALSE ;
        bPlaying = TRUE ;
        return TRUE ;

    case MM_WOM_DONE:

        waveOutUnprepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
        waveOutClose (hWaveOut) ;
        EnableWindow (PlyButton, TRUE);
        return TRUE ;

    case MM_WOM_CLOSE:

        dwRepetitions = 1 ;
        bPlaying = FALSE ;



        return TRUE ;





    case WM_COMMAND:

        switch (wParam)
        {


        case APP_SAVE:
        {


            int chunksize,pcmsize,NumSamples,subchunk1size;
            int audioFormat = 1;
            int numChannels = 1;
            int bitsPerSample = 8;



            NumSamples = ((long) (NUMPTS/sampleRate) * 1000);
            pcmsize = sizeof(PCMWAVEFORMAT);

            ;
            subchunk1size= 16;
            int byteRate = sampleRate*numChannels*bitsPerSample/8;
            int blockAlign = numChannels*bitsPerSample/8;
            int subchunk2size = pWaveHdr1->dwBufferLength*numChannels;


			chunksize = (36 + subchunk2size);
            fstream myFile ("test.wav", ios::out | ios::binary);

            // write the wav file per the wav file format
            myFile.seekp (0, ios::beg);
            myFile.write ("RIFF", 4);					// chunk id
            myFile.write ((char*) &chunksize, 4);	        	// chunk size (36 + SubChunk2Size))
            myFile.write ("WAVE", 4);					// format
            myFile.write ("fmt ", 4);					// subchunk1ID
            myFile.write ((char*) &subchunk1size, 4);			// subchunk1size (16 for PCM)
            myFile.write ((char*) &audioFormat, 2);			// AudioFormat (1 for PCM)
            myFile.write ((char*) &numChannels, 2);			// NumChannels
            myFile.write ((char*) &sampleRate, 4);			// sample rate
            myFile.write ((char*) &byteRate, 4);			// byte rate (SampleRate * NumChannels * BitsPerSample/8)
            myFile.write ((char*) &blockAlign, 2);			// block align (NumChannels * BitsPerSample/8)
            myFile.write ((char*) &bitsPerSample, 2);			// bits per sample
            myFile.write ("data", 4);					// subchunk2ID
            myFile.write ((char*) &subchunk2size, 4);			// subchunk2size (NumSamples * NumChannels * BitsPerSample/8)

            myFile.write (pWaveHdr1->lpData, pWaveHdr1->dwBufferLength);	// data

        }
        break ;




        case IDC_RECORD:
			{
            EnableWindow (RecButton, FALSE) ;
            EnableWindow (PlyButton, FALSE) ;
            EnableWindow (StpButton, TRUE)  ;
            pBuffer1=reinterpret_cast <PBYTE> (malloc(INP_BUFFER_SIZE) );
            pBuffer2= reinterpret_cast <PBYTE> ( malloc(INP_BUFFER_SIZE) );

            if (!pBuffer1 || !pBuffer2)
            {
                if (pBuffer1) free (pBuffer1) ;
                if (pBuffer2) free (pBuffer2) ;
                MessageBox (hwnd, szMemError, szAppName,
                            MB_ICONEXCLAMATION | MB_OK) ;
                return TRUE ;
            }
            // Open waveform audio for input

            waveform.wFormatTag      = WAVE_FORMAT_PCM ;
            waveform.nChannels       = 1 ;
            waveform.nSamplesPerSec  = 11025 ;
            waveform.nAvgBytesPerSec = 11025 ;
            waveform.nBlockAlign     = 1 ;
            waveform.wBitsPerSample  = 8 ;
            waveform.cbSize          = 0 ;

            if (waveInOpen (&hWaveIn, WAVE_MAPPER, &waveform,
                            (DWORD) hwnd, 0, CALLBACK_WINDOW))
            {
                free (pBuffer1) ;
                free (pBuffer2) ;
            }
            // Set up headers and prepare them

            pWaveHdr1->lpData          =reinterpret_cast <CHAR*>( pBuffer1 ) ;
            pWaveHdr1->dwBufferLength  = INP_BUFFER_SIZE ;
            pWaveHdr1->dwBytesRecorded = 0 ;
            pWaveHdr1->dwUser          = 0 ;
            pWaveHdr1->dwFlags         = 0 ;
            pWaveHdr1->dwLoops         = 1 ;
            pWaveHdr1->lpNext          = NULL ;
            pWaveHdr1->reserved        = 0 ;

            waveInPrepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;

            pWaveHdr2->lpData          = reinterpret_cast <CHAR*>(pBuffer2 ) ;
            pWaveHdr2->dwBufferLength  = INP_BUFFER_SIZE ;
            pWaveHdr2->dwBytesRecorded = 0 ;
            pWaveHdr2->dwUser          = 0 ;
            pWaveHdr2->dwFlags         = 0 ;
            pWaveHdr2->dwLoops         = 1 ;
            pWaveHdr2->lpNext          = NULL ;
            pWaveHdr2->reserved        = 0 ;

            waveInPrepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;
			}
            break ;

        case IDC_STOP:
			{
			// Reset input to return last buffer
            EnableWindow (RecButton, TRUE) ;
            EnableWindow (StpButton, FALSE) ;
            EnableWindow (PlyButton, TRUE);
            bEnding = TRUE ;

			//save wav file to temp.wav
            int chunksize,pcmsize,NumSamples,subchunk1size;
            int audioFormat = 1;
            int numChannels = 1;
            int bitsPerSample = 8;



            NumSamples = ((long) (NUMPTS/sampleRate) * 1000);
            pcmsize = sizeof(PCMWAVEFORMAT);


            subchunk1size= 16;
            int byteRate = (sampleRate*numChannels)*(bitsPerSample/8);
            int blockAlign = numChannels*bitsPerSample/8;
            int subchunk2size = pWaveHdr1->dwBufferLength*numChannels;


			chunksize = (36 + subchunk2size);
            fstream myFile ("temp.wav", ios::out | ios::binary);

            // write the wav file per the wav file format
            myFile.seekp (0, ios::beg);
            myFile.write ("RIFF", 4);					// chunk id
            myFile.write ((char*) &chunksize, 4);	        	// chunk size (36 + SubChunk2Size))
            myFile.write ("WAVE", 4);					// format
            myFile.write ("fmt ", 4);					// subchunk1ID
            myFile.write ((char*) &subchunk1size, 4);			// subchunk1size (16 for PCM)
            myFile.write ((char*) &audioFormat, 2);			// AudioFormat (1 for PCM)
            myFile.write ((char*) &numChannels, 2);			// NumChannels
            myFile.write ((char*) &sampleRate, 4);			// sample rate
            myFile.write ((char*) &byteRate, 4);			// byte rate (SampleRate * NumChannels * BitsPerSample/8)
            myFile.write ((char*) &blockAlign, 2);			// block align (NumChannels * BitsPerSample/8)
            myFile.write ((char*) &bitsPerSample, 2);			// bits per sample
            myFile.write ("data", 4);					// subchunk2ID
            myFile.write ((char*) &subchunk2size, 4);			// subchunk2size (NumSamples * NumChannels * BitsPerSample/8)

            myFile.write (pWaveHdr1->lpData, pWaveHdr1->dwBufferLength);	// data
			}
			break ;

        case IDC_PLAY:
			{
			// play wav file
          bPlaying = TRUE;

			EnableWindow (PlyButton, FALSE);
           waveform.wFormatTag      = WAVE_FORMAT_PCM ;
            waveform.nChannels       = 1 ;
            waveform.nSamplesPerSec  = 11025 ;
            waveform.nAvgBytesPerSec = 11025 ;
            waveform.nBlockAlign     = 1 ;
            waveform.wBitsPerSample  = 8 ;
            waveform.cbSize          = 0 ;
            waveInReset (hWaveIn) ;

			if (waveOutOpen (&hWaveOut, WAVE_MAPPER, &waveform,
                             (DWORD) hwnd, 0, CALLBACK_WINDOW))
            {

                MessageBox (hwnd, szOpenError, szAppName,
                            MB_ICONEXCLAMATION | MB_OK) ;
            }




           Wav("temp.wav");
            // Open waveform audio for output




			RECT rc;
            GetClientRect(hwnd, &rc);
            PLAY = TRUE;
            InvalidateRect(hwnd,&rc,TRUE);
			}
			break ;
        }
        break ;

    case WM_DESTROY:
        PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
        break;




    default:                      /* for messages that we don't deal with */
        return DefWindowProc (hwnd, message, wParam, lParam);
    }



    return 0;
}

//start of wave visualisation process

int readSample(int number,bool leftchannel)
{

    /*
      Reads sample number, returns it as an int, if
      this.mono==false we look at the leftchannel bool
      to determine which to return.

      number is in the range [0,length/byte_samp]

      returns 0xefffffff on failure
    */

    if (number>=0 && number<length/byte_samp)
    {
        // go to beginning of the file
        rewind(stream);

        // we start reading at sample_number * sample_size + header length
        int offset = number * 1 + 44;

        // unless this is a stereo file and the rightchannel is requested.
        //if (!mono && !leftchannel)
        //{
        // offset += byte_samp/2;
        //  }

        // read this many bytes;
        int amount;
        amount=byte_samp;

        fseek(stream,offset,SEEK_CUR);
        short sample = 0;
        fread((void *)&sample,1,amount,stream);

        return sample;
    }
    else
    {
        // return 0xefffffff if failed
        return (int)0xefffffff;
    }
}
// Read the temporary wav file
void Wav(char *c)
{

    filename = new char[strlen(c)+1];
    strcpy(filename,c);
    // open filepointer readonly
    stream = fopen(filename,"r");
    if (stream==NULL)
    {
        cout << "Could not open " << filename << endl;
    }
    else
    {
        // declare a char buff to store some values in
        char *buff = new char[5];
        buff[4]='\0';
        // read the first 4 bytes
        fread((void *)buff,1,4,stream);
        // the first four bytes should be 'RIFF'
        if (strcmp((char *)buff,"RIFF")==0)
        {

            // read byte 8,9,10 and 11
            fseek(stream,4,SEEK_CUR);
            fread((void *)buff,1,4,stream);
            // this should read "WAVE"
            if (strcmp((char *)buff,"WAVE")==0)
            {
                // read byte 12,13,14,15
                fread((void *)buff,1,4,stream);
                // this should read "fmt "
                if (strcmp((char *)buff,"fmt ")==0)
                {
                    fseek(stream,20,SEEK_CUR);
                    // final one read byte 36,37,38,39
                    fread((void *)buff,1,4,stream);
                    if (strcmp((char *)buff,"data")==0)
                    {


                        // Now we know it is a wav file, rewind the stream
                        rewind(stream);
                        // now is it mono or stereo ?
                        fseek(stream,22,SEEK_CUR);
                        fread((void *)buff,1,2,stream);
                        if (buff[0]==0x02)
                        {
                            mono=false;
                        }
                        else
                        {
                            mono=true;
                        }
                        // read the sample rate
                        fread((void *)&s_rate,1,4,stream);
                        fread((void *)&byte_sec,1,4,stream);
                        byte_samp=0;
                        fread((void *)&byte_samp,1,2,stream);
                        bit_samp=0;
                        fread((void *)&bit_samp,1,2,stream);
                        fseek(stream,4,SEEK_CUR);
                        fread((void *)&length,1,4,stream);
                    }
                }
            }
        }
        delete buff;

    }
}




use the original resource.h and resource.rc files

link to relevant Libraries. I trust you know how to do that ?

WinMM.lib
becomes
libwinmm.a etc..etc...

Best Wishes

Snoopy.
Was This Post Helpful? 1
  • +
  • -

#4 Weaselmummy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 03-March 12

Posted 03 March 2012 - 05:45 AM

Nice tutorial. One problem, it wont compile for me at the moment (using VS2008).

It gives me the following erros:


Error	1	error C2065: 'CALLBACK' : undeclared identifier	c:\program files\microsoft sdks\windows\v6.0a\include\prsht.h	97
Error	2	error C2065: 'LPFNPSPCALLBACKA' : undeclared identifier	c:\program files\microsoft sdks\windows\v6.0a\include\prsht.h	97
Error	3	error C4430: missing type specifier - int assumed. Note: C++ does not support default-int	c:\program files\microsoft sdks\windows\v6.0a\include\prsht.h	97
Error	4	fatal error C1903: unable to recover from previous error(s); stopping compilation	c:\program files\microsoft sdks\windows\v6.0a\include\prsht.h	97


Looks like somethings wrong with at which point windows.h gets included, but I can't get it to work.

Any ideas?

Cheers!
Was This Post Helpful? 0
  • +
  • -

#5 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 762
  • View blog
  • Posts: 2,218
  • Joined: 20-March 10

Posted 03 March 2012 - 09:53 AM

Hi WeaselMummy,

Can't be totally sure as you don't include the
full error as it appears in your enviroment
just an abbreviated version of it.

My best guess is there is something wrong
with the series of includes.

#include "stdafx.h"

Should come first before any of the other
includes in vs.

If that doesn't work move the series of
Includes in the program into the
StdAfx.h header file. Then just include "StdAfx.h"
In the programs main.cpp.

Try that and let me know.

Best Wishes

Snoopy.
Was This Post Helpful? 0
  • +
  • -

#6 Weaselmummy  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 03-March 12

Posted 04 March 2012 - 05:42 AM

Hey Snoopy,

Thanks for the reply! Got rid of the error, got some others now but I can
figure them out. Again, thanks!
Was This Post Helpful? 0
  • +
  • -

#7 bboychee  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 28-May 12

Posted 28 May 2012 - 08:21 PM

Hi KoolKoder,

Thank you for your great tutorial.I'm a newbie and got a lot problems.hmm. Do you know how to get the raw format data? Thank you in advance.

Best Regards,
Chee
Was This Post Helpful? 0
  • +
  • -

#8 bboychee  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 28-May 12

Posted 28 May 2012 - 08:29 PM

Hey snoopy11,

Ahh. Sorry guy. I called wrong name just now.

Best Regards!
Was This Post Helpful? 0
  • +
  • -

#9 snoopy11  Icon User is offline

  • Engineering ● Software
  • member icon

Reputation: 762
  • View blog
  • Posts: 2,218
  • Joined: 20-March 10

Posted 03 June 2012 - 10:35 AM

View Postbboychee, on 29 May 2012 - 03:29 AM, said:

Hey snoopy11,

Ahh. Sorry guy. I called wrong name just now.

Best Regards!


No Worries,

The raw data in the program is stored in

pWaveHdr1->lpData

its only a few seconds... however due to resources n stuff

real world audio programs buffer it record a few seconds buffer it and so on,
wash, rinse and repeat.

But this is just a very basic demo..

Best Wishes

Snoopy.
Was This Post Helpful? 0
  • +
  • -

#10 ericetc  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 21
  • Joined: 24-July 12

Posted 24 July 2012 - 08:04 PM

Hi snoopy,

I am getting the following error:

resource.h(18) : fatal error C1070: mismatched #if/#endif pair in file 'c:\users\eric\desktop\wav recorder\wavrecord2\wavrecord\resource.h'

I pasted the source that you posted exactly as posted.... any suggestions? :)
Was This Post Helpful? 0
  • +
  • -

#11 ericetc  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 21
  • Joined: 24-July 12

Posted 24 July 2012 - 08:12 PM

Nevermin... I figured it out. getting other errors (have include stdafx.h) but trying to figure them out before posting.
Was This Post Helpful? 0
  • +
  • -

#12 ericetc  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 21
  • Joined: 24-July 12

Posted 25 July 2012 - 02:08 AM

I am getting fatal error LNK1104: cannot open file 'WinMM.Lib;'. I added WinMM.Lib; kernel32.lib; user32.lib; comdlg32.lib as required to the linker. As a test I removed WinMM.Lib and I received the same error regarding kernel32.lib. I've checked my computer and WinMM.Lib exists on my computer as I expected. Any ideas what is going on?

thanks
Eric
Was This Post Helpful? 0
  • +
  • -

#13 Skydiver  Icon User is online

  • Code herder
  • member icon

Reputation: 3457
  • View blog
  • Posts: 10,665
  • Joined: 05-May 12

Posted 25 July 2012 - 06:18 PM

Sounds like the path to where your libraries are is not set correctly.

I don't have VC2008, otherwise I would tell you how to post back the path that the IDE thinks where it should find the library files. I think it'll be something like:
Project Properties / Configuration Properties / VC++ Directories / Library Directories
or
Project Properties / Configuration Properties / Linker / General / Additional Library Directories
Was This Post Helpful? 0
  • +
  • -

#14 ericetc  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 21
  • Joined: 24-July 12

Posted 26 July 2012 - 03:34 AM

Hi Skydiver,

I made the change you suggested with --> Project Properties / Configuration Properties / Linker / General / Additional Library Directories to reflect the location of the lib files but still having the same error.

Eric
Was This Post Helpful? 0
  • +
  • -

#15 Skydiver  Icon User is online

  • Code herder
  • member icon

Reputation: 3457
  • View blog
  • Posts: 10,665
  • Joined: 05-May 12

Posted 26 July 2012 - 09:50 AM

You probably should start a thread in the C/C++ forum. I think this is an issue specific to your build environment.
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2