MGSDRVでループすると音がズレる...?


MGSDRV用のMMLを作っていると、ループすると音がズレるのでバグではないか?と思うことがあります。
原因は多くの場合、入力ミスなのですが、入力したMMLが一見完璧に思えるのに、演奏すると期待通り発音されないことがあります。

実例

次のMMLを演奏してみましょう。同じフレーズを2回演奏するつもりのMMLです。

#opll_mode 1
#tempo 90

9 v15@10 l4 [ g4>d4<b-4.l8 agb-agf+ad4 r1 ]2
  • MMLはこちらで実際に演奏できます。

同じフレーズが2回演奏されるように見えますが、2回目は、最初のg4>d4< が4分音符ではなく8分音符で演奏されてしまいます。バグっぽいですよね。

原因

MGSDRV 用の MML コンパイラ MGSC には MML の最適化機能がついていているのですが、ループを一切考慮しないで最適化してしまうという問題があります。

最適化とはどういうことが行われるかというと、直前の音長lコマンドで指定したのと同じ音長のノートは、音長を省略したMMLとして扱われます。例えば

l4 c4d4 l8 e8f8

と書いた場合、直前の音長指定コマンドを考慮して

l4 cd l8 ef

と書いたかのようにコンパイルされます。これがなぜ最適化なのかというと、音長付きの c4d4 はコンパイル後に2バイトになるのですが、音長なしの cd は1バイトになるのです。

この最適化は大変ありがたいことなのですが、ループを使うと、問題が起こります。
例えば次のように書いたMMLが

l4 [c4d4 l8 e8f8]2

次のように最適化されます。

l4 [cd l8 ef]2

このMMLのループを展開して考えてみると、

l4 cd l8 ef cd l8 ef

となります。MMLを書いた側からすると、2回目の cd も4分音符で演奏されることが期待なのですが、
8分音符として演奏されてしまうことが分かります。

対策

lコマンドはループの開始点で必ず指定しましょう。

l4 [cd l8 ef]2

ではなく

[l4 cd l8 ef]2

とすれば意図通りに演奏が行われるようになります。