android 字节转wav,Android音频开发(4):PCM转WAV格式音频

Android 音频开发 目录

项目地址

前面几篇已经介绍了PCM音频文件的录制,这一篇主要介绍下pcm转wav。

一、wav 和 pcm

一般通过麦克风采集的录音数据都是PCM格式的,即不包含头部信息,播放器无法知道音频采样率、位宽等参数,导致无法播放,显然是非常不方便的。pcm转换成wav,我们只需要在pcm的文件起始位置加上至少44个字节的WAV头信息即可。

RIFF

WAVE文件是以RIFF(Resource Interchange File Format, "资源交互文件格式")格式来组织内部结构的

RIFF文件结构可以看作是树状结构,其基本构成是称为"块"(Chunk)的单元.

WAVE文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF WAVE Chunk, Format Chunk, Fact Chunk(可选), Data Chunk。

Fact Chunk 在压缩后或在非PCM编码时存在

二、WAV头文件

所有的WAV都有一个文件头,这个文件头记录着音频流的编码参数。数据块的记录方式是little-endian字节顺序。

90c77197f1d4?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

image

偏移地址

命名

内容

00-03

ChunkId

"RIFF"

04-07

ChunkSize

下个地址开始到文件尾的总字节数(此Chunk的数据大小)

08-11

fccType

"WAVE"

12-15

SubChunkId1

"fmt ",最后一位空格。

16-19

SubChunkSize1

一般为16,表示fmt Chunk的数据块大小为16字节,即20-35

20-21

FormatTag

1:表示是PCM 编码

22-23

Channels

声道数,单声道为1,双声道为2

24-27

SamplesPerSec

采样率

28-31

BytesPerSec

码率 :采样率 * 采样位数 * 声道个数,bytePerSecond = sampleRate * (bitsPerSample / 8) * channels

32-33

BlockAlign

每次采样的大小:位宽*声道数/8

34-35

BitsPerSample

位宽

36-39

SubChunkId2

"data"

40-43

SubChunkSize2

音频数据的长度

44-...

data

音频数据

三、java 生成头文件

WavHeader.class

public static class WavHeader {

/**

* RIFF数据块

*/

final String riffChunkId = "RIFF";

int riffChunkSize;

final String riffType = "WAVE";

/**

* FORMAT 数据块

*/

final String formatChunkId = "fmt ";

final int formatChunkSize = 16;

final short audioFormat = 1;

short channels;

int sampleRate;

int byteRate;

short blockAlign;

short sampleBits;

/**

* FORMAT 数据块

*/

final String dataChunkId = "data";

int dataChunkSize;

WavHeader(int totalAudioLen, int sampleRate, short channels, short sampleBits) {

this.riffChunkSize = totalAudioLen;

this.channels = channels;

this.sampleRate = sampleRate;

this.byteRate = sampleRate * sampleBits / 8 * channels;

this.blockAlign = (short) (channels * sampleBits / 8);

this.sampleBits = sampleBits;

this.dataChunkSize = totalAudioLen - 44;

}

public byte[] getHeader() {

byte[] result;

result = ByteUtils.merger(ByteUtils.toBytes(riffChunkId), ByteUtils.toBytes(riffChunkSize));

result = ByteUtils.merger(result, ByteUtils.toBytes(riffType));

result = ByteUtils.merger(result, ByteUtils.toBytes(formatChunkId));

result = ByteUtils.merger(result, ByteUtils.toBytes(formatChunkSize));

result = ByteUtils.merger(result, ByteUtils.toBytes(audioFormat));

result = ByteUtils.merger(result, ByteUtils.toBytes(channels));

result = ByteUtils.merger(result, ByteUtils.toBytes(sampleRate));

result = ByteUtils.merger(result, ByteUtils.toBytes(byteRate));

result = ByteUtils.merger(result, ByteUtils.toBytes(blockAlign));

result = ByteUtils.merger(result, ByteUtils.toBytes(sampleBits));

result = ByteUtils.merger(result, ByteUtils.toBytes(dataChunkId));

result = ByteUtils.merger(result, ByteUtils.toBytes(dataChunkSize));

return result;

}

}

四、PCM转Wav

WavUtils.java

public class WavUtils {

private static final String TAG = WavUtils.class.getSimpleName();

/**

* 生成wav格式的Header

* wave是RIFF文件结构,每一部分为一个chunk,其中有RIFF WAVE chunk,

* FMT Chunk,Fact chunk(可选),Data chunk

*

* @param totalAudioLen 不包括header的音频数据总长度

* @param sampleRate 采样率,也就是录制时使用的频率

* @param channels audioRecord的频道数量

* @param sampleBits 位宽

*/

public static byte[] generateWavFileHeader(int totalAudioLen, int sampleRate, int channels, int sampleBits) {

WavHeader wavHeader = new WavHeader(totalAudioLen, sampleRate, (short) channels, (short) sampleBits);

return wavHeader.getHeader();

}

}

/**

* 将header写入到pcm文件中 不修改文件名

*

* @param file 写入的pcm文件

* @param header wav头数据

*/

public static void writeHeader(File file, byte[] header) {

if (!FileUtils.isFile(file)) {

return;

}

RandomAccessFile wavRaf = null;

try {

wavRaf = new RandomAccessFile(file, "rw");

wavRaf.seek(0);

wavRaf.write(header);

wavRaf.close();

} catch (Exception e) {

Logger.e(e, TAG, e.getMessage());

} finally {

try {

if (wavRaf != null) {

wavRaf.close();

}

} catch (IOException e) {

Logger.e(e, TAG, e.getMessage());

}

}

RecordHelper.java

private void makeFile() {

mergePcmFiles(recordFile, files);

//这里实现上一篇未完成的工作

byte[] header = WavUtils.generateWavFileHeader((int) resultFile.length(), currentConfig.getSampleRate(), currentConfig.getChannelCount(), currentConfig.getEncoding());

WavUtils.writeHeader(resultFile, header);

Logger.i(TAG, "录音完成! path: %s ; 大小:%s", recordFile.getAbsoluteFile(), recordFile.length());

}

参考链接:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、Java实现wav音频文件换为pcm音频文件(AudioUtils.java) 2、Java实现播放pcm音频文件(PCMPlay.java) WAVwav是一种无损的音频文件格式WAV符合 PIFF(Resource Interchange File Format)规范。所有的WAV都有一个文件头,这个文件头音频流的编码参数。WAV音频流的编码没有硬性规定,除了PCM之外,还有几乎所有支持ACM规范的编码都可以为WAV音频流进行编码。 PCM:PCM(Pulse Code Modulation----脉码调制录音)。所谓PCM录音就是将声音等模拟信号变成符号化的脉冲列,再予以记录。PCM信号是由[1]、[0]等符号构成的数字信号,而未经过任何编码和压缩处理。与模拟信号比,它不易受传送系统的杂波及失真的影响。动态范围宽,可得到音质相当好的影响效果。 简单来说:wav是一种无损的音频文件格式pcm是没有压缩的编码方式。 WAVPCM的关系 WAV可以使用多种音频编码来压缩其音频流,不过我们常见的都是音频流被PCM编码处理的WAV,但这不表示WAV只能使用PCM编码,MP3编码同样也可以运用在WAV中,和AVI一样,只要安装好了相应的Decode,就可以欣赏这些WAV了。在Windows平台下,基于PCM编码的WAV是被支持得最好的音频格式,所有音频软件都能完美支持,由于本身可以达到较高的音质的要求,因此,WAV也是音乐编辑创作的首选格式,适合保存音乐素材。因此,基于PCM编码的WAV被作为了一种中介的格式,常常使用在其他编码的相互换之中,例如MP3换成WMA。 简单来说:pcm是无损wav文件中音频数据的一种编码方式,但wav还可以用其它方式编码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值