早些年给消防系统中做过一个报警器,为了节省资源,直接使用了单片机解码,再加上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
这个区域只需要关心 NumChannels SampleRate BitsPerSample 三个参数就可以了,其它的都是依据这三个计算出来的。
DATA区块

- 以 ‘data’ 为标识
- Size表示音频数据的长度,N = ByteRate * seconds
- Data音频数据
对于Data块,根据声道数和采样率的不同情况,为了方便播放,每个采样值连续放置,如果是8bit单声道,就一个字节一个字节排队。如果是16bit单声道,那就两个字节两个字节的排队。
如果是双声道,那就先放左声道的采样值,再放右声道的采样值,这样成对成对的排队。
下面我们看一个具体的例子,声音文件如下:
Plain Text 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

单片机中播放
如果要在单片机中播放wav文件,有两种做法,一种是直接将wav文件存储到Flash中,我们在播放相应的文件时,从相应起始地址读取前面的12个字节,判断是否是RIFF文件,格式为WAVE,同时取出文件长度。接下来就是搜索fmt块来解析通道数,采样频率,采样深度信息。
最后搜索到data块,按照fmt提供的信息,把data数据推流到DAC中。
当然,还有一种更简单的方式,那就是我们使用上位机解析wav文件,采用固定的采样频率和采样深度,单独取出data数据写入到flash中。这样只需要提供音频的起始地址和结束地址就可以直接播放了。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...