最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++讀取wav文件中的PCM數(shù)據(jù)

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

前言

wav文件通常會(huì)使用PCM格式數(shù)據(jù)存儲(chǔ)音頻,這種格式的數(shù)據(jù)讀取出來(lái)直接就可以播放,要在wav文件中讀取數(shù)據(jù),我們首先要獲取頭部信息,wav的文件結(jié)構(gòu)里面分為多個(gè)chunk,我們要做的就是識(shí)別這些chunk的信息,獲取音頻的格式以及數(shù)據(jù)。

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

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

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

只定義PCM格式的wav文件頭,對(duì)于PCM格式的數(shù)據(jù)只需要下面3個(gè)結(jié)構(gòu)體即可。

struct WaveRIFF;
struct WaveFormat;
struct WaveData;

2.讀取頭部信息

打開(kāi)文件后需要讀取頭部信息,需要獲取聲音的格式以及數(shù)據(jù)長(zhǎng)度。

WaveRIFF riff;
WaveFormat format;
WaveData data;
int userDataSize;
f= fopen(fileName.c_str(), "rb+");
//讀取頭部信息
fread(&riff, 1, sizeof(riff), f);
fread(&format, 1, sizeof(format),f);
//判讀頭部信息是否正確
//略
//查找data chunk
//略
//記錄數(shù)據(jù)起始位置

3.讀取數(shù)據(jù)

獲取頭部信息后,就知道數(shù)據(jù)在位置及長(zhǎng)度了,只需要直接讀文件即可。

//跳到數(shù)據(jù)起始位置
seek(f, _dataOffset, SEEK_SET);
//讀取數(shù)據(jù)
fread(buf, 1, bufLength, f);

二、完整代碼

完整代碼總用有3部分,頭結(jié)構(gòu)、WavFileReader.h、WavFileReader.cpp。

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

#pragma pack(push,1)
?? ?struct WaveRIFF {
?? ??? ?const?? ?char id[4] = { 'R','I', 'F', 'F' };
?? ??? ?uint32_t fileLength;
?? ??? ?const?? ?char waveFlag[4] = { 'W','A', 'V', 'E' };
?? ?};
?? ?struct WaveFormat
?? ?{
?? ??? ?const?? ?char id[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;
?? ?};
?? ?struct ?WaveData
?? ?{
?? ??? ?const?? ?char id[4] = { 'd','a', 't', 'a' };
?? ??? ?uint32_t dataLength;
?? ?};
#pragma pack(pop)

2.WavFileReader.h

#pragma once
#include<string>
/************************************************************************
* @Project: ??? ?AC.WavFileWriter
* @Decription: ?wav文件讀取工具
* 本版本只支持pcm讀取,且未處理字節(jié)順序。?? ?riff文件是小端,通常在intel的設(shè)備上是沒(méi)問(wèn)題的,在java虛擬機(jī)上則需要處理。
* @Verision: ??? ?v1.0.0.0
* @Author: ??? ?Xin Nie
* @Create: ??? ?2019/4/10 11:10:17
* @LastUpdate: ?2019/4/16 10:45:00
************************************************************************
* Copyright @ 2019. All rights reserved.
************************************************************************/
namespace AC {
?? ?/// <summary>
?? ?/// wav文件讀取對(duì)象
?? ?/// </summary>
?? ?class WavFileReader {
?? ?public:
?? ??? ?/// <summary>
?? ??? ?/// 構(gòu)造方法
?? ??? ?/// </summary>
?? ??? ?WavFileReader();
?? ??? ?/// <summary>
?? ? ? ?/// 析構(gòu)方法
?? ? ? ?/// </summary>
?? ??? ?~WavFileReader();
?? ??? ?/// <summary>
?? ??? ?/// 打開(kāi)wav文件
?? ??? ?/// </summary>
?? ??? ?/// <param name="fileName">文件名</param>
?? ??? ?/// <returns>是否打開(kāi)成功</returns>
?? ??? ?bool OpenWavFile(const std::string& fileName);
?? ??? ?/// <summary>
?? ??? ?/// 關(guān)閉文件
?? ??? ?/// </summary>
?? ??? ?void CloseFlie();
?? ??? ?/// <summary>
?? ??? ?/// 讀取音頻數(shù)據(jù)
?? ??? ?/// </summary>
?? ??? ?/// <param name="buf">外部緩存</param>
?? ??? ?/// <param name="bufLength">緩存長(zhǎng)度</param>
?? ??? ?/// <returns>讀取長(zhǎng)度</returns>
?? ??? ?int ReadData(unsigned char* buf, int bufLength);
?? ??? ?/// <summary>
?? ??? ?/// 設(shè)置讀取位置
?? ??? ?/// </summary>
?? ??? ?/// <param name="position"> 讀取位置</param>
?? ??? ?void SetPosition(int position);
?? ??? ?/// <summary>
?? ??? ?/// 獲取讀取位置
?? ??? ?/// </summary>
?? ??? ?/// <returns>讀取位置</returns>
?? ??? ?int GetPosition();
?? ??? ?/// <summary>
?? ??? ?/// 獲取文件長(zhǎng)度
?? ??? ?/// </summary>
?? ??? ?/// <returns>文件長(zhǎng)度</returns>
?? ??? ?int GetFileLength();
?? ??? ?/// <summary>
?? ??? ?/// 獲取音頻數(shù)據(jù)長(zhǎng)度
?? ??? ?/// </summary>
?? ??? ?/// <returns>音頻數(shù)據(jù)長(zhǎng)度</returns>
?? ??? ?int GetDataLength();
?? ??? ?/// <summary>
?? ??? ?/// 獲取聲道數(shù)
?? ??? ?/// </summary>
?? ??? ?/// <returns>聲道數(shù)</returns>
?? ??? ?int GetChannels();
?? ??? ?/// <summary>
?? ??? ?/// 獲取采樣率
?? ??? ?/// </summary>
?? ??? ?/// <returns>采樣率,單位:hz</returns>
?? ??? ?int GetSampleRate();
?? ??? ?/// <summary>
?? ??? ?/// 獲取位深
?? ??? ?/// </summary>
?? ??? ?/// <returns>位深,單位:bits</returns>
?? ??? ?int GetBitsPerSample();
?? ?private:
?? ??? ?void* _file = nullptr;
?? ??? ?uint32_t _fileLength = 0;
?? ??? ?uint32_t _dataLength = 0;
?? ??? ?int _channels = 0;
?? ??? ?int ?_sampleRate = 0;
?? ??? ?int ?_bitsPerSample = 0;
?? ??? ?int _dataOffset = 0;
?? ?};
}

3.WavFileReader.cpp

#include"WavFileReader.h"
namespace AC {
?? ?WavFileReader::WavFileReader()
?? ?{
?? ?}
?? ?WavFileReader::~WavFileReader()
?? ?{
?? ??? ?CloseFlie();
?? ?}
?? ?bool WavFileReader::OpenWavFile(const std::string& fileName)
?? ?{
?? ??? ?if (_file)
?? ??? ?{
?? ??? ??? ?printf("已經(jīng)打開(kāi)了文件!\n");
?? ??? ??? ?return false;
?? ??? ?}
?? ??? ?WaveRIFF riff;
?? ??? ?WaveFormat format;
?? ??? ?WaveData data;
?? ??? ?int userDataSize;
?? ??? ?_file = fopen(fileName.c_str(), "rb+");
?? ??? ?if (!_file)
?? ??? ?{
?? ??? ??? ?printf("打開(kāi)文件失敗!\n");
?? ??? ??? ?return false;
?? ??? ?}
?? ??? ?//讀取頭部信息
?? ??? ?if (fread(&riff, 1, sizeof(riff), static_cast<FILE*>(_file)) != sizeof(riff))
?? ??? ?{
?? ??? ??? ?printf("文件讀取錯(cuò)誤,讀取riff失敗!\n");
?? ??? ??? ?goto error;
?? ??? ?}
?? ??? ?if (std::string(riff.id, 4) != "RIFF" || std::string(riff.waveFlag, 4) != "WAVE")
?? ??? ?{
?? ??? ??? ?printf("頭部信息不正確,不是wav文件!\n");
?? ??? ??? ?goto error;
?? ??? ?}
?? ??? ?if (fread(&format, 1, sizeof(format), static_cast<FILE*>(_file)) != sizeof(format))
?? ??? ?{
?? ??? ??? ?printf("文件讀取錯(cuò)誤,讀取format失敗!\n");
?? ??? ??? ?goto error;
?? ??? ?}
?? ??? ?if (std::string(format.id, 4) != "fmt ")
?? ??? ?{
?? ??? ??? ?printf("頭部信息不正確,缺少fmt!\n");
?? ??? ??? ?goto error;
?? ??? ?}
?? ??? ?if (format.formatTag != 1)
?? ??? ?{
?? ??? ??? ?printf("程序不支持,數(shù)據(jù)格式非pcm,只支持pcm格式的數(shù)據(jù)!\n");
?? ??? ??? ?goto error;
?? ??? ?}
?? ??? ?userDataSize = format.blockSize - sizeof(format) + 8;
?? ??? ?if (userDataSize < 0)
?? ??? ?{
?? ??? ??? ?printf("頭部信息不正確,blockSize大小異常!\n");
?? ??? ??? ?goto error;
?? ??? ?}
?? ??? ?else if (userDataSize > 0)
?? ??? ?{
?? ??? ??? ?if (fseek(static_cast<FILE*>(_file), userDataSize, SEEK_CUR) != 0)
?? ??? ??? ?{
?? ??? ??? ??? ?printf("文件讀取錯(cuò)誤!\n");
?? ??? ??? ??? ?goto error;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?while (1)
?? ??? ?{
?? ??? ??? ?if (fread(&data, 1, sizeof(data), static_cast<FILE*>(_file)) != sizeof(data))
?? ??? ??? ?{
?? ??? ??? ??? ?printf("文件讀取錯(cuò)誤!\n");
?? ??? ??? ??? ?goto error;
?? ??? ??? ?};
?? ??? ??? ?if (std::string(data.id, 4) != "data")
?? ??? ??? ?{
?? ??? ??? ??? ?if (fseek(static_cast<FILE*>(_file), data.dataLength, SEEK_CUR) != 0)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?printf("文件讀取錯(cuò)誤!\n");
?? ??? ??? ??? ??? ?goto error;
?? ??? ??? ??? ?}
?? ??? ??? ??? ?continue;
?? ??? ??? ?}
?? ??? ??? ?break;
?? ??? ?}
?? ??? ?_dataOffset = ftell(static_cast<FILE*>(_file));
?? ??? ?_fileLength = riff.fileLength+8;
?? ??? ?_dataLength = data.dataLength;
?? ??? ?_channels = format.channels;
?? ??? ?_sampleRate = format.samplesPerSec;
?? ??? ?_bitsPerSample = format.bitsPerSample;
?? ??? ?return true;
?? ?error:
?? ??? ?if (fclose(static_cast<FILE*>(_file)) == EOF)
?? ??? ?{
?? ??? ??? ?printf("文件關(guān)閉失敗!\n");
?? ??? ?}
?? ??? ?_file = nullptr;
?? ??? ?return false;
?? ?}
?? ?void WavFileReader::CloseFlie()
?? ?{
?? ??? ?if (_file)
?? ??? ?{
?? ??? ??? ?if (fclose(static_cast<FILE*>(_file)) == EOF)
?? ??? ??? ?{
?? ??? ??? ??? ?printf("文件關(guān)閉失敗!\n");
?? ??? ??? ?}
?? ??? ??? ?_file = nullptr;
?? ??? ?}
?? ?}
?? ?int WavFileReader::ReadData(unsigned char* buf, int bufLength)
?? ?{
?? ??? ?if (ftell(static_cast<FILE*>(_file)) >= _dataOffset + _dataLength)
?? ??? ??? ?return 0;
?? ??? ?return fread(buf, 1, bufLength, static_cast<FILE*>(_file));
?? ?}

?? ?void WavFileReader::SetPosition(int postion)
?? ?{
?? ??? ?if (fseek(static_cast<FILE*>(_file), _dataOffset + postion, SEEK_SET) != 0)
?? ??? ?{
?? ??? ??? ?printf("定位失敗!\n");
?? ??? ?}
?? ?}
?? ?int WavFileReader::GetPosition()
?? ?{
?? ??? ?return ftell(static_cast<FILE*>(_file)) - _dataOffset;
?? ?}

?? ?int WavFileReader::GetFileLength()
?? ?{
?? ??? ?return _fileLength;
?? ?}

?? ?int WavFileReader::GetDataLength()
?? ?{
?? ??? ?return _dataLength;
?? ?}

?? ?int WavFileReader::GetChannels()
?? ?{
?? ??? ?return _channels;
?? ?}

?? ?int WavFileReader::GetSampleRate()
?? ?{
?? ??? ?return _sampleRate;
?? ?}

?? ?int WavFileReader::GetBitsPerSample()
?? ?{
?? ??? ?return _bitsPerSample;
?? ?}
}

三、使用示例

1、播放

#include "WavFileReader.h"
int main(int argc, char** argv) {
?? ?AC::WavFileReader read;
?? ?unsigned char buf[1024];
?? ?if (read.OpenWavFile("test_music.wav"))
?? ?{
?? ??? ?int channels, sampleRate, bitsPerSample;
?? ??? ?//獲取聲音格式
?? ??? ?channels = read.GetChannels();
?? ??? ?sampleRate = read.GetSampleRate();
?? ??? ?bitsPerSample = read.GetBitsPerSample();
?? ??? ?//打開(kāi)聲音設(shè)備(channels,sampleRate,bitsPerSample)
?? ??? ?int size;
?? ??? ?do?
?? ??? ?{
?? ??? ? ? ?//讀取音頻數(shù)據(jù)
?? ??? ??? ?size = read.ReadData(buf,1024);
?? ??? ??? ?if (size > 0)
?? ??? ??? ?{
?? ??? ??? ??? ?//播放(buf,1024)
?? ??? ??? ?}
?? ??? ??? ?
?? ??? ?} while (size);
?? ??? ?read.CloseFlie();
?? ?}
?? ?return 0;
}

2、循環(huán)播放

#include "WavFileReader.h"
int main(int argc, char** argv) {
?? ?AC::WavFileReader read;
?? ?unsigned char buf[1024];
? ? bool exitFlag = false;
?? ?if (read.OpenWavFile("test_music.wav"))
?? ?{
?? ??? ?int channels, sampleRate, bitsPerSample;
?? ??? ?//獲取聲音格式
?? ??? ?channels = read.GetChannels();
?? ??? ?sampleRate = read.GetSampleRate();
?? ??? ?bitsPerSample = read.GetBitsPerSample();
?? ??? ?//打開(kāi)聲音設(shè)備(channels,sampleRate,bitsPerSample)
?? ??? ?int size;
?? ??? ?while (!exitFlag)
?? ??? ?{
?? ??? ? ? ?//讀取音頻數(shù)據(jù)
?? ??? ??? ?size = read.ReadData(buf, 1024);
?? ??? ??? ?if (size > 0)
?? ??? ??? ?{
?? ??? ??? ??? ?//播放(buf,1024)
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ?{ ??
?? ??? ??? ? ? ?//回到數(shù)據(jù)起始位置
?? ??? ??? ??? ?read.SetPosition(0);?? ??? ?
?? ??? ??? ?}
?? ??? ?}?
?? ??? ?read.CloseFlie();
?? ?}
?? ?return 0;
}

總結(jié)

以上就是今天要講的內(nèi)容,wav文件中讀取PCM還是相對(duì)較簡(jiǎn)單的,只要了解wav頭結(jié)構(gòu),然后自定義其頭結(jié)構(gòu),讀取頭部信息,校驗(yàn)頭部信息,然后再讀取數(shù)據(jù)所在的chunk,就可以實(shí)現(xiàn)這樣一個(gè)功能。

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

相關(guān)文章

  • C語(yǔ)言中結(jié)構(gòu)體實(shí)例解析

    C語(yǔ)言中結(jié)構(gòu)體實(shí)例解析

    大家好,本篇文章主要講的是C語(yǔ)言中結(jié)構(gòu)體實(shí)例解析,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下
    2022-02-02
  • C++中String類(lèi)型的逆序方式

    C++中String類(lèi)型的逆序方式

    這篇文章主要介紹了C++中String類(lèi)型的逆序方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C++分析講解類(lèi)的靜態(tài)成員函數(shù)如何使用

    C++分析講解類(lèi)的靜態(tài)成員函數(shù)如何使用

    與靜態(tài)數(shù)據(jù)成員不同,靜態(tài)成員函數(shù)的作用不是為了對(duì)象之間的溝通,而是為了能處理靜態(tài)數(shù)據(jù)成員,靜態(tài)成員函數(shù)沒(méi)有this指針。既然它沒(méi)有指向某一對(duì)象,也就無(wú)法對(duì)一個(gè)對(duì)象中的非靜態(tài)成員進(jìn)行默認(rèn)訪(fǎng)問(wèn)
    2022-04-04
  • C++實(shí)現(xiàn)LeetCode(241.添加括號(hào)的不同方式)

    C++實(shí)現(xiàn)LeetCode(241.添加括號(hào)的不同方式)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(241.添加括號(hào)的不同方式),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 詳解C語(yǔ)言數(shù)組越界及其避免方法

    詳解C語(yǔ)言數(shù)組越界及其避免方法

    這篇文章主要介紹了詳解C語(yǔ)言數(shù)組越界及其避免方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • C++中const用于函數(shù)重載的示例代碼

    C++中const用于函數(shù)重載的示例代碼

    這篇文章主要介紹了C++中const用于函數(shù)重載的相關(guān)資料,需要的朋友可以參考下
    2017-09-09
  • C++ new與malloc和delete及free動(dòng)態(tài)內(nèi)存管理及區(qū)別介紹

    C++ new與malloc和delete及free動(dòng)態(tài)內(nèi)存管理及區(qū)別介紹

    這篇文章主要介紹了深入理解C++中的new/delete和malloc/free動(dòng)態(tài)內(nèi)存管理,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-12-12
  • C語(yǔ)言版醫(yī)院管理系統(tǒng)

    C語(yǔ)言版醫(yī)院管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言版醫(yī)院管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • C++實(shí)現(xiàn)LeetCode165.版本比較)

    C++實(shí)現(xiàn)LeetCode165.版本比較)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode165.版本比較),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • DEV C++自動(dòng)補(bǔ)全文件頭的設(shè)置操作教程

    DEV C++自動(dòng)補(bǔ)全文件頭的設(shè)置操作教程

    Dev-C++ 是一款輕量級(jí)的集成開(kāi)發(fā)環(huán)境 (IDE),主要用于 C 和 C++ 的程序編寫(xiě),它提供了基本的功能來(lái)幫助開(kāi)發(fā)者更高效地工作,其中包括文件頭的自動(dòng)補(bǔ)全功能,本文就給大家介紹了DEV C++自動(dòng)補(bǔ)全文件頭的設(shè)置操作教程,需要的朋友可以參考下
    2025-04-04

最新評(píng)論

卓资县| 福海县| 高雄市| 丰镇市| 朝阳市| 策勒县| 贺州市| 辉南县| 如皋市| 乌兰浩特市| 田东县| 兰溪市| 新余市| 香港 | 会同县| 嘉善县| 陇南市| 盐亭县| 栖霞市| 嵊州市| 建平县| 纳雍县| 正安县| 沁源县| 盐山县| 固阳县| 女性| 宜宾县| 汪清县| 正安县| 清河县| 天长市| 班戈县| 涟水县| 黑龙江省| 赤水市| 三原县| 麻栗坡县| 明星| 偏关县| 宜州市|