【M5Stack 2021】 #M5Stack Core2 ＋ #UIFlow で音を鳴らすのに手間が少なそうな方法（＋ ffmpeg での音声ファイルの処理の話）

この記事は、[2021年の M5Stack のアドベントカレンダー](https://qiita.com/advent-calendar/2021/m5stack) の 2日目の記事です。

やってみた内容は、以下のツイートの動画に出てくるものです。
SDカードは利用しないで、音を鳴らす仕組みを利用しています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/M5StackCore2?src=hash&amp;ref_src=twsrc%5Etfw">#M5StackCore2</a> と <a href="https://twitter.com/hashtag/UIFlow?src=hash&amp;ref_src=twsrc%5Etfw">#UIFlow</a> の組み合わせ、SDカードを使わなくても、けっこう手軽に音を鳴らすことができたのか！<a href="https://twitter.com/hashtag/M5Stack?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack</a> <a href="https://t.co/5yvkWu7NO3">pic.twitter.com/5yvkWu7NO3</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1459229336058298370?ref_src=twsrc%5Etfw">November 12, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ちなみに、上記の動画の中で鳴らしている音は、[効果音ラボさん](https://soundeffect-lab.info/)の効果音素材になります。

## UIFlow から音のファイルをアップロードして利用する
M5Stack＋UIFlow に限らず、M5Stack・ESP32関連で音のファイルを扱う方法を調べると、「フラッシュメモリエリアに SPIFFS（SPI Flash File System）で書き込んで扱う方法」や「SDカードを利用する方法」が出てきたりします。

UIFlow に、SDカードのファイルを読み込んで使うブロックはありますが、今回は SDカードを使わず本体があればできる（ただし、使える端末は限られる...）方法を使っていきます。
具体的には、UIFlow の右上メニュー（以下のツイートの画像で示した部分）からファイルをアップロードするやり方になります。

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr">前にツイートしていた件、<a href="https://twitter.com/hashtag/UIFlow?src=hash&amp;ref_src=twsrc%5Etfw">#UIFlow</a> の右上のメニューのこちらを使います。<a href="https://twitter.com/hashtag/M5Stack?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack</a> <a href="https://t.co/8kHe4fZHS3">pic.twitter.com/8kHe4fZHS3</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1464933008905891851?ref_src=twsrc%5Etfw">November 28, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

このボタンを押した後の画面に「WAV」というタブがあるので、それを選びます。
そうすると、「Only support core2 or Tough, less than 500kb」という記載とともに、ファイルをアップロードするためのボタンが出てきます。

<blockquote class="twitter-tweet" data-conversation="none"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/M5StackCore2?src=hash&amp;ref_src=twsrc%5Etfw">#M5StackCore2</a> とか Tough限定らしかったり、ファイルのサイズは 500キロバイトまで、<br>といった制約はありますが、 <a href="https://twitter.com/hashtag/UIFlow?src=hash&amp;ref_src=twsrc%5Etfw">#UIFlow</a> 上で音のファイルを簡単にアップできる方法。<a href="https://twitter.com/hashtag/M5Stack?src=hash&amp;ref_src=twsrc%5Etfw">#M5Stack</a> <a href="https://t.co/gjZUgkkqQP">pic.twitter.com/gjZUgkkqQP</a></p>&mdash; you (@youtoy) <a href="https://twitter.com/youtoy/status/1464933280973606913?ref_src=twsrc%5Etfw">November 28, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ここで、「Add WAV」を押してファイルをアップロードすると、そのファイルを UIFlow で扱うことができます。
ちなみに、複数のファイルをアップロードすることも可能です。

1つ注意点としては、ファイルのアップロードをする際に、デバイスが UIFlow とつながっている状態にしておいてください。つながってない状態でアップすると、以下のようなエラーがでます。
![エラー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/a27e94a9-7fd8-210d-905e-6810724e565d.jpeg)

うまくアップロードできると、以下のようにファイルが表示されます。
![アップロード後.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/1023dfcc-d46f-1258-fa71-3fb240f02dee.jpeg)
アップロードでエラーが出なかったのに、ファイル一覧にファイルが出ていない場合は、右下の「Reload」ボタンを押してみましょう。

この状態になれば、下準備は OK です。
このファイル一覧を閉じるには、右下の「キャンセル」ボタンを押します。

### アップロードした音を鳴らす
先ほどのファイルを使うためのブロックは、「ハードウェア　⇒ スピーカー」の中にあります。
![音を鳴らすブロック.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/75ff7fde-4863-4384-03ab-d80ee47c03a0.jpeg)

このプルダウンメニューを押すと、先ほどアップロードしたファイルが一覧に表示されます。
![対象となる音のファイルを選ぶ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/d13df86b-fbbc-ea1f-9b5d-0e93f3963067.jpeg)
もし、複数のファイルをアップロードしていたら、ここに選択肢で複数出てきます（冒頭の動画は、2種類の効果音のファイルをアップしていました）。

「ボタンを押したら音を鳴らす」という処理をするのであれば、以下のような内容にします。
![ボタンを押したら音が鳴る.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/bc09e102-2f12-c2d4-69ff-622c4799afef.jpeg)

たったこれだけで、音を鳴らすことができます。

### 補足： 公式ドキュメントを見てみる
以下の部分は、ドキュメントへのリンクになっています。
ここに書かれた情報を見てみて、いくつか情報を確認してみようと思います。
![リンク.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/059b7017-1d88-8c8d-9902-a39c22e4f707.jpeg)

上記のリンク先は、以下になっていました。

●m5-docs
　https://docs.m5stack.com/en/uiflow/hardwares/speaker

中を見ていくと、今回使った対象端末が限定される機能の話も書かれています（ドキュメントのほうは、Tough の話が出てきてないですが、更新が追いついてない感じかな...）。
![スピーカーの機能の説明.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/95a51cc5-0567-ebaa-ddd5-4f98744e68c2.jpeg)

UIFlow上にも書いてありましたが、ファイルサイズ制限の話や、サンプリング周波数・ビット深度の話も記載されています。

> Recommended to use 16000 sampling frequency, 16 Bit WAV file to reduce the file size

よく見かけるパラメータだと「16bit 48,000Hz（または、44,100Hz）」なので、サンプリング周波数はそれより低くしても良さそうです（ファイルサイズを削減する際など）。


## 音声ファイルの変換・ファイルサイズの削減
今回、冒頭にちらっと書いたとおり、音のファイルは[効果音ラボさん](https://soundeffect-lab.info/)の効果音素材を用いました。
その場合、ファイル形式が MP3 になっており、WAV に変換する必要があります。
また、選ぶ効果音のファイルによっては、その変換をした後に 500キロバイトをこえるものもあります（今回のファイルの片方が、それに該当しました）。

そのような変換・ファイルサイズの削減を、ffmpeg を使ってやったので、その方法も書いておきます。

なお、ffmpeg を用いた理由は、動画の処理用に自分の環境に入っていたから、というものです。
そのため、もっと使いやすいアプリ・やりやすい方法はあるかと思います。

### ffmpeg でフォーマット変換（MP3 ⇒ WAV）
ffmpeg でフォーマット変換をする場合、パラメータの変更をせず、そして標準で入るコーデックを使うのであれば、ちょっとコマンドをうつだけです。

```bash
$ ffmpeg -i test.mp3 test.wav
```

`-i`オプションの後に入力ファイル名を指定して、その後に出力ファイル名を指定します。
その時に、入出力のそれぞれのファイル名の拡張子を mp3・wav　にしておけば、フォーマット変換は完了です。

### ffmpeg でファイルサイズの削減（ファイルサイズを半分くらいにする）
次に、wavファイルが 500キロバイトをこえてしまった場合の対処です。

今回、効果音ラボさんの効果音ファイルを使った場合で、それを M5Stack Core2 で鳴らした場合、という例になりますので、その点はご了承ください。
少し補足すると、MP3 の効果音ファイルのパラメータは、効果音ラボさんが使っているパラメータになります。そして、音のファイルに何らか手を加えたものが満たすべき要件は、今回の UIFlow経由で M5Stack Core2 で使えるパラメータという形です。

まず、ファイルサイズを削減しなければならなくなった話ですが、自分の場合は具体的には以下が該当しました。

![演出・アニメ_1_｜効果音ラボ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50868/892d6918-9ee3-5ee0-4ec6-312836defdce.jpeg)

演出・アニメ[1] の「警報が鳴る.mp3」は、元のファイルサイズは「97キロバイトほど」なのですが、WAV　に変換したところ「705キロバイトほど」となってしまいました。
最低限、7割ほどには削減する必要があり、そしてできれば半分くらいにできると良いかな、というところでした。

#### 音声ファイルのモノラル化
上記のとおり M5Stack Core2 で鳴らせれば良く、また難しいことを考えずに手軽にファイルサイズを削る方法として、音声ファイルのモノラル化を試すことを考えました。
（そもそも、内蔵スピーカーがモノラルではないだろうか、という...）

先に実行したコマンドを掲載しておきます。

```bash
$ ffmpeg -i test.wav -ac 1 test_mono.wav
```

これで、ファイルサイズは「352キロバイトほど」に削減できました。

### 上記の音声ファイルに行った処理に関する補足
今回の ffmpeg　を用いた処理について、少し補足をしておきます。

#### パラメータを比較する
今回の WAV への変換、モノラル化が行われる過程のそれぞれのファイルのパラメータをチェックしてみます。
チェック方法は、以下の ffmpeg を導入すると使える ffprobe のコマンドで行いました。

```bash
$ ffprobe 【対象のファイル名】
```

まずは、mp3 のファイルを指定した場合の出力結果の抜粋です。

> Input #0, mp3, from '【ファイル名】.mp3':
　Duration: 00:00:04.02, start: 0.025057, bitrate: 193 kb/s
　Stream #0:0: Audio: mp3, 44100 Hz, stereo, fltp, 192 kb/s
　　Metadata:
　　　　encoder         : LAME3.100
　　Side data:
　　　　replaygain: track gain - 0.100000, track peak - unknown, album gain - unknown, album peak - unknown,

これを単純に WAV にしたものは以下です。

> Input #0, wav, from '【ファイル名】.wav':
　Metadata:
　　encoder         : Lavf58.76.100
　Duration: 00:00:03.99, bitrate: 1411 kb/s
　Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, 2 channels, s16, 1411 kb/s

記事の途中で出てきたパラメータを含め、主要なパラメータのについては、「サンプリング周波数 44100 Hz」、「ステレオ 2 channels」、「ビット深度 16ビット（s16　という部分）」、「ビットレート 1411 kb/s」となっているようです。

そして、モノラル化したものは、以下のとおりです。

> Input #0, wav, from 'a警報が鳴るmono.wav':
　Metadata:
　　encoder         : Lavf58.76.100
　Duration: 00:00:03.99, bitrate: 705 kb/s
　Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, 1 channels, s16, 705 kb/s

モノラル化前と明らかに違っているのは、1チャンネルになって、かつビットレートが半分になっている部分です。

### モノラル化以外も試してみる
サンプリング周波数を低くする話がありましたが、それも最後に試してみます。
`-ar` オプションに数値（44100　など）をつければ良さそうです。

```bash
$ ffmpeg -i test.wav -ar 16000 test_16.wav
```

これを実行すると、ファイルサイズが「705キロバイトほど」から「256キロバイトほど」になりました。
モノラル化と合わせると、「128キロバイトほど」まで削減できます。

ffprobe の出力を、モノラル化まで行ったもので試しておきます。
以下の出力結果を見ると、パラメータは想定通りになっていそうです。

> Input #0, wav, from '【ファイル名】.wav':
　Metadata:
　　encoder         : Lavf58.76.100
　Duration: 00:00:03.99, bitrate: 256 kb/s
　Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, 1 channels, s16, 256 kb/s

#### 音質について
上記のサンプリング周波数を下げる前後の音を聞き比べてみました。

PC上で鳴らす分には、あまり変わらない感じがしたのですが、M5Stack Core2 で鳴らすと、16000 Hz にする前後で音が明らかに違っている感じがしました。
音質とかあまり気にしない自分でも、聞き比べると分かるレベルでした（スピーカーの性能で、という感じでしょうか...）。

このあたりは、実際に音のパラメータを変える場合に、実機で鳴らしてどうなるかを確認してパラメータを決めるのが良いかもしれません。