MML作成の手引き
ここでは簡単なMML作成の手順を説明します(MML初心者寄りの内容です)。
下準備
blueMSXをturboRで起動するようにセットアップしておきます。
blueMSXに読み込ませるディレクトリを作成し、中にMSX-DOSのファイルとドライバを入れ、blueMSXにD&Dします。


次にコンパイラの方の設定です。

設定を開き

出力フォルダをblueMSXに読み込ませた物に、文字コードをこれから書くテキストファイルに合わせて変更します。この設定で、コンパイルすれば直ぐにblueMSXで読み込める状態になります。設定はコンパイラを終了した時にiniファイルに書き出され、次回からはその設定で起動します。
テキストファイル作成
空のテキストファイルを作成します。ファイル名はそのまま大文字に変換されて、MSX用SDTのファイル名になるので、MSXの制限(8文字以内等)で作成します。
注意点として、DOS1ではコマンドラインのファイル名は_(アンダーバー)を認識してくれません。_を使ったファイル名の場合、?に変えるととりあえず回避することはできます。プレイヤーモードではプログラムからファイル名を指定しているので_を使ったファイルでも大丈夫です。

上の画像の場合出力されるファイル名はYAKF.SDTとなります。
テキストファイルへの記述
こう書かないとエラーになるわけではありませんが、とりあえず最初に初期設定等を書きます。
tempotype=["calculation"]
all_tempo=[112]
@title=["Yie Ar Kung-Fu"]
@author=["めが"]
@original=["KONAMI"]
@comment=["MML作成のサンプルです。"]
s1=@all_k3 @s"sin" v15 o6 l8 ff16f16eecc<a4 b16>c16<b16a16faf2
※背景色が同色の行は表示上折り返しされていても一行で記述していると見て下さい。
1行目から7行目までが定義部分、s1=からが演奏内容を表すシーケンス部分となっています。
ではまず1行目から。ここは;(セミコロン)でコメントとなりその行は無視されます。
次にtempotype=["calculation"]ですが、値が"table"と"calculation"があり、tableは過去の互換性のために残しているだけなので、音長計算の精度が良い"calculation"を指定しています(デフォルトでは"table")。
all_tempo=[112]はテンポ指定です。4分音符が1分間に何個入るかを表します。全チャンネルにt112と書いたのと同じ処理ですが、記述が1箇所で済むので視認性が良くなります。曲中にテンポが変更される曲の場合は、個別にtコマンドで対応します。
@title,@author,@original,@commentはプレーヤーモードで再生した時に表示される情報になります。これをコンパイルすると以下のようにプレイヤーに表示されることになります。

緑丸が@title、黄丸が@comment、青丸が@author、赤丸が@originalに対応しています。
シーケンスデータ
今回はSCCを使うことにしたので、s1=と書き出します。以降、別のチャンネル名や、定義等が出現するまでは、改行してもずっとs1チャンネルのデータとして解釈されます。
今回打ち込む曲はファとドとソにシャープが付く曲で、楽譜では下の図のようになっていました。

楽譜上はこのように最初に指定してあれば、あとは一々書いていなくてもファ、ド、ソ、ならシャープを付けて演奏することになっていますが、そういう記述をSCMDのMMLでも@all_k(または@k)コマンドを使って可能です。
シャープならプラス、フラットならマイナスの数値をその数だけ記述するフォーマットなので、今回はシャープが3つで@all_k3となります。このコマンドが読み込まれた時点で、(内部処理的には@k3が)全チャンネルに設定されます。これは、tコマンドとall_tempoコマンドの関係と同じです。これでこのMML上では、f+c+g+としなくて良くなりました(因みにナチュラルになっている場合は、f-のように記述します)。記述が減って楽になるということに加えて、+/-の付け忘れによるミスが減ります。
音色指定他
@s"sin"として、SCCの音色を適用しています。"sin"はコンパイラのプリセット音色なので、音色データを定義する必要なく使用可能です。残りはv15で音量指定、o6でオクターブ指定、l8でデフォルト音長指定をした後、演奏する音階が続きます。
音階指定部分の詳細
冒頭、ff16f16の最初のfでは音長が省略されているのでデフォルト音長8で演奏されます。また、発音は@all_k3の作用により、実際にはf+(ファのシャープ)が発音されることになります。次のf16ではf+を音長16で演奏します。音長は〇〇分音符の〇〇を表しています。
途中<や>が出てきますが、これはオクターブを1つ下げる、上げるコマンドです。直接oコマンドを使ってo5やo6等と指定しても同じですが、1文字楽できるのと相対的な指定なので、基準となるo指定を変更するだけで、演奏全体のオクターブを上げたり下げたりが簡単にできるという長所があります。
コンパイル
とりあえず、ここまでのMMLをコンパイルしてみます。

テキストファイルをコンパイラにD&Dして、コンパイルボタンを押します。blueMSXのディレクトリにSDTファイルが出力されました。
blueMSXを起動し、sc ファイル名と入力します。

ダイレクトモードでのクイックセーブ
この時ファイル名を入力した時点で、クイックセーブを行うのがこの後のデバッグのキモです。こうすることで、以後クイックロードを行うとファイル名入力まで済んだ状態に一瞬で戻り、尚且つディレクトリの再読み込みが行われるので新しく出力したSDTファイルも反映されている状態になります。

プレイヤーモードでのクイックセーブ
ダイレクトモードのクイックセーブと同様にプレイヤーモードでも可能です。この場合scだけを入力し、まずプレイヤーモードを立ち上げます。.DIRファイルが無いので@キーを押して作成し、曲一覧を表示し、目的の曲にカーソルを合わせた状態でクイックセーブとなります。

セーブポイントをダイレクトモードで行うか、プレイヤーモードで行うかは以下の違いから決めると良いかも知れません。
ダイレクトモードの場合: 曲の負荷チェックができる。blueMSX上で何故かDIRファイルを新規作成できなくなっても演奏は可能。
プレイヤーモードの場合: チャンネルごとの音量変更、ミュートができる。FM音源では音色エディタが使える。セーブポイントまで少し手間がかかる。
演奏チェック
再生して演奏をチェックしてみます。演奏が一本調子で同じ音が全て繋がって聞こえてしまいました。波形を見てみるとこのようになっています。

PSGやSCCのような音源は終始同じ波形を一定音量で繰り返すだけなので、同じ音階の音を連続で演奏すると、前後が繋がって切れ目が分からなくなってしまいます。1音の発音に何かしらの変化を付け、音の境目を分かるようにしなければなりません。今回は音量を次第に減衰させるボリュームエンベロープを適用してみます。
まずはボリュームエンベロープの定義を作成します。
@15,1 : -1,3
]
定義を使うために名前が必要です。"at00"としました。
音を発音するとまず最初に@15,1が実行されます。@が付くので絶対値指定でボリューム値15(最大)の指定になります。,1の部分が継続する時間を表し、@15を1クロック(約1/60秒)維持する、ということになります。
次の:は、ループポイントです。定義データが終わりに達した時、ここに戻ってきます。その次の-1は@が付かないので相対指定となり、エンベロープのボリュームを-1することになります。先程15を指定したので、14となりそれを3クロック維持します。
定義はそれで終わりなので、3クロック経ったらループポイントに戻り、また-1,3が実行されます。次は13、そしてその次は12…と3クロックごとに1ずつ音量が下がる定義です。
波形として表すと下の画像のようになります。v15の音が消えるのに0.7秒程掛かる減衰になりました。

捕捉: エンベロープのボリューム値とvコマンドのボリューム値について
音源のハードウェアはボリューム値を0~15で受け付けるとします(音源によって違います)。MML上でv13として適用したエンベロープのボリューム値が@15となった場合どのような値がハードウェアに書き込まれるのか、とういう話です。
各ボリューム値を区別するために名前を付けるとすれば、MMLで指定するvコマンドはチャンネルボリューム(cv)、エンベロープでの指定はエンベロープボリューム(ev)、そしてプレイヤー上でコントロールするボリュームがマスターボリューム(mv)となります。
ボリューム値では15からの差分を算出しています。@15とした場合差分は0で、@10なら5となります。
それぞれ15からの差分を算出し、それらの合計を15から引いてハードウェアに書き込む値となります。
例えばプレイヤー上で最大音量(mv=0)で、v13(cv=2)とした場合、エンベロープが@12(ev=3)ならば、15-0-2-3で、最終的に出力される値は10となるわけです。
マスターボリュームはプレイヤーのボリュームなので、あまり考える必要はありません。MML上でv13、エンベロープが@15なら13が出力、@12なら10が出力されるということを考えて、MMLを書きます。
シーケンス部の変更
定義適用のためシーケンス部分も変更します。
@v"at00"を入れると、ボリュームエンベロープ定義"at00"が適用されます。
既にコンパイラにはMMLファイルを読み込ませているので、テキストファイルを上書き保存後、コンパイルボタンで直ぐにコンパイルできます。
blueMSXの方もクイックロードで準備万端、キーを1回押すだけです。途中の読み込みすらも長く感じれば、blueMSXの実行速度を目一杯上げても良いかも知れません。音が鳴れば実行速度を元に戻し、改めてスペースキーを押せば最初から演奏されます。
さて、ボリュームエンベロープを適用してみましたが、まだ減衰が緩やかすぎて音の切れ目が分かり難い感じです(特に16分音符が連続する部分)。

定義の方を少し変更します。-1のクロックを3から1にして、変化を速くしてみました。
@15,1 : -1,1
]
コンパイル、blueMSX読み込みを手早く済ませ聞いてみます。音の途切れはしっかり分かるようになりました。

ボリュームエンベロープの改良
ボリュームエンベロープにより、1音1音切り離すことができましたが、原曲では1音1音減衰するものの完全には消音しないようです。ボリュームエンベロープを改良します。
@15,1 -1,1 -1,1 -1,1 -1,1 -1,1 -1,1 -1,1
]
ループ指定が無くなりました。@15から1ずつ下がり、8になった時にエンベロープ変化は終了します。音は終了した状態を維持するので、以下のような波形になります。

感じが出てきました。しかし何かのっぺりとした印象を受けます。これは8まで下がったエンベロープが次の音まで全くそのままであるところから来ているようです。ピアノのような楽器では次の音を発音する時、次の音のちょっと手前で一旦鍵盤から指を離して改めて押し直す動作をします。今度はそれを真似てみます(別にピアノを再現したいということではありませんが)。
q指定を使う
次の音のちょっと手前で指を離すというのは、そこから音が減衰するということです。
ボリュームエンベロープの変更で、クロックを調整して次の音の手前で減衰する定義を作るとすると、4分音符用、8分音符用というように、音長ごとに合わせた定義が必要になったり音長からクロックに換算したりと作業が大変です。
そこでqコマンドを使い、1つの音をq1時間、q2時間というように分けます。q2用のエンベロープを作成すれば音長に応じて自動でエンベロープの切り換えが可能です。
まずq2用のエンベロープを作成します。
: -1,1
]
q1用のエンベロープボリューム値を引き継ぎたいので相対指定のみとし、単純に毎クロック-1していくエンベロープです。マイナスしていった結果0以下になった場合は、0のままとなります。
次にシーケンス部分です。qコマンドでq1時間の割合を指定します。1音の長さを8としてどれくらいをq1の時間とするかの指定です。
q1の時間は6としたので、残り2でq2時間になり、q2用のボリュームエンベロープが適用されます。q2用のボリュームエンベロープも@v"at00","at01"として"at01"を指定しておきます。以下が再生した時の波形です。

次の音の手前で減衰しているのが分かるかと思います。

少し拡大して、1音のq1時間、q2時間に線を入れてみました。確かにq2時間になるとエンベロープが変更されています。短い音の方は、q1時間のエンベロープの減衰が終わらないままに、q2時間のエンベロープになっているので、平坦な部分がなくただの減衰音のように見えてしまっています。
音を聞いた感じでは、かなり自然な感じになりました。このように、qコマンドを利用すると、音長にとらわれずにエンベロープを使うことができます。
マクロの使用
ここまでシーケンス部分にMMLを直接記述していましたが、基本的にはマクロを使う方が後からの変更などに対応しやすくなるため便利です。ここまで記述したものをマクロにしてみます。
"q6 @s"sin" @v"at00","at01" o6 l8 ff16f16eecc<a4 b16>c16<b16a16faf2"]
s1=@all_k3 v15 /"ma0"
ここでのマクロとはある種の変数、入れ物です。コンパイル時、呼び出し部分にその内容が展開されます。
定義は名前と内容を""で囲みます。呼び出しは/"マクロ名"となります。使いまわしたい部分をマクロにすると効果的です。
上記の場合、@all_k3は全チャンネルに対するコマンドなので全体で1つあれば良く、逆に複数箇所に存在するとバグの元になるのでマクロから外しています。ボリュームを外しているのは、次の解説で他のチャンネルでボリュームだけ変更して同じ内容を演奏することを想定したため、このようにしました。
マクロ利用例:エコー
基本的なエコーの表現は、複数のチャンネルを使い、少し小さい音で同じフレーズを遅れて演奏するというものです。こういう処理をしたい時、マクロを使っていると楽になります。SCMDでは実機を使わずにPCのテキストエディタでソースを書くので、同じ内容ならコピペでも楽に記述はできますが、後から修正が必要になった場合にマクロなら定義部分の修正で済みます。
s2=v12 %8 /"ma0"
s1ではv15で演奏し、s2ではv12で演奏しています。%8は次の音に8クロック加算するコマンドで、以降s2チャンネルは8クロックずれた状態で演奏することになります。
音量を下げて遅らせるチャンネルをずらして増やせばもっとエコー感は増しますが、使用可能なチャンネルはそんなに多くないので、どこまでこのような効果用にチャンネルを使うのかはMML打ち込み時の試行錯誤するポイントにもなります。
※注意点としては、ループしない曲の場合はずれたままで終わらせても良いのですが、ループ時には全チャンネルの足並みを揃えるので、その時にはずらした分を戻さないとループ地点でもたつくような演奏になってしまいます。
マクロ利用例:デチューン
デチューンもマクロが活躍する記述箇所になります。
デチューンとは、少し周波数をずらしてフレーズを同時に演奏すると響きが良くなったりするテクニックで、多くずらすと不協和音に聞こえたり逆の場合は効果が薄かったりと、こちらも試行錯誤のポイントになります。
s2=v15 z2 /"ma0"
z2としたので、SCCの周波数を設定するレジスタに書き込む値がs2チャンネルだけ+2されます。
とりあえず曲の終わりまで作成
エコーとデチューンは今回は使わずに最後まで打ち込んでみます。

コンパイル後には、画像のように各チャンネルの総クロック数が表示されます(テンポ合わせ処理、%や**コマンドがあればそこで一旦0になり、再びカウントされます)。この値が±1以内であれば音長に関しての打ち込みミスは無いと思われます。2以上離れているものがあれば、どこかで打ち込みミスがある可能性を示唆しています。
この曲はループするので、各チャンネルにループポイントを設けます。
s2= ** v15 /"mb0" v-6 @s"squ50"
ループポイント**を配置しました。記述場所は全ての音長が揃う位置でないとスムーズな演奏になりません。発音を伴わないコマンドは音長に関係しないので、上記のMMLではどちらも演奏の最初に設定されています。
作成したMMLソースは ここ に置いておきます。参考にどうぞ。音色、ボリュームエンベロープ等は、少し調整してあります。