可暂停播放MP3


本程序的最终实现可谓历经千辛万苦,先总结一下走过的弯路(脑子里经过的水):

1.ArduinoIDE提示“开发板和库有更新”,我见他提示很多次就点了更新,结果第二天打开IDE来用,M5Stack的开发板没了!

只好重下,结果因为github在外面,下载很多次都失败,无奈之下只好出去,找了一个稳定的线路,下载速度比之前快多了,结果又提示CRC校验错误,搜索了一下,解决方法是删掉C:\Users\***\AppData\Local\Arduino15\staging文件夹下的文件,安装成功(当时下的2.0.2版本,冥冥中注定了后面的遭遇),所以不要随便更新啊!

2.开发板问题解决后,我验证官网的PlayMP3FromSPIFFSToDAC例程,但总是有如下报错,

 联系工程师,得知是开发板版本高了,有些库不兼容,建议我退回1.0.9版本,退回后果然这个报错没了,但是仍然有和ESP8266Audio有关的编译错误,现在我有了类似的思路,回退ESP8266Audio库的版本,果然可以,编译顺利通过;所以更新带来的问题,回退解决,要耐心地去看报错提示,不要恐惧他

 3.例程编译通过了,文件也顺利传入了SPIFFS,但是我的M5Stack为什么不响啊?!

    经过漫长的探索,我现在觉得当初要是能响就是一个奇迹:

   (1)Speaker没有初始化,这要怪官方文档了:

    上图暗示了M5.begin()可以初始化speaker,但是我找到M5.begin()的实现:

     Speaker.begin()被注释掉了!!所以要想初始化Speaker要单独调用 Speaker.begin()

     ##不过后来我发现即使不单独用 Speaker.begin()(不初始化Speaker),也是可以正常发声的,很奇怪。

     但是模块出问题,还是应该首先想到模块有没有初始化,这一点我在刚开始编程时经常忘记

   (2)关键部分没有放到loop()里面去:

if (myplay&&mp3->isRunning()) {//mp3->begin()会将running成员设为true,isRunning()就是返回running的函数
    if (!mp3->loop()) mp3->stop();//这里的loop非常关键,包含了file的loop()和out的loop(),可以简单理解为每次大循环执行到这里的mp3->loop(),就会播放一点,mp3->stop()则释放相关内存
  }

     这个部分最重要,我却以为只要setup()里面mp3->begin()了就好,一直没有把上面的代码放入loop(),所以一直不会出声

     所以验证例程时,要谦逊小心,切忌想当然;照葫芦画瓢,也应当先把葫芦画好

  (3)做完这些终于可以发声了,但是只能一直放,停不下来怎么行,我又开始探索(走弯路):

   a.想读取按钮,却忘记通过M5.update()读取按钮变化

   b.使用按钮的isPressed(),出现短时间按下多次的情况,之前我以为是要做按键防抖,认真看了下官网的button部分,wasPressed()函数可以检测是否按下过一次

   c.通过避开mp3->loop()实现暂停播放,但是音乐停了,又有很大的噪音(大过Speaker初始化后隐隐的噪音),而且噪音的频率和暂停时刻正在播放的音有关,我个  人简单推测是out输出时,有硬件的电平没有复位,所以一直响某个音,后来我到AudioOutputI2S库里面找到了out->flush(),可以减小噪音,使其和暂停时刻无关,但是噪音还是比Speaker初始化后的噪音大

所以可以多在例程中找思路,也许是某个变量的值,也许是某个函数,又或者是它包含的头文件都可能是解决问题的线索

下面是最终的代码:

#include 
#include 
#include "AudioFileSourceSD.h"
#include "AudioFileSourceID3.h"
#include "AudioGeneratorMP3.h"
#include "AudioOutputI2S.h"

AudioGeneratorMP3 *mp3;
AudioFileSourceSD *file;
AudioOutputI2S *out;
AudioFileSourceID3 *id3;

bool myplay = false;
void setup() {
  M5.begin();
  M5.Speaker.begin();
  WiFi.mode(WIFI_OFF); 
  
  M5.Lcd.drawJpgFile(SD,"/a.jpg",0,0);
  file = new AudioFileSourceSD("/c.mp3");
  id3 = new AudioFileSourceID3(file);
  out = new AudioOutputI2S(0, 1); // Output to builtInDAC
  out->SetOutputModeMono(true);
  mp3 = new AudioGeneratorMP3();
  mp3->begin(id3, out);
}
void loop(){
  M5.update();
  if (myplay&&mp3->isRunning()) {
    if (!mp3->loop()) mp3->stop();
  } 
  if(M5.BtnC.wasPressed()){
    myplay = myplay^true;//异或运算,反转bool变量的值
    if(!myplay){
        out->flush();  
     }
  }
}

相关