How To Use the FamiTracker Driver Source to make NSF Music F

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
How To Use the FamiTracker Driver Source to make NSF Music F
by on (#63289)
I asked about this topic to many people and also posted questions, but there is very little documentation about it. So i learned it how to do it with the help of jsr and miau in #nesdev irc channel. So i want to put up this thing so people can clarify their doubts.


How To Use the FamiTracker Driver Source to make NSF Music Files

You have made your own game but without sound, it’s uninteresting. So let’s see how to put some sound in your game at your desired position.
This article contains the method to convert the raw music data to NSF file using ca65 compiler. If you haven’t been introduced to NSF or FamiTracker, go to http://famitracker.shoodot.net/ and download it. YouTube contains many videos regarding how to make music using this software.
Firstly many people are making music in FamiTracker software and are exporting it into .nsf format. This file they include in their code using .incbin to play the music. But there are two main disadvantages – Firstly, the nsf file has 3 important address – LOAD, PLAY and INIT. So by directly exporting as nsf file, we have no control over the these addresses. So if you have some code at the same place as LOAD address of the song, then there is a problem. Secondly, the output file size is large. So if you have limited space, then it’s not the best option.
But we can do in another way. When you make your music in FamiTracker, export it as .bin = Raw Music Data file. Then you have two files with you- 1. music.bin and 2. samples.bin
Now go to ftp://ftp.musoftware.de/pub/uz/cc65/ download the cc65 compiler according to the OS you are using. Then go to http://famitracker.shoodot.net/downloads.php and download the NSF Driver Source. This folder contains 14 files. Now copy the compiler ca65, linker ld65 and necessary files into this folder. Also copy your music.bin and samples.bin files to this folder.
Now open up nsf.cfg file. It may look like this:
MEMORY {
ZP: start = $00, size = $100, type = rw, file = "";
RAM: start = $200, size = $400, type = rw, file = "";
HDR: start = $7F80, size = $80, type = ro, file = %O;
PRG: start = $8000, size = $20000, type = rw, file = %O;
}

SEGMENTS {
ZEROPAGE: load = ZP, type = zp;
BSS: load = RAM, type = bss, define = yes;
HEADER: load = HDR, type = ro;
CODE: load = PRG, type = rw, start = $8000;
MUSIC: load = PRG, type = rw, start = $A000;
DPCM: load = PRG, type = rw, start = $C000;
}

So now you can change the address in the CODE and PRG from $8000 to desired position. The address you put will be the LOAD address. The INIT address is same as LOAD address. The PLAY address is 3 more than INIT address. So PLAY = INIT + 3
So for example, if you locate it at $A000 then init = $A000 and play = $A003
Now we can remove the MUSIC and DPCM lines in the SEGMENTS as we don’t use it. Also if you don’t want the header, then remove HEADER line also. But by doing this, you need not remove the first 128 bytes (header) of your nsf file manually.
Now we make the compiler. Make a compiler.bat file and put the following lines in it:
ca65 driver.s -D INC_MUSIC
ld65 -C nsf.cfg -o music.nsf driver.o
pause

So by these commands, the music.bin file converted and put into driver.o file along with other details. Then the nsf.cfg file determines the addresses and the final resultant file will be music.nsf
You can also use these lines if you don’t remove the HEADER line in nsf.cfg file:

ca65 nsf_wrap.s -D INC_MUSIC
ld65 -C nsf.cfg -o music.nsf nsf_wrap.o
pause

Then by doing this, you have to manually remove the header using any hex editor software (I use xvi32).

Now the first objective is achieved. We now have control over the addresses. For the second part, reducing the file size is a tricky task. When you open driver.s file (it opens in an editor. I use ConText) , you will notice that the code contains many lines which are not useful. So we can remove these lines and can save space.
Firstly, if you are not using any external chip like MMC5 or VRC6, you can remove that part of the code. Also if you are not using any bank switching, remove that part also. Notice the following lines in the code :

.include "init.s"
.include "player.s"
.include "effects.s"
.include "instrument.s"
.include "apu.s"

So to reduce space, you can remove unnecessary code from these files also. For example, if you are not using the effects of Vibrato, you can remove its code. Similarly, if the instrument remains same throughout the song, then instrument.s can be removed also. Please don’t get excited and remove code haphazardly as it might affect your music.nsf file. So it is advisable to check the proper working of the file after every modification. Also if you know which system you use – PAL or NTSC, then you can remove the other one and save the space.
So, the second objective is fulfilled. Though large amount of file size will not be reduced, but nonetheless this is useful if you are tight on space.

Finally, after doing all these things, test you code with sound and enjoy!!!

I would really like to thank jsr and miau for their help. They both cleared my doubts and helped me on this topic. Also a really nice place to learn these things http://famitracker.shoodot.net/ and http://nesdev.com/
For knowing how to play song in your code, see this open source code for multi-song NSF: http://no-carrier.com/index.php?/vegaplay/
Also the irc channel #nesdev is the best source to interact with these people and involve in NES mania.

- enigma
Re: How To Use the FamiTracker Driver Source to make NSF Mus
by on (#161256)
Is it also possible to change the ZP and BSS memory address?
I noticed that the default BSS page is set to Page 2 - OAM Copy.

eg. for:
Code:
            ZP:    start = $80,    size = $80,    type = rw, file = "";
            RAM:    start = $300,    size = $100,    type = rw, file = "";

Set half ZP (80-FF), and whole page 3 (300-3FF)

I'm not sure how much memory reserves this player.
From what I see (FCEU ram viewer), it used the memory bytes are scattered at different Mem. locations
Re: How To Use the FamiTracker Driver Source to make NSF Mus
by on (#161258)
Are you using cc65 (to code in C) or just ca65 (coding in ASM)? Your use of the term 'BSS' implies you are using C.

I can't remember how many bytes of ZP memory the Famitracker NSF file uses, but cc65 also uses about 10-20 ZP variables. Interestingly, the assembler waits till the last minute before assigning addresses to the C variables. It's a shame that the NSF file is using Random addresses scattered all over the RAM.

You can't move the ZP, of course. But I also question only allowing $100 bytes for BSS. NSF is not the ideal way to get music into a game. Is that what you are attempting? I would recommend trying Famitone2, which uses FAR less memory and far less CPU time.
Re: How To Use the FamiTracker Driver Source to make NSF Mus
by on (#161269)
Now that I'm looking at the Famitracker Driver...I don't know what you're talking about at all...

Famitracker's Driver doesn't use that much ZP Ram, and it look like it uses a contiguous block in the $200+ BSS section of the RAM. And, it looks like its using only about 100-150 bytes of RAM in the BSS. You should have at least RAM $300-$7ff left to use for a game.

Where did this come from...
Code:
            ZP:    start = $80,    size = $80,    type = rw, file = "";
            RAM:    start = $300,    size = $100,    type = rw, file = "";

??

The default Famitracker Driver (downloaded from the Famitracker website) included this as its .cfg file...

Code:
MEMORY {
            ZP:    start = $00,    size = $100,    type = rw, file = "";
            RAM:    start = $200,    size = $400,    type = rw, file = "";
            HDR:    start = $7F80,    size = $80,    type = ro, file = %O;
            PRG:    start = $8000,    size = $40000,    type = rw, file = %O;
       }


Which isn't really very good either. Hmm.

Does anyone out there have a ca65 cfg file that is set up to work with the Famitracker Driver?
Re: How To Use the FamiTracker Driver Source to make NSF Mus
by on (#161272)
BTW, every time I read your screen name (SDM) my brain reads that as either Saddam or Sodom. Neither is a good connotation. I looked SDM up on wikipedia...https://en.wikipedia.org/wiki/SDM

I think I like 'Self-Destruct Mode' best.
Re: How To Use the FamiTracker Driver Source to make NSF Mus
by on (#161276)
This doesn't answer anything asked directly, but FWIW, I almost never go out of my way to use the same assembler for a music driver and my projects. I just assemble it with whatever is convenient, then .INCBIN it in my project. There are really only a couple subroutines to call (maybe 3 if sound effect is a different one), I take care of that by putting them at the beginning, like include it at $8000 then the first thing in the sound driver is JMP init / JMP play, then you don't need to import/export addresses, just JSR $8000 and JSR $8003. The other concern is RAM usage, just make sure the sound driver doesn't overlap your main program's RAM area, and that's it. Since everyone uses different assemblers, this can make things easier. You see a lot of this in commercial games too, alot of the times there are a bunch of JMP $xxxx at the beginning of a bank, probably for similar reasons.
Re: How To Use the FamiTracker Driver Source to make NSF Mus
by on (#161302)
dougeff wrote:
Where did this come from...
Code:
            ZP:    start = $80,    size = $80,    type = rw, file = "";
            RAM:    start = $300,    size = $100,    type = rw, file = "";

??



These are MY changes that I wanted to use. That is why I ask whether it is at all possible to change the memory location, because in the first post is not described (only changes the load, init play).
Re: How To Use the FamiTracker Driver Source to make NSF Mus
by on (#161304)
I think that should work. If you didn't want to change the linker config, you can also put something like .res $80 at the start of the zeropage segment.