Wio Terminal + Grove MP3 でMP3プレーヤーにしてみた

Wio Terminal にGrove MP3のモジュールをつないで、MP3プレーヤーにしてみました。
f:id:manpukukoji:20200708154406j:plain
Wio Terminalは、ボタンやディスプレーが充実しているので、こういう用途には、便利ですね。
まぁ、僕の場合、バッテリーを何とかしないとならんのですが…。
WioとGrove接続は、いたって簡単で、Wioの3.3VとGrovenoVcc, それぞれのGNDどうし、あとは、シリアルのRxとTxをクロスして接続するだけです。
ソフトの方は、Seeedのライブラリやサンプルを参考にすれば、特に問題なさそうです。
基本的な機能しか用意していませんが、Seeedのライブラリになっていない機能もMP3のKT403にはあるようなので、時間をかければ、もう少し凝ったこともできそうです。
ですが、時々、急に機嫌が悪くなったりするので、もしかしたら、結構バグがあるかもしれません。 まぁ、このまま作る人もないでしょうけど、ご迷惑をおかけしたら、ごめんちゃい。 自己責任でよろしく…と、いうことで…。
MP3ファイルをSDカードに保存するときには、少し、癖があって、決められたファルダ構成でないとうまくPlayしてくれません。
フォルダを01、02、03…と分け、その中のファイルの頭に001、002、003…とつけていきます。 ファイル名では、残念ながらコントロールできないようです。
KT403Aとフォルダに関しては、参考サイトで詳しく説明してくれています。

使い方は、

電源を入れると、Play画面が立ち上がり、Aボタンでループモードで再生されます。
5ボタンで、右を押すと次のファイル、左が前のファイル。 上がボリュームアップ、下がボリュームダウンです。また、センターは、ポーズです。
f:id:manpukukoji:20200708154521j:plain
Cボタンを押すと設定画面に切り替わります。
再生のモードが5種類あって、

  • Loop_All  全体を順番に再生しながらループします。
  • Loop_folder  ある特定のフォルダ内をループします。 フォルダの指定が必要です。
  • Play_root  ルートフォルダのファイルを指定して再生します。 ファイルの指定が必要です。
  • Play_MP3  MP3フォルダのファイルを指定して再生します。 ファイルの指定が必要です。
  • Play_Folder_file  特定のフォルダのファイルを指定して再生します。 フォルダとファイルの指定が必要です。

イコライザの機能もあって、NORMAL、POP、ROCK、JAZZ、CLASSIC、BASSの、6種類から選べます。
設定画面では、右、左のボタンで項目を選択します。 上下のボタンで、次の項目選択に移動します。
選択項目は、再生のモードによって変わります。
選択が完了すると、CボタンでPlay画面に戻り、再生が開始されます。
f:id:manpukukoji:20200708154546j:plain

Wio-chan画像の表示

画面が文字ばかりでさみしいので、WioTeriminal-chan の画像を表示するようにしてみましたが、よく考えると、画像は、SDカードから読み込むので、MP3用のSDカードとWio用のSDカードと2枚必要になってしまいます。 とりあえず、1枚しかもっていないので、Wio-chanは、しばらくお休みいただくことにしました。 プログラムのSDカードの初期化のところ ( setup() の初めのところ) を生かせば、画像が表示できるようになりますが、画像は、別途用意しなければなりません。
SeeedのWikiにやり方は、説明されていますけど簡単に書くと、以下のような手順です。
まず、適当なサイズの24ビットのBMP画像を用意します。
次に画像ファイルを変換するパイソンのファイルをダウンロードして(ここbmp_converter.pyというファイル)、どこかのフォルダに置きます。そのフォルダにBMPというフォルダを作って、そこに先ほど用意したBMP画像を置きます。
コマンドプロンプトでパイソンのファイルを置いたフォルダに移動し、"python bmp_converter.py" と、やると8ビットファイルにするか[1]、16ビットファイルにするか[2]聞いてくるので、選択します。
すると、bmpフォルダの中にサブフォルダができて、変換された画像ファイルができています。
画像はSDカードから読み込むので、SDカードのライブラリもインポートしておく必要があります。それと、先ほどのWikiのサイトから、”RawImage.h" というヘッダファイルもダウンロードして、スケッチと同じフォルダに保存しておく必要があるようです。

参考サイト
こちらのサイトでKT403Aについて詳しく説明されています。
www.ne.jp/asahi/shared/o-family/ElecRoom/AVRMCOM/MP3module/MP3module.html
SeeedのWikiは、外せないですよね
Loading Image - Seeed Wiki
こちらは、MP3
GitHub - Seeed-Studio/Seeed_Serial_MP3_Player


スケッチは、以下、参照ください。

#include "KT403A_Player.h"
#include"TFT_eSPI.h"
#include "Seeed_FS.h" //Including SD card library
#include"RawImage.h"  //Including image processing library

TFT_eSPI tft;
#ifdef ARDUINO_SAMD_VARIANT_COMPLIANCE
    #define COMSerial Serial1
    #define ShowSerial SerialUSB

    KT403A<Uart> Mp3Player;
#endif

int menu = 0, p_menu = 4;
int plmode = 0, p_plmode = 5;
int p_status = 0;
int idx_folder = 1, idx_file = 1;
String mode_S[] = {"Loop_All", "Loop_Folder", "Play_Root" , "Play MP3", "Play_File"};
int Eq = 0;
String Eq_S[] = {"NORMAL", "POP", "ROCK" , "JAZZ", "CLASSIC", "BASS"};
EQUALIZER Eq_e[] = {NORMAL, POP, ROCK , JAZZ, CLASSIC, BASS};

void disp_title() {  
  tft.fillScreen(TFT_BLACK);
  
  if (menu == 0) {
    drawImage<uint8_t>("wio-chan8.bmp", 21, 32);
    tft.setTextColor(TFT_YELLOW);
    tft.drawString("MP3 Player",105, 5);
    tft.drawString("Play : ",5, 35);
    tft.drawString(mode_S[plmode], 89, 35);
    tft.drawString("Equalizer : ",5, 65);
    tft.drawString(Eq_S[Eq], 145, 65);
    //tft.fillTriangle(140,100,180,120,140,140,TFT_YELLOW);
  }
  
  if (menu == 1) {
    tft.drawString("Setting", 117, 5);
    tft.drawString("Play : ", 5, 37);
    tft.drawString(mode_S[plmode], 89, 37);
        
    tft.drawString("Equalizer : ", 5, 120);
    tft.drawString(Eq_S[Eq], 149, 120);

    if( (plmode == 1) or (plmode == 4) ) {
       tft.drawString("Folder# : ", 29, 60);
       tft.drawString(String(idx_folder), 150, 60);
    }
    if( (plmode == 2) or (plmode == 3) or (plmode == 4) ) {
       tft.drawString("File# : ", 52, 85);
       tft.drawString(String(idx_file), 150, 85);
    }
    
  }   //  end of menu 1
}   //  endo of disp_title()

void set_play() {
    int set_item = 0;
    int dummy = 0;
    while(menu == 1) {
      if (menu != p_menu)  disp_title();
      p_menu = menu;
      //play mode
      if(set_item == 0) {   // Play mode setting
        dummy = 1;
        tft.drawFastHLine(89,55,180,TFT_WHITE);
        while (dummy){
          if (digitalRead(WIO_5S_RIGHT) == LOW) {
            plmode++;
            if(plmode > 4) plmode = 0;
            disp_title();
            tft.drawFastHLine(89,55,180,TFT_WHITE);
            while(digitalRead(WIO_5S_RIGHT) == LOW){}
          }
          if (digitalRead(WIO_5S_LEFT) == LOW) {
            plmode--;
            if(plmode < 0) plmode = 4;
            disp_title();
            tft.drawFastHLine(89,55,180,TFT_WHITE);
            while(digitalRead(WIO_5S_LEFT) == LOW){}
          }
          if (digitalRead(WIO_5S_DOWN) == LOW) {
            tft.drawFastHLine(89,55,180,TFT_BLACK);
            if( (plmode == 1) or (plmode == 4) ) {
              set_item = 1;
              dummy = 0;
            }
            else if( (plmode == 2) or (plmode == 3) ) {
              set_item = 2;
              dummy = 0;
            }
            else {
              set_item = 3;
              dummy = 0;
            }
            while(digitalRead(WIO_5S_DOWN) == LOW){}
          }
          if (digitalRead(WIO_5S_UP) == LOW) {
            tft.drawFastHLine(89,55,180,TFT_BLACK);
            set_item = 3;
            dummy = 0;
            while(digitalRead(WIO_5S_UP) == LOW){}
          }
          if (digitalRead(WIO_KEY_C) == LOW) {
            menu = 0;
            dummy = 0;
            while(digitalRead(WIO_5S_UP) == LOW){}
          }
        }   //end of while dummy
     }  //end of set item 0
    
      if(set_item == 1) {   // Folder setting
        dummy = 1;
        tft.drawFastHLine(150,76,36,TFT_WHITE);
        while (dummy){
          if (digitalRead(WIO_5S_RIGHT) == LOW) {
            idx_folder++;
            if(idx_folder > 99) idx_folder = 99;
            disp_title();
            tft.drawFastHLine(150,76,36,TFT_WHITE);
            while(digitalRead(WIO_5S_RIGHT) == LOW){}
          }
          if (digitalRead(WIO_5S_LEFT) == LOW) {
            idx_folder--;
            if(idx_folder < 1) idx_folder = 1;
            disp_title();
            tft.drawFastHLine(150,76,36,TFT_WHITE);
            while(digitalRead(WIO_5S_LEFT) == LOW){}
          }
          if (digitalRead(WIO_5S_DOWN) == LOW) {
            tft.drawFastHLine(150,76,36,TFT_BLACK);
            if (plmode == 1)  {
              set_item = 3;
              dummy = 0;
            }
            else {
              set_item = 2;
              dummy = 0;
            }
            while(digitalRead(WIO_5S_DOWN) == LOW){}
          }
          if (digitalRead(WIO_5S_UP) == LOW) {
            tft.drawFastHLine(150,76,36,TFT_BLACK);
            set_item = 0;
            dummy = 0;
            while(digitalRead(WIO_5S_UP) == LOW){}
          }
          if (digitalRead(WIO_KEY_C) == LOW) {
            menu = 0;
            dummy = 0;
            while(digitalRead(WIO_5S_UP) == LOW){}
          }
        }   //end of while dummy
     }  //end of set item 1

      if(set_item == 2) {   // File setting
        dummy = 1;
        tft.drawFastHLine(150,101,36,TFT_WHITE);
        while (dummy){
          if (digitalRead(WIO_5S_RIGHT) == LOW) {
            idx_file++;
            if(idx_folder > 255) idx_folder = 255;
            disp_title();
            tft.drawFastHLine(150,101,36,TFT_WHITE);
            while(digitalRead(WIO_5S_RIGHT) == LOW){}
          }
          if (digitalRead(WIO_5S_LEFT) == LOW) {
            idx_file--;
            if(idx_folder < 1) idx_folder = 1;
            disp_title();
            tft.drawFastHLine(150,101,36,TFT_WHITE);
            while(digitalRead(WIO_5S_LEFT) == LOW){}
          }
          if (digitalRead(WIO_5S_DOWN) == LOW) {
            tft.drawFastHLine(150,101,36,TFT_BLACK);
              set_item = 3;
              dummy = 0;
            while(digitalRead(WIO_5S_DOWN) == LOW){}
          }
          if (digitalRead(WIO_5S_UP) == LOW) {
            tft.drawFastHLine(150,101,36,TFT_BLACK);
           if( (plmode == 2) or (plmode == 3) ) {
             set_item = 0;
             dummy = 0;
           }
           else {
             set_item = 1;
             dummy = 0;
           }
            while(digitalRead(WIO_5S_UP) == LOW){}
          }
          if (digitalRead(WIO_KEY_C) == LOW) {
            menu = 0;
            dummy = 0;
            while(digitalRead(WIO_5S_UP) == LOW){}
          }
        }   //end of while dummy
     }  //end of set item 2

      if(set_item == 3) {   // Equalizer setting
        dummy = 1;
        tft.drawFastHLine(149,136,84,TFT_WHITE);
        while (dummy){
          if (digitalRead(WIO_5S_RIGHT) == LOW) {
            Eq++;
            if(Eq > 5) Eq = 5;
            disp_title();
            tft.drawFastHLine(149,136,84,TFT_WHITE);
            while(digitalRead(WIO_5S_RIGHT) == LOW){}
          }
          if (digitalRead(WIO_5S_LEFT) == LOW) {
            Eq--;
            if(Eq < 0) Eq = 0;
            disp_title();
            tft.drawFastHLine(149,136,84,TFT_WHITE);
            while(digitalRead(WIO_5S_LEFT) == LOW){}
          }
          if (digitalRead(WIO_5S_DOWN) == LOW) {
            tft.drawFastHLine(149,136,84,TFT_BLACK);
              set_item = 0;
              dummy = 0;
            while(digitalRead(WIO_5S_DOWN) == LOW){}
          }
          if (digitalRead(WIO_5S_UP) == LOW) {
            tft.drawFastHLine(149,136,84,TFT_BLACK);
           if( (plmode == 2) or (plmode == 3) or (plmode == 4) ) {
             set_item = 2;
             dummy = 0;
           }
           else if (plmode == 1){
             set_item = 1;
             dummy = 0;
           }
           else {
             set_item = 0;
             dummy = 0;
           }
            while(digitalRead(WIO_5S_UP) == LOW){}
          }
          if (digitalRead(WIO_KEY_C) == LOW) {
            menu = 0;
            dummy = 0;
            while(digitalRead(WIO_5S_UP) == LOW){}
          }
        }   //end of while dummy
     }  //end of set item 3

    }   //end of menu1 
    disp_title();
}   //end of set_play

void setup() {
/*  
    //Initialise SD card
    if (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI)) {
        while (1);
    }
*/  
    tft.begin();
    tft.setRotation(3);
    tft.fillScreen(TFT_BLACK); 
    tft.setTextSize(2);

    //ShowSerial.begin(9600);
    COMSerial.begin(9600);
    while (!COMSerial);
    Mp3Player.init(COMSerial);

    pinMode(WIO_KEY_A, INPUT_PULLUP);
    pinMode(WIO_KEY_B, INPUT_PULLUP);
    pinMode(WIO_KEY_C, INPUT_PULLUP);
    
    pinMode(WIO_5S_UP, INPUT_PULLUP);
    pinMode(WIO_5S_DOWN, INPUT_PULLUP);
    pinMode(WIO_5S_LEFT, INPUT_PULLUP);
    pinMode(WIO_5S_RIGHT, INPUT_PULLUP);
    pinMode(WIO_5S_PRESS, INPUT_PULLUP);

}

void loop() {
  if (menu != p_menu) {
    disp_title();
  }
  
  if (menu == 0) {
    
             if (digitalRead(WIO_5S_PRESS) == LOW) {
                ShowSerial.println("Press 5s PRESS");
                Mp3Player.pause_or_play();
                while(digitalRead(WIO_5S_PRESS) == LOW){}
             }  
             if (digitalRead(WIO_KEY_A) == LOW) {
                plmode = 0;
                disp_title();
                Mp3Player.setEqualizer(Eq_e[Eq]);
                Mp3Player.loop(1);
                while(digitalRead(WIO_KEY_A) == LOW){}
             }
             if (digitalRead(WIO_KEY_C) == LOW) {
                menu = 1;
                while(digitalRead(WIO_KEY_C) == LOW){}
             }
             if (digitalRead(WIO_KEY_B) == LOW) {
                Mp3Player.play();
                while(digitalRead(WIO_KEY_B) == LOW){}
             }
            if (digitalRead(WIO_5S_RIGHT) == LOW) {
                Mp3Player.next();
                while(digitalRead(WIO_5S_RIGHT) == LOW){}
            }
            if (digitalRead(WIO_5S_LEFT) == LOW) {
                Mp3Player.previous();
                while(digitalRead(WIO_5S_LEFT) == LOW){}
            }
             if (digitalRead(WIO_5S_UP) == LOW) {
                Mp3Player.volumeUp();
                while(digitalRead(WIO_5S_UP) == LOW){}
            }
            if (digitalRead(WIO_5S_DOWN) == LOW) {
                Mp3Player.volumeDown();
                while(digitalRead(WIO_5S_DOWN) == LOW){}
            }
  }
  else if (menu == 1) {
    p_menu = 0;
    set_play();
    switch (plmode) {
      case 0:   // Loop All
        Mp3Player.setEqualizer(Eq_e[Eq]);
        Mp3Player.loop(1);
        break;
      case 1:   //  Loop Folder
        Mp3Player.setEqualizer(Eq_e[Eq]);
        Mp3Player.loopFolder(idx_folder);
        break;
      case 2:   //  Play index folder (Root)
        Mp3Player.setEqualizer(Eq_e[Eq]);
        Mp3Player.playSongIndex(idx_file);
        break;
      case 3:   //  Play index folder (Root)
        Mp3Player.setEqualizer(Eq_e[Eq]);
        Mp3Player.playSongMP3(idx_file);
        break;
      case 4:   //  Play index folder (Root)
        Mp3Player.setEqualizer(Eq_e[Eq]);
        Mp3Player.playSongSpecify(idx_folder,idx_file);
        break;
    } // end of switch
        
   }  //end of menu 1
    p_menu = menu;
    delay(200);
}//end of loop