こんばんは。5月なのに暑すぎます。溶けます。令和ちゃん、早く新暦の生活に慣れてね。
てなわけで、Nukkitサーバーの中でMIDIファイルを再生させてみました。技術的な説明とかをちょこっとしてみようと思います。
ロード
1.まず、Javaに標準でついているJavaSoundAPIのmidiパッケージを用いてMIDIのメタデータと各トラックを取得します。
2.Oracleのドキュメントをもとにテンポと1tickあたりの秒数を計算し、保存しておきます。
再生開始
1.再生コマンドを送信
2.スレッドプールからトラックの数(だいたい数個~十数個)だけスレッドを取得し、各トラックを再生するスレッドを定義してリストに保存します。
3.保存しておいたスレッドを同時に実行していきます。(再生)
トラックの再生
MIDIEvent…一つの音を管理するクラス
1.トラックにあるMIDIEventの数だけループを回します。
2.ひとつ前のMIDIEventと、現在読み込んでいるMIDIEventとのtick時間の差をだし、そこにロード時に取得した秒数をかけたミリ秒分だけスレッドを待機させます。(各音符の長さを表現)
3.MIDIEventから取得した音のキーをピッチに直します。(Math.pow(2, (key – 60) / 12d);(maa123氏のを参考にしました)
4.MIDIEventから取得したチャンネルを現在設定されている楽器に変換します。
5.生成した情報をもとにPlaySoundPacketを組み立て、プレイヤーに送信します。(一音で一つのパケット)
一時停止
1.再生開始時に保存したリストを呼び出します。
2.各スレッドに対してwait()またはnotify()を発行します。
思ったこと
ExecutorService#invokeAll(Collection<? extends Callable<T>>)ってブロッキングするんですね。知りませんでした。
リピート再生ってできますか?
厳しいですね
nukkit2.0用のバージョン作れますか?
Nukkit2.0に対応してるやつも作ってください。