WAV文件格式分析

目录

WAV简介

WAV的文件组成成分

RIFF Chunk

FORMAT Chunk

DATA Chunk

8 bit 单声道:

8 bit 双声道:

16 bit 单声道:

16 bit 双声道

解析代码

实例分析

RIFF Chunk

 FORMAT Chunk

 DATA Chunk

总结

参考文献


WAV简介

       WAVE,又或者是因为扩展名而被大众所知的WAV,是微软与IBM公司所开发在个人电脑存储音频流的编码格式,在Windows平台的应用软件受到广泛的支持。该文件能记录各种单声道或立体声的声音信息,并能保证声音不失真。由于此音频格式未经过压缩,所以在音质方面不会出现失真的情况,但文件的体积因而在众多音频格式中较为大。

WAV的文件组成成分

        WAVE文件是以RIFF(Resource Interchange File Format, "资源交互文件格式")格式来组织内部结构的,因此符合 PIFF Resource Interchange File Format规范。

WAV文件本身主要由三个“块”信息组成:

  • 将文件标识为WAV文件的RIFF Chunk
  • 识别采样率等参数的FORMAT Chunk
  • 包含实际数据(样本)的DATA Chunk

        除了上述三个主要Chunk以外,文件中还可能包含一些可选的区块,如:Fack Chunk、Cue Points Chunk、Playlist Chunk、Associated data list Chunk等。

       一个使用WAV文件的应用程序必须能够读取三个主要的区块,可以选择忽略那些可区块。但是,所有对WAV文件进行复制操作的应用程序应该复制WAV文件中的所有区块。RIFF Chunk总是排在第一的Chunk。FORMAT Chunk应该出现在DATA Chunk之前。除此以外,WAV文件中各区块的顺序没有任何限制。

首先先解释一下大端数据和小端数据:

  • 所谓的大端模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
  • 所谓的小端模式,是指数据的低位保存在内存的低地址中,而数据的高位保存在内存的高地址中。

RIFF Chunk

RIFF Chunk是标识符,它意在告诉我们这是个WAV文件。

field name file offset field size(bytes) endian content
ChunkID 0x00 4 big "RIFF"(0x52494646)
ChunkSize 0x04 4 little 文件大小,=(fileSize - 8)
Format 0x08 4 big "WAVE"(0x57415645)

FORMAT Chunk

Format Chunk包含描述波形的许多重要参数,比如它的采样率、每采样值的比特数、声道数等等。

field name file offset field size(bytes) endian content
Subchunk1ID 0x0C 4 big "fmt" (0x666D7420)
Subchunk1Size 0x10 4 little 表示该区块数据的长度(不包含ID和Size的长度,为16时WAV文件头部不包含附加信息
AudioFormat 0x14 2 little 表示音频格式。PCM=1(即线性量化),除1之外的值则表示某种形式的压缩
NumChannels 0x16 2 little 表示通道数。单声道为1,双声道为2
SampleRate 0x18 4 little 表示采样率
ByteRate 0x1C 4 little 表示WAV音频数据传送速率。其值=通道数×采样率×每样本的数据位数/8
BlockAlign 0x20 2 little 一个样本的包含所有通道在内的字节数。其值=通道数×每样本的数据位数/8
BitsPerSample 0x22 2 little 表示每样本的数据位数。例如8bits=8,16bits=16

       在解释WAV文件时,使用的测量单位是 "样本"。一个样本代表在一个采样周期内捕获的数据。所以,如果采样频率是44KHz,则将有44K个样本。每个样本可以表示为8比特、16比特、24比特或32比特。(除了必须是8的倍数外,对采样的位数没有限制)。在某种程度上,样本中的比特数越多,音频的质量就越好。

      当处理这种多通道的声音时,每个通道的单个样本点是交错的,而不是先存储所有的左通道的样本点,然后存储所有的右通道的样本点。两个通道的样本交错在一起:将存储左通道的第一个样本;然后,再将存储右通道的第一个样本,以此类推。

       这个区域只需要关心 NumChannels、SampleRate和BitsPerSample 三个参数就可以了,因为其它的都是依据这三个参数计算得到的。

DATA Chunk

field name file offset field size(bytes) endian content
Subchunk2ID 0x24 4 big 数据标记符"data"
Subchunk2Size 0x28 4 little 表示语音数据的长度。其值=样本数×通道数×每样本的数据位数/8
data 0x2C 不定 little 实际的声音数据

对于DATA Chunk,根据声道数和采样率的不同情况,布局如下(每列代表8bits):

8 bit 单声道:

采样1 采样2
数据1 数据2

8 bit 双声道:

采样1 采样2
声道1数据1 声道2数据1 声道1数据2 声道2数据2

16 bit 单声道:

采样1 采样2
数据1低字节 数据1高字节 数据2低字节 数据2高字节

16 bit 双声道

采样1
声道1数据1低字节 声道1数据1高字节 声道2数据1低字节 声道2数据1高字节
采样2
声道1数据2低字节 声道1数据2高字节 声道2数据2低字节 声道2数据2高字节

解析代码

#include 
#include 
#include 
#include "wave.h"

int main()
{
    FILE *fp = NULL;

    Wav wav;
    RIFF_t riff;
    FMT_t fmt;
    Data_t data;

    fp = fopen("/home/douzi/Douzi_qdreamer/resolve_wav/mbfio_mic3.wav", "rb");
    if (!fp) {
        printf("can't open audio file\n");
        exit(1);
    }

    fread(&wav, 1, sizeof(wav), fp);

    riff = wav.riff;
    fmt = wav.fmt;
    data = wav.data;

    /**
     *  RIFF
     */
    printf("ChunkID \t\t%c%c%c%c\n", riff.ChunkID[0], riff.ChunkID[1], riff.ChunkID[2], riff.ChunkID[3]);
    printf("ChunkSize \t\t%d\n", riff.ChunkSize);
    printf("Format \t\t\t%c%c%c%c\n", riff.Format[0], riff.Format[1], riff.Format[2], riff.Format[3]);

    printf("\n");

    /**
     *  fmt
     */
    printf("Subchunk1ID \t%c%c%c%c\n", fmt.Subchunk1ID[0], fmt.Subchunk1ID[1], fmt.Subchunk1ID[2], fmt.Subchunk1ID[3]);
    printf("Subchunk1Size \t%d\n", fmt.Subchunk1Size);
    printf("AudioFormat \t%d\n", fmt.AudioFormat);
    printf("NumChannels \t%d\n", fmt.NumChannels);
    printf("SampleRate \t\t%d\n", fmt.SampleRate);
    printf("ByteRate \t\t%d\n", fmt.ByteRate);
    printf("BlockAlign \t\t%d\n", fmt.BlockAlign);
    printf("BitsPerSample \t%d\n", fmt.BitsPerSample);

    printf("\n");

    /**
     *  data
     */
    printf("blockID \t\t%c%c%c%c\n", data.Subchunk2ID[0], data.Subchunk2ID[1], data.Subchunk2ID[2], data.Subchunk2ID[3]);
    printf("blockSize \t\t%d\n", data.Subchunk2Size);

    printf("\n");

//    duration = Subchunk2Size / ByteRate
    printf("duration \t\t%d\n", data.Subchunk2Size / fmt.ByteRate);

}

实例分析

RIFF Chunk

属性 取值 说明
ChunkID “RIFF”
ChunkSize 文件大小为64036字节
Format “WAVE”

 FORMAT Chunk

属性 取值 说明
Subchunk1ID “fmt”
Subchunk1Size 大小为16,表示不包含附加信息
AudioFormat PCM=1,即线性量化
NumChannels 通道数为1,单声道音频
SampleRate 采样率为8000
ByteRate WAV音频数据传送速率为16000
BlockAlign 一个样本的包含所有通道在内的字节数为2
BitsPerSample 样本的数据位数为16bit

 DATA Chunk

属性 取值 说明
Subchunk2ID “data”
Subchunk2Size 语音数据的长度为64000字节
data 太太太多了,略 实际的声音数据

总结

       对WAV格式影响最大的参数是编码格式。采用不同的编码的WAV格式是不同的,PCM是最常见的编码格式,其它的为压缩编码格式,一般很少使用,有的已经废弃。随着人们认识的进步可能还会有新的编码格式出现。今后对WAV文件格式的更多的研究是压缩编码格式。

参考文献

[1]维基百科:WAV

[2]WAV文件格式解析 - CodeAntenna

[3]CSDN:WAV文件格式详解

[4] CSDN:wav音频文件格式解析

[5]博客园:WAVE 文件格式分析 

你可能感兴趣的:(数据压缩作业,其他)