音频—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;…

react18封装公共请求函数

如果里面要处理比如token过期&#xff0c;跳转登录这种情况的话&#xff0c;官方又说组件外不允许使用Hooks函数&#xff0c;这里可以这样做 使用redux 并新建一个store/index.ts import { configureStore, combineReducers } from reduxjs/toolkit import counterRouter fro…

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));● 直接按照年、月、…

用于接收参数的几个注解

了解四种主要请求方法的传参格式 GET方法&#xff1a; 参数通常通过URL的查询字符串&#xff08;query string&#xff09;传递&#xff0c;形式为key1value1&key2value2。示例&#xff1a;http://example.com/api/resource?key1value1&key2value2 POST方法&#xf…

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] 。 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地&#…

【退役之重学Java】Redis 持久化机制及其选择

一、RDB RDB 持久化机制&#xff0c;对 Redis 中的数据执行周期性的持久化 二、AOF AOF 机制对每条写入命令最为日志&#xff0c;以 append-only 的模式写入一个日志文件中&#xff0c;在 Redis 重启的时候&#xff0c;可以通过回放 AOF 日志中的写入指令&#xff0c;来重新…

SHELL脚本编程----sshd服务启停脚本

题目&#xff1a; 判断 sshd 进程是否运行&#xff0c;如果服务未启动则启动相应服务。 具体代码实现&#xff1a; #!/bin/bashsshd_servicesystemctl is-active sshdif [ "$sshd_service" "active" ]; thenecho "sshd is running....." els…

跟我学C++中级篇——内联补遗

一、内联引出的问题 在将一个内联变量定义到编译单元时&#xff0c;然后再按正常的方式使用时&#xff0c;编译会报一个错误“odr-used”。ODR&#xff0c;One Definition Rule&#xff0c;单一定义规则。在C/C程序中&#xff0c;变量的定义只能有一处&#xff0c;至于ODR的规…

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

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

第十七章 数据管理和组织变革管理练习

单选题 (每题1分,共10道题) 1、 [单选] 以下不属于科特确定了有效传播愿景关键要素是? A:保持简单 B:使用比喻、类比和例子 C:重复,重复,再重复 D:解释表面上的一致性 正确答案:D 你的答案:D 解析:详见书本P469 七大要素,D选项和第六要素 不一致和一致性 2、 …

c++多态机制

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

微信小程序支付全攻略:从零搭建到安全交易【微信支付】

微信小程序支付全攻略&#xff1a;从零搭建到安全交易 在移动互联网时代&#xff0c;微信小程序凭借其便捷性和高效性&#xff0c;成为了众多企业和开发者的心头好。其中&#xff0c;微信支付和小程序支付功能的集成&#xff0c;无疑是提升用户体验、增加商业转化的关键环节。…

1.5编程基础之循环控制 03:均值

描述 给出一组样本数据&#xff0c;计算其均值。 输入 输入有两行&#xff0c;第一行包含一个整数n&#xff08;n小于100&#xff09;&#xff0c;代表样本容量&#xff1b;第二行包含n个绝对值不超过1000的浮点数&#xff0c;代表各个样本数据。 输出 输出一行&#xff0…

CentOS 安装 Portainer

Portainer Community Edition是一个针对容器化应用程序的轻量级服务交付平台&#xff0c;可用于管理 Docker、Swarm、Kubernetes 和 ACI 环境。它的设计理念是部署和使用都简单&#xff0c;该应用程序允许您通过“智能”GUI 和/或广泛的 API 管理所有编排器资源。 1、查询Porta…

第七届精武杯部分wp

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