続・NTS1カスタムコントロールパネルのプログラミング


前回に引き続き、カスタムコントロールパネルのAPIを使うサンプルを紹介していきます。

前回はメッセージハンドラのプログラミングと、OSCの個数の取得、各OSCの名称などの情報取得を行いましたが、今回はShapeパラメータの送信、OSCのエディットパラメータの取得などを試してみます。

メッセージハンドラは登録可能な7つのハンドラ(パラメータチェンジ、ノートON、ノートOFF、Tick、Value、ユニット情報、エディットパラメータ情報)を全て使用します。

動作としては、コントロールパネルとして使用しているNucleo-F030にはユーザボタンとユーザLEDが1つずつありますので、

●ボタンON
・新しいオシレータを選択
・LED消灯
・ノートオン(ノートNOは64、ベロシティは127で固定)
・現在のOSCの情報をシリアルポートに出力
●ボタンOFF
・LED点灯
・ノートオフ
●常時
・Shapeパラメータを0から1023まで増やす
・MIDIインタフェース経由でのパラメータチェンジをシリアルポートに出力

という処理をさせてみました。

◆◆◆

使用するAPIは以下のものです。

nts1.paramChange(k_param_id_osc_type,k_invalid_param_subid, osc_number);
nts1.reqParamValue(k_param_id_osc_type,k_invalid_param_subid);

nts1.paramChange(k_param_id_osc_shape, k_invalid_param_subid, shape);

paramChangeはメインボードのパラメータを設定し、reqParamValueは現在の設定値をメインボードから取得します。対象となるパラメータはメインIDとサブIDの2つを引数で与えて指定します。

上の最初の二つのメインIDとサブIDの組み合わせは、使用するオシレータを指定します。
3つ目の例は、Shapeパラメータの値を設定します。

2つ目の引数がk_invalid_param_subidとなっていますが、これはサブIDが存在しない場合に使用するようです。

nts1.noteOn(note_num, velocity);
nts1.noteOff(note_num);

ノートオンとノートオフです。

nts1.reqOscEditParamDesc(param_num);

現在使用中のオシレータのパラメータ情報を取得します。引数はパラメータの番号(0~5)です。

情報を取得するAPIでは、前回も書いたとおり、情報はメッセージハンドラ経由で受信します。
今回は、メッセージハンドラでは以下のように情報をグローバル変数に保存するだけです。

nts1_rx_value_t           s_rx_value;
nts1_rx_unit_desc_t       s_rx_unit;
nts1_rx_edit_param_desc_t s_rx_param;

int s_rx_avail = 0;

void rx_value(const nts1_rx_value_t *val) {
  s_rx_value = *val;
  s_rx_avail = 2;
}

void rx_unit_desc(const nts1_rx_unit_desc_t *desc) {
  s_rx_unit = *desc;
  s_rx_avail = 3;
}

void rx_edit_param_desc(const nts1_rx_edit_param_desc_t *desc) {
  s_rx_param = *desc;
  s_rx_avail = 4;
}

s_rx_availは情報を受信できたことを表すフラグとして用います。(前回の記事参照)

このほか、以下のような4つのメッセージハンドラを用意します。

void rx_param_change(const nts1_rx_param_change_t *param) {
  s_rx_avail = 1;
  fmtprint("param_change: %d %d %d %d\r\n", param->param_id, param->param_subid, param->msb, param->lsb);
}

void rx_note_on(const nts1_rx_note_on_t *evt) {
  fmtprint("note_on: %d %d\r\n", evt->note, evt->velocity);
}

void rx_note_off(const nts1_rx_note_off_t *evt) {
  fmtprint("note_off: %d\r\n", evt->note);
}

void rx_tick() {
  if (++s_tick % 40 == 0) {
    fmtprint("tick: %d\r\n", s_tick);
  }
}

最初の3つはコントロールパネルではなくMIDIからイベントを受信した場合にも呼び出されます。例えばNTS1にMIDIキーボードをつないで、モジュレーションホイールを操作するとrx_param_changeが呼ばれます。

最後の1つは周期的に呼びだされるメッセージハンドラです。呼び出し周期はアルペジエイターのテンポと連動しています。NTS1のLEDは最後の桁の小数点がアルペジエイターのテンポと連動して点滅していますが、これにはこのクロックが使われているのでしょう。

テンポは電源ON時は120.0(パラメータ値としては1200)になっています。このとき1 tickは1/8秒(四分音符が1/2秒なので、16分音符相当)となっています。従って、上のコードでは40 tick=5秒ごとに1行メッセージを出力します。なお、アルペジエイターのテンポ設定は上述のparamChangeで行えます(メインIDはk_param_id_arp_tempo、サブIDはk_invalid_param_subid)。

◆◆◆

今回作成したスケッチを動かしている様子です。ボタンを押すたびに新しいオシレータが選択され、その情報がターミナルに表示されます。また、Shapeパラメータはボタンを押さなくても勝手に変化していきます。

最後にコード全体を載せておきます。ちょっと長いですが、前回との重複部分も多いです。

コメント