VC录音机程序开发过程

本文详细介绍了在Windows环境下使用WAVEIN和WAVEOUT API进行音频录音和回放的步骤。通过创建输入和输出设备句柄,设置声音格式,使用WAVEHDR结构体管理缓冲区,并处理MM_WIM_DATA等关键消息,实现音频数据的捕获和存储。此外,还涉及到wav文件格式的理解和文件操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(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 = 1
00162wf.nChannels
00184wf.nSamplesPerSec
001C4wf.nAvgBytesPerSec
00202wf.nBlockAlign
00222wf.wBitsPerSample
00244「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;
}

 

 

 

 

 


          

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值