(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档案格式 |
偏移量 | 位元组 | 资料 |
---|---|---|
0000 | 4 | 「RIFF」 |
0004 | 4 | 波形块的大小(档案大小减8) |
0008 | 4 | 「WAVE」 |
000C | 4 | 「fmt 」 |
0010 | 4 | 格式块的大小(16位元组) |
0014 | 2 | wf.wFormatTag = WAVE_FORMAT_PCM = 1 |
0016 | 2 | wf.nChannels |
0018 | 4 | wf.nSamplesPerSec |
001C | 4 | wf.nAvgBytesPerSec |
0020 | 2 | wf.nBlockAlign |
0022 | 2 | wf.wBitsPerSample |
0024 | 4 | 「data」 |
0028 | 4 | 波形资料的大小 |
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;
}