录制声音一般采用两种机制:
第一种: 直接在UI下采用消息;
第二种: 开辟一个线程单独进行;
下面先介绍第一种如何进行,DEMO是网上的,挺零碎的,我费了点功夫,调试能直接使用的.
<1> : wav族函数进行声音采集和播放时,会以下几个消息:
MM_WIM_OPEN、 MM_WIM_DATA、MM_WIM_CLOSE、MM_WOM_OPEN、MM_WOM_DONE、MM_WOM_CLOSE
所以新建一个MFC工程,并且添加如下三个消息:
MM_WIM_OPEN、 MM_WIM_DATA、MM_WIM_CLOSE
当然也可以将另外三个播放的消息也一并添加.
假设新建了Recorde MFC Dialog工程.
<2> : 添加消息:
// Generated message map functions //{ {AFX_MSG(CRecordeDlg) virtual BOOL OnInitDialog();... afx_msg LRESULT OnMM_WIM_OPEN(UINT wParam,LONG lParam); afx_msg LRESULT OnMM_WIM_DATA(UINT wParam,LONG lParam); afx_msg LRESULT OnMM_WIM_CLOSE(UINT wParam,LONG lParam); afx_msg LRESULT OnMM_WOM_OPEN(UINT wParam,LONG lParam); afx_msg LRESULT OnMM_WOM_DONE(UINT wParam,LONG lParam); afx_msg LRESULT OnMM_WOM_CLOSE(UINT wParam,LONG lParam);... //}}AFX_MSG DECLARE_MESSAGE_MAP()
BEGIN_MESSAGE_MAP(CRecordeDlg, CDialog) //{ {AFX_MSG_MAP(CRecordeDlg)... ON_MESSAGE(MM_WIM_OPEN,OnMM_WIM_OPEN) ON_MESSAGE(MM_WIM_DATA,OnMM_WIM_DATA) ON_MESSAGE(MM_WIM_CLOSE,OnMM_WIM_CLOSE) ON_MESSAGE(MM_WOM_OPEN,OnMM_WOM_OPEN) ON_MESSAGE(MM_WOM_DONE,OnMM_WOM_DONE) ON_MESSAGE(MM_WOM_CLOSE,OnMM_WOM_CLOSE)
...
//}}AFX_MSG_MAPEND_MESSAGE_MAP()
<3> : 添加头文件:
#include<mmsystem.h>#pragma comment(lib, "Winmm.lib")
全局变量:
#define INP_BUFFER_SIZE 2048//该值越大,录取的数据就越多.
#define WAVE_HEADER_SIZE 44
enum et{
RECORD_STATE_INIT, RECORD_STATE_STOP, RECORD_STATE_STOPING, RECORD_STATE_PLAYING, RECORD_STATE_RECING};类中自定义变量:
int m_nRecordState;
DWORD m_dwDataLength; //数据长度
WAVEFORMATEX m_waveform; //声音格式 HWAVEIN m_hWaveIn; //音频输入句柄 HWAVEOUT m_hWaveOut; //音频输出句柄 PBYTE m_pSaveBuffer; //音频存储内存WAVEHDR m_WAVEHDR1;
WAVEHDR m_WAVEHDR2;char m_cbBuffer1[INP_BUFFER_SIZE]; //声音临时缓存1
char m_cbBuffer2[INP_BUFFER_SIZE]; //声音临时缓存2新添加录音button1播放button2按钮.
<4> : 录音按钮如下:
void CRecordeDlg::OnButton1()
{ // TODO: Add your control notification handler code here //打开声音设备 if(waveInOpen(&m_hWaveIn,WAVE_MAPPER,&m_waveform, (DWORD)m_hWnd,NULL,CALLBACK_WINDOW)){ MessageBeep(MB_ICONEXCLAMATION); MessageBox(_T("录制声音失败!"), _T("错误"),MB_ICONEXCLAMATION|MB_OK); return; }//设置缓冲区
m_WAVEHDR1.lpData = (LPTSTR)m_cbBuffer1; m_WAVEHDR1.dwBufferLength = INP_BUFFER_SIZE; m_WAVEHDR1.dwBytesRecorded = 0; m_WAVEHDR1.dwUser=0; m_WAVEHDR1.dwFlags=0; m_WAVEHDR1.dwLoops=1; m_WAVEHDR1.lpNext=NULL; m_WAVEHDR1.reserved=0;m_WAVEHDR2.lpData=(LPTSTR)m_cbBuffer2;
m_WAVEHDR2.dwBufferLength = INP_BUFFER_SIZE; m_WAVEHDR2.dwBytesRecorded = 0; m_WAVEHDR2.dwUser=0; m_WAVEHDR2.dwFlags=0; m_WAVEHDR2.dwLoops=1; m_WAVEHDR2.lpNext=NULL; m_WAVEHDR2.reserved=0;//设置双缓冲
waveInPrepareHeader(m_hWaveIn,&m_WAVEHDR1,sizeof(WAVEHDR)); waveInPrepareHeader(m_hWaveIn,&m_WAVEHDR2,sizeof(WAVEHDR));waveInAddBuffer(m_hWaveIn,&m_WAVEHDR1,sizeof(WAVEHDR));
waveInAddBuffer(m_hWaveIn,&m_WAVEHDR2,sizeof(WAVEHDR));//先随便分配个内存
if(m_pSaveBuffer == NULL){ free(m_pSaveBuffer); m_pSaveBuffer = NULL; } m_pSaveBuffer = (PBYTE)malloc(1); m_dwDataLength = 0;//开始录音
// Begin sampling waveInStart(m_hWaveIn);}
播音按钮如下:
void CRecordeDlg::OnButton2()
{ // TODO: Add your control notification handler code here //打开声音播放句柄 if(waveOutOpen(&m_hWaveOut,WAVE_MAPPER,&m_waveform,(DWORD)m_hWnd, NULL, CALLBACK_WINDOW)){ MessageBeep(MB_ICONEXCLAMATION); MessageBox(_T("录制声音失败!"),_T("错误"),MB_ICONEXCLAMATION|MB_OK); return; }}
<4> :添加响应消息函数(附带了功能代码):
LRESULT CRecordeDlg::OnMM_WIM_CLOSE (UINT wParam,LONG lParam){
waveInUnprepareHeader(m_hWaveIn, &m_WAVEHDR1, sizeof (WAVEHDR)) ;
waveInUnprepareHeader(m_hWaveIn, &m_WAVEHDR2, sizeof (WAVEHDR)) ; m_nRecordState = RECORD_STATE_STOP; //SetButtonState();
return NULL;
}
LRESULT CRecordeDlg::OnMM_WIM_DATA (UINT wParam,LONG lParam){
PWAVEHDR pWaveHdr = (PWAVEHDR)lParam;
if(pWaveHdr->dwBytesRecorded > 0){ m_pSaveBuffer = (PBYTE)realloc(m_pSaveBuffer,m_dwDataLength + pWaveHdr->dwBytesRecorded); if(m_pSaveBuffer == NULL){ waveInClose (m_hWaveIn); MessageBeep (MB_ICONEXCLAMATION) ; AfxMessageBox("erro memory"); return NULL; }
memcpy(m_pSaveBuffer+m_dwDataLength , pWaveHdr->lpData,pWaveHdr->dwBytesRecorded);
m_dwDataLength += pWaveHdr->dwBytesRecorded;
}
if(m_nRecordState == RECORD_STATE_STOPING){
waveInClose(m_hWaveIn); }
waveInAddBuffer(m_hWaveIn, pWaveHdr, sizeof (WAVEHDR));
return NULL;
}
LRESULT CRecordeDlg::OnMM_WIM_OPEN (UINT wParam,LONG lParam){
m_nRecordState = RECORD_STATE_RECING;
//SetButtonState(); return NULL;}
LRESULT CRecordeDlg::OnMM_WOM_CLOSE (UINT wParam,LONG lParam){
m_nRecordState = RECORD_STATE_STOP;
//SetButtonState(); return NULL;}
LRESULT CRecordeDlg::OnMM_WOM_DONE (UINT wParam,LONG lParam){
PWAVEHDR pWaveHdr = (PWAVEHDR)lParam;
waveOutUnprepareHeader (m_hWaveOut, pWaveHdr, sizeof (WAVEHDR)) ; waveOutClose (m_hWaveOut); return NULL;}
LRESULT CRecordeDlg::OnMM_WOM_OPEN (UINT wParam,LONG lParam){
memset(&m_WAVEHDR1,0,sizeof(WAVEHDR));
m_WAVEHDR1.lpData = (char *)m_pSaveBuffer;//指向要播放的内存 m_WAVEHDR1.dwBufferLength = m_dwDataLength;//播放的长度 m_WAVEHDR1.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP; m_WAVEHDR1.dwLoops = 1;
waveOutPrepareHeader(m_hWaveOut,&m_WAVEHDR1,sizeof(WAVEHDR));
waveOutWrite(m_hWaveOut,&m_WAVEHDR1,sizeof(WAVEHDR));
m_nRecordState = RECORD_STATE_PLAYING;
//SetButtonState(); return NULL;}