【音视频|wav】wav音频文件格式详解

news2024/11/17 2:28:50

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍wav音频格式🍭
😎金句分享😎:🍭子曰:父母在,不远游,游必有方。 ——《论语·里仁篇》。意思是,父母还健在时,就不要远离他们,如果一定要出远门,也必须告知自己所去的地方。🍭

目录

  • 🎄一、概述
  • 🎄二、wav 文件结构
    • ✨2.1 RIFF 规范
    • ✨2.2 wav 文件结构
  • 🎄三、PCM 转 WAV 的C语言程序
  • 🎄四、总结


在这里插入图片描述

🎄一、概述

WAV全称是 Waveform Audio File Format,是一种常用的无损音频文件格式,它最初由微软和IBM于1991年共同开发,并成为Windows操作系统中音频文件的标准格式之一。从文件结构来讲,WAV文件格式是微软存储多媒体文件的RIFF规范的子集。本文将详细介绍WAV格式文件的文件结构。

WAV格式文件相对于其他音频文件格式具有以下特点:

  • 无损压缩:WAV文件采用无损压缩算法,不会丢失原始音频数据,能够保留音频的高质量。
  • 高音质:由于无损压缩技术的使用,WAV文件通常具有较高的音质和更好的还原性能。
  • 大文件大小:由于不进行任何压缩,WAV文件相对于其他压缩格式(如MP3)的文件大小较大,占用存储空间较多。
  • 支持多种采样率和位深度:WAV文件支持多种采样率和位深度,可以根据需求选择合适的参数进行录制或处理。
  • 广泛兼容性:WAV格式是一种通用的音频文件格式,几乎所有的音频软件和硬件设备都能够支持读取和播放WAV文件。

在这里插入图片描述

🎄二、wav 文件结构

WAV 文件采用RIFF规范来存储音频数据和相关元信息。这小节我们先了解RIFF规范,然后介绍wav文件的组成部分。

✨2.1 RIFF 规范

RIFF(Resource Interchange File Format)是一种通用的文件格式规范,最初由微软开发,用于在不同应用程序之间交换数据。它以分块的方式组织数据,每个块包含一个标识符和相应的数据内容。

在音视频领域中,wav文件avi文件 都使用了RIFF规范来存储数据。

✨2.2 wav 文件结构

WAV文件通常是一个RIFF文件,整个文件由 44个字节的文件头+音频数据 构成。

这个文件头分为三个部分:RIFF块(下图紫色部分)、指定数据格式的fmt块(下图绿色部分)、包含实际样本数据的data块(下图砖红色部分)。

在这里插入图片描述

  • RIFF块:
    • 1、ChunkID:包含ASCII格式的字母RIFF
    • 2、ChunkSize:这个数值ChunkSize后面所有数据的大小。可以是整个文件的大小减去8个字节;也可以是36+SubChunk2Size;还可以是4 + (8+SubChunk1Size) + (8+SubChunk2Size)
    • 3、Format:包含字母WAVE

  • fmt块:
    • Subchunk1ID:包含字母fmt,表示fmt块;
    • Subchunk1Size:这个数值是Subchunk1Size后所有fmt块数据的大小,对于PCM数据来说,这个值固定为16;
    • AudioFormat:如果音频数据是PCM,这个值为 11 以外的值表示一些压缩形式;
    • NumChannels:声道数,Mono = 1, Stereo = 2 等等;
    • SampleRate:采样率,8000,44100,48000 等;
    • ByteRate:每秒的字节数,采样率 * 声道数 * 样本位数 / 8
    • BlockAlign:每个声道取一个样本的字节数之和,声道数 * 样本位数 / 8
    • BitsPerSample:样本位数,每个样本占用的bit位个数。8bit、16bit 等等。

  • data块:
    • Subchunk2ID:包含字母data,表示data块;
    • Subchunk2Size:这个数值是Subchunk2Size后所有数据的字节数,也就是实际音频数据的总字节数。
    • Data:实际的音频数据;

在这里插入图片描述

🎄三、PCM 转 WAV 的C语言程序

// pcm2wac.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * Convert PCM16LE raw data to WAVE format
 * @param pcmpath      Input PCM file.
 * @param channels     Channel number of PCM file.
 * @param sample_rate  Sample rate of PCM file.
 * @param wavepath     Output WAVE file.
 */
int simplest_pcm16le_to_wave(const char *pcmpath,int channels,int sample_rate,const char *wavepath)
{
 
	typedef struct WAVE_HEADER{  
		char         fccID[4];        
		unsigned   int    dwSize;            
		char         fccType[4];    
	}WAVE_HEADER;  
 
	typedef struct WAVE_FMT{  
		char         fccID[4];        
		unsigned   int       dwSize;            
		unsigned   short     wFormatTag;    
		unsigned   short     wChannels;  
		unsigned   int       dwSamplesPerSec;  
		unsigned   int       dwAvgBytesPerSec;  
		unsigned   short     wBlockAlign;  
		unsigned   short     uiBitsPerSample;  
	}WAVE_FMT;  
 
	typedef struct WAVE_DATA{  
		char       fccID[4];          
		unsigned int dwSize;              
	}WAVE_DATA;  
 
 
	if(channels==0||sample_rate==0){
		channels = 2;
		sample_rate = 44100;
	}
	int bits = 16;
 
    WAVE_HEADER   pcmHEADER;  
    WAVE_FMT   pcmFMT;  
    WAVE_DATA   pcmDATA;  
 
    unsigned   short   m_pcmData;
    FILE   *fp,*fpout;  
 
	fp=fopen(pcmpath, "rb");
    if(fp == NULL) {  
        printf("open pcm file error\n");
        return -1;  
    }
	fpout=fopen(wavepath,   "wb+");
    if(fpout == NULL) {    
        printf("create wav file error\n");  
        return -1; 
    }        
	//WAVE_HEADER
    memcpy(pcmHEADER.fccID,"RIFF",strlen("RIFF"));                    
    memcpy(pcmHEADER.fccType,"WAVE",strlen("WAVE"));  
    fseek(fpout,sizeof(WAVE_HEADER),1); 
	//WAVE_FMT
    pcmFMT.dwSamplesPerSec=sample_rate;  
    pcmFMT.dwAvgBytesPerSec=pcmFMT.dwSamplesPerSec*sizeof(m_pcmData);  
    pcmFMT.uiBitsPerSample=bits;
    memcpy(pcmFMT.fccID,"fmt ",strlen("fmt "));  
    pcmFMT.dwSize=16;  
    pcmFMT.wBlockAlign=2;  
    pcmFMT.wChannels=channels;  
    pcmFMT.wFormatTag=1;  
 
    fwrite(&pcmFMT,sizeof(WAVE_FMT),1,fpout); 
 
    //WAVE_DATA;
    memcpy(pcmDATA.fccID,"data",strlen("data"));  
    pcmDATA.dwSize=0;
    fseek(fpout,sizeof(WAVE_DATA),SEEK_CUR);
 
    fread(&m_pcmData,sizeof(unsigned short),1,fp);
    while(!feof(fp)){  
        pcmDATA.dwSize+=2;
        fwrite(&m_pcmData,sizeof(unsigned short),1,fpout);
        fread(&m_pcmData,sizeof(unsigned short),1,fp);
    }  
 
    pcmHEADER.dwSize=44+pcmDATA.dwSize;
 
    rewind(fpout);
    fwrite(&pcmHEADER,sizeof(WAVE_HEADER),1,fpout);
    fseek(fpout,sizeof(WAVE_FMT),SEEK_CUR);
    fwrite(&pcmDATA,sizeof(WAVE_DATA),1,fpout);
	
	fclose(fp);
    fclose(fpout);
 
    return 0;
}

int main()
{
	simplest_pcm16le_to_wave("48000Hz-s16le-2ch-ChengDu.pcm",2,48000,"output_nocturne.wav");
	return 0;
}

代码来自:https://blog.csdn.net/leixiaohua1020/article/details/50534316

在这里插入图片描述

🎄四、总结

本文详细介绍wav音频文件的结构,以及提供了pcm转wav的C语言代码。

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

参考资料:
WAVE PCM soundfile format
视音频数据处理入门:PCM音频采样数据处理
https://blog.csdn.net/xianrenli38/article/details/93621344

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

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

相关文章

取石子

每一堆数量都>1的话可以把合并操作和取石子看成一种操作&#xff0c;总操作数就是sumn-1&#xff0c;为奇数就是Alice先手必胜&#xff0c;哪怕有一堆是2&#xff0c;Bob取后变为1&#xff0c;Alice也可以通过合并操作让1变成>1的数 可以分成两大板块a、b, a中方石子个数…

VM搭建虚拟机2(自定义安装)

文章目录 自定义安装选择你的centos下载目录设置用户名密码自定义安装目录注意&#xff0c;尽量别再同一位置安装虚拟机设置处理器数量内存根据所需配置&#xff08;默认1G&#xff09;NAT按需设置磁盘大小点击完成即可等待安装即可 VMware、centos、典型安装 自定义安装 选择你…

分治法求解棋盘覆盖问题

分治法求解棋盘覆盖问题 如何应用分治法求解棋盘覆盖问题呢&#xff1f;分治的技巧在于如何划分棋盘&#xff0c;使划分后的子棋盘的大小相同&#xff0c;并且每个子棋盘均包含一个特殊方格&#xff0c;从而将原问题分解为规模较小的棋盘覆盖问题。 基本思路 棋盘覆盖问题是…

Python算法练习 10.30

leetcode 841 钥匙和房间 有 n 个房间&#xff0c;房间按从 0 到 n - 1 编号。最初&#xff0c;除 0 号房间外的其余所有房间都被锁住。你的目标是进入所有的房间。然而&#xff0c;你不能在没有获得钥匙的时候进入锁住的房间。 当你进入一个房间&#xff0c;你可能会在里面找…

生产环境使用boost::fiber

简介 boost::fiber是一类用户级线程&#xff0c;也就是纤程。其提供的例子与实际生产环境相距较远&#xff0c;本文将对其进行一定的改造&#xff0c;将其能够投入到生产环境。 同时由于纤程是具有传染性的&#xff0c;使用纤程的代码里也全部要用纤程封装&#xff0c;本文将对…

canvas绘制签名并保存

实现签名的三个关键方法&#xff1a; 1.mousedown&#xff1a;当鼠标按下时开始绘制签名。 2.mousemove&#xff1a;鼠标移动时持续绘制。 3.mouseup&#xff1a;鼠标抬起时结束绘制。 html&#xff1a; <div class"setSign"><canvasref"canvas&q…

驱动开发7 基于GPIO子系统编写LED驱动,编写应用程序进行测试设置定时器,5秒钟打印一次hello world

驱动代码 #include <linux/init.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/gpio.h> #include <linux/timer.h> #include <linux/of_irq.h> #include <linux/interrupt.h…

最新Ubuntu20.04安装教程(图文)

总的来说&#xff0c;安装Ubantu包含以下三个步骤&#xff1a; 一、安装虚拟机 二、Ubuntu镜像下载 三、虚拟机配置 一、安装虚拟机 选择安装VMware Workstation&#xff0c;登录其官网下载安装包&#xff0c;链接如下&#xff1a; 下载 VMware Workstation Pro | CN 下载…

从原理到实践,深入理解CPU缓存一致性

1 存储体系结构 速度快的存储硬件成本高、容量小&#xff0c;速度慢的成本低、容量大。为了权衡成本和速度&#xff0c;计算机存储分了很多层次&#xff0c;扬长避短&#xff0c;有寄存器、L1 cache、L2 cache、L3 cache、主存&#xff08;内存&#xff09;和硬盘等。图1 展示…

掌握组件缓存:解开Vue.js中<keep-alive>的奥秘

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

自己的开题ppt分享 做的很烂 请喷我 谢谢

研究背景与意义 给出自己要做的东西 钢铁异常检测方法 为需求 技术挑战性 回答以下这几个问题 所做任务在技术上的挑战性是什么&#xff1f; &#xff08;数学描述&#xff1a;数据层面、任务层面或者模型层面等&#xff09; 什么原因导致这个挑战&#xff1f; 它为什么是…

程序环境+预处理

&#x1f493;博客主页&#xff1a;江池俊的博客⏩收录专栏&#xff1a;C语言进阶之路&#x1f449;专栏推荐&#xff1a;✅C语言初阶之路 ✅数据结构探索✅C语言刷题专栏&#x1f4bb;代码仓库&#xff1a;江池俊的代码仓库&#x1f389;欢迎大家点赞&#x1f44d;评论&#x…

设计模式:解释器模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

上一篇《责任链模式》 下一篇《设计模式学习顺序》 简介&#xff1a; 解释器模式&#xff0c;它是一种行为型模式&#xff0c;它给定一门语言&#xff0c;定义其文法的一种表示&#xff0c;并定义一个解释器&#…

KDL库在VS2022上配置博客

一、前提准备 1.下载kdl库和kdl所依赖的eigen库&#xff0c; &#xff08;在kdl库中找到FindEigen3可以查看里面所需要的Eigen3库所需要的最低版本&#xff09;下载完成后重命名压缩包为kdl和eigen3之后解压缩文件 2.安装好cmake工具 二、建立build目录 ..\kdl\orocos_kine…

SpringCloud(一) 服务架构的演变及注册RestTemplate实现服务的远程调用

目录 一, 服务架构的演变 1.1 单体架构 1.2 分布式架构 1.3 微服务 1.4 SpringCloud 二, 服务拆分和远程调用 2,1 服务拆分原则 2.2 服务拆分示例 2.3 创建相应数据库 2.4 实现远程调用示例 1, 更改需求 2, 注册RestTemplate实现远程调用 2.5 服务消费者和提供者 一…

Spring的条件注解,一篇文章盘得清清楚楚明明白白

前言 在Spring中&#xff0c;条件注解可根据特定的条件来决定是否创建或配置Bean&#xff0c;这些条件可以基于类、属性、环境等因素。通过使用条件注解&#xff0c;我们可以在Spring容器中更加灵活地管理和控制组件的创建和注入&#xff0c;帮助我们更加灵活地管理和控制Bean…

3.5每日一题(求齐次方程组的特解)

1、判断类型选择方法&#xff1a;看出为齐次方程&#xff08;次幂都一样&#xff09; 2、 化为变量可分离&#xff1b;按变量可分离的方法求出通解&#xff08;此题等式两边同时除以 x &#xff09; 3、把x1&#xff0c;y0带入通解&#xff0c;定常数C&#xff0c;求出特解 …

Android 优质的UI组件汇总

1、RuleView &#xff1a;Android自定义标尺控件(选择身高、体重等) 链接&#xff1a;https://github.com/cStor-cDeep/RuleView 2、DashboardView &#xff1a;Android自定义仪表盘View&#xff0c;仿新旧两版芝麻信用分、炫酷汽车速度仪表盘 链接&#xff1a;https://git…

业务连续性的重要性及关键因素

在今天的竞争激烈的商业环境中&#xff0c;保持业务连续性至关重要。业务连续性是指企业能够在面对各种不可预测的挑战和灾难情况下&#xff0c;保持运营&#xff0c;提供产品和服务&#xff0c;以确保客户满意度和可持续发展。本文将探讨业务连续性的重要性、关键因素和最佳实…

探营云栖大会:蚂蚁集团展出数字人全栈技术,三大AI“机器人”引关注

一年一度的科技盛会云栖大会将于10月31日正式开幕。30日&#xff0c;记者来到云栖大会展区探营&#xff0c;提前打卡今年上新的“黑科技”。 记者在蚂蚁集团展馆看到&#xff0c;超1亿人参与的亚运“数字火炬手”全栈技术首次公开展示&#xff0c;还可体验基于数字人技术的“数…