こう書く。
#include <M5Unified.h>
// 画面の横幅に合わせてサンプル数を設定 (StickC Plus2は横向きで240px)
const int32_t record_length = 240;
const uint32_t record_samplerate = 16000; // 16kHzサンプリング
int16_t* rec_data; // 音声データを格納するバッファへのポインタ
int32_t prev_y[record_length]; // 前回の描画位置を記憶する配列(チラつき防止用)
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
// 画面を横向きに設定
MALLOC_CAP_8BIT;
M5.Display.setRotation(3);
M5.Display.fillScreen(TFT_BLACK);
// 録音用のメモリ領域(バッファ)を確保
rec_data = (int16_t*)heap_caps_malloc(record_length * sizeof(int16_t), MALLOC_CAP_8BIT);
if (rec_data == nullptr) {
M5.Display.println("Memory allocation failed!");
while (1) delay(10);
}
// 内蔵マイクの初期化と開始
M5.Mic.begin();
// 過去の描画位置配列を画面中央(y=67)で初期化
for (int i = 0; i < record_length; i++) {
prev_y[i] = M5.Display.height() / 2;
}
}
void loop() {
M5.update();
// マイクからデータを record_length 分だけ録音
if (M5.Mic.record(rec_data, record_length, record_samplerate)) {
int32_t mid_y = M5.Display.height() / 2; // 画面の中央
// 最初の点のy座標を計算しておく(ループの外で1点目を作っておく)
int32_t next_y = mid_y + (rec_data[0] >> 8);
if (next_y < 0) next_y = 0;
if (next_y >= M5.Display.height()) next_y = M5.Display.height() - 1;
int32_t current_y = next_y; // 今回のスタート点
int32_t last_current_y = current_y;
// 1ピクセルずつ右に進みながら、前のピクセルと線を結ぶ
for (int32_t x = 1; x < M5.Display.width(); ++x) {
// ① 前回の古い「線」を黒で消す (x-1 から x への線)
M5.Display.drawLine(x - 1, prev_y[x - 1], x, prev_y[x], TFT_BLACK);
// ② 次の点のy座標を計算
next_y = mid_y + (rec_data[x] >> 8);
if (next_y < 0) next_y = 0;
if (next_y >= M5.Display.height()) next_y = M5.Display.height() - 1;
// ③ 新しい「線」を緑色(TFT_GREEN)で描画してみる (オシロスコープ風)
M5.Display.drawLine(x - 1, current_y, x, next_y, TFT_GREEN);
// ④ 次のループのために、今回のスタート地点のy座標を記憶
// (同時に、次回の「消去用」としてprev_yにも保存)
prev_y[x - 1] = current_y;
current_y = next_y;
}
// ループが終わったら、最後の1点分の履歴も保存
prev_y[M5.Display.width() - 1] = current_y;
}
}