早些年给消防系统中做过一个报警器,为了节省资源,直接使用了单片机解码,再加上PWM输出直接推流到功放驱动扬声器,这个方案里面使用音频的PCM编码。
后来在做平衡车的时候,也是用到了同样的方法,为了让flash空间更紧凑,还进行了音频数据的ADPCM压缩。
做这一切之前,我们首先要获得音频文件,然后再进行处理或者直接把音频放到单片机的Flash里面,这里就不得不提到WAV格式的音频文件,这个是相对比较简单的格式。
WAV概述
wav是window系统中的后缀名,它的完整叫法应嘎是Waveform Audio File Format 也就是wave文件格式,它采用RIFF(Resource Interchange File Format)文件格式结构。通常用来保存PCM格式的原始音频数据,所以通常被称为无损音频。但是严格意义上来讲,WAV也可以存储其它压缩格式的音频数据。
声音文件大体上可以分为两类,分别对应于单声道(11.025KHz 采样率、8Bit 的采样值)和双声道(44.1KHz 采样率、16Bit 的采样值)。
采样率是指:声音信号在模数转换过程中,1秒内采样的次数。采样值是指每一次采样周期 内声音模拟信号的电压量化值。
对于单声道的声音文件,音频细节不多,因此可以采用8bit采样深度,11.025K的采样频率(8K其实也可以的),采样数据为八位的短整数(00H-FFH);而对于双声道立体声声音文件,每次采样数据为一个16位的整数(0000H-FFFFH),高八位和低八位分别代表左右两个声道。
音频采样与播放
人耳对频率的识别范围是 20HZ - 20000HZ, 如果每秒钟能对声音做 20000 个采样, 回放时就足可以满足人耳的基本需求. 所以 22050 的采样频率是常用的, 44100已是CD音质。
根据奈奎斯特定理,采样频率超过信号频率的2倍就可以还原出原始信号的细节,因此超过48000的采样对人耳已经没有意义。
就比如,早期电影帧数定为24帧,基本够用了,不过现如今,120帧的刷屏也是比比皆是了,之前是低估了人眼的灵敏度。
假设我们现在有了一段音频wav,采样率为22.050KHz,采样深度为16bit,双通道。文件大小为424644字节。
那么音频每秒的传输速率(位速, 也叫比特率、取样率)是 22050162 = 705600(bit/s), 换算成字节单位就是 705600/8 = 88200(字节/秒),也就是位速是 705.6kbps。
播放时间:424644(总字节数) / 88200(每秒字节数) ≈ 4.8145578(秒)。
要是存储成window可以播放的文件,也就是wave文件,除了音频本身的信息以外,我们还需要一些其他信息放在文件的头部, 包装标准的 PCM 格式的 WAVE 文件(.wav)中至少带有 42 个字节的头信息,这在计算播放时间时应该将其去掉, 所以就有:(424644-42) / (2205016*2/8) ≈ 4.8140816(秒)。 这样就比较精确了。
wave格式解析
WAV文件遵循RIFF规则,其内容以区块(chunk)为最小单位进行存储。
WAV文件一般由3个区块组成:RIFF chunk、Format chunk和Data chunk。另外,文件中还可能包含一些可选的区块,如:Fact chunk、Cue points chunk、Playlist chunk、Associated data list chunk等,主要用于存储作者,转接类的附加信息。
这里我们只看最基础的RIFF chunk、Format chunk和Data chunk。
常见的wave文件的格式图示
RIFF区块
以'RIFF'为标识
Size是整个文件的长度减去ID和Size的长度,也就是自己后面的长度。
Type是WAVE表示后面需要两个子块:Format区块和Data区块
FORMAT区块
以'fmt '为标识
Size表示该区块数据的长度(不包含ID和Size的长度)
AudioFormat表示Data区块存储的音频数据的格式,PCM音频数据的值为1
NumChannels表示音频数据的声道数,1:单声道,2:双声道
SampleRate表示音频数据的采样率
ByteRate每秒数据字节数 = SampleRate * NumChannels * BitsPerSample / 8
BlockAlign每个采样所需的字节数 = NumChannels * BitsPerSample / 8
BitsPerSample每个采样存储的bit数,8:8bit,16:16bit,32:32bit
DATA区块
以'data'为标识
Size表示音频数据的长度,N = ByteRate * seconds
Data音频数据
对于Data块,根据声道数和采样率的不同情况,为了方便播放,每个采样值连续放置,如果是8bit单声道,就一个字节一个字节排队。如果是16bit单声道,那就两个字节两个字节的排队。
如果是双声道,那就先放左声道的采样值,再放右声道的采样值,这样成对成对的排队。
下面我们看一个具体的例子,声音文件如下:
单片机中播放
如果要在单片机中播放wav文件,有两种做法,一种是直接将wav文件存储到Flash中,我们在播放相应的文件时,从相应起始地址读取前面的12个字节,判断是否是RIFF文件,格式为WAVE,同时取出文件长度。接下来就是搜索fmt块来解析通道数,采样频率,采样深度信息。
最后搜索到data块,按照fmt提供的信息,把data数据推流到DAC中。
当然,还有一种更简单的方式,那就是我们使用上位机解析wav文件,采用固定的采样频率和采样深度,单独取出data数据写入到flash中。这样只需要提供音频的起始地址和结束地址就可以直接播放了。
当然,还有一种更简单的方式,那就是我们使用上位机解析wav文件,采用固定的采样频率和采样深度,单独取出data数据写入到flash中。这样只需要提供音频的起始地址和结束地址就可以直接播放了。
6883