Vol.942 15.May.2026

サクラエディッタ M5A)Speakerで再生 Suicaの機種変更対応

E サクラエディッタ

by fjk

 abc941で紹介したように、「秀丸エディッタ」でSD-PAD15による「テキスト入力」ができなかった。VisualStudioCodeではSD-PAD15の全機能が使えるが、補完機能がデフォルトで働き、邪魔になる場合がある(Editor:QuiickSuggestionsでON/OFFの設定が可能ですが・・)。
 そこで、無料の日本語エディッタである「サクラエディッタ」を使ってみた。なお、サクラエディッタの動作環境はwindows10までですが、v2.4.2はwindows11でも動作し、今のところ不具合はありません。そして、SD-PAD15も問題なく使えます。サクラエディッタの詳細は以下のページを参照、

【主な特徴】
・Windows 10で動作するテキストエディタ
・文書毎にウィンドウが開くSDIを採用(設定によりタブ型エディタとして動作 タブモード)
・同時に256のファイルや、数メガの大きなテキストも編集可能(メモリ依存)
・元に戻す(Undo)、やり直し(Redo)は無制限(メモリ依存)
・文字コードセット自動判別(Shift_JIS,JIS,EUC,UTF-16,UTF-16BE,UTF-8,CESU-8,UTF-7)
・矩形編集・インデント機能、キーワード、文字列定数、コメント等の色分け機能
・Grep、検索機能は正規表現可能
・見出し記号やC/C++関数、PL/SQL関数のアウトライン解析・ジャンプ機能
・入力補完機能、キーワードヘルプ機能、キーボードマクロ


さくらエディッタ画面例


M M5_Atomシリーズ(8) 〜Atomicスピーカーベース

by fjk

 M5_AtomS3R(AtomS3では内部リソースと競合する可能性あり)とAtomicスピーカーベースで、Atomic SPK Base Arduino Tutorialを参考に、スピーカー動作テストとSDカードに保存されたWAVファイルの演奏を試みた。

【動作テストとトラブル】
 参考ページの「BasicUsage(M5Unified)」で動作を確認したところ、spk_cnfの設定でエラーが発生。このエラーはC++言語で構造体の「指示付集成体初期化」が正常に行われないことが原因で、C++のバージョンが2.0以上であれば、この初期化が有効(なはず)。−>参考

そこで、VSCのC++のバージョンの設定を、以下の手順で実行。
@ 左下の「管理」(歯車アイコン)をクリック
A 「設定」をクリック後、上部のコマンドラインに「cppStandard」と入力
B 「CppStandard」のリストでc++のバージョンの「C++20」を選択
ところが、上記の手順を実行しても、エラーは無くならなかった。「c_cpp_properties.json」で確認すると、
            "cStandard“: "gnu99",
            "cppStandard: "gnu++11"
のままだった。そこで、上記でGnu++20を選び、さらに,「c_cpp_properties.json」の記述も以下に変更、
            "cppStandard: "gnu++20"
としてみたが、やはりエラー。(−>今後の宿題)

 仕方ないので、「指示付集成体初期化」を諦め、「C言語方式」で初期化を行うと、今度はエラー無くコンパイルが終わり、スピーカーの動作の確認ができました。

<参考> M5Unifiedを使用したスピーカー制御

AtomcS3R-Speaker_Basic.cpp(zip)

#include <M5Unified.h>
#include <M5GFX.h>

// Define I2S audio pins connected to the speaker
#define PIN_DATA 38             // Data output pin for audio signal
#define PIN_BCLK 5              // Bit clock pin for I2S communication
#define PIN_LRCK 39             // Left/Right clock pin for channel selection

// Set audio output sample rate (44.1kHz is standard for audio)
static constexpr const size_t output_samplerate = 44100;
static bool isPlaying = false;                  // Flag to play state

void setup() {
    M5.begin();
    M5.Display.setFont(&fonts::FreeMonoBold9pt7b);
    M5.Display.setTextDatum(middle_center);
    M5.Display.drawCenterString("SPK Example", 64, 60);

    // Configure speaker settings using I2S protocol
    m5::speaker_config_t spk_cfg;
      spk_cfg.pin_data_out = PIN_DATA;          // Assign data pin
      spk_cfg.pin_bck = PIN_BCLK;               // Assign bit clock pin
      spk_cfg.pin_ws = PIN_LRCK;                // Assign left/right clock pin
      spk_cfg.sample_rate = output_samplerate;  // Set audio sample rate
      spk_cfg.dma_buf_len = 256;                // DMA buffer length
      spk_cfg.dma_buf_count = 6;                // Number of DMA buffers
      spk_cfg.i2s_port = i2s_port_t::I2S_NUM_0; // Specify I2S hardware port
    M5.Speaker.config(spk_cfg);                 // Apply the speaker configuration
    M5.Speaker.begin();                         // Initialize the speaker hardware
    M5.Speaker.setVolume(64);
}

void check_Btn(){
    M5.update();                                // Update M5 hardware state 
    if (M5.BtnA.wasPressed()) {
        isPlaying = !isPlaying;                 // Flip play state 
    }
}

void loop() {
    check_Btn();
    if (isPlaying) {
        for (int i = 24; i < 32; ++i ){
            float Hz = 220 * powf(2.0, i / 12.0f);
            M5.Speaker.tone(Hz, 400, 0, false);
            check_Btn();
        }
    }
    delay(1000);

/*---------- original parts --------
    // Play 6000Hz tone for 100ms
    M5.Speaker.tone(6000, 100);
    delay(1000);

    // Play 2000Hz tone for 20ms
    M5.Speaker.tone(2000, 20);
    delay(1000);
*/

【SDカード上のWAVファイルの演奏】
 上記参考ページの「Based on M5Unified Speaker API」をベースに、前記と同様にspk_cnfを初期化し、さらに幾つか修正や追加を行った。
 SD設定で CS = -1 にしたため、GPIOエラーが出るが、SDカードに保存したfanfare4.wav(275kb)の再生ができた。
 なお、WAVファイルの再生は本体ボタンでON/OFFできる(スイッチ応答が悪いが・・)。

<参考>
@M5Unifiedでwav再生
AM5Unified/SpekerClass

※ ファイルサイズが大きいとメモリ不足(最大320kb程度)となるので、ファイルを分割して処理するか・・[−> ]。

Atomc_playWav.cpp(zip)   ▼fanfare4.wav

#include <SPI.h>
#include <SD.h>
#include <M5Unified.h>
#include <M5GFX.h>

// ------------------- Pin Definitions -------------------
// SPI pins for microSD card in speaker
#define SD_SPI_CS_PIN     -1   // CS pin not connected(no use)
#define SD_SPI_SCK_PIN    7    // SPI Clock pin
#define SD_SPI_MISO_PIN   8    // SPI MISO pin
#define SD_SPI_MOSI_PIN   6    // SPI MOSI pin

// I2S pins for speaker (audio output protocol)
#define SPK_I2S_PIN_DATA 38    // I2S audio data output pin
#define SPK_I2S_PIN_BCLK 5     // I2S bit clock pin
#define SPK_I2S_PIN_LRCK 39    // I2S LR clock pin

#define TEST_WAV_FILE "/fanfare4.wav"

// ------------------- Audio Configuration -------------------
static constexpr const size_t output_samplerate = 44100; // 44.1kHz
static bool isPlaying = false;     // Flag to track audio play state 

// ------------------- Global File/Buffer Variables -------------------
File wavFile;                 // File object for WAV audio file
uint8_t* wavBuffer = nullptr; // Buffer to store entire WAV file 
size_t wavBufferLen = 0;      // Total length of WAV data in buffer

void setup() {
    M5.begin();
    M5.Display.setFont(&fonts::FreeMonoBold9pt7b);
    M5.Display.setTextDatum(middle_center);
    Serial.begin(115200);

    // ------------------- SD Card Initialization -------------------
    SPI.begin(SD_SPI_SCK_PIN, SD_SPI_MISO_PIN, SD_SPI_MOSI_PIN, SD_SPI_CS_PIN);
    M5.Display.drawCenterString("SD Init...", 64, 0);
    Serial.println("SD Init...");

    // Attempt SD card init (25MHz SPI speed); halt on failure
    if (!SD.begin(SD_SPI_CS_PIN, SPI, 25000000)) {
        M5.Display.clear();
        M5.Display.drawCenterString("SD Error!", 64, 50);
        Serial.println("SD Error!");
        while (1);  // Infinite loop = halt if SD card fails
    } else {
        M5.Display.clear();
        M5.Display.drawCenterString("SD Ready", 64, 0);
        Serial.println("SD Ready");
    }

    // -------------- Speaker Configuration (I2S) -------------------
    m5::speaker_config_t spk_cfg;
        spk_cfg.pin_data_out = SPK_I2S_PIN_DATA;
        spk_cfg.pin_bck = SPK_I2S_PIN_BCLK;
        spk_cfg.pin_ws = SPK_I2S_PIN_LRCK;
        spk_cfg.sample_rate = output_samplerate;
        spk_cfg.dma_buf_len = 256;      // DMA buffer size 
        spk_cfg.dma_buf_count = 6;      // Number of DMA buffers
        spk_cfg.i2s_port = i2s_port_t::I2S_NUM_0;  // Use I2S hardware port 0
    M5.Speaker.config(spk_cfg);         // Apply speaker settings

    // Initialize speaker; halt on failure
    if(!M5.Speaker.begin()){
        M5.Display.drawCenterString("SPK Error!", 64, 50);
        Serial.println("SPK Error!");
        while (1);
    } else {
        M5.Display.drawCenterString("SPK Ready", 64, 15);
        Serial.println("SPK Ready\n");
    }
    M5.Speaker.setVolume(96);
    delay(1000);

    // ---------------- Display Initial Instructions -------------------
    M5.Display.clear();
    M5.Display.setTextColor(TFT_YELLOW);
    M5.Display.drawCenterString("Press Screen", 64, 0);
    M5.Display.drawCenterString("to Play/Stop", 64, 15);
    M5.Display.setTextColor(TFT_WHITE);

    // ------------- Load WAV File from SD Card -------------------
    wavFile = SD.open(TEST_WAV_FILE, FILE_READ); //Open WAV file
    // Halt if WAV file not found
    if (!wavFile) {
        M5.Display.drawCenterString("Find wav Error!", 64, 40);
        Serial.println("Find wav Error!");
        while (1);
    } else {
        M5.Display.drawCenterString("Find wav", 64, 40);
        Serial.println("Find wav");
    }

    // Check freeHeap size
    size_t freeHeap = ESP.getFreeHeap();
    Serial.printf("Heap: %d byte\n",freeHeap);
    // Allocate buffer to store entire WAV file 
    wavBufferLen = wavFile.size();      // Get total file size
    wavBuffer = (uint8_t*)malloc(wavBufferLen); // Allocate memory
    // Halt if memory allocation fails
    if (wavBuffer == nullptr) {
        Serial.println("Memory Error!");
        wavFile.close();
        while (1);
    } else {
        wavFile.read(wavBuffer, wavBufferLen);  //Read entire file into buffer
        wavFile.close();                        // Close file
        // Display WAV file size (convert bytes to KB)
        String str_buf = String("Size:") + wavBufferLen/1024 + "KB";
        M5.Display.drawCenterString(str_buf, 64, 55);
        Serial.printf("Size: %d KB\n", wavBufferLen/1024);
    }
    M5.Display.drawCenterString("Stopped", 64, 80);  // (stopped)
}

void loop() {
    M5.update();                                // detect button presses
    if (M5.BtnA.wasClicked())  {
        isPlaying = !isPlaying;                 // Flip play state 
        M5.Display.fillRect(0, 80, 128, 48, TFT_BLACK);
    }
    if (isPlaying) {
        M5.Display.drawCenterString("Playing", 64, 80);
        M5.Speaker.playWav(wavBuffer, wavBufferLen, 1, 0, false);
        delay(2000);
    } else {
        M5.Display.drawCenterString("Stopped", 64, 80);
        M5.Speaker.stop();
    }
}


【おまけ】
 オーディオファイルには多くの種類があり、特にWAV(Waveform Audio File Format)ファイルは、音をそのままデジタル化した無圧縮の音声ファイル形式で、その特徴は、

○ 音質が良い(無圧縮なので何度編集しても、音質が落ちない)
○ 互換性が高い(ほとんどの機器で再生可能)
● ファイルサイズが大きくなる(MP3の4〜10倍)ので、ストリームング向きで無い
● アーティストなどの情報を保存しにくい
参考: WAVって何?(ちょげぶろぐ)


S (モバイル)Suicaの機種変更対応

by fjk

 コロナ下から、しばらくJRに乗ることも無くなっていた(最近の移動は主にキャンカー)ので、スマホの機種変更後にモバイルSuicaの引越を行っていなかったが、急に東京に行くことになり、新スマホでモバイルSuicaの設定を行った。
 最初、「新規登録」で(旧スマホと同じメールアドレスで)手続きを実施したところ、手続き最終画面で「エラー」となって、登録手続きができなかった(メールアドレス重複エラー?)。
 そこで、「端末の変更」メニューで、以下のように、再度手続きを実施した。
     参考:モバイルSuica(JR東日本)

@ 旧スマホをWiFiネットワークに接続する(SIMが無いので)
A Suicaではなく「おさいふケイタイ」を起動
B 「マイサービス」から「モバイルSuica」を選択(残額があれば表示される)
C 「カードを預ける(機種変更)」を実施し、「Suicaの預入」を行う
D 続いて、新スマホでモバイルSuicaを起動
E「以前の端末からSuicaを移行する(機種変更)」をタップ
F 画面に指示に従い(説明を見ながら)、Suicaの再設定を行う

で、新スマホでSuicaが使えるようになりました(旧スマホの残金も新スマホに移行できました)。
 それにしても、旧スマホを、稼働可能状態で、残しておいて良かったです。

  • なお、モバイルSuicaの登録にはJRE_ID登録が必要です。
  • また、クレジットカードは「登録無し」でもSuicaが使えます(チャージは駅やコンビニなどで可能)。

 ☆ ところで、Suicaのペンギンがなくなるのは、チョット寂しいですね。


★ M5-Atom(追加)

【SD上のサイズが大きいWAVファイルをAtomicスピーカーベースで再生】
 「Arduino入門」ページを参考に、SD上にあるサイズが大きいWAVファイルの再生を試みた。

  • CS = -1で再生は可能だが、SD読み込み時にターミナルにエラーメッセージが表示され、音が途切れるので、CS = 1とした(Grove端子が使えない)。
  • 一応、WAVファイルの再生ができたが、セグメント読込時か?、ノイズが入る。

起動時

再生中

再生終り

AtomcS3R-Play.cpp(zip)   ▼fanfare.wav   ▼twinkle_twinkle.wav

#include <SPI.h>
#include <SD.h>
#include <M5Unified.h>
#include <M5GFX.h>

// ------------------- Pin Definitions -------------------
// SPI pins for microSD card in speaker
#define SD_SPI_CS_PIN     1     // CS pin(*)
#define SD_SPI_SCK_PIN    7     // SPI Clock pin
#define SD_SPI_MISO_PIN   8     // SPI MISO pin
#define SD_SPI_MOSI_PIN   6     // SPI MOSI pin

// I2S pins for speaker (audio output protocol)
#define SPK_I2S_PIN_DATA 38     // I2S audio data output pin
#define SPK_I2S_PIN_BCLK 5      // I2S bit clock pin
#define SPK_I2S_PIN_LRCK 39     // I2S LR clock pin

//#define TEST_WAV_FILE "/fanfare.wav"        // 452kB
//#define TEST_WAV_FILE "/fanfare4.wav"       // 275kB
#define TEST_WAV_FILE "/twinkle_twinkle.wav"  // 2,068kB

bool playWAVFromSD(const char* filename, uint32_t repeat = 1, int channel = -1, bool stop_current = true);
bool playWAVMemory(File& wavFile, size_t fileSize, uint32_t repeat, int channel, bool stop_current);
bool playWAVSegmented(const char* filename, uint32_t repeat, int channel, bool stop_current);  
void printf_log(const char *format, ...);
void println_log(const char *str);
void println_cent_log(const char *str, int row, uint16_t color);

// ------------------- Audio Configuration -------------------
static constexpr const size_t output_samplerate = 44100;  // audio sample rate (44.1kHz)
static bool isPlaying = false;                          // Flag to track audio play state)

// ------------------- Global File/Buffer Variables -------------------
File wavFile;                       // File object for WAV audio file
uint8_t* wavBuffer = nullptr;       // Buffer to store entire WAV file (header + audio data)
size_t wavBufferLen = 0;            // Total length of WAV data in buffer

// ==================================================================
void prompt(void){
    M5.Display.setTextColor(TFT_YELLOW,TFT_BLACK);
    M5.Display.drawCenterString("Press Screen", 64, 32);
    M5.Display.drawCenterString("to Play/Stop", 64, 48);
}

// ==================================================================
void setup() {
    auto cfg = M5.config();
    M5.begin(cfg);
    M5.Display.setFont(&fonts::FreeMonoBold9pt7b);
    M5.Display.setTextDatum(middle_center);
    Serial.begin(115200);

    // ------------------- SD Card Initialization -------------------
    SPI.begin(SD_SPI_SCK_PIN, SD_SPI_MISO_PIN, SD_SPI_MOSI_PIN, SD_SPI_CS_PIN);
    println_cent_log("SD Init...", 0, 1);

    // Attempt SD card init (25MHz SPI speed); halt on failure
    if (!SD.begin(SD_SPI_CS_PIN, SPI, 25000000)) {
        M5.Display.clear();
        println_cent_log("SD Error!", 50, 1);
        while (1);                  // Infinite loop = halt if SD card fails
    } else {
        M5.Display.clear();
        println_cent_log("SD Ready", 0, 1);
    }

    // ------------------- Speaker Configuration (I2S) -------------------
    m5::speaker_config_t spk_cfg;
    
        spk_cfg.pin_data_out = SPK_I2S_PIN_DATA;
        spk_cfg.pin_bck = SPK_I2S_PIN_BCLK;
        spk_cfg.pin_ws = SPK_I2S_PIN_LRCK;
        spk_cfg.sample_rate = output_samplerate;
        spk_cfg.dma_buf_len = 256;                  // DMA buffer size 
        spk_cfg.dma_buf_count = 6;                  // Number of DMA buffers 
        spk_cfg.i2s_port = i2s_port_t::I2S_NUM_0;   // Use I2S hardware port 0
    
    M5.Speaker.config(spk_cfg);                     // Apply speaker settings

    if(!M5.Speaker.begin()){                        // Initialize speaker; halt on failure
        println_cent_log("SPK Error!", 50, 1);
        while (1);
    } else {
        println_cent_log("SPK Ready", 15, 16);
    }
    M5.Speaker.setVolume(128);
    delay(1000);

    // ------------------- Display Initial Instructions -------------------
    M5.Display.clear();
    M5.Display.setTextColor(TFT_WHITE);

    // SDカード初期化
    SPI.begin(SD_SPI_SCK_PIN, SD_SPI_MISO_PIN, SD_SPI_MOSI_PIN, SD_SPI_CS_PIN);

    if (!SD.begin(SD_SPI_CS_PIN, SPI, 25000000)) {
        println_log("No card!");
        while (1) delay(1000);
    }

    uint64_t cardSize = SD.cardSize() / (1024 * 1024);
    M5.Display.setCursor(0,8);
    printf_log("SD: %llu MB\n", cardSize);

    prompt();
}

void loop() {
    M5.update();                // Update M5 hardware state (detect button presses, etc.)
    if (M5.BtnA.wasClicked())  {
        isPlaying = !isPlaying;                     // Flip play state (playing - stopped)
        M5.Display.fillRect(0, 80, 128, 48, TFT_BLACK);     // (x,y,w,h,col)
    }
    if (isPlaying) {
        M5.Display.setTextColor(TFT_GREEN,TFT_BLACK);
        M5.Display.drawCenterString("Playing", 64, 72);
        playWAVFromSD(TEST_WAV_FILE, 1, -1, true);
        isPlaying = false;
        prompt();
    } else {
        M5.Display.setTextColor(TFT_RED,TFT_BLACK);
        M5.Display.drawCenterString("Stopped", 64, 72);
        M5.Speaker.stop();
    }
}

//===================================================================
bool playWAVFromSD(const char* filename, uint32_t repeat, int channel, bool stop_current) {
    if (!SD.exists(filename)) {
        println_cent_log("not faund!", 64, 72);         // ファイルが存在しない
        return false;
    }
    File wavFile = SD.open(filename, FILE_READ);
    if (!wavFile) {
        println_cent_log("not open!", 64, 72);          //ファイルを開けない
        return false;
    }
    size_t fileSize = wavFile.size();
    M5.Display.clear(TFT_BLACK);                        // 全画面クリア
    M5.Display.setCursor(0,8);                          // カーソル・ホーム
    M5.Display.setTextColor(TFT_CYAN,TFT_BLACK);
    println_log(filename);
    printf_log(" %.1f kB\n", fileSize/1024.0);
    size_t freeHeap = ESP.getFreeHeap();
    Serial.printf("Heap:%d\n", freeHeap);
    if (fileSize < freeHeap ) {
        return playWAVMemory(wavFile, fileSize, repeat, channel, stop_current);
    }
    // ファイルが大きすぎる場合、分割再生を使用
    wavFile.close();
    return playWAVSegmented(filename, repeat, channel, stop_current);
}

bool playWAVMemory(File& wavFile, size_t fileSize, uint32_t repeat, int channel, bool stop_current) {
    uint8_t* wavData = (uint8_t*)malloc(fileSize);
    if (!wavData) {
        println_log("Allocate Error!");
        wavFile.close();
        return false;
    }
    M5.Display.setTextColor(TFT_GREEN,TFT_BLACK);
    println_log("Reading...");
    size_t bytesRead = wavFile.read(wavData, fileSize);
    wavFile.close();
    if (bytesRead != fileSize) {
        Serial.printf("Read Error!: %d/%d bytes\n", bytesRead, fileSize);
        free(wavData);
        return false;
    }
    println_log("Playing...");
    bool result = M5.Speaker.playWav(wavData, fileSize, repeat, channel, stop_current);
    if (result) {
        while (M5.Speaker.isPlaying()) {
            delay(100);
        }
        M5.Display.setTextColor(TFT_WHITE,TFT_BLACK);
        M5.Display.setCursor(0,116);
        println_log("PlayBk End!");
    }
    free(wavData);
    M5.Display.fillRect(0, 64, 128, 24, TFT_BLACK);
    return result;
}

// 分割再生(大きなファイル向け)- メモリ使用量の最適化
bool playWAVSegmented(const char* filename, uint32_t repeat, int channel, bool stop_current) {
    File wavFile = SD.open(filename, FILE_READ);
    if (!wavFile) return false;
    uint8_t header[44];
    if (wavFile.read(header, 44) != 44) {
        wavFile.close();
        return false;
    }
    if (strncmp((char*)header, "RIFF", 4) != 0 ||
        strncmp((char*)header + 8, "WAVE", 4) != 0) {
        println_log("Not WAVfile!");
        wavFile.close();
        return false;
    }
    uint32_t totalFileSize = *(uint32_t*)(header + 4) + 8;
    uint32_t sampleRate = *(uint32_t*)(header + 24);
    uint16_t channels = *(uint16_t*)(header + 22);
    uint16_t bitsPerSample = *(uint16_t*)(header + 34);
    Serial.printf("WAV: %dHz, %dch, %dbit\n", sampleRate, channels, bitsPerSample);
    size_t dataSize = totalFileSize - 44;
    size_t bytesPerSample = (bitsPerSample / 8) * channels;
    size_t chunkSizeInSamples = 16384 / bytesPerSample;
    size_t chunkSize = chunkSizeInSamples * bytesPerSample;
    Serial.printf("chunk: %d bytes (%d samples)\n", chunkSize, chunkSizeInSamples);
    uint8_t* chunkBuffer = nullptr;
    size_t actualChunkSize = chunkSize;
    while (actualChunkSize >= 4096 && !chunkBuffer) {       // 最小4KB
        chunkBuffer = (uint8_t*)malloc(actualChunkSize + 44);
        if (!chunkBuffer) {
            actualChunkSize /= 2;
            chunkSizeInSamples = actualChunkSize / bytesPerSample;
            actualChunkSize = chunkSizeInSamples * bytesPerSample;
            printf_log("Retry chunk: %d bytes\n", actualChunkSize);
        }
    }
    if (!chunkBuffer) {
        println_log("Cannot allocated!");
        wavFile.close();
        return false;
    }
    M5.Display.setTextColor(TFT_WHITE,TFT_BLACK);
    Serial.printf ("Chunk: %d bytes\n", actualChunkSize);
    M5.Display.setTextColor(TFT_GREEN,TFT_BLACK);
    M5.Display.drawCenterString("Split play", 64, 72);
    for (uint32_t rep = 0; rep < repeat; rep++) {
        size_t totalRead = 0;
        int segmentNum = 0;
        wavFile.seek(44);
        while (totalRead < dataSize) {
            size_t bytesToRead = min(actualChunkSize, dataSize - totalRead);
            memcpy(chunkBuffer, header, 44);
            uint32_t chunkFileSize = bytesToRead + 36;
            memcpy(chunkBuffer + 4, &chunkFileSize, 4);
            memcpy(chunkBuffer + 40, &bytesToRead, 4);
            size_t bytesRead = wavFile.read(chunkBuffer + 44, bytesToRead);
            if (bytesRead == 0) break;
            totalRead += bytesRead;
            segmentNum++;
            M5.Display.setTextColor(TFT_WHITE,TFT_BLACK);
            if (segmentNum % 5 == 1) {
                M5.Display.setCursor(0,116);
                printf_log("Play:%3.1f%%\n", (float)totalRead / dataSize * 100.0);
            }
            bool playResult= M5.Speaker.playWav(chunkBuffer,bytesRead+44,1,channel,stop_current);
            if (!playResult) {
                printf_log("Play failed : %d\n", segmentNum);
                break;
            }
            while (M5.Speaker.isPlaying()) {
                delay(5);
            }
            delay(10);
        }
        if (rep < repeat - 1) {
            delay(1000);
        }
    }
    free(chunkBuffer);
    wavFile.close();
    M5.Display.setTextColor(TFT_WHITE,TFT_BLACK);
    M5.Display.setCursor(0,116);
    println_log("PlayBk End!");
    M5.Display.fillRect(0, 64, 128, 28, TFT_BLACK);
    return true;
}

void printf_log(const char *format, ...) {
    char buf[256];
    va_list args;
    va_start(args, format);
    vsnprintf(buf, 256, format, args);
    va_end(args);
    Serial.print(buf);
    M5.Display.printf(buf);
}

void println_log(const char *str) {
    Serial.println(str);
    M5.Display.println(str);
}

void println_cent_log(const char *str, int row, uint16_t color) {
    Serial.println(str);
    M5.Display.fillRect(0, row, 128, 48, TFT_BLACK);
    M5.Display.setTextColor(color);
    M5.Display.drawCenterString(str, 64, row);
}


※プログラムのリストをハイライト無しのスタイルで見る場合はここをクリック


※ 本レポートの参考・利用は、あくまでも自己責任でお願いします。


サクラエディッタ M5A)Speakerで再生 Suicaの機種変更対応