//========================================================================
//TITLE:
// CSoundBase实现录音与播放
//AUTHOR:
// norains
//DATE:
// Wednesday 10-January -2007
//Environment:
//EVC4.0 + Standard SDK
//========================================================================
1.简介
CSoundBase是我封装的一个API类,主要是为了能方便实现声音的录制和播放.目前仅支持WAV的录制和播放.
完整的代码见本文第四节.
如果各位朋友发现有BUG需要修正,欢迎和我联系,谢谢!
2.使用方法
CSoundBase类的使用非常简单,首先声明一个类指针,然后获取类的实例:
CSoundBase*pSoundPlayer;
pSoundPlayer->CSoundBase::GetInstance();
假如我们需要在"record"文件夹中录制一个名字为"first"的文件,只需很简单的一条语句:
pSoundPlayer->Record(TEXT("record/first.wav"));
不过这样是采用默认的录制格式,实际录音中我们可以进行更改.不过在进行这一步之前,我们先看一下这个类:
typedefstruct

...{
ChannelTypechannel;
SamplesPerSecTypesamples;
BitsPerSampleTypebits;
}WAVEFORMAT_SETTING,*PWAVEFORMAT_SETTING;
我们来看看这个类成员代表的意义:
channel
声道数,其取值可以为:CHANNEL_SINGLE(单声道),CHANNEL_DOUBLE(双声道).
samples
采样率,其取值可以为SAMPLES_11025,SAMPLES_22050,SAMPLES_44100
bits
采样位,其取值为BITS_8,BITS_16
如果我们录制的一个文件有如下要求:单声道,采样率为22050MHZ,采样位为16位,代码非常简单,如下:
WAVEFORMAT_SETTINGwaveFormat;
waveFormat.channel=CHANNEL_SINGLE;
waveFormat.samples=SAMPLES_22050;
waveFormat.bits=SAMPLES_44100;
pSoundPlayer->Record(TEXT("record/first.wav"),&waveFormat);
当想停止录音时,可调用StopRecording():
pSoundPlayer->StopRecording();
如果想播放刚刚的录制的wav文件,只需简单调用Play()即可:
pSoundPlayer->Play();
当然,也可以播放储存器上任意一处的wav文件,如:
pSoundPlayer->Play(TEXT("record/second.wav"));
停止播放同样也很简单:
pSoundPlayer->StopPlaying();
由于录音和播放是分别占用不同的缓冲区,所以我们可以边播放边录音,当然了,前提是录音和播放的不能是同一个文件:
pSoundPlayer->Record(TEXT("record/first.wav"));
pSoundPlayer->Play(TEXT("record/second.wav"));
这时候我们可以调用StopAll()函数同时停止录音和播放:
pSoundPlayer->StopAll();
3.CSoundBase的实现细节
3.1 waveInUnprepareHeader()的死锁
有的追求完美的朋友可能会觉得,为什么waveInUnprepareHeader()不放在WIM_CLOSE消息的响应函数OnWIM_DATA()中.恩,这个方法我曾经想过,也曾经尝试过,不过很可惜失败了.因为在回调函数中调用waveInUnprepareHeader()会导致死锁,从而使程序崩溃.所以在处理WIM_DATA消息时,很巧妙地没有调用waveInUnprepareHeader()来卸载,而是直接把已经录制完毕并且其数据已经写到文件中的内存作为新录制缓冲区添加:waveInAddBuffer (m_hWaveIn, (PWAVEHDR) wParam, sizeof (WAVEHDR)).这样即可避免了死锁,又减少了分配内存的花销,可谓一箭双雕吧.
3.2 WIM_DATA消息的响应
细心的朋友可能会发现,在StopRecording()函数里调用waveInClose()之前还调用了waveInReset().因为根据文档,如果在调用waveInClose()之前调用waveInAddBuffer()添加的内存没有返回释放,则waveInClose()将调用失败,从另一个角度来说,此时系统将不会回调WIM_CLOSE消息.故在waveInClose()函数之前调用waveInReset()来释放之前映射的内存.
不过这时候会有一个小问题,就是调用waveInReset()时系统会发送WIM_DATA消息.所以我们在WIM_DATA消息的响应函数中需要做个小小的判断,就是在响应调用waveInReset()而返回的WIM_DATA消息时,我们不再添加录音缓存区.
在代码中表现如下:
if(m_bRecording==TRUE)

...{
waveInAddBuffer(m_hWaveIn,(PWAVEHDR)wParam,sizeof(WAVEHDR));
}
3.3 更多实现细节
由于代码的总体思路在我的另一篇文章中已经详细说明,在此略为不表.
有兴趣的朋友可参考《EVC录音详解》一文:http://blog.youkuaiyun.com/norains/archive/2006/06/13/795777.aspx
4.CSoundBase 完整源代码


/**///////////////////////////////////////////////////////////////////////
//SoundBase.h:interfacefortheCSoundBaseclass.//

/**///////////////////////////////////////////////////////////////////////
//AUTHOR://
//norains//
//VERSION://
//1.0.0//
//DATE://
//Wednesday10-January-2007//
//Environment://
//EVC4.0+StandardSDK//

/**///////////////////////////////////////////////////////////////////////
#ifndefSOUNDBASE_H
#defineSOUNDBASE_H

#include"mmsystem.h"
//------------------------------------------------------------------------------
//Macrodefine
#defineMAX_SAVEPATH_LENGTH500//Thelengthofsavedpath

//------------------------------------------------------------------------------
//Valuetype

enumChannelType

...{
CHANNEL_SINGLE,
CHANNEL_DOUBLE
};

enumSamplesPerSecType

...{
SAMPLES_11025,
SAMPLES_22050,
SAMPLES_44100
};

enumBitsPerSampleType

...{
BITS_8,
BITS_16
};
//---------------------------------------------------------------------------
//Struct

//Waveformatdata
typedefstruct

...{
ChannelTypechannel;
SamplesPerSecTypesamples;
BitsPerSampleTypebits;
}WAVEFORMAT_SETTING,*PWAVEFORMAT_SETTING;
//------------------------------------------------------------------------------
classCSoundBase

...{
public:
voidStopPlaying();
voidStopRecording();
voidStopAll();
staticCSoundBase*GetInstance();
BOOLPlay(constTCHAR*pszPath=NULL);
BOOLRecord(TCHAR*pszPath,constPWAVEFORMAT_SETTINGpWaveFormat=NULL);

virtual~CSoundBase();
protected:
voidOnWIM_OPEN(WPARAMwParam,LPARAMlParam);
voidOnWIM_DATA(WPARAMwParam,LPARAMlParam);
voidOnWIM_CLOSE(WPARAMwParam,LPARAMlParam);
BOOLWriteWaveFileHeader(TCHAR*pszFilename,constPWAVEFORMATEXpWFX,DWORDdwBufferSize,BOOLbCover);
staticvoidCALLBACKWaveInProc(HWAVEINhWi,UINTuMsg,DWORDdwInstance,DWORDdwParam1,DWORDdwParam2);
CSoundBase();
voidSetRecordWaveFormat(constPWAVEFORMAT_SETTINGpWaveFormat);

staticCSoundBase*m_pInstance;
WAVEFORMATEXm_WaveFormatEx;
BOOLm_bRecording;
HANDLEm_hSaveFile;
HWAVEINm_hWaveIn;
PBYTEm_pBuffer1;
PBYTEm_pBuffer2;
PWAVEHDRm_pWaveHdr1;
PWAVEHDRm_pWaveHdr2;
DWORDm_dwDataLength;//Thelengthofthedata
TCHARm_szSavePath[MAX_SAVEPATH_LENGTH];//Thepathtosave


};

#endif//SOUNDBASE_H




/**//////////////////////////////////////////////////////////////////////
//SoundBase.cpp:implementationoftheCSoundBaseclass.//

/**//////////////////////////////////////////////////////////////////////
#include"stdafx.h"
#include"SoundBase.h"



//------------------------------------------------------------------------------
//Macrodefine
#defineINP_BUFFER_SIZE16*1024//Theinputbuffersize

#defineRIFF_FILEmmioFOURCC('R','I','F','F')
#defineRIFF_WAVEmmioFOURCC('W','A','V','E')
#defineRIFF_FORMATmmioFOURCC('f','m','t','')
#defineRIFF_CHANNELmmioFOURCC('d','a','t','a')

//Defaultvalues
#defineDEFAULT_CHANNELCHANNEL_SINGLE
#defineDEFAULT_SAMPLESSAMPLES_11025
#defineDEFAULT_BITSBITS_8

//------------------------------------------------------------------------------
//Thestruct

//FileHeader
typedefstruct

...{
DWORDdwRiff;//Typeoffileheader.
DWORDdwSize;//Sizeoffileheader.
DWORDdwWave;//Typeofwave.
}RIFF_FILEHEADER,*PRIFF_FILEHEADER;



//ChunkHeader
typedefstruct

...{
DWORDdwCKID;//TypeIdentificationforcurrentchunkheader.
DWORDdwSize;//Sizeofcurrentchunkheader.
}RIFF_CHUNKHEADER,*PRIFF_CHUNKHEADER;
//---------------------------------------------------------------------------------

//-------------------------------------------------------------------
//Staticmemberinitialize
CSoundBase*CSoundBase::m_pInstance=NULL;//Ifyoudon'tinitialize,theGetInstance()willlinkerro.



/**///////////////////////////////////////////////////////////////////////
//Construction/Destruction

/**///////////////////////////////////////////////////////////////////////
CSoundBase::CSoundBase()

...{
memset(m_szSavePath,0,sizeof(m_szSavePath));
memset(&m_WaveFormatEx,0,sizeof(m_WaveFormatEx));
m_pBuffer1=NULL;
m_pBuffer2=NULL;
m_pWaveHdr1=NULL;
m_pWaveHdr2=NULL;
m_hWaveIn=NULL;
m_hSaveFile=NULL;
m_bRecording=FALSE;
m_dwDataLength=0;


}

CSoundBase::~CSoundBase()

...{

if(m_pWaveHdr1!=NULL)

...{
free(m_pWaveHdr1);
m_pWaveHdr1=NULL;
}

if(m_pWaveHdr2!=NULL)

...{
free(m_pWaveHdr2);
m_pWaveHdr2=NULL;
}

if(m_pBuffer1!=NULL)

...{
free(m_pBuffer1);
m_pBuffer1=NULL;
}

if(m_pBuffer2!=NULL)

...{
free(m_pBuffer2);
m_pBuffer2=NULL;
}

}

//----------------------------------------------------------------------
//Decription:
//Starttorecord.
//
//Parameter:
//pszPath:[in]Therecordpath
//
//RetrunValues:
//TRUE:Succeed.
//FALSE:Failed.
//----------------------------------------------------------------------
BOOLCSoundBase::Record(TCHAR*pszPath,constPWAVEFORMAT_SETTINGpWaveFormat)

...{
BOOLbResult=FALSE;
_tcscpy(m_szSavePath,pszPath);

SetRecordWaveFormat(pWaveFormat);

if(waveInOpen(&m_hWaveIn,WAVE_MAPPER,&m_WaveFormatEx,(DWORD)WaveInProc,NULL,CALLBACK_FUNCTION)!=MMSYSERR_NOERROR)

...{
gotoEND;
}

m_pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);
m_pBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE);
if(m_pBuffer1==NULL||m_pBuffer2==NULL)

...{
gotoEND;
}


//allocatememoryforwaveheader
m_pWaveHdr1=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
m_pWaveHdr2=reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));

if(m_pWaveHdr1==NULL||m_pWaveHdr2==NULL)

...{
gotoEND;
}

m_pWaveHdr1->lpData=(LPSTR)m_pBuffer1;
m_pWaveHdr1->dwBufferLength=INP_BUFFER_SIZE;
m_pWaveHdr1->dwBytesRecorded=0;
m_pWaveHdr1->dwUser=0;
m_pWaveHdr1->dwFlags=0;
m_pWaveHdr1->dwLoops=1;
m_pWaveHdr1->lpNext=NULL;
m_pWaveHdr1->reserved=0;
waveInPrepareHeader(m_hWaveIn,m_pWaveHdr1,sizeof(WAVEHDR));

m_pWaveHdr2->lpData=(LPSTR)m_pBuffer2;
m_pWaveHdr2->dwBufferLength=INP_BUFFER_SIZE;
m_pWaveHdr2->dwBytesRecorded=0;
m_pWaveHdr2->dwUser=0;
m_pWaveHdr2->dwFlags=0;
m_pWaveHdr2->dwLoops=1;
m_pWaveHdr2->lpNext=NULL;
m_pWaveHdr2->reserved=0;
waveInPrepareHeader(m_hWaveIn,m_pWaveHdr2,sizeof(WAVEHDR));

//Addthebuffers
waveInAddBuffer(m_hWaveIn,m_pWaveHdr1,sizeof(WAVEHDR));
waveInAddBuffer(m_hWaveIn,m_pWaveHdr2,sizeof(WAVEHDR));


if(WriteWaveFileHeader(m_szSavePath,&m_WaveFormatEx,0,TRUE)==FALSE)

...{

gotoEND;
}

//norains:Opentheexistingwavefileincordingtoaddwavedata
m_hSaveFile=CreateFile(m_szSavePath,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
if(m_hSaveFile==INVALID_HANDLE_VALUE)

...{
gotoEND;
}
//Setthefilepointertotheend.
SetFilePointer(m_hSaveFile,0,NULL,FILE_END);

//Beginrecording
waveInStart(m_hWaveIn);

bResult=TRUE;
END:
if(bResult==FALSE)

...{
if(m_pWaveHdr1!=NULL)

...{
free(m_pWaveHdr1);
m_pWaveHdr1=NULL;
}

if(m_pWaveHdr2!=NULL)

...{
free(m_pWaveHdr2);
m_pWaveHdr2=NULL;
}

if(m_pBuffer1!=NULL)

...{
free(m_pBuffer1);
m_pBuffer1=NULL;
}


if(m_pBuffer2!=NULL)

...{
free(m_pBuffer2);
m_pBuffer2=NULL;
}

if(m_hWaveIn!=NULL)

...{
//Stoprecording,closethedevice
waveInReset(m_hWaveIn);
waveInClose(m_hWaveIn);
m_hWaveIn=NULL;
}
}
returnbResult;
}

//----------------------------------------------------------------------
//Decription:
//Stoprecordingandplaying
//
//Parameter:
//NULL
//
//RetrunValues:
//NULL
//----------------------------------------------------------------------
voidCSoundBase::StopAll()

...{
StopRecording();
StopPlaying();
}

//----------------------------------------------------------------------
//Decription:
//Stopplaying
//
//Parameter:
//NULL
//
//RetrunValues:
//NULL
//----------------------------------------------------------------------
voidCSoundBase::StopPlaying()

...{
sndPlaySound(NULL,SND_ASYNC);
}

//----------------------------------------------------------------------
//Decription:
//Stoprecording
//
//Parameter:
//NULL
//
//RetrunValues:
//NULL
//----------------------------------------------------------------------
voidCSoundBase::StopRecording()

...{
if(m_bRecording==FALSE)

...{
return;
}

m_bRecording=FALSE;
waveInReset(m_hWaveIn);
waveInClose(m_hWaveIn);

//Pleasedon'tcallwaveInUnprepareHeader()intheWIM_CLOSE,
//oritwillworkbadly!
waveInUnprepareHeader(m_hWaveIn,m_pWaveHdr1,sizeof(WAVEHDR));
waveInUnprepareHeader(m_hWaveIn,m_pWaveHdr2,sizeof(WAVEHDR));

if(m_pWaveHdr1!=NULL)

...{
free(m_pWaveHdr1);
m_pWaveHdr1=NULL;
}

if(m_pWaveHdr2!=NULL)

...{
free(m_pWaveHdr2);
m_pWaveHdr2=NULL;
}

if(m_pBuffer1!=NULL)

...{
free(m_pBuffer1);
m_pBuffer1=NULL;
}

if(m_pBuffer2!=NULL)

...{
free(m_pBuffer2);
m_pBuffer2=NULL;
}


}

//----------------------------------------------------------------------
//Decription:
//Starttoplay.
//
//Parameter:
//pszPath:[in]Theplayingpath
//
//RetrunValues:
//TRUE:Succeed.
//FALSE:Failed.
//----------------------------------------------------------------------
BOOLCSoundBase::Play(constTCHAR*pszPath)

...{

TCHARszPath[MAX_SAVEPATH_LENGTH]=...{0};
if(pszPath!=NULL)

...{
_tcscpy(szPath,pszPath);
}
else

...{
_tcscpy(szPath,m_szSavePath);
}

if(sndPlaySound(szPath,SND_ASYNC)==FALSE)

...{
returnFALSE;
}
returnTRUE;

}


//----------------------------------------------------------------------
//Decription:
//Setthewaveformatforrecording.
//
//Parameter:
//pWaveFormat:[in]Thewaveformattoset.
//
//RetrunValues:
//TRUE:Succeed.
//FALSE:Failed.
//----------------------------------------------------------------------
voidCSoundBase::SetRecordWaveFormat(constPWAVEFORMAT_SETTINGpWaveFormat)

...{
WAVEFORMAT_SETTINGwaveFormatSetting;
if(pWaveFormat==NULL)

...{
waveFormatSetting.channel=DEFAULT_CHANNEL;
waveFormatSetting.samples=DEFAULT_SAMPLES;
waveFormatSetting.bits=DEFAULT_BITS;
}
else

...{
waveFormatSetting=*pWaveFormat;
}

m_WaveFormatEx.wFormatTag=WAVE_FORMAT_PCM;
m_WaveFormatEx.cbSize=0;//WhenthewFormatTagisPCM,theparameterisabort.

switch(waveFormatSetting.channel)

...{
caseCHANNEL_SINGLE:
m_WaveFormatEx.nChannels=1;
break;
caseCHANNEL_DOUBLE:
m_WaveFormatEx.nChannels=2;
break;
}

switch(waveFormatSetting.samples)

...{
caseSAMPLES_11025:
m_WaveFormatEx.nSamplesPerSec=11025;
break;
caseSAMPLES_22050:
m_WaveFormatEx.nSamplesPerSec=22050;
break;
caseSAMPLES_44100:
m_WaveFormatEx.nSamplesPerSec=44100;
break;
}


switch(waveFormatSetting.bits)

...{
caseBITS_8:
m_WaveFormatEx.wBitsPerSample=8;
break;
caseBITS_16:
m_WaveFormatEx.wBitsPerSample=16;
break;
}

m_WaveFormatEx.nBlockAlign=m_WaveFormatEx.nChannels*m_WaveFormatEx.wBitsPerSample/8;
m_WaveFormatEx.nAvgBytesPerSec=m_WaveFormatEx.nBlockAlign*m_WaveFormatEx.nSamplesPerSec;

}


//----------------------------------------------------------------------
//Decription:
//Getinstance
//
//Parameter:
//Null
//
//RetrunValues:
//Thepointertoobject
//----------------------------------------------------------------------
CSoundBase*CSoundBase::GetInstance()

...{
if(m_pInstance==NULL)

...{
m_pInstance=newCSoundBase;
}
returnm_pInstance;
}


//----------------------------------------------------------------------
//Decription:
//WaveInProcess
//
//Parameter:
//hwi:[in]Handletothewaveform-audiodeviceassociatedwiththecallbackfunction
//uMsg:[in]Waveform-audioinputmessage.Itcanbeoneofthemessagesshown:WIM_CLOSE,WIM_DATA,WIM_OPEN
//dwInstance:[in]UserinstancedataspecifiedwithwaveInOpen.
//dwParam1:[in]Messageparameter.
//dwParam2:[in]Messageparameter.
//
//RetrunValues:
//DWORDtype.
//----------------------------------------------------------------------
voidCALLBACKCSoundBase::WaveInProc(HWAVEINhWi,UINTuMsg,DWORDdwInstance,DWORDdwParam1,DWORDdwParam2)

...{
switch(uMsg)

...{
caseWIM_CLOSE:
m_pInstance->OnWIM_CLOSE(dwParam1,dwParam2);
break;
caseWIM_DATA:
m_pInstance->OnWIM_DATA(dwParam1,dwParam2);
break;
caseWIM_OPEN:
m_pInstance->OnWIM_OPEN(dwParam1,dwParam2);
break;
}

}



//----------------------------------------------------------------------
//Decription:
//Writethewavefileheader.
//
//Parameter:
//pszFilename:[in]Thepathtosave
//pWFX:[in]Theinformationtowrite
//dwBufferSize:[in]Thesizeofwavebuffer
//bCover:[in]Coverwritingornot
//
//RetrunValues:
//TRUE:Succeed.
//FASLE:Failed.
//----------------------------------------------------------------------
BOOLCSoundBase::WriteWaveFileHeader(TCHAR*pszFilename,constPWAVEFORMATEXpWFX,DWORDdwBufferSize,BOOLbCover)

...{

RIFF_FILEHEADERFileHeader;
RIFF_CHUNKHEADERWaveHeader;
RIFF_CHUNKHEADERDataHeader;
DWORDdwBytesWritten;
HANDLEfh;
BOOLbResult=FALSE;

//Fillinthefile,waveanddataheaders
WaveHeader.dwCKID=RIFF_FORMAT;
WaveHeader.dwSize=sizeof(WAVEFORMATEX)+pWFX->cbSize;

//theDataHeaderchunkcontainstheaudiodata
DataHeader.dwCKID=RIFF_CHANNEL;
DataHeader.dwSize=dwBufferSize;

//TheFileHeader
FileHeader.dwRiff=RIFF_FILE;
FileHeader.dwSize=sizeof(WaveHeader)+WaveHeader.dwSize+sizeof(DataHeader)+DataHeader.dwSize;
FileHeader.dwWave=RIFF_WAVE;

//Openwavefile
if(bCover==TRUE)

...{
//Ifthefileexisted,coverwritng
fh=CreateFile(pszFilename,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL);
}
else

...{
//Openthefileexisted
fh=CreateFile(pszFilename,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL);
//Movethepointertothebegin
SetFilePointer(fh,0,NULL,FILE_BEGIN);
}

if(fh==INVALID_HANDLE_VALUE)...{
DEBUGMSG(1,(TEXT("Erroropening%s.Errorcode=0x%08x "),pszFilename,GetLastError()));
gotoERROR_EXIT;
}

//writetherifffile

if(!WriteFile(fh,&FileHeader,sizeof(FileHeader),&dwBytesWritten,NULL))...{
DEBUGMSG(1,(TEXT("Errorwritingfileheader ")));
gotoERROR_EXIT;
}

//writethewaveheader

if(!WriteFile(fh,&WaveHeader,sizeof(WaveHeader),&dwBytesWritten,NULL))...{
DEBUGMSG(1,(TEXT("Errorwritingwaveheader ")));
gotoERROR_EXIT;
}

//writethewaveformat

if(!WriteFile(fh,pWFX,WaveHeader.dwSize,&dwBytesWritten,NULL))...{
DEBUGMSG(1,(TEXT("Errorwritingwaveformat ")));
gotoERROR_EXIT;
}

//writethedataheader

if(!WriteFile(fh,&DataHeader,sizeof(DataHeader),&dwBytesWritten,NULL))...{
DEBUGMSG(1,(TEXT("ErrorwritingPCMdataheader ")));
gotoERROR_EXIT;
}
//Success
bResult=TRUE;

ERROR_EXIT:
if(fh!=INVALID_HANDLE_VALUE)

...{
CloseHandle(fh);
}
returnbResult;
}


//----------------------------------------------------------------------
//Decription:
//OnWIM_CLOSE
//------------------------------------------------------------------------
voidCSoundBase::OnWIM_CLOSE(WPARAMwParam,LPARAMlParam)

...{

if(m_hSaveFile!=NULL)

...{
CloseHandle(m_hSaveFile);
m_hSaveFile=NULL;
}
if(0!=m_dwDataLength)

...{
//Writethedatalengthtothefile.
WriteWaveFileHeader(m_szSavePath,&m_WaveFormatEx,m_dwDataLength,FALSE);
}

}

//----------------------------------------------------------------------
//Decription:
//OnWIM_DATA
//------------------------------------------------------------------------
voidCSoundBase::OnWIM_DATA(WPARAMwParam,LPARAMlParam)

...{

DWORDdwBytesRecorded=((PWAVEHDR)wParam)->dwBytesRecorded;

PBYTEpSaveBuffer;
//allocatememoryforsavebuffer
pSaveBuffer=reinterpret_cast<PBYTE>(malloc(dwBytesRecorded));
if(pSaveBuffer==NULL)

...{
waveInClose(m_hWaveIn);
return;
}

//Copythedatatothesavebuffer.
CopyMemory(pSaveBuffer,((PWAVEHDR)wParam)->lpData,dwBytesRecorded);

//Writethememorydatatothefile
DWORDdwBytesWritten;
if(WriteFile(m_hSaveFile,pSaveBuffer,dwBytesRecorded,&dwBytesWritten,NULL)!=TRUE)

...{
if(m_bRecording==TRUE)

...{
waveInClose(m_hWaveIn);
}
}

m_dwDataLength+=dwBytesWritten;

free(pSaveBuffer);

//Ifm_bRecordingisFALSE,itmaycallthefunctionwaveInReset().Sodon'taddbuffer.
if(m_bRecording==TRUE)

...{
//Sendoutanewbuffer.Thenewbufferistheoriginalfullbuffer,usedagain.
waveInAddBuffer(m_hWaveIn,(PWAVEHDR)wParam,sizeof(WAVEHDR));
}
}

//----------------------------------------------------------------------
//Decription:
//OnWIM_OPEN
//------------------------------------------------------------------------
voidCSoundBase::OnWIM_OPEN(WPARAMwParam,LPARAMlParam)

...{
m_bRecording=TRUE;
m_dwDataLength=0;
}

