(1)常见的数据类型与数据结构:
HWAVEIN m_hwavin; //输入设备句柄,在录音时要用
HWAVEOUT m_hwavout; // 输出设备句柄,在回放时要用
WAVEFORMATEX m_waveform; //设置采集的声音格式
WAVEHDR m_wavehdr; //音频数据块缓存结构
音频数据块缓存结构WAVEHDR 其声明如下: type struct{ LPSTR lpData; //指向锁定的数据缓冲区的指针 DWORD dwBufferLength; //数据缓冲区的大小 DWORD dwByteRecorded; //录音时指明缓冲区中的数据量,
When the header is used in input, this member specifies how much data is in the buffer. DWORD dwUser; //用户数据 DWORD dwFlag; //提供缓冲区信息的标志 DWORD dwLoops; //循环播放的次数 struct wavehdr_tag *lpNext; //保留 DWORD reserved; //保留 } WAVEHDR;
这个结构体的应用:
首先申请一段内存: char m_cbBuffer1[INP_BUFFER_SIZE]; //声音临时缓存1
m_wavehdr.lpData=(LPTSTR)m_cbBuffer1;
m_wavehdr.dwBufferLength=INP_BUFFER_SIZE;
m_wavehdr.dwBytesRecorded = 0; m_wavehdr.dwUser=0; m_wavehdr.dwFlags=0; m_wavehdr.dwLoops=1; m_wavehdr.lpNext=NULL; m_wavehdr.reserved=0 ;
//设置缓冲区
waveInPrepareHeader(&m_hwavin,&m_wavehdr,sizeof(WAVEHDR));
waveInAddBuffer(&m_hwavin,&m_wavehdr,sizeof(WAVEHDR));
//开始录音
waveStart(&m_hwavin);
(2) 处理几个消息的函数
第一:MM_WOM_CLOSE消息处理函数 //LRESULT通常是用来作为消息处理函数的返回值的
LRESULT CWaveRecordDlg::OnMM_WIM_CLOSE(UINT wParam, LONG lParam) { waveInUnprepareHeader(m_hWaveIn, &m_WAVEHDR1, sizeof (WAVEHDR)) ; waveInUnprepareHeader(m_hWaveIn, &m_WAVEHDR2, sizeof (WAVEHDR)) ; return NULL; }
DWORD m_dwDataLength; //数据长度 PBYTE m_pSaveBuffer; //音频存储内存
第二:MM_WIM_DATA消息处理函数
LRESULT CWaveRecordDlg::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));
//The waveInAddBuffer function sends an input buffer to the given waveform-audio input device. When the buffer is filled, the application is notified.
return NULL;
}
(3) wav 文件的回放
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; }
LRESULT CWaveRecordDlg::OnMM_WON_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;}
LRESULT CWaveRecordDlg::OnMM_WOM_DONE(UINT wParam,LONG lParam){ PWAVEHDR pWaveHdr = (PWAVEHDR)lParam;
waveOutUnprepareHeader (m_hWaveOut, pWaveHdr, sizeof (WAVEHDR)) ; waveOutClose (m_hWaveOut);
return NULL;}
LRESULT CWaveRecordDlg::OnMM_WOM_CLOSE(UINT wParam,LONG lParam){ m_nRecordState = RECORD_STATE_STOP; SetButtonState(); return NULL;}
(4)wav文件格式
表 .WAV档案格式
偏移量 位元组 资料00004「RIFF」00044波形块的大小(档案大小减8)00084「WAVE」000C4「fmt 」00104格式块的大小(16位元组)00142wf.wFormatTag = WAVE_FORMAT_PCM = 100162wf.nChannels00184wf.nSamplesPerSec001C4wf.nAvgBytesPerSec00202wf.nBlockAlign00222wf.wBitsPerSample00244「data」00284波形资料的大小002C 波形资料
(5)wav文件的保存
第一:读wav头文件信息
#define WAVE_HEADER_SIZE 44
int CWaveRecordDlg::read_wav_head(WAVEFORMATEX *wf,char **out_buffer,int *out_len,char *in_buffer,int in_len){ char *lp_pos; int itmp; lp_pos = in_buffer; if(in_buffer == NULL || in_len == 0 || in_len < WAVE_HEADER_SIZE || wf==NULL) return 1;
if(strncmp(lp_pos,"RIFF",4)!=0) return -1; lp_pos += 4;
itmp = *((int*)lp_pos); if(itmp != (in_len-8)) return -1; lp_pos += 4;
if(strncmp(lp_pos,"WAVEfmt ",8)!=0) return -1; lp_pos += 8;
itmp = *((int*)lp_pos); if(itmp != 16) return -1; lp_pos += 4;
/**//*格式信息*/ memcpy(wf,lp_pos,16); lp_pos += 16;
if(strncmp(lp_pos,"data",4)!=0) return -1; lp_pos += 4;
//真正的数据长度 *out_len = *((int*)lp_pos); lp_pos += 4;
if(*out_len != (in_len - WAVE_HEADER_SIZE)) return 1;
*out_buffer = (char*)malloc(*out_len); if(*out_buffer == NULL) return -2;
memcpy(*out_buffer,lp_pos,*out_len); return 0;}
第二:写wav头文件函数
int CWaveRecordDlg::write_wav_head(WAVEFORMATEX *wf,char *in_buffer,int in_len,char **out_buffer, int *out_len){
char *buffer; int *int_tmp,pos=0;
*out_len = WAVE_HEADER_SIZE + in_len; buffer = (char*)malloc(*out_len); if(buffer == NULL) return -1; memcpy(buffer,"RIFF",4); pos = 4;
int_tmp = (int*)(buffer+pos); *int_tmp = WAVE_HEADER_SIZE + in_len - 8;/**//*波形块的大小(档案大小减8)*/ pos += 4;
memcpy(buffer+pos,"WAVEfmt ",8); pos += 8;
int_tmp = (int*)(buffer+pos); *int_tmp = 16; pos += 4;
/**//*格式信息*/ memcpy(buffer+pos,wf,16); pos += 16;
memcpy(buffer+pos,"data",4); pos += 4;
int_tmp = (int*)(buffer+pos); *int_tmp = in_len; pos += 4;
memcpy(buffer+pos,in_buffer,in_len);
*out_buffer = buffer;
return 0;}