ESP32 2432S028R (CYD)でLVGL - MP3 Music Playerをリリースします
新年、明けましておめでとうございます 🐎
昨年2月の「ESP32 2432S028R (CYD)にサーモグラフィカメラを移植しました」以来、1年に1本しかマトモなソフトをリリース出来ず、情けない限りです。しかも投稿した記事のほぼ全てが CYD 関連でした。
まぁ、本年もユルユルとやっていきますので、よろしくお願い致します 🥱
さて新年の一発目も CYD ネタで恐縮ですが、LVGL の習熟を目標とし、LCD・タッチパネル・SD カード・アンプ IC の全機能を活かすことに拘って制作を進めて来た表題の件です。
まずはハードウェアから…
未登録の技適マーク付き CYD を引いた件
「ESP32 2432S028R (CYD)でLVGL - I2SとInternal DACでMP3 Player - 基本動作編」で CYD の音質改善について報告しました。これをやり直すべく、昨年ちゃんとした技適マーク付きが購入できた AliExpress のショップから再購入したところ、写真のようなモノが届きました。
総務省のサイトで検索 すると「検索条件に該当するデータが存在しません」でした。さすが中国、やってくれます。生産元が色々と変わる様なので、もう正規の技適マーク付きは入手が難しいのかもしれませんネ。
音質改善、再び
さて気を取り直し、昨年購入のストック品を引っ張り出し、アンプ IC(SC8002B)周りの回路定数を決め直しました。
まずは回路図と R7、R8、R9 のおさらいです。
出回っている2種類の 2.8インチ CYD のうち、ILI9341版は回路図と同じモノが付いている一方、ST7789版は R7 と R8 に 0Ω が付けられ、全く酷い音質でした。
この問題を改善するため、hexeguitar/ESP32_TFT_PIO では R7、R8 を回路図通りに、R9 は並列に接続した 47K〜100KΩ で調整し音質改善を図っています。
一方私は、依然ゲインが高く、高域が潰れた様に感じたので、JPOP 系を何曲か試聴し、R9 に並列な抵抗は 2KΩ を選びました。これ以上低いと音量が物足りず、高いとザラつき始めるギリギリの値です(個人の感想デス)。
さて今回、CYD 由来の派生品や類似品の回路図を調査し、また試行錯誤した結果、R7 は 0Ωのまま、R8 を回路図通りの 22kΩに、R9 を 10KΩにすることで、ほぼ前回同様の試聴感が得られました。付け替える 0603 抵抗が1つ減ったワケです。
ただ再生する周波数を上げていくと改修版でも再現性は悪く、ゲインが下がった分、目立たなくなっただけの様で、そもそも楽曲の再生には適さない IC であることが分かりました。
ということで、やはり音質にこだわるなら PCM5102A DAC や macsbug さんの記事 のように、DAC とアンプは外付けが良さそうなので、そのうちトライしてみたいと思います。
ソフトウェアの解説
リポジトリの紹介
Github リポジトリ embedded-kiddie/CYD_MP3Player には以下を収載しました。
-
CYD_Audio
PlatformIO 用に作られたオリジナルの ESP32 I2S audio library を フォーク し、コンパイル時の警告やエラーを修正、スケッチブックフォルダのlibrariesにインストール可能な Arduino IDE 用ライブラリとしたバージョンです。 -
CYD_MP3Player_Basic
CYD_Audio ライブラリを簡単に扱えるようにしたヘルパー関数の使用例です。詳しくは 前回記事 を参照ください。 -
CYD_MP3Player_Simple
MP3PlayerというCYD_Audioラッパークラスで、SD カード上のオーディオファイルをスキャンし、プレイリストを作成し、設定された順序で連続再生を制御する例です。 -
CYD_MP3Player_LVGL
本記事で紹介する LVGL 版です。WiFi 機能を無効にし、SdFat 専用にカスタマイズしたCYD_Audioを内包しています。
LVGL 版の構築方法
プラットフォームパッケージ
| 名称 | バージョン |
|---|---|
| esp32 by Espressif Systems | 2.0.17 |
バージョン 3.x では内蔵の I2S DAC が非推奨となり、耳障りなクリック音が出るため、2.0.17 が必須です。
またコンパイル時の設定は以下の通りです。
| 項目 | 設定 |
|---|---|
| Partition Scheme | “Huge App (3MB No OTA/1MB SPIFFS)” |
| Upload Speed | “460800” (Mac), “921600” (Win) |
ライブラリ
| 名称 | バージョン |
|---|---|
| LVGL by kisvegabor | 9.2.2 以降 |
| LovyanGFX by lovyan03 | 1.2.7 |
| SdFat by Bill Greiman | 2.3.0 |
| ArduinoJson by Benoit Blanchon | 7.4.2 |
-
LVGL の設定
まず、公式資料の Configure LVGL を参考に、スケッチブックフォルダのlibrariesにlv_conf.hを 配置します。同ファイルの設定についてはREADME.mdと各バージョンのサンプルを参考にして下さい。 -
SdFat の設定
長いファイル名と日本語ファイル名を有効化するため、SdFat のインストールフォルダからSdFatConfig.hを開き、コメントアウトされているシンボルUSE_UTF8_LONG_NAMESの定義を有効にして下さい。
アプリケーションの設定
IDE で config.h を開き、1. 〜 8. のコメントに沿って設定を編集して下さい。
-
TFT Screen configuration
残念ながら UI 画面はレスポンシブではなく、240x320 の設定は変更不可です 😞 -
Graphic library configuration
新し目の CYD 派生モデルでは、LovyanGFX の自動設定機能が働かないモノがあるようです。その場合はUSE_AUTODETECTをfalseに設定し、お持ちの LCD を設定して下さい。 -
Touch panel calibration
タッチ位置にズレがある場合は、一旦USE_CALIBRATEDをfalseを設定し、再コンパイル後に LovyanGFX のキャリブレーションを実行し、シリアルモニタに表示されるコードをCYD_MP3Player_LVGL.inoにコピペして下さい。その後USE_CALIBRATEDに戻すことを忘れずにネ。 -
Custom fonts configuration
既に色々な記号や JIS 第1水準と第2水準が入ってます。変更の必要がないことを祈ります。 -
Path to the folder where MP3 audio files are saved
MP3_ROOT_PATHに楽曲ファイルを格納する SD カードのルートパスを設定します。またよく使う楽曲ファイルの拡張子をMP3_FILE_EXTの先頭に移して下さい。SD カードの検索が少し早くなります。 -
File that stores settings related to the operation of this player
アプリケーションの設定を保存するファイル名を設定します。変更する場合は、ファイル名には@から始まる文字列を設定して下さい。 -
Partitions under “MP3_ROOT_PATH”
SRAM 容量の制限により、1つのプレイリストに入る曲数を 600 程度に制限していますが、複数のサブフォルダに分けることで全体の収容数を増やせる仕様としています。本アプリではこのサブフォルダのことを「パーティション」と呼び、PARTITION_PATHにサブフォルダ名のテンプレートを設定します。デフォルトは単なる「数字」です。 -
Album list configuration under “PARTITION_PATH”
後述するアルバムリストの保存用設定です。特に変更する必要はないと思います。
使い方
SD カード内のファイル構成
本アプリは、CD をリッピングしたイメージ(アーティスト名/アルバム名/曲名で構成される階層構造)がそのまま SD に保存されることを想定しています。
[パーティションなし] [パーティションあり]
MP3_ROOT_PATH/ MP3_ROOT_PATH/
├── Artist1/ ├── 1/
│ ├── Arbum1.1/ │ ├── Artist1/
│ │ ├── 01 title01.mp3 │ │ ├── Arbum1.1/
│ │ ├── 02 title02.mp3 │ │ │ ├── 01 title01.mp3
│ │ ├── ... │ │ │ ├── 02 title02.mp3
│ │ └── ... │ │ │ ├── ...
│ ├── Arbum1.2/ │ │ │ └── ...
│ │ └── ... │ │ ├── Arbum1.2/
│ └── ... │ │ │ └── ...
├── Artist2/ │ │ └── ...
│ ├── Arbum2.1 │ ├── Artist2/
│ └──... │ │ ├── Arbum2.1/
└── ... │ │ └── ...
└── ... │ └── ...
├── 2/
│ ├── Artist3/
│ │ ├── ...画面構成
全部で4つの画面からなり、それぞれスワイプ(または矢印ボタン)で遷移します。
全体の画面構成
-
メイン画面
デザインセンスがゼロの MP3 プレイヤー画面です。Bluetooth ボタンは現在機能しません 😊 -
プレイリスト
楽曲の一覧で、再生する曲を選択します。❤️ボタンで「お気に入り」の登録ができます。また演奏時間は最初「0:00」ですが、再生終了時に更新され SD カードに保存されます。 -
アルバムリスト
プレイリストに入れるアルバムを選択します。ドロップダウンリストには “All” 以外に任意のリストが登録/編集/削除ができます。リスト名に日本語を使いたい場合は、前章 8. のALBUM_LIST_FILEで設定した.txtファイルを編集して下さい。
アルバムリスト
- 設定画面
パーティションの切り替え、LCD 消灯までの時間、及びスリープタイマーを設定します。
アルバムのカバー写真について
本アプリでは、予め埋め込まれた10枚の画像のうち1枚をランダムに選び、楽曲の再生中にメイン画面に表示します。この埋め込み画像を変えるには、各アルバムフォルダにお好みの画像を @photo.jpg として保存して下さい。
ただしスワイプのアニメーション中も オンザフライで JPEG 画像をデコードするので、サイズは 96x96 程度に、サイズは 6KB 以下に抑えて下さい。圧縮率は 50 〜 75% がお勧めです。
既知の問題点
コンパイル時の警告
ESP32 のコア 2.0.17 でコンパイルすると、次の警告が出ます。
/Users/xxxx/Documents/Arduino/libraries/SdFat/src/FsLib/FsNew.h:44:48: warning: optimization attribute on 'void* operator new(size_t, newalign_t*)' follows definition but the attribute doesn't match [-Wattributes]
void* operator new(size_t size, newalign_t* ptr);
^
/Users/xxxx/Library/Arduino15/packages/esp32/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/xtensa-esp32-elf/include/c++/8.4.0/new:168:14: note: previous definition of 'void* operator new(std::size_t, void*)' was here
inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
^~~~~~~~これは、new 演算子の例外に関する取り扱い方が SdFat と Espressif の C++ 標準ライブラリとで異なることが原因ですが、アプリケーション側でトラップしており、通常動作には影響ないので無視しておいて大丈夫です。
コンパイル時のリセット問題
私の環境は Mac なので、Win ユーザーには当てはまらないかもしれませんが… ESP32 のコア 2.0.17 でコンパイル中にリセットが掛かる事象を経験しています。そのまま再コンパイルしてもリンク時点でハングし、IDE を終了させることも出来なくなります。ターミナル APP で次のコマンドを実行し、IDE の全タスクを kill した後、IDE を再起動してみて下さい。
% ps -axc|grep -i arduino|awk '{print $1}'|xargs -I@ kill -9 @演奏時間について
I2S オーディオライブラリによる推定値で、実際の演奏時間とはズレます。UI 演出上のギミックとお考え下さい。
アルバムのカバー写真が表示されない
JPEG 画像のデコードには LVGL に添付された Tiny JPEG Decoder をカスタマイズして使っています。画像の圧縮ツールによっては、まれに表示されない事象が発生しているので、画像の編集ソフトは GIMP を使うことをお勧めします。
SD カード内のドットファイル
Mac ユーザー特有の問題ですが、SD カードにドラッグ&ドロップでファイルをコピーすると . で始まるファイルが作成されます。特に大量の楽曲ファイルをコピーし続けると、. ファイルも同数生成されることになり、本アプリが SD カードをスキャンするときに余計な時間がかかることになります。
. で始まるファイルを一気に削除するには、ターミナル APP から SD カードの該当フォルダに移動し、以下を参考に find コマンドを実行して下さい。
% cd /Volumes/NO\ NAME/MP3/
% find . -name ".???*" -print -exec /bin/rm -rf {} \;雑記
メモリ消費量と収容曲数について
曲の再生はコア0に生成した audioplay タスクの役割ですが、再生中にコア1の UI ループ中で SD カードを読み書きすると例外エラーが発生します。この競合問題の解消は難しいため、プレイリストに表示するデータは全てメモリ上に保持する仕様で逃げています。
またアルバムのカバー写真用に JPEG 画像のデコード用バッファ(4KB)とキャッシュ(6KB)も必要でした。
このため、あちらこちらから少しずつメモリをかき集めています。
| コンポーネント | 元のサイズ | 縮小後のサイズ | 稼いだサイズ |
|---|---|---|---|
| I2S 用オーディオタスクのスタック | 約 10K | 4K | 約 6K |
| I2S 用 WiFi 機能 | 約 22K | 0K | 22K |
| LVGL 用描画バッファ | 15KB | 10KB | 5K |
| LVGL ウィジェット用メモリ | 48KB | 40KB | 8KB |
他にも LVGL プログラミングの工夫により(「習熟」の目標はかなり達成できた気がします)、計算上はプレイリストに 750 曲余りを収容可能ですが、今後の Bluetooth 化に備え、今回は 600 曲程に抑えることとしました。
LVGL のプログラミング上の工夫については、別途まとめて報告したいと思います 😉
シャッフルモードについて
アルバムリストの画面で “All” を選んだ時の動作は次の通りです。
-
シャッフルが OFF の時
ランダムに1つアルバムを選び、全曲をプレイリストに加えます。これをプレイリストの曲数が 600 を超えるまで繰り返します。アルバムをランダムに選ぶ理由は、プレイリストの偏りをなくす為です。 -
シャッフルが ON の時
OFF と同じロジックでプレイリストを作成し、最後にプレイリスト全体をランダムに並べ替えます。1曲ずつランダムに選んでいるとプレイリストの作成に 10 倍の時間がかかるため、この様な仕様にしています。
最後に、お願い
試してみよう!という奇特な方、問題を見つけたり、改善点やご要望があれば、是非 Github やココに書き込みをお願いします 🙇♂️