一. 前言
在做UAC,PWM音頻播放的項目,需要解析WAV格式文件,通過UAC發(fā)送,或接收PCM數(shù)據(jù),驅(qū)動喇叭播放。這里對WAV文件格式相關(guān)內(nèi)容進(jìn)行整理備忘。
僅介紹使用非壓縮的PCM(Puls Code Modulation)脈沖編碼調(diào)制格式,其他壓縮格式這里不描述。
二.參考
http://tiny.systems/software/soundProgrammer/WavFormatDocs.pdf
http://soundfile.sapp.org/doc/WaveFormat/
http://www.lightlink.com/tjweber/StripWav/WAVE.html
三.格式解析
WAVE文件格式是微軟RIFF多媒體文件存儲規(guī)范的一個子集。RIFF文件從一個文件頭開始,后面跟著一系列數(shù)據(jù)塊。WAVE文件通常只是一個RIFF文件,其中包含一個由兩個子塊組成的“WAVE”塊——一個“fmt”塊指定數(shù)據(jù)格式,一個“data”塊包含實際的示例數(shù)據(jù)。我們稱這種形式為“規(guī)范形式”。
如下所示由RIFF fmt data三個chunk組成。
Offset Size Name Description
規(guī)范的WAVE格式以RIFF報頭開始:
0 4 ChunkID ASCII的"RIFF" 0x52494646 大端
4 4 ChunkSize 36+SubChunk2Size即 4+(8+SubChunk1Size)+(8+SubChunk2Size)
ChunkSize之后所有內(nèi)容的大小即
整個文件-8即不包括ChunkID和ChunkSize的大小.
8 4 Format ASCII的"WAVE"(0x57415645 大端).
"WAVE" 包括以下兩個subchunks: "fmt " 和 "data":
"fmt " subchunk描述聲音數(shù)據(jù)的格式:
12 4 Subchunk1ID ASCII的 "fmt "(0x666d7420 大端).
16 4 Subchunk1Size 對于PCM為16.Subchunk1Size后本chunk剩余部分大小.
20 2 AudioFormat 格式:PCM = 1(即線性量化值),其他值為壓縮格式.
22 2 NumChannels 通道數(shù):Mono = 1, Stereo = 2, etc.
24 4 SampleRate 采樣率:8000, 44100, etc.
28 4 ByteRate 字節(jié)速率: SampleRate * NumChannels * BitsPerSample/8
32 2 BlockAlign 塊大小,即一個采樣所有通道的數(shù)據(jù)量:NumChannels * BitsPerSample/8(是不是應(yīng)該向上取整?)
34 2 BitsPerSample 8 bits = 8, 16 bits = 16, etc.
2 ExtraParamSize 其他參數(shù)大小:對于PCM沒有
X ExtraParams 其他參數(shù)
"data" subchunk 包括數(shù)據(jù)的大小和實際的數(shù)據(jù):
36 4 Subchunk2ID ASCII的"data"(0x64617461 大端).
40 4 Subchunk2Size 后續(xù)數(shù)據(jù)大小:NumSamples * NumChannels * BitsPerSample/8.
44 * Data 實際的數(shù)據(jù).
以上注意所有整數(shù)是小端格式,字符ID和字符format都是大端(按照字符順序,從低地址開始按順序依次存放)。WAVE數(shù)據(jù)文件的默認(rèn)字節(jié)順序是小端序。使用大端字節(jié)排序方案編寫的文件具有標(biāo)識符RIFX而不是RIFF。
樣本數(shù)據(jù)必須在偶數(shù)字節(jié)邊界上結(jié)束 。
8位采樣被存儲為無符號字節(jié),范圍從0到255。16位采樣被存儲為2補(bǔ)碼有符號整數(shù),范圍從-32768到32767。
在Wave數(shù)據(jù)流中可能有額外的子塊。
RIFF代表資源交換文件格式。
多媒體應(yīng)用需要存儲和管理各種各樣的數(shù)據(jù),包括位圖、音頻數(shù)據(jù)、視頻數(shù)據(jù)和外圍設(shè)備控制信息。RIFF提供了一種存儲所有這些不同類型數(shù)據(jù)的方法。RIFF文件包含的數(shù)據(jù)類型由文件擴(kuò)展名表示??赡艽鎯υ赗IFF文件中的數(shù)據(jù)示例如下:
·Audio/visual interleaved data (.AVI)
·Waveform data (.WAV)
·Bitmapped data (.RDI)
·MIDI information (.RMI)
·Color palette (.PAL)
·Multimedia movie (.RMN)
·Animated cursor (.ANI)
·A bundle of other RIFF files (.BND)
四.舉例說明
一個WAVE文件的前面72字節(jié)如下
52 49 46 46** 24 08 00 00 57 41 56 45 66 6d 74 20 10 00 00 00 01 00** 02 00** 22 56 00 00 88 58 01 00 04 00 10 00 64 61 74 61 **00 08 00 00 00 00 00 00 24 17 1e f3 3c 13 3c 14 16 f9 18 f9 34 e7 23 a6 3c f2 24 f2 11 ce 1a 0d
另外一個文件格式解析如下
字節(jié)速率: SampleRate * NumChannels * BitsPerSample/8 = 44100216/2=176,400=0x0002B110
五.音頻處理工具
二進(jìn)制編輯查看010Editor
Sox:https://sox.sourceforge.net/Main/HomePage
六.WAV文件曲線顯示
# -*- coding: utf-8 -*-
import wave
import pylab as pl
import numpy as np
# 打開WAV文檔
f = wave.open(r"1.wav", "rb")
# 讀取格式信息
# (nchannels, sampwidth, framerate, nframes, comptype, compname)
params = f.getparams()
nchannels, sampwidth, framerate, nframes = params[:4]
print(params)
# 讀取波形數(shù)據(jù)
str_data = f.readframes(nframes)
f.close()
#將波形數(shù)據(jù)轉(zhuǎn)換為數(shù)組
wave_data = np.fromstring(str_data, dtype=np.short)
wave_data.shape = -1, 2
wave_data = wave_data.T
time = np.arange(0, nframes) * (1.0 / framerate)
# 繪制波形
pl.subplot(211)
pl.plot(time, wave_data[0])
pl.subplot(212)
pl.plot(time, wave_data[1], c="g")
pl.xlabel("time (seconds)")
pl.show()
七.解析C代碼
#define CHUNK_RIFF "RIFF"
#define CHUNK_WAVE "WAVE"
#define CHUNK_FMT "fmt "
#define CHUNK_DATA "data"
?
#define AUDIO_FORMAT_PCM 0x01
?
typedef struct
{
uint32_t off;
uint32_t chunksize;
uint16_t audioformat;
uint16_t numchannels;
uint32_t samplerate;
uint32_t byterate;
uint16_t blockalign;
uint16_t bitspersample;
uint32_t datasize;
}wav_t;
?
int wav_decode(uint8_t* addr, wav_t* wav);
?
int wav_decode(uint8_t* addr, wav_t* wav)
{
uint8_t* p = addr;
uint32_t chunksize;
uint32_t subchunksize;
if(0 != memcmp(p,CHUNK_RIFF,4))
{
return -1;
}
p += 4;
chunksize = (uint32_t)p[0] | ((uint32_t)p[1]< 8) | ((uint32_t)p[2]< 16) | ((uint32_t)p[3]< 24);
wav- >chunksize = chunksize;
p += 4;
if(0 != memcmp(p,CHUNK_WAVE,4))
{
return -2;
}
p += 4;
?
do
{
if(0 == memcmp(p,CHUNK_FMT,4))
{
p += 4;
subchunksize = (uint32_t)p[0] | ((uint32_t)p[1]< 8) | ((uint32_t)p[2]< 16) | ((uint32_t)p[3]< 24);
p += 4;
/* 解析參數(shù) */
wav- >audioformat = (uint16_t)p[0] | ((uint16_t)p[1]< 8);
if(wav- >audioformat == 0x0001)
{
p += 2;
wav- >numchannels = (uint16_t)p[0] | ((uint16_t)p[1]< 8);
p += 2;
wav- >samplerate = (uint32_t)p[0] | ((uint32_t)p[1]< 8) | ((uint32_t)p[2]< 16) | ((uint32_t)p[3]< 24);
p += 4;
wav- >byterate = (uint32_t)p[0] | ((uint32_t)p[1]< 8) | ((uint32_t)p[2]< 16) | ((uint32_t)p[3]< 24);
p += 4;
wav- >blockalign = (uint16_t)p[0] | ((uint16_t)p[1]< 8);
p += 2;
wav - >bitspersample = (uint16_t)p[0] | ((uint16_t)p[1]< 8);
p += 2;
}
else
{
p += subchunksize;
}
}
else if(0 == memcmp(p,CHUNK_DATA,4))
{
p += 4;
subchunksize = (uint32_t)p[0] | ((uint32_t)p[1]< 8) | ((uint32_t)p[2]< 16) | ((uint32_t)p[3]< 24);
wav- >datasize = subchunksize;
p += 4;
wav- >off = (uint32_t)(p- addr);
return 0;
}
else
{
p += 4;
subchunksize = (uint32_t)p[0] | ((uint32_t)p[1]< 8) | ((uint32_t)p[2]< 16) | ((uint32_t)p[3]< 24);
p += 4;
p += subchunksize;
}
}while((uint32_t)(p - addr) < (chunksize + 8));
return -3;
}
八.測試文件下載
https://samplelib.com/zh/sample-wav.html
審核編輯:湯梓紅
-
usb
+關(guān)注
關(guān)注
60文章
8158瀏覽量
271691 -
音頻
+關(guān)注
關(guān)注
29文章
3030瀏覽量
83217 -
驅(qū)動開發(fā)
+關(guān)注
關(guān)注
0文章
133瀏覽量
12279 -
DWC2
+關(guān)注
關(guān)注
0文章
35瀏覽量
243
發(fā)布評論請先 登錄
基于DWC2的USB驅(qū)動開發(fā)-0x01開篇介紹與新思DWC2 USB2.0控制器簡介

基于DWC2的USB驅(qū)動開發(fā)-0x02 DWC2 USB2.0 IP功能特征介紹

基于DWC2的USB驅(qū)動開發(fā)-IAD描述符詳解

基于DWC2的USB驅(qū)動開發(fā)-USB復(fù)位詳解

基于DWC2的USB驅(qū)動開發(fā)-USB連接詳解

基于DWC2的USB驅(qū)動開發(fā)-設(shè)備類驅(qū)動框架

基于DWC2的USB驅(qū)動開發(fā)-數(shù)據(jù)不能發(fā)送問題分析案例

請問如何把WAV,MP3格式的音頻文件轉(zhuǎn)化為16位的數(shù)據(jù)IIS格式?
【NXP LPC54110試用體驗】WAV音頻文件
基于STM32的WAV音頻格式播放器
WAV格式音頻文件剪切工具軟件下載

數(shù)字音頻文件格式與接口標(biāo)準(zhǔn)

一招教你快速解析WAV文件格式

評論