⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 22. 声音与音乐.txt

📁 本书介绍了在Microsoft Windows 98、Microsoft Windows NT 4.0和Windows NT 5.0下程序写作的方法
💻 TXT
📖 第 1 页 / 共 5 页
字号:

                                                       // Message generated when a buffer is finished
        
                  
        
           case   MM_WOM_DONE:
        
                          if (bShutOff)
        
                          {
        
                                         waveOutClose (hWaveOut) ;
        
                                         return TRUE ;
        
                          }
        

                                         // Fill and send out a new buffer
        

                          FillBuffer (((PWAVEHDR) lParam)->lpData, iFreq) ;
        
                          waveOutWrite (hWaveOut, (PWAVEHDR) lParam, sizeof (WAVEHDR)) ;
        
                          return TRUE ;
        
        
        
           case   MM_WOM_CLOSE:
        
                         waveOutUnprepareHeader (hWaveOut, pWaveHdr1, sizeof (WAVEHDR)) ;
        
                         waveOutUnprepareHeader (hWaveOut, pWaveHdr2, sizeof (WAVEHDR)) ;
        

                          free (pWaveHdr1) ;
        
                          free (pWaveHdr2) ;
        
                          free (pBuffer1) ;
        
                          free (pBuffer2) ;
        

                          hWaveOut = NULL ;
        
                          SetDlgItemText (hwnd, IDC_ONOFF, TEXT ("Turn On")) ;
        
        
        
                          if (bClosing)
        
                                                 EndDialog (hwnd, 0) ;
        
        
        
                          return TRUE ;
        
        
        
           case   WM_SYSCOMMAND:
        
                          switch (wParam)
        
                          {
        
                          case SC_CLOSE:
        
                                                 if (hWaveOut != NULL)
        
                                                {
        
                                                         bShutOff = TRUE ;
        
                                                         bClosing = TRUE ;
        
                  
        
                                                         waveOutReset (hWaveOut) ;
        
                                                 }
        
                                                 else
        
                                                         EndDialog (hwnd, 0) ;
        
             
        
                                                 return TRUE ;
        
                          }
        
                          break ;
        
                  }
        
                  return FALSE ;
        
}
        
SINEWAVE.RC (摘录)
        
//Microsoft Developer Studio generated resource script.
        
#include "resource.h"
        
#include "afxres.h"
        
/////////////////////////////////////////////////////////////////////////////
        
// Dialog
        
SINEWAVE           DIALOG DISCARDABLE  100, 100, 200, 50
        
STYLE                      WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
        
CAPTION            "Sine Wave Generator"
        
FONT 8,            "MS Sans Serif"
        
BEGIN
        
   SCROLLBAR                            IDC_SCROLL,8,8,150,12
        
   RTEXT                                                "440",IDC_TEXT,160,10,20,8
        
   LTEXT                                               "Hz",IDC_STATIC,182,10,12,8
        
   PUSHBUTTON                           "Turn On",IDC_ONOFF,80,28,40,14
        
END
        
RESOURCE.H (摘录)
        
// Microsoft Developer Studio generated include file.
        
// Used by SineWave.rc
        
#define IDC_STATIC                                                                     -1
        
#define IDC_SCROLL                                                               1000
        
#define IDC_TEXT                                                                 1001
        
#define IDC_ONOFF                                                                1002
        
注意,FillBuffer例程中用到的OUT_BUFFER_SIZE、SAMPLE_RATE和PI标识符在程序的顶部定义。FillBuffer的iFreq参数是需要的频率,单位是Hz。还要注意,sin函数的结果调整到了0到254的范围之间。对于每个样本,sin函数的fAngle参数都增加一个值,该值的大小是2π弧度乘以需要的频率再除以取样频率。

SINEWAVE的窗口包含三个控件:一个用于选择频率的水平滚动条,一个用于显示目前所选频率的静态文字区域,以及一个标记为「Turn On」的按钮。按下此按钮后,您将从连结声卡的扩音器中听到正弦波的声音,同时按钮上的文字将变成「Turn Off」。用键盘或者鼠标移动滚动条可以改变频率。要关闭声音,可以再次按下按钮。

SINEWAVE程序代码初始化滚动条,以便频率在WM_INITDIALOG消息处理期间最低是20Hz,最高是5000Hz。初始化时,滚动条设定为440 Hz。用音乐术语来说就是中音上面的A,它在管弦乐队演奏时用来调音。DlgProc在接收WM_HSCROLL消息处理期间改变静态变量iFreq。注意,Page Left和Page Right将导致DlgProc增加或者减少一个八度音阶。

当DlgProc从按钮收到一个WM_COMMAND消息时,它首先配置4个内存块-2个用于WAVEHDR结构,我们马上讨论。另两个用于缓冲区储存波形数据,我们将这两个缓冲区称为pBuffer1和pBuffer2。

通过呼叫waveOutOpen函数,SINEWAVE打开波形声音设备以便输出,waveOutOpen函数使用下面的参数:

waveOutOpen (&hWaveOut, wDeviceID, &waveformat, dwCallBack,
        
                                         dwCallBackData, dwFlags) ;
        
将第一个参数设定为指向HWAVEOUT(handle to waveform audio output:波形声音输出句柄)型态的变量。从函数传回时,此变量将设定为一个句柄,后面的波形输出呼叫中将使用该句柄。

waveOutOpen的第二个参数是设备ID。它允许函数可以在安装多个声卡的机器上使用。参数的范围在0到系统所安装的波形输出设备数之间。呼叫waveOutGetNumDevs可以获得波形输出设备数,而呼叫waveOutGetDevCaps可以找出每个波形输出设备。如果想消除设备问号,那么您可以用常数WAVE_MAPPER(定义为-1)来选择设备,该设备在「控制台」的「多媒体」中「音效」页面卷标里的「喜欢使用的设备」中指定。另外,如果首选设备不能满足您的需要,而其它设备可以,那么系统将选择其它设备。

第三个参数是指向WAVEFORMATEX结构的指针(后面将详细介绍)。第四个参数是窗口句柄或指向动态链接库中callback函数的指标,用来表示接收波形输出消息的窗口或者callback函数。使用callback函数时,可在第五个参数中指定程序定义的数据。dwFlags参数可设为CALLBACK_WINDOW或CALLBACK_FUNCTION,以表示第四个参数的型态。您也可用WAVE_FORMAT_QUERY标记来检查能否打开设备(实际上并不打开它)。还有其它几个标记可用。

waveOutOpen的第三个参数定义为指向WAVEFORMATEX型态结构的指针,此结构在MMSYSTEM.H中定义如下:

typedef struct waveformat_tag
        
{
        
           WORD  wFormatTag ;             // waveform format = WAVE_FORMAT_PCM
        
           WORD  nChannels ;                   // number of channels = 1 or 2
        
          DWORD nSamplesPerSec ;              // sample rate
        
           DWORD nAvgBytesPerSec ;        // bytes per second
        
           WORD  nBlockAlign ;                 // block alignment
        
           WORD  wBitsPerSample ;              // bits per samples = 8 or 16
        
           WORD  cbSize ;                     // 0 for PCM
        
}
        
WAVEFORMATEX, * PWAVEFORMATEX ;
        
您可用此结构指定取样频率(nSamplesPerSec)和取样精确度(nBitsPerSample),以及选择单声道或立体声(nChannels)。结构中有些信息看起来是多余的,但该结构也可用于非PCM的取样方式。在非PCM取样方式下,此结构的最后一个字段设定为非0值,并带有其它信息。

对于PCM取样方式,nBlockAlign字段设定为nChannels乘以wBitsPerSample再除以8所得到的数值,它表示每次取样的总字节数。nAvgBytesPerSec字段设定为nSamplesPerSec和nBlockAlign的乘积。

SINEWAVE初始化WAVEFORMATEX结构的字段,并呼叫waveOutOpen函数:

waveOutOpen (      &hWaveOut, WAVE_MAPPER, &waveformat,
        
                  (DWORD) hwnd, 0, CALLBACK_WINDOW)
        
如果呼叫成功,则waveOutOpen函数传回MMSYSERR_NOERROR(定义为0),否则传回非0的错误代码。如果waveOutOpen的传回值非0,则SINEWAVE清除窗口,并显示一个标识错误的消息框。

现在设备打开了,SINEWAVE继续初始化两个WAVEHDR结构的字段,这两个结构用于在API中传递缓冲。WAVEHDR定义如下:

typedef struct wavehdr_tag
        
{
        
   LPSTR lpData;                                              // pointer to data buffer
        
       DWORD dwBufferLength;                                   // length of data buffer
        
   DWORD dwBytesRecorded;                                     // used for recorded
        
   DWORD dwUser;                                               // for program use
        
   DWORD dwFlags;                                             // flags
        
   DWORD dwLoops;                                              // number of repetitions
        
   struct wavehdr_tag FAR *lpNext;                     // reserved
        
   DWORD reserved;                                             // reserved
        
}
        
WAVEHDR, *PWAVEHDR ;
        
SINEWAVE将lpData字段设定为包含数据的缓冲区地址,dwBufferLength字段设定为此缓冲区的大小,dwLoops字段设定为1,其它字段都设定为0或NULL。如果要重复循环播放声音,可设定dwFlags和dwLoops字段。

SINEWAVE下一步为两个信息表头呼叫waveOutPrepareHeader函数,以防止结构和缓冲区与磁盘发生数据交换。

到此为止,所有的这些准备都是响应单击开启声音的按钮。但在程序的消息队列里已经有一个消息在等待响应。因为我们已经在函数waveOutOpen中指定要用一个窗口消息处理程序来接收波形输出消息,所以waveOutOpen函数向程序的消息队列发送了MM_WOM_OPEN消息,wParam消息参数设定为波形输出句柄。要处理MM_WOM_OPEN消息,SINEWAVE呼叫FillBuffer函数两次,并用正弦波形数据填充pBuffer缓冲区。然后SINEWAVE把两个WAVEHDR结构传送给waveOutWrite,此函数将数据传送到波形输出硬件,才真正开始播放声音。

当波形硬件播放完waveOutWrite函数传送来的数据后,就向窗口发送MM_WOM_DONE消息,其中wParam参数是波形输出句柄,lParam是指向WAVEHDR结构的指针。SINEWAVE在处理此消息时,将计算缓冲区的新数据,并呼叫waveOutWrite来重新提交缓冲区。

编写SINEWAVE程序时也可以只用一个WAVEHDR结构和一个缓冲区。不过,这样在播放完数据后将会有很短暂的停顿,以等待程序处理MM_WOM_DONE消息来提交新的缓冲区。SINEWAVE使用的「双缓冲」技术避免了声音的不连续。

当使用者单击「Turn Off」按钮关闭声音时,DlgProc接收到另一个WM_COMMAND消息。对此消息,DlgProc把bShutOff变量设定为TRUE,并呼叫waveOutReset函数。此函数停止处理声音并发送一条MM_WOM_DONE消息。bShutOff为TRUE时,SINEWAVE透过呼叫waveOutClose来处理MM_WOM_DONE,从而产生一条MM_WOM_CLOSE消息。处理MM_WOM_CLOSE通常包括清除程序。SINEWAVE为两个WAVEHDR结构而呼叫waveOutUnprepareHeader、释放所有的内存块并把按钮上的文字改回「Turn On」。

如果硬件继续播放缓冲区的声音数据,那么它自己呼叫waveOutClose就没有作用。您必须先呼叫waveOutReset来停止播放并产生MM_WOM_DONE消息。当wParam是SC_CLOSE时,DlgProc也处理WM_SYSCOMMAND消息,这是因为使用者从系统菜单中选择了「Close」。如果波形声音继续播放,DlgProc则呼叫waveOutReset。无论如何,最后总要呼叫EndDialog来结束程序。

数位录音机


Windows提供了一个称为「录音程序」来录制和播放数字声音。程序22-3所示的程序(RECORD1)不如「录音程序」完善,因为它不含有任何文件I/O,也不允许声音编辑。然而,这个程序显示了使用低阶波形声音API来录制和回放声音的基本方法。

程序22-3 RECORD1 
        
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)
        

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -