FM音源をArduboyで動かしてみた の続き

前回の続きです。
やはり16ステップのシーケンスが1つ使えるだけでは物足りないので、シーケンサー周りをグレードアップしました。
具体的には

・シーケンスは16個(個々のシーケンスは16ステップで変わらず)
・シーケンスの連続演奏
・シリアルポート経由でのシーケンスのインポート/エクスポート
・EEPROMへの保存

といった機能を実装しました。
そのほか、

・直前の音を消さない「タイ」と直前の音を消す「休符」を分けて実装
・1ステップを四分音符から八分音符へ変更

などの拡張も行っています。
以下のGitHubリポジトリも更新しました。(前回のものはリリースv1.0として保存してあります。)

boochow/abSynth-FM: FM Synthesizer with step sequencer for Arduboy

前回からコードを整理せずにそのまま拡張したので、相変わらず中身はきれいではありません。
行数は現時点でインベーダーゲームより多い1700行超になっていますが、ビットマップやプリセットで用意した曲データ、Protonで開発するためのシリアルポート入力の代替コードなどを含んでいます。

プログラミングとしては、シーケンスの選択や通信を行うユーザーインタフェースと、シリアルポートからの入力のパーサが主な追加部分です。
データの受信中は、誤ったデータや通信の中断によってArduboy側がロックされてしまわないように、メインループから呼ばれて通信バッファが空(Serial.available()がゼロ)だった場合は必ずメインループへ戻ってボタン入力の処理を行うようにしています。

GUIは今回かなりたくさん書いた結果、ある程度スタイルができてきました。
コードはどう考えても現在のスタイルではなくOOPで書き直したほうが良いと思われますので、時間と意欲があればクラスライブラリ化したいところです。

現在重要な役割を担っているのは「process_button()」という関数で、ボタンの状態管理を行います。
引数は

・bool *state ・・・ 現在のボタンのオンオフ
・uint8_t *repeat_count ・・・ 長押し判定のためのカウンタ(処理不要の場合はNULL)
・uint8_t keycode ・・・ 処理対象のボタンの指定
・void(*release_func)() ・・・ ボタンを離したときの処理を行う関数
・void(*repeat_func)()) ・・・ 長押しのときの処理を行う関数
・返り値(bool) ・・・ 画面更新をする必要があるときはtrue

となっています。
例えば、Aボタンの処理はメインループの中で

process_button(&g_keystat.a, &g_keystat.a_repeat, A_BUTTON, a_released, a_long_press);

というようにコールしています。
a_releasedにAボタンが押されたときの処理、a_long_pressはAボタンが長押しされたときの処理を書きます。

ゲームと違って、GUIでは、ボタン操作への反応は押された時ではなく離された時に行うのが基本です。
反応の速さよりも、最後の最後までユーザに選択肢を残すことが重要だからです。

コメント