红灯记 发表于 2011-10-24 22:13:49

C++语言对WAV文件编程简析

本帖最后由 红灯记 于 2011-10-24 22:27 编辑

WAV文件,是目前公认的最好的数码音频的文件格式,但是用不同的计算机语言实现WAV文件的录制和播放,是有所区别的,这主要与编程语言语句的性能和算法的采用决定的。
Wav文件直接反映了一个声音在每个时刻的大小值,比如说一个正弦波段波形:
我们按每次0.1秒取一点,得到的wav文件数值就是0,1,1,-1,0,1。因此,假如我们能把许多Wav文件的数据直接相加,你听到的就是所有的声音,这就是混音器的原理。
打开并分析一下Wav文件结构:
我们可以打开一个Wav文件直接看其二进制码:
00000000 5249 4646 9CB6 1E00 5741 5645 666D 7420
00000010 1000 0000 0100 0200 2256 0000 44AC 0000
00000020 0200 0800 6461 7461 78B6 1E00 7F7F 7F7F
00000030.7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F
00000040.7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F
00000050.7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F
00000060.7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F
00000070.7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F
00000080.7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F
00000090.7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F
000000A0.7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F 7F7F
大家可以看到wav文件存储格式如下:

"RIFF"
×××× 文件大小
"WAVE"
"fmt"
×××× PCMWAWFORMAT——数据结构大小
××××
…… 数据结构“PCMWAVEFORMAT”
××××
data
×××× 数据大小
∶ 数据

首先是字符串“RIFF”,表示此文件遵循一种标准格式名为“资源互换文件格式”(Resource Intercharge Format)。后面紧跟四个字节指明文件大小。其次是字符串“WAVE”和“fmt”,后面紧跟一个名为“PCMWAVEFORMAT”的结构,最后是字符串“data”,紧跟数据大小及所有数据。PIFF文件为一种树状结构,基本构成单位是“块”。wav文件结构为两层,由父块“RIFF”和两个子块“fmt”、“data”组成。“fmt”块包含wav文件格式信息,“data”块包含数据信息

红灯记 发表于 2011-10-24 22:17:50

有关WAV语句的含义:
waveInAddBuffer向声音输入设备发送缓冲区
waveInClose关闭声音输入设备
waveInGetDevCaps获取声音输入设备性能
waveInGetErrorText获取声音出错的信息文本
waveInGetID获取声音输入设备ID
waveInGetNumDevs返回声音输入设备数量
waveInGetPosition获取声音设备输入位置
waveInMessage向声音输入设备发送信息
waveInOpen打开声音输入设备
waveInPrepareHeader预备声音输入缓冲区
waveInReset停止声音输入设备工作
waveInStart停止声音输入设备工作
waveInStop停止声音输入
waveInUnprepareHeader清除预备的声音文件头
waveOutBreakLoop中断声音输出循环
waveOutClose关闭声音输出设备
waveOutGetDevCaps获取声音输出设备性能
waveOutGetErrorText获取声音出错文本
waveOutGetID获取声音输出设备ID
waveOutGetNumDevs获取声音输出设备数量
waveOutGetPitch获取声音输出的强度
waveOutGetPlaybackRate获取声音回放率
waveOutGetPosition获取声音回放位置
waveOutGetVolume获取声音音量
waveOutMessage向声音输出设备发送消息
waveOutOpen打开声音输出设备
waveOutPause暂停声音回放
waveOutPrepareHeader预备声音回放数据块
waveOutReset停止声音回放
waveOutRestart重开始声音回放
waveOutSetPitch设置波形输出强度
waveOutSetPlaybackRate设置回放率
waveOutSetVolume设置输出音量
waveOutUnprepareHeader清除预备声音数据块
waveOutWrite写入声音输出设备

红灯记 发表于 2011-10-24 22:25:57

媒体控制接口
MCI(Media Control Interface)媒体控制接口是MircroSoft提供的一组多媒体设备和文件的标准接口,它的好处是可以方便地控制绝大多数多媒体设备包括音频、视频、影碟、录像等多媒体设备,而不需要知道它们的内部工作状况。但是古人云:成也萧何,败也萧何。MCI虽然看上去高大全,但对于一些高级应用来说,它是远远不够的。好比Visual C++虽然看上去无所不能,却需要程序员自己开发多媒体引擎一样。
MCI的控制方式:

一般说来,程序员使用两个函数就可以与MCI打交道了:

MCIERROR mciSendCommand(MCIDEVICEID wDeviceID, UINT uMsg,
DWORD dwFlags, DWORD dwParam );

命令字符串方式,用接近于日常生活用语的方式发送控制命令,适用于高级编程如VB、TOOLBOOK等。

MCIERROR mciSendString(LPCTSTR lpszCommand,LPTSTR lpszReturnStr
ing, UINT cchReturn, HANDLE hwndCallback);

命令消息方式,用专业语法发送控制消息,适用于VC等语言编程,此方式直接与MCI设备打交道。

 

对于mciSendCommand,第一个参数指定了设备标识,这个标识会在程序员打开MCI设备时由系统提供。第二个参数指定将如何控制设备。第三个参数为访问标识,第四个参数一般是一个数据结构,标识程序在访问MCI时要的一些信息。有关详细资料,请查阅C++文本说明。
对于mciSendString,第一个参数为一串控制字符串,返回信息由系统填入第二个参数,第三个参数指明返回信息的最大长度,若对MCI装置设定了"notify"标志则需要在第四个参数填上返回窗口句柄。

举例:

mciSendCommand(DeviceID,MCI_CLOSE,NULL,NULL);//关闭一个MCI设备;

mciSendString("open aaa.avi",0,0,0); //打开文件"aaa.avi";

MCI的设备类型:

MCI的设备类型有:

设备描述 描述字符串 说明

MCI_ALL_DEVICE_ID   所有设备

MCI_DEVTYPE_ANIMATION Animation 动画设备

MCI_DEVTYPE_CD_AUDIO Cdaudio CD音频

MCI_DEVTYPE_DAT Dat 数字音频

MCI_DEVTYPE_DIGITAL_VIDEO Digitalvideo 数字视频

MCI_DEVTYPE_OTHER Other 未定义设备

MCI_DEVTYPE_OVERLAY Overlay 重叠视频

MCI_DEVTYPE_SCANNER Scanner 扫描仪

MCI_DEVTYPE_SEQUENCER Sequencer MIDI 序列器

MCI_DEVTYPE_VCR Vcr合式录像机

MCI_DEVTYPE_VIDEODIS Videodisc 激光视盘

MCI_DEVTYPE_WAVEFORM_AUDIO waveaudio Wave 音频

对于未在上面定义的MCI设备,用我们可查看system.ini文件中部分,例如:



cdaudio=mcicda.drv
sequencer=mciseq.drv
waveaudio=mciwave.drv
avivideo=mciavi.drv
videodisc=mcipionr.drv
vcr=mcivisca.drv
ActiveMovie=mciqtz.drv
QTWVideo=mciqtw.drv
MPEGVideo=C:\PROGRA~1\XING\XINGMP~1\xmdrv95.dll
其中最后两句分别指明了Apple的QuickTime设备,设备名为"QTWVidio"、MPEG影像设备,设备名为"MPEGVideo"。

在MCI编程中,既可以将设备描述当设备名,也可以将描述字符串当设备名,一个极端偷懒的办法是程序员不要在程序中指定设备名,Windows将自动根据文件扩展名识别设备类型。

举个例子来说,打开一个多媒体文件有以下三种方式:
:自动识别:打开一个"WAV"文件
MCI_OPEN_PARMS mciOpen;
mciOpen.lpstrDeviceType=0;
mciOpen.lpstrElementName="aaa.wav";
mciSendCommand(NULL,MCI_OPEN, MCI_OPEN_ELEMENT,
(DWORD)&mciOpen);

:指定设备描述:打开CD播放器
MCI_OPEN_PARMS mciOpen;
mciOpen.lpstrDeviceType=(LPSTR)MCI_DEVTYPE_CD_AUDIO ;
mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID,
(DWORD)&mciOpen);

:指定描述字符串: 打开一个AVI文件
MCI_OPEN_PARMS mciOpen;
mciOpen.lpstrDeviceType="avivideo";
mciOpen.lpstrElementName="aaa.avi";
mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
(DWORD)&mciOpen);


注意三种打开方式中,函数第三个参数的区别。

 

MCI指令

MCI使用如下指令:

MCI_BREAK
设置中断键,缺省是”CTRL+BREAK"

MCI_CAPTURE
抓取当前帧并存入指定文件,仅用于数字视频

MCI_CLOSE
关闭设备

MCI_CONFIGURE
弹出配置对话框,仅用于数字视频

MCI_COPY
拷贝数据至剪贴板

MCI_CUE
延时播放或录音

MCI_CUT
删除数据

MCI_DELETE
删除数据

MCI_ESCAPE
仅用于激光视频

MCI_FREEZE
将显示定格

MCI_GETDEVCAPS
获取设备信息

MCI_INDEX
当前屏幕显示与否,仅用于VCR设备

MCI_INFO
获取字符串信息

MCI_LIST
获取输入设备数量,支持数字视频和VCR设备

MCI_LOAD
装入一个文件

MCI_MARK
取消或做一个记号,与MCI_SEEK配套

MCI_MARK
取消或做一个记号,与MCI_SEEK配套

MCI_MONITOR
为数字视频指定报告设备

MCI_OPEN
打开设备

MCI_PASTE
粘帖数据

MCI_PAUSE
暂停当前动作

MCI_PLAY
播放

MCI_PUT
设置源、目的和边框矩形

MCI_QUALITY
定义设备缺省质量

MCI_RECORD
开始录制

MCI_RESERVE
分配硬盘空间

MCI_RESTORE
拷贝一个bmp文件至帧缓冲

MCI_RESUME
使一个暂停设备重新启动

MCI_SAVE
保存数据

MCI_SEEK
更改媒体位置

MCI_SET
设置设备信息

MCI_SETAUDIO
设置音量

MCI_SETTIMECODE
启用或取消VCR设备的时间码

MCI_SETTUNER
设置VCR设备频道

MCI_SETVIDEO
设置video参数

MCI_SIGNAL
在工作区上设置指定空间

MCI_STATUS
获取设备信息

MCI_STEP
使播放设备跳帧

MCI_STOP
停止播放

MCI_SYSINFO
返回MCI设备信息

MCI_UNDO
取消操作

MCI_UNFREEZE
使使用MCI_UNFREEZE的视频缓冲区恢复运动

MCI_UPDATE
更新显示区域

MCI_WHERE
获取设备裁减矩形

MCI_WINDOW
指定图形设备窗口和窗口特性


其中比较常用的指令有MCI_OPEN、MCI_CLOSE、MCI_PLAY、MCI_STOP、MCI_PAUSE、MCI_STATUS等等

泡泡 发表于 2011-10-24 23:59:48

好复杂的东西。{:soso_e141:}

珠江源 发表于 2011-10-25 00:05:24

太好了,我看不懂{:soso_e121:}支持灯哥{:soso_e160:}

肥牛牛 发表于 2011-10-25 09:53:33

小小迷糊 发表于 2011-10-27 20:09:21

{:soso__10626351939150152096_3:}好复杂噢

肥牛牛 发表于 2011-10-28 09:54:45

yjwu 发表于 2011-11-1 21:15:59

非常專業的文章,應該進精華區,讓我們有時間再來細細品味{:soso_e179:}
页: [1]
查看完整版本: C++语言对WAV文件编程简析