mmlについて思うこと


mmlがどうしても職人芸になりがちな理由として,標準的な仕様が無いというのがある.数値がレジスタ値の直記入だったりするのでモジュールを横断するような標準的な仕様は作りにくいっていう背景もあるんだけど.
自分のmml遍歴は,FM7 -> FM-TOWNS -> PCE500の3重和音プログラム -> TSS(TSSCP) -> FlMML って感じで,メジャーな仕様にはほとんど触れていない.「メジャーなmml」って時点で「日本語でおk?」なんだけど,それは置いといて,自分が思うメジャーどころは,z-musicmckマビノギさくら,あたりか.


これらの共通要素をくくりだすとおおよそwikipedia の mml の項のa-g,r,l,o,v,t,+,-,'.' あたりになる.それ以外の命令についてはどうなっているのか,多分まとめる奇特な人はいないと思うので,ここで少し書いてみる.仕様が手に入った,TSS, FlMML, z-music, ppmck, マビmml,さくら,みゅあっぷ98,mml2midiが対象.

オクターブシフト

  • <上,>下; TSS(default), FlMML, z-music, (x68系)
  • >上,<下; マビmml, ppmck(default), さくら(default), みゅあっぷ98, mml2midi(default), (pc98系)
  • 変更可能; TSS, ppmck, さくら, mml2midi

最も有名なmml不可解問題のひとつ.一般に'<上'がx68000ベース,'>上'がpc9801ベースらしい.

a=440Hzになるオクターブ

  • o3; (standard MIDI)
  • o4; FlMML, z-music, ppmck, マビmml, mml2midi, みゅあっぷ98
  • o5; TSS, さくら

o4がマジョリティ.でも実はo5センターにはちゃんと理由があって,o0cがMIDIノートナンバー0番になるので,全MIDIノートを表現できる事になる.

ボリュームコマンドの最大値

  • 15; TSS, FlMML, ppmck(モジュール依存), マビmml, みゅあっぷ98
  • 63; ppmck(モジュール依存)
  • 127; z-music, さくら(ベロシティ/ボリューム), mml2midi(ベロシティ/ボリューム)

0-15がマジョリティ.詳細ボリュームコマンドが無い場合は0-127.

詳細ボリュームコマンドの最大値

  • 無し; z-music, ppmck, マビmml, さくら, mml2midi
  • 127; FlMML(@v), みゅあっぷ98(@v)
  • 255; TSS(@v)

詳細ボリュームコマンド自体がマイノリティ.

ボリュームシフト

  • 無し; FlMML, マビmml, さくら
  • (,); TSS(コンパイラ擬似命令)
  • (n,)n; mml2midi(相対ベロシティ変化)
  • _n,~n; TSS(0-255), z-music(0-127)
  • v+n,v-n; ppmck, みゅあっぷ98

このコマンドは結構バラけた.

Lコマンド値依存ゲートタイム指定

  • 無し; マビmml
  • qコマンド; TSS(0-15), FlMML(0-15), z-music(-8~-8), ppmck(1-8), さくら(0-100), みゅあっぷ98(1-8)
  • Qコマンド; mml2midi(1-8)

ゲートタイムがqというのは,[a-grlovt]についで標準的といって良いっぽい.ただし値はバラバラ,1-8がやや優勢か.

絶対値ゲートタイム指定

  • 無し; マビmml, TSS, FlMML, さくら
  • qコマンド; mml2midi(特殊)
  • @qコマンド; 偽TSS(0-192), z-music(-32767~32767), ppmck(0-65535), みゅあっぷ98(0-192)

実は絶対値ゲートタイムは詳細ボリュームよりメジャーなコマンドと言える.やっぱり値はばらばらだけど.

タイ&

  • 無し;
  • 有り; TSS, FlMML, z-music, ppmck, マビmml, さくら, みゅあっぷ98, mml2midi(特殊)

これは標準と言って良いコマンドで挙動も大体一緒.大体がスラー兼用だけどスラー時の挙動は各々少し違うみたい(要検証).

音長加算^

  • 無し; FlMML, マビmml, mml2midi
  • 有り; TSS, z-music, ppmck, さくら, みゅあっぷ98

上述タイとあんま変わらないはずだけど,結構搭載されている.

連符{}

  • 無し; TSS, FlMML, ppmck, マビmml, mml2midi
  • 有り; z-music, さくら, みゅあっぷ98

無しがやや優勢.

リピート

  • 無し; マビmml
  • [n..|..]; TSS(コンパイル時展開)
  • /:n../..:/; TSS, FlMML
  • [..|..]n; ppmck(コンパイル時展開)
  • |:..\..:|n; ppmck
  • [n..:..]; さくら
  • [..:..]n; mml2midi
  • (..@IF..); みゅあっぷ98

これはひどいカオス.こういう重要命令が統一されてないのがmmlのダメなところ.

コメントアウト

  • 無し; マビmml
  • {..}; TSS
  • /*..*/; FlMML, ppmck, mml2midi
  • ;..\n; ppmck, みゅあっぷ98, mml2midi
  • /..\n; z-music
  • コメント{".."}; さくら

"/*..*/"ブロックと行頭";"が一応マジョリティ.


あと繰り返し命令によるパラメータの遷移を調べたかったんだけど,これは仕様書だけではどうにもならないので保留.具体的には,下のコマンドについて,各mmlで如何様に鳴るのか興味がある.

l4c /:c l8 c:/ r1
o4c /:c o5 c:/ r1
q3c /:c q9 c:/ r1
v3c /:c v9 c:/ r1

FlMMLの場合,l,o,q,vの各イベントは全てメモリ上で正直に登録されるため,繰り返しの先頭に戻ってもパラメータは変化しない.よって,全て前半2音/後半3音の組み合わせ(1行目なら"l4c l4c l8c l8c l8c")で鳴る.感覚的には自然な挙動といえる.が,音楽データとしてみると,繰り返し時に1回目と2回目で異なる鳴らし方をする必要があるのかとも思える(ループでクレッシェンドをかけるとかなら有利なんだけど).
mmlの場合,モジュールの仕様等によりメモリ上では展開される命令も多い.実際,tsscpで再生すると,1行目は"l4c l4c l8c l4c l8c"と再生される(o,qコマンドも同様),一方,4行目は"v4c v4c v8c v8c v8c"と再生される.tssはクローズドソースなので想像しか出来ないが,恐らくメモリ上ではノートイベント内に長さとオクターブの情報も含んでいるためと思われる.一見,不自然な挙動だけど,メモリ上でオクターブ+ノートをノートナンバーとして展開したり,ゲートタイムをノートオン/ノートオフとして展開するのは,モジュールの挙動を考えれば,まっとうなメモリ展開方法といえるし,音楽データとして繰り返し時にループ先頭の状態にリセットされるのはありがたい.


mmlでこういう不自然さが受け入れられてきた背景には,マニアックなユーザーがモジュールの挙動や,メモリ上に展開されたバイナリデータの仕様まで把握しており,仕様設計者も得てしてそういうマニアックなユーザーだったという点が少なからずあると思う.
当時はメモリもCPUもカツカツだったためメモリ節約術が効果的だったが,現在のPCスペックであれば,mml展開時のメモリ量も,イベント増加に伴う計算負荷も,波形生成に比べて大したウェイトではない.そういう意味で感覚的には自然なFlMML風の展開を行うのが良いのか...悩む.