当前位置: 首页 > news >正文

Windows 读取wav文件字节流并播放

Windows 读取wav文件字节流并播放

使用Windows Wave相关API播放wav文件,实现文件读取进内存,按照一定字节数播放,
对wav文件音频格式进行检测,只能播放48kHz采样率,16bit位深,单通道格式的音频文件。

 * @brief   wav文件读取解析和使用Windows api输出* @date    2024-08-02* @author  shentujia@qq.com*/#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include "WAVHeader.h"
#include<Windows.h>
#include <MMSystem.h>
#pragma comment(lib, "winmm.lib")
// 48k 16bit 1channels 音频采样100ms数据大小为9600字节
#define  WAVE_BUFFER_SIZE 9600
using namespace std;HWAVEOUT hWaveOut; // waveOut设备句柄
WAVEHDR waveOutHdr; // waveOut数据块头int main()
{string audio_file = "rain_48khz_1ch_16bit.wav";ifstream fin(audio_file, ios::binary);if (!fin) {cout << "open file failed!" << endl;return 1;}WAVHeader header;//读取wav文件头并保存到header对象中fin.read((char*)&header, sizeof(header));if (strncmp(header.riff.chunkID, "RIFF", 4) != 0 || strncmp(header.riff.format, "WAVE", 4) != 0|| strncmp(header.fmt.chunkID, "fmt ", 4) != 0 || strncmp(header.data.chunkID, "data", 4) != 0) {cout << "file is not a valid WAV file" << endl;return 1;}//判断音频文件是否为16bit 1channels 采样率为48000的音频文件if(header.fmt.numChannels != 1 || header.fmt.bitsPerSample != 16||header.fmt.sampleRate!=48000){cout << "only support 8bit 1channels audio file" << endl;return 1;}WAVEFORMATEX waveFormat;/*WAVEFORMATEX是一种数据结构,用于指定波形音频流的数据格式。它包含以下字段:wFormatTag:设置波形声音的格式。nChannels:设置音频文件的通道数量,对于单声道的声音,此值为1;对于立体声,此值为2。nSamplesPerSec:设置每个声道播放和记录时的样本频率。nAvgBytesPerSec:设置每秒平均字节数。nBlockAlign:设置数据块的对齐方式,即最小数据的原子大小。wBitsPerSample:设置每个样本的位数。cbSize:设置此结构的大小。*/waveFormat.wFormatTag = WAVE_FORMAT_PCM;waveFormat.nChannels = header.fmt.numChannels;waveFormat.nSamplesPerSec = header.fmt.sampleRate;waveFormat.nBlockAlign = header.fmt.blickAlign;waveFormat.wBitsPerSample = header.fmt.bitsPerSample;waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.wBitsPerSample / 8;waveFormat.cbSize = 0;if (waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormat, (DWORD_PTR)0, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {cout << "无法打开音频设备" << endl;return 1;}char* pcmData = new char[header.data.chunkSize];//读取wav文件的pcm数据部分,保存到char 数组中fin.read(pcmData, header.data.chunkSize);// 计算1毫秒内的样本字节数int bytesPerMs = (header.fmt.sampleRate / 1000) * (header.fmt.bitsPerSample / 8) * header.fmt.numChannels;WAVEHDR* waveHdr = new WAVEHDR();std::vector<char*>char_points;for (int i = 0; i < header.data.chunkSize; i += WAVE_BUFFER_SIZE) {int buffersize = min(WAVE_BUFFER_SIZE, header.data.chunkSize - i);char* perFrameData = new char[WAVE_BUFFER_SIZE];char_points.push_back(perFrameData);memcpy(perFrameData, pcmData + i, WAVE_BUFFER_SIZE);cout << "play " << i << " to " << i + WAVE_BUFFER_SIZE << " bytes" <<",total:" <<header.data.chunkSize<< endl;waveHdr->lpData = perFrameData;waveHdr->dwBufferLength = buffersize;waveHdr->dwFlags = 0;waveHdr->dwLoops = 0;if (waveOutPrepareHeader(hWaveOut, waveHdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) {cout << "无法准备音频数据" << endl;break;}if (waveOutWrite(hWaveOut, waveHdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) {cout << "无法播放音频" << endl;waveOutUnprepareHeader(hWaveOut, waveHdr, sizeof(WAVEHDR));break;}Sleep(90);}getchar();fin.close();waveOutClose(hWaveOut);//使用new创建的对象需要手动deletedelete waveHdr;delete[] pcmData;for (auto& p : char_points) {delete[] p;}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 多旋翼+四光吊舱:5Kg负载无人机技术详解
  • MySQL:行级锁
  • 车载音频开发(一):从看懂wav开始
  • DUILib 创建自定义文本编辑控件
  • 【Python】模块
  • 《Windows API每日一练》24.1 WinSock简介
  • Java中的notify()与notifyAll()区别
  • 探展2024世界人工智能大会之合合信息扫描黑科技~
  • Harmony学习(四)(应用程序框架基础)
  • 电影票房数据的获取,可以控制数量,并导出表格或csv
  • filebeat + logstash使用笔记
  • 优化PyCharm:让IDE响应速度飞起来
  • 一键生成视频并批量上传视频抖音、bilibili、腾讯(已打包)
  • 【vulnhub】The Ether: Evil Science靶机
  • 浦语提示词工程实践
  • JS 中的深拷贝与浅拷贝
  • Consul Config 使用Git做版本控制的实现
  • ES6之路之模块详解
  • Golang-长连接-状态推送
  • HomeBrew常规使用教程
  • macOS 中 shell 创建文件夹及文件并 VS Code 打开
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • Theano - 导数
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • 高程读书笔记 第六章 面向对象程序设计
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 验证码识别技术——15分钟带你突破各种复杂不定长验证码
  • 要让cordova项目适配iphoneX + ios11.4,总共要几步?三步
  • 一天一个设计模式之JS实现——适配器模式
  • 用jQuery怎么做到前后端分离
  • Java总结 - String - 这篇请使劲喷我
  • ​VRRP 虚拟路由冗余协议(华为)
  • ###STL(标准模板库)
  • (C语言)共用体union的用法举例
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (笔记)M1使用hombrew安装qemu
  • (补)B+树一些思想
  • (二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (回溯) LeetCode 46. 全排列
  • (论文阅读32/100)Flowing convnets for human pose estimation in videos
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (数据大屏)(Hadoop)基于SSM框架的学院校友管理系统的设计与实现+文档
  • (五)Python 垃圾回收机制
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (小白学Java)Java简介和基本配置
  • (原創) 未来三学期想要修的课 (日記)
  • (转)Sublime Text3配置Lua运行环境
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • (轉貼) 寄發紅帖基本原則(教育部禮儀司頒布) (雜項)
  • .equal()和==的区别 怎样判断字符串为空问题: Illegal invoke-super to void nio.file.AccessDeniedException
  • .gitignore文件设置了忽略但不生效