Creating & Recording Sound in WAV file using MIMOS with C/C++

by Angelos on July 31, 2009

I spent quite a time to make the header and sub-header of wav file properly. Searched a lot on internet but didn’t find much help. So, after writing the code successfully, I have posted it on my web site and to help any one who is interested in this.

I have tried to explain the code in the most easiest of the fashion along with comments, but if you feel any problem, do ask, I might be able to lend you some hand. One thing should be mentioned, that I have the “Recording.wav” file already created before running this code, you can create it using fstream. The reason for already creating the file is that I was actually interested in creating the header and sub-header of wav file, because even if you record data in wav file, it will not work properly, as long as its header and sub-header are not created successfully. Also,  performed sound recording using mimo. You can use fstream for it also.  If you want further help in understanding the basic structure of wav file, do check the links given at the end of the post.

#include <Windows.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <Mmsystem.h>
#include <Mmreg.h.>
#include <fstream.h>

#define BUFFER_LEN 102400

void main()
{
WAVEINCAPS lpwaveincaps;
MMRESULT sounddeviceinfo;

UINT count = waveInGetNumDevs();

printf("%d\n",count);

sounddeviceinfo = waveInGetDevCaps(0, &amp;lpwaveincaps, sizeof(WAVEINCAPS));
if (sounddeviceinfo != MMSYSERR_NOERROR)
{
printf("Error in getting info about Sound Device\n");
return;
}
printf("%d",sounddeviceinfo);

WAVEFORMATEX formatinfo;
formatinfo.cbSize = 0;
formatinfo.wFormatTag = WAVE_FORMAT_PCM;
formatinfo.nChannels = 1; // 1 for mono 2 and 2 for stereo
formatinfo.wBitsPerSample = 16; // can be 8 or 16
formatinfo.nSamplesPerSec = 8000; // u can set nSamplesPerSec as 16000, 24000.
//44100, 48000 depending on the quality you want
formatinfo.nBlockAlign = formatinfo.nChannels * (formatinfo.wBitsPerSample / 8);
formatinfo.nAvgBytesPerSec = formatinfo.nSamplesPerSec * formatinfo.nBlockAlign;

MMRESULT soundfileopen;
HWAVEIN hwi;

char buffer1[BUFFER_LEN]//waveform buffer

soundfileopen = waveInOpen( &amp;hwi, WAVE_MAPPER, &amp;formatinfo, 0, 0, 0);
if (soundfileopen != MMSYSERR_NOERROR)
{
if (soundfileopen == MMSYSERR_ALLOCATED)
{
printf("Error in opening audio device, 1\n");
return;
}
if (soundfileopen == MMSYSERR_BADDEVICEID)
{
printf("Error in opening audio device, 2\n");
return;
}
if (soundfileopen == MMSYSERR_NODRIVER)
{
printf("Error in opening audio device, 3 \n");
return;
}
if (soundfileopen == MMSYSERR_NOMEM)
{
printf("Error in opening audio device, 4\n");
return;
}
if (soundfileopen == WAVERR_BADFORMAT)
{
printf("Error in opening audio device, 5 \n");
return;
}
}

// Preaparing WHDR
WAVEHDR buffer;
ZeroMemory(&amp;buffer, sizeof(buffer)); //filling the block with zeros
buffer.dwBufferLength=BUFFER_LEN;
buffer.lpData=(LPSTR)&amp;buffer1;

// Preaparing header
MMRESULT waveinheader;
waveinheader = waveInPrepareHeader( hwi, &amp;buffer, sizeof(WAVEHDR));
if (waveinheader == MMSYSERR_NOERROR)
{
waveInAddBuffer( hwi, &amp;buffer, sizeof(buffer));

printf("Recording Data…\n");

// start recording
waveInStart( hwi);

//keep recording for 100milliseconds unless flag is set
while ( (buffer.dwFlags &amp; WHDR_DONE) != WHDR_DONE)
{
Sleep(100);
//printf("dwFlags %d\n", buffer.dwFlags);
}

waveInStop( hwi);

printf("Recording Completed, number of bytes recorded are %d\n", buffer.dwBytesRecorded );

/*
Basic steps you need to follow while writing wave file using mmio
1) mmioOpen
2) mmioCreateChunk – ‘RIFF’ &amp; ‘WAVE’
3) mmioCreateChunk – ‘fmt ‘
4) mmioWrite – WAVEFORMATEX
5) mmioAscend – out of ‘fmt ‘ – writes fmt length
6) mmioCreateChunk ‘data’
7) mmioWrite – audio data
8) mmioAscend – out of ‘data’ – writes data length
9) mmioAscend -out of ‘RIFF’ – write ‘RIFF’ length
10) mmioClose
*/

// creating a file using mmio, C:\\Recording.wav already exists
HMMIO file;
file = mmioOpen("C:\\Recording.wav", NULL, MMIO_CREATE | MMIO_READWRITE );
if (file == NULL)
{
printf("Error in creating file using MIMO-OPEN\n");
}

MMCKINFO mmckinfo;
MMCKINFO mmckinfoSubchunk;
MMCKINFO mmckinfoData;

memset(&amp;mmckinfo, 0, sizeof(mmckinfo));
memset(&amp;mmckinfoSubchunk, 0, sizeof(mmckinfoSubchunk));
memset(&amp;mmckinfoData, 0, sizeof(mmckinfoData));

//step 1 create riff chunk
mmckinfo.fccType    = mmioFOURCC(‘W’, ‘A’, ‘V’, ‘E’);
if(mmioCreateChunk( file, &amp;mmckinfo, MMIO_CREATERIFF) != MMSYSERR_NOERROR)
{
printf("Error in creating chunk wave\n");
}

//step 2 create fmt chunk
//creating fmt chunk also includes writing formatex to this chunk
mmckinfoSubchunk.ckid = mmioFOURCC(‘f’, ‘m’, ‘t’, ‘ ‘);
mmckinfoSubchunk.cksize = sizeof(WAVEFORMATEX) ;

if(mmioCreateChunk( file, &amp;mmckinfoSubchunk, 0) != MMSYSERR_NOERROR)
{
printf("Error in creating chunk sub\n");
}

if(mmioWrite( file, (char*)&amp;formatinfo, sizeof(formatinfo)) == -1 )
{
printf("Error in writing chunk sub\n");
}
if(mmioAscend( file,   &amp;mmckinfoSubchunk, 0) != MMSYSERR_NOERROR )
{
printf("Error in ascending out of chunk sub\n");
}

//step 3 creating data chunk
//creating this chunk includes writing actual voice data
mmckinfoData.ckid=mmioFOURCC(‘d’,‘a’,‘t’,‘a’);
mmckinfoData.cksize = formatinfo.nAvgBytesPerSec;
if(mmioCreateChunk( file, &amp;mmckinfoData, 0) != MMSYSERR_NOERROR)
{
printf("Error in creating chunk data\n");
}
if (mmioWrite( file, (char*)&amp;buffer.lpData, BUFFER_LEN) == -1 )
{
printf("Error in writing chunk data\n");
}

MMRESULT check = mmioAscend( file, &amp;mmckinfoData, 0);
if(check != MMSYSERR_NOERROR)
{
printf("Error in ascending out of chunk data\n");
}

if(mmioAscend( file,   &amp;mmckinfo, 0) != MMSYSERR_NOERROR )
{
printf("Error in ascending out of chunk wave\n");
}

waveInUnprepareHeader(hwi, &amp;buffer, sizeof(buffer));

mmioClose( MMIO_READ, MMIO_FHOPEN);

waveInClose(hwi);
}
else
{
if (waveinheader == MMSYSERR_INVALHANDLE)
{
printf("Specified device handle is invalid.\n");
return;
}
if (waveinheader == MMSYSERR_NODRIVER)
{
printf("No device driver is present.\n");
return;
}
if (waveinheader == MMSYSERR_NOMEM)
{
printf("Unable to allocate or lock memory.\n");
return;
}
}
}

/*
to read any wav file, use this link
http://loosethinker.com/software_development/?page=knowledge_base&amp;id=2

Refernces
http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
http://www.topherlee.com/software/pcm-tut-wavformat.html
http://www.tech-archive.net/
http://msdn.microsoft.com/en-us/library/ms712601%28VS.85%29.aspx
http://www.programmersheaven.com
*/

Related Posts:

  • No Related Post
  • Shakil

    hi.i read your document.i have few questions.
    1.which compiler did you use to compile this code.
    2.is it possible to compile it in borland c++ 3.0 if yes how and if no why not
    3.is there any library to support wav file playback in pc speakers(stereo) for borland
    c++ compiler
    4.can u provide me with basic idea(algorithm) to understand how exactly C reads,processes and plays the wav file.

  • zarLag

    @shakil || whoever

    #include
    #include
    #include
    #include
    #include
    #include
    #include

    so you have any of this headers in your compiler’s library? that is the a possible main reason why it wont compile on you system cause the method that are used in the non-existing header file are not declare therefore the compile has no idea how to translate the code in the machine language.

  • http://www.nerdcrunch.com NemanShahid

    I used Visual C++ 6.0 to compile this code, I dont know if this works in borland compiler or not. To understand the idea how C processes/plays wav file, you need to go through links I mentioned at the end of the code. Hope it helps!

  • Santoshthota87

    so many errors im getting when i run in VS++.. amp undefined…. plz provide error less code..

blog comments powered by Disqus

Previous post:

Next post: