<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
一開始本來在網上找程式碼,不過改了好幾個都不是很好用。因為很多wav檔案的fmt塊後面並不是data塊,經常還帶有其他塊,正確的方法應該是按MSDN的方法,找到data塊再讀取。
最後介面如下:
class AudioReader { public: struct PCM { int _numChannel;//通道數 1,2 AL_FORMAT_MONO8,AL_FORMAT_STEREO8 int _bitPerSample;//取樣數 8,16 byte* _data; size_t _size; size_t _freq;//取樣率 void Delete() { delete[] _data; } }; static bool ReadWAV(string_view path_name, PCM& pcm); };
開啟檔案,這裡就是普通的檔案流,按二進位制、唯讀開啟檔案即可:
ifstream ifs; if (!g_file->GetFile(path_name, ifs)) { debug_err(format("開啟檔案失敗:{}", 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("匹配標記失敗(fourccWAVE):{}", path_name)); return false; }
其中fourccRIFF和fourccWAVE是我們定義的標記,也就是處理了下大小端,如下:
#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兩個函數,分別是查詢一個塊,和讀取一個塊。程式碼實現有點長,可以參考後面我給出的完整原始碼。
接著,查詢並讀取fmt塊,這個塊描述了wav檔案的音訊屬性,結構如下(部分欄位會用到):
//16位元組 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("查詢塊失敗(fourccFMT):{}", path_name)); return false; } //讀wave資訊 WAVEFormat wave_format; if (!ReadChunkData(ifs, &wave_format, dwChunkSize, dwChunkPosition)) { debug_err(format("讀取塊失敗(wave_format):{}", path_name)); return false; };
接下來查詢data塊,根據返回的大小分配記憶體:
//查詢音訊資料 if (!FindChunk(ifs, fourccDATA, dwChunkSize, dwChunkPosition)) { debug_err(format("查詢塊失敗(fourccDATA):{}", path_name)); return false; }; pcm._data = new byte[dwChunkSize];
然後讀取data塊,將資料讀取到我們分配的記憶體pcm._data。然後記錄下一些重要的欄位。由於OpenaAL不能直接播放32位元(只8、16)的資料,這裡簡單返回失敗。
if (!ReadChunkData(ifs, pcm._data, dwChunkSize, dwChunkPosition)) { debug_err(format("讀取塊失敗(pcm資料):{}", 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;
可以此處獲取最新的原始碼(我將來會新增ogg格式的解析),也可以用下面的:傳送門
//.h class AudioReader { public: struct PCM { int _numChannel;//通道數 1,2 AL_FORMAT_MONO8,AL_FORMAT_STEREO8 int _bitPerSample;//取樣數 8,16 byte* _data; size_t _size; size_t _freq;//取樣率 void Delete() { delete[] _data; } }; static bool ReadWAV(string_view path_name, PCM& pcm); }; //16位元組 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("開啟檔案失敗:{}", 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("匹配標記失敗(fourccWAVE):{}", path_name)); return false; } //查詢fmt塊 if (!FindChunk(ifs, fourccFMT, dwChunkSize, dwChunkPosition)) { debug_err(format("查詢塊失敗(fourccFMT):{}", path_name)); return false; } //讀wave資訊 WAVEFormat wave_format; if (!ReadChunkData(ifs, &wave_format, dwChunkSize, dwChunkPosition)) { debug_err(format("讀取塊失敗(wave_format):{}", path_name)); return false; }; //查詢音訊資料 if (!FindChunk(ifs, fourccDATA, dwChunkSize, dwChunkPosition)) { debug_err(format("查詢塊失敗(fourccDATA):{}", path_name)); return false; }; pcm._data = new byte[dwChunkSize]; if (!ReadChunkData(ifs, pcm._data, dwChunkSize, dwChunkPosition)) { debug_err(format("讀取塊失敗(pcm資料):{}", 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; }
到此這篇關於C++解析wav檔案方法介紹的文章就介紹到這了,更多相關C++解析wav內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45