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

一、wav 和 pcm

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

RIFFWAVE文件是以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字节顺序。

image偏移地址命名内容00-03ChunkId"RIFF"

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

08-11fccType"WAVE"

12-15SubChunkId1"fmt ",最后一位空格。

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

20-21FormatTag1:表示是PCM 编码

22-23Channels声道数,单声道为1,双声道为2

24-27SamplesPerSec采样率

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

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

34-35BitsPerSample位宽

36-39SubChunkId2"data"

40-43SubChunkSize2音频数据的长度

44-...data音频数据

三、java 生成头文件WavHeader.classpublic 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转WavWavUtils.javapublic 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.javaprivate 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());

}

作者:android_赵乐玮

链接:https://www.jianshu.com/p/90c77197f1d4

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

  1. Android 音视频深入 一 AudioRecord录音生成pcm转换为wav(附源码下载)

    本篇项目地址,求star https://github.com/979451341/Audio-and-video-learning-materials/tree/master/AudioRecord ...

  2. 音频开发_如何获取单词的音频mp3文件

    1.gstatic oxford https://ssl.gstatic.com/dictionary/static/sounds/oxford/no--_gb_1.mp3 https://ssl.g ...

  3. 电脑常用音频剪辑软件_如何使用音频剪辑软件,快速剪辑任意格式音频!

    下面介绍音乐剪辑软件使用方法,日程生活中,需要剪辑音乐制作手机铃声,音乐问价转换格式等,音乐剪辑软件是我们常用的编辑工具之一,我么可以把多个文件合并成一个整体,然后对整个文件剪辑,分成多个片段,保留我 ...

  4. 如何使用音频剪辑软件,快速剪辑任意格式音频!

    支持操作系统 widowns vista/ win7/win8 / win10 素材:任意格式的音频文件,mp3,wav ,m4a等 QVE音频剪辑,安装方法:http://www.qvevideo. ...

  5. Android Multimedia框架总结(十七)音频开发基础知识

    原文链接:http://blog.csdn.net/hejjunlin/article/details/53078828 近年来,唱吧,全民K歌,QQ音乐,等成为音频软件的主流力量,音频开发一直是多媒 ...

  6. android音频编辑之音频转换PCM与WAV

    前言 本篇开始讲解在Android平台上进行的音频编辑开发,首先需要对音频相关概念有基础的认识.所以本篇要讲解以下内容: 常用音频格式简介 WAV和PCM的区别和联系 WAV文件头信息 采样率简介 声 ...

  7. 原 android音频编辑之音频转换PCM与WAV

    http://blog.csdn.net/hesong1120/article/details/79043482 本文出自: hesong的专栏 前言 本篇开始讲解在Android平台上进行的音频编辑 ...

  8. Android音频开发(四):音频播放模式

    一.Android音频开发(一):音频基础知识 二.Android音频开发(二):录制音频(WAV及MP3格式) 三.Android音频开发(三):使用ExoPlayer播放音频 四.Android音 ...

  9. Android音频开发(一):音频基础知识

    一.Android音频开发(一):音频基础知识 二.Android音频开发(二):录制音频(WAV及MP3格式) 三.Android音频开发(三):使用ExoPlayer播放音频 四.Android音 ...

  10. MP3格式音频转WAV格式开发

    一.简述 ALSA库仅支持播放WAV格式音频资源,需要播放MP3格式音频就需要用到另一个开源第三方库--lame. 本文档MP3转WAV音频方案使用lame库编译出来的可执行文件放到固件中,然后使用s ...

最新文章

  1. 由浅到深了解工厂模式
  2. Linux中相关知识(atexit(),fork(),粘滞位)
  3. Linux下/var/spool/clientmqueue空间不足的解决
  4. [传奇单机架设]DBC2000数据库使用教程
  5. CSS的三种定位,成功入职字节跳动
  6. SJXXX串口扩展芯片 4串口芯片 UART串口芯片
  7. 程序员面试金典 - 面试题 17.18. 最短超串(双指针+哈希)
  8. 马拉车(manacher)算法——最长回文(hdu3068)
  9. 【华为云技术分享】云图说 | 一张图看懂华为云弹性公网IP
  10. 复数正弦波 matlab,为什么正弦,反正弦函数计算结果会出现复数?
  11. button点击事件不响应的解决方法(子视图大小超过父视图)
  12. shell读取用户输入
  13. linux df命令无反馈,Linux df 命令长时间没有返回
  14. linux系统下 blast,Linux下BLAST安装及BLAST使用
  15. 学计算机的发说说,计算机说说
  16. 微软OpenPai平台部署安装(kubernetes 大数据和深度学习平台安装部署)
  17. 让Atmega8A-PU 支持外部晶振的熔丝设置
  18. 渗透测试面试问题集合(转载自己看,链接在开头)
  19. 佛山市政携手企企通,打造高效协同的云端极速供应链
  20. JAVAWeb01-BS架构简述、HTML

热门文章

  1. 工程院院士李德毅:数据挖掘就是云环境下的搜索服务
  2. 深度 | 这两年的人工智能淘金热 真正赚钱的公司是这几家
  3. 2022年湖南省自考考试学前教育原理练习题及答案
  4. nginx为服务配置访问密码
  5. 基于Android网上相亲交友婚恋app软件设计
  6. 什么是HTML语义化标签?常见HTML语义化标签大全,以及不同标签比较
  7. 二进制详解+集合算法的实现笔记
  8. linux 查看动态库基址,一种动态call地址查找及使用方法 -- QQ游戏斗地主角色版-喊话call定位技巧...
  9. win10 打开 Intel Realsense R200获取深度和彩色视频流 ,并测试python opencv 获取
  10. 机器人空间采样算法研究现状简述