c语言音频.wav读写示例

news2024/11/15 6:49:10

1 .wav格式说明

一. RIFF 概念

在 Windows 环境下,大部分的多媒体文件都依循着一种结构来存放信息,这种结构称为"资源互换文件格式"(Resources lnterchange File Format),简称 RIFF。例如声音的 WAV 文件、视频的 AV1 文件等等均是由此结构衍生出来的。RIFF 可以看做是一种树状结构,其基本构成单位为 chunk,犹如树状结构中的节点,每个 chunk 由"辨别码"、“数据大小"及"数据"所组
成。
在这里插入图片描述
辨别码由 4 个 ASCII 码所构成,数据大小则标示出紧跟其后数据的长度(单位为 Byte),而数据大小本身也用掉 4 个 Byte,所以事实上一个 chunk 的长度为数据大小加 8。一般而言,chunk 本身并不允许内部再包含 chunk,但有两种例外,分别为以"RIFF"及"L1ST"为辨别码的chunk。而针对此两种 chunk,RIFF 又从原先的"数据"中切出 4 个 Byte。 此 4 个 Byte 称为"格式辨别码”,然而 RIFF 又规定文件中仅能有一个以"RIFF"为辨别码的 chunk。
在这里插入图片描述
只要依循此一结构的文件,我们均称之为 RIFF 档。此种结构提供了一种系统化的分类。如果和 MS 一 DOS 文件系统作比较,"RIFF"chunk 就好比是一台硬盘的根目录,其格式辨别码便是此硬盘的逻辑代码(C:或 D:),而"L1ST"chunk 即为其下的子目录,其他的 chunk 则为一般的文件。至于在 RIFF 文件的处理方面,微软提供了相关的函数。视窗下的各种多媒体文件格式就如同在磁盘机下规定仅能放怎样的目录,而在该目录下仅能放何种数据。

二. WAV 文件格式

WAVE 文件是非常简单的一种 RIFF 文件,它的格式类型为"WAVE"。RIFF 块包含两个子块,这两个子块的 ID 分别是"fmt"和"data",其中"fmt"子块由结构 PCMWAVEFORMAT 所组成,其子块的大小就是 sizeofof(PCMWAVEFORMAT),数据组成就是 PCMWAVEFORMAT 结构中的数据。
在这里插入图片描述
PCMWAVEFORMAT 结构定义如下:

typedef struct
{ 
 WAVEFORMAT wf; /波形格式; 
 WORD wBitsPerSample; //WAVE 文件的采样大小; 
} PCMWAVEFORMAT; 
//WAVEFORMAT 结构定义如下:
typedef struct
{ 
 WORD wFormatag; //编码格式,包括 WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM 等 
 WORD nChannls; //声道数,单声道为 1,双声道为 2; 
 DWORD nSamplesPerSec; //采样频率; 
 DWORD nAvgBytesperSec; //每秒的数据量; 
 WORD nBlockAlign; //块对齐; 
} WAVEFORMAT; 

"data"子块包含 WAVE 文件的数字化波形声音数据,其存放格式依赖于"fmt"子块中wFormatTag 成员指定的格式种类,在多声道 WAVE 文件中,样本是交替出现的。如 16bit 的单声道 WAVE 文件和双声道 WAVE 文件的数据采样格式分别如图四所示:
在这里插入图片描述
在这里插入图片描述

2 c语言读写.wav文件示例

下面是一个简单的C语言示例,用于读取和写入WAV音频文件。这段代码展示了如何打开WAV文件、读取其头部信息、读取音频数据以及写回一个新的WAV文件。

读取和写入WAV文件示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#pragma pack(1)
typedef struct {
    char riff[4];        // "RIFF"
    unsigned int size;   // Size of the file
    char wave[4];        // "WAVE"
    char fmt[4];         // "fmt "
    unsigned int fmt_size;// Size of format
    unsigned short audio_format; // Audio format
    unsigned short num_channels;  // Number of channels
    unsigned int sample_rate;     // Sample rate
    unsigned int byte_rate;        // Byte rate
    unsigned short block_align;    // Block align
    unsigned short bits_per_sample; // Bits per sample
    char data[4];         // "data"
    unsigned int data_size; // Size of data
} WAVHeader;

void read_wav(const char *filename) {
    FILE *file = fopen(filename, "rb");
    if (!file) {
        perror("Unable to open file");
        return;
    }

    WAVHeader header;
    fread(&header, sizeof(WAVHeader), 1, file);

    printf("RIFF: %.4s\n", header.riff);
    printf("WAVE: %.4s\n", header.wave);
    printf("Format: %.4s\n", header.fmt);
    printf("Channels: %hu\n", header.num_channels);
    printf("Sample Rate: %u\n", header.sample_rate);
    printf("Bits per Sample: %hu\n", header.bits_per_sample);
    printf("Data Size: %u\n", header.data_size);

    // Read audio data
    short *data = malloc(header.data_size);
    fread(data, header.data_size, 1, file);
    fclose(file);

    // Example: Print first 10 samples
    for (int i = 0; i < 10 && i < header.data_size / 2; i++) {
        printf("Sample %d: %d\n", i, data[i]);
    }

    free(data);
}

void write_wav(const char *filename, short *data, unsigned int data_size, int sample_rate, int num_channels) {
    FILE *file = fopen(filename, "wb");
    if (!file) {
        perror("Unable to open file");
        return;
    }

    WAVHeader header;
    strncpy(header.riff, "RIFF", 4);
    header.size = 36 + data_size;
    strncpy(header.wave, "WAVE", 4);
    strncpy(header.fmt, "fmt ", 4);
    header.fmt_size = 16;
    header.audio_format = 1; // PCM
    header.num_channels = num_channels;
    header.sample_rate = sample_rate;
    header.byte_rate = sample_rate * num_channels * (16 / 8);
    header.block_align = num_channels * (16 / 8);
    header.bits_per_sample = 16;
    strncpy(header.data, "data", 4);
    header.data_size = data_size;

    fwrite(&header, sizeof(WAVHeader), 1, file);
    fwrite(data, data_size, 1, file);
    fclose(file);
}

int main() {
    const char *input_filename = "input.wav";
    const char *output_filename = "output.wav";

    read_wav(input_filename);

    // Here you would modify `data` as needed
    short sample_data[10] = {0}; // Example data
    write_wav(output_filename, (short *)sample_data, sizeof(sample_data), 44100, 1);

    return 0;
}

说明
WAV 文件头结构 (WAVHeader):定义了WAV文件的结构,包括文件格式、采样率、声道等信息。
读取 WAV 文件:read_wav 函数打开一个WAV文件,读取其头部信息和音频数据,并打印一些基本信息和前10个音频样本。
写入 WAV 文件:write_wav 函数根据提供的音频数据生成一个新的WAV文件。
主函数:在main函数中,读取input.wav文件并输出到output.wav文件。

使用注意
确保使用的WAV文件符合标准(如PCM编码)。
在实际应用中,可能需要对音频数据进行处理或操作。
编译命令
使用GCC编译:

gcc -o wav_example wav_example.c

在这里插入图片描述

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

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

相关文章

EmguCV学习笔记 VB.Net 2.4 Image类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV学习笔记目录 Vb.net EmguCV学习笔记目录 C# 笔者的博客网址&#xff1a;VB.Net-CSDN博客 教程相关说明以及如何获得pdf教…

【图解秒杀系列】秒杀技术点——秒杀按钮点亮、削峰

【图解秒杀系列】秒杀技术点——秒杀按钮点亮、削峰 秒杀按钮点亮涉及的问题以及解决办法处理流程 削峰答题 & 验证码具体流程 排队 秒杀按钮点亮 在秒杀场景中&#xff0c;秒杀商品页面是需要处理按钮点亮的逻辑的。在秒杀未开始前&#xff0c;按钮置灰&#xff0c;不可点…

POSIX信号量semaphore实现线程同步

POSIX标准定义了信号量接口如下&#xff0c;常常用于线程间同步。 #include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value); int sem_destroy(sem_t *sem); int sem_post(sem_t *sem); int sem_wait(sem_t *sem); sem_init()在sem指向的地址…

微信小程序反编译工具

目录 介绍 工程结构还原 微信开发者工具运行 如何查看当前运行版本? 开启小程序F12 重新打包运行 效果示例 安装 用法 参数说明 获取微信小程序AppID 文件夹名即为AppID 下载地址 介绍 纯Golang实现,一个用于自动化反编译微信小程序的工具,小程序安全利器, 自…

【杂谈】-8个常用的Python图像操作库

8个常用的Python图像操作库 文章目录 8个常用的Python图像操作库1、OpenCV2、Pillow&#xff08;PIL&#xff09;3、Scikit Image4、Numpy5、SciPy6、Mahotas7、SimpleITK8、Matplotlib 在当今世界&#xff0c;数据在每个行业垂直领域中都发挥着至关重要的作用。图像可以是提取…

Redis 操作的原子性及其保证机制

Redis 操作的原子性及其保证机制 1、单命令的原子性2、事务的原子性3、并发操作的考虑4、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; Redis 的操作之所以是原子性的&#xff0c;主要得益于其单线程的执行模型。这种模型确保了每个命…

5.9.8 最优化控制初探——PID参数优化

总目录&#xff1a;http://t.csdnimg.cn/YDe8m 5.9.8 最优化控制初探——PID参数优化 之前在“A_2_PID控制转速例程”例程中&#xff0c;PID参数是手动调节的。然而在已经获得系统完整数学模型的情况下&#xff0c;我们可以使用效率更高的方法&#xff0c;即最优化控制。先来看…

Nios II新建项目

1.Nios II Application and BSP form Template BSP:board support package&#xff08;板级支持包&#xff09; 2.Nios II Sotware Examples SOPC Information File name:选择项目文件夹下的 .sopcinfo 文件 Project name:自定义名称 Project location:Use default locatio…

删除镜像报容器依赖错误

1、删除镜像报容器依赖错误 出现这个错误的原因是因为5303b5323a4c容器使用了此镜像。解决&#xff1a;先停止容器、删除容器、之后再镜像即可。 2、查看镜像对应的容器 # docker ps -a | grep 611a37aa5ffc 3、先停止容器 # docker stop 5303b5323a4c 4、删除容器 # do…

Spring Boot: 2.7.x 至 2.7.18 及更旧的版本,漏洞说明

本文提供的修复指南将帮助开发者有效规避 CVE-2024-38808 和 CVE-2024-38809 的风险。如果你正在使用老版本的 Spring Boot&#xff0c;请尽快参考本文进行修复与升级。 此漏洞来源于spring官网&#xff1a;https://spring.io/blog/2024/08/14/spring-framework-releases-fixe…

flink车联网项目前篇:业务实现1(第67天)

系列文章目录 业务实现 3.1 创建catalog 3.1.1 vvp 3.1.2 mysqlcdc 3.1.2.1 使用限制 3.1.2.2 配置MySQL Catalog 3.1.3 xxxxpm 3.1.3.1 下载Paimon插件 3.1.3.2 在MaxCompute项目中上传Paimon插件 3.1.3.3 创建自定义Catalog类型 3.1.3.5 配置catalog 3.1.4 xxxxx 3.1.4.1 背…

Linux设置yum源为阿里云镜像源

一、验证网络是否可以连接阿里云镜像 #验证网络是否可以连接阿里云镜像 ping mirrors.aliyun.com如果ping不通&#xff0c;则找一台可以连接外网的电脑&#xff0c;ping一下mirrors.aliyun.com&#xff0c;找到mirrors.aliyun.com对应的ip。 二、 手动配置 #删除原yum源 rm -…

微信小程序免费《短视频去水印》

分享一个uniapp开发的微信小程序免费《短视频去水印》小程序 <template><view class"content"><view class"area-wrap"><textarea name"" v-model"state.content" maxlength"800" id"" cols…

接口自动化测试怎么做?该怎么学习

一. 什么是接口测试 顾名思义&#xff0c;接口测试是对系统或组件之间的接口进行测试&#xff0c;主要是校验数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及相互逻辑依赖关系。其中接口协议分为HTTP,WebService,Dubbo,Thrift,Socket等类型&#xff0c;测试类型又主…

《黑神话:悟空》媒体评分解禁 M站均分82

《黑神话&#xff1a;悟空》媒体评分现已解禁&#xff0c;截止发稿时&#xff0c;M站共有43家媒体评测&#xff0c;均分为82分。 部分媒体评测&#xff1a; God is a Geek 100&#xff1a; 毫无疑问&#xff0c;《黑神话&#xff1a;悟空》是今年最好的动作游戏之一&#xff…

linux系统安装mysql服务

linux系统安装mysql服务 1.下载安装包2.下载压缩文件解压安装3. 安装完启动服务4.查看安装密码5.使用上述密码登录6.修改密码7.创建一个root可以在任意主机远程连接数据库8.远程登录成功 1.下载安装包 https://downloads.mysql.com/archives/community/ mysql下载地址 2.下载…

【AI安防】YOLOv8 + OpenVINO2023 + QT5 电子围栏预警系统

引言 电子围栏是一种利用无线通信技术和地理信息系统实现的虚拟边界&#xff0c;用于监控和控制被监控对象的位置。它可以帮助我们实现对特定区域内的自定义对象进行实时检测、定位与跟踪。本文介绍了一种基于YOLOv8 OpenVINO2023 QT5 联合打造的实时高效、多线程、自定义对…

Keepalived简介以及常见用途

一、Keepalived 简介 Keepalived 是一个高可用性&#xff08;HA&#xff09;解决方案&#xff0c;主要用于实现 Linux 系统的负载均衡和故障转移。它最初设计用于与 LVS&#xff08;Linux Virtual Server&#xff09;一起使用&#xff0c;但也可以独立使用&#xff0c;主要功能…

0815,析构函数,拷贝构造函数,赋值运算符函数

来自同济医院的问候 目录 01&#xff1a;对象创建 001.cc 003size.cc 02&#xff1a;对象销毁 004pointer.cc 005destroytime.cc 03&#xff1a;本类型对象的复制 3.1 拷贝构造函数 006cp.cc 007cptime.cc 008recursion.cc 009rightleft.cc 3.2 赋值运算符函数 …

8.15 Day20 Windows服务器(Windows service 2008 R2)上域的搭建 (3)

1、域策略配置 1.1 DC服务端的策略配置 1.1.1 下放权限 由于各部门经理的电脑上并不存在对应的工具&#xff0c;即便授予权限也无法对各自部门进行管理 如果经理只有几个&#xff0c;管理员可以一一为其配置&#xff0c;但如果一个公司有几十个经理&#xff0c;则会变得相当冗…