NES to NSF

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
NES to NSF
by on (#64549)
Hi all,

I write music (chipnoise) using only NESASM, I've tried to find a good method to convert NES-files to NSF, found NES2NSF but only Japanese version which doesn't work as I'm not able to edit the config file. Any other methods, the programs are simple, usual iNES-header, .org to $8000, lots of LDA's and STA's, a simple Vblank routine for timing.

Any tips are highly appreciated !

-Jukka

by on (#64552)
Let me guess, you want to rip the NSF out of your ROM?

NES2NSF is not really a conversion utility. As it says in the readme, it's a NSF compilation utility. It's purpose is to take a large NES/FC ROM image and split it into specified sized bank files (it also removes the iNES header for you). It also has a detection method based on the config file settings to detect writes to $4015. Also a setting to prepend a NSF header or not to prepend a NSF header. Sounds great in theory, but it has a bug when splitting 8K banks, they are split incorrectly. It also has a copy of a NSF header with some default settings for the NSF spec which you need to edit with a hex editor. Btw, you can edit that config file. All you do is change the numbers at the top that kind of resemble bits. Some of them can be larger than a 0 or 1. Anyways, you don't need to use this utility. It's buggy and it's not really effective anymore, as far as I'm concerned. I use a different file splitter now days.

If you're making a ROM that is mapper 0, 16K or 32K. All you need do is load up a emulator (FCEU mod) and dump $8000 - $FFFF from the memory viewer (after snapping at a write break point to $4000 - $4008). If you made a ROM that has a origin of $C000, then you dump $C000 - $FFFF (make sure you change the load address). Using this method gives you a completely stripped file. After that, prepend a NSF header to it and fill out the NSF spec information via a hex editor.

If you want more details, I have a document that shows you how to rip NSFs. NSF Ripper Guide

by on (#64553)
Yes, exactly, I write music using only NESASM, always mapper 0, always 16k or 32k, always starting from $8000, ROM (NES) which I need to convert/rip to NSF-format. As I make the programs that generate the ROM's I also know exact addresses, just trying to find a simple way to dump/convert the APU registers (and vblank timers) to NSF. Thanks of information regarding NES2NSF, it doesn't work and probably it is useless for me.

by on (#64555)
If you're writing the stuff yourself, and you know the INIT/PLAY address, you can just take your 32k of PRG, and slap a valid NSF header on it, and it should work.

An NSF file is a NES rom basically.

by on (#64556)
I'm not sure how you wrote your music driver. However, most games have a JSR to the music driver in the NMI code. That will be your play address.

by on (#64559)
Dwedit: thanks of the info, NSF-header seems the best way, I will try it !

Gil-Galad: As I only compose music, no games, graphics or anything else,
just an iNes header and bunch of LDA/STA directly to APU registers, timing with VBlanks. Simple but works for me, especially with NES as the sound world is extremely rich with it.

Here's a small example:

ftp://ftp.untergrund.net/users/pxtr/nes/nes071910-1.nes


Thanks !

-J

by on (#64596)
haha, fun-sounding stuff.

You might need to start using a new timing system in your code, depending on what you're doing. The INIT address can only be called once and I think a lot of NSF players might freak out if you never return from it. Plus they definitely won't let you do timing by reading any registers or using the NMI interrupt. In your case you may want to make the init address blank by pointing it to an RTS instruction (unless you are doing anything to initialze something). Use it though if you want more than one song per NSF.

The PLAY address just gets called every vblank. So you need to make your program run 1 frames-worth of code, then hit an RTS (including times it just waits and does nothing). you can use this as an NES ROM by putting a JSR to your routine in the NMI handler. (and have the main code sit in an infinite JMP loop while the NMIs happen, don't enable NMIs before going into the infinite loop though).

In the .NES ROM, in it's most basic form your NMI would simply be
Code:
nmi:
 jsr play
 rti


Let me know if you need that explained better.

by on (#64606)
I've long maintained that we need a NES music format that is and iNES file, with certain restrictions, and a simple protocol for selecting the song in a PPU-less player. It ensures there are no (meaningful) restrictions on what the music can do.

by on (#64611)
blargg wrote:
I've long maintained that we need a NES music format that is an iNES file, with certain restrictions, and a simple protocol for selecting the song in a PPU-less player. It ensures there are no (meaningful) restrictions on what the music can do.

I agree. Do you have any ideas for specification?

by on (#64631)
I'm always happy when this stuff makes people laugh, that it sounds fun !
At least it sounds fun for me !

That's true, I took a closer look to NSF, no way that I could convert this directly to NSF, header was quickly done but I'm deliberately avoiding any interrupt-driven players/formats/etc., I operate several different console "platforms", my first task is find a way to do VBlank, after that there are no restrictions what I write to sound chip registers. And this doesn't seem to work in conversion, anyway thanks, it seems someone (Blargg) is taking another direction which sounds very very interesting !

-J


Memblers wrote:
haha, fun-sounding stuff.

You might need to start using a new timing system in your code, depending on what you're doing. The INIT address can only be called once and I think a lot of NSF players might freak out if you never return from it. Plus they definitely won't let you do timing by reading any registers or using the NMI interrupt. In your case you may want to make the init address blank by pointing it to an RTS instruction (unless you are doing anything to initialze something). Use it though if you want more than one song per NSF.

The PLAY address just gets called every vblank. So you need to make your program run 1 frames-worth of code, then hit an RTS (including times it just waits and does nothing). you can use this as an NES ROM by putting a JSR to your routine in the NMI handler. (and have the main code sit in an infinite JMP loop while the NMIs happen, don't enable NMIs before going into the infinite loop though).

In the .NES ROM, in it's most basic form your NMI would simply be
Code:
nmi:
 jsr play
 rti


Let me know if you need that explained better.

by on (#64632)
blargg wrote:
I've long maintained that we need a NES music format that is and iNES file, with certain restrictions, and a simple protocol for selecting the song in a PPU-less player. It ensures there are no (meaningful) restrictions on what the music can do.


Yes, this is very interesting, PPU-less player, a simple protocol (although in my case I'm especially interested of meaningless restrictions :) .

by on (#64634)
thefox wrote:
blargg wrote:
I've long maintained that we need a NES music format that is an iNES file, with certain restrictions, and a simple protocol for selecting the song in a PPU-less player. It ensures there are no (meaningful) restrictions on what the music can do.

I agree. Do you have any ideas for specification?


One possible approach could be something like csound score format, simple text files, time/durations wouldn't be beats, perhaps frames (or even seconds), pitch 8+3 bits (not note names etc, you wouldn't be restricted to any particular temperament), rest would be direct writing to registers so that the full potential of NES APU would be in total control of composer. I should mention here that I'm classically trained composer which of course restrict my thinking, also I'm just starting the discussion of possible formats, it is too hot here Kitee (terveisiä Pohjois-Karjalasta sinne Tampereelle) that I could think as clearly as usually (well, it is not much better in Winter either...).

by on (#64832)
blargg wrote:
I've long maintained that we need a NES music format that is and iNES file, with certain restrictions, and a simple protocol for selecting the song in a PPU-less player. It ensures there are no (meaningful) restrictions on what the music can do.


What the NSF format is lacking, is the IRQ. I was missing out on the end-of-sample DPCM IRQ that my speech synth uses - I was able to add $4015 polling code and have it work that way, though.

I don't know if there is a way to totally escape using the PPU, at the very least you need to disable/enable the NMI. Though for jp48's case I guess the NMI could just be an RTI instruciton.

Is there anything different that would make an expansion incompatible with NSF? Maybe if it could be spec'ed that the NES is allowed to never return from the INIT routine. What you could also add to the NSF header is an address for where a standard bootup/player code stub is to be loaded (and maybe you could specify what version of this code, for future cases).

I guess if it never returns from INIT also, there is the problem of regaining control to change tracks. Might need the NMI for this.. seems kinda complicated.

by on (#64833)
You reset the CPU when you change tracks.

by on (#64840)
Yeah, the basic idea is that an iNES music file is a totally standard iNES ROM whose reset handler reads the track number to play, etc. from zero-page bytes. This way an emulator doesn't need any special handling, other than doctoring the initial values of those zero-page locations before powering up the emulated NES. To change tracks, you repeat the above process. So you never need to know anything about how the music code works, where its routines are, etc. and the music code has full flexibility in how it works, and what mapper it uses. This of course would supplement NSF, rather than replace it, since NSF works fine for most music.

That covers the essential functionality. You could also have the info strings at the beginning of PRG data, so that they are always at offset $10 in the file. And you could have some way of plugging in a NES-based UI, so that it can be booted standalone on a NES. Perhaps the reset code would check for a signature in zero-page; if not present, it jumps to an area where the NES-based front-end can be plugged in, and also specifies routines similar to NSF for changing the track while running.