網站首頁 編程語言 正文
前言
使用聲音設備采集的聲音數據通常是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
相關推薦
- 2022-10-08 Python中集合創建與使用詳解_python
- 2022-10-22 BroadcastReceiver靜態注冊案例詳解_Android
- 2022-09-05 卷積層計算量(FLOPS)和參數量的計算
- 2022-04-10 Blazor頁面組件用法介紹_基礎應用
- 2022-03-28 go?select的用法_Golang
- 2022-10-14 yum 倉庫管理 yum-config-manager
- 2022-08-17 C++詳細分析lambda表達式的本質_C 語言
- 2022-04-15 Android一個類實現錄音與播放實例_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支