C++如何读取wav文件中的PCM数据
发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,这篇文章主要介绍C++如何读取wav文件中的PCM数据,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!前言wav文件通常会使用PCM格式数据存储音频,这种格式的数据读取出来直接就
千家信息网最后更新 2025年01月20日C++如何读取wav文件中的PCM数据
这篇文章主要介绍C++如何读取wav文件中的PCM数据,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
前言
wav文件通常会使用PCM格式数据存储音频,这种格式的数据读取出来直接就可以播放,要在wav文件中读取数据,我们首先要获取头部信息,wav的文件结构里面分为多个chunk,我们要做的就是识别这些chunk的信息,获取音频的格式以及数据。
一、如何实现?
首先需要构造wav头部,wav文件音频信息全部保存在头部,我们要做的就是读取wav头部信息,并且记录PCM的相关参数。
1.定义头结构
只定义PCM格式的wav文件头,对于PCM格式的数据只需要下面3个结构体即可。
struct WaveRIFF;struct WaveFormat;struct WaveData;
2.读取头部信息
打开文件后需要读取头部信息,需要获取声音的格式以及数据长度。
WaveRIFF riff;WaveFormat format;WaveData data;int userDataSize;f= fopen(fileName.c_str(), "rb+");//读取头部信息fread(&riff, 1, sizeof(riff), f);fread(&format, 1, sizeof(format),f);//判读头部信息是否正确//略//查找data chunk//略//记录数据起始位置
3.读取数据
获取头部信息后,就知道数据在位置及长度了,只需要直接读文件即可。
//跳到数据起始位置seek(f, _dataOffset, SEEK_SET);
//读取数据fread(buf, 1, bufLength, f);
二、完整代码
完整代码总用有3部分,头结构、WavFileReader.h、WavFileReader.cpp。
1.头结构
#pragma pack(push,1) struct WaveRIFF { const char id[4] = { 'R','I', 'F', 'F' }; uint32_t fileLength; const char waveFlag[4] = { 'W','A', 'V', 'E' }; }; struct WaveFormat { const char id[4] = { 'f','m', 't', ' ' }; uint32_t blockSize = 16; uint16_t formatTag; uint16_t channels; uint32_t samplesPerSec; uint32_t avgBytesPerSec; uint16_t blockAlign; uint16_t bitsPerSample; }; struct WaveData { const char id[4] = { 'd','a', 't', 'a' }; uint32_t dataLength; };#pragma pack(pop)
2.WavFileReader.h
#pragma once#include/************************************************************************* @Project: AC.WavFileWriter* @Decription: wav文件读取工具* 本版本只支持pcm读取,且未处理字节顺序。 riff文件是小端,通常在intel的设备上是没问题的,在java虚拟机上则需要处理。* @Verision: v1.0.0.0* @Author: Xin Nie* @Create: 2019/4/10 11:10:17* @LastUpdate: 2019/4/16 10:45:00************************************************************************* Copyright @ 2019. All rights reserved.************************************************************************/namespace AC { /// /// wav文件读取对象 /// class WavFileReader { public: ////// 构造方法 /// WavFileReader(); ////// 析构方法 /// ~WavFileReader(); ////// 打开wav文件 /// /// 文件名 ///是否打开成功 bool OpenWavFile(const std::string& fileName); ////// 关闭文件 /// void CloseFlie(); ////// 读取音频数据 /// /// 外部缓存 /// 缓存长度 ///读取长度 int ReadData(unsigned char* buf, int bufLength); ////// 设置读取位置 /// /// 读取位置 void SetPosition(int position); ////// 获取读取位置 /// ///读取位置 int GetPosition(); ////// 获取文件长度 /// ///文件长度 int GetFileLength(); ////// 获取音频数据长度 /// ///音频数据长度 int GetDataLength(); ////// 获取声道数 /// ///声道数 int GetChannels(); ////// 获取采样率 /// ///采样率,单位:hz int GetSampleRate(); ////// 获取位深 /// ///位深,单位:bits int GetBitsPerSample(); private: void* _file = nullptr; uint32_t _fileLength = 0; uint32_t _dataLength = 0; int _channels = 0; int _sampleRate = 0; int _bitsPerSample = 0; int _dataOffset = 0; };}
3.WavFileReader.cpp
#include"WavFileReader.h"namespace AC { WavFileReader::WavFileReader() { } WavFileReader::~WavFileReader() { CloseFlie(); } bool WavFileReader::OpenWavFile(const std::string& fileName) { if (_file) { printf("已经打开了文件!\n"); return false; } WaveRIFF riff; WaveFormat format; WaveData data; int userDataSize; _file = fopen(fileName.c_str(), "rb+"); if (!_file) { printf("打开文件失败!\n"); return false; } //读取头部信息 if (fread(&riff, 1, sizeof(riff), static_cast(_file)) != sizeof(riff)) { printf("文件读取错误,读取riff失败!\n"); goto error; } if (std::string(riff.id, 4) != "RIFF" || std::string(riff.waveFlag, 4) != "WAVE") { printf("头部信息不正确,不是wav文件!\n"); goto error; } if (fread(&format, 1, sizeof(format), static_cast (_file)) != sizeof(format)) { printf("文件读取错误,读取format失败!\n"); goto error; } if (std::string(format.id, 4) != "fmt ") { printf("头部信息不正确,缺少fmt!\n"); goto error; } if (format.formatTag != 1) { printf("程序不支持,数据格式非pcm,只支持pcm格式的数据!\n"); goto error; } userDataSize = format.blockSize - sizeof(format) + 8; if (userDataSize < 0) { printf("头部信息不正确,blockSize大小异常!\n"); goto error; } else if (userDataSize > 0) { if (fseek(static_cast (_file), userDataSize, SEEK_CUR) != 0) { printf("文件读取错误!\n"); goto error; } } while (1) { if (fread(&data, 1, sizeof(data), static_cast (_file)) != sizeof(data)) { printf("文件读取错误!\n"); goto error; }; if (std::string(data.id, 4) != "data") { if (fseek(static_cast (_file), data.dataLength, SEEK_CUR) != 0) { printf("文件读取错误!\n"); goto error; } continue; } break; } _dataOffset = ftell(static_cast (_file)); _fileLength = riff.fileLength+8; _dataLength = data.dataLength; _channels = format.channels; _sampleRate = format.samplesPerSec; _bitsPerSample = format.bitsPerSample; return true; error: if (fclose(static_cast (_file)) == EOF) { printf("文件关闭失败!\n"); } _file = nullptr; return false; } void WavFileReader::CloseFlie() { if (_file) { if (fclose(static_cast (_file)) == EOF) { printf("文件关闭失败!\n"); } _file = nullptr; } } int WavFileReader::ReadData(unsigned char* buf, int bufLength) { if (ftell(static_cast (_file)) >= _dataOffset + _dataLength) return 0; return fread(buf, 1, bufLength, static_cast (_file)); } void WavFileReader::SetPosition(int postion) { if (fseek(static_cast (_file), _dataOffset + postion, SEEK_SET) != 0) { printf("定位失败!\n"); } } int WavFileReader::GetPosition() { return ftell(static_cast (_file)) - _dataOffset; } int WavFileReader::GetFileLength() { return _fileLength; } int WavFileReader::GetDataLength() { return _dataLength; } int WavFileReader::GetChannels() { return _channels; } int WavFileReader::GetSampleRate() { return _sampleRate; } int WavFileReader::GetBitsPerSample() { return _bitsPerSample; }}
三、使用示例
1、播放
#include "WavFileReader.h"int main(int argc, char** argv) { AC::WavFileReader read; unsigned char buf[1024]; if (read.OpenWavFile("test_music.wav")) { int channels, sampleRate, bitsPerSample; //获取声音格式 channels = read.GetChannels(); sampleRate = read.GetSampleRate(); bitsPerSample = read.GetBitsPerSample(); //打开声音设备(channels,sampleRate,bitsPerSample) int size; do { //读取音频数据 size = read.ReadData(buf,1024); if (size > 0) { //播放(buf,1024) } } while (size); read.CloseFlie(); } return 0;}
2、循环播放
#include "WavFileReader.h"int main(int argc, char** argv) { AC::WavFileReader read; unsigned char buf[1024]; bool exitFlag = false; if (read.OpenWavFile("test_music.wav")) { int channels, sampleRate, bitsPerSample; //获取声音格式 channels = read.GetChannels(); sampleRate = read.GetSampleRate(); bitsPerSample = read.GetBitsPerSample(); //打开声音设备(channels,sampleRate,bitsPerSample) int size; while (!exitFlag) { //读取音频数据 size = read.ReadData(buf, 1024); if (size > 0) { //播放(buf,1024) } else { //回到数据起始位置 read.SetPosition(0); } } read.CloseFlie(); } return 0;}
以上是"C++如何读取wav文件中的PCM数据"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!
文件
数据
信息
头部
格式
位置
长度
音频
声音
结构
错误
设备
支持
起始
C++
代码
内容
单位
声道
就是
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
go服务器部署
齐齐哈尔黑河安卓软件开发
APP网络安全科学辟谣
单片机软件开发与嵌入式软件
什么是抖音服务器升级中
我的世界火车服务器手机版下载
云服务器同步本地文件
先锋服务器一体机
服务器生存指令
qq smtp服务器
校园网络安全隐患自查及整改情况
从事软件开发会有前途吗
山东网络安全公司有哪些
战争学院服务器是什么意思
快活程网络技术
信创服务器哪家好
网络安全局限于未来
荷兰外贸仿品服务器
网络安全售前培训课程招投标
青浦区市场软件开发收费标准
聚百达网络技术公司
架设mp3服务器
天门网络安全周
紫色监控能做服务器硬盘用吗
做好网络安全疫情监测
开源进销存数据库设计
亚太互联网科技
护苗网络安全课手抄报排版
幻塔官方有几个服务器
沈职信息网络技术