Tiny Music Compiler


img
自分用に作った音源ドライバを公開します。
音源は他機種と遜色ないので頑張ればP6でも立派な曲が鳴らせるはず…。





■ MMLコンパイラ

・Tiny Music Compiler 本体 tmc_20151127.zip (2015.11.27版)
 .NET Framework が必要です。Windows Update で入手できます。

・概 略

・PC-6001/mkII/6601/SR 向け音源ドライバです。FM/PSG とおまけで SCC とか鳴らせます。
・1 つの物理チャンネルに複数のトラックを割り当てられます。上位のトラックが休符の時に下位のトラックの音が鳴ります。
・効果音モードを使用した FM 第 3 チャンネルのサブトラックが使えます。
・PSG で非矩形波発音ができます。
・PSG/SCC では音程*1,音量*2の独立したモジュレーションが可能。
・FM では音程*1,音量*1,音量モジュレーションはオペレータ指定可能。
・FM 第 3チャンネルで OPM の DT2 をエミュレート。
・PSG 第 2,3チャンネルを使用した PCM 再生機能 (SR+TMCF 環境のみ)。
・おまけの KSS/hoot 用ドライバ添付で作業効率up.

添付のリファレンスドライバでは上記仕様にいくつか制限があります。
(上位トラックは PSG の M のみ、FM3 サブトラックは N の 1 つのみ、PCM 再生不可、mode5 専用仕様)

・PC-6001mk2SR/6601SR 専用簡易ファイラtmcf_20171108.zip (2017.11.08版)
 TMCF は SR 専用にドライバをカスタマイズし、簡易 OS 機能と合わせて実装したものです。UI からの曲選択や PCM 再生機能などが使えます。
 使い方は中の readme.txt 参照。


・使い方

MML で書かれたテキストファイルを用意し、コマンドプロンプトから以下のように入力します。

C:\TMC>tmc.bat 曲データ.txt 

エラー表示が無く無事にコンパイルが成功すれば sound.bin というファイルが生成されるはずです。
PC-6001VW をお使いの方は BASIC モード 5 (N60m/N66-BASIC) を指定して play.p6b をドラッグ&ドロップすることで演奏することが出来ます。
FM 音源を使用している曲の場合、FM音源カートリッジ使用オプションを ON にしておく必要があります。

曲オブジェクトは 16KB 程度までです。ドライバは $0100 以降にロードされ、曲オブジェクトはドライバの後に続けて配置されます。
この連続配置は便宜上のもので、曲オブジェクト自体はどこに置いてあってもかまいません。
de レジスタに曲オブジェクト開始アドレスを入れて xSDRV_SETUPを呼べばOKです(FM/PSG を使うときは FSDRV_SETUP と PSDRV_SETUP を両方呼ぶ)。

BASIC との同居も可能なのですが、説明が冗長な割に誰も求めていないと思うので割愛します。
3つのドライバで重複する部分が多いのですが、混乱を避けるためにそのままにしてあります。



■ MMLマニュアル

大文字、小文字は基本的に区別しますので注意してください。
p v @ 等、最初にチャンネルの初期化をしないと音が出ません。

制御コマンド
'A(〜N) MML
トラック指定 PSG FM SCC
行頭に記述します。A〜N がそれぞれトラック番号の指定になります。
この後に続けて MML を書くことで、各トラックにコマンドを発行します。
付属のドライバの場合、ABCN=FM DEFM=PSG GHIJK=SCC で使用してください。

どのトラックがどの音源チャンネルかは #PSG #OPN #SCC の各コマンドで変更できますが、
トラックを増やす場合、ドライバソースの変更と再コンパイルが必要になります。
P6の能力的にあまり多くのトラックを扱うと重くなるのでデフォルトでは制限をかけています。

トラック指定を複数にすることで、同じMMLを同時に複数トラックに登録できます。
(別々のトラックで同じ番号のマクロを使用することはできませんので注意してください)
<例>
'A cde → トラック A (FM音源ch.1) にドレミの発音コマンド
'AB cde → トラック A と B に同時にドレミの発音コマンド
;
(セミコロン)
注釈 PSG FM SCC
コメントです。コンパイラはこれ以降、改行まで解釈をスキップします。
<例>
;コメント。
'A cde ; fgab → ファソラシ(fgab)の部分は無視される。
/*〜*/コンパイルスキップ PSG FM SCC
行頭に記述します。
/*〜*/の間の全てのMMLはスキップされます。
;セミコロンと/*は;セミコロンの方が優先度が高いので ;/* または ;*/と書いた場合
コンパイルスキップは有効になりません。
<例>
'A cde
/*
'A fga	→ ここは読み飛ばされます
*/
'A bcd
#M番号 MMLマクロ登録 PSG FM SCC
行頭に記述します。番号には 0〜999 が指定できます。
ここで登録したマクロを MML に記述することで登録内容を取り込む事ができ、
MMLを簡略化できます。
同じ番号のマクロを登録すると、後で登録した内容は追加扱いになります。

マクロの中でマクロを呼び出すことは出来ません。
あるトラックで使ったマクロは、そのトラック用として登録される為、別のトラックで使い回すことが出来ません。
同じ MML を別の番号で登録して使ってください。
<例>
#M0 fg ファソ(fg)を登録しておく。
'A cde M0 ab → ドレミファソラシになる。
#M0 ab 追加登録なので、ファソラシ(fgab)の登録になる。
'A cde M0   →ドレミファソラシになる。
#MKILL 番号
#MKILLALL
マクロ削除 PSG FM SCC
行頭に記述します。#MKILLの番号には 0〜999 が指定できます。
指定した番号のマクロを削除します。
#MKILLALLは今まで登録した全てのマクロを削除します。
別のトラックで番号を変えずに同じMMLを書きたい場合などに便利です。
<例>
#M0 fg
'A cde M0 ab → ドレミファソになる。
#MKILL 0
#M0 ab 新規登録
'B cde M0   →ドレミラシになる。
'@S番号 {xx,xx,・・・,xx}

'@S番号 {xxxxxx・・・}
SCCの音色登録 PSG FM SCC
行頭に記述します。番号には 0〜255 が指定できます。
SCCの波形を定義できます。
{ }内に 2桁16進数をカンマ区切り、あるいはスペース区切りで32個並べます。
または、区切りなしで16進数を64個並べてもかまいません。

波形は最低一つ登録して、それを使って発音しないと SCCは鳴りません。

16進数のアルファベット部分は大文字でも小文字でもかまいません。 da = DA
カンマ/スペース区切りの場合は2桁でなく1桁でもかまいません。 01,A9 = 1,A9
<例>
'@S1 {305050300000104060706030F0E0E000202010C0A090A0C00000D0B0B0D00000}

'G @1 v15 cde → @S1で登録した音色でドレミ
'@F番号 { ・・・ }FM音色登録 PSG FM SCC
行頭に記述します。番号には 0〜255 が指定できます。
FM音源の波形を定義できます。書式は以下の通り。

コメント・空白行は読み飛ばします。
DTは-3〜3でも0〜7でもかまいません。
DT2 は FM3 拡張モードを使用したときのみ適用されます。
FM3 でも拡張モードを使用していないときは無視されます。
DT2の箇所はSSG-EGと兼用です。0〜3がDT2、8〜15がSSG-EGです。

音色は最低一つ登録して、それを使って発音しないと FMは鳴りません。
<例>
;     ALG FB		FM Tone Form
'@F0  { 0, 0
;      AR DR SR RR SL  TL KS ML DT DT2(SSG-EG)
        0, 0, 0, 0, 0,  0, 0, 0, 0, 0
        0, 0, 0, 0, 0,  0, 0, 0, 0, 0
        0, 0, 0, 0, 0,  0, 0, 0, 0, 0
        0, 0, 0, 0, 0,  0, 0, 0, 0, 0 }

'C @0 cde → DT2は無視
'C @0 X%1111 cde →DT2が設定されていればDT2エミュレーションを行う
#VOLTL { ・・・ }音量テーブル設定 PSG FM SCC
行頭に記述します。 FM音源のvで指定する音量とキャリアオペレータに設定する
TL=トータルレベルの対応を設定します。
V設定値と同じで、数値は0(小さい)〜127(大きい)です。

デフォルトの設定値を変えたいとき以外は設定する必要はありません。
17段階なので、v0〜v15の16段階しか使わない場合は最後にダミーの数値を入れてください。
<例>
#VOLTL { 85, 87, 90, 93, 95, 98, 101, 103, 106, 109, 111, 114, 117, 119, 122, 125, 127 }
デフォルトの音量テーブルは↑の通り
#OCTAVE-REV オクターブ反転 PSG FM SCC
行頭に記述します。 MML 中で使われるオクターブ上下指定「>」「<」の役割がそれぞれ逆になります。
> → オクターブ下げになります。
< → オクターブ上げになります。
<例>

#PCMLOAD 数値
,"ファイル名"
PCM登録 PSG FM SCC
行頭に記述します。
数値の番号に、指定したファイル名の PCM 音声を登録します。
数値は 0-255、ファイル名は 8+3 形式(ファイル名8文字+拡張子3文字)で指定します。
ここで登録した番号を #PCMSET で音程と紐付けます。

PCM ファイルは 8bit 8192Hz のものに限ります。

この音源ドライバとは別の、独立したファイルシステムに依存してロードするので
今のところ SR 環境 + PC-6006SR 相当の 64KB 拡張 RAM + 簡易ファイラ(TMCF)環境でのみ鳴らせます。

ロード可能なサイズは全 PCM ファイル合計で 64KB までです。
最大 8 秒間の PCM ファイルが入ります。

このコマンド指定は PCM ファイルを曲データバイナリに取り込むわけではなく、
単にファイル名を記録しておくだけなので、演奏の際には PCM ファイル実体が
ディスクに書き込まれている必要があります。

TMCF の場合、PCM ファイルは曲データの書き込みと同様に D88TOOL を使って書き込みます。

PCM は PSG の第2,3チャンネルを使って再生します。音質は悪いです。

#PCMSET と p コマンドも参照のこと。
<例>
#PCMLOAD 0,"DRUM.PCM" ← PCM 番号 0 番として"DRUM.PCM"を登録
#PCMLOAD 1,"VOICE.PCM" ← PCM 番号 1 番として"VOICE.PCM"を登録

>d88tool TMCF.D88 DRUM.PCM -ua  ← ディスクイメージへの書き込み

>d88tool TMCF.D88 D:\SONG\PCMDATA\*.PCM -ua
ワイルドカードを使うと一括して書き込めて便利です。

#PCMSET "音程",数値1
,数値2,数値3
,数値4,数値5
PCM音程割り付け PSG FM SCC
行頭に記述します。
#PCMLOAD で登録した PCM ファイルを音程に割り付けます。
PSG の第2,3チャンネルの MML で p5(PCM再生モード)が指定されているときに、
cdefgab の音程コマンドでどの PCM を再生するかを設定します。

※ 割り付けた音程で鳴るわけではありません。PCM の再生速度変更には未対応。

数値1 は #PCMLOAD で登録した PCM ファイルの番号です。
異なる音程コマンド(c〜b)に同じファイル(DRUM.PCM等)を割り付けることもできます。

数値2 は開始位置です。通常は 0 (先頭から再生)を指定します。
数値3 は長さです。0 を指定すると PCM ファイルの最後まで再生します。
PCM は q/Q が効かないので、必要な場合は別の音程コマンドに違う長さで登録しておく方法で代用します。

数値4,5 は PC88 の ADPCM 用(Delta/Repeat) なので 0 にしておいてください。

PCM の再生は PSG の第2,3 チャンネルを同時に占有します。
通常の PSG 発音 → PCM再生 → 通常の PSG という具合に曲中に p コマンドで切り替えて使用できますが、
その際、第2,3 チャンネルが必ず同じタイミングで PCM 発音を行うようにしてください。
もしくは第2チャンネルを全く使わないでおいてもかまいません。

#PCMLOAD および p コマンドも参照のこと。
<例>
;        note num start length delta repeat
#PCMSET "o4c"  ,0 ,0    ,0     ,0    ,0  ← o4c  を PCM 番号0番の再生に割り付ける。
#PCMSET "o4c+" ,1 ,0    ,0     ,0    ,0  ← o4c+ を PCM 番号1番の再生に割り付ける。

'EF o4 p5 c8 r8  ← c8 で PCM 0 番を先頭から八分音符で再生する

'E p1 l4 rrr  ← 'F での通常の発音があるので 'E で休符を入れて
'F p1 l4 cde    PCM 発音タイミングを合わせる
'EF p5 c8 p1
#PSG (A〜Z)PSGトラック登録 PSG FM SCC
行頭に記述します。PSGを使用する場合は必ず指定してください。
PSGとして使うトラックを指定します。
先頭から順にPSGの第1,2,3チャンネルの順で割り当てられ3つを超えたら再び1,2,3となります。
複数のトラックを持つと割り込み演奏機能が使用できます。
","カンマがある場合は、物理チャンネルを一つ飛ばします。
" "スペースは無視します。

付属ドライバのデフォルトは DEFM 固定なので変更は不可です。
MはPSG第1チャンネルの割り込み演奏用です。
<例>
#PSG ABCM → A=PSG第1チャンネル B=PSG第2チャンネル C=PSG第3チャンネル
             M=PSG第1チャンネル
#PSG ABC,,M → M=PSG第3チャンネルになる
#SCC (A〜Z)SCCトラック登録 PSG FM SCC
行頭に記述します。SCCを使用する場合は必ず指定してください。
SCCとして使うトラックを指定します。
先頭から順にSCCの第1,2,3,4,5チャンネルの順で割り当てられ5つを超えたら再び1,2,3,4,5となります。
複数のトラックを持つと割り込み演奏機能が使用できます。
","カンマがある場合は、物理チャンネルを一つ飛ばします。
" "スペースは無視します。

付属ドライバのデフォルトでは GHIJK 固定なので変更は不可です。
<例>
#SCC GHIJK → G=SCC第1チャンネル H=SCC第2チャンネル I=SCC第3チャンネル
              J=SCC第4チャンネル K=SCC第5チャンネル
#OPN (A〜Z)FMトラック登録 PSG FM SCC
行頭に記述します。FMを使用する場合は必ず指定してください。
FMとして使うトラックを指定します。
先頭から順にFMの第1,2,3チャンネルの順で割り当てられ3つを超えたら再び1,2,3となります。
複数のトラックを持つと割り込み演奏機能が使用できます。
","カンマがある場合は、物理チャンネルを一つ飛ばします。
" "スペースは無視します。

付属のドライバのデフォルトでは ABC,,N固定なので変更は不可です。
NはFM第3チャンネルで効果音モードを使ったときの別トラックになります。
<例>
#OPN ABC → A=FM第1チャンネル B=FM第2チャンネル C=FM第3チャンネル
#OPN ABC,,N N=FM第3チャンネルの効果音モード用のトラックになる
#INCLUDE ファイル取り込み PSG FM SCC
行頭に記述します。
他のファイルを取り込みます。音色などを記述したファイルを別に用意しておけば
毎回音色を記述する手間が省けます。
ファイルの中身について全くチェックしないので、十分注意してください。
<例>
#include <tone.txt>
#TITLE
#AUTHOR
#COPYRIGHT
曲情報 PSG FM SCC
行頭に記述します。
曲の情報を埋め込みます。
情報(漢字・罫線なども)は出来るだけP6のキャラクタに変換するようになっていますが
事前に変換可能か確認するようにした方が無難です。
濁点半濁点などは分離して書かなくてもOKです。「た゛」と書かずに「だ」でOK。
ここで埋め込んだ情報をどう利用するかはアプリケーション側の判断なので
文字数や順序そのものには特に意味はありません。
<例>
#TITLE "songname"
MML コマンド
cdefgab(+/-)数値
r数値
音程・音長,休符 PSG FM SCC
音程を指定します。cdefgabがそれぞれドレミファソラシです。
+をつけると半音上がり-をつけると半音下がります。
非矩形波モード時は音程によっては音痴になるので注意してください。

音程の後の数値は音長を表します。4が4分音符・16が16分音符などです。
音長を省略すると「l」(小文字のエル)コマンドで指定した数値が使用されます。

192,96,64,48,32,24,16,12,8,6,4,3,2,1 (分音符) が指定できます。

付点も指定でき「.」(ピリオド)をつけることで前の音長の半分を追加します。
複数の付点も可ですが、前の音長の半分が整数でないとエラーになります。

音長は「n」に続けて指定すると、ステップ数で直接指定できます。
n指定の時は1〜999までの数値が指定できます。
n指定時も付点はつけられます。
※ステップ数=何フレームその音を持続させるか。
 1ステップ=ドライバの発音できる最短音長。n192が全音符でn48が4分音符です。

rは休符指定です。音長は音程と同じ。
<例>
'A c+1.. → c+1c+2c+4と同じ音長になります。音程はドの半音上
'A c+n192.. → 上と同じ音長です。192ステップ+96ステップ+48ステップ
'A c64. → 64分音符(=n3)の半分は整数でないので付点エラーになります。
[cmd:$00-$5F] [length] : 音程
[cmd:$82] [length] : 休符
^数値
^-数値
タイ PSG FM SCC
音長を加算または減算します。
音を延ばしたい/縮めたい時に使います。
指定できる音長は音符のものと同じです。

数値の部分をマイナスにすると、音長を足すのではなく引いて処理します。
引く数値にも「n数値」が使えます。
引いた結果音長が0以下になるとエラーが出ます。
<例>
'A c1^1^1. → 全音符3つと二分音符一つ分の長さで発音します。
'A c1^n384^n96 → 上と同じ音長です。
'A cn192^-4 → n192(全音符)から四分音符分の数値を引いて付点二分音符で発音。
[cmd:$81] [length]
&スラー PSG FM SCC
キーオンしたまま次のコマンドに繋げます。
&の後の音程系コマンドはキーオンせずに発音します。
&は音程系コマンドの直後に置いてください。でないとエラーになります。
<例>
'D s0m10000 c8&d1 → エンベロープの途中から音程が変わります
'D c4&p1d → Ok
'D c4p1&d → 音程コマンドの直後でないため NG
[cmd:$80]
o数値
<
>
オクターブ・上下 PSG FM SCC
音程のオクターブを変えます。数値は1〜8までです。
「>」で現在のオクターブを一つ上げ、「<」で一つ下げます。
数値を指定しないとo4になります。
発音可能域を超えた音程(o1cより下、o8bより上)はエラーが出ます。

#OCTAVE-REV コマンドを指定することで役割が逆になります。
<例>
'A o4cdefgab>c → ドレミファソラシド
'A o1c- → エラーが出ます
'A o6>>>c → o9になってしまうのでエラーが出ます
v数値
v+数値
v-数値
音量・上下 PSG FM SCC
音量を変えます。数値はPSG/SCCが0〜15まで、FMは0〜16。
「v+数値」で現在のオクターブを数値分上げ、「v-数値」で数値分下げます。
vコマンドは数値を省略するとv8になります。
v+,v-コマンドは数値を省略すると、それぞれv+1/v-1と見なされます。

vコマンドを使用すると非矩形波モードは解除されます。

FM音源でのvとキャリアTLに与える値の関係は以下の通り。
[ (0)85, 87, 90, 93, 95, 98, 101, 103, 106, 109, 111, 114, 117, 119, 122, 125, 127(16)]
<例>
'D v15c → 最大音量でド
'D v10 v+5 c → v15cと同じ
[cmd:$83] [volume] : PSG/SCCは0-15 FMは0-127(TLに加算する値)
V数値
V+数値
V-数値
FM音量・上下 PSG FM SCC
FMの音量を変えます。数値は0〜127までです。
Vコマンドは数値を省略するとV117になります。
設定値はV0(小さい)〜V127(大きい)です。

V+,V-コマンドは数値を省略すると、それぞれV+1/V-1と見なされます。
+ または - に続けて数値を指定すると現在の音量から数値分を加算/減算します。
<例>
'A V127c → 最大音量でド
[cmd:$83] [volume] : 0-127(キャリアTLに加算する値)
@v数値
@v-数値
マスターボリューム PSG FM SCC
音量に加算する値を指定します。数値は-127〜127までです。
以後の MML に指定されている音量系コマンド全てに、指定した値を加減算します。

PSG/SCC は加減算後の数値は 0〜15 に補正されます。
FM は加減算後の数値は 0〜127 に補正されます。
<例>
'A @v127 V100 c → 最大音量でド
l 数値基準音長 PSG FM SCC
小文字のエルです。音程の後の数値を省略した時の音長を指定します。
数値省略時はl4、つまり四分音符になります。
音程と同じく、 「n数値」での指定や「^」タイコマンドを使った指定も出来ます。
付点も使えます。
<例>
'A l4cde → 4分音符でドレミ c4d4e4 と同じ。
'A l4c l8de → 4分音符でド 8分音符でレミ c4d8e8 と同じ。
t数値テンポ PSG FM SCC
テンポを指定します。数値は1〜65535で、省略時は256になります。
256を基準として、512で2倍速、128で半分の速さになります。

計算式は、以下の通りです。デフォルトがt256なので1分間に4分音符が75回鳴ります。
bpm = 75 * t / 256
t = 256 * bpm / 75

P6の処理能力依存なのであまり極端な数値は避けてください。
なお、「@y$F6,数値」でP6自体のタイマー設定を変更できます。デフォルトは32になっています。
<例>
'A t256 c1 → デフォルトのテンポ 全音符の長さは約 192/60秒
[cmd:$84] [L] [H]
s数値エンベロープ形状 PSG FM SCC
ハードウェアエンベロープの形状です。数値は0〜15。
設定値はPSG3チャンネルで共有です。
エンベロープモードに入ります。以降の発音は指定したエンベロープで発音されます。
vで音量を指定するとエンベロープモード解除。

p4を指定して、非矩形波モードで発音するためには
s でエンベロープ形状を設定する必要があります。
<例>
'D s8 m10000 c1
[cmd:$85] [shape] : 0-15
m数値エンベロープ周期 PSG FM SCC
ハードウェアエンベロープの周期です。数値は0〜65535。
設定値はPSG3チャンネルで共有です。
mだけではエンベロープモードにはなりません。sを指定してください。

mコマンドを使うと非矩形波モードは解除になります。
<例>
'D s8 m10000 c1
[cmd:$86] [L] [H]
w数値/td>ノイズ周波数 PSG FM SCC
ノイズ周波数の値です。数値は0〜31。
設定値はPSG3チャンネルで共有です。
ノイズモードに入るには p2 または p3 を指定してください。
<例>
'D p2 w0 v15 c1
[cmd:$87] [noise] : 0-31 (+0x80)
現在のミキサの設定を見て、ノイズ発声ありならば最上位ビットON
p数値ミキシング設定・非矩形波・PCM モード指定 PSG FM SCC
PSGのトーン/ノイズのミキシングを設定します。
p0 : トーン・ノイズは両方ともオフになります。発音は全て無効化。
p1 : トーンのみオン。
p2 : ノイズのみオン。
p3 : トーン・ノイズ両方ともオン。
p4 : 非矩形波モード。
p5 : PCM 再生モード。

非矩形波モードではエンベロープ波形を指定する必要があります。
s10/s14 が三角波 s8/s12がノコギリ波です。
エンベロープジェネレータはPSG3チャンネルで共有している1つしかないので、
非矩形波が出せるチャンネルも1つと考えてください。

非矩形波モードをやめる場合、音量「v」でエンベロープ指定を
解除しないと正常な発音はできません。

SCCでは単純に p0=オフ(発音無効) p1=オン(発音有効)です。
ただし、現状ドライバ側でこの値を見ていないので意味はありません。

p5 を PSG 第2,3チャンネルで指定すると PCM 再生モードになります。
cdefgab は #PCMSET で登録した PCM 音声の再生になります。
<例>
'D v15 p3 c1 → ノイズとトーンが一緒に出る。
'D p4 s10 cdef → 非矩形波モードでドレミファ
[cmd:$88] [mixer] : p0-3の場合、ビット配置 [xxNNNTTT] x=0 N=ノイズ T=トーン
bit0/3=ch1 bit1/4=ch2 bit 2/5=ch3 N/T共に 0=使用 1=未使用。

p4の場合は0x80
%数値
%-数値
デチューン PSG FM SCC
デチューン。数値は-128〜127まで。
本来の音程周波数値に加算する値を指定します。
負の数値で音程が下がり正の数値で音程が上がります。
各音源の発音域から外れてもエラーは出ませんが出音はおかしくなります。
<例>
'A c1 %5 c1 → 後のドは5ポイント高い音が出る
[cmd:$89] [L] [H] PSG/SCCは符号を逆転する
i数値トランスポーズ PSG FM SCC
トランスポーズ。数値は-84〜84
音階を指定数値分だけずらして出力します。
12を指定するとちょうど1オクターブずれます。
<例>
'A i1 cde  → 実際の出力は c+d+f になる。
y数値,数値
@y数値,数値
Y数値,数値
レジスタ・アドレス直接書き込み PSG FM SCC
音源レジスタ、I/Oポート、アドレスに値を書き込みます。
書き込む音源レジスタは音源デバイスによって役割が異なります。
@yで指定出来るI/Oポートは本体(PC-6001)のI/Oポートです。
Yで指定出来るアドレスは本体(PC-6001)のアドレスです。

いずれの数値指定も$を付けることで16進数指定ができます。
16進数のアルファベットは大文字のみです。音符とまぎらわしいので。
I/Oポート($F6)でタイマの設定を変えることでテンポを変えたり出来ます。
<例>
'A y7,56 → 音源レジスタ7に56を書き込みます。
'A @y$A0,7 @y$A1,$38 → 上と同じ。I/OポートのPSGレジスタラッチと出力。
'A Y$8010,$9C → $8010に$9Cを書き込み
[cmd:$94] [Reg] [Data] : y
[cmd:$93] [Port] [Data] : @y
[cmd:$95] [L][H] [Data] : Y
L曲ループポイント PSG FM SCC
曲が最後まで演奏されたとき、このコマンドで指定したポイントに戻ります。
指定しない場合はループしません。
<例>
'A cd L efg → cd efg efg efg …
[cmd:$8C] [L] [H] : Hのアドレスからいくつ戻るか
M数値マクロ呼び出し PSG FM SCC
#M で指定したマクロを呼び出します。数値は登録したマクロ番号。
登録していない番号を指定するとエラーになります。

マクロの中でマクロを呼び出すことは出来ません。
あるトラックで使ったマクロは、そのトラック用として登録される為別のトラックで使い回すことが出来ません。
<例>
#M0 ef
'A cd M0 gab → cdefgab
マクロが初回に使われたときは、マクロのMMLをそのままコピーしておき、
末尾に Macro Pop を付加しておく。2回目からはMacro Pushを使う。
[cmd:$8A] [L] [H] : Macro Push [H]のアドレスを基準にいくつ戻るか。
ドライバは[H]の次のアドレスを専用スタックに積んでおく。
[cmd:$8B] : Macro pop スタックにアドレスが積んでなければスルー。
積んであったらそのアドレスに戻る。
[数値 : ]ループ PSG FM SCC
繰り返しコマンドです。数値は2〜255まで。
数値を省略すると2になります。
「:」以降はループの最終回にスキップします。
多重ループも8重まで可能です。
ループ内では相対変化系のコマンドが意図した動作をしない場合があります。
<例>
'A [2 cde ] → cdecde と同じ。
'A [3 cd : ef] → cdef cdef cd と同じ。最終回は ef をスキップする。
'A [2c [3d] e] → c ddd e c ddd e と同じ。

'A o3 [3>cde] → o4cde o4cde o4cde となる。
'A v5 [4 cv-1] → v5c v4ccc(だんだん小さくなっていかない)
[cmd:$91] [cnt] cnt>=2の時 "[" cnt=ループ回数。
[cmd:$91] [cnt] [L] [H] dir=0の時 "]" [H]のアドレスに[H][L]を足したアドレスに戻る。
[cmd:$91] [cnt] [L] [H] dir=1の時 ":" ループ最終回に[H]のアドレスに[H][L]を足したアドレスに飛ぶ。
zp数値1,数値2,数値3,数値4ピッチモジュレーション PSG FM SCC
数値1 : 速度 1〜255
数値2 : 増減値 -32768〜32767
数値3 : 深さ 1〜127
数値4 : ディレイ 0〜255

三角波/矩形波LFOの効果を音程に適用します。

速度で指定したステップ毎に効果を適用します。
増減値を現在の周波数値に加算します。正の数値で音程が上がり負で下がります。
増減値を深さで指定した回数分累積加算した後、増減値の符号を反転します。
ディレイは、指定したステップ分だけ効果適用を待機します。
数値を全て省略してzpとだけ書くとオフになります。
深さ=1の時は矩形波になります。
<例>
'D v15p1 L zp1,2,3,48 c1 d1 e1 r
値が全て0の時はオフ。
[cmd:$8D] [speed] [L][H] [depth] [delay]
[L][H]は増減値。PSG/SCCは正負逆転しておく。
zv数値1,数値2,数値3,数値4音量モジュレーション PSG FM SCC
≪PSG/SCC≫
数値1 : Attack Legnth 1〜255
数値2 : Decay Depth -15〜15
数値3 : Susutain Rate 0〜255
数値4 : Release Rate 0〜255

ADSR型のエンベロープを音量に適用します。zmとの併用も可能です。
このページの一番下参照のこと。

Attack Lengthは開始音量を何ステップ持続させるか指定します。
Decay DepthでAttack Length経過後、開始音量から増減する相対音量を指定します。
Sustain Rateで指定したステップ毎にDecay Depth適用後の音量から-1されます。
Release Rateは、キーオフされた後に指定したステップ毎にその時点の音量から±1され、
目標音量に達するまで繰り返されます。目標音量はq/Qの第二パラメータで指定します。

キーオフのタイミングはゲートタイムコマンド(q/Q)で指定します。
RRが0の時はキーオフで即時無音になります。
音量モジュレーションを使用するとHWエンベロープ(s)は無効化されます。

≪FM≫
数値1 : 速度 1〜255
数値2 : 増減値 -127〜127
数値3 : 深さ 1〜255
数値4 : ディレイ 0〜255

三角波/矩形波LFOの効果を音量に適用します。

速度で指定したステップ毎に効果を適用します。
増減値を現在の音量に深さの回数分、累積加算します。
深さの回数分終了したら増減値の符号を反転します。
ディレイは、指定したステップ分だけ効果適用を待機します。
深さ=1の時は矩形波になります。

最終的な音量(キャリアTLに与えられる値)は
音色のTL(0〜127)+Vで指定した音量(0〜127)+zvでの変化(-127〜127)になります。
x(小文字)コマンドでzvの効果を適用するオペレータを指定出来ます。
音色設定直後のデフォルトではキャリアTLが対象ですがモジュレータTLに変更することが出来ます。

PSG/FM共に数値を全て省略してzvとだけ書くとオフになります。
<例>
'D v15p1 t256q15 L zv1,-3,0,5 l4 cde r
値が全て0の時はオフ。
[cmd:$8E] [Attack] [Decay] [Sustain] [Release] : PSG/SCC
[cmd:$8E] [speed] [Level] [depth] [delay] : FM
Level は TL に加算する値。正負は反転しておく。
zm数値1,数値2,数値3,数値4音量モジュレーション2 PSG FM SCC
数値1 : 速度 1〜255
数値2 : 増減値 -15〜15
数値3 : 深さ 1〜15
数値4 : ディレイ 0〜255

三角波/矩形波LFOの効果を音量に適用します。zvと併用が可能です。
このページの一番下参照のこと。

速度で指定したステップ毎に効果を適用します。
増減値をを現在の音量に加算します。
深さは増減値を指定した回数分だけ加算した後、増減値の符号を反転します。
ディレイは、指定したステップ分だけ効果適用を待機します。
深さ=1の時は矩形波になります。

数値を全て省略してzmとだけ書くとオフになります。
音量モジュレーション2を使用するとHWエンベロープ(s)は無効化されます。
<例>
'D v13p1 L zm3,1,1,5  c1 → v12とv14で周期的に発音します
値が全て0の時はオフ。
[cmd:$8F] [Speed] [L][H] [Depth] [Delay]
X数値コントロールオペレータ指定 PSG FM SCC
FM第3チャンネルと拡張トラック専用。
そのトラックでコントロールするオペレータを指定します。数値は0〜15まで。
$に続けて16進数での指定も出来ます。$0〜$F
%に続けて2進数での指定も出来ます。%0000〜%1111

オペレータ指定はビット3〜0がそれぞれ=Op4, Op3, Op2, Op1 の順です。
4231ではありません。

このコマンドを使うと効果音モードが起動し、FM第3チャンネルの4オペレータを
独立して操作できるようになります。
一旦効果音モードにすると戻れませんが、X%1111で通常モードと同じ状態で使えます。
処理は少し重くなりますが。

オペレータの重複使用などは、チェックしていません。
FM第3チャンネル、拡張トラックどちらで音色設定しても両方に適用されます。
両方同時に設定するのは無意味なのでおすすめしません。

逆に効果音モードのON/OFFはC,Nトラックで同時に行った方が良いです。
片方をX%1111にしたときはもう片方をX%0000にします。
<例>
'C v15@2 X%0011  ceg	→ オペレータ1,2 で発音する
'N v15   X%1100  egb	→ オペレータ3,4 で発音する 音色はいずれも @2
[cmd:$9A] [op] : オペレータは上位4bitにシフトしておく
x数値TL操作対象オペレータ指定 PSG FM SCC
音量操作コマンド(v,zv)で操作対象となるオペレータを指定します。数値は0〜15まで。
$に続けて16進数での指定も出来ます。$0〜$F
%に続けて2進数での指定も出来ます。%0000〜%1111

オペレータ指定はビット3〜0がそれぞれ=Op4, Op3, Op2, Op1 の順です。
4231ではありません。

音色をセットした直後はキャリアTLになっています。デフォルトが音量ということです。
キャリアTLはキーオン時に諸々の音量設定を反映した数値を書き込むことになっており、
それまでは不定です。前回書き込んだ値がそのまま残っています。
x コマンドの設定次第ではキャリアTLが意図した音量設定にならない場合があるので
注意してください。
<例>
'C @2 x%0101  ceg	→ アルゴリズム4,vコマンドでオペレータ1,3のTLを変更する
[cmd:$9B] [op] : オペレータは上位4bitにシフトしておく
q数値
q-数値1,数値2
ゲートタイム PSG FM SCC
ゲートタイムを指定します。0〜255
数値1はステップ数なので4分音符の場合48と指定します。音階の項目を参照。
符号がマイナスの場合音長が255未満でないと効果がありません。
q0で無効化。

キーオン時からカウントして、
数値1がプラスの場合、指定した数値をダウンカウントし0になったらキーオフします。
数値1がマイナスの場合、残り音長が指定した値になったらキーオフします(=後ろからカウント)。

キーオフ状態になると、zvエンベロープがリリース段階に入ります。

q にマイナスの数値1を設定している時、数値1>=音長にするとq=1に設定されます。
完全に無音には出来ません。

数値2は省略可でPSG/SCC専用です。FMも指定できますが意味はありません。
指定すると、ゲートタイム以降、現音量から数値2まで音量が上下して行きます。
「zv」でリリースレートを指定していない場合、即時数値2の音量になります。
従来は音量0に向かうor即時音量0であったのを目標値として持つことが出来るようになりました。
<例>
'D v15 l4 q-2 cde ↓
'D v15 cn46 rn2 dn46 rn2 en46 rn2 四分音符=48なので 46と2に分割されます
'D v15 q-24,10 cde  → ゲートタイム以降、音量が10まで下がります
[cmd:$90] [sign] [0-255] sign:正なら0負なら$FF
Q数値1,数値2ゲートタイム2 PSG FM SCC
ゲートタイムを指定します。数値1は0〜8。
n/8 のゲートタイムを指定します。0と8はオフです。
「q」とは排他指定なので、後で指定された方が有効になります。

数値2は省略可でPSG/SCC専用です。FMも指定できますが意味はありません。
指定すると、ゲートタイム以降、現音量から数値2まで音量が上下して行きます。
「zv」でリリースレートを指定していない場合、即時数値2の音量になります。
従来は音量0に向かうor即時音量0であったのを目標値として持つことが出来るようになりました。
<例>
'A v15 Q7 cde → 音と音の間の区切りが明確になります
'A v15 Q6,10 cde  → ゲートタイム以降、音量が10まで下がります
[cmd:$90] [128] [1-7]
{音程1,音程2}音長ポルタメント PSG FM SCC
音程を滑らかに変化させます。
音程1には開始音程を入れます。オクターブ指定も出来ます。
音程2には終了音程を入れます。オクターブ指定も出来ます。

数値を省略すると「l」の基準音長が使われます。

ポルタメント音程は、その時点で指定されているデチューン「%」値も反映されます。

ポルタメント後のオクターブは音程2のものを引き継ぎます。
<例>
'A o3{c,>c}1 → オクターブ3のドからオクターブ4のドまで
'A {o6c,o3c}1^1. → オクターブ6のドからオクターブ3のドまで
[cmd:$96] [note] [dir] [dL][dH] [mL][mH] [sL][sH] [length]
note : 開始音程(0-95) dir:下向き=0 上向き=1
dL,dH : (周波数1-周波数2) / (音長-1) の商
mL,mH : (周波数1-周波数2) / (音長-1) の余
sL,sH : 音長-1 (-1なのは、コマンドが来たときに必ず1ステップ分発音するため)
(音程1,..,音程4)音長高速アルペジオ PSG FM SCC
音程を高速に切り替えて1チャンネルで和音のような表現を行います。
音程は最大で2〜4つ指定できます。オクターブ指定もできます。
<例>
'D o4(ceg)1 → ドミソを高速に切り替えます。
[cmd:$9D] [count] [note4] [note3] [note2] [note1] [length]
count : アルペジオ音符の数-1。2〜4個なので 1,2,3 のいずれか
note : アルペジオ音符の数だけ、逆順に 音程(0-96) の 2 倍 の数値(0-192)で格納される
W数値1,数値2,数値3セルフディレイ PSG FM SCC
セルフディレイの設定をします。数値1は0〜2、数値2は-127〜127、数値3は-255〜255。
音符系コマンドと共に使い、元の音長を数値3と分割して、数値1で指定したn音前の音程でキーオンしなおします。

数値1は0で当の音、1で1音前の音、2で2音前の音です。
数値2はセルフディレイキーオン時に その時点の "v"あるいは "V" で指定された音量に数値を足します。
ハードエンベロープが指定されている場合は数値2は無視します。
数値3はゲートタイムと同じ表記方法です。

使い方にもよりますがゲートタイムとは相性が悪いです。
セルフディレイがコンパイラ側で音を分割するのに対し、ゲートタイムはドライバ側で音を分割するためです。

音程系コマンドの後ろに & があるときはセルフディレイを追加しません。
ポルタメントにも一応セルフディレイは付きますが、音長がおかしくなります。
元の音長から数値3が分割できないときは、セルフディレイを追加しません。
セルフディレイはn音前の音でキーオンし直すだけで、音色やハードエンベロープなどは戻しません。

数値指定なしの「W」のみでセルフディレイ機能を停止します。
<例>
'D p2v10 W0,-3,-8 cde ↓
'D p2v10 c^-n8 v-3cn8v+3 d^-n8 v-3dn8v+3 e^-n8 v-3en8v+3 とコンパイラ側で展開される
~数値1,数値2,数値3装飾音符 PSG FM SCC
装飾音符を付加します。数値1は-12〜12、数値2は1〜8、数値3は0〜1。
音符コマンドと共に使い、元の音長を数値2と分割して、数値1で指定した半音単位の音程を直前に付与します。

数値1は半音単位で指定します。トランスポーズ「i」と同じ指定です。-1で半音下の音が装飾音符の音程になります。
数値2は装飾音符の音長です。
数値3は装飾音符と元の音符を「&」で繋げるかどうかを指定します。0で「&」を付けない、1で付ける。

ポルタメント、アルペジオには装飾音符は付きません。

数値指定なしの「~」のみで機能を停止します。
<例>
'D p2v10 ~-1,3,1 cde ↓
'D p2v10 c^-n3 c+n3&d^-n3 d+n3&e^-n3 とコンパイラ側で展開される
@数値音色指定 PSG FM SCC
登録した音色をチャンネルに設定します。
登録していない音色を指定するとエラーになります。
<例>
'A @0 c1 → ch.Aの音色を0番にする。
[cmd:$98] [L] [H] : SCC 音色番号*32しておく。
[cmd:$99] [L] [H] : FM 音色番号*32しておく。


音量モジュレーション図解
PSG/SCC には音量モジュレーションが2つあり、zv は独自仕様、zm は FM音源 の zv と同じです。ややこしいですが。
音程モジュレーション(zp)は基本的に zm と同じです。

・zv @,A,B,C
@… v で表される初期音量を何フレーム継続させるか.
A… @が終わった時に音量をどれだけ上げ/下げするか(相対値). 0だと音量変化なし.
B… @が終わった後、Bフレーム毎に音量を1ずつ下げる. 0だと音量変化なし.
C… ゲートタイム(q)が設定されている時(=キーオフ)Cフレーム毎に音量を1ずつ下げる. 0の場合は即音量0にする.
D… W コマンド(セルフディレイ)の第2パラメータが設定されていると、Cの開始時に音量を±できる.

ゲートタイム(qコマンド)はキーオンからのフレーム数。マイナス値で指定すると後ろから(音長-指定値)のフレーム数で設定する。

・zm @,A,B,C
@… @フレーム毎にAを現在の音量に加算する.
A… 加算値(マイナス可).
B… @の加算処理をB回分繰り返したら向きを逆にする.
C… (c)モジュレーションの開始を指定分だけ遅らせる.

zv,zmともに、加算した結果の音量が 0〜15 の範囲に収まらない場合、出力は 0〜15 に補正されるが、内部的には -128〜127 まで保持しているので加減算結果が狂うことは無い。
反転したとき、Bは 2倍 になる。これは基準音量(v)に対して±AxBが同じになるような挙動となる。
Bを 1 にすると矩形波を作ることができる。

zm と zv を併用すると、山(谷)+持続+リリースという変化を作ることができる。
zv の第1パラメータ(Attack Length)は zm の変化を指定フレーム分待つ「ディレイ」として機能する。
zv の第2パラメータDecay Depth)を適用した時点で zm は強制的に解除され、zvの第3第4パラメータが発動する。

q/Q の第2パラメータを使うと、ゲートタイム以降の音量を指定できる(目標音量)。
このとき、zvでリリースレートを指定しておくと、リリースレートに従って目標の音量へ向けて音量が増減していく。
zvはオフであってもリリースレートを参照する。デフォルトはリリースレート=0、目標音量=0なのでゲート即音量0のぶつ切りになる。

どうしてこんなややこしいことになっているかというと、zv と zm どちらかだけで当面は事足りると思っていたからです。
お手本にしている PMD は他にもノコギリ波など色々あるのですが、マシンが非力なので何かと工夫が必要です。

■ 更新履歴

・20100616 初版
・20140623 第8b版
+ 内部処理に中規模の変更とPC88対応準備. 遅くなった&バグが残っているかも. 従来の MML は再コンパイルが必要.
+ "&" コマンドを、音符系コマンドの直後限定とするよう仕様変更. それ以外はエラーになる.
+ セルフディレイをコンパイラコマンドに変更. 従来と完全互換ではない.
+ OPN の特徴を潰すのは忍びないので SSG-EG を書き込むようにした. 0〜3 だと DT2、8〜15 だと SSG-EG とみなす.
+ FM3 効果音モードのバグを修正.
+ ポルタメント使用時に "#OCTAVE-REV" が無視されていたのを修正.
+ PSG に高速アルペジオコマンド "(〜)" 追加.
+ 相対音量コマンド "v+/v-/V+/V-" で値を省略した場合 1 になるようにした.
+ チャンネル毎のマスターボリューム "@v" コマンドを追加.
+ FM ポルタメント時にトランスポーズが反映されていなかったのを修正(+a)
+ 装飾音符コマンド"~"を追加(+b)
+ Qでn/8した結果音長が0になった時の挙動を修正(+b)
+ Q/qのリリース時の目標音量を追加(+b)

・20141013 第8c版
+ 音量テーブル設定 #VOLTL コマンド追加.
+ 全体的に微妙な高速化. 内部的に細かく変えたので従来の MML は再コンパイルが必要.
+ デチューン "%" の範囲を -128〜127 へと変更. サイズ削減のため.
+ q/Q コマンドのバグ修正. FM でのコマンド長を間違っていて、以後の演奏がおかしくなっていた.

・20150917〜20151127 第9b版
+ 若干の高速化とバグ修正. MML 再コンパイルが必要.
+ #OPN/#PSG/#SCC のトラックと物理チャンネルの対応で "," の解釈を変更. 既存の MML も変更を推奨.
+ 簡易ファイラとして TMCF を添付. ファイルシステムの仕様は未だ固まっていない.
+ TMCF 環境専用で OPNx2 有効化(仮).
+ TMCF 環境専用で PCM 再生機能を有効化. SR+64KB拡張RAM 専用.
+ ポルタメントを使うとエラーが出る場合があったのを修正.


■ あとがき

あとは音声合成との同期ですかね。

▲ TOP