在 2440 win-ce5.0 下实现,录音、播放录音
一、要用到得数据结构
1 、
        typedef struct tWAVEFORMATEX
{
     WORD         wFormatTag;          // format type 
     WORD         nChannels;           // number of channels (i.e. mono, stereo...) 
     DWORD        nSamplesPerSec;      // sample rate 
     DWORD        nAvgBytesPerSec;     // for buffer estimation
     WORD         nBlockAlign;         /* block size of data 
     WORD         wBitsPerSample;      // number of bits per sample of mono data 
     WORD         cbSize;              // the count in bytes of the size of 
                      /* extra information (after cbSize) 
} WAVEFORMATEX, *PWAVEFORMATEX, NEAR *NPWAVEFORMATEX, FAR *LPWAVEFORMATEX;
参数说明:
wFormatTag 是音频格式类型
nChannels 是声道数
nSamplesPerSec 是采样频率
nAvgBytesPerSec 是每秒钟的字节数
nBlockAlign 是每个样本的 字节数
wBitsPerSample 是每个样本的量化位数
cbSize 是附加信息的字节大小。
2 、
wave data block header 
typedef struct wavehdr_tag {
     LPSTR        lpData;                  // pointer to locked data buffer
     DWORD        dwBufferLength;          // length of data buffer 
     DWORD        dwBytesRecorded;         // used for input only 
     DWORD        dwUser;                  // for client's use 
     DWORD        dwFlags;                 // assorted flags (see defines) 
     DWORD        dwLoops;                 // loop control counter 
     struct wavehdr_tag FAR *lpNext;      // reserved for driver 
     DWORD        reserved;                // reserved for driver 
} WAVEHDR, *PWAVEHDR, NEAR *NPWAVEHDR, FAR *LPWAVEHDR;
参数说明:
lpData 是指定的缓冲块地址
dwBufferLength 是指定的缓冲块大小
dwBytesRecorded 是已录音数据大小
dwUser 是用户数据
dwFlags 是控制标志表明缓冲的使用状态
dwLoops 是音频输出时缓冲数据块循环的次数
lpNext 是系统保留数据
reserved 是系统保留数据
 
 
二、基本操作流程:
 
 1、  
 录音流程 
(1)        
 打开录音设备:  waveInOpen
(2)        
 为录音设备准备缓存:  waveInPrepareHeader
(3)        
 为输入设备增加缓存: waveInAddBuffer
(4)        
 启动录音:  waveInStart
(5)        
 清除缓存:  waveInUnprepareHeader
(6)        
 停止录音:  waveInReset
(7)        
 关闭录音设备:  waveInClose
 
 
 2、  
 声音输出流程 
(1)  打开输出设备:  waveOutOpen
(2)  为输出设备准备缓存:  waveOutPrepareHeader
(3)  写数据导输出设备缓存:  waveOutWrite
(4)  清除输出缓存:  waveOutUnprepareHeader
(5)  停止输出:  waveOutReset
(6)  关闭输出设备:  waveOutClose
 
三、消息及处理
在录音,声音输出过程中,会产生很多 WM_WIM_*** 格式的 WINDOWS 消息。程序通过捕获   这些消息对缓存,数据和设备进行处理
1、  
 录音过程消息
(1)        
 WM_WIM_OPEN    音频输入   设备打开消息
(2)        
 WM_WIM_DATA      缓冲录满或停止录音消息
(3)        
 WM_WIM_CLOSE  音频输入   设备关闭消息
2、   
 播放过程消息
(1)        
 WM_WOM_OPEN  音频输出 设备打开消息
(2)        
 WM_WOM_DONE 缓冲播放完或停止输出消息
(3)        
 WM_WOM_CLOSE 音频输出 设备关闭消息
 
四、程序设计
 
1 、开始录音
void CRecorderDlg::OnRecStart() 
{
        // TODO: Add your control notification handler code here
 
        m_pBuffer1=(PBYTE)malloc(INP_BUFFER_SIZE);
        m_pBuffer2=(PBYTE)malloc(INP_BUFFER_SIZE);
        if (!m_pBuffer1 || !m_pBuffer2) {// 判断是否为空
               if (m_pBuffer1) free(m_pBuffer1);//
               if (m_pBuffer2) free(m_pBuffer2);
               MessageBeep(MB_ICONEXCLAMATION);// 发出声音
               AfxMessageBox((CString)"Memory error!");
               return ;
        }
        
        MessageBeep(MB_OK);
 
// WAVEFORMATEX 结构体,声音在采集(录音)和播放的时需要有一些统一的格式,包括音频格式类型,声道,采样率等信息
        //open waveform audo for input
        m_waveform.wFormatTag=WAVE_FORMAT_PCM;//PCM 脉冲编码调制(指定格式类型 ;  默认  WAVE_FORMAT_PCM = 1 )
        m_waveform.nChannels=1;// 单声道
        m_waveform.nSamplesPerSec=11025;11.025kHz (抽样率)
        m_waveform.nAvgBytesPerSec=11025;// 指定数据传输的传输速率 ( 每秒的字节数
        m_waveform.nBlockAlign=1;// 指定块对齐 ( 每个样本的字节数 ),  块对齐是数据的最小单位 }
        m_waveform.wBitsPerSample=8;//8 bit (抽样编码比特数)采样大小 ( 字节 ),  每个样本的量化位数
        m_waveform.cbSize=0;//{ 附加信息的字节大小 }
 
MMRESULT WINAPI waveInOpen(LPHWAVEIN phwi,
  UINT uDeviceID,
LPCWAVEFORMATEX pwfx, 
DWORD dwCallback, 
DWORD dwInstance, 
DWORD fdwOpen);
参数说明:
LPHWAVEIN phwi 用于返回设备句柄的指针
UINT uDeviceID  设备 ID
LPCWAVEFORMATEX pwfx      TWaveFormat  结构的指针
DWORD dwCallback 回调函数地址或窗口句柄
DWORD dwInstance 给回调函数的实例数据、
DWORD fdwOpen 打开选项
 
waveInOpen 打开波形输入设备
               free(m_pBuffer1);
               free(m_pBuffer2);
               MessageBeep(MB_ICONEXCLAMATION);
               AfxMessageBox((CString)"Audio can not be open!");
        }
 
// WAVEHDR 结构体,结构包含了音频数据缓冲的地址,大小,已录音数据大小等信息和其他各种控制标志
        m_pWaveHdr1->lpData=(LPSTR)m_pBuffer1;// 指定缓冲的地址
        m_pWaveHdr1->dwBufferLength=INP_BUFFER_SIZE;// 指定缓冲的大小 ;
        m_pWaveHdr1->dwBytesRecorded=0;// 若  TWaveHdr  用于输入 ,  指出缓冲区中的数据量
        m_pWaveHdr1->dwUser=0;// 指定用户的 32 位数据
        m_pWaveHdr1->dwFlags=0;// 缓冲区标志
        m_pWaveHdr1->dwLoops=1;// 循环播放次数 ,  仅用于输出缓冲区
        m_pWaveHdr1->lpNext=NULL;// 保留
        m_pWaveHdr1->reserved=0;// 保留
waveInPrepareHeader 为录音设备准备缓存
 
        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_pSaveBuffer = (PBYTE)realloc (m_pSaveBuffer, 1) ;
 
        // Add the buffers
waveInAddBuffer 为输入设备增加缓存
waveInAddBuffer
        
        // Begin sampling
        
        m_bRecording = TRUE ;
        m_bEnding = FALSE ;
        m_dwDataLength = 0 ;
waveInStart 启动录音
}
2 、停止录音
void CRecorderDlg::OnRecStop() 
{
        // TODO: Add your control notification handler code here
        m_bEnding=TRUE;
waveInReset 停止录音
waveInClose 关闭录音设备
}
3 、开始播放
void CRecorderDlg::OnPlayStart() 
{
        // TODO: Add your control notification handler code here
               if (m_bPlaying) 
        {
               waveOutReset(m_hWaveOut);
        }
// WAVEFORMATEX 结构体               
        //open waveform audio for output
        m_waveform.wFormatTag            =      WAVE_FORMAT_PCM;
        m_waveform.nChannels         =      1;
        m_waveform.nSamplesPerSec       =11025;
        m_waveform.nAvgBytesPerSec=11025;
        m_waveform.nBlockAlign      =1;
        m_waveform.wBitsPerSample       =8;
        m_waveform.cbSize                     =0;
 
waveOutOpen 打开输出设备
               MessageBeep(MB_ICONEXCLAMATION);
               AfxMessageBox((CString)"Audio output error");
               return;
        }
 
        m_bEnding = FALSE ;
        m_bPlaying=TRUE;
}
4 、停止播放
void CRecorderDlg::OnPlayStop() 
{
        // TODO: Add your control notification handler code here
        m_bPlaying=FALSE;
waveOutReset 停止输出
waveOutClose 关闭输出设备
}
5 、消息函数
        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_CLOSE,OnMM_WOM_CLOSE)
        ON_MESSAGE(MM_WOM_DONE,OnMM_WOM_DONE)
 
// 缓冲录满或停止录音消息
void CRecorderDlg::OnMM_WIM_DATA
{
        // TODO: Add your message handler code here and/or call default
        // Reallocate save buffer memory
        MessageBeep(MB_OK);
               
        m_pNewBuffer = (PBYTE)realloc (m_pSaveBuffer, m_dwDataLength +
               ((PWAVEHDR) lParam)->dwBytesRecorded) ;
 
 
        if (m_pNewBuffer == NULL)
        {
               waveInClose (m_hWaveIn) ;
               MessageBeep (MB_ICONEXCLAMATION) ;
               AfxMessageBox((CString)"error memory");
               return ;
        }
 
        
        m_pSaveBuffer = m_pNewBuffer ;
               
        CopyMemory (m_pSaveBuffer + m_dwDataLength, ((PWAVEHDR) lParam)->lpData,
               ((PWAVEHDR) lParam)->dwBytesRecorded) ;
        
        m_dwDataLength += ((PWAVEHDR) lParam)->dwBytesRecorded ;
        
        if (m_bEnding)
        {
               waveInClose (m_hWaveIn) ;
               return ;
        }
 
        
        // Send out a new buffer
        
        waveInAddBuffer (m_hWaveIn, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ;// 向波形输入设备添加一个输入缓冲区
        return ;
}
// 音频输入设备关闭消息
void CRecorderDlg::OnMM_WIM_CLOSE
{
        // TODO: Add your message handler code here and/or call default
 
        if (0==m_dwDataLength) {
               return;
        }
                waveInUnprepareHeader (m_hWaveIn, m_pWaveHdr1, sizeof (WAVEHDR)) ;// 清除输出缓存
        waveInUnprepareHeader (m_hWaveIn, m_pWaveHdr2, sizeof (WAVEHDR)) ;
        
        free (m_pBuffer1) ;
        free (m_pBuffer2) ;
        
        if (m_dwDataLength > 0)
        {
               //enable play
 
        }
        m_bRecording = FALSE ;
 
}
 
// 音频输出 设备打开消息
void CRecorderDlg::OnMM_WOM_OPEN
{
 
        AfxMessageBox((CString)"OnMM_WOM_OPEN called!");
        m_pWaveHdr1->lpData           = (LPSTR)m_pSaveBuffer ;
        m_pWaveHdr1->dwBufferLength   = m_dwDataLength ;
        m_pWaveHdr1->dwBytesRecorded = 0 ;
        m_pWaveHdr1->dwUser           = 0 ;
        m_pWaveHdr1->dwFlags          = WHDR_BEGINLOOP | WHDR_ENDLOOP ;
        m_pWaveHdr1->dwLoops          = m_dwRepetitions ;
        m_pWaveHdr1->lpNext           = NULL ;
        m_pWaveHdr1->reserved         = 0 ;
 
        // Prepare and write
        
        waveOutPrepareHeader (m_hWaveOut, m_pWaveHdr1, sizeof (WAVEHDR)) ;// 为输出设备准备缓存
        waveOutWrite (m_hWaveOut, m_pWaveHdr1, sizeof (WAVEHDR)) ;// 写数据导输出设备缓存
        
}
// 音频输出设备关闭消息
void CRecorderDlg::OnMM_WOM_CLOSE
{
        AfxMessageBox((CString)"OnMM_WOM_CLOSE called!");
}
 
// 缓冲播放完或停止输出消息
void CRecorderDlg::OnMM_WOM_DONE
{
        AfxMessageBox((CString)"OnMM_WOM_DONE called!");
 
 
}
五、音频 API
waveInGetNumDevs  返回系统中存在的波形输入设备的数量
  waveInAddBuffer  向波形输入设备添加一个输入缓冲区
waveInGetDevCaps  查询指定的波形输入设备以确定其性能
  waveInGetErrorText  检取由指定的错误代码标识的文本说明
waveInGetID  获取指定的波形输入设备的标识符
  waveInGetPosition  检取指定波形输入设备的当前位置
waveInMessage  发送一条消息给波形输入设备的驱动器
waveInOpen  为录音而打开一个波形输入设备
waveInPrepareHeader  为波形输入准备一个输入缓冲区
waveInStart  启动在指定的波形输入设备的输入
waveInReset  停止给定的波形输入设备的输入,且将当前位置清零
  waveInStop  停止在指定的波形输入设备上的输入
waveInUnprepareHeader  清除由 waveInPrepareHeader 函数实现的准备
  WaveInClose  关闭指定的波形输入设置
waveOutBreakLoop  中断给定的波形输出设备上一个循环,并允许播放驱动取列表中的下一个块
waveOutClose  关闭指定的波形输出设备
waveOutGetDevCaps  查询一个指定的波形输出设备以确定其性能  waveOutGetErrorText  检取由指定的错误代码标识的文本说明
waveOutGetID  检取指定的波形输出设备的标识符
waveOutGetNumDevs  检取系统中存在的波形输出设备的数量
waveOutGetPitch  查询一个波形输出设备的当前音调设置
waveOutGetPlaybackRate  查询一个波形输出设备当前播放的速度
waveOutGetPosition  检取指定波形输出设备的当前播放位置
waveOutGetVolume  查询指定波形输出设备的当前音量设置
  waveOutMessage  发送一条消息给一个波形输出设备的驱动器
waveOutOpen  为播放打开一个波形输出设备
  waveOutPause  暂停指定波形输出设备上的播放
waveOutPrepareHeader  为播放准备一个波形缓冲区
waveOutRestart  重新启动一个被暂停的波形输出设备
waveOutSetPitch  设置一个波形输出设备的音调
waveOutSetPlaybackRate  设置指定波形输出设备的速度
waveOutSetVolume  设置指定的波形输出设备的音量
waveOutUnprepareHeader  清除由 waveOutPrepareHeader 函 数实现的准备  
waveOutWrite  向指定的波形输出设备发送一个数据块