windows 程序设计之「RECORD1.C」范例分析笔记

/*----------------------------------------

   RECORD1.C -- Waveform Audio Recorder

                (c) Charles Petzold, 1998

  ----------------------------------------*/

 

#include <windows.h>

#include "resource.h"

 

#define INP_BUFFER_SIZE 16384

 

BOOL CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM) ;

 

TCHAR szAppName [] = TEXT ("Record1") ;

 

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,

                    PSTR szCmdLine, int iCmdShow)

{

     if (-1 == DialogBox (hInstance, TEXT ("Record"), NULL, DlgProc))

     {

          MessageBox (NULL, TEXT ("This program requires Windows NT!"),

                      szAppName, MB_ICONERROR) ;

     }

     return 0 ;

}

 

void ReverseMemory (BYTE * pBuffer, int iLength)

{

     BYTE b ;

     int  i ;

    

     for (i = 0 ; i < iLength / 2 ; i++)

     {

          b = pBuffer [i] ;

          pBuffer [i] = pBuffer [iLength - i - 1] ;

          pBuffer [iLength - i - 1] = b ;

     }

}

 

BOOL CALLBACK DlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

{

     static BOOL         bRecording, bPlaying, bReverse, bPaused,

                         bEnding, bTerminating ;

     static DWORD        dwDataLength, dwRepetitions = 1 ;

     static HWAVEIN      hWaveIn ;

     static HWAVEOUT     hWaveOut ;

     static PBYTE        pBuffer1, pBuffer2, pSaveBuffer, pNewBuffer ;

     static PWAVEHDR     pWaveHdr1, pWaveHdr2 ;

     static TCHAR        szOpenError[] = TEXT ("Error opening waveform audio!");

     static TCHAR        szMemError [] = TEXT ("Error allocating memory!") ;

     static WAVEFORMATEX waveform ;

    

     switch (message)

     {

     case WM_INITDIALOG:

 

         // 波形文件数据头内存分配

          pWaveHdr1 = malloc (sizeof (WAVEHDR)) ;

          pWaveHdr2 = malloc (sizeof (WAVEHDR)) ;

         

         // 保存缓冲区分配内存

          pSaveBuffer = malloc (1) ;

          return TRUE ;

         

     case WM_COMMAND:

          switch (LOWORD (wParam))

          {

          case IDC_RECORD_BEG: // 按下录音按钮

               // 分配缓冲存储器

               pBuffer1 = malloc (INP_BUFFER_SIZE) ;

               pBuffer2 = malloc (INP_BUFFER_SIZE) ;

              

               if (!pBuffer1 || !pBuffer2)

               {

                    if (pBuffer1) free (pBuffer1) ;

                    if (pBuffer2) free (pBuffer2) ;

 

                    MessageBeep (MB_ICONEXCLAMATION) ;

                    MessageBox (hwnd, szMemError, szAppName,

                                      MB_ICONEXCLAMATION | MB_OK) ;

                    return TRUE ;

               }

              

               // 定义波形音频数据格式

               // 波形音频格式类型 WAVE_FORMAT_PCM 一个或两个通道的PCM数据

               waveform.wFormatTag      = WAVE_FORMAT_PCM ;

               // 波形音频数据通道,单声道的数据使用一个通道

               waveform.nChannels       = 1 ;

               // 采样率

               waveform.nSamplesPerSec  = 11025 ;

               // 所需的平均数据传输速率

               waveform.nAvgBytesPerSec = 11025 ;

               /* 对于PCM取样方式,nBlockAlign字段设定为nChannels乘以wBitsPerSample再除以8所得到的数值,

                  它表示每次取样的总字节数*/

               waveform.nBlockAlign     = 1 ;

               // 每个样本占位大小 = 8 16

               waveform.wBitsPerSample  = 8 ;

               // 用于非PCM格式的额外信息

               waveform.cbSize          = 0 ;

               // 打开特定的波形记录音频输入设备

               if (waveInOpen (&hWaveIn, WAVE_MAPPER, &waveform,

                               (DWORD) hwnd, 0, CALLBACK_WINDOW))

               {

                    free (pBuffer1) ;

                    free (pBuffer2) ;

                    MessageBeep (MB_ICONEXCLAMATION) ;

                    MessageBox (hwnd, szOpenError, szAppName,

                                      MB_ICONEXCLAMATION | MB_OK) ;

               }

 

               // 初始化一个准备数据标头

               pWaveHdr1->lpData          = pBuffer1 ;

               pWaveHdr1->dwBufferLength  = INP_BUFFER_SIZE ;

               pWaveHdr1->dwBytesRecorded = 0 ;

               pWaveHdr1->dwUser          = 0 ;

               pWaveHdr1->dwFlags         = 0 ;

               pWaveHdr1->dwLoops         = 1 ;

               pWaveHdr1->lpNext          = NULL ;

               pWaveHdr1->reserved        = 0 ;

               // 让系统准备一个波形音频输入缓冲区

               waveInPrepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;

         

               pWaveHdr2->lpData          = pBuffer2 ;

               pWaveHdr2->dwBufferLength  = INP_BUFFER_SIZE ;

               pWaveHdr2->dwBytesRecorded = 0 ;

               pWaveHdr2->dwUser          = 0 ;

               pWaveHdr2->dwFlags         = 0 ;

               pWaveHdr2->dwLoops         = 1 ;

               pWaveHdr2->lpNext          = NULL ;

               pWaveHdr2->reserved        = 0 ;

         

               waveInPrepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;

               return TRUE ;

              

          case IDC_RECORD_END:

               bEnding = TRUE ;

               /*停止在给定的波形音频输入设备的输入和复位当前句柄为NULL

                 所有等待的缓冲区标记为已完成并返回给应用程序。*/

               waveInReset (hWaveIn) ;

               return TRUE ;

              

          case IDC_PLAY_BEG:

              

               waveform.wFormatTag      = WAVE_FORMAT_PCM ;

               waveform.nChannels       = 1 ;

               waveform.nSamplesPerSec  = 11025 ;

               waveform.nAvgBytesPerSec = 11025 ;

               waveform.nBlockAlign     = 1 ;

               waveform.wBitsPerSample  = 8 ;

               waveform.cbSize          = 0 ;

               // 打开一个波形输出设备,发送MM_WOM_OPEN消息

               if (waveOutOpen (&hWaveOut, WAVE_MAPPER, &waveform,

                                (DWORD) hwnd, 0, CALLBACK_WINDOW))

               {

                    MessageBeep (MB_ICONEXCLAMATION) ;

                    MessageBox (hwnd, szOpenError, szAppName,

                         MB_ICONEXCLAMATION | MB_OK) ;

               }

               return TRUE ;

              

          case IDC_PLAY_PAUSE:

                    // 暂停或重新开始输出

               if (!bPaused)

               {

                   // 暂停波形音频输出设备

                    waveOutPause (hWaveOut) ;

                    // 更改按钮文字

                    SetDlgItemText (hwnd, IDC_PLAY_PAUSE, TEXT ("Resume")) ;

                    bPaused = TRUE ;

               }

               else

               {

                   // 恢复暂停播放的波形音频输出设备

                    waveOutRestart (hWaveOut) ;

                    SetDlgItemText (hwnd, IDC_PLAY_PAUSE, TEXT ("Pause")) ;

                    bPaused = FALSE ;

               }

               return TRUE ;

              

          case IDC_PLAY_END:

                    // Reset output for close preparation

              

               bEnding = TRUE ;

               // 停止波形音频输出设备上的播放并重置当前句柄为NULL,发送MM_WOM_DONE消息

               waveOutReset (hWaveOut) ;

               return TRUE ;

              

          case IDC_PLAY_REV:

 

               bReverse = TRUE ;

               // 将缓冲区数据反向

               ReverseMemory (pSaveBuffer, dwDataLength) ;

               // 发送播放按钮点击消息

               SendMessage (hwnd, WM_COMMAND, IDC_PLAY_BEG, 0) ;

               return TRUE ;

              

          case IDC_PLAY_REP:

              // 设置循环次数为无限,发送播放按钮点击消息

               dwRepetitions = -1 ;

               SendMessage (hwnd, WM_COMMAND, IDC_PLAY_BEG, 0) ;

               return TRUE ;

              

          case IDC_PLAY_SPEED:

 

              // 将采样率提高一倍,加快音频播放速度

               waveform.wFormatTag      = WAVE_FORMAT_PCM ;

               waveform.nChannels       = 1 ;

               waveform.nSamplesPerSec  = 22050 ;

               waveform.nAvgBytesPerSec = 22050 ;

               waveform.nBlockAlign     = 1 ;

               waveform.wBitsPerSample  = 8 ;

               waveform.cbSize          = 0 ;

              

               if (waveOutOpen (&hWaveOut, 0, &waveform, (DWORD) hwnd, 0,

                                           CALLBACK_WINDOW))

               {

                    MessageBeep (MB_ICONEXCLAMATION) ;

                    MessageBox (hwnd, szOpenError, szAppName,

                                      MB_ICONEXCLAMATION | MB_OK) ;

               }

               return TRUE ;

          }

          break ;

 

          // 消息由waveInOpen调用发出

     case MM_WIM_OPEN:

          // 改变内存大小到1字节,自动释放先前内存空间

          pSaveBuffer = realloc (pSaveBuffer, 1) ;

         

         // 启用和禁用按钮

          EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), TRUE)  ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG),   FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END),   FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV),   FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP),   FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), FALSE) ;

          SetFocus (GetDlgItem (hwnd, IDC_RECORD_END)) ;

 

          // 向波形音频输入设备发送一个给定的输入缓冲区,用于记录输入的波形

          waveInAddBuffer (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;

          waveInAddBuffer (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;

          

          bRecording = TRUE ;

          bEnding = FALSE ;

          dwDataLength = 0 ;

          // 启动波形输入设备,开始采样

          waveInStart (hWaveIn) ;

          return TRUE ;

         

          // 消息由用于采样的缓冲区填满或调用waveInReset发出

     case MM_WIM_DATA:

         

         // 增加pSaveBuffer内存大小

          pNewBuffer = realloc (pSaveBuffer, dwDataLength +

                        // 返回的WAVEHD结构中的dwBytesRecorded字段记录了录入的数据大小

                                   ((PWAVEHDR) lParam)->dwBytesRecorded) ;

         

          if (pNewBuffer == NULL)

          {

               waveInClose (hWaveIn) ;

               MessageBeep (MB_ICONEXCLAMATION) ;

               MessageBox (hwnd, szMemError, szAppName,

                                 MB_ICONEXCLAMATION | MB_OK) ;

               return TRUE ;

          }

         

          pSaveBuffer = pNewBuffer ;

          // 复制录入的数据到新增加的内存中

          CopyMemory (pSaveBuffer + dwDataLength, ((PWAVEHDR) lParam)->lpData,

                         ((PWAVEHDR) lParam)->dwBytesRecorded) ;

 

          // 累加录入数据长度

          dwDataLength += ((PWAVEHDR) lParam)->dwBytesRecorded ;

 

          // 判断消息是否由调用waveInReset发出

          if (bEnding)

          {

               waveInClose (hWaveIn) ;

               return TRUE ;

          }

         

          // 继续录入

          waveInAddBuffer (hWaveIn, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ;

          return TRUE ;

 

          // 消息由waveInClose调用发出

     case MM_WIM_CLOSE:

 

         // 释放数据

          waveInUnprepareHeader (hWaveIn, pWaveHdr1, sizeof (WAVEHDR)) ;

          waveInUnprepareHeader (hWaveIn, pWaveHdr2, sizeof (WAVEHDR)) ;

 

          free (pBuffer1) ;

          free (pBuffer2) ;

 

          // 启用和禁用按钮,设置焦点

          EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), TRUE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE) ;

          SetFocus (GetDlgItem (hwnd, IDC_RECORD_BEG)) ;

         

          // 做数据有效性检查,并设置播放按钮

          if (dwDataLength > 0)

          {

               EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG),   TRUE)  ;

               EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE) ;

               EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END),   FALSE) ;

               EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP),   TRUE)  ;

               EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV),   TRUE)  ;

               EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), TRUE)  ;

               SetFocus (GetDlgItem (hwnd, IDC_PLAY_BEG)) ;

          }

          // 设置录音标记

          bRecording = FALSE ;

 

          // 判断当前窗口是否要关闭

          if (bTerminating)

               SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;

         

          return TRUE ;

         

     case MM_WOM_OPEN:

          // 启用和禁用按钮

          EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG),   FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), TRUE)  ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END),   TRUE)  ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP),   FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV),   FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), FALSE) ;

          SetFocus (GetDlgItem (hwnd, IDC_PLAY_END)) ;

         

          // 设置波形数据头

          pWaveHdr1->lpData          = pSaveBuffer ;

          pWaveHdr1->dwBufferLength  = dwDataLength ;

          pWaveHdr1->dwBytesRecorded = 0 ;

          pWaveHdr1->dwUser          = 0 ;

          // WHDR_BEGINLOOP 缓冲区是一个循环的第一个缓冲区

          // WHDR_ENDLOOP   缓冲区是一个循环的最后一个缓冲区

          pWaveHdr1->dwFlags         = WHDR_BEGINLOOP | WHDR_ENDLOOP ;

          pWaveHdr1->dwLoops         = dwRepetitions ;

          pWaveHdr1->lpNext          = NULL ;

          pWaveHdr1->reserved        = 0 ;

         

          // 准备数据

          waveOutPrepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;

          // 发送输入给设备

          waveOutWrite (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;

         

          bEnding = FALSE ;

          bPlaying = TRUE ;

          return TRUE ;

 

          // 停止播放,或播放完毕时收到此消息

     case MM_WOM_DONE:

         // 清除数据

          waveOutUnprepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;

          // 关闭设备,发送MM_WOM_CLOSE消息

          waveOutClose (hWaveOut) ;

          return TRUE ;

         

     case MM_WOM_CLOSE:

          // 启用和禁用按钮,设置焦点

          EnableWindow (GetDlgItem (hwnd, IDC_RECORD_BEG), TRUE)  ;

          EnableWindow (GetDlgItem (hwnd, IDC_RECORD_END), TRUE)  ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_BEG),   TRUE)  ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_PAUSE), FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_END),   FALSE) ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REV),   TRUE)  ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_REP),   TRUE)  ;

          EnableWindow (GetDlgItem (hwnd, IDC_PLAY_SPEED), TRUE)  ;

          SetFocus (GetDlgItem (hwnd, IDC_PLAY_BEG)) ;

         

          SetDlgItemText (hwnd, IDC_PLAY_PAUSE, TEXT ("Pause")) ;

          bPaused = FALSE ;

          dwRepetitions = 1 ;

          bPlaying = FALSE ;

          // 如果点击了反向播放,则重置波形数据

          if (bReverse)

          {

               ReverseMemory (pSaveBuffer, dwDataLength) ;

               bReverse = FALSE ;

          }

         

          if (bTerminating)

               SendMessage (hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L) ;

         

          return TRUE ;

         

     case WM_SYSCOMMAND:

          switch (LOWORD (wParam))

          {

          case SC_CLOSE:

              // 必须要先停止设备,才能正常关闭设备

               if (bRecording)

               {

                    bTerminating = TRUE ;

                    bEnding = TRUE ;

                    waveInReset (hWaveIn) ;

                    return TRUE ;

               }

              

               if (bPlaying)

               {

                    bTerminating = TRUE ;

                    bEnding = TRUE ;

                    waveOutReset (hWaveOut) ;

                    return TRUE ;

               }

              

               free (pWaveHdr1) ;

               free (pWaveHdr2) ;

               free (pSaveBuffer) ;

               EndDialog (hwnd, 0) ;

               return TRUE ;

          }

          break ;

     }

     return FALSE ;

}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值