wav头文件解析

本文深入解析WAV格式文件的构成,包括文件头和实体音频数据的作用,以及如何使用不同方法正确书写WAV文件头,确保音频文件能被正确播放。

什么是wav格式

网上介绍wav 格式的文章已经很多了 为什么还要写这个文章

  • 练手 发帖子比较少,找到适合自己写作风格的方式 写帖子 为以后做准备
  • 整理自己的知识库, 这个知识点之前习得的过程比较零散.整理一下,心里有个底,思路上可以完善的将各个零散的点合并起来,便于记忆
  • 好记性不如烂笔头
  • 帮助后来者理解该知识点,每个知识点,每个人理解的方式过程不一样,没准有那么一类人,就喜欢我的心路风格呢

.WAV 格式文件 为微软公司(Microsoft)开发的一种声音文件格式.

WAV是最接近无损的音乐格式,所以文件大小相对也比较大.

那么为什么 wav格式是如何存储的呢

文件构成

事实上 wav格式文件分为两部分,文件头+音频文件两部分
wav文件格式样式

文件头(也叫头文件)

作用: 告诉播放器(为什么是告诉播放器,而不是告诉 word打开,应为.wav后缀的文件默认是用播放器打开的,你要强制用word去打开,我也没办法),这个文件 中的数据 如何使用, 用什么样的方法 才能正确的进行播放.
就像迷宫门口的建筑图纸,还是带gps定位的那种,可以指引需要的人穿过 整个座迷宫,还顺便知道了迷宫的构造

文件实体:

作用: 具体播放的内容 就是迷宫本身
当播放器 拿着迷宫门口的建筑图纸后,获取迷宫中的信息,那是分分钟的事.

wav头文件

头文件 听起来高大上,说白了依然是二进制流.(废话,所有数据都可以搞成二进制流) 其本质是按照一定格式规范 写的一个固定 说明书,
就像图书,有个目录,有序,有引言.
wav头文件有44个字节
在这里插入图片描述
如图[1][1]:图片来自http://soundfile.sapp.org/doc/WaveFormat/

wav头文件描述
如图,这就是头文件中的信息
以及相互之间的关系

写头文件 方法一

需要注意的是大端存储以及小端存储.

这个涉及到cpu的规则,我不太了解.
在实际应用这个知识点时,
涉及到 RandomAccessFile 的write 方法
具体去看api了

从源码中可以看到

写头文件时,writeInt,writeShort,会将其中的序列翻过来,变为大端

/**
     * Writes an {@code int} to the file as four bytes, high byte first.
     * The write starts at the current position of the file pointer.
     *
     * @param      v   an {@code int} to be written.
     * @exception  IOException  if an I/O error occurs.
     */
    public final void writeInt(int v) throws IOException {
        write((v >>> 24) & 0xFF);
        write((v >>> 16) & 0xFF);
        write((v >>>  8) & 0xFF);
        write((v >>>  0) & 0xFF);
        //written += 4;
    }

而我们需要的顺序是

 	 
        write((v >>>  0) & 0xFF);
        write((v >>>  8) & 0xFF);
      	write((v >>> 16) & 0xFF);
      	write((v >>> 24) & 0xFF);
     
        

因此在使用RandomAccessFile .writeInt,和writeByet时需要手动想将其倒序,然后调用api,就负负得正了

开始写录音文件前调用

/**
	 * @param weikuan    位宽
	 * @param nChannels  通道数
	 * @param sampleRate 采样率
	 * @throws IOException
	 */
	private void writeHead(short weikuan, short nChannels, int sampleRate) throws IOException {
		RandomAccessFile rand;

		int byteofSeconds = weikuan * nChannels * sampleRate/8;
		rand = randomAccessFile;
		//设置文件大小为0, 防止未知情况导致 该文件已经存在
		rand.setLength(0);
		//初始化wav文件的头文件

		/* RIFF header */
		rand.writeBytes("RIFF"); // riff id
		rand.writeInt(0); // riff chunk size *PLACEHOLDER*
		rand.writeBytes("WAVE"); // wave type

		/* fmt chunk */
		rand.writeBytes("fmt "); // fmt id
		rand.writeInt(Integer.reverseBytes(16)); // fmt chunk size
		rand.writeShort(Short.reverseBytes((short) 1)); // AudioFormat,1 for PCM
		rand.writeShort(Short.reverseBytes(nChannels));// Number of channels, 1 for mono, 2 for stereo
		rand.writeInt(Integer.reverseBytes(sampleRate)); // Sample rate 采样率
		rand.writeInt(Integer.reverseBytes(byteofSeconds));//Byte rate,波形数据传输速率(每秒平均字节数)
		// SampleRate*NumberOfChannels*BitsPerSample/8
		//每次采样大小 单位byte
		rand.writeShort(Short.reverseBytes((short) (nChannels * weikuan / 8))); // Block align,
		// NumberOfChannels*BitsPerSample/8
		rand.writeShort(Short.reverseBytes(weikuan)); // Bits per sample

		/* data chunk */
		rand.writeBytes("data"); // data id
		rand.writeInt(0); // data chunk size *PLACEHOLDER*
	}


录完音后,补充 头文件中的内容


	private void writeInsertHead() throws IOException {
		RandomAccessFile rand = randomAccessFile;

		rand.seek(4); // riff chunk size
//			rand.writeInt(Integer.reverseBytes((int) (rand.length() - 8)));
		rand.writeInt(Integer.reverseBytes((int) (dataSize + 36)));
		rand.seek(40); // data chunk size
//			rand.writeInt(Integer.reverseBytes((int) (rand.length() - 44)));
		rand.writeInt(Integer.reverseBytes((int) (dataSize)));

		onSuccess(rand.length());
	}


写头文件 方法二

当然 如果搞不清上面的这个问题. 写头文件也可以直接使用writebyte,在录音结束时,返回到开口预留的44个字节中 从seek(0)开始,一次写入 44个字节的数组,就可以避开这个问题.

/**
	 * @param totalAudioLen 音频数据总大小
	 * @param sampleRate    采样率
	 * @param byteRate      位元(组)率(每秒的数据量 单位 字节/秒)   采样率(44100之类的) * 通道数(1,或者2)*每次采样得到的样本位数(16或者8) / 8;
	 * @param nChannels     声道数量
	 * @param weikuan       位宽
	 * @throws IOException
	 */
	private void writeHead(int totalAudioLen, int sampleRate, int byteRate, int nChannels, int weikuan) throws
			IOException {

		RandomAccessFile rand = randomAccessFile;


		long totalDataLen = totalAudioLen + 36;
	

		//长度
		print(rand.readInt());

		rand.seek(0);



		byte[] header = new byte[44];
		header[0] = 'R'; // RIFF/WAVE header
		header[1] = 'I';
		header[2] = 'F';
		header[3] = 'F';
		header[4] = (byte) (totalDataLen & 0xff);
		header[5] = (byte) ((totalDataLen >> 8) & 0xff);
		header[6] = (byte) ((totalDataLen >> 16) & 0xff);
		header[7] = (byte) ((totalDataLen >> 24) & 0xff);
		header[8] = 'W';
		header[9] = 'A';
		header[10] = 'V';
		header[11] = 'E';
		header[12] = 'f'; // 'fmt ' chunk
		header[13] = 'm';
		header[14] = 't';
		header[15] = ' ';
		header[16] = 16; // 4 bytes: size of 'fmt ' chunk
		header[17] = 0;
		header[18] = 0;
		header[19] = 0;
		header[20] = 1; // format = 1
		header[21] = 0;
		header[22] = (byte) (nChannels & 0xff);
		header[23] = (byte) ((nChannels >> 8) & 0xff);

		header[24] = (byte) (sampleRate & 0xff);//采样率
		header[25] = (byte) ((sampleRate >> 8) & 0xff);
		header[26] = (byte) ((sampleRate >> 16) & 0xff);
		header[27] = (byte) ((sampleRate >> 24) & 0xff);

		header[28] = (byte) (byteRate & 0xff);//取八位
		header[29] = (byte) ((byteRate >> 8) & 0xff);
		header[30] = (byte) ((byteRate >> 16) & 0xff);
		header[31] = (byte) ((byteRate >> 24) & 0xff);

		int b = weikuan * nChannels / 8;//每次采样的大小
		header[32] = (byte) (b & 0xff); // block align
		header[33] = (byte) ((b >> 8) & 0xff);

		header[34] = (byte) (weikuan & 0xff);//位宽
		header[35] = (byte) ((weikuan >> 8) & 0xff);
		
		header[36] = 'd';//data
		header[37] = 'a';
		header[38] = 't';
		header[39] = 'a';
		header[40] = (byte) (totalAudioLen & 0xff);
		header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
		header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
		header[43] = (byte) ((totalAudioLen >> 24) & 0xff);

		rand.write(header, 0, header.length);


本文参考了
http://soundfile.sapp.org/doc/WaveFormat/
https://www.cnblogs.com/wangguchangqing/p/5957531.html
https://www.jianshu.com/p/90c77197f1d4

<think>好的,我现在需要回答用户的问题:如何用Matlab读取和解析WAV文件的信息。首先,我得回忆一下Matlab中处理音频文件的函数。用户提到了audioread函数,引用[1]中的代码示例显示audioread可以读取WAV文件,并返回数据和采样率。不过用户的问题是关于信息,而audioread可能主要返回的是音频数据,不是信息的具体细节。 接下来,用户提供的引用[3]详细描述了WAV文件的结构,包括RIFF块、文件大小、通道数、采样率等信息。这说明信息包含多个字段,比如文件格式、通道数、采样率、位数等。Matlab是否有函数可以直接获取这些信息呢? 我知道Matlab的audioinfo函数可以返回音频文件的信息,比如NumChannels(通道数)、SampleRate(采样率)、TotalSamples(总样本数)、Duration(时长)、BitsPerSample(每个样本的位数)等。这些信息其实就包含在WAV文件的信息中。因此,使用audioinfo函数可能是获取信息的关键方法。 此外,引用[1]中的示例使用了audioread的'native'参数,这可能允许读取原始数据,但不确定是否影响信息的获取。不过用户的问题主要是信息,所以audioinfo应该更合适。 步骤可能如下: 1. 使用audioinfo函数获取WAV文件的基本信息,包括通道数、采样率、位数等。 2. 如果需要更底层的信息,可能需要手动读取二进制文件,解析结构。但Matlab可能没有直接支持这个的函数,可能需要参考引用[3]中的结构体,用fread逐字段读取。 但用户可能更倾向于使用Matlab内置函数,所以首先推荐audioinfo,如果用户需要更详细的信息,再建议手动解析。 另外,引用[3]提到WAV头文件的结构体定义,比如RIFF、文件大小、fmt块、数据大小等。如果用户需要访问这些特定字段,可能需要用低级文件操作函数,如fopen和fread,按照结构体的偏移量读取每个字段的值。例如,读取前4个字节检查是否是'RIFF',然后接下来的4字节是文件大小,依此类推。 总结回答的结构: 1. 推荐使用audioinfo获取标准信息。 2. 如果需要更底层的信息,提供手动解析的方法,参考结构体定义,逐字节读取。 需要确保步骤正确,语法正确,比如使用正确的函数和参数。同时,引用相关的引用来源,比如引用[1]和引用[3]中的信息。 可能的相关问题包括如何获取音频时长,如何读取多通道数据,或者如何用其他工具解析信息,如Python的wave模块(引用[2]提到)。因此,生成的问题可能涉及这些方面。</think>### 使用Matlab读取和解析WAV文件信息的方法 #### 方法1:通过`audioinfo`函数获取标准信息 Matlab内置的`audioinfo`函数可以直接读取WAV文件的基本信息,包括采样率、通道数、时长等关键参数。 **操作步骤**: 1. 使用`audioinfo('文件路径')`函数读取文件: ```matlab info = audioinfo('C:\Users\CL\Desktop\test.wav'); ``` 2. 解析返回的结构体`info`,包含以下关键字段: - `NumChannels`: 通道数(单声道为1,双声道为2) - `SampleRate`: 采样率(单位:Hz) - `TotalSamples`: 总采样点数 - `Duration`: 音频时长(单位:秒) - `BitsPerSample`: 每个采样点的位数(如16位、24位)[^1][^3]。 #### 方法2:手动解析二进制文件获取完整信息 若需要获取更底层的信息(如RIFF标识、文件大小等),可通过二进制文件操作逐字段读取。 **操作步骤**: 1. 使用`fopen`打开文件并读取前44字节(标准WAV长度): ```matlab fid = fopen('test.wav', 'r'); header = fread(fid, 44, 'uint8=>char'); % 读取信息 fclose(fid); ``` 2. 按WAV结构体逐字段解析(参考引用[3]中的定义): - **RIFF标识**:`header(1:4)` 应为`'RIFF'` - **文件总大小**:`typecast(header(5:8), 'uint32')`(需转换字节序) - **fmt块信息**:`header(13:16)` 应为`'fmt '` - **采样率**:`typecast(header(25:28), 'uint32')` - **数据块大小**:`typecast(header(41:44), 'uint32')`[^3]。 #### 注意事项 - 若文件包含扩展信息(如非PCM格式),长度可能超过44字节,需动态解析。 - 字节序问题:WAV文件采用小端序存储,需使用`typecast`或`swapbytes`正确处理。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值