设为首页 加入收藏

TOP

痞子衡嵌入式:PCM编码与Waveform音频文件(.wav)格式详解(二)
2019-08-29 23:53:09 】 浏览:82
Tags:痞子 嵌入式 PCM 编码 Waveform 音频 文件 .wav 格式 详解
号在整个动态范围内的信噪比基本一致。下面是这两种编码与LPCM的 对比图

三、Waveform文件格式解析

  前面讲的PCM编码后的声音数据是需要保存的,WAVE文件常常用来保存PCM编码数据。WAVE文件是微软公司(Microsoft)开发的一种声音文件格式,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持,WAVE文件默认打开工具是WINDOWS的媒体播放器。

3.1 RIFF文件格式标准

  WAVE文件是以微软RIFF格式为标准的,RIFF全称为资源互换文件格式(Resources Interchange File Format),是Windows下大部分多媒体文件遵循的一种文件结构。RIFF文件所包含的数据类型由该文件的扩展名来标识,能以RIFF格式存储的数据有很多:音频视频交错格式数据(.AVI)、波形格式数据(.WAV)、位图数据格式(.RDI)、MIDI格式数据(.RMI)、调色板格式(.PAL)、多媒体电影(.RMN)、动画光标(.ANI)等。
  如下代码所示的CK结构体是RIFF文件的基本单元,该基本单元也称 Chunk。其中ckID用于标识块中所包含的数据类型,其取值可有'RIFF'、'LIST'、'fmt '、'data'等;ckSize表示存储在ckData域中的数据长度(不包含ckID和ckSize的大小);ckData存储数据,数据以字节为单位存放,如果数据长度为奇数,则最后添加一个空字节。

由于RIFF文件结构最初是由Microsoft和IBM为PC机所定义,RIFF文件是按照小端little-endian字节顺序写入的。

typedef unsigned long DWORD;
typedef unsigned char BYTE;
typedef DWORD         FOURCC;    // Four-character code

typedef struct { 
     FOURCC ckID;          // The unique chunk identifier 
     DWORD ckSize;         // The size of field <ckData> 
     BYTE ckData[ckSize];  // The actual data of the chunk 
} CK; 

  Chunk是可以嵌套的,但是只有ckID为'RIFF'或者'LIST'的Chunk才能包含其他的Chunk。标志为'RIFF'的Chunk是比较特殊的,每一个RIFF文件首先存放的必须是一个'RIFF' Chunk,并且只能有这一个标志为'RIFF'的Chunk。

  更多RIFF的知识详见这个网站链接 RIFF (Resource Interchange File Format),链接里收集了很多介绍RIFF的资源。

3.2 WAVE文件结构

  WAVE是Microsoft开发的一种音频文件格式,它符合上面提到的RIFF文件格式标准,可以看作是RIFF文件的一个具体实例。既然WAVE符合RIFF规范,其基本的组成单元也是Chunk。一个 WAVE文件 通常有三个Chunk以及一个可选Chunk,其在文件中的排列方式依次是:RIFF Chunk,Format Chunk,Fact Chunk(附加块,可选),Data Chunk,如下图所示:

  根据上面的WAVE文件结构图,可以定义如下44bytes的wave_head_t用来描述WAVE文件的头。如果你曾经接触过Windows的音频接口API,你会发现wave_fmt_t中的部分结构与标准MSDN里的 WAVEFORMAT 是一致的。

typedef char    int8_t;    //有符号8位整数
typedef short   int16_t;   //有符号16位整数
typedef int     int32_t;   //有符号32位整数

struct _wave_tag
{
    int8_t     riff[4];            //"RIFF",资源交换文件标志
    int32_t    filesize;           //文件大小(从下个地址开始到文件尾的总字节数)
    int8_t     wave[4];            //"WAVE",文件标志
} wave_tag_t;
struct _wave_format
{
    int8_t     fmt[4];             //"fmt ",波形格式标志 
    int32_t    chunksize;          //文件内部Chunk信息大小
    int16_t    wFormatTag;         //音频数据编码方式
    int16_t    wChanles;           //声道数
    int32_t    nSamplesPerSec;     //采样率
    int32_t    nAvgBytesPerSec;    //波形数据传输速率(每秒平均字节数)
    int16_t    nBlockAlign;        //数据的调整数(按字节计算)
    int16_t    wBitsPerSample;     //样本数据位数
} wave_fmt_t;
struct _wave_data
{
    int8_t     data[4];            //"data",数据标志符
    int32_t    datasize;           //采样数据总长度
} wave_dat_t;

struct _wave_head
{
    wave_tag_t   waveTag;
    wave_fmt_t   waveFmt;
    wave_dat_t   waveDat;
} wave_head_t;

  wave_head_t结构体内除了wFormatTag成员之外,其他都可以根据字面上的意思来理解。关于wFormatTag的具体定义,可见Windows SDK里的 mmreg.h文件,下面列举了几个最常见Format的Tag值定义:

  当WAVE文件的头被解析成功后,下一步便是获取WAVE文件里的声音源数据,我们知道声音文件有单声道和多声道之分,对于单声道文件很好理解,声音数据就是按序排放,而如果是立体声(2声道)文件,那么左右声道的声音数据到底是怎么排放的呢?下面以一个示例立体声文件数据(仅分析前72bytes)进行解释:

offset(h)
00000000: 52 49 46 46 24 08 00 00 57 41 56 45 66 6d 74 20
00000010: 10 00 00 00 01 00 02 00 22 56 00 00 88 58 01 00
00000020: 04 00 10 00 64 61 74 61 00 08 00 00 00 00 00 00
00000030: 24 17 1e f3 3c 13 3c 14 16 f9 18 f9 34 e7 23 a6
00000040: 3c f2 24 f2 11 ce 1a 0d

  下图是这个72bytes数据解析图,从图中可以看到,左右声道的声音数据是按块(nBlockAlign指定)交替排放的。

  更多WAVE的知识详见这两个网站链接 WAVE Audio File FormatAudio File Format Specifications,链接里收集了很多介绍WAVE的资源。

3.3 WAVE文件实例分析

  WAVE文件格式我们都了解透彻了,下面我们尝试分析一个经典的WAVE文件:"Windows XP 启动.wav",这个文件可以说是最知名的WAVE文件了,痞子衡特别喜欢这段music,让我们直接用二进制编辑器HxD打开它:

  按wave_head_t解析WAVE头可知,这段wave是44.1kHz/16bit双声道线性PCM码音频

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇树莓派3B+简单入门 下一篇在Amazon FreeRTOS V10中使用运行..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目