Hey Everyone!

For my Senior Independent Project in college, I have decided to try my hand at writing code for the NES in 6502 Assembly. Having graphic rendering more or less handled, i am now moving on to audio playback. I found some code for nerdtracker .nsf playback here:

https://wiki.nesdev.com/w/index.php/Ner … _in_NESASM

I assumed it would work with all .nsf files.  However, after exporting my .nsf from deflemask and running the code, I was able to create a NES rom but without any audio playback. Is there a difference in .nsf files generated by different pieces of software? Am I missing something? Any help on this issue would be very helpful.

Thanks!

NSF files can (and do!) have different load/init/play addresses. Take a look here: https://wiki.nesdev.com/w/index.php/NSF.
Download a hex editor if you don't have one, it's invaluable for quickly looking inside .NSFs (I use XVI32 personally). Definitely check you're not playing a bankswitched NSF, that's way more complicated that this example you've posted can handle (to the point of requiring custom hardware).

For non-bankswitched NSFs, this should work. If the load address is not $8000, change the

.org $8000

before

.incbin

Also modify the init and play constants and you should be set!
(I dunno why the code defines the load address and then just hardcodes it, oh well)

Good luck! :]
EDIT: Don't forget to strip the header from the .NSF before including it!

Last edited by kvee (Nov 7, 2018 5:18 am)

Oh, and to answer your question, each tracker has its own driver code. The FamiTracker NSF driver is even open source, so you can take a peek if you're curious. Games typically include drivers at the source level, NSF was meant more as a format to rip game music to originally.

Last edited by kvee (Nov 7, 2018 2:10 am)

NES is not the platform I program for, but I can still speculate a little.

When you're saying no audio playback, do you mean completely silent, or no PCM samples?

For NMIs to be triggered, you need to set bit 7 in PPU1 (register $2000). The example code does this for you. However the reference document Everynes suggests that writes to this register during the first frame after reset are ignored. Maybe you need to wait 1-2 frames, or wait for VBlank, after the call to init, but before the write to $2000.

RAM contains random data at power-on. Maybe Deflemask expects RAM to be cleared before calling init, but Nerdtracker's init initializes all the RAM it's using so that's why it works.

Might be obvious, but check whether Deflemask's manual has an example player routine.

Try running your silent ROM in a debugger like no$nes and see if you can figure it out by single-stepping the ROM to figure out what it does.

Check whether the file that's exported is NSF or NSFe or NSF2 and check with documentation whether that might matter. (I leave that work to you. wink )

Useful links:
http://problemkaputt.de/nes.htm
https://wiki.nesdev.com/w/index.php/NSF

kvee wrote:

NSF files can (and do!) have different load/init/play addresses. Take a look here: https://wiki.nesdev.com/w/index.php/NSF.
Download a hex editor if you don't have one, it's invaluable for quickly looking inside .NSFs (I use XVI32 personally). Definitely check you're not playing a bankswitched NSF, that's way more complicated that this example you've posted can handle (to the point of requiring custom hardware).

For non-bankswitched NSFs, this should work. If the load address is not $8000, change the

.org $8000

before

.incbin

Also modify the init and play constants and you should be set!
(I dunno why the code defines the load address and then just hardcodes it, oh well)

Good luck! :]
EDIT: Don't forget to strip the header from the .NSF before including it!

Hey, thank you for the information, but i still have a few questions (I am very new to this). First, how do I determine that the load address is not $8000? Do I simply look for where the bulk of the hex data (song data) is? In my case, the largest chunk of the data IS located at address $8080 (with $8000 being the beginning of the file). In a similar fashion, i am unsure how to modify the init and play registers accordingly.

I tried to manually copy the data stored at $070-$077 into the registers denoted by the table on the NESDEV wiki but other than turning my emulator screen white (?), there was no change in audio playback.

Any more pointers would be very helpful, thank you.

venoSci wrote:

how do I determine that the load address is not $8000? Do I simply look for where the bulk of the hex data (song data) is? In my case, the largest chunk of the data IS located at address $8080 (with $8000 being the beginning of the file)

Oh, don't confuse the offsets inside the file (where the song data always starts at byte $80) with the memory layout of the NES. It's possible Deflemask actually does this (have load=$8080), but I don't use it so I'm not sure.
Your data would be located at $8080 if and only if bytes 8 and 9 of the .NSF header are $80.
Also, don't include the first 128 bytes from the .NSF, that's the header. It's metadata and it doesn't belong in the final .NES file.

(Ok, side note here: if the load address is indeed $8080, you could load the entire .nsf file at $8000 and the song data would in fact then be at $8080, because it would be shifted by the size of the header data, so some programs might even do that on purpose, but it's ugly and somewhat confusing! Just read the addresses from the header and then throw the header away. I know, it might take a bit of wrapping your head around all this)

Here's a quick and dirty diagram:

(I've made a test .nsf that is shown there, but the principle is always the same)

Don't worry about $70-$77, just check it's all zeroes (that means no bankswitching). If it's not all zeroes however, you're not gonna be able to use the simple playback method from the nerdtracker example.

Oh, and you can also ask in the nesdev forums, or in the famitracker.org discord (while this discord server is mainly for famitracker users, there are definitely people who know NES programming and might be willing to help, in the #development channel!).

kvee wrote:

Don't worry about $70-$77, just check it's all zeroes (that means no bankswitching). If it's not all zeroes however, you're not gonna be able to use the simple playback method from the nerdtracker example.

Thank you for all the info! It looks like i will need to do some bank switching since bytes $75-$77 are non-zero values (thanks deflemask). I appreciate all the help, and I will use this information in order to (hopefully) get something working in the near future.

Thanks!

venoSci wrote:

looks like i will need to do some bank switching since bytes $75-$77 are non-zero values

You might need to use this then: https://wiki.nesdev.com/w/index.php/INES_Mapper_031

venoSci wrote:

I appreciate all the help, and I will use this information in order to (hopefully) get something working in the near future.

Thanks!

No problem! :]
Let me know how everytinhg turns out!