TL; DR
機械に読ませやすくするか、人間が編集しやすいままにするか
楽譜上の時刻?
皆さん、音ゲーはお好きですか?アーケードからスマートフォンまで様々な筐体で遊べるリズムゲームですが、譜面はどのように記述されているか、気になったことはありませんか?
この記事では、ノーツの判定時刻を4種類の方法で表し、それらの長短を比べようと思います。
時刻の表し方
演奏開始からの秒数
まずは最もシンプルなところから。
音源の再生が始まってから何秒後にアクションすればよいかを表すものです。BPM=120で刻むなら
0.0
0.5
1.0
1.5
2.0
...
といったところでしょうか。
もちろん、単位は秒に限りません。1ミリ秒を1として
0
500
1000
1500
2000
...
などとしてもよいですし、60FPSで動く&判定する仕様に合わせて
0
15
30
45
60
...
などと表すのもよいでしょう。
この記法の長所は、「機械にとって処理しやすい」点が挙げられます。
BPMや小節の拍数など他の要素を気にせず、とにかくアクション時の音源の再生位置と譜面の時刻を比較すればよいだけなので、高速に処理できます。
一方、この記法は譜面師さんが読み書きするには面倒です。というのも、BPM=120の楽曲ならまだいいんですが、BPM=121のような中途半端な数字になると
0
0.496
0.992
1.488
1.983
...
のように、読みづらく作成する際にも毎回計算が必要になってしまいます。
MBTを用いた方法
MBTは「Measure:Beat:Tick」という表記の略称で、"小節番号"と"拍番号"と"拍内のズレ"の3要素を用いて表す方式です。"拍内のズレ"は、1拍を"分解能"と呼ばれる数字(譜面で1つ定義)で分割した際の何番目かを表します。
例えば、3小節目から8分音符で5回叩くことは次のように表せます。分解能は960としています。小節番号や拍数は0-indexedである点に注意して下さい。
2:0:0
2:0:480
2:1:0
2:1:480
2:2:0
この方法の長所は、「譜面師さんが読みやすく、他者と会話をする際に分かりやすい」点にあります。
「oo小節目のxx拍目のノーツはhogehogeがいいな」のように小節数と拍数が会話内であったときにすぐにノーツを特定できます。
この方法の短所は、「機械が読みにくい」点があります。
この記法の場合、あるMBT表記が与えられたときに、そのノーツの音源上の時刻を計算するのに「BPM」「1小節内の拍数」「分解能」「音源オフセット1」を意識する必要があります。特に「BPM」と「1小節内の拍数」は楽曲によっては演奏途中で変化することがあり、特定のMBT表記から時刻を算出するのに過去のBPM・拍数変化を全て加味する必要があります。
Tickを用いる方法
MBTでは「1小節内の拍数」を考慮しなければなりませんでした。そこで、「演奏開始からの経過Tick数だけで全て表現できないか」ということでTickのみを用いる方法があります。
例えば、4/4拍子の楽曲で3小節目から8分音符で5回叩くことは次のように表せます。分解能は960としています。
7680
7920
8160
8400
8640
...
この方法は数字1つで位置を表すことができ、MIDIファイルの内部構造でも利用されています。
この方法の長所は、「譜面師さんがそこそこ読みやすい形式に簡単に変換でき、機械にも多少読みやすい」点です。
分解能の何倍の値かを見ることで小節番号を推測したり、値を分解能で割った余りを見ることで小節内のどこにあるのかを簡単に知ったりできます。機械にとっても、ノーツの時刻を割り出すのに必要な要素が「BPM」「分解能」「音源オフセット1」だけになるため、考えることが1つ減ります。
一方、短所は「一般に数字が大きくなりやすい」点です。様々な拍パターン(3連符・5連符なども含む)に対応するため、一般的なMIDIファイルの分解能は480や960と大きめな数字になっています。4/4拍子で100小節進むと192,000という大きな値を扱うことになります。これは機械ならまだしも人間が読む数字としては大きすぎます。
分解能をノーツ毎に指定する方法
先述の2方式では分解能が譜面に1つでしたが、譜面によっては「一部だけ変拍子を使っているが、多くの部分はそうでもない」ということがあります。そのため、必要なところだけ分解能を上げるという方法を取ることがあります。
例えば、4/4拍子の楽曲で3小節目から8分音符で5回叩くことは次のように表せます。分解能は960としています。
本記事においては、表記を(開始からの拍番号),(拍内のオフセット)/(分解能)
とします。
8,0/1
8,1/2
9,0/1
9,1/2
10,0/1
...
この方法はBMSの考え方に近く、1拍をn等分したm番目という表現をします。
この方法の利点は「小さな数字で多くの表現ができる」点にあります。
例えば、MBTやTickを分解能480や960で出力すると7分音符が正確に再現できません。これは、480や960が7で割り切れないことに起因します。
この記法の場合、7連符を
0,1/7
のように分母に7を置くことで表現することができます。
また、小節番号をデータに入れないことで、Tickを用いる場合と同様の情報で時刻の計算が可能となります。
一方、この方法では一般にノーツ毎に分解能が異なるため、パッと見ただけではどれが最初に来るのか分からなくなりがちであるという問題があります。これは、通分できたとしても1拍内では同じ分解能を使い続けるよう制約をかけることで回避することができます。
組み合わせ
機械にとっては、演奏開始からの秒数が最も楽に取り扱えるため、編集中はMBTなど人間が読みやすい形式を用い、利用前に各ノーツの時刻を計算しておきメモリ内部に秒数で保持しておくという方法を取ることがあります。
参考記事
MBT
https://qiita.com/toyoshim/items/69dce2c58f72418b3d19
BMSの記法
https://w.atwiki.jp/laser_bm/pages/93.html