日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++將音頻PCM數據封裝成wav文件的方法_C 語言

作者:Alfred-N ? 更新時間: 2022-03-28 編程語言

前言

使用聲音設備采集的聲音數據通常是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頭結構,然后自定義其頭結構,然后再進行一定的測試,就可以實現這樣一個功能。

原文鏈接:https://blog.csdn.net/u013113678/article/details/122268109

欄目分類
最近更新