シーケンスを作って音を鳴らすことができました。今回はテンポを設定して演奏の速さを変えたいと思います。
BPMとMPQ
曲の速さを表すのに一般にはBPMを使います。BPMはBeats Per Minuteの略で通常ポピュラー音楽では四分音符を使います。BPMによる曲の速さはこの四分音符が1分間に何拍数えられるかで決まります。例えば時計の秒を一拍と考えるとは1分間に60拍となるのでBPMは60になります。BPMは音楽全般で使われる概念で数字が大きくなるほど速くなります。
MIDIではシーケンスになにも指定されないとテンポはBPMが120にデフォルトで指定されます。ちょうど時計の秒の半分、つまり一秒に2拍になります。今までのサンプルでは特にテンポを指定していなかったのでBPMは120になっていました。
MPQはMIDIでのテンポの設定に使う概念でMicroseconds per Quater-noteの略です。「四分音符一つあたりの時間をマイクロ秒で表した数字」になります。こちらは値が大きくなるほど遅くなります。
1秒は1,000,000マイクロ秒、1分は60,000,000マイクロ秒になりますからBPMとMPQは以下のような計算で変換することができます。
BPM = 60,000,000 / MPQ MPQ = 60,000,000 / BPM BPM * MPQ = 60,000,000
例えばBPMが120の場合、MPQは500,000になります。
MPQの設定方法
シーケンスでMPQを設定するにはMetaMessageを使います。
MetaMessage
(int type, byte[] data, int length)
テンポ設定のtypeは0x51です。dataはデータ自身、lengthはその長さになります。
MPQの値は3つのデータバイトを使って表現されます。個々のデータバイトは0x00から0xFFまで値をとることができ、これを3つ使うことができるので0x000000から0xFFFFFFまでの6桁の値をテンポの設定値として使うことができます。
実際にはMPQが最小値0ということは通常ありません。無限に早いテンポということになり全てのデータが一度に送信される事になってしまいます。また最大値の0xFFFFFF、10進では16,777,215という数字は1拍に17秒弱かかります。BPMで3となりこれも通常の楽曲ではまず起こりえないほど遅いテンポです。
最小値最大値を確認したところ通常要求されるテンポの範囲はこれで表現できることがわかります。
実装
では実装していきます。まずdouble値でBPMの値をもっているものとします。
double bpm = 120;
これをMPQに変換します。小数点以下は丸めてlong値にします。
long mpq = Math.round(60000000d / bpm);
それぞれのバイトデータを作ります。
byte[] data = new byte[3]; data[0] = new Long(mpq / 0x10000).byteValue(); data[1] = new Long((mpq / 0x100) % 0x100).byteValue(); data[2] = new Long(mpq % 0x100).byteValue();
これを元にメタメッセージを作ります。
new MetaMessage(0x51, data, data.length);
ユーティリティーメソッド
ここまでの実装を使ってユーティリティーメソッドを作ります。次回これを利用してシーケンスのテンポを変えるようにします。
public static MetaMessage getTempoMessage(double bpm) { long mpq = Math.round(60000000d / bpm); byte[] data = new byte[3]; data[0] = new Long(mpq / 0x10000).byteValue(); data[1] = new Long((mpq / 0x100) % 0x100).byteValue(); data[2] = new Long(mpq % 0x100).byteValue(); try { return new MetaMessage(0x51, data, data.length); } catch (InvalidMidiDataException ex) { throw new IllegalStateException(ex); } }