NRTDRV仕様
メモリマップ
アドレス | 内容 |
---|---|
0000-17FFH | IPL起動用プログラム (IPLPATCH.BIN) / NRDSEL (NRDSEL2D.BIN) / OPM音色エディタ (IPLOPMED.BIN) |
1800-3DFFH | ドライバ本体 (NRTDRV.BIN) |
3E00-3EFFH | OPM#1仮想レジスタ(NRDSEL、OPM音色エディタで使用) |
3F00-3FFFH | OPM#2仮想レジスタ(NRDSEL、OPM音色エディタで使用) |
4000-FEFFH | 曲データ (*.NRD) |
FF00-FFFFH | IPL起動用ワークエリア / スタック領域 |
※NRTDRV内ではスタックポインタを設定していないため、呼び出すプログラム側でSPレジスタに適切な値を設定しておく必要がある(X1の場合は0000H)。
エントリ
- 01800H (DRVINI)
- ドライバ初期化。最初に実行する必要がある。
- 01803H (MPLAY)
- 再生。EI状態になり、任意のアドレスから演奏する。
- 01806H (MSTOP)
- 停止。EI状態になる。
- 01809H (MFADE)
- フェードアウト。
- 0180FH (MTEST)
- テスト音を発音。
- 01812H (MPLAYD)
- デフォルトアドレス再生。EI状態になり、04000Hから演奏する。
- 01815H (VINIT)
- 簡易演奏モニタ用の画面初期化。PCGの定義などを行う。
- 01818H (VMAIN)
- 簡易演奏モニタを1フレーム描画する。
外部参照用ワークエリア
- 01831H (VER)
- 内部バージョン番号
- 0 : 2016/10/28版まで
- 1 : 2016/11/01版から
- 2 : 2017/03/03版から
この内部バージョン番号は、ユーザーアプリケーション側でドライバと曲データの不整合を防ぐために使う。
実際にバージョン番号が実装されているのは2016/12/03版からとなる。それ以前のバージョンで上記のワークエリアを読むと「0」が返る。
2016/12/03版以前では演奏開始した時点で値が変化してしまう(トラック1のワークエリアと重複している)ため、演奏開始前に値を取得しておく必要がある。
データ
4000Hから配置。リロケータブルなので別の場所にも置けるが、その場合はドライバ側のBGMADRワークを書き換える(曲データを再アセンブルする必要はなく、再生エントリをコールする前にワークを書き換えるだけでOK)。
曲データ内で使用されるアドレスは、すべて曲データ開始アドレスからみたオフセット値。たとえば、曲データが04A00H〜で、トラックAの実際のアドレスが06809H〜なら、曲データ内に記録されているトラックAの開始アドレスは1E09Hとなる。
- 1バイト目
- CTC0の初期分周値 (#TEMPOヘッダで設定)
- 2バイト目
- CTC3の初期分周値 (#TEMPOヘッダで設定)
早送りの時は上記2バイトに早送り時の分周値が入る。
jコマンドの実体はtコマンド。tコマンドで分周値を再設定することによって、本来のテンポに戻している。
上記2バイトは必ず確保されているので#TEMPOヘッダは曲データのサイズに影響しない。
#TEMPOヘッダを全く使わなくても上記にはBPM120相当の分周値が入る。
よって、テンポの変わらない曲では#TEMPOヘッダだけを使うのがサイズ的に望ましい。
- 3バイト目
- 4バイト目〜41バイト目
- OPM#1の8チャンネル分の各トラック先頭アドレス(16バイト)
- OPM#2の8チャンネル分の各トラック先頭アドレス(16バイト)
- PSGの3チャンネル分の各トラック先頭アドレス(6バイト)
- 42バイト目
- 存在しない=2016/10/28版まで
- 1=2016/11/01版から
- 2=2017/03/03版から
3バイト目の最上位ビットが立っている場合は内部バージョン番号がここに入る。
- 42/43バイト目以降
- 曲名/ANK (#TITLE_ANKヘッダ)
- 曲名/Shift_JIS (#TITLEヘッダ)
- 作曲者名 (#COMPOSERヘッダ)
- プログラマ名 (#PROGRAMMERヘッダ)
- メモ (#MEMOヘッダ)
3バイト目の最上位ビットが立っている場合は43バイト目から、立っていない42バイト目から、上記5項目の曲情報が入る。可変長で、各項目の終端は0。
- それ以降
シーケンスデータ
シーケンスデータ仕様
コマンド番号はすべて10進数で記載する。[????.w] の場合は2バイト値。
- [00]+[count] (+[count]+[count]...)
休符。[count] はカウント数。もしカウント数が255なら、その次の1バイトもカウント数として扱う。
- [01]+[times]+[register]+[data] (+[register]+[data]...)
zコマンド。一気に複数のレジスタへと書き込める。[times]は書き込むレジスタの個数。
- [02]+[PAN/ALG/FB]+[voice_address+2.w]
軽量音色設定。PAN/ALG/FBをドライバ側で計算せずに決め打ちする。さらに、オペレータマスクは指定できない(前回の設定値を引き継ぐ)。[voice_address+2.w] は音色データが置かれているメモリの相対アドレス+2バイト。
- [03]+[volume]
ボリューム値をワークエリアに書き込む。レジスタへの書き込みは行わない。音色切替と音量コマンドが連続したときにTLレジスタを2回叩くのを防ぐために使用。[volume]はボリューム値。
- [04]+[OP1のDT2/MUL]+[OP1のTL]...[OP4のDT2/MUL]+[OP4のTL]
全オペレータのMUL、DT2、TLを一括で書き換える。CSM音声合成に使用可能。
- [05]+[type/sync]
ソフトウェアPM-タイプ再設定(シンクフラグ設定用)
- [06]+[OP/sync]
OPMトラックではソフトウェアAM-OP再設定(シンクフラグ設定用) / PSGトラックでは予約。
- [07]〜[11]
予約。
- [12]+[port]+[register]+[data]
ポート指定時のyコマンド。[port] はOPMのポートアドレスの下位バイト(0=PSG、1=0701H、9=0709H)。[register] はレジスタ番号、[data] は書き込む値。
- [13]+[release_rate]+{release_level]
PSGリリース設定。PSGパートでキーオフした際のリリースレートとリリースレベルを設定する。
- [14]+[voice_address.w]
音色設定。[voice_address.w] は音色データが置かれているメモリの相対アドレス。
- [15]+[detune]
デチューン。[detune]はデチューン値。2の補数でマイナスを表現するので、値のもつ範囲は-128〜127となる。
- [16]+[macro.address.w]
マクロ。[macro.address.w] はマクロデータの相対アドレス。
- [17]
レガートON。
- [18]
レガートOFF。
- [19]+[volume]
ボリューム。[volume] はボリュームの値。PSGトラックでも0〜127となっているため、ドライバ側で3ビット右シフトし、0〜15に丸め込まれる。
- [20]+[number]
OPMトラックではパン。[number] はパンの値。PSGトラックではトーン・ノイズ指定。[number] のビット0を立てるとトーン有効、ビット1を立てるとノイズ有効 (0=ミュート 1=トーン 2=ノイズ 3=両方)。
- [21]+[times]
リピート開始。[times] はリピート回数。
- [22]
リピート終了。
- [23]
リピート脱出。
- [24]+[register]+[data]
yコマンド。[register] はレジスタ番号、[data] は書き込む値。
- [25]+[number]
- [26]+[number]
- [27]+[number]
OPMトラックではハードウェアLFOリセット兼シンク。[number] は機能選択 (0=リセット 1=シンク解除 2=シンク)。PSGトラックではノイズ周波数。PSGレジスタ#6の値。
- [28]+[key_shift]
移調。[key_shift] はキーシフト値。2の補数。
- [29]+[pitch]/[pitch.d]+[pitch]
ポルタメント。[pitch] の値が割り込み1周期ごとにレジスタに加算される。
OPMトラックでは [pitch] は 0〜255で、この値がポルタメントON/OFFのフラグも兼ねる。
PSGトラックでは [pitch.d]+[pitch] の2バイトとなり、[pitch.d] は小数点以下2桁を100倍したものとなる。また、[pitch] は 0〜127で、最上位ビットはポルタメントON/OFFのフラグとして扱う(つまり、この2バイトで0.01〜127.99の精度となる)。
- [30]+[CTC0]+[CTC3]
テンポ。[CTC0] と [CTC3] は各CTCチャンネルの分周値。
- [31]+[delay]+[pitch]+[steps/flag]+[type/sync]
ソフトPM。[steps/flag] が動作フラグも兼ねている(0以外で動作)。[type/sync] のビット7はシンクフラグ。
- [32]+( OPM=[delay]+[depth]+[steps/flag]+[OP/sync] / PSG=[shape] )
OPMトラックではソフトAM。[steps/flag] が動作フラグも兼ねている(0以外で動作)。[OP/sync] のビット7はシンクフラグ。PSGトラックではsコマンド(ハードウェアエンベロープ設定)。
- [33]
強制キーオフ。
- [34]+[number]
トラック再開。[number] はトラック番号(トラックA〜Pが1〜16、トラック1〜3が17〜19になる)。
- [35]+[incliment]+[start_pitch.w]
グライド。[incliment] は増分兼フラグ(0でオフ)。[start_pitch] はグライド開始ピッチ。2の補数。
- [36]+( OPM=[volume]+[OP] / PSG=[period.w] )
OPMトラックではOP指定型ボリューム。[volume] はボリュームの値。[OP] はオペレータ指定。PSGトラックではmコマンド(ハードウェアエンベロープ周期)。
- [37]+[fade_speed]
フェードアウト。[fade_speed] はフェードアウトの速度。0〜15で、0が最速。
- [38]〜[124]
予約。内部処理は [126] のトラック終了と同等。
- [125]
トラック一時停止。トラック再開コマンドで再開できる。
- [126]
トラック終了。トラック再開コマンドで再開できない。
- [127] (+[loop_address.w])
トラック/マクロ終了。トラック終了の場合は [loop_address.w] がループ地点の相対アドレス。
- [128〜247]+[count] (+[count]+[count]...)
音符。[128]=o0c、[247]=o9b。[count] はカウント数。もしカウント数が255なら、その次の1バイトもカウント数として扱う。
割り込み仕様
2本の割り込みを駆動し、テンポとエフェクトに利用している。
CTC0+CTC3
この割り込みに演奏ルーチンを接続。割り込み周期自体を可変させてテンポを変更する。
周期 = 937500 / ( BPM * ( TimeBase / 4 ) )
X1のクロックは4MHzなので、1クロックあたりの時間は250ns。
しかし、プリスケーラを256倍にしているため、割り込み周期の最小単位は64ms(250ns*256)となる。
- [例] BPM=120、TimeBase=192の場合
937500/(120*(192/4))*250ns*256=10.4166666…
つまり、BPM120の割り込み1周期あたりの時間は約10.42ミリ秒。
CTC1
この割り込みにエフェクトルーチンを接続。常に1周期16.384msで処理されるため、各種エフェクト(ポルタメント、グライド、ソフトウェアLFO)に関してはテンポの影響を受けない。タイマモードでタイムコンスタント値は0(256)、プリスケーラは1(256倍)。
周期 = 16.384ms = 16384000ns = 256(タイムコンスタント) * 256(プリスケーラ) * 250ns(4MHz)
音色データ仕様
OPM音色データ
下記の30バイトからなる。
PAN/FB/ALG, OM, DT1/ML, DT1/ML, DT1/ML, DT1/ML, VOL, VOL, VOL, VOL, KS /AR, KS /AR, KS /AR, KS /AR, AM /DR, AM /DR, AM /DR, AM /DR, DT2/SR, DT2/SR, DT2/SR, DT2/SR, SL /RR, SL /RR, SL /RR, SL /RR, TL, TL, TL, TL ;(OP1) (OP3) (OP2) (OP4)
VOLはコンパイラ側で音量コマンドの値を反映するように加工したTL値。そのため、同じ音色で音量だけが違う場合、データ内には複数個の音色データが定義される(音色定義時にドライバ側でTLを再計算させるのを避けて負荷軽減するため)。
PSG音色
次の値が可変長で並ぶ。
[00]〜[15] 音量 [16]〜[47] ノイズ周波数指定(-16した値をPSGレジスタ#6に) [48]〜[51] トーン/ノイズ指定 [52]〜[67] ハードエンベロープ指定(-52した値をPSGレジスタ#13に) [68]+[env_period.w] ハードエンベロープ周期指定 [255]+[loop_offset] 音色データ終了
発音が最後まで到達すると、発音位置からloop_offsetの値を引く。loop_offsetは1バイトなので、255バイト以上前にループさせることはできない。