DFPlayerを使ってMP3プレイヤーをつくる

今回はとても珍しく、玩具改造系ではありません。長男にせがまれてMP3プレイヤーを自作しました、というお話です。

開発経緯

私の玩具改造は長男が生まれる前からの趣味ですが、ぼちぼち長男が私の趣味を知る年齢にもなってきまして、「パパはなんかいろいろ自分で作れるらしい」ということを理解し始めました。

ということで、我が子に「○○を作って」と言われることはしばしばあるのですが、私も父親である前に一人の趣味人、作りたいものが常時渋滞している状態なので、基本的にはお断りさせて頂いておりました。

が、『ベイブレイラウザー』の制作中に「これ終わったら作ってあげるから」という約束をしてしまいましたので、観念して作成することにしました。

 

お題は『MP3プレイヤー』です。

。。。既製品を買った方が、遥かに出来はいいしお安いです。が、なぜかはよくわかりませんがとにかく作ってほしいとのことなので、私が死んだときの形見にしてもらうつもりで作ることにしました(残してくれるかわかりませんが)。

 

特徴

長男からの要求仕様はただ一つ。『スピーカーを接続できること』です。

「なぜ?」と思われた方がほとんどだと思いますが、これはウチの長男の特性としか言いようがないかもしれません。なんかスピーカーが好きみたいです。

ということで、それ以外の仕様は全て私に委ねられたので、私の方で以下のように仕様を定義して作成することにしました。

  1. 外部スピーカーを接続できる
  2. 内部スピーカーでも鳴らせる
  3. 乾電池で使える
  4. USBによる電源供給でも使える
  5. 再生/停止ボタン、NEXTボタン、PREVボタンがあり、ボリューム調整はダイヤル式
  6. ボタンが光る

1.は長男の要望。

2.は、今回使用するDFPlayerが単体でスピーカーを鳴らせる機能があるので、せっかくなので単体でも鳴らせるようにするため。

3.は、持ち運んでどこでも使えるようにするため。子どもが使うものなので、リチウムイオンポリマー充電池は使用しない方向で。

4.は、電池を気にせず使えるようにもしておきたいため。

5.は、最低限これだけあれば実用には耐え得るだろうというUI。

6.は、基本的に光っている方が長男が喜ぶため。

 

で、出来上がったものがこちら。

正面左がボリューム兼再生/停止ボタン、右側左がPREVボタン、右側右がNEXTボタン。見え辛いですが、真ん中にモノラルスピーカー。筐体は3Dプリンタ製です。

サイドにはマイクロSDカードのスロットと、長男ご要望のスピーカー接続用のジャック。

背面には電源スイッチと、給電兼プログラム書き替え用のUSB Type-C接続口。電源スイッチを右にすると電池駆動、左のままでUSBを挿すと、USB給電駆動になります。

底面には電池蓋があり、

単四電池3本で駆動させることができます。

機能はシンプルに、再生、停止、戻る、進む、音量調整のみ。

電源が入っている間は、こんな風にボタン類が点灯します。特に意味はないですが、電源オフし忘れには役立つかもしれません。思想的にはゲーミングPCみたいなものです。

実際に再生してみた様子がこちら。

 

内蔵スピーカーだと流石に音質は良くないですが、外付けスピーカーにするとだいぶマシになります。

 

ちなみに上の外付けスピーカーは格安の電池駆動アンプに適当なスピーカーを配線しただけのものなので、ちゃんとしたスピーカーならちゃんと鳴る(?)と思います。

 

ハードウェア解説

ごくごく簡単なものですが、一応使用した具材を紹介しておきます。

今回はプログラムとしてはめちゃめちゃシンプルなので、これで必要十分です。

 

肝心かなめのMP3プレイヤー。コピー品?が多数出回っていますが、正規品を使うのが安心です。スイッチサイエンス秋月電子の方がちょっと安く買えるかもしれません(送料次第かも)。

 

マイクロSDカードです。MP3ファイルを格納してDFPlayerにセットします。

 

DFPlayer用の便利アイテムです。このUNITにDFPlayerをセットすると、マイコンとの配線がわかりやすくなる他、スピーカーが接続され、さらに外付けスピーカー用のジャックも接続されます。「スピーカーを接続できるようにする」という今回の仕様にぴったりのアイテムでしたので、採用しました。なお、受託販売商品のようなので、いつまで手に入るかは製作者の方次第です。

 

上記のUNITは便利なアイテムなのですが、私の今回の工作で使用するには一つ難点があって、「ジャックの向きとSDカードのスロットの向きが逆」ということです。つまり、ジャックがケースの外を向くように取り付けてしまうと、SDカードのスロットが筐体の内側になってしまい、SDカードの抜き差しが困難になってしまいます。まあ、筐体の設計次第ではそれでも使用上は問題ないようには出来たと思いますが、SDカードスロットにはできるだけ簡単にアクセスできるようにしておきたかったので、スロットの向きを変えるためにこちらを併用することにしました。

 

ボリューム機能があり、かつ、ボタンとしても使えて、かつ、光る。ということで採用です。

 

こちらも光るボタン、ということで、NEXT/PREVボタン用に使用しました。ただ、9年ぐらい前に購入しておいたものを今回発掘して使用したので、今でも入手できるかは不明です。詳しい使い方は私の過去記事をご参照ください。

 

主な具材は以上で、あとは、スライドスイッチと単四電気3本用の電池ケースとかです。

 

筐体は3Dプリンタで作成するので、こんな感じでモデリング。

あんまり複雑なことはスキルが足りないのでできません。

印刷直後の写真は撮り忘れましたが、表面処理直後の写真がこちら。

カビが生えているわけではなく、パテを塗りこんでペンサンダーでやすりがけした後の状態です。この処理、とても面倒ではあるのですが、積層型の3Dプリンタだと、これをやるやらないで最終的な出来上がりの質感が全然違うので、やらざるを得ないという。

で、先の表面処理後にサーフェイサー(ブラック)→スプレー(メタルブラック)→スーパークリア(光沢)をかけた状態がこちら。これでも積層跡はそこそこ残りますが、それでも何もしないよりは遥かにマシです。

 

これでケースはできたので、あとは部品の組み込みです。回路図はこんな感じです。

すみません、PREVボタンとNEXTボタンのLEDの配線は省略してしまっています。というのも、PREVボタンとNEXTボタンは当初は光らせる予定がなかったのを、土壇場で光らせるように軌道修正したためです。

で、実際に組み込んでみた様子がこちら。

電池ケースはめ込み前。

電池ケースはめ込み後。

ハードウェアの解説としては以上です。最後はソフトウェア。

 

ソフトウェア解説

今回はプログラムとしてもメチャメチャ短いので、全文載せるだけで特に補足はなくて良いかなと思います。ライブラリとして、本家DFRobotのライブラリではなく、こちらのライブラリを使用しているぐらいです。

#define LOOP_DELAY_MS 10

#define PIN_MP3_RX   0
#define PIN_MP3_TX   1
#define PIN_SW_PREV  2
#define PIN_SW_NEXT  3
#define PIN_SW_PLAY  4
#define PIN_VOL      5
#define PIN_PLAY_LED 6
#define PIN_PREV_LED 7
#define PIN_NEXT_LED 8

#define ON  LOW
#define OFF HIGH

uint8_t sw_prev = OFF;
uint8_t sw_next = OFF;
uint8_t sw_play = OFF;
int8_t  vol     = 0;

uint8_t prev_sw_prev = OFF;
uint8_t prev_sw_next = OFF;
uint8_t prev_sw_play = OFF;
int8_t  prev_vol     = 0;

#include <DFPlayerMini_Fast.h>
#include <SoftwareSerial.h>

SoftwareSerial ss_mp3_player(PIN_MP3_RX, PIN_MP3_TX);
DFPlayerMini_Fast mp3_player;

// 音声ファイルはSDカードのrootに直置きでよいが、
// Macの場合は._xxxxのファイルが勝手に生成されて動作がおかしくなるので、
// コマンドラインの$cd /Volumes でSDカードに移動した後、
//  $rm ._*.mp3 などで該当のファイルをまとめて消す必要あり

bool is_playing = true; // 電源ONで自動スタートするため

int8_t getVolume(uint16_t vol_raw){
  //Serial.print(F("Vol_Raw:"));
  //Serial.println(vol_raw);
  int8_t vol = vol_raw/34 + 1;
  if(vol > 30){
    vol = 30;
  }
  return vol;
}

/////////////////////////////////////////////////////

void setup() {
  pinMode(PIN_SW_PREV, INPUT_PULLUP);
  pinMode(PIN_SW_NEXT, INPUT_PULLUP);
  pinMode(PIN_SW_PLAY, INPUT_PULLUP);
  pinMode(PIN_VOL, INPUT);
  pinMode(PIN_PLAY_LED, OUTPUT);
  pinMode(PIN_PREV_LED, OUTPUT);
  pinMode(PIN_NEXT_LED, OUTPUT);

  // MP3プレイヤーセットアップ
  ss_mp3_player.begin(9600);
  if(!mp3_player.begin(ss_mp3_player)) {
    Serial.println(F("Unable to begin music_player:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true);
  }
  Serial.println(F("dfplayer online."));

  prev_vol = vol = getVolume(analogRead(PIN_VOL));
  Serial.print(F("Volume: "));
  Serial.println(vol);
  delay(500); // 間を開けるのが短すぎるとコマンドが有効にならないので注意
  mp3_player.volume(vol);
  delay(500); // 間を開けるのが短すぎるとコマンドが有効にならないので注意
  mp3_player.startRepeatPlay();

  digitalWrite(PIN_PLAY_LED, HIGH);
  digitalWrite(PIN_PREV_LED, HIGH);
  digitalWrite(PIN_NEXT_LED, HIGH);
}

/////////////////////////////////////////////////////

void loop() {

  sw_prev = digitalRead(PIN_SW_PREV);
  sw_next = digitalRead(PIN_SW_NEXT);
  sw_play = digitalRead(PIN_SW_PLAY);
  vol     = getVolume(analogRead(PIN_VOL));

  if(prev_sw_prev == OFF && sw_prev == ON){
    mp3_player.playPrevious();
    Serial.println(F("Prev."));
    delay(200);
  }

  if(prev_sw_next == OFF && sw_next == ON){
    mp3_player.playNext();
    Serial.println(F("Next."));
    delay(200);
  }

  if(prev_sw_play == OFF && sw_play == ON){
    if(is_playing){
      mp3_player.pause();
      Serial.println(F("Pause."));
    }else{
      mp3_player.resume();
      Serial.println(F("Resume."));
    }
    is_playing = !is_playing;
  }

  if(vol - prev_vol < -1 || 1 < vol - prev_vol){
    // 1刻みの変化にするとボリューム次第で値がふらつくので、
    // 2段階以上の変化があったときに値を実際にセットするようにする
    mp3_player.volume(vol);
    Serial.print(F("Volume: "));
    Serial.println(vol);
    prev_vol = vol;
    delay(200);
  }

  prev_sw_prev = sw_prev;
  prev_sw_next = sw_next;
  prev_sw_play = sw_play;

  delay(LOOP_DELAY_MS);
}

ちなみに、WindowsでなくMacで開発している人向けの注意点が一つあります。mp3ファイルはSDカードのルート直下に置いていけば問題なく、置いた順で再生されるようになるのですが、ファイルをそのままMacからSDカードにコピーすると、多分動作が変になると思います。具体的には、PREV/NEXTボタンを押しても前/次の曲が再生されず、もう一度押すと再生される。これは、MacがSDカードにファイルをコピーする際に、隠しファイルを同時に生成してしまって(※例えば、「0001_test.mp3」というファイルをコピーすると、同時に「._0001_test.mp3」が勝手に生成される)、その隠しファイルを再生しようとしてしまうためです。

そもそも勝手に隠しファイルが生成されないようにできればそれが一番良いのですが、その方法があるのかないのかよくわかっていないので、私は必要なmp3ファイルを全てSDカードにコピーした後、「ターミナル」で「$cd /Volumes/xxxx」でSDカードに入った後、「$rm ._*.mp3」で隠しファイルをまとめて消しています。これで、意図通りの動作になると思います。

 

まとめ

以上、DFPlayerを使った自作MP3プレイヤーのご紹介でした。『ベイブレイラウザー』の開発終了直後に作り始めて、大体2〜3週間ぐらいでできました。

冒頭にも言いましたが、正直、買った方が安くて出来も良いです。が、まあ、これはこれで味がある(?)し、何より長男は満足しているっぽいので、決して無駄ではないだろう、と思います。