C++将音频PCM数据封装成wav文件的方法

前言

使用声音设备采集的声音数据通常是PCM数据,直接写入文件是无法播放的,通常的做法是将其封装成wav格式,这样播放器就能够识别且播放了。本文将介绍如何将PCM封装成wav的方法。

一、如何实现?

首先需要构造wav头部,wav文件音频信息全部保存在头部,我们要做的就是在PCM数据的前面加入wav头,并且记录PCM的相关参数。

1.定义头结构

只定义PCM格式的wav文件头

//WAV头部结构-PCM格式
struct WavPCMFileHeader;

2.预留头部空间

创建文件时预留头部空间

FILE*f = fopen(fileName.c_str(), "wb+");
//预留头部位置
fseek(f, sizeof(WavPCMFileHeader), SEEK_SET);

3.写入PCM数据

写入数据,并记录数据总长度。

fwrite(data, 1, dataLength, f);
//录数据总长度
_totalDataLength += dataLength;

4.写入头部信息

关闭文件时,回到起始位置写入头部信息

//写入头部信息
fseek(f, 0, SEEK_SET);
WavPCMFileHeader h(_channels, _sampleRate, _bitsPerSample, _totalDataLength);
fwrite(&h, 1, sizeof(h), f);
fclose(f);

二、完整代码

WavWapper.h

#pragma once
#include<string>
namespace AC {
    class  WavWapper {
    public:
        WavWapper();
        ~WavWapper();
        /// <summary>
        /// 创建wav文件
        /// </summary>
        /// <param name="fileName">文件名</param>
        /// <param name="channels">声道数</param>
        /// <param name="sampleRate">采样率,单位hz</param>
        /// <param name="bitsPerSample">位深</param>
        void CreateWavFile(const std::string &fileName, int channels, int  sampleRate, int  bitsPerSample);
        /// <summary>
        /// 写入PCM数据
        /// </summary>
        /// <param name="data">PCM数据</param>
        /// <param name="dataLength">数据长度</param>
        void WriteToFile(unsigned char* data, int dataLength);
        /// <summary>
        /// 关闭文件
        /// </summary>
        void CloseFile();
    private:
        void* _file=nullptr;
        uint32_t _totalDataLength=0;
    };
}

WavWapper.cpp

#include"WavWapper.h"
#include<stdio.h>
namespace AC {
    //WAV头部结构-PCM格式
    struct WavPCMFileHeader
    {
        struct RIFF {
            const    char rift[4] = { 'R','I', 'F', 'F' };
            uint32_t fileLength;
            const    char wave[4] = { 'W','A', 'V', 'E' };
        }riff;
        struct Format
        {
            const    char fmt[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;
        }format;
        struct  Data
        {
            const    char data[4] = { 'd','a', 't', 'a' };
            uint32_t dataLength;
        }data;
        WavPCMFileHeader() {}
        WavPCMFileHeader(int nCh, int  nSampleRate, int  bitsPerSample, int dataSize) {
            riff.fileLength = 36 + dataSize;
            format.formatTag = 1;
            format.channels = nCh;
            format.samplesPerSec = nSampleRate;
            format.avgBytesPerSec = nSampleRate * nCh * bitsPerSample / 8;
            format.blockAlign = nCh * bitsPerSample / 8;
            format.bitsPerSample = bitsPerSample;
            data.dataLength = dataSize;
        }
    };
    WavWapper::WavWapper()
    {
    }

    WavWapper::~WavWapper()
    {
        CloseFile();
    }
    int _channels;
    int _sampleRate;
    int _bitsPerSample;
    void WavWapper::CreateWavFile(const std::string& fileName, int channels, int sampleRate, int bitsPerSample)
    {
        if (!_file)
        {
            _channels = channels;
            _sampleRate = sampleRate;
            _bitsPerSample = bitsPerSample;
            _totalDataLength = 0;
            _file = fopen(fileName.c_str(), "wb+");
            //预留头部位置
            fseek(static_cast<FILE*>(_file), sizeof(WavPCMFileHeader), SEEK_SET);
        }
    }
    void WavWapper::WriteToFile(unsigned char* data, int dataLength)
    {
        fwrite(data, 1, dataLength, static_cast<FILE*>(_file));
        _totalDataLength += dataLength;
    }
    void WavWapper::CloseFile()
    {
        if (_file)
        {
            if (_totalDataLength > 0)
            {
                //写入头部信息
                fseek(static_cast<FILE*>(_file), 0, SEEK_SET);
                WavPCMFileHeader h(_channels, _sampleRate, _bitsPerSample, _totalDataLength);
                fwrite(&h, 1, sizeof(h), static_cast<FILE*>(_file));
            }
            fclose(static_cast<FILE*>(_file));
            _file = nullptr;
        }
    }
}

三、使用示例

#include "WavWapper.h"
#include<Windows.h>
int main()
{    
    AC::WavWapper ww;
    //创建wav文件,确保pcm声音格式与参数一致
    ww.CreateWavFile("sound.wav",2, 44100, 16);
    while (flag)
    {
        //获取PCM数据
        //略
        //获取PCM数据-end
        //写入PCM数据
        ww.WriteToFile(data, dataLength);
    }
    //关闭文件
    ww.CloseFile();    
}

总结

以上就是今天要讲的内容,PCM封装成wav还是相对较简单的,只要了解wav头结构,然后自定义其头结构,然后再进行一定的测试,就可以实现这样一个功能。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C++标准库实现WAV文件读写的操作

    在上一篇文章RIFF和WAVE音频文件格式中对WAV的文件格式做了介绍,本文将使用标准C++库实现对数据为PCM格式的WAV文件的读写操作,只使用标准C++库函数,不依赖于其他的库. WAV文件结构 WAV是符合RIFF标准的多媒体文件,其文件结构可以如下: WAV 文件结构 RIFF块 WAVE FOURCC fmt 块 fact 块(可选) data块(包含PCM数据) 首先是一个RIFF块,有块标识RIFF,指明该文件是符合RIFF标准的文件:接着是一个FourCC,WAVE,该文件为WA

  • C++读取WAV音频文件的头部数据的实现方法

    C++读取WAV音频文件的头部数据的实现方法 前言: 在这里分享一下自己的心得,希望和大家一起分享技术,如果有什么不足,还请大家指正.写出这篇目的,就是希望大家一起成长,我也相信技术之间没有高低,只有互补,只有分享,才能使彼此更加成长. 实现代码: #include <iostream> #include <string> #include <fstream> using namespace std; using std::string; using std::fstr

  • C++读取wav文件中的PCM数据

    前言 wav文件通常会使用PCM格式数据存储音频,这种格式的数据读取出来直接就可以播放,要在wav文件中读取数据,我们首先要获取头部信息,wav的文件结构里面分为多个chunk,我们要做的就是识别这些chunk的信息,获取音频的格式以及数据. 一.如何实现? 首先需要构造wav头部,wav文件音频信息全部保存在头部,我们要做的就是读取wav头部信息,并且记录PCM的相关参数. 1.定义头结构 只定义PCM格式的wav文件头,对于PCM格式的数据只需要下面3个结构体即可. struct WaveR

  • C++将音频PCM数据封装成wav文件的方法

    前言 使用声音设备采集的声音数据通常是PCM数据,直接写入文件是无法播放的,通常的做法是将其封装成wav格式,这样播放器就能够识别且播放了.本文将介绍如何将PCM封装成wav的方法. 一.如何实现? 首先需要构造wav头部,wav文件音频信息全部保存在头部,我们要做的就是在PCM数据的前面加入wav头,并且记录PCM的相关参数. 1.定义头结构 只定义PCM格式的wav文件头 //WAV头部结构-PCM格式 struct WavPCMFileHeader; 2.预留头部空间 创建文件时预留头部空

  • delphi制作wav文件的方法

    本文实例讲述了delphi制作wav文件的方法.分享给大家供大家参考.具体如下: 这里delphi用waveIn...函数制作wav文件 具体代码如下: //使用窗口接受音频设备发出的消息: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button

  • python实现将html表格转换成CSV文件的方法

    本文实例讲述了python实现将html表格转换成CSV文件的方法.分享给大家供大家参考.具体如下: 使用方法:python html2csv.py *.html 这段代码使用了 HTMLParser 模块 #!/usr/bin/python # -*- coding: iso-8859-1 -*- # Hello, this program is written in Python - http://python.org programname = 'html2csv - version 20

  • python 自动化将markdown文件转成html文件的方法

    一.背景 我们项目开发人员写的文档都是markdown文件.对于其它组的同学要进行阅读不是很方便.每次编辑完markdown文件,我都是用软件将md文件转成html文件.刚开始转的时候,还没啥,转得次数多了,就觉得不能继续这样下去了.作为一名开发人员,还是让机器去做这些琐碎的事情吧.故写了两个脚本将md文件转成html文件,并将其放置在web服务器下,方便其他人员阅读. 主要有两个脚本和一个定时任务: •一个python脚本,主要将md文件转成html文件: •一个shell脚本,主要用于管理逻

  • python使用wxPython打开并播放wav文件的方法

    本文实例讲述了python使用wxPython打开并播放wav文件的方法.分享给大家供大家参考.具体实现方法如下: ''' wx_lib_filebrowsebutton_sound.py select a sound file and play it wx.lib.filebrowsebutton.FileBrowseButton(parent, labelText, fileMask) (combines wx.TextCtrl and wxFileDialog widgets) wx.So

  • Python调用系统底层API播放wav文件的方法

    本文实例讲述了Python调用系统底层API播放wav文件的方法.分享给大家供大家参考,具体如下: 这里未使用其他库,只是使用 pywin32 调用系统底层 API 播放 wav 文件. 具体代码如下: # Our raison d'etre - playing sounds import pywintypes import struct import win32event import win32com.directsound.directsound as ds import os WAV_H

  • C#实现将javascript文件编译成dll文件的方法

    本文实例讲述了C#实现将javascript文件编译成dll文件的方法.分享给大家供大家参考,具体如下: 第一步:新建项目 添加js文件 写个测试Function (JScript.js) 单击JS文件属性.将 生成操作 改成嵌入的资源 第二步:在项目文件中添加一个类文件  该 类继承System.Web.UI.WebControl类 并重写控件预呈现的方法 代码如下: public class ClientScript:System.Web.UI.WebControls.WebControl

  • C#中将DataTable转换成CSV文件的方法

    DataTable用于在.net项目中,用于缓存数据,DataTable表示内存中数据的一个表.CSV文件最早用在简单的数据库里,由于其格式简单,并具备很强的开放性,所以起初被扫图家用作自己图集的标记.CSV文件是个纯文本文件,每一行表示一张图片的许多属性. 在.net项目中运用C#将DataTable转化为CSV文件,现在提供一个较为通用的方法,具体代码如下: /// <summary> /// 将DataTable转换成CSV文件 /// </summary> /// <

  • vue完成项目后,打包成静态文件的方法

    vue完成项目后,如何打包成静态文件,并且用Node调试 打包 1.修改config里面的index.js里面的productionSourceMap为false,默认情况是true(true代表打包环境是开发环境,可以进行调试:false表示生产环境,正式上线的) 2.在cmd里面运行npm run build,(运行的是build里面的build.js文件) 生成的包放在dist下面 使用node进行调试 1.在根目录下创建prod.server.js文件,这个文件的作用是作为一个小的htt

  • Vue webpack 项目自动打包压缩成zip文件的方法

    这段时间用 Vue2.0 开发项目,每次打包都会用到 npm run build 命令,但是每次部署时给后端发包都要手动zip压缩,这样一两次还行,但遇到项目板块测试和临时加急功能测试的时候,一天可能就要打包好多次,这就很烦了.所以索性在执行 npm run build 命令时就直接打包成zip文件,方便省事! 1.插件装备 webpack插件:filemanager-webpack-plugin,该插件可执行打包,复制,移动,删除文件以及新文件夹在build之前及之后创建. 安装: npm i

随机推荐