Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

ESP-WROOM-02(ESP8266)でAdafruit Audio FX Sound Boardを制御する

More than 3 years have passed since last update.

Audio FX Sound Boardは、3.3Vでも制御できる偉い子なので、
ESP8266で音制御するのに使えないかなと思って、試してみました。

1. Example、うごかへん...。

Adafruit_Soundboardのexamplesにある、menucommands.inoを実行したが動かなかった。

原因: 無限ループ

サンプルのsetup関数は、下記のようになってます。

menucommands.ino
// we'll be using software serial
SoftwareSerial ss = SoftwareSerial(SFX_TX, SFX_RX);

// pass the software serial to Adafruit_soundboard, the second
// argument is the debug port (not used really) and the third 
// arg is the reset pin
Adafruit_Soundboard sfx = Adafruit_Soundboard(&ss, NULL, SFX_RST);
// can also try hardware serial with
// Adafruit_Soundboard sfx = Adafruit_Soundboard(&Serial1, NULL, SFX_RST);

void setup() {
  Serial.begin(115200);
  Serial.println("Adafruit Sound Board!");

  // softwareserial at 9600 baud
  ss.begin(9600);
  // can also do Serial1.begin(9600)

  if (!sfx.reset()) { // ← こいつがわるさしてる
    Serial.println("Not found");
    while (1);
  }
  Serial.println("SFX board found");
}
  1. sfx.reset()のところで、常にfalseが帰ってきてしまい、while(1)が走り続けます。
  2. ESP8266のWDTが1000msで、1000ms以内に関数内の処理をおえないとリセットがかかります。
  3. 1に戻ります。

解消方法: reset()関数のreturnを無視 + SoftwareSerialからの卒業

というわけで、sfx.reset()がtrueを返すかとかを無視することにしました。
ついでに、SoftwareSerialが不安定なので、ESP8266ではIO2をSerial1のTXピンとして使えるので、下記のように処理を変更しました。

menucommands.ino
// pass the software serial to Adafruit_soundboard, the second
// argument is the debug port (not used really) and the third 
// arg is the reset pin
Adafruit_Soundboard sfx = Adafruit_Soundboard(&Serial1, NULL, SFX_RST);

void setup() {
  Serial.begin(115200);
  Serial.println("Adafruit Sound Board!");

  // softwareserial at 9600 baud
  Serial1.begin(9600);

  // just reset!
  sfx.reset();
}

これだけで良かったんや!!

2. 割込再生をやりたいんや(やりたいんや)

Audio FX Sound Boardさんは、MP3 Triggerさんみたいに割込で楽曲の切替ができません。
でも、やりたいんやで。

パターン1: 1曲目が勝手にとまって2曲目を再生できたら嬉しいけどできないパターン

たとえば、下記のようなコードを書いても、1曲目が勝手に止まって2番目が再生…とはいきません。
※ ただ、1曲目が2.5 秒以内の場合は2曲目は問題なく再生されます

sample.ino
// 1曲目を再生するます
sfx.playTrack(1);

// 2.5秒待ってから、、、
delay(2500);

// 1曲目を止めて、2曲目を再生したい、、、がしかし再生されず
sfx.playTrack(2);

パターン2: 1曲目を手動でとめて2曲目再生するが、ラグがかなりあるパターン

たとえば、下記のようにstop関数を入れてからやるという方法があるのですが、以下の理由からあまり使えません。
- 何も再生してない時にstop関数を走らせるとバグる
- stop関数からの次の再生までのラグが異様にある

sample.ino
// 1曲目を再生するます
sfx.playTrack(1);

// 2.5秒待ってから、、、
delay(2500);

// 手動でストップ(割と時間かかる)
sfx.stop();

// 2曲目を再生
sfx.playTrack(2);

 何も再生していない時にstop()関数を走らせないようにするには、ACKピン(再生中はLOW、ストップ中はHIGHを出力)を見ながらやるという方法もあるのですが、いずれにせよstop()関数を挟んでから別の楽曲再生となると、ちと遅くなってしまいます。

パターン3: たとえばstop()ではなく、reset()

強制的に楽曲を止めるといえば、reset()関数つかえばいいのかな?と思ってやってみたのですが、
Adafruit_Soundboardの元ソースでは、リセット後1000ms待つ処理が入ってました。
そりゃ遅いわ。

sample.ino
// 1曲目を再生するます
sfx.playTrack(1);

// 2.5秒待ってから、、、
delay(2500);

// 強制的に止めるために、リセット(しかしこれがおそい)
sfx.reset();

// 2曲目を再生
sfx.playTrack(2);

ちなみに、ライブラリの該当箇所のソース。

Adafruit_Soundboard.cpp
boolean Adafruit_Soundboard::reset(void) {
  digitalWrite(reset_pin, LOW);
  pinMode(reset_pin, OUTPUT);
  delay(10);
  pinMode(reset_pin, INPUT);
  delay(1000); // give a bit of time to 'boot up'

パターン4: 手動リセット(最終型)

というわけで、リセット後の起き上がり時間を直接操作できるように、
下記のようにしたところ、割と現実的な待ち時間になりました(1/4!)。

sample.ino
// 1曲目を再生するます
sfx.playTrack(1);

// 2.5秒待ってから、、、
delay(2500);

// 手動リセット(250msですむ)
digitalWrite(SFX_RST, LOW);
pinMode(SFX_RST, OUTPUT);
delay(10);
pinMode(SFX_RST, INPUT);
delay(250); // ここがミソ

// 2曲目を再生
sfx.playTrack(2);

ちなみに、200msとかにすると楽曲再生できなかったです。
以上。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away