草庐IT

WAV格式文件分析

河合 曜 2023-08-01 原文

WAV格式文件分析

目录


概述

WAV格式目前是最常见的音频文件格式之一,是微软公司专门为旗下Windows操作系统开发的一种标准数字音频文件。WAV格式文件最早于1991年8月出现在Windows 3.1操作系统上,文件扩展名为*.wav,是WaveForm的简写,也称为波形文件,可直接存储声音波形,且还原的波形曲线十分逼真。

本质上,WAV文件格式是一种存储声音波形的数字音频格式,是由微软公司和IBM联合设计的,经过了多次修订,可用于Windows,Macintosh,Linux等多种操作系统。WAV支持多种音频数字、取样频率和声道,标准格式化的WAV文件和CD格式一样,也是44.1kHz的取样频率,16位量化数字,因此声音文件质量和CD相差无几。同时,WAV格式文件还有真实记录自然声波形、数据压缩程度低、数据量相对较大等特点。

在本文中,作者则以多媒体文件的“容器”概念出发,针对WAV格式文件的文件结构、数据组织结构、元数据信息等方面作简要的说明。


一、WAV格式文件

1、波形声音文件格式 WAV

WAV即波形声音文件格式 (Waveform Audio File Format,简称WAVE,因后缀为*.wav故简称WAV文件),其采用RIFF(Resource Interchange File Format,资源互换文件格式)结构,并符合(RIFF)规范,用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持。Wave格式支持MSADPCM、CCITT A律、CCITT μ律和其他压缩算法,支持多种音频位数、采样频率和声道,是PC机上最为流行的声音文件格式;但由于“无损”的特点,WAV文件格式所占用的磁盘空间相对较大(每分钟的音乐大约需要12MB磁盘空间),故此文件格式多用于存储简短的声音片段。同时WAV文件格式通常用来保存PCM格式的原始音频数据,所以通常被称为无损音频。但是严格意义上来讲,WAV也可以存储其它压缩格式的音频数据。

2、音频文件参数简介

对于形如44100HZ 16bit stereo 或者 22050HZ 8bit mono参数描述的音频文件,其蕴含的文件参数包括:

  • 采样率:声音信号在“模→数”转换过程中单位时间内采样的次数。
  • 采样值(采样精度):每一次采样周期内声音模拟信号的积分值。
    同时,每个采样数据记录的是振幅, 而采样精度取决于储存空间的大小。

对于单声道(mono)文件,采样数据为8位的短整数,同时其采样精度有:

  • 1 字节(8bit) 只能记录 256 个数, 也就是只能将振幅划分成 256 个等级;
  • 2 字节(16bit) 可以细到 65536 个数, 即为 CD 标准;
  • 4 字节(32bit) 能把振幅细分到 4294967296 个等级, 实在是没必要了。

对于双声道立体声(stereo)文件,每次采样数据为一个16位的整数(int),且采样是双份的,也为单声道文件的两倍。采样数据中高八位(左声道)和低八位(右声道)分别代表两个声道。

由于wav格式文件本质上为音频文件,即可根据文件的大小、采样频率和采样大小估算文件的播放长度。


二、文件结构

WAV文件遵循RIFF规则,其数据体以区块(Chunk)为最小单位进行存储,而整个文件则以文件头进行标识。其结构示意如下表与图。

WAV HeadData Chunk……Data Chunk

1、WAV文件的文件头

PNG格式文件的文件头是由位固定的字节进行描述,其大小占44个字节。

char *header = new char[44]; //wav文件头

其中前四字节为资源交换文件标志“RIFF”。

header[0] ='R';
header[1] ='I';
header[2] ='F';
header[3] ='F';	

后40字节则分别声明音频文件参数,包括:

int file_size;      //文件大小
int channel;         //声道数
int sample_rate;   //采样率
int bit_rate;      //比特率
int sample_bit;    //每个采样点的位数
int data_size;     //pcm数据的大小

2、WAV文件的数据体

WAV文件的数据体区块一般由3个区块组成:RIFF Chunk、Format Chunk和Data Chunk。示意如下表。另外,文件中还可能包含一些可选的区块,如:Fact Chunk、Cue Points Chunk、Playlist Chunk、Associated Data List Chunk等。

RIFF ChunkFormat ChunkData Chunk……

三、WAV格式文件数据体结构

目前可知,WAV音频文件的内部数据是以数据体为单位在文件头后进行存储,其数据体内部数据由PCM(脉冲编码调制)格式表示的样本组成。每个区块则均有表征数据块特点的ID、Size等码段,同时也有不同码段内容。

1、RIFF Chunk区块

RIFF数据块长度为12字节,共有三种码段。如下表所示。

名称偏移地址字节数内容
ID0x004RIFF (0x52494646)
Size0x044fileSize - 8
Type0x084WAVE(0x57415645)

其中:

  • RIFF Chunk类型数据块以RIFF的ID部分为标识,说明数据块类型;
  • Size是整个文件的长度减去ID和Size的长度,表征包含Type字段在内的数据块长度;
  • Type是WAVE表示后面需要Format和Data两个子区块。

2、Format Chunk区块

名称偏移地址字节数内容
ID0x004'fmt ’ (0x666D7420)
Size0x04416
AudioFormat0x082音频格式
NumChannels0x0A2声道数
SampleRate0x0C4采样率
ByteRate0x104每秒数据字节数
BlockAlign0x142数据块对齐
BitsPerSample0x162采样位数

其中:

  • 此类型数据块以“fmt”的ID为标识,说明数据块类型;
  • Size表示该区块数据不包含ID和Size的长度;
  • AudioFormat表示Data区块存储的音频数据的格式,PCM音频数据的值为1;
  • NumChannels表示音频数据的声道数,其中1表示单声道,2表示双声道;
  • SampleRate表示音频数据的采样率;
  • ByteRate每秒数据字节数,计算公式为

ByteRate = SampleRate × NumChannels × BitsPerSample / 8

  • BlockAlign每个采样所需的字节数,计算公式为NumChannels*BitsPerSample/8;
  • BitsPerSample每个采样存储的bit数,其中8表示8bit,16表示16bit,32表示32bit。

3、DATA区块

DATA区块为音频文件存储实际的数据。

名称偏移地址字节数内容
ID0x004‘data’ (0x64617461)
Size0x044-
Data0x08-音频数据

其中:

  • Size表示音频数据的长度,不包含ID和Size数据段,且对于采样率为ByteRate的音频文件数据来说,其计算公式为

Size = ByteRate × seconds

  • Data为实际存储的完整音频数据。

总结

通过对WAV格式文件的文件结构、数据结构以及元数据表示方法的简要学习,作者对WAV格式媒体文件有了进一步的认识。同时,通过分析WAV格式文件内部数据的表示内容,此过程中也对音频文件的各项参数指标有了更深的了解。


参考及引用材料

[1] WAV文件格式详解
[2] WAVE PCM Sound File Format
[3] wav文件格式分析
[4] WAV 百度百科

有关WAV格式文件分析的更多相关文章

  1. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  6. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  9. Ruby 写入和读取对象到文件 - 2

    好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信

  10. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

随机推荐