音频—WAV格式及写入wav文件代码实现

1.RIFF规范

FIFF 是 Resource Interchange File Format(资源交换文件格式)的简称。RIFF 是一种文件格式规范,用于在计算机系统之间交换和存储多媒体资源。WAV 文件格式是 Microsoft 的 RIFF 规范的一个子集。

RIFF 规则定义了文件的结构和数据组织方式,包括文件头和数据块。它的结构如下:

RIFF 头部(12 字节):包含四个字节的文件标识符 "RIFF",四个字节的文件长度信息(不包括标识符和长度本身),以及四个字节的文件类型标识符。

数据块:紧随文件头的是一个或多个数据块,每个数据块包含一个四字节的标识符和四个字节的数据长度信息,以及实际的数据内容。

RIFF 还定义了很多不同的文件类型标识符(FourCC),用于标识特定类型的媒体资源,比如音频、视频、图像等。每种类型的文件都有特定的数据块结构和内容。

RIFF 文件格式的特点是灵活和可扩展,它允许在文件中包含不同类型的数据块,并且可以轻松添加新的数据块类型。这使得 RIFF 成为了多媒体资源交换和处理中常用的文件容器格式之一。

2.WAV文件格式

WAV 文件格式是 Microsoft 的 RIFF 规范的一个子集,用于存储多媒体文件。

wav 文件支持多种不同的比特率、采样率、多声道音频。

wav 文件由若干个 RIFF chunk 构成,分别为: RIFF WAVE Chunk,Format Chunk,Fact Chunk(可选),Data Chunk。另外,文件中还可能包含一些可选的区块,如:Fact chunk、Cue points chunk、Playlist chunk、Associated data list chunk 等。

具体格式如下:

文件解析说明:

wav 文件都是由 chunk 组成,chunk 的格式如下:

RIFF chunk:

typedef struct

{

    char ChunkID[4]; //'R','I','F','F'

    unsigned int ChunkSize;

    char Format[4];  //'W','A','V','E'

}riff_chunk;

其中 ChunkSize 代表的是整个 file_size 的大小减去 ChunkID 和 ChunkSize 的大小,即 file_size=ChunkSize+8。

fmt chunk:

typedef struct

{

    char FmtID[4];

    unsigned int FmtSize;

    unsigned short FmtTag;

    unsigned short FmtChannels;

    unsigned int SampleRate;

    unsigned int ByteRate;

    unsigned short BlockAilgn;

    unsigned short BitsPerSample;

}fmt_chunk;

data chunk:

struct DATA_CHUNK

{

    char DataID[4]; //'d','a','t','a'

    unsigned int DataSize;

};

3.wav文件示例分析

linux下 hd 工具查看原始数据:

4.C代码实现wav文件写入保存

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

typedef struct

{

    char ChunkID[4]; //'R','I','F','F'

    unsigned int ChunkSize;

    char Format[4];  //'W','A','V','E'

}riff_chunk;

typedef struct

{

    char FmtID[4]; //'f','m','t'

    unsigned int FmtSize;

    unsigned short FmtTag;

    unsigned short FmtChannels;

    unsigned int SampleRate;

    unsigned int ByteRate;

    unsigned short BlockAilgn;

    unsigned short BitsPerSample;

}fmt_chunk;

typedef struct {

    char DataID[4]; //'d','a','t','a'

    unsigned int DataSize;

} data_chunk;

typedef struct {

    riff_chunk riff;

    fmt_chunk fmt;

    data_chunk data;

} wav_struct;

wav_struct gst_wav;

void init_wav()

{

    gst_wav.riff.ChunkID[0] = 'R';

    gst_wav.riff.ChunkID[1] = 'I';

    gst_wav.riff.ChunkID[2] = 'F';

    gst_wav.riff.ChunkID[3] = 'F';

    

    //计算回写数据长度

    gst_wav.riff.ChunkSize = 0;  //即 ChunkSize = file_size - 8

    gst_wav.riff.Format[0] = 'W';

    gst_wav.riff.Format[1] = 'A';

    gst_wav.riff.Format[2] = 'V';

    gst_wav.riff.Format[3] = 'E';

    gst_wav.fmt.FmtID[0] = 'f';

    gst_wav.fmt.FmtID[1] = 'm';

    gst_wav.fmt.FmtID[2] = 't';

    gst_wav.fmt.FmtID[3] = ' ';

    gst_wav.fmt.FmtSize = 16; //0x10=16 代表PCM编码方式

    gst_wav.fmt.FmtTag = 1; //为1,代表PCM编码方式

    

    //双通道

    gst_wav.fmt.FmtChannels = 2; //通道个数

    gst_wav.fmt.SampleRate = 48077;  //采样频率 48.077KHz

    gst_wav.fmt.ByteRate = 192308; //传输速率,每秒的字节数,计算公式为:SampleRate * FmtChannels * BitsPerSample/8

    gst_wav.fmt.BlockAilgn = 4; //16*2/8

    gst_wav.fmt.BitsPerSample = 16; //采样位数,一般有8/16/24/32/64

    gst_wav.data.DataID[0] = 'd';

    gst_wav.data.DataID[1] = 'a';

    gst_wav.data.DataID[2] = 't';

    gst_wav.data.DataID[3] = 'a';

    

    //计算回写数据长度

    gst_wav.data.DataSize = 0;  //即 DataSize = file_size - 44

}

int main(int argc, char *argv[])

{

    FILE *file;

    char *text = "1237894561238878";  //实际应用中为采集的音频数据

    size_t text_len = strlen(text);

    file = fopen("test.wav", "wb+");

    if (file == NULL) {

        perror("Error opening file");

        return EXIT_FAILURE;

    }

    //写入文件头

    init_wav();

    fwrite(&gst_wav, sizeof(char), sizeof(gst_wav), file);

    //写入音频数据

    fwrite(text, sizeof(char), text_len, file);

    //回写音频文件长度

    int fileSize = ftell(file);

    fseek(file, 4, SEEK_SET);

    fileSize = fileSize - 8;

    fwrite(&fileSize, sizeof(char), sizeof(fileSize), file);

    fseek(file, 40, SEEK_SET);

    fileSize = fileSize + 8 - 44;

    fwrite(&fileSize, sizeof(char), sizeof(fileSize), file);

    fclose(file);

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/835682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【案例分享】校园服务小程序开发经验和主要功能,引领校园生活新方式

随着移动互联网的普及&#xff0c;学生们对于校园生活的需求也在不断增长。校园圈子、校园跑腿、校园外卖、校园服务等小程序等应用应运而生&#xff0c;为学生们提供了更加便捷、高效的生活方式。那么&#xff0c;如何开发一款能够满足学生需求的校园服务小程序呢&#xff1f;…

JavaScript创建日期

创建日期 在JavaScript中创建日期有四种方法 ● 使用new Date() const now new Date(); console.log(now);● 直接输入月、日、年、时间 console.log(new Date(Aug 02 2024 18:05:41));● 也可以输入年月日 console.log(new Date(December 24, 2015));● 直接按照年、月、…

C++入门系列-析构函数

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 析构函数 概念 析构函数&#xff0c;与构造函数功能相反&#xff0c;析构函数不是完成对对象本身的销毁&#xff0c;局部对象销毁工作是由编译器完成的&#xff0c;而对象在销…

基于深度学习的人体关键点检测与姿态识别

文章目录 源码下载地址&#xff1a; 源码地址在视频简介中 深度学习人体关键点检测&#xff0c;姿态识别 界面效果&#xff1a; 界面代码&#xff1a; from PyQt5.QtGui import * from PyQt5.QtWidgets import * from PyQt5.QtGui import * from PyQt5.QtWidgets import * f…

OGG几何内核开发-BRepAlgoAPI_Fuse与BRep_Builder.MakeCompound比较

最近在与同事讨论BRepAlgoAPI_Fuse与BRep_Builder.MakeCompound有什么区别。 一、从直觉上来说&#xff0c;BRepAlgoAPI_Fuse会对两个实体相交处理&#xff0c;相交的部分会重新的生成相关的曲面。而BRep_Builder.MakeCompound仅仅是把两个实体组合成一个新的实体&#xff0c;…

Apache Sqoop:高效数据传输工具搭建与使用教程

目录 引言一、环境准备二、安装sqoop下载sqoop包解压文件 三、配置Sqoop下载mysql驱动拷贝hive的归档文件配置环境变量修改sqoop-env.sh配置文件替换版本的commons-lang的jar包 验证Sqoop安装查看Sqoop版本测试Sqoop连接MySQL数据库是否成功查看数据库查看数据表去除警告信息 四…

【免费】在线识别通用验证码接口

模块优势价格5元1000次&#xff0c;每天免费100次api文档支持 使用量小的完全够用了 <?phpfunction Post_base64($base64_str){$url http://api.95man.com:8888/api/Http/Recog?Taken41******QK&imgtype1&len0 ; $fields array( ImgBase64>$base64_str); $ch…

031.下一个排列Java实现

题意 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。 例如&#xff0c;arr [1,2,3] &#xff0c;以下这些都可以视作 arr 的排列&#xff1a;[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地&#…

移除链表元素(C语言)———链表经典算法题

题目描述&#xff1a;203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 答案展示: 答1&#xff08;遍历删除&#xff09;&#xff1a; /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ struct ListNo…

c++多态机制

多态 在 C 中&#xff0c;多态&#xff08;Polymorphism&#xff09;是一种面向对象编程的重要概念&#xff0c;它允许不同类的对象对同一消息做出不同的响应。具体来说&#xff0c;多态性允许基类的指针或引用在运行时指向派生类的对象&#xff0c;并且根据对象的实际类型来调…

第七届精武杯部分wp

第一部分&#xff1a;计算机和手机取证 1.请综合分析计算机和手机检材&#xff0c;计算机最近一次登录的账户名是 答案&#xff1a;admin 创建虚拟机时直接给出了用户名 2. 请综合分析计算机和手机检材&#xff0c;计算机最近一次插入的USB存储设备串号是 答案&#xff1a…

抖音快速涨粉秘籍解密!从巨量千川投流真实粉丝,快速增粉1000~10万!

随着抖音的风靡&#xff0c;对于众多用户来说&#xff0c;快速涨粉已经成为了追求的目标。在这篇文章中&#xff0c;我们将揭秘全网都在搜索的抖音快速涨1000粉的方法&#xff0c;帮助你打造一个高人气的抖音账号&#xff01;从巨量千川投流到官方真实流量&#xff0c;再到真实…

外卖系统微信小程序支付

微信小程序支付时序图 其中第9.步骤就是微信小程序前端调用wx.requestPayment

QT7_视频知识点笔记_3_自定义控件,事件处理器⭐,定时器,QPainter,绘图设备,不规则窗口

第三天&#xff1a; 自定义控件&#xff0c;事件处理器⭐&#xff0c;定时器&#xff0c;QPainter,绘图设备&#xff0c;不规则窗口实现 1.自定义控件&#xff1a; 创建新的QT控件类&#xff0c;然后再需要使用的地方--》提升为 来使用如何使用基础控件的信号和槽函数&…

1.前端环境搭建

1.安装nodejs 因为我们开发Vue项目需要使用npm命令来创建和启动&#xff0c;安装node.js是为了获得这个命令&#xff0c;目前和使用node.js无关 下载地址&#xff1a;http://nodejs.cn/download/ 下载完之后安装&#xff0c;通过cmd查看是否安装成功 node --version2.创建项目…

探讨 vs2019 c++ 里函数指针与函数类型在使用上的语法区别

&#xff08;1&#xff09;咱们可以用 decltype &#xff08;&#xff09; 来判断函数的类型。但以这个类型定义有用的可指向已存在函数的变量&#xff0c;却行不通。测试如下&#xff1a; 如果把上面的注释去掉会报错&#xff1a; 所以函数类型只有语法意义。但在使用上没有函…

【C语言】/*操作符(下)*/

目录 一、操作符的分类 二、二进制和进制转换 2.1 进制 2.2 进制之间的转换 三、原码、反码、补码 四、单目操作符 五、逗号表达式 六、下标引用操作符[] 七、函数调用操作符() 八、结构体成员访问操作符 8.1 直接访问操作符(.) 8.2 间接访问操作符(->) 九、操作符…

修改el-checkbox样式

一定要在最外层&#xff1b; //未选中框/deep/ .el-checkbox__inner{border-color: #0862a3;}//选中框/deep/ .el-checkbox__input.is-checked .el-checkbox__inner{background-color: #0862a3;border-color: #0862a3;}//未选中框时右侧文字/deep/ .el-checkbox__label{}//选中…

git 推送github 选https遇到登录 openSSH问题

使用https需要使用github令牌token作为密码&#xff0c; 使用SSH不需要登录。 还有一个问题&#xff1a; 创建github仓库后没有quick setup页面解决办法 千万不要点击任何多的操作&#xff01;&#xff01;&#xff01;输入仓库名&#xff0c;直接create&#xff01;&#x…

return语句

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 return语句 一、return语句后面跟表达式二、return无返回三、return返回的值和函数返回类型不一致四、return语句执行后,后方仍然存在代码五、存在分支语句&#xff0c;需考虑…