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

C++解析wav文件方法介紹

 更新時(shí)間:2022年09月05日 09:24:43   作者:略游  
最近將項(xiàng)目改為跨平臺(tái),于是音頻模塊從微軟的XAudio2改用OpenAL庫(kù)。之前使用MSDN的代碼,所以現(xiàn)在改為了C++標(biāo)準(zhǔn)的寫(xiě)法,適用性更廣

一、前言

一開(kāi)始本來(lái)在網(wǎng)上找代碼,不過(guò)改了好幾個(gè)都不是很好用。因?yàn)楹芏鄔av文件的fmt塊后面并不是data塊,經(jīng)常還帶有其他塊,正確的方法應(yīng)該是按MSDN的方法,找到data塊再讀取。

二、接口

最后接口如下:

class AudioReader
{
public:
	struct PCM
	{
		int _numChannel;//通道數(shù) 1,2 AL_FORMAT_MONO8,AL_FORMAT_STEREO8
		int _bitPerSample;//采樣數(shù) 8,16 
		byte* _data;
		size_t _size;
		size_t _freq;//采樣率
		void Delete() { delete[] _data; }
	}; 
	static bool ReadWAV(string_view path_name, PCM& pcm);
};

三、具體步驟

打開(kāi)文件,這里就是普通的文件流,按二進(jìn)制、只讀打開(kāi)文件即可:

ifstream ifs;
if (!g_file->GetFile(path_name, ifs))
{
	debug_err(format("打開(kāi)文件失?。簕}", path_name));
	return false;
}

查找riff塊:

uint32_t dwChunkSize;
uint32_t dwChunkPosition;
//查找riff塊
FindChunk(ifs, fourccRIFF, dwChunkSize, dwChunkPosition);
uint32_t filetype;
ReadChunkData(ifs, &filetype, sizeof(uint32_t), dwChunkPosition);
if (filetype != fourccWAVE)
{
	debug_err(format("匹配標(biāo)記失?。╢ourccWAVE):{}", path_name));
	return false;
}

其中fourccRIFF和fourccWAVE是我們定義的標(biāo)記,也就是處理了下大小端,如下:

#ifdef DND_ENDIAN_BIG
#define fourccRIFF 'RIFF'
#define fourccDATA 'data'
#define fourccFMT 'fmt '
#define fourccWAVE 'WAVE'
#define fourccXWMA 'XWMA'
#define fourccDPDS 'dpds'
#endif
#ifdef DND_ENDIAN_LITTLE
#define fourccRIFF 'FFIR'
#define fourccDATA 'atad'
#define fourccFMT ' tmf'
#define fourccWAVE 'EVAW'
#define fourccXWMA 'AMWX'
#define fourccDPDS 'sdpd'
#endif

而FindChunk和ReadChunkData兩個(gè)函數(shù),分別是查找一個(gè)塊,和讀取一個(gè)塊。代碼實(shí)現(xiàn)有點(diǎn)長(zhǎng),可以參考后面我給出的完整源碼。

接著,查找并讀取fmt塊,這個(gè)塊描述了wav文件的音頻屬性,結(jié)構(gòu)如下(部分字段會(huì)用到):

//16字節(jié)
struct WAVEFormat 
{
	int16_t audioFormat;
	int16_t numChannels;
	int32_t sampleRate;
	int32_t byteRate;
	int16_t blockAlign;
	int16_t bitsPerSample;
};
//查找fmt塊
if (!FindChunk(ifs, fourccFMT, dwChunkSize, dwChunkPosition))
{
	debug_err(format("查找塊失?。╢ourccFMT):{}", path_name));
	return false;
}
//讀wave信息
WAVEFormat wave_format;
if (!ReadChunkData(ifs, &wave_format, dwChunkSize, dwChunkPosition))
{
	debug_err(format("讀取塊失敗(wave_format):{}", path_name));
	return false;
};

接下來(lái)查找data塊,根據(jù)返回的大小分配內(nèi)存:

//查找音頻數(shù)據(jù)
if (!FindChunk(ifs, fourccDATA, dwChunkSize, dwChunkPosition))
{
	debug_err(format("查找塊失敗(fourccDATA):{}", path_name));
	return false;
};
pcm._data = new byte[dwChunkSize];

然后讀取data塊,將數(shù)據(jù)讀取到我們分配的內(nèi)存pcm._data。然后記錄下一些重要的字段。由于OpenaAL不能直接播放32位(只8、16)的數(shù)據(jù),這里簡(jiǎn)單返回失敗。

if (!ReadChunkData(ifs, pcm._data, dwChunkSize, dwChunkPosition))
{
	debug_err(format("讀取塊失?。╬cm數(shù)據(jù)):{}", path_name));
	pcm.Delete();
	return false;
};
pcm._size = dwChunkSize;
pcm._numChannel = wave_format.numChannels;
pcm._bitPerSample = wave_format.bitsPerSample;
pcm._freq = wave_format.sampleRate;
if (pcm._bitPerSample == 32)
{
	debug_err(format("不支持32位:{}", path_name));
	pcm.Delete();
	return false;
}
return true;

四、完整源碼

可以此處獲取最新的源碼(我將來(lái)會(huì)添加ogg格式的解析),也可以用下面的:傳送門(mén)

//.h
class AudioReader
{
public:
	struct PCM
	{
		int _numChannel;//通道數(shù) 1,2 AL_FORMAT_MONO8,AL_FORMAT_STEREO8
		int _bitPerSample;//采樣數(shù) 8,16 
		byte* _data;
		size_t _size;
		size_t _freq;//采樣率
		void Delete() { delete[] _data; }
	}; 
	static bool ReadWAV(string_view path_name, PCM& pcm);
};
//16字節(jié)
struct WAVEFormat 
{
	int16_t audioFormat;
	int16_t numChannels;
	int32_t sampleRate;
	int32_t byteRate;
	int16_t blockAlign;
	int16_t bitsPerSample;
};
//.cpp
#ifdef DND_ENDIAN_BIG
#define fourccRIFF 'RIFF'
#define fourccDATA 'data'
#define fourccFMT 'fmt '
#define fourccWAVE 'WAVE'
#define fourccXWMA 'XWMA'
#define fourccDPDS 'dpds'
#endif
#ifdef DND_ENDIAN_LITTLE
#define fourccRIFF 'FFIR'
#define fourccDATA 'atad'
#define fourccFMT ' tmf'
#define fourccWAVE 'EVAW'
#define fourccXWMA 'AMWX'
#define fourccDPDS 'sdpd'
#endif
bool FindChunk(ifstream& ifs, uint32_t fourcc, uint32_t& size, uint32_t& pos)
{
	bool ret = true;
	ifs.seekg(0);
	if (ifs.fail())
		return false;
	uint32_t dwChunkType;
	uint32_t dwChunkDataSize;
	uint32_t dwRIFFDataSize = 0;
	uint32_t dwFileType;
	uint32_t bytesRead = 0;
	uint32_t dwOffset = 0;
	while (ret)
	{
		ifs.read((char*)&dwChunkType, sizeof(uint32_t));
		ifs.read((char*)&dwChunkDataSize, sizeof(uint32_t));
		switch (dwChunkType)
		{
		case fourccRIFF:
			dwRIFFDataSize = dwChunkDataSize;
			dwChunkDataSize = 4;
			ifs.read((char*)&dwFileType, sizeof(uint32_t));
			break;
		default:
			ifs.seekg(dwChunkDataSize, std::ios::cur);
			if (ifs.fail())
				return false;
			break;
		}
		dwOffset += sizeof(uint32_t) * 2;
		if (dwChunkType == fourcc)
		{
			size = dwChunkDataSize;
			pos = dwOffset;
			return true;
		}
		dwOffset += dwChunkDataSize;
		if (bytesRead >= dwRIFFDataSize)
			return false;
	}
	return true;
}
bool ReadChunkData(ifstream& ifs, void* buffer, uint32_t size, uint32_t pos)
{
	ifs.seekg(pos);
	if (ifs.fail())
		return false;
	ifs.read((char*)buffer, size);
	return true;
}
bool AudioReader::ReadWAV(string_view path_name, PCM& pcm)
{
	ifstream ifs;
	if (!g_file->GetFile(path_name, ifs))
	{
		debug_err(format("打開(kāi)文件失?。簕}", path_name));
		return false;
	}
	uint32_t dwChunkSize;
	uint32_t dwChunkPosition;
	//查找riff塊
	FindChunk(ifs, fourccRIFF, dwChunkSize, dwChunkPosition);
	uint32_t filetype;
	ReadChunkData(ifs, &filetype, sizeof(uint32_t), dwChunkPosition);
	if (filetype != fourccWAVE)
	{
		debug_err(format("匹配標(biāo)記失?。╢ourccWAVE):{}", path_name));
		return false;
	}
	//查找fmt塊
	if (!FindChunk(ifs, fourccFMT, dwChunkSize, dwChunkPosition))
	{
		debug_err(format("查找塊失?。╢ourccFMT):{}", path_name));
		return false;
	}
	//讀wave信息
	WAVEFormat wave_format;
	if (!ReadChunkData(ifs, &wave_format, dwChunkSize, dwChunkPosition))
	{
		debug_err(format("讀取塊失?。╳ave_format):{}", path_name));
		return false;
	};
	//查找音頻數(shù)據(jù)
	if (!FindChunk(ifs, fourccDATA, dwChunkSize, dwChunkPosition))
	{
		debug_err(format("查找塊失?。╢ourccDATA):{}", path_name));
		return false;
	};
	pcm._data = new byte[dwChunkSize];
	if (!ReadChunkData(ifs, pcm._data, dwChunkSize, dwChunkPosition))
	{
		debug_err(format("讀取塊失?。╬cm數(shù)據(jù)):{}", path_name));
		pcm.Delete();
		return false;
	};
	pcm._size = dwChunkSize;
	pcm._numChannel = wave_format.numChannels;
	pcm._bitPerSample = wave_format.bitsPerSample;
	pcm._freq = wave_format.sampleRate;
	if (pcm._bitPerSample == 32)
	{
		debug_err(format("不支持32位:{}", path_name));
		pcm.Delete();
		return false;
	}
	return true;
}

到此這篇關(guān)于C++解析wav文件方法介紹的文章就介紹到這了,更多相關(guān)C++解析wav內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言轉(zhuǎn)義字符詳解

    C語(yǔ)言轉(zhuǎn)義字符詳解

    這篇文章主要介紹了C語(yǔ)言轉(zhuǎn)義字符詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了C語(yǔ)言轉(zhuǎn)義字符該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • 詳解C++函數(shù)模板與分離編譯模式

    詳解C++函數(shù)模板與分離編譯模式

    這篇文章主要介紹了詳解C++函數(shù)模板與分離編譯模式的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)c++,感興趣的朋友可以了解下
    2020-08-08
  • Visual Studio2000系列版本安裝OpenGL的圖文教程

    Visual Studio2000系列版本安裝OpenGL的圖文教程

    這篇文章主要介紹了Visual Studio2000系列版本安裝OpenGL的圖文教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • C語(yǔ)言自定義函數(shù)的實(shí)現(xiàn)

    C語(yǔ)言自定義函數(shù)的實(shí)現(xiàn)

    這篇文章主要介紹了C語(yǔ)言自定義函數(shù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • 用C++的odeint庫(kù)求解微分方程

    用C++的odeint庫(kù)求解微分方程

    求解微分方程的數(shù)值解一般使用MATLAB等數(shù)值計(jì)算軟件,其實(shí)C++也可以求解微分方程,需要用到odeint庫(kù),它是boost庫(kù)的一部分。官方教程和示例比較晦澀,本文力求用較短的篇幅介紹它的基本用法,需要的朋友可以參考下面文章的具體內(nèi)容
    2021-09-09
  • C++中的自定義函數(shù)返回類(lèi)型

    C++中的自定義函數(shù)返回類(lèi)型

    這篇文章主要介紹了C++中的自定義函數(shù)返回類(lèi)型,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • OpenCV計(jì)算輪廓長(zhǎng)度/周長(zhǎng)和面積

    OpenCV計(jì)算輪廓長(zhǎng)度/周長(zhǎng)和面積

    這篇文章主要為大家詳細(xì)介紹了OpenCV計(jì)算輪廓長(zhǎng)度/周長(zhǎng)和面積,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • C語(yǔ)言數(shù)據(jù)結(jié)構(gòu) 棧的基礎(chǔ)操作

    C語(yǔ)言數(shù)據(jù)結(jié)構(gòu) 棧的基礎(chǔ)操作

    這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu) 棧的基礎(chǔ)操作的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • VC++?2019?"const?char*"類(lèi)型的實(shí)參與"LPCTSTR"類(lèi)型的形參不兼容解決

    VC++?2019?"const?char*"類(lèi)型的實(shí)參與"LPCTSTR"

    這篇文章主要給大家介紹了關(guān)于VC++?2019?"const?char*"類(lèi)型的實(shí)參與"LPCTSTR"類(lèi)型的形參不兼容的解決方法,文中通過(guò)圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-03-03
  • 在C語(yǔ)言編程中使用變量的基礎(chǔ)教程

    在C語(yǔ)言編程中使用變量的基礎(chǔ)教程

    這篇文章主要介紹了在C語(yǔ)言編程中使用變量的基礎(chǔ)教程,特別需要注意C語(yǔ)言中的指針變量,需要的朋友可以參考下
    2016-02-02

最新評(píng)論

张家口市| 建昌县| 宜宾市| 宜昌市| 宽甸| 固镇县| 夏邑县| 新巴尔虎左旗| 镇沅| 台前县| 安庆市| 惠州市| 渝北区| 枣阳市| 漯河市| 呼图壁县| 五指山市| 辽中县| 永丰县| 察哈| 泉州市| 八宿县| 盘山县| 章丘市| 丰县| 蚌埠市| 明星| 嘉义市| 闸北区| 开阳县| 鄂州市| 大荔县| 合水县| 天峨县| 邓州市| 台南市| 丘北县| 阿合奇县| 六安市| 平泉县| 沙坪坝区|