概要
ATOM Echoにフリー素材のmp3音声を利用して、Waveファイルに変換して、スケッチに埋め込んで再生する手順を解説します。
音素材
効果音ラボさんのデータを利用させていただきました。音声はどんなものでも構いませんが、埋め込む関係でファイルサイズに上限があります。
ファイルサイズ
再生する音声ファイルは、1サンプリングあたり16ビット(2バイト)必要です。1秒間にどれだけサンプリングするかでサンプリング周波数を決定します。
今回は16,000を利用していますが8,000や他のサンプリング周波数でも問題ありません。周波数を増減することでファイルサイズが変わりますので、いろいろ変えながら試すのもいいと思います。
| 周波数 | 1秒あたりの容量 | 1MBで保存できる秒数 | 備考 |
| 16,000 | 32,000 | 33 | 音声での最低限? |
| 22,050 | 44,100 | 24 | |
| 32,000 | 64,000 | 16 | あまり使わない |
| 44,100 | 88,200 | 12 | CD音源で利用 |
| 48,000 | 96,000 | 11 | 映像などで使う |
フラッシュサイズ
ATOMは標準だと1.3M程度のフラッシュしか使えませんので、16,000だと30秒程度しか埋め込むことができません。

コンパイルが終わると「最大1966080バイトのフラッシュメモリのうち、スケッチが280887バイト(14%)を使っています。」などの文字が表示されると思います。
ここの最大サイズは「ツール」から「Partition Scheme」を変更することで設定を変更することができます。ほぼ空のスケッチをコンパイルしたときの数値が以下です。
| Partition Scheme | フラッシュ | 利用済み | 未使用 |
| 初期値 | 1,310,720 | 280,887 | 1,029,833 |
| No OTA | 2,097,152 | 280,887 | 1,816,265 |
| Minimal SPIFFS | 1,966,080 | 280,887 | 1,685,193 |
OTAを利用しない場合には「No OTA」を選択するとたくさんのファイルを利用できます。また、自分で設定ファイルを編集することで最大3Mまで拡張が可能です。
音声ファイルの変換
利用するファイルと、サンプリング周波数を決定したあとには音声ファイルを変換する必要があります。
細かい調整をおこないたい人には、上記のオープンソースの音声編集ソフトがおすすめです。
今回はもっとかんたんにブラウザで変換できるページを利用してみたいと思います。
上記のページを利用させていただきました。

変換したいファイルを開き、保存形式を「WAV」、詳細設定を開き「サンプリングレート」を利用するもの(16000など)、チャンネル数を「1」にして変換します。複数のファイルを同時に変換することも可能でした。
非常にかんたんに使えるのでおすすめです。
WAVファイルから埋め込み形式に変換
ここもいろいろ面倒なので、ブラウザで変換できるツールを私が作りました。
このブログのメニューにある「TOOLS」の中に「音声ファイル変換」がありますので、このページになります。

上記が変換ページです。音声ファイルを選択して、変数名を「データ名」に入れてから送信すると変換されます。
ボリュームを100%から変更することで大きさも同時に変更されます。ATOM Echoは大音量を再生するとスピーカーが壊れる事例が報告されていますので、必要最低限の音量まで調整することをおすすめします。
目安はまだ確定していませんが、最大56%ぐらいとの情報もあります。
M5Atom Echoを壊さない使用法
— ushineko3 (@ushineko3n) June 13, 2020
スピーカーの出力を約56%に抑えれば壊れない計算になります。供給電圧を下げれば実質出力が下がります。
NS4168は5V駆動なので、こちらを3.8V程度まで下げれば壊れない計算になります。
要は供給電圧を下げるだけです。https://t.co/lkfKM4Vzi2#M5Stack #M5Atom
スケッチ例(GitHub)
/*Press button to record,released button to playback*/
// https://github.com/m5stack/M5-ProductExampleCodes/blob/master/Core/Atom/AtomEcho/Arduino/Repeater/Repeater.ino
#include <driver/i2s.h>
#include <M5Atom.h>
#include "wav1.h"
#include "wav2.h"
#include "wav3.h"
#include "wav4.h"
#include "wav5.h"
const unsigned char *wavList[] = {wav1, wav2, wav3, wav4, wav5};
const size_t wavSize[] = {sizeof(wav1), sizeof(wav2), sizeof(wav3), sizeof(wav4), sizeof(wav5)};
#define CONFIG_I2S_BCK_PIN 19
#define CONFIG_I2S_LRCK_PIN 33
#define CONFIG_I2S_DATA_PIN 22
#define CONFIG_I2S_DATA_IN_PIN 23
#define SPEAKER_I2S_NUMBER I2S_NUM_0
#define MODE_MIC 0
#define MODE_SPK 1
void InitI2SSpeakerOrMic(int mode)
{
esp_err_t err = ESP_OK;
i2s_driver_uninstall(SPEAKER_I2S_NUMBER);
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER),
.sample_rate = 16000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ALL_RIGHT,
.communication_format = I2S_COMM_FORMAT_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 6,
.dma_buf_len = 60,
.use_apll = false,
.tx_desc_auto_clear = true,
.fixed_mclk = 0
};
if (mode == MODE_MIC)
{
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM);
}
else
{
i2s_config.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX);
}
err += i2s_driver_install(SPEAKER_I2S_NUMBER, &i2s_config, 0, NULL);
i2s_pin_config_t tx_pin_config = {
.bck_io_num = CONFIG_I2S_BCK_PIN,
.ws_io_num = CONFIG_I2S_LRCK_PIN,
.data_out_num = CONFIG_I2S_DATA_PIN,
.data_in_num = CONFIG_I2S_DATA_IN_PIN,
};
err += i2s_set_pin(SPEAKER_I2S_NUMBER, &tx_pin_config);
if (mode != MODE_MIC) {
err += i2s_set_clk(SPEAKER_I2S_NUMBER, 16000, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
}
i2s_zero_dma_buffer(SPEAKER_I2S_NUMBER);
}
void setup() {
M5.begin(true, false, true);
delay(50);
Serial.println();
M5.dis.drawpix(0, CRGB(128, 128, 0));
InitI2SSpeakerOrMic(MODE_MIC);
delay(2000);
}
void loop() {
if (M5.Btn.isPressed())
{
size_t bytes_written;
M5.dis.drawpix(0, CRGB(0, 128, 0));
InitI2SSpeakerOrMic(MODE_SPK);
// Random Play
int wav = random(5);
// Write Speaker
i2s_write(SPEAKER_I2S_NUMBER, wavList[wav], wavSize[wav], &bytes_written, portMAX_DELAY);
i2s_zero_dma_buffer(SPEAKER_I2S_NUMBER);
// Set Mic Mode
InitI2SSpeakerOrMic(MODE_MIC);
M5.dis.drawpix(0, CRGB(128, 128, 0));
}
M5.update();
}
スケッチ例です。ランダムで5つの音声が順番に再生されます。音声自体はwav1.hからwav5.hに保存されています。
スケッチ自体はシンプルです。
まとめ
短い音声を再生する場合には、Waveファイルをソースに埋め込むのが楽だと思います。思ったよりクリアな音がでると思いますので、みなさん活用してみてください。
ちょっと長めの音声を埋め込みたい場合にはmp3にしたり、8ビットで保存したのを、再生時に16ビットにするなど他の方法を検証する必要がありそうです。




コメント
このサイトを参考にさせていただいたおかげで、Tiny LED Clipができました!とっても感謝しております。これからの投稿も楽しみにしております 🙂
・ちんまりLEDクリップ:Tiny LED clip
https://protopedia.net/prototype/3264
おー、きれいにまとまってますね!
音楽再生はArduinoライブラリのバージョンが変わって、いろいろ変更がありそうなので確認してみたいと思います
音声系の開発であれば情報は少ないのですがM5Unifiedがおすすめです
返信ありがとうございます!
確かにArduinoのバージョンが変わっていて、プログラムもそれに合わせて修正した気がしましたw
M5Unified、各機種別に整理、ご苦労様です。
音声制御は、下記のページで会話している内容ですかね。音声と画像を非同期実行できるように見えます。
https://togetter.com/li/1909993
https://twitter.com/m5stack/status/1494284839515979784