无需MP3模块!开发板+扬声器就能播放音频!
本帖最后由 TRIM 于 2024-9-9 20:41 编辑1.引入
我们做项目和作品时,难免会遇到一些地方需要语音提示或播放音频的地方。
我浏览了许多类似的作品,大多都是使用了语言合成或MP3模块来实现此功能。
但是,短短几秒钟的音频,真的需要再加一个模块来实现吗?
没必要。
不仅没有物尽其用,还得花钱,还占地方......
那有没有什么办法,仅仅接一个扬声器,就能够使其播放音频呢?
当然有!
我们先找一段音频来看看:
这是一段“你干嘛哎哟”的音频:
将其一部分放大,可以看到这样的图像:
再放大一点?
可以看到一堆小点。其中,点的横坐标代表了时间,纵坐标代表了此时扬声器的振幅
如果我们把这些点集的纵坐标用一个列表表示出来,知道了每个点之间间隔的时间,再控制开发板,在对应的时间向扬声器输出对应的电压,不就可以了吗?
理论上是可以的!
2.转换音频
问题来了:如何将音频转换成这样的列表呢?
PCM来了!(关于PCM)
PCM编码是最原始的音频编码,其他编码都是在它基础上再次编码和压缩的。它的数据正好符合我们所需要的列表!
我们有很多方式将音频转换成PCM格式
我使用了ffmpeg:
ffmpeg -i [需要转换的文件] -f u8 -ar [采样率] -ac 1 output.pcm
(当然,这需要你使用ffmpeg工具,并添加至环境变量)ffmpeg官网
(你也可以使用其他的软件转换,但必须转换编码为单声道的无符号8位PCM)
“u8”代表无符号的8位,也就是说,数据的范围是0-255,有利于在开发板上使用。
“采样率”指的是每秒钟有多少个点。一般的采样率有80001102516000220503200044100 Hz,采样率越高,音质越好,但是占用的空间也就越大。
在开发板处理较慢,仅有几MB的Flash的情况下,极力推荐采样率为8000!
我们成功获得了PCM格式的音频:output.pcm!
但是......打开怎么是乱码?
哦,PCM为了节省空间,使用了二进制来保存数据。我们再将其转换成我们想要的就行啦!
我使用了python来转换,很简单的:
# 打开pcm文件
with open('output.pcm', 'rb') as pcm_file:
pcm_data = pcm_file.read()
# 将其转换成列表
pcm_list = list(pcm_data)
# 保存到output.txt文件里
with open('output.txt', 'w') as txt_file:
txt_file.write(str(pcm_list))
运行,搞定!
打开文件,我们看到了一大堆数组,这就是我们可以看懂的数字了
接下来,我们只需编写程序,让开发板间隔一定时间,依次向扬声器输出这些值,就可以了!
3.编写程序
Arduino
Arduino已经有现成的库了,在库管理器搜索“PCM”即可
下面是这个库给的示例程序:(点击这里查看文字示例)
#include <PCM.h>
const unsigned char sample[] PROGMEM = {
在这里输入获得的数据(注意去掉中括号)
};
void setup()
{
startPlayback(sample, sizeof(sample));
}
void loop()
{
}
ps:这个库把扬声器的引脚写死了(20),要改得去库文件里改
ESP32
目前没找到相关的库!
所以我自己写了个:
#include <Arduino.h>
// 储存数据到Flash,Flash容量一般会高一些
const uint8_t myArray[] PROGMEM = {
在这里输入获得的数据(注意去掉中括号)
};
// 计算长度
const int arraySize = sizeof(myArray) / sizeof(myArray);
// 定义扬声器的管脚
const int buzzerPin = 20;
void setup(){
// 初始化PWM,中间是PWM的频率,高一些会更好,但如果不发声音说明太高了,开发板不支持,需要调小一些
ledcAttach(buzzerPin, 120000, 8);
}
void loop(){
for(int n = 0; n <= arraySize; n++){
// 从Flash读取相应的值
uint8_t value = pgm_read_byte(&myArray);
// 设置扬声器引脚的PWM
ledcWrite(buzzerPin, value);
// 这里等待的时间为采样率的倒数:1/8000秒,即125微秒,如果采样率不同需要调整
// 实际上由于执行代码需要时间,这个值需要调小一些,播放才是正常速度
// 如果大佬们能使用定时器来完成会更好哦!(强烈建议!)
delayMicroseconds(125);
}
delay(1000);
}
将程序上传,连接好扬声器,就可以发声啦!
4.闲谈
由于开发板储存较小,我的ESP32 C6(4MB)也只能储存22秒的音频数据
(这是在未配置Flash大小的情况下,大佬们也可手动配置,理论上每MB可以储存15秒)
但是对于一些小音频(提示语音、按钮音频等)来说,肯定是够的
实在不够,那就外接一张SD卡吧!
另外,蜂鸣器也可以代替扬声器,只不过音质差点罢了,但把它放在小盒子里音质又会好一些
总之,我的ESP32 C6和Arduino nano都成功地发出了清晰的“你干嘛哎哟”,期待大家利用此方法做出更加有创意的作品!
另外,如果有更好的方法或找到了更好的库,欢迎大佬们评论区留言!
附上音频、Python文件及转换好的PCM文件:
一个错误:在 2024-9-9 20:41 之前下载的文件中,bat及pcm数据均为22.05khz采样率,需要自行修改
页:
[1]