Writing a NSF player

Discuss NSF files, FamiTracker, MML tools, or anything else related to NES music.

Moderator: Moderators

User avatar
SusiKette
Posts: 147
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: Writing a NSF player

Post by SusiKette »

Do NSF players usually run on single thread or do they run on multiple? If they run on one, should the player really take much processing power at all?
Avatar is pixel art of Noah Prime from Astral Chain
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: Writing a NSF player

Post by lidnariq »

The only computationally intensive thing is resampling the original audio stream at 1.8MHz down to whatever is supported by the sound card, and that only if you synthesize audio that way in the first place.
User avatar
SusiKette
Posts: 147
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: Writing a NSF player

Post by SusiKette »

Unless some error occurred in my emulation code, FamiTracker's NSF files seem to use some illegal opcodes. I have currently set it so that when encountering one, a message is printed to console and the player is halted. The specific opcode is LAX, zpg ($A7). Since I have to implement these, how do the status flags behave on the ones that are usable? Some are mentioned to affect no flags, though. At least for LAX, both A and X will have the same value, so it probably doesn't matter which register you check the flags with, unless the status flags behave differently for some reason
Avatar is pixel art of Noah Prime from Astral Chain
User avatar
rainwarrior
Posts: 8734
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Writing a NSF player

Post by rainwarrior »

Regular Famitracker does not use illegal opcodes AFAIK, so that could indicate another issue, though I couldn't say whether the 0CC fork uses them.

I think I learned most of what I needed to know about the illegal opcodes from this document, and by inspecting source code of a few emulators:
http://www.oxyron.de/html/opcodes02.html
User avatar
SusiKette
Posts: 147
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: Writing a NSF player

Post by SusiKette »

The original cause of the issue was JMP incrementing PC after it was set to the target value. Next problem seems to be either with JSR or RTS. I'm not sure which one it is though.

Just in case there is some obvious mistake that I just can't see here is how I have implemented the said instructions: https://pastebin.com/GpFKfKQf
I'm not sure how easy it is to read, but I added some comments to hopefully make it a bit easier to understand.

(EDIT: cv. and sr. are references to other files)
Avatar is pixel art of Noah Prime from Astral Chain
tepples
Posts: 22708
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Writing a NSF player

Post by tepples »

JSR is supposed to add 2 to PC before pushing it, and RTS is supposed to add 1 after pulling PC. Some NSFs rely on this as a means of jumping through a jump table.
User avatar
SusiKette
Posts: 147
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: Writing a NSF player

Post by SusiKette »

I did a few tests some time ago before implementing these instructions, but just to be sure:
-JSR pushes the high byte to stack first and then the low byte
-RTS pulls the low byte first and then the high byte
Avatar is pixel art of Noah Prime from Astral Chain
User avatar
SusiKette
Posts: 147
Joined: Fri Mar 16, 2018 1:52 pm
Location: Finland

Re: Writing a NSF player

Post by SusiKette »

I took a look at bankswitching and I don't understand the meaning of the "padding bytes" that you get from load_addr AND #$0FFF. Can someone explain this a bit further?
Avatar is pixel art of Noah Prime from Astral Chain
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: Writing a NSF player

Post by Memblers »

An NSF that doesn't use bankswitching can be loaded directly into NES memory based on the load address, and one that does needs to be loaded as a (potentially larger) ROM that gets mapped into NES memory.

If I understand it correctly (I'll need to implement this myself soon), basically you're building a ROM out of 4kB banks. AND #$0FFF keeps the padding within that 4kB size, those upper 4 bits of the load address are ignored. The NSF load address becomes the beginning load address for your ROM. Like this:

NSF header says load address is $8456 (or $A456, $F456 would all be the same)
[ROM at 0x000000] bank 0
[padding up until 0x000456]
[load NSF data from here on]
Post Reply