欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++將音頻PCM數(shù)據(jù)封裝成wav文件的方法

 更新時(shí)間:2022年01月13日 13:31:36   作者:Alfred-N  
這篇文章主要為大家詳細(xì)介紹了C++將音頻PCM數(shù)據(jù)封裝成wav文件的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

前言

使用聲音設(shè)備采集的聲音數(shù)據(jù)通常是PCM數(shù)據(jù),直接寫(xiě)入文件是無(wú)法播放的,通常的做法是將其封裝成wav格式,這樣播放器就能夠識(shí)別且播放了。本文將介紹如何將PCM封裝成wav的方法。

一、如何實(shí)現(xiàn)?

首先需要構(gòu)造wav頭部,wav文件音頻信息全部保存在頭部,我們要做的就是在PCM數(shù)據(jù)的前面加入wav頭,并且記錄PCM的相關(guān)參數(shù)。

1.定義頭結(jié)構(gòu)

只定義PCM格式的wav文件頭

//WAV頭部結(jié)構(gòu)-PCM格式
struct WavPCMFileHeader;

2.預(yù)留頭部空間

創(chuàng)建文件時(shí)預(yù)留頭部空間

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

3.寫(xiě)入PCM數(shù)據(jù)

寫(xiě)入數(shù)據(jù),并記錄數(shù)據(jù)總長(zhǎng)度。

fwrite(data, 1, dataLength, f);
//錄數(shù)據(jù)總長(zhǎng)度
_totalDataLength += dataLength;

4.寫(xiě)入頭部信息

關(guān)閉文件時(shí),回到起始位置寫(xiě)入頭部信息

//寫(xiě)入頭部信息
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>
?? ??? ?/// 創(chuàng)建wav文件
?? ??? ?/// </summary>
?? ??? ?/// <param name="fileName">文件名</param>
?? ??? ?/// <param name="channels">聲道數(shù)</param>
?? ??? ?/// <param name="sampleRate">采樣率,單位hz</param>
?? ??? ?/// <param name="bitsPerSample">位深</param>
?? ??? ?void CreateWavFile(const std::string &fileName, int channels, int ?sampleRate, int ?bitsPerSample);
?? ??? ?/// <summary>
?? ??? ?/// 寫(xiě)入PCM數(shù)據(jù)
?? ??? ?/// </summary>
?? ??? ?/// <param name="data">PCM數(shù)據(jù)</param>
?? ??? ?/// <param name="dataLength">數(shù)據(jù)長(zhǎng)度</param>
?? ??? ?void WriteToFile(unsigned char* data, int dataLength);
?? ??? ?/// <summary>
?? ??? ?/// 關(guān)閉文件
?? ??? ?/// </summary>
?? ??? ?void CloseFile();
?? ?private:
?? ??? ?void* _file=nullptr;
?? ??? ?uint32_t _totalDataLength=0;
?? ?};
}

WavWapper.cpp

#include"WavWapper.h"
#include<stdio.h>
namespace AC {
?? ?//WAV頭部結(jié)構(gòu)-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+");
?? ??? ??? ?//預(yù)留頭部位置
?? ??? ??? ?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)
?? ??? ??? ?{
?? ??? ??? ??? ?//寫(xiě)入頭部信息
?? ??? ??? ??? ?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;
?? ?//創(chuàng)建wav文件,確保pcm聲音格式與參數(shù)一致
?? ?ww.CreateWavFile("sound.wav",2, 44100, 16);
?? ?while (flag)
?? ?{
?? ??? ?//獲取PCM數(shù)據(jù)
?? ??? ?//略
?? ??? ?//獲取PCM數(shù)據(jù)-end
?? ? ? ?//寫(xiě)入PCM數(shù)據(jù)
?? ??? ?ww.WriteToFile(data, dataLength);
?? ?}
?? ?//關(guān)閉文件
?? ?ww.CloseFile();?? ?
}

總結(jié)

以上就是今天要講的內(nèi)容,PCM封裝成wav還是相對(duì)較簡(jiǎn)單的,只要了解wav頭結(jié)構(gòu),然后自定義其頭結(jié)構(gòu),然后再進(jìn)行一定的測(cè)試,就可以實(shí)現(xiàn)這樣一個(gè)功能。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C語(yǔ)言判定一棵二叉樹(shù)是否為二叉搜索樹(shù)的方法分析

    C語(yǔ)言判定一棵二叉樹(shù)是否為二叉搜索樹(shù)的方法分析

    這篇文章主要介紹了C語(yǔ)言判定一棵二叉樹(shù)是否為二叉搜索樹(shù)的方法,結(jié)合實(shí)例形式綜合對(duì)比分析了C語(yǔ)言針對(duì)二叉搜索樹(shù)判定的原理、算法、效率及相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2018-08-08
  • C語(yǔ)言中堆空間的生成與釋放詳解

    C語(yǔ)言中堆空間的生成與釋放詳解

    以下是對(duì)C語(yǔ)言中堆空間的生成與釋放進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下
    2013-08-08
  • C語(yǔ)言進(jìn)階之字符串查找?guī)旌瘮?shù)詳解

    C語(yǔ)言進(jìn)階之字符串查找?guī)旌瘮?shù)詳解

    字符串是一種非常重要的數(shù)據(jù)類型,但是C語(yǔ)言不存在顯式的字符串類型,C語(yǔ)言中的字符串都以字符串常量的形式出現(xiàn)或存儲(chǔ)在字符數(shù)組中,下面這篇文章主要給大家介紹了關(guān)于C語(yǔ)言進(jìn)階之字符串查找?guī)旌瘮?shù)的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • C語(yǔ)言約瑟夫環(huán)的實(shí)現(xiàn)

    C語(yǔ)言約瑟夫環(huán)的實(shí)現(xiàn)

    這篇文章主要介紹了C語(yǔ)言約瑟夫環(huán)的實(shí)現(xiàn)的相關(guān)資料,這里主要是利用數(shù)據(jù)數(shù)據(jù)結(jié)果中循環(huán)鏈表來(lái)實(shí)現(xiàn),需要的朋友可以參考下
    2017-08-08
  • OpenCV圖像處理基本操作詳解

    OpenCV圖像處理基本操作詳解

    這篇文章主要為大家詳細(xì)介紹了OpenCV圖像處理基本操作,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • C++使用htslib庫(kù)讀入和寫(xiě)出bam文件的實(shí)例

    C++使用htslib庫(kù)讀入和寫(xiě)出bam文件的實(shí)例

    下面小編就為大家分享一篇C++使用htslib庫(kù)讀入和寫(xiě)出bam文件的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-11-11
  • 詳解c++ libuv工作隊(duì)列

    詳解c++ libuv工作隊(duì)列

    這篇文章主要介紹了c++ libuv工作隊(duì)列的相關(guān)資料,幫助大家更好的理解和使用libuv,感興趣的朋友可以了解下
    2021-02-02
  • C語(yǔ)言 詳細(xì)講解接續(xù)符和轉(zhuǎn)義符的使用

    C語(yǔ)言 詳細(xì)講解接續(xù)符和轉(zhuǎn)義符的使用

    接續(xù)符是用來(lái)告訴編譯器行為的符號(hào),那編譯器遇到接續(xù)符是什么行為呢,就是去掉接續(xù)符,然后把下一行連接到現(xiàn)在這行上面,轉(zhuǎn)義符是主要用于表示無(wú)回顯字符,也用于表示常規(guī)字符,轉(zhuǎn)義符必須放在單引號(hào)或者雙引號(hào)里面
    2022-04-04
  • linux 匿名管道實(shí)例詳解

    linux 匿名管道實(shí)例詳解

    這篇文章主要介紹了linux 匿名管道實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • C++ LeetCode1781題解所有子字符串美麗值之和

    C++ LeetCode1781題解所有子字符串美麗值之和

    這篇文章主要為大家介紹了C++ LeetCode1781題解所有子字符串美麗值之和,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12

最新評(píng)論