windows声音应用程序开发指南 张新宇 第2章 WAV文件格式.ppt_第1页
windows声音应用程序开发指南 张新宇 第2章 WAV文件格式.ppt_第2页
windows声音应用程序开发指南 张新宇 第2章 WAV文件格式.ppt_第3页
windows声音应用程序开发指南 张新宇 第2章 WAV文件格式.ppt_第4页
windows声音应用程序开发指南 张新宇 第2章 WAV文件格式.ppt_第5页
已阅读5页,还剩69页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第2章WAV文件格式 2 1WAV文件格式 1 2 3 4 2 2保存为WAV文件格式 1 2 3 4 5 2 3压缩WAVE音频 5 2 4本章小结 2 1WAV文件格式 1 2 3 4 2 1 1RIFF文件和WAV文件格式1 RIFF文件RIFF可以看做是一种树状结构 其基本构成单位为 块 Chunk 它犹如树状结构中的节点 每个Chunk由 辨别码 ID 数据大小 Size 和 数据 Data 所组成 如表2 1所示 表2 1RIFF文件格式 一般而言 Chunk本身并不允许内部再包含Chunk 但有两种情况例外 即分别以 RIFF 及 LIST 为辨别码的Chunk可以包含子Chunk 以 RIFF 为辨别码的Chunk包含子Chunk的格式如图2 1所示 图中前4个字符 图2 1RIFF文件结构 2 WAV文件WAV为WAVEFORM 波形 的缩写 WAV文件的结构如图2 2所示 RIFFChunk中子Chunk的 格式辨别码 为 WAVE 整个文件由两个Chunk所组成 辨别码 fmt 注意 最后一个是空白字符 及 data 图2 2WAV文件结构 在 fmt 的Chunk下包含了一个PCMWAVEFORMAT数据结构 该结构与前一章中的WAVEFORMATEX结构类似 其定义如下 typedefstructwaveformat tag WORDwFormatTag WORDnChannels DWORDnSamplesPerSec DWORDnAvgBytesperSec WORDnBlockAlign WAVEFORMAT typedefstructpcmwaveformat tag WAVEFORMATwf WORDwBitsPerSample PCMWAVEFORMAT 其意义分别如下 wFormatTag 记录着此声音的格式代号 例如WAVE FORMAT PCM WAVE FORMAT ADPCM等等 nChannels 记录声音的声道数 nSamp1esPerSec 记录每秒采样数 采样率 nAvgBytesPerSec 记录每秒的平均数据量 nBlockA1ign 记录块的对齐单位 wBitsPerSample 记录每个采样样本所需的位元数 data Chunk包含真正的声音数据 Windows目前仅提供WAVE FORMAT PCM一种数据格式 其所代表的意义是脉冲编码调制 PCM Pu1seCodeModulation 用编辑工具UltraEdit查看WAV文件的文件头 如图2 3所示 表2 2以数据在文件中的存放位置说明了WAV文件格式 其中偏移地址是相对于文件头的地址 图2 3WAV文件的文件头 表2 2WAV文件格式说明表 Windows定义了在 data Chunk中数据的存放情形 表2 3列出了四种不同声道数及取样所需的位元数以及位元位置的安排 其中 对于8位单声道 每个样本数据由8位 bit 表示 对于8位立体声 每个声道的数据由一个8位 bit 数据表示 且第一个8位 bit 数据表示0声道 左 数据 紧随其后的8位 bit 数据表示1声道 右 数据 对于16位单声道 每个样本数据由16位 bit 表示 对于16位立体声 每个声道的数据由一个16位 bit 数据表示 且第一个16位 bit 数据表示0声道 左 数据 紧随其后的16位 bit 数据表示1声道 右 数据 表2 3PCM数据的存放方式 WAV文件的每个样本值包含在一个整数i中 i的长度为容纳指定样本长度所需的最小字节数 首先存储低有效字节 表示样本幅度的位放在i的高有效位上 剩下的位置为0 这样8位和16位的PCM波形样本的数据格式如表2 4所示 表2 4PCM数据的存放方式 2 1 2WAV文件信息的具体应用WAV文件包括了对原始声音的高速率采样数据 并且以WAVE PCM FORMAT格式的形式保存 在读出WAV文件头信息之后 接着的数据就是原始声音的高速率采样信息 我们可以在VisualC 程序中对这些信息作多方面的处理 其中包括 波形显示我们可以以时间 振幅的方式显示出原始声音的波形 这是最简单同时也是最直接的信息处理方式 在时间范围内 我们可以观察该信号波形是否连续 中间是否有跳变等 频谱显示我们可以以频率 振幅的方式显示出原始声音的频谱 在对原始信号经过FFT变换之后 可以得到该信号的频谱 进而得到该信号的能量集中带 分布特征 谱对称系数等等 用于语音信号识别讲话者的个体识别是语音信号处理的一个重要内容 但它的一个前提条件是必须提供语音信号的数字波形 通常的方法是将原始的语音信号进行放大 抗混叠滤波 A D采样 数值编码 最终得到语音信号的数字波形 2 2保存为WAV文件格式 1 2 3 4 5 2 2 1创建一个空文件用系统函数CreateFile创建一个空文件 其程序如下 includeFILE m fp NULL 文件句柄DWORDdwFileSize 0 文件长度 DWORDdwTotalAudioLength 0 声音数据长度HANDLEOpenFileToWrite LPCTSTRlpFileName SECURITY ATTRIBUTESsa sa nLength sizeof SECURITY ATTRIBUTES sa lpSecurityDescriptor NULL sa bInheritHandle FALSE returnCreateFile lpFileName GENERIC WRITE 0 2 2 2写WAV文件头首先 要得到声音采样数据的相关信息 通常这些信息存储在一个WAVEFORMATEX结构中 用系统函数WriteFile将文件头信息写入新创建的文件 其程序如下 BOOLWriteWaveFileHeader char DesFilename WAVEFORMATEXwfx longcbFmtChunk cbDataChunk m fp在前面已定义过m fp fopen DesFilename w b if m fp returnFALSE 打开文件出错cbFmtChunk sizeof WAVEFORMATEX wfx cbSize WAVEFORMATEX结构长度dwFileSize 46 46为文件头的长度dwTotalAudioLength 0 cbDataChunk dwTotalAudioLength fwrite RIFF 1 sizeof DWORD m fp RIFF标识符 占用4Byte fwrite WAVEFORMAT结构的长度 4Byte fwrite 2 2 3写声音数据将给定缓冲区中声音数据写入WAV文件 其程序如下 BOOLWriteWaveFileData LPBYTElpBufferData DWORDdwDataSize if dwDataSize 0 returnFALSE elsefwrite lpBufferData 1 dwDataSize m fp dwFileSize dwDataSize 文件长度随着增加dwTotalAudioLength dwTotalAudioLength dwDataSize 声音数据长度随着增加returnTRUE fseek m fp 42 SEEK SET 设置文件指针fwrite 2 3压缩WAVE音频 5 2 3 1CODECs介绍Microsoft的Windows95 98 NT 2000操作系统都具有能通过安装的CODECs处理编码的WAVE格式的音频和视频数据流的能力 一个CODEC是一小段用于编码 Code 及解码 DECode 数据流的代码 因此得名CODEC 许多CODECs既能编码又能解码 而一些CODECs仅能用于解码 这样私有数据可以在系统上播放 但数据格式不能在系统上创建 2 3 2系统中有什么CODECsMicrosoft的Windows95 98 NT 2000本身附带有几种标准的CODECs 也可由系统中所安装的应用程序安装其它的CODECs 例如 DSPGroup公司的TrueSpeechCODEC随Windows95发送 因此 用户写的任何基于Windows95的应用程序都可使用此CODEC 只要用户没有在控制面板中删除它或禁止它 所有安装的CODECs都由音频编码解码器 ACM 管理 见图2 4 我们可以用一段小程序从ACM中查到安装了哪些CODECs 它们都支持什么格式 也可双击控制面板中的多媒体选项 选择高级标签 就能看到系统中所安装的CODECs 下面用一段程序介绍如何应用ACM 首先从调用ACM编程接口所需的包含的头文件开始 include include include 多媒体注册 include 音频编码解码器 include 图2 4音频编码解码器 mmsystem h头文件包含了Windows支持的大部分的多媒体功能 但不包含ACM接口及任何厂商定义 mmreg h包含了对不同厂商设计的各种WAVE数据类型的格式标签的定义 它也包含了用于处理不同的WAVE数据类型的结构 基于WAVEFORAMTEX 的定义 msacm h包含了ACM所需的API 标志等等 我们要做的第一件事就是执行一些常见的ACM查询来判断版本号 获取它当前管理了多少个驱动程序的信息 下面是查询ACM的部分代码 DWORDdwACMVer acmGetVersion printf ACMversion u 02ubuild u HIWORD dwACMVer 8 HIWORD dwACMVer acmGetVersion函数返回一个32位的十六进制数值 表示ACM的版本号 其形如0 xAABBCCCC 其中 AA代表ACM的主版本号 BB代表ACM的副版本号 CCCC代表ACM的debug版本的build号 对于一个非debug版本 零售版 的ACM CCCC总为0 例如 在应用程序中返回版本号为0 x05000856 则ACM版本号为5 00 且系统中安装的是debug版本 build号为2134 十进制 用acmMetrics函数可以知道系统中安装了多少个CODECs驱动程序 DWORDdwCodecs 0 MMRESULTmmr acmMetrics NULL ACM METRIC COUNT CODECS 对ACM有了简单了解后 现在可以要求它枚举出系统中当前所有的驱动程序 我们在程序中所调用的枚举函数使用回调函数来显示每个设备的数据 这在Windows编程中是一种很普遍的方法 下面的调用就是枚举当前ACM所管理的所有设备 枚举所有允许的驱动程序printf Enableddrivers n mmr acmDriverEnum DriverEnumProc 0 0 if mmr show error mmr acmDriverEnum函数列举出可用的ACM驱动程序 第一个参数指出回调函数的地址 现在 让我们看看枚举回调函数DriverEnumProc 它由系统中的每一个驱动程序调用 BOOLCALLBACKDriverEnumProc HACMDRIVERIDhadid DWORDdwInstance DWORDfdwSupport printf id 8 8lxH hadid printf supports n if fdwSupport 获得一些具体信息ACMDRIVERDETAILSdd dd cbStruct sizeof dd MMRESULTmmr acmDriverDetails hadid else printf Shortname s n dd szShortName printf Longname s n dd szLongName printf Copyright s n dd szCopyright printf Licensing s n dd szLicensing printf Features s n dd szFeatures printf Supports uformats n dd cFormatTags printf Supports ufilterformats n dd cFilterTags 打开驱动程序HACMDRIVERhad NULL mmr acmDriverOpen mmr acmMetrics had ACM METRIC MAX SIZE FORMAT if mmr printf show error mmr free pwf acmDriverClose had 0 returnTRUE 继续枚举 为结构分配了空间后 现在可以用acmFormatEnum来枚举所支持的格式 这次又用到一个回调函数来取得枚举出的所支持格式的相关数据 BOOLCALLBACKFormatEnumProc HACMDRIVERIDhadid LPACMFORMATDETAILSpafd DWORDdwInstance DWORDfdwSupport printf 4 4lXH s n pafd dwFormatTag pafd szFormat returnTRUE 继续枚举 2 3 3使用特定的CODEC1 两步实现编码在理想的情况下 编码一些数据可能只要向系统发出命令 这有一些数据 请编码成这种格式 即可 但实际上 Windows编程与理想相去甚远 在当前的现实中 我们得自已做许多琐碎的工作 2 编码的实现过程在本例中 实现编码分以下四个阶段 1 创建一些WAV格式数据的样本 2 找到一个合适的CODEC 3 将数据转换为该CODEC可处理的中间格式 4 将数据转换成所需的格式 为了简单起见 源数据用程序创建 而不是录入或是从WAV文件中读取 首先我们创建一个可能是刚刚才录制的WAV 其格式为11 025kHz 8位单声道PCM 这是一个 在所有机器上都可用的录入格式 例如1秒长的1kHz的正弦波WAVE 刚好1000个周期WAVEFORMATEXwfSrc memset wfSrc wFormatTag WAVE FORMAT PCM PCMwfSrc nChannels 1 单声道wfSrc nSamplesPerSec 11025 11 025kHzwfSrc wBitsPerSample 8 8bitwfSrc nBlockAlign wfSrc nChannels wfSrc wBitsPerSample 8 wfSrc nAvgBytesPerSec wfSrc nSamplesPerSec wfSrc nBlockAlign DWORDdwSrcSamples wfSrc nSamplesPerSec BYTE pSrcData newBYTE dwSrcSamples 分配1秒种的长度内存空间BYTE pData pSrcData doublef 1000 0 doublepi 4 0 atan 1 0 doublew 2 0 pi f for DWORDdw 0 dw dwSrcSamples dw pData dw w 上面的代码创建了一个WAVEFORMATEX结构用来描述源数据格式 并用简单的数学方法生成了1秒钟长的11 025kHz 8位单声道的PCM的WAVE数据 下一步就是选择要将数据转换成什么格式及选定一个合适的CODEC WORDwFormatTag WAVE FORMAT DSPGROUP TRUESPEECH 现在我们选定一个支持目标格式标签的CODECHACMDRIVERIDhadid find driver wFormatTag if hadid NULL printf Nodriverfound n exit 1 printf Driverfound hadid 4 4lXH n hadid find driver函数枚举所有的驱动程序 直到找到一个支持给定标签值的驱动程序 本例为WAVE FORMAT DSPGROUP TRUESPEECH 之所以没有在此给出代码 是因为它与前面的枚举代码非常相像 随后你可以查看它是怎样工作的 选定了驱动程序后 现在要为最终驱动程序将要产生的压缩数据格式创建一个WAVEFORMATEX结构 并为驱动程序用于输入的中间PCM格式产生一个WAVEFORMATEX结构 获得格式的详情 注意 这只是一个给定格式标签的第一种或是最可能的格式WAVEFORMATEX pwfDrv get driver format hadid wFormatTag if pwfDrv NULL printf Errorgettingformatinfo n exit 1 printf Driverformat ubits lusamplespersecond n pwfDrv wBitsPerSample pwfDrv nSamplesPerSec 获取驱动程序所支持的PCM格式标签 注意 我们只是选取CODEC所支持的枚举出的第一种PCM格式 但不一定是最好的选择WAVEFORMATEX pwfPCM get driver format hadid WAVE FORMAT PCM if pwfPCM NULL printf ErrorgettingPCMformatinfo n exit 1 printf PCMformat ubits lusamplespersecond n pwfPCM wBitsPerSample pwfPCM nSamplesPerSec 还要进一步强调的是 get driver format函数仅仅枚举出第一种匹配的格式 也许不能获得最好的质量 让我们看看第一步的转换 它完成的是将源数据转换为中间格式 将源WAVE转换为CODEC所支持的PCM格式 我们使用任一种能实现PCM格式间相互转换的驱动程序HACMSTREAMhstr NULL mmr acmStreamOpen hstr NULL 任一驱动程序 标志 if mmr printf FailedtoopenastreamtodoPCMtoPCMconversion n exit 1 为转换结果开辟一个缓冲区DWORDdwSrcBytes dwSrcSamples wfSrc wBitsPerSample 8 DWORDdwDst1Samples dwSrcSamples pwfPCM nSamplesPerSec wfSrc nSamplesPerSec DWORDdwDst1Bytes dwDst1Samples pwfPCM wBitsPerSample 8 BYTE pDst1Data newBYTE dwDst1Bytes 填写转换信息ACMSTREAMHEADERstrhdr memset 转换数据 printf ConvertingtointermediatePCMformat n mmr acmStreamConvert hstr 最后一步是将中间格式转换为最终的压缩格式 将中间格式转换为最终的压缩格式 打开驱动程序HACMDRIVERhad NULL mmr acmDriverOpen 打开转换流 注意使用了ACM STREAMOPENF NONREALTIME标志 若没有此标志 一些软件压缩程序会报告512号错误 即不可能mmr acmStreamOpen hstr had 驱动程序句柄pwfPCM 源格式pwfDrv 目标格式NULL 不过滤NULL 无回调函数0 实例数据 未使用 if mmr printf FailedtoopenastreamtodoPCMtodriverformatconversion n exit 1 为转换结果分配一个缓冲区 根据以字节计的平均速率计算输出缓冲区的尺寸 并加上一机动位 bit 若没有此额外的空间 IMA ADPCM驱动程序将不能转换DWORDdwDst2Bytes pwfDrv nAvgBytesPerSec dwDst1Samples pwfPCM nSamplesPerSec dwDst

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论