📄 22. 声音与音乐.txt
字号:
声音与音乐
智能中国——游戏组 整理编译
--------------------------------------------------------------------------------
在Microsoft Windows中,声音、音乐与视讯的综合运用是一个重要的进步。对多媒体的支持起源于1991年所谓的Microsoft Windows多媒体延伸功能(Multimedia Extensions to Microsoft Windows)。1992年,Windows 3.1的发布使得对多媒体的支持成为另一类API。最近几年,CD-ROM驱动器和声卡-在90年代初期还很少见-已成为新PC的标准配备。现在,几乎所有的人们都深信: 多媒体在很大程度上有益于Windows的可视化图形,从而使计算机摆脱了其只是处理数字和文字的机器的传统角色。
WINDOWS和多媒体
从某种意义上来说,多媒体就是透过与设备无关的函数呼叫来获得对各种硬件的存取。让我们首先看一下硬件,然后再看看Windows多媒体API的结构。
多媒体硬件
或许最常用的多媒体硬件就是波形声音设备,也就是平常所说的声卡。波形声音设备将麦克风的输入或其它声音输入转换为数字取样,并将其储存到内存或者储存到以.WAV为扩展名的磁盘文件中。波形声音设备还将波形转换回模拟声音,以便通过PC扩音器来播放。
声卡通常还包含MIDI设备。MIDI是符合工业标准的乐器数字化接口(Musical Instrument Digital Interface)。这类硬件播放音符以响应短的二进制命令消息。MIDI硬件通常还可以通过电缆连结到如音乐键盘等的MIDI输入设备上。通常,外部的MIDI合成器也能够添加到声卡上。
现在,大多数PC上的CD-ROM驱动器都具备播放普通音乐CD的能力。这就是平常所说的「CD声音」。来自波形声音设备、MIDI设备以及CD声音设备的输出,一般在使用者的控制下用「音量控制」程序混合在一起。
另外几种普遍的多媒体「设备」不需要额外的硬件。Windows视讯设备(也称作AVI视讯设备)播放扩展名为.AVI(audio-video interleave:声音视频插格)的电影或动画文件。「ActiveMovie控件」可以播放其它型态的电影,包括QuickTime和MPEG。PC上的显示卡需要特定的硬件来协助播放这些电影。
还有个别PC使用者使用某种Pioneer雷射影碟机或者Sony VISCA系列录放机。这些设备都有串行端口接口,因此可由PC软件来控制。某些显示卡具有一种称为「窗口影像(video in a window)」的功能,此功能允许一个外部的视讯信号与其它应用程序一起出现在Windows的屏幕上。这也可认为是一种多媒体设备。
API概述
在Windows中,API支持的多媒体功能主要分成两个集合。它们通常称为「低阶」和「高阶」界面。
低阶接口是一系列函数,这些函数以简短的说明性前缀开头,而且在/Platform SDK/Graphics and Multimedia Services/Multimedia Reference/Multimedia Functions(与高阶函数一起)中列出。
低阶的波形声音输入输出函数的前缀是waveIn和waveOut。我们将在本章看到这些函数。另外,本章还讨论用midiOut函数来控制MIDI输出设备。这些API还包括midiIn和midiStream函数。
本章还使用前缀为time的函数,这些函数允许设定一个高分辨率的定时器例程,其定时器的时间间隔速率最低能够到1毫秒。此程序主要用于播放MIDI音乐。其它几组函数包括声音压缩、视讯压缩以及动画和视讯序列,可惜的是本章不包括这些函数。
您还会注意到多媒体函数列表中七个带有前缀mci的函数,它们允许存取媒体控制接口(MCI:Media Control Interface)。这是一个高阶的开放接口,用于控制多媒体PC中所有的多媒体硬件。MCI包括所有多媒体硬件都共有的许多命令,因为多媒体的许多方面都以磁带录音机这类设备播放/记录方式为模型。您为输入或输出而「打开」一台设备,进而可以「录音」(对于输入)或者「播放」(对于输出),并且结束后可以「关闭」设备。
MCI本身分为两种形式。一种形式下,可以向MCI发送消息,这类似于Windows消息。这些消息包括位编码标记和C数据结构。另一种形式下,可以向MCI发送文字字符串。这个程序主要用于描述命令语言,此语言具有灵活的字符串处理函数,但支持呼叫Windows API的函数不多。字符串命令版的MCI还有利于交互研究和学习MCI,我们马上就举一个例子。MCI中的设备名称包括CD声音(cdaudio)、波形音响(waveaudio)、MIDI编曲器(sequencer)、影碟机(videodisc)、vcr、overlay(窗口中的模拟视频)、dat(digital audio tape:数字式录频磁带)以及数字视频(digitalvideo)。MCI设备分为「简单型」和「混合型」。简单型设备(如CD声音)不使用文件。混合型设备(如波形音响)则使用文件。使用波形音响时,这些文件的扩展名是.WAV。
存取多媒体硬件的另一种方法包括DirectX API,它超出了本书的范围。
另外两个高阶多媒体函数也值得一提:MessageBeep和PlaySound,它们在第三章有示范。MessageBeep播放「控制台」的「声音」中指定的声音。PlaySound可播放磁盘上、内存中或者作为资源加载的.WAV文件。本章的后面还会用到PlaySound函数。
用TESTMCI研究MCI
在Windows多媒体的早期,软件开发套件含有一个名为MCITEST的C程序,它允许程序写作者交谈式输入MCI命令并学习这些命令的工作方式。这个程序,至少是C语言版,显然已经消失了。因此,我又重新建立了它,即程序22-1所示的TESTMCI程序。虽然我不认为目前程序代码与旧的程序代码有什么区别,但现在的使用者接口还是依据以前的MCITEST程序,并且没有使用现在的程序代码。
程序22-1 TESTMCI
TESTMCI.C
/*---------------------------------------------------------------------------
TESTMCI.C -- MCI Command String Tester
(c) Charles Petzold, 1998
----------------------------------------------------------------------------*/
#include <windows.h>
#include "resource.h"
#define ID_TIMER 1
BOOL CALLBACK DlgProc (HWND, UINT, WPARAM, LPARAM) ;
TCHAR szAppName [] = TEXT ("TestMci") ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
if (-1 == DialogBox (hInstance, szAppName, NULL, DlgProc))
{
MessageBox ( NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
}
return 0 ;
}
BOOL CALLBACK DlgProc ( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hwndEdit ;
int iCharBeg, iCharEnd, iLineBeg, iLineEnd, iChar, iLine, iLength ;
MCIERROR error ;
RECT rect ;
TCHAR szCommand [1024], szReturn [1024],
szError [1024], szBuffer [32] ;
switch (message)
{
case WM_INITDIALOG:
// Center the window on screen
GetWindowRect (hwnd, &rect) ;
SetWindowPos (hwnd, NULL,
(GetSystemMetrics (SM_CXSCREEN) - rect.right + rect.left) / 2,
(GetSystemMetrics (SM_CYSCREEN) - rect.bottom + rect.top) / 2,
0, 0, SWP_NOZORDER | SWP_NOSIZE) ;
hwndEdit = GetDlgItem (hwnd, IDC_MAIN_EDIT) ;
SetFocus (hwndEdit) ;
return FALSE ;
case WM_COMMAND:
switch (LOWORD (wParam))
{
case IDOK:
// Find the line numbers corresponding to the selection
SendMessage (hwndEdit, EM_GETSEL, (WPARAM) &iCharBeg,
(LPARAM) &iCharEnd) ;
iLineBeg = SendMessage (hwndEdit, EM_LINEFROMCHAR, iCharBeg, 0) ;
iLineEnd = SendMessage (hwndEdit, EM_LINEFROMCHAR, iCharEnd, 0) ;
// Loop through all the lines
for (iLine = iLineBeg ; iLine <= iLineEnd ; iLine++)
{
// Get the line and terminate it; ignore if blank
* (WORD *) szCommand = sizeof (szCommand) / sizeof (TCHAR) ;
iLength = SendMessage (hwndEdit, EM_GETLINE, iLine,
(LPARAM) szCommand) ;
szCommand [iLength] = '\0' ;
if (iLength == 0)
continue ;
// Send the MCI command
error =mciSendString (szCommand, szReturn,
sizeof (szReturn) / sizeof (TCHAR), hwnd) ;
// Set the Return String field
SetDlgItemText (hwnd, IDC_RETURN_STRING, szReturn) ;
// Set the Error String field (even if no error)
mciGetErrorString (error, szError, sizeof (szError) / sizeof (TCHAR)) ;
SetDlgItemText (hwnd, IDC_ERROR_STRING, szError) ;
}
// Send the caret to the end of the last selected line
iChar = SendMessage (hwndEdit, EM_LINEINDEX, iLineEnd, 0) ;
iChar += SendMessage (hwndEdit, EM_LINELENGTH, iCharEnd, 0) ;
SendMessage (hwndEdit, EM_SETSEL, iChar, iChar) ;
// Insert a carriage return/line feed combination
SendMessage (hwndEdit, EM_REPLACESEL, FALSE,
(LPARAM) TEXT ("\r\n")) ;
SetFocus (hwndEdit) ;
return TRUE ;
case IDCANCEL:
EndDialog (hwnd, 0) ;
return TRUE ;
case IDC_MAIN_EDIT:
if (HIWORD (wParam) == EN_ERRSPACE)
{
MessageBox (hwnd, TEXT ("Error control out of space."),
szAppName, MB_OK | MB_ICONINFORMATION) ;
return TRUE ;
}
break ;
}
break ;
case MM_MCINOTIFY:
EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_MESSAGE), TRUE) ;
wsprintf (szBuffer, TEXT ("Device ID = %i"), lParam) ;
SetDlgItemText (hwnd, IDC_NOTIFY_ID, szBuffer) ;
EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_ID), TRUE) ;
EnableWindow (GetDlgItem (hwnd, IDC_NOTIFY_SUCCESSFUL),
wParam & MCI_NOTIFY_SUCCESSFUL) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -