chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

俺BLE MIDIからFL-Studioに向かってMIDIデータを送信する

俺BLE MIDI試作がFL-Studioとつながったので、次はMIDIデータを送ってみる。作りたいのは、SWを押すと和音やアルペジオデータをMIDIデータとして送る機能だ。BLE MIDIペリフェラル(ESP32等)からPCにMIDIデータを送るにはNotifyを使う。
リアルタイムOSのプログラミングってこれまでやったことがなかったのでタスクをどう作ったらいいのかとか分からない。理解不十分なまま、GPIOサンプルの割り込み駆動プログラム(タスク生成ルーチン等)をBLEプログラムにマージするとBLE自体が動かなくなった。NimBleの場合、NimBle側がメインタスクを持つ?ようで、、不用意に別のタスクを走らせてしまうと、BLE自体が応答しなくなるようである。。詳細は理解できていない。
FreeRTOSの仕様を理解せずに適当に他のサンプルからCopy&Pasteしてもおかしくなるだけ(特に、NimBLEのメインタスクとの関係を理解しておくべき)なので、余計なトラブルを避けるため、NimBleのサンプルの中に、Timer実装されているHertRateMonitorサンプルがあったので、このサンプルをベースに、SWによる割り込みでMIDIデータ送るのではなく、Timer割り込みで送る実装にしてみた。
MIDIデータってすぐに出てこないので、、記事にあった、MIDIデータ例:「8080903C7F」を使わせてもらって、以下のコードで定期的にNotifyしてみた。
各所にhrateというのがあるが、これは下地のソフトがHertRateMonitorサンプルだから。そのうち、BLE_MIDI等に修正予定

static void blehr_tx_hrate(xTimerHandle ev)
{
  extern uint16_t hrs_hrm_handle;
  uint8_t midi[5] = {0x80,0x80,0x90,0x3c,0x7f};
    int rc;
    struct os_mbuf *om;

    printf("*** Enter hrate ***\n");

    if (!notify_state) {
        blehr_tx_hrate_stop();
        heartrate = 90;
        return;
    }
    om = ble_hs_mbuf_from_flat(midi, sizeof(midi));
    rc = ble_gattc_notify_custom(conn_handle, hrs_hrm_handle, om);
    assert(rc == 0);
    blehr_tx_hrate_reset();
}

使ったAPIは、ble_gattc_notify_customという関数で、この引数にMIDIデータの配列へのポインタを渡す。この結果、FL-Studioでは、MIDI装置から、以下のMIDIデータが送信されたと解釈して、何か音を流している。

Note on: C5/ velocity:128

0x3cは10進の60で、60はMIDI音階で、C5らしい。(Cはドの音)。FL-Studioは起動直後はドラムとかパーカッションだけなので、Kickが自動演奏されるだけだけど、シンセとかに切り替えると、シンセでC5が再生される。
いろいろあったけど、、ひとまず、ESP32 + NimBLE を使って俺BLE MIDIを試作して、Windowsとペアリングして、MIDIデータが送れるところまでは来た。。
最終的には、ドミナントとかのコード進行をボタン操作によりMIDIデータを送信したいのだが、、どうやったらSWの割り込みを取れるのか、、タスクの書き方が分からない。。

■追記
作り方が雑なのか、assert()にひっかかって、よく再起動がかかる。組み込みの試作だから笑ってられるけど。。

■追記
今後の方針・・・タイマ機能により関数が周期的に呼び出せるので、10msec周期ぐらいで関数を呼び出して、その関数内でSWの状態を取得して、SWが押されていると判断したら、MIDIデータを送信するという。。ポーリング方式で実装する。せっかくのRTOSなのに、、なんともローテクな。。教科書通りに考えるなら、タイマ割り込みも割り込み処理ルーチン内なので、時間のかかる処理は実装すべきではない。だから。。本当は、SWの状態を取得してQUEUEなんかに貯めて、別のタスクで、QUEUEを取得して、MIDIデータを送出すべき。だが、、そのタスクにそういった処理を任せるべきなのか?が分からない。ひとまず、臭いし、普通にはNGの実装だが、、ひとまずタイマ割り込み内で送出してしまう。RTOSの理解が深まったら、メッセージングとかqueueとか使うことにして。

■実装上の問題点
stack overflowが発生。なぜだろうか。再帰呼び出しになっている??多重呼び出しになっている??

***ERROR*** A stack overflow in task Tmr Svc has been detected.
Backtrace:0x4008e677:0x3ffbc6d0 0x4008edd5:0x3ffbc6f0 0x4008f0fd:0x3ffbc710 0x4008fe85:0x3ffbc790 0x4008f2c0:0x3ffbc7b0 0x4008f276:0x81253c00 |<-CORRUPTED

あと、MIDI的な意味では、NoteONを連続していて、押した鍵盤をさらに押した状態。物理的にはありえない。NoteOn->NoteOffと実装すべき。

■参考にした記事
MIDI over Bluetooth LE - Bluetooth low energy - Short-range guides - Nordic DevZone
MIDI Lecture


マイコン徹底入門:RTOS編:フリーのリアルタイムOS活用法
電子工作室
https://yukblog.net/stm32-freertos/