MMLコンパイラは、アセンブリ言語ソースに対して、各記述ブロックの先頭にラベルを付与します。
このラベルは、MMLの"#label
"コマンドで設定された文字列を先頭に、以下の名前が付与されます。
ブロック | ラベル名 | export宣言 |
---|---|---|
Envelope | Envelopenumber | no |
SUB | SUBnumber | no |
DPCM | DPCMinfo | yes |
BGM | BGMnumber | yes |
SE | SEnumber | yes |
numberは、MMLで記述した番号が10進数で表記されます。
このラベルが示しているポインタを引数に、nsd_play_bgm()関数や、
nsd_play_se()関数を呼び出すことで、BGM、効果音データが再生されます。
6502のメモリ空間にさえ存在していれば(バンクがセレクトされていれば)、どこに配置されていても再生可能です。
実際にC言語からリンクするサンプルは、"\sample\cc65"フォルダ、
アセンブリ言語からリンクするサンプルは、"\sample\ca65"フォルダをご参照願います。
#title "Test"
#Label "_Test_" //C言語から extern 宣言するので、シンボル先頭には'_'を付ける。
#bgm 1
#offsetPCM $C000 //⊿PCMの配置アドレス。ld65.exeのコンフィグで設定したアドレスと合わせる。
DPCM{
b1, "../dmc/bd.dmc",14,0,64
c2, "../dmc/bd.dmc",15,0,64
d2, "../dmc/sd.dmc",15,0,64
e2, "../dmc/sd.dmc",14,0,64
f+2, "../dmc/hhc.dmc",15,0,64
a+2, "../dmc/hho.dmc",15,0,64
c+3, "../dmc/cymbal.dmc",15,0,64
f2, "../dmc/tom.dmc",10,0,64
g2, "../dmc/tom.dmc",11,0,64
a2, "../dmc/tom.dmc",12,0,64
b2, "../dmc/tom.dmc",13,0,64
c3, "../dmc/tom.dmc",14,0,64
d3, "../dmc/tom.dmc",15,0,64
}
Envelop( 0){15 L 12 R 10 8 7 6 D0 5 D1 4 D2 3 D3 L 2 }
Envelop(100){ 0 D36 L 1 2 3 2 1 0 -1 -2 -3 -2 -1 }
Envelop(300){ 3 2 L 0 }
Sub(0){ l4o4u8. E@300 Em100 Ev0 cdefgab > c1,2. }
BGM(0){
TR1 v12 S0
TR2 v8 r-8. S0
TR5 o2l16 [2 c8f+f+ d8f+f+ c8f+f+ d8f+f+ ] `c+1
}
#define __NES__
#include <nes.h>
#include <conio.h>
#include "..\..\include\nsd.h"
//曲データ
extern const char Test_BGM0[]; //C言語なので、シンボル先頭の'_'は不要。
extern const nsd_dpcm Test_DPCMinfo[]; //C言語なので、シンボル先頭の'_'は不要。
//メインルーチン
void main()
{
nsd_init(); //音源ドライバの初期化。必ず呼ぶ。
nsd_set_dpcm(Test_DPCMinfo); //⊿PCM制御構造体のセット
nsd_play_bgm(Test_BGM0); //演奏開始
while(1){
waitvblank();
nsd_main(); //V-Blank毎に呼び出す。(ここに書かなくても、NMI割り込みでやっても良い。)
}
}
MEMORY {
# INES Cartridge Header
HEADER: start = $0, size = $10, file = %O ,fill = yes;
# PRG-ROM (32kByte)
ROM0: start = $8000, size = $4000, file = %O ,fill = yes, define = yes;
ROM1: start = $C000, size = $3ff4, file = %O ,fill = yes, define = yes;
ROMV: start = $fff6, size = $c, file = %O, fill = yes;
# CHR-ROM ( 8kByte)
ROM2: start = $0000, size = $2000, file = %O, fill = yes;
# RAM ( 2kByte)
ZP: start = $02, size = $60, type = rw, define = yes;
SRAM: start = $0500, size = $0300, define = yes;
RAM: start = $6000, size = $2000, define = yes;
}
SEGMENTS {
HEADER: load = HEADER, type = ro;
STARTUP: load = ROM0, type = ro, define = yes;
LOWCODE: load = ROM0, type = ro, optional = yes;
INIT: load = ROM0, type = ro, define = yes, optional = yes;
CODE: load = ROM0, type = ro, define = yes;
RODATA: load = ROM0, type = ro, define = yes;
DATA: load = ROM0, run = RAM, type = rw, define = yes;
PCMDATA: load = ROM1, type = ro, define = yes;
VECTORS: load = ROMV, type = rw;
CHARS: load = ROM2, type = rw;
ZEROPAGE: load = ZP, type = zp;
BSS: load = RAM, type = bss, define = yes;
HEAP: load = RAM, type = bss, optional = yes;
}
FEATURES {
CONDES: segment = INIT,
type = constructor,
label = __CONSTRUCTOR_TABLE__,
count = __CONSTRUCTOR_COUNT__;
CONDES: segment = RODATA,
type = destructor,
label = __DESTRUCTOR_TABLE__,
count = __DESTRUCTOR_COUNT__;
CONDES: type = interruptor,
segment = RODATA,
label = __INTERRUPTOR_TABLE__,
count = __INTERRUPTOR_COUNT__;
}
SYMBOLS {
# 3 pages stack
# __STACKSIZE__ = $0300; for cc65 version 2.13.3
__STACKSIZE__: type = weak, value = $0300; for cc65 version 2.14
cl65 -t none -Oi -Os -Or -c -o test.o test.c
nsc -a testmus.mml
ca65 -t none testmus.s
ld65 -C config.cfg -v -o test.nes test.o testmus.o nsd.lib nes.lib