-
Notifications
You must be signed in to change notification settings - Fork 1
mugene users guide ja
(このドキュメントは、まあ読めば分かるかと思いますが未完成です。肝心のMMLコマンドの命令は追って書きます。)
mugeneの世界へようこそ! mugeneはMML(music macro language)と呼ばれる命令を記述したテキストファイルから、SMF(standard MIDI file; 標準MIDIファイル)を作成するためのコンパイラ(変換ソフトの一種)です。MMLはSMFを作成するための古典的な方法ですが、DAW(digital audio workstation; 統合音楽作成環境) には馴染めないけど、ある種のオーディオ プログラミング言語ほど高度な知識もなく、MIDI楽器を使って簡単な作曲をしたいだけという人には、今でも向いています。mugeneでは、ある程度の文法上の柔軟性を維持しつつ、短く効率的な記述を不可能にしないことを目的として、文法を設計してあります。
このドキュメントでは、「mugeneの」MML文法について説明します。ここで説明されているmugene MML文法の説明を理解するには、基本的なMIDI命令に関する知識、基本的なSMFの構造、そしてMMLとはどんなものであるかについての何となくの理解が必要になります。MMLがどんなものであるかについては、別途イントロダクションとなる文章を用意してありますので、そちらをご覧ください。
MMLとひとことで言っても、そこにはさまざまな文法のバリエーションが存在しています。このドキュメントは、mugeneの文法がどのようなものであるかを説明するために書かれているものです。
このドキュメントは、MMLコンパイラの動作の詳細を完全に記述することを意図したものではありません。詳細な動作はコンパイラがバージョンアップを重ねるごとに変わります。mugeneのソースコードは公開されており、自由に改変して利用することができます。
このドキュメントはmugeneの「ユーザ」を対象に記述するものです。mugeneをライブラリとして活用したい、mugeneのソースコードをハックしたい、という方向けのドキュメントではありません。mugeneでは残念ながらライブラリとしての利用者のために安定したAPIを提供してはおらず(バージョンアップに伴い変更される可能性があります)、ハッカー向けのドキュメントは作成してありませんので、ソースコードを解読してください。MMLコンパイラとしてのエントリポイントはシンプルなものです。
mugeneのMML文法は、他種のMML文法と比べると、「一般化」されたもので、命令の多くは、プリミティブな命令(たとえば「命令バイトxxを出力する」といったもの)を組み合わせた「既定のマクロ」として実現しています。究極的には、mugeneユーザがカスタマイズできない命令は、MMLコンパイラの実行ファイルであるmugene.exeが提供するプリミティブ命令のみです。
多くの命令は、「既定のマクロ」であるところの default-macro.mml という名前のファイルで記述されており、これを使用するかどうかはユーザの自由です。多くのユーザはこれをそのまま使うことになるのではないかと思いますが、あなた自身でカスタマイズした default-macro.mml を使用しても良いでしょうし、ゼロから作り直しても良いでしょう(とはいっても、mugene.exeが提供する命令のいくつかは default-macro.mml を実装するために特化したもので、あなたが全く別の独自言語を設計するのには向いていないかもしれません)。
(独自の default-macro.mml は、たとえば相対オクターブ命令や相対ヴェロシティ指定命令の効果を逆にしたい場合などに有用です。)
多くのmugene初心者ユーザーにとっては、default-macro.mml で用意された命令を使いこなすところからスタートすることになるでしょう。
mugene MMLは、テキストファイルとして記述します。その内容は、原則として1行単位で解釈されます。
mugene MMLには、以下の3種類のMML行があります:
- ディレクティブ: 行頭を # とし、トラック以外の各種命令を記述します。
- コメント: 行頭を // とし、コンパイルされないコメントを記述します。
- トラック: 行頭をトラック番号の数値とし、SMFのトラックの内容を記述します。
これ以外の文字はエラーとなります。ただし例外として、(1)テキスト行が空白文字で始まった場合、その行は直前のトラック行の続きとして処理され、(2)テキスト行からコメントを取り除いた末尾が \ (円記号、バックスラッシュ)で終わっている場合は、続く1行も直前のMML行の続きとして認識されます。
// 例: 1 cdefg \ abc // 内容は cdefgabc となります
空白文字は、半角スペースおよびタブとなります。MML命令と引数、引数と引数、MML命令とMML命令の間には、空白文字を含めることができます。ひとつのMML命令と引数群は、ひとつのMML行に含めなければならず、改行は認められません。ただし、 \ 記号で複数行を連結することは認められます。
コメント行は、ユーザーがMMLに自分用の注釈を残しておくために使われるもので、MMLのコンパイルには影響しません。
ディレクティブ行の役割は、# の後に続く識別子によって異なります。詳しくは該当セクションで後述します。MMLで音を鳴らすために必要なのはトラック行のみですが、多くの場合は何らかのディレクティブを指定することになるでしょう。
MMLトラックは、SMFにおけるトラックの概念に相当します。トラックとチャネルは別個の概念です。複数のトラックから1つのチャネルを制御することができます。
トラック行は、まずトラック番号を書いて、それからMML命令を順次書きます。トラック番号は、数値 0 以上の値で指定します(mugeneのコンパイラは論理的な限界をチェックしませんが、通常はせいぜい数十トラックで足りるでしょう)。トラック指定では、以下のような複雑な指定も可能です
- 1,2 : トラック1およびトラック2を指定します
- 2-5 : トラック2~5を指定します(2,3,4,5 と同じ意味です)
- 1,2-4,5 : 上記の組み合わせ。この場合、トラック1,2,3,4,5を指定します
MML命令は、(1)プリミティブ命令と(2)マクロ呼び出しのいずれかになります。プリミティブ命令は、通常は default-macro.mml で定義されている標準マクロを定義するために使用されるもので、ユーザーが使用することはありませんが、文法上は使用することが可能です。マクロ呼び出しは、文字通り、定義済みのマクロを呼び出すという命令です。
MML命令は、命令語となる識別子と、その命令の引数から成ります。これらについては次節以降で詳しく説明します。
識別子は、マクロ名やプリミティブ命令の定義で用いられる文字列で、MML中で命令を識別するためにある概念です。
一般的なプログラミング言語とは異なり、mugene MMLでは多くの文字が識別子名として許容されており(これは、MMLに慣れている人は自分の経験に合った文字を自分の好みの命令に割り当てられるようにするという意図で設計されているためです)、一方で一般的なプログラミング言語より厳しい制約もかかえています。
識別子名の文法的制約は以下の通りです:
- 常に禁止される文字: 0 1 2 3 4 5 6 7 8 9 " , { }
- 先頭で使用できない文字: – + ^ ? #
- 先頭でしか使用できない文字: / : ( )
MML命令のほとんどは、引数(パラメータ)を伴います。どんなパラメータを与えるかによって、(SMFに)出力される発音(命令)が変わってきます。
たとえば、今のトラックのオクターブを指定する命令 o は、オクターブの高さを引数にとります(o0 ~ o10)。プログラムチェンジやコントロール(CC)、アフタータッチなどは、MIDIメッセージと同等の引数をとります。複数の引数は、’,’(カンマ)で区切ります。
数値は通常は10進数として解釈されますが、# を付けることで16進数として解釈されます。
発音命令と休符命令の引数は少し特殊です。これは「数値」とは別に扱われる「音長」となります。たとえば r は休符命令ですが、r4 と書いた場合は4分休符になります。r1 と書いた場合は全休符になります。r8. と書いた場合は付点8分休符になります。
しかし、r4はコンパイラの内部では、4という数値としては処理されません。音長は、内部的には「ステップ数」という数値に変換されます。標準状態では、r4 は48ステップという数値になり、r1 は192ステップという数値になり、r8. は36ステップという数値になります。全休符を192として、音の長さを乗除算して出した数値になります。
音長は、数値の前に % を付けることで、このような数値として直接記述することもできます。たとえば r%48 は4分休符と同じです。
ちなみに、全休符に対応する 192 という数値は、#basecount というディレクティブ命令で変更できます。
MML命令の中には、他にも「文字列」を引数に取るものがあります。文字列の値は “…” のかたちで、ダブルクォーテーションで囲んで記述します。一部の文字は、文字列の中で直接表現することができないので、「エスケープシーケンス」を使って表現します:
- \r : 改行(CR)
- \n : 復改(LF)
- \/ : スラッシュ
- \" : ダブルクォーテーション
- \\ : 円記号/バックスラッシュ
最後に、「型」について説明します。型はマクロを定義したり、MMLリファレンスを読んだりする時のために、理解しておく必要があります。
どのMML命令の引数にも「型」があります。命令を使うときは、それぞれの引数の型で期待される値を指定しなければなりません。mugene MMLには、以下の4種類の引数型があります:
- number : 数値。整数となります。
- length : 音長。上記の通りの意味で解釈されます。内部的には数値となります。末尾に付点を付けることで長さが1.5倍になり(多重付点も指定可能で、1.75倍、1.875倍…となります)、%を付けることでステップ数の直接指定となります。
- string : 文字列となります。
- buffer : これは __STORE という特殊な命令のために用意された、特殊な型で、通常はmugeneユーザーが使う必要はありません。
MMLでは、発音命令および休符命令が実行されると、次の命令呼び出しまで、指定された音長分だけ待機することになります。たとえば、c4d4 というMMLがあった場合、レが発音されるのは、ドが発音されてから4分音符分の時間が経過してからです。MMLで記述された音楽はこのようにして成り立っています。SMFにおいては、この「命令と命令の間の時間」の概念は デルタタイム と呼ばれています。
休符命令はマイナス値を引数にとることも出来ます(実は発音命令でもコンパイラの処理としては可能ですが、発音と消音のタイミングの関係で、そのような命令呼び出しを行うと、結果的に生成されるSMFはおかしなものになりますので、作者は推奨しません)。マイナス値の休符命令を呼び出すと、「巻き戻し」を行うことができます。
やや高度な話になりますが、mugeneにおけるMML命令には全て「呼び出した時点での時間軸上の位置」が関連づけられており、これはMML解析中に __timeline_position という変数として、MML中で参照したり設定したりできます。これはあくまでトラックごとに管理される変数値であり、たとえばトラック間での時間軸の同期に用いることは出来ません(そもそもMMLの解析は必ずしもファイル行順に行われるわけではないので、そのような使用は出来ません)が、この変数を活用してスペクトラムのような動的なSMFメッセージの生成が実現できています。
:書式:
- #comment
この行以降、#endcomment ディレクティブが出現するまでの行は、コンパイラによって処理されません。条件コンパイルよりもさらに簡単にMMLのコンパイルをスキップしたい場合に活用してください。
:書式:
- #endcomment
#comment からこの行までの行は、コンパイラによって処理されません。(コメントアウトの意味は#commentディレクティブを参照してください。)
:書式:
- #basecount [number]
全音符ひとつが、ステップカウントいくつに相当するかを指定します。ステップカウントについてはこちらを参照してください。
ベースカウント値を引数として直接指定します。
:書式:
- #conditional block [blocks]
- #conditional track [tracks]
特定の条件に合致したトラックや楽曲ブロックのみをコンパイルするようにします。特定のトラックをフィルタしたい場合や、特定の楽曲ブロックから先だけを効率よく編集・再生したい場合に活用できます。
:書式:
- #meta title 楽曲タイトル
- #meta copyright 著作権情報
- #meta text テキスト情報
それぞれ、SMFのメタテキストとして出力されます。(text = FF 01, copyright = FF 02, title = FF 03)
:書式:
- #define [source] [replacement]
ここで記述した [source] の文字列を、全て [replacement] に置き換えます。これはプリプロセッサ命令を全て読み込んだ後、マクロ定義行とトラック行に対して行われます。
注意点として、この置換処理は、これらの行の「本体」部分ではなく、行全体に対して適用されます。つまり、トラック指定やブロック指定に使われている文字列も対象となります。
(このディレクティブは、特にリズムトラック命令を適用したい「リズムトラック」を、エイリアス DRUMTRACKS によって指定し、それらのトラックのみを対象としてリズムトラック用マクロを定義したいという目的で追加されました。)
:書式:
- #macro [tracks] [identifier] { […] }
[identifier] という名称のマクロを定義します。その内容は { と } の間で囲まれた文字列となります。
[tracks] は通常は省略しますが、明示的に指定することによって、マクロを定義するトラックを限定することが出来ます。リピートフレーズや和音、リズムトラックにおける発音命令などは、トラックを限定して指定すると、他のトラックとの間で混乱や衝突が生じなくなるので良いでしょう。
マクロの内容はコンパイラによって適宜展開され、循環参照は禁止されます。
プリミティブ命令は、多くのmugeneユーザーにとっては無関係かもしれませんが、変数の代入や参照、条件分岐など高度なマクロ命令を記述するための基本命令を多く含んでいます。言い換えれば、ここで説明する命令は、高度なマクロ命令を記述する人向けのものです。
:書式:
- __PRINT [identifier]
:書式:
- __LET [identifier], [value]
:書式:
- __STORE [identifier], [string], …
これはVocaloidサポートのために用意された特別なプリミティブ命令です。
:書式:
- __STORE [identifier], [format], [number], …
] で表された書式に従って、全て追加します。書式文字列は、ECMA CLI (ECMA 335)の System.String.Format()で使用される書式となります。
これはVocaloidサポートのために用意された特別なプリミティブ命令です。(C#の文法に依存するのはあまり賢くないので、今後はフォーマット文字列を限定することになるかもしれませんが、いずれにしろ特殊用途での拡張構文なので、大きな影響はないと考えています。)
:書式:
- __APPLY [macro_string], arguments…
[macro_string] で指定された文字列を、マクロとして解析し、再帰的にマクロ呼び出しとして、2番目以降の引数をそのマクロ命令呼び出しの引数に用い、その場で展開します。この文字列は定数である必要はありません。
これと条件分岐演算子 ? を組み合わせて使用することにより、柔軟な条件分岐を実現できます。
:書式:
- __MIDI arguments …
引数を全てそのままバイト列として出力します。基本的には number となりますが、全て1バイトの範囲でしか出力されないことに注意してください。
:書式:
- __MIDI_META arguments …
MIDIメタイベントを出力します。最初に FFh を出力し、続いて引数をバイト列で出力します。文字列の場合、mugene.exeの呼び出し時に指定されたエンコーディング(無指定時はUTF-8)を用いて、文字列からバイト配列に変換されます。
:書式:
- __ON_MIDI_NOTE_OFF
これはかなり特殊な目的のために追加された命令です。default-macro.mml において、音長が0のキーを和音として扱うために、発音コマンドでノートオフがあった際に呼び出されるものです。これにより、 c0e0g1 をド・ミ・ソの和音として処理することを可能にしています(この命令を使用しない場合、c0もe0も実質的に発音されません)。
和音表記をあえて無効化する理由は無いと思いますが、無効化したい場合は、default-macro.mml を編集して、ON_MIDI_NOTE_OFF を呼び出さないようにすると良いでしょう。
:書式:
- __LOOP_BEGIN
ループの開始を指示します。default-macro.mmlでは [ が命令として割り当てられており、そちらを使うのが一般的です。
:書式:
- __LOOP_BREAK arguments …
ループの中断(区切り)を指示します。default-macro.mmlでは : および / が命令として割り当てられており、そちらを使うのが一般的です。
引数には、直前のループ開始ないしループ中断命令から、このループ中断命令までのブロックが、何回目のループで使用されるのかを指定します。引数は省略可能であり、また複数値の指定も可能です。引数が省略された場合は、他のループブロックが適用されなかった場合に適用されます。
たとえば
1 [ A : B :1,3 C :2 D] 5
というループがあった場合、その内容は A C A D A C A B A となります(Bの前の : には指定値が無いので、B は対象ループブロックの無い4ループ目で適用されます。Cは1,3回目のループで適用されます)。
ループの終了を指示します。default-macro.mml では ] が命令として割り当てられており、そちらを使うのが一般的です。
(vocaloidサポート用の内部命令なので、ここでは説明しません)
(vocaloidサポート用の内部命令なので、ここでは説明しません)
(vocaloidサポート用の内部命令なので、ここでは説明しません)
さて、ここからいよいよ一般ユーザー向けの命令である、デフォルトマクロ命令の説明に入ります。
:書式:
- DEBUG [string]
引数を文字列にして出力します。これはプリミティブ命令 __PRINT の単なるエイリアスです。
:書式:
- NOFF [key],[vel]
指定した音階[key]とヴェロシティ[vel]のノートをオフにします。いずれも0~127の数値で指定します。全ての音階コマンドはこの命令を利用しています。MIDI命令 8*h を出力します。
:書式:
- NON [key],[vel]
指定した音階[key]とヴェロシティ[vel]のノートをオンにします。いずれも0~127の数値で指定します。全ての音階コマンドはこの命令を利用しています。MIDI命令 9*h を出力します。
:書式:
- PAF [key],[vel]
指定した音階[key]とヴェロシティ[vel]のノートでアフタータッチを出力します。いずれも0~127の数値で指定します。MIDI命令 A*h を出力します。
:書式:
- CC [opcode],[val]
指定した命令アドレス[opcode]と値[val]でコントロール チェンジを出力します。いずれも0~127の数値で指定します。MIDI命令 B*h を出力します。
:書式:
- PROGRAM [val]
音色を音色番号で指定します。0~127の数値で指定します。MIDI命令 C*h を出力します。通常は @ 命令を使用します。
:書式:
- CAF [val]
指定値でチャネル全体のアフタータッチを出力します。0~127の数値で指定します。MIDI命令 D*h を出力します。
:書式:
- PITCH [val]
指定値でピッチベンド値を出力します。0~16383の数値で指定します。MIDI命令 E*h を出力します。
PITCH命令はSMFの生データに近い数値をそのまま指定します。B命令を使用すると、マイナス値を利用した、より直感的な数値が指定できます。
:書式:
- l [length]
引数で指定した音長が、以降に出現する音長省略時の、発音・消音命令のデフォルト値として使用されるようになります。
:書式:
- K [val]
- K[c..b]+
- K[c..b]-
- K[c..b]=
引数で指定した値だけ、発音コマンドのキーを移調させます。正/負の任意の数値が指定可能です。ただし最終的な発音命令で許容される範囲は 0~127になります。
Kc, Kd…などキーが指定されている場合は、特定のキーの値のみ 1 または -1 します。K[c..b]およびK[c..b]-で変更した値は、K[c..b]= 命令を使用して 0 に戻すことができます。
:書式:
- v [val]
指定値をヴェロシティ値として設定します(絶対指定)。この値は、ノートオン命令およびノートオフ命令におけるヴェロシティのデフォルト値として使用されます(発音命令では個別にヴェロシティを指定することも可能です)。有効な値は0~127です。
:書式:
- ) [val=4]
- ( [val=4]
指定値を現在のヴェロシティ値に加減算して設定します(相対指定)。設定された値の意味は v命令と同様です。) が加算、 ( が減算になります。(この設定が好みに合わない場合は、default-macro.mml に手を加えて意味を逆にした方が良いでしょう。)
引数は省略可能で、その場合の値はデフォルトでは4となります。この4という値は、 __velocity_sence という変数の値を設定することで変更可能です。
:書式:
- E [val]
指定値をエクスプレッション値として設定します(絶対指定)。この命令はCC #0Bを出力するもので、従って対象チャネルにおける全てのノート命令に適用されます。有効な値は0~127です。
:書式:
- E+ [val]
- E- [val]
指定値を現在のエクスプレッション値に加減算して設定します(相対指定)。設定された値の意味は v命令と同様です。引数は省略できません。
:書式:
- t [val]
- TEMPO [val]
テンポの値を、1分間における4分音符の数によって指定します。
テンポは、楽曲全体で共有される情報です。一方で、変数の値というものはトラック単位でしか保存されません(MML行をコンパイルする順序も一定ではないため、実質的に複数トラック単位で指定できるものではありません)。多くのシーケンサでは、トラック0にテンポ命令を全て記述しています。
:書式:
- t+ [val]
- t- [val]
指定値を現在のテンポ値に加減算して設定します(相対指定)。設定された値の意味は t命令と同様です。引数は省略できません。
:書式:
- M [val]
指定値をモジュレーション値として設定します(絶対指定)。この命令はCC #01を出力するものです。有効な値は0~127です。
:書式:
- M+ [val]
- M- [val]
指定値を現在のモジュレーション値に加減算して設定します(相対指定)。設定された値の意味は M命令と同様です。引数は省略できません。
:書式:
- V [val]
指定値をヴォリューム値として設定します(絶対指定)。この命令はCC #07を出力するものです。有効な値は0~127です。
:書式:
- V+ [val]
- V- [val]
指定値を現在のヴォリューム値に加減算して設定します(相対指定)。設定された値の意味は M命令と同様です。引数は省略できません。