FireBeetle 直接放声(DAC篇)

声音,是物体振动产生的,通常情况下通过空气将震动传递到耳朵我们就能听到了声音。常见的喇叭就是一种将电能转换为机械能的器件。

FireBeetle 核心是 ESP32-WROOM-32D, 主控频率高达240Mhz, Flash Rom 有 16MB。这里介绍一种直接通过它来播放声音的方法。用这种方法可以直接通过喇叭来播放音乐,但是因为 ESP32 输出功率有限,直接推动喇叭产生的声音很小。为此,这里使用“Gravity: 带功放喇叭模块”来实现更大的声音输出。

Gravity: 带功放喇叭模块

基本原理是将数据存储在 FireBeetle 的Flash 上,然后通过 ESP32 的DAC 直接输出之。

具体步骤如下:

第一步,将音乐转化为8位单声道。我是用 Golden Wave ,将罗大佑的 “恋曲1990.mp3“转为 8000Hz 8 Bits的Wav 格式。

Golden Wave 打开音频文件

选择 Resample
使用 8000Hz 重新采样

注意,这里必须重新采样为 8000Hz。直接另存为的话实际上并没有设置为 8000Hz。

保存为8Bits 单声道

GoldenWave 自动重新打开文件

重新加载处理后的 8000Hzm 8Bits Wave 音频数据

第二步,使用Bin2C 将这个 Wav 生成C 语言的头文件。命令如下:

bin2c.exe -o audio.h 19908bits.wav

实际上数据中包含了 wav的文件头,但是因为数据量不大,对播放几乎没有影响,所以这里也没有额外处理。

这样,我们就有了这个歌曲的数据。特别需要注意的有下面两点:

1.需要设置编译模式为  3MB APP/9MB FATFS 模式

2.原始的 Wav 最好不要超过 2.7MB(2,831,155.2Bytes, 0x2B3333Bytes),否则会超过最大程序的限制。这次我使用的 WAV 是 2,527,766 字节的,编译后结果如下:

Sketch uses 2746845 bytes (87%) of program storage space. Maximum is 3145728 bytes.

Global variables use 15372 bytes (4%) of dynamic memory, leaving 312308 bytes for local variables. Maximum is 327680 bytes.

第三步,我们需要一些基本的测试。首先,编写一个循环,使用 dacwrite() 输出数值,输出2000000次花费了11102ms ,也就是说一次 dac 输出需要花费 0.005551ms。前面提到使用的 Wav采样率是 8000Hz。这样一个周期是 1/8000=0.125ms。 因此,为了重建一个声音,我们需要 0.125/0.005551=22.5184次 dacwrite。

第四步,编写代码:

#include "audio\SoundData.h"
void setup() {
}
void loop() {
  for (unsigned int i=0;i<2527766;i++) {
    for (int j=0;j<21;j++) dacWrite(25,WarOfWorldsWav[i]);
  }
}

我们将音频数据放在audio目录下的SoundData.h文件中,这样每次Arduino 打开ino 文件的时候并不会一起打开音频数据,否则因为音频数据很大,会耽误很多时间,有时候甚至会导致Arduino 编译器崩溃。另外,和前面提到的22次 dacwrite 不同,代码使用的是21次,因为for循环有一些开销,所以实际测量下来22次有一点点慢。

第五步,Gravity: 带功放喇叭模块,上面有3个线,VCC和GND 连接到 FireBeetle上,信号输入Pin 连接到 FireBeetle D2 (IO25)。

下载代码后即可播放出音乐了。

很明显,上述方法足够简单,能够存储 2.7*1024*1024/8000=354秒的音频。在要求不高的场合下完全能够满足要求。

可以直接连接喇叭,只是声音小一些

8Bits Wave 格式的歌曲:

完整的代码和数据:

工作的视频:

https://www.bilibili.com/video/BV1Df4y1x7WF?share_source=copy_web

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注