通常使用三个参数来表示声音,量化位数
、取样频率
、采样点振幅
。
量化位数分为8位
、16位
、24位
三种,声道有单声道
和立体声
之分。
单声道振幅数据为n * 1矩阵点,立体声为n * 2矩阵点,取样频率一般有11025Hz(11kHz)
,22050Hz(22kHz)
,44100Hz(44kHz)
三种。
大概了解音频采样即可。
主要明白,就是把传感器(麦克风)在某瞬间(某周期内,用取样频率算)的电压值采集进来,用ADC转换成对应的数字位数存下来,就是采样量化了。
WAV文件是什么
WAV为微软公司(Microsoft)开发的一种声音文件格式,它符合RIFF(Resource Interchange File Format)文件规范。
用于保存Windows平台的音频信息资源,被Windows平台及其应用程序所广泛支持,该格式也支持MSADPCM、CCITT A LAW等多种压缩运算法。
支持多种音频数字,取样频率和声道,标准格式化的WAV文件和CD格式一样,也是44.1K的取样频率,16位量化数字,因此在声音文件质量和CD相差无几!
WAV打开工具是WINDOWS的媒体播放器。
不过尽管音质出色,但在压缩后的文件体积过大!相对其他音频格式而言是一个缺点。
其文件大小的计算方式为:WAV格式文件所占容量
(B) = (取样频率 X量化位数X 声道) X 时间 / 8 (字节 = 8bit)
每一分钟WAV格式的音频文件的大小为10MB,其大小不随音量大小及清晰度的变化而变化。
WAV是最接近无损的音乐格式,所以文件大小相对也比较大。
所有的WAV都有一个文件头,这个文件头音频流的编码参数。
数据块的记录方式是little-endian字节顺序,标志符并不是字符串而是单独的符号。
所谓的little-endian就是小端序,举个例子:
0x55AA,这样一个16bit的数据,在WAV文件中存储的形式就是 : AA 55
所以在使用这个数据的时候, 需要将
1 | data = (0x55 << 8) | (0xAA); |
如果采样频率是8bit的,就不用转换了。
关于WAV文件头格式
偏移地址 | 大小 | 数据块类型 | 内容 |
---|---|---|---|
00H~03H | 4 | 4字符 | 资源交换文件标志(RIFF) |
04H~07H | 4 | 长整数 | 从下个地址开始到文件尾的总字节数 |
08H~0BH | 4 | 4字符 | WAV文件标志(WAVE) |
0CH~0FH | 4 | 4字符 | 波形格式标志(fmt ),最后一位空格 |
10H~13H | 4 | 整数 | 过滤字节(一般为00000010H) |
14H~15H | 2 | 整数 | 格式种类(值为1时,表示数据为线性PCM编码) |
16H~17H | 2 | 整数 | 通道数,单声道为1,双声道为2 |
18H~1BH | 4 | 长整数 | 采样频率 |
1CH~1FH | 4 | 长整数 | 波形数据传输速率(每秒平均字节数) |
20H~21H | 2 | 整数 | DATA数据块长度,字节 |
22H~23H | 2 | 整数 | PCM位宽 |
24H~27H | 4 | 4字符 | “fact”,该部分一下是可选部分,即可能有,可能没有 |
28H~2BH | 4 | 长整数 | size,数值为4 |
关于WAV文件尾需要特别强调
有些文件是添加了结尾的<LIST>
这样开头的文件尾的,包含了一些录制的公司的信息,日期,等等…
所以对于这样的文件尾还是需要做相应的处理..
总的来说,提取真实有效的数据段就好了(剔除头和尾)。
当然,在我的实验中,我采取的方式是,将8bit的数据段提取出来后,放进这样一个数组里面。
1 | const unsigned char datap[] = {}; |
这样,编译的时候,这个数组的区域自然会被编译器放到FLASH当中。当然,也可以不放在flash中,因为实在太占空间了。
会有更好的办法,这是后话,待会儿再说。
当然,有的盆友就不明白了,都看不到这个数据,怎么提取…
别担心,当然有好用的工具啦..
Binary Viewer,这是一个在windows环境中的一个以二进制查看文件的工具,能够显示偏移量,hex,ascii,格式化输出等等..
可以自定义数据输出格式的功能也是很棒,并且这个软件才1.8M。
能看数据了,还不够,这样看数据来识别WAV文件是什么采样率,什么bit位,都太不直观了..
于是又有mediainfo这个软件,能够显示WAV文件的详细信息.采样率,量化bit什么都看到了..
所以你觉得有了这些就够了吗? 不!
还有个最重要的软件,Audition。
这个软件不仅能够修改WAV的采样频率,还能修改量化bit的大小,简直就是个神器。重要的是,能够看到每个采样点的波形点…
简直…太棒辣..
解码!PWM来模拟DA输出
现在开始说PWM模拟DA输出。对于玩过单片机的人来说,PWM并不陌生,即,脉冲宽度调制。实际上PWM出来的,是一个方波。
大家都知道,但是它有一个周期,所以有周期,那么就有频率了。好,请记住此处是PWM频率!与之前所说的音频采样频率不是同一个东西。
那么占空比是什么呢?占空比就是在一个方波周期内,高电平脉冲宽度所占有周期的百分比..也不能说是百分比,总之就是那个意思了…
如果把一个周期分成0xff份,那0x01,高电平就占有1/255的周期时间。那么使用这个比例去设置电压,假设所使用的单片机使用的是5V电压基准,那么设置占空比0x01,则
5V/255*1 = 0.019607843137255V
所以现在你算出来,把PWM周期分成255份,然后将占空比设置为1/255。
现在拿万用表量一下,现在PWM输出的电压值是不是0.019607843137255V。
对吧,没错吧…
那么再试试将占空比设置为128,再用万用表测量一下…
对吧,2.5V有了吧..
这样,我们就能够使用PWM模拟DA输出了。既然这样能够调节占空比来输出不同的电压了,那么我们应该使用什么样的频率来输出PWM呢?
当然是结合MCU的频率,高于WAV文件的采样频率更好更好。之前看了别的文章,说是两倍于采样频率即可(我的实验中采用两倍)。
到这个地方,请记住,这个PWM频率,是用来产生模拟DA电压的频率,不是播放音频文件的频率或音频文件的采样频率!
那么我们播放音频文件到底使用什么样的节奏(频率)呢?
当然是使用采用频率啦,不然播放出来的音乐总感觉哪里不对,要么就是一片杂音。
为了达到准确的播放频率,那就取决于我们定时器中断的时间了。
比如,1000us进一次中断,那么我们播放音频文件的频率就是1kHz。
如果我们的WAV文件的采样率是1kHz,且数据位是8bit。
那么每次进中断(此处的中断,使用的是定时器中断)的时候,就按照8bit的数据,调整不同的占空比。
1000us改变一次电压,就在横纵坐标(横轴是时间,纵轴是电压)。
这样一个一个时间-电压点打出来,就在横纵坐标上画出来了音频文件的曲线。
用Audition打开所播放的音频波形和画出来的音频曲线大概对比一下就能发现,图像是一模一样的…
好,现在应该就能够听见喇叭出来的每秒的声音了吧..
当输入的模拟信号上限频率为 fc,只要取样脉冲 us(t)的重复频率 fs不低于 fc
的两倍,总可以无失真地由取样后的离散信号恢复出原来的模拟信号,即不失真输出条件为:
fs≥2fc (2.1)
硬件怎么设计
MCU引脚—->功放—>滤波器—>喇叭。
Google一下,网络上很多很多的示范电路…
我就不贴图了,对。
是因为我…..懒!
关于之前提到的,不要存flash里面的问题。不够用当然要想办法,用SD卡吧,SPI读写,毕竟大多数人都是这么干的..
有时候从众也不是一件坏事..
つづく
是,没错,我用MCU放了一首张学友的《爱我别走》。
音质,简直毁了…
对于想做得更考究的朋友,除了在硬件上需要有所优化。
在软件上需要使用更高采样率的音频源(44.1k)。
另外还有一种玩法,就是从PCM的原始数据(WAV)上着手,使用算法将midi的音算出来。这种玩法的好处是,
非常节省资源,非常适合在MCU等资源紧缺的器件上使用。
参考文献
1.毕厚杰,《新一代视频压缩编码标准——H.264/AVC》,人民邮电出版社,2009,2.1.2,数字电视的 PCM 原理