NSF Extensions, NSF2 and NSFe (2018)

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

Moderator: Moderators

User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

NSF Extensions, NSF2 and NSFe (2018)

Post by rainwarrior »

News:
The proposed NSF2 outlined below is now implemented in NSFPlay 2.4 beta 9, available here:
https://github.com/bbbradsmith/nsfplay/releases


Original proposal below:


So, about 8 years ago kevtris openly speculated about an "NSF 2.0" format that would update the existing NSF format with a few goals in mind:

1. Practical ways of using the IRQ and/or NMI as interrupts.
2. Track times and names, or other non-essential metadata.

I didn't want to continue that thread, as basically nothing ever came of it. Quietust made a Battletoads RIP that relied on the idea of a "non returning INIT that gets interrupted by PLAY", but I think it predated the NSF 2.0 proposal, and wasn't really relying on the whole IRQ idea, just an INIT timeout.

So... now that I'm actively working on some NSF stuff again, I like some of the ideas in that proposal, and I want to make this stuff "real" finally. Here's what I propose to do:


1. Metadata

Kevtris' proposal used the last 3 bytes of the NSF header (previously reserved as 0) to indicate the length of NSF data that follows the header. This means that any metadata appended goes right after the other data. This is good, and I don't think it even requires a version change; it's backward compatible with NSF 1. Any nonzero value in the last 3 bytes should be interpreted as a data length, and indicates the presence of non-essential metadata. (We don't really have the DISKDUDE! problem with NSFs that we did with iNES; the headers are generally very conformant in this respect.)

The other question is what the metadata should look like. Kevtris had some ideas about them, but they weren't very firm. It was some chunked format with basically whatever fields he could think of at the time. My counter to this is: we already have a chunky metadata format for NSFs, called NSFe.

NSFe was Disch's idea, implemented about 15 years ago for his NotSoFatso NSF player. It has always been very extensible (unlike NSF 1), but it never received widespread adoption. Several emulators do support it, though, and I've found a lot of use for it over the last few years. It's existing metadata formats are reasonably parsable by the 6502, IMO. (Emulators can also reuse their NSFe implementation to support both, which is helpful.)

So, in light of this, I see no reason to create a new competing metadata standard. We might as well just merge these two. There's no fundamental incompatibility between the two ideas. So, what I've decided to go with is just putting NSFe chunks (as defined by the NSFe spec) at the metadata location. This does not inclulde the "NSFE" header (unnecessary), and the "INFO"/"DATA"/"BANK" chunks that are normally mandatory in a .NSFe file must be omitted here.

To try this idea out I have implemented exactly this for my most recent beta of NSFPlay:
https://github.com/bbbradsmith/nsfplay/ ... /tag/2.4b5

To additionally help test it, I've created this python tool that easily converts NSFe to this NSF + metadata format. Try it out:
https://gist.github.com/bbbradsmith/4bc ... ddfbea5009

Edit: and for the purists, here's a python script to strip that metadata:
https://gist.github.com/bbbradsmith/e22 ... 1a4f6a7e45

I see no reason to increase the version number just for metadata. There is no backward compatibility issue in simply treating a value other than 0 in the last 3 bytes of the NSF header as an indicator for the presence of metadata.

Header change:

Code: Select all

header byte $7D-7F:
    3 bytes - 24-bit size of data following header (little endian)
(Note that the appended data will become part of the ROM image on old players. NSFs should not be relying on the presence of 0 outside their data areas anyway, though, so this is generally safe, and easily fixed with explicit padding in the file.)


2. Non returning INIT, IRQ / NMI etc.

This part of kevtris' proposal was a bit more solid. I have not implemented any of it yet, but I plan to keep most of it. Here's some plans:

1.1. Non-returning INIT is a problem. We need a way to signal to the player hardware when we're done starting up and ready to receive PLAY / IRQ interruptions. (Quietust's implementaion of this is just to "time out" the INIT routine after some large number of cycles. I think GME ended up borrowing this implementation. This worked, but I think we really need an explicit non-arbitrary moment of synchronization here.)

Instead my thought is: the non-returning INIT flag means that INIT will be called twice. The first call is still required to return, but can set RAM variables to tell itself that it's the second call. (The second call does not have to return, of course, as per the point of this.) Edit: The first and second calls will have the argument Y=$80 and Y=$81 respectively to make it very easy to branch to the non-returning code.

1.2. With non-returning INIT, PLAY becomes an "interrupt" that is intended to be driven by the NMI. A hardware player with no PPU can generate an NMI externally, and the player will likely use some sort of wrapper in between NMI and PLAY but that's up to the implementation. PLAY should still RTS, not RTI. The actual timing of PLAY vs the second call of INIT will necessarily be implementation-defined. (Edit: the NMI wrapping PLAY when this feature is used implies an SEI for it that will be reverted after PLAY returns via the wrapper's RTI. This should be fine, but if using IRQ features at the same time it should be considered. Also: the wrapper should disable its own NMI during execution of PLAY to prevent re-entry.)

2.1. IRQ handling: this I want to keep exactly as kevtris proposed. $FFFE-FFFF becomes a RAM overlay, and the NSF code gets direct IRQ control through it, no intermediary. CLI/SEI is explicitly allowed, of course. The DPCM and APU IRQs are also fair game.

2.2. IRQ timer: again, I think kevtris' proposal for an additional IRQ timer is solid, but with one minor change later proposed by B00daW to change the address of its interface to avoid the "test" registers that were discovered later.

Code: Select all

$401B - low 8 bits of 16-bit IRQ timer reload
$401C - low 8 bits of 16-bit IRQ timer reload
$401D - bit 0 controls the IRQ (0 = held in reset, continually reload timer, 1 = enable)
There's more detail about this on the wiki but basically I think the IRQ stuff is good as proposed.

3. NSF2 header change:

Code: Select all

header byte $05:
    byte = 2 - version 2 - indicates we must interpret byte $7C.

header byte $7C:
    bit 0-3 - reserved, 0
    bit 4 - IRQ features enabled
    bit 5 - Two INIT calls, second not required to return.
    bit 6 - Disable PLAY calls (not very useful without bit 5 also set)
    bit 7 - metadata contains a critical chunk*
This is almost what was in the proposal, *except bit 7 was proposed to indicate the presence or absence of metadata. I think it was redundant for that purpose (non-zero $7D-7F already achieves this), but I think we could use it to indicate instead that there is some essential chunk in the metadata that is critical for correct playback.

This basically works like NSFe, in which any chunk FourCC starting with an uppercase letter means it must be parsed to correctly play the file. This allows the NSFe extensions to work as that format intended, and also gives appropriate places for things like, e.g. sample data chunks for new expansion sound devices that need it.

Basically the presence of the version 2 indicator should only be needed for using the non backward compatible features, which are all encapsulated be $7C. Non-essential metadata can be freely included as version 1.

(FWIW, I couldn't find any players that even checked the version number. :P)


Anyway, that's what I'm working on for this. Part 1 is already more or less implemented (see above). Part 2 will take more work, but it's on the way. If you think I've made a critical mistake somewhere, let me know before the world turns to mud.

Edit: Replaced Y init spec with $80/$81 for non-returning INIT sequence that's distinguishable from the usual default.
Last edited by rainwarrior on Mon Mar 04, 2019 5:56 pm, edited 4 times in total.
Rahsennor
Posts: 479
Joined: Thu Aug 20, 2015 3:09 am

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by Rahsennor »

rainwarrior wrote:(FWIW, I couldn't find any players that even checked the version number. :P)
Mine does! It also aborts if the last four bytes are nonzero, so I'm going to have to change that.

The only question I can think of is, what should implementations do if the second INIT does return? Probably nothing, but just for completion...
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by rainwarrior »

The second INIT returning I think that could be implementation defined, but the simplest would just be to fall back to an infinite loop.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by rainwarrior »

One thing to note for the non-returning INIT, is that since PLAY is NMI driven in that mode, players that are to run on an NES or Famicom will not be able to use the variable playback rate field to control its rate. (A hardware player with no PPU could have its own NMI timer, though.)

This doesn't affect PLAY without the non-returning INIT though. If you're not letting the NSF run an INIT forever you can just poll for PLAY like the PowerPak does. (The IRQ features are entirely unaffected by this.)

PLAY being NMI driven does give an NES based player a nice opportunity to poll the controller in its NMI wrapper though, so it could still have a responsive menu on e.g. a battletoads rip.
User avatar
Anders_A
Posts: 88
Joined: Mon Nov 27, 2006 11:56 pm
Location: Sollentuna, Sweden

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by Anders_A »

Why is calling INIT twice preferrable over having two separate functions? One for INIT and one that's expected to be called after init and to never return?
User avatar
Jarhmander
Formerly ~J-@D!~
Posts: 569
Joined: Sun Mar 12, 2006 12:36 am
Location: Rive nord de Montréal

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by Jarhmander »

I guess it's a debate of whenever we want to add another routine address in the metadata vs reusing resources (address). Either ways looks fine, but the "init called twice", while a bit awkward, has the advantage of being simple, is almost compatible with the existing non-returning NSFs and sidesteps the following questions:
  • Where do we locate this field, in which chunk and which offset?
  • How do we name that field?
  • What are the exact semantics of the call?
((λ (x) (x x)) (λ (x) (x x)))
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by rainwarrior »

The question of why we don't add a new routine field for this? Doesn't fit in the existing header. There's no unused bytes left. It's either break potential backward compatibility by expanding the header, or put it in metadata at the end. ...or this third option which adds ~6 bytes of a decision code at the beginning of your INIT. I think that's an easy compromise.

Actually I think I'll add "Y=0" for the first call and "Y=1" for the second, just to get rid of that need to count it internally.


The original NSF2 proposal I think was based on quietust's INIT timeout idea, which I think was partly just a way to sidestep the spec for this. In this minimal way it didn't need a separate function but...

An NSF needs an INIT some some sort before it begins playing, whether or not it's "non-returning". Making it a timeout means the NSF author needs to manage that time to make sure they don't exceed it, and the player author needs to build some sort of timeout interrupt for it (can't use IRQ because that belongs to the NSF now... maybe NMI is viable). Also means every NSF has to have that same delay regardless of how much it uses/needs. Not a good deal, IMO. Returning and calling again I think will make this a lot easier and cleaner.
NewRisingSun
Posts: 1510
Joined: Thu May 19, 2005 11:30 am

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by NewRisingSun »

I like the merge proposal very much.

While we are on the subject of updating NSF, I would like to request:
  1. A means of indicating the Namco 163 audio volume, similiar to the new submappers, or to the NSFe MIXE chunk. Or shall the MIXE chunk become part of the NSF metadata at the end?
  2. An expansion sound bit for the YM2413. It's only used by one game (a main cartridge, plus four optional dumped expansion cartridges, plus an undumped one), but so is the VRC7.
  3. An expansion sound bit for a second APU, used by a handful of games.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by rainwarrior »

NewRisingSun wrote:While we are on the subject of updating NSF, I would like to request:
  1. A means of indicating the Namco 163 audio volume, similiar to the new submappers, or to the NSFe MIXE chunk. Or shall the MIXE chunk become part of the NSF metadata at the end?
  2. An expansion sound bit for the YM2413. It's only used by one game (a main cartridge, plus four optional dumped expansion cartridges, plus an undumped one), but so is the VRC7.
  3. An expansion sound bit for a second APU, used by a handful of games.
The 'mixe' chunk is mostly specified already, I need to write a few test NSFs/ROMs to fill in some of the implementation details in NSFPlay (though it does already parse that chunk, it just doesn't have reference volumes for a few expansions, including N163 yet... next beta I'll finish it soon.) Yes with the merging of metadata this becomes a solution under NSF2 as well.

Edit: I misremembered, I believe NSFPlay 2.4b5 does implement 'mixe' for N163 already.

The YM2143 karaoke thing is on my radar, but I have a bunch of VRC7 work to do before I will think about implementing it (not much of a priority, isn't there already a VGM dump?). In theory I don't see a problem with using one of the (2 or 6) remaining expansion bits for this.

There is also YM2143-with-VRC7 interface, which some people have done with TNS carts. This I don't think would get an expansion bit, since it's mutually exclusive with the VRC7 just uses that bit plus a mandatory chunk to designate replacing the VRC7 with it. (Also related: a 'vrc7' chunk with the built-in patches of choice is another thing I will likely implement.)

You didn't mention these, but for the Moe Pro sports games expansion that needs extra sample data, I think that doesn't need an expansion bit. Since it needs a mandatory chunk for the sample data anyway an expansion bit is unnecessary. Basically anything that needs more info than a single bit shouldn't bother to waste an expansion bit, IMO.

A second APU I don't think belongs under expansion bits. It could easily be accommodated by a mandatory chunk, though. (Easiest thing that comes to mind is just embed a whole second NSF in the chunk. Inception?) Implementing it, on the other hand, will probably be an ordeal...
Last edited by rainwarrior on Wed Aug 29, 2018 12:46 pm, edited 1 time in total.
Rahsennor
Posts: 479
Joined: Thu Aug 20, 2015 3:09 am

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by Rahsennor »

rainwarrior wrote:One thing to note for the non-returning INIT, is that since PLAY is NMI driven in that mode, players that are to run on an NES or Famicom will not be able to use the variable playback rate field to control its rate. (A hardware player with no PPU could have its own NMI timer, though.)
I was wondering about that.

Cycle-timed music engines can still use a non-returning PLAY, right?
rainwarrior wrote:Actually I think I'll add "Y=0" for the first call and "Y=1" for the second, just to get rid of that need to count it internally.
That is an excellent idea.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by rainwarrior »

Rahsennor wrote:Cycle-timed music engines can still use a non-returning PLAY, right?
That's still a valid idiom, yes.

I'm not sure if there's much advantage to using non-returning INIT as a replacement for that. The point is to have a baseline loop that's interrupted by PLAY. (...or IRQ)

I think non-returning INIT with a PLAY that is just an RTS though would potentially give the player hardware a chance to take input, etc. in its NMI handler but that'd also put small interruptions in the sound at 60hz anyway. (It's definitely a better replacement for the "deflemask trick" though, where it's already simulating interrupting a base loop with an NMI by polling in a non-returning PLAY.)
NewRisingSun
Posts: 1510
Joined: Thu May 19, 2005 11:30 am

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by NewRisingSun »

rainwarrior wrote:isn't there already a VGM dump
Yes, I made it because there was no NSF support. The Karaoke cartridge puts the chip registers at $6000/$6001, but I see no reason to define the chip such that it responds to both $6000/$6001 and $9010/$9030 for the "YM2413 using VRC7 interface". One could further define that the YM2413 shall not respond at $9010/$9030 if the VRC7 bit is also set, in case somebody wants to use both chips at the same time.
rainwarrior wrote:A second APU I don't think belongs under expansion bits. It could easily be accommodated by a mandatory chunk, though. (Easiest thing that comes to mind is just embed a whole second NSF in the chunk. Inception?) Implementing it, on the other hand, will probably be an ordeal...
You must be thinking of the arcade version of Donkey Kong 3, which has two 2A03 CPUs each with their own sound core,when you suggest a second NSF. I was thinking of the OneBus games, which have just one CPU that has a second set of APU channels. Surely an expansion bit would be practical for those.

I should mention that I would gladly volunteer to make NSFs from the games using these configurations, so you would have something to test with.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by rainwarrior »

NewRisingSun wrote:
rainwarrior wrote:isn't there already a VGM dump
Yes, I made it because there was no NSF support. The Karaoke cartridge puts the chip registers at $6000/$6001, but I see no reason to define the chip such that it responds to both $6000/$6001 and $9010/$9030 for the "YM2413 using VRC7 interface".
Yes those are two separate things. One could use an expansion bit, the other I think not.
NewRisingSun wrote:One could further define that the YM2413 shall not respond at $9010/$9030 if the VRC7 bit is also set, in case somebody wants to use both chips at the same time.
...or did you mean "no reason not to define" above? I'd rather they just be two separate things. I don't really see any advantage in combining them. They both happen to use that chip, but are otherwise completely unrelated.

As far as multichip goes, the prevailing treatment is to ignore all audio mapper writes outside of their canonical address to prevent overlap, and disable FDS RAM. That's pretty much what the TNS hardware that runs it has to do as well. Technically the Karaoke cart itself doesn't even use the expansion audio feedback though, right? ...so whatever mix value chosen for it will be completely fictional. (I guess we could treat it as the same volume VRC7, for the purpose of consistency.)
NewRisingSun wrote:
rainwarrior wrote:A second APU I don't think belongs under expansion bits. It could easily be accommodated by a mandatory chunk, though. (Easiest thing that comes to mind is just embed a whole second NSF in the chunk. Inception?) Implementing it, on the other hand, will probably be an ordeal...
You must be thinking of the arcade version of Donkey Kong 3, which has two 2A03 CPUs each with their own sound core,when you suggest a second NSF. I was thinking of the OneBus games, which have just one CPU that has a second set of APU channels. Surely an expansion bit would be practical for those.
Ah, I was not aware of OneBus. (How many games is this?) Sure that's a possible expansion bit I suppose. I thought you were talking about either something like DK3 or just having two synchronized NES' (which I've seen people do in the past as well), so maybe again that's a separate possibility.
NewRisingSun wrote:I should mention that I would gladly volunteer to make NSFs from the games using these configurations, so you would have something to test with.
Sure. New expansions aren't really a priority to me and I've got a bunch of tasks that I would put ahead of this stuff, but if you make the NSFs and can point me to a good spec for emulating something, I'd be happy to implement them when I have a chance.

I could really use a YM2413 for testing though. :( I'm about to rewrite the VRC7 and 5B emulation from scratch for NSFPlay. Every expansion chip that NSFPlay implements is something I've been able to verify and test first-hand, but once we start adding new stuff this isn't true anymore...
lidnariq
Posts: 11432
Joined: Sun Apr 13, 2008 11:12 am

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by lidnariq »

rainwarrior wrote:Technically the Karaoke cart itself doesn't even use the expansion audio feedback though, right?
It does return the YM2413 audio to the Famicom's RF modulator, but it blocks audio from the 2A03, so there's ... pedantically ... a balance of +∞ dB :/
NewRisingSun
Posts: 1510
Joined: Thu May 19, 2005 11:30 am

Re: NSF Extensions, NSF2 and NSFe (2018)

Post by NewRisingSun »

rainwarrior wrote:Yes those are two separate things. One could use an expansion bit, the other I think not.
Yes, keep the YM2413 at $6000/$6001 only. It makes the spec cleaner, and those few NSFs that wrote to $9010/$9030 for YM2413 (the VRC7 interface) would need to have their address writes modified. No reason to directly accomodate them --- I view them similarly to those N163 NSFs that play several octaves too low on accurate N163 audio emulators.
rainwarrior wrote:Technically the Karaoke cart itself doesn't even use the expansion audio feedback though, right?
Right, although for multiple-chip possibilities I would not put that into the NSF spec.
rainwarrior wrote:I was not aware of OneBus. (How many games is this?)
If you count all multicart games as separate ones, hundreds, but only twenty or so use the additional sound channel.
rainwarrior wrote:but if you make the NSFs and can point me to a good spec for emulating something, I'd be happy to implement them when I have a chance.
Then I'll get to it. I can add preliminary support to NintendulatorNRS and provide the source. (I already took the liberty of using your FDS emulation core. ;))
rainwarrior wrote:I could really use a YM2413 for testing though.
Technically, the Karaoke cartridge uses an unlicensed clone of the YM2413, though no sound differences have been discovered.

On a related note, I will have a request for optional even cleaner-than-original-sounding N163 emulation at some point, and can provide source code from NintendulatorNRS for that.
Post Reply