The NES Sound Format (.nsf) is used for storing and playing music from the NES and related systems. It is similar to the PSID file format for C64 music/sound, where one rips the music/sound code from an NES game and prepends a small header to the data. An NSF player puts the music code into memory at the proper place, based on the header, prepares sound hardware, then runs it to make music. An NSF can be played on NES/Famicom hardware or in an emulator (NSF player or NES emulator).
There are two extensions of the NSF format:
All 2-byte address and period values are little endian. For example, an NTSC play speed of FF 40
means $40FF, or 16639 microseconds.
offset # of bytes Function ---------------------------- $000 5 STRING 'N','E','S','M',$1A (denotes an NES sound format file) $005 1 BYTE Version number $01 (or $02 for NSF2) $006 1 BYTE Total songs (1=1 song, 2=2 songs, etc) $007 1 BYTE Starting song (1=1st song, 2=2nd song, etc) $008 2 WORD (lo, hi) load address of data ($8000-FFFF) $00A 2 WORD (lo, hi) init address of data ($8000-FFFF) $00C 2 WORD (lo, hi) play address of data ($8000-FFFF) $00E 32 STRING The name of the song, null terminated $02E 32 STRING The artist, if known, null terminated $04E 32 STRING The copyright holder, null terminated $06E 2 WORD (lo, hi) Play speed, in 1/1000000th sec ticks, NTSC (see text) $070 8 BYTE Bankswitch init values (see text, and FDS section) $078 2 WORD (lo, hi) Play speed, in 1/1000000th sec ticks, PAL (see text) $07A 1 BYTE PAL/NTSC bits bit 0: if clear, this is an NTSC tune bit 0: if set, this is a PAL tune bit 1: if set, this is a dual PAL/NTSC tune bits 2-7: reserved, must be 0 $07B 1 BYTE Extra Sound Chip Support bit 0: if set, this song uses VRC6 audio bit 1: if set, this song uses VRC7 audio bit 2: if set, this song uses FDS audio bit 3: if set, this song uses MMC5 audio bit 4: if set, this song uses Namco 163 audio bit 5: if set, this song uses Sunsoft 5B audio bit 6: if set, this song uses VT02+ audio bit 7: reserved, must be zero $07C 1 BYTE Reserved for NSF2 $07D 3 BYTES 24-bit length of contained program data. If 0, all data until end of file is part of the program. If used, can be used to provide NSF2 metadata in a backward compatible way. $080 nnn ---- The music program/data follows
Strings are usually encoded in plain ASCII. In most game rips Japanese titles have been romanized into plain ASCII. More rarely NSFs have also used extended characters, the most common of which is Windows CP-932 (Shift-JIS) for Japanese titles. Windows CP-1252 (Latin) encoding examples may also exist.
NSF2 and NSFe should use UTF-8 instead, or plain ASCII for backward compatibility.
If file offsets $070 to $077 have $00 in them, then bank switching is not used. Data should be read from the file beginning at $080 and loaded contiguously into the 6502 address space beginning at the load address until the end of file is reached.
Some FDS NSFs use a load address below $8000 to fill in the $6000-7FFF range. It is recommended to use bankswitching to accomplish this instead, because it is not universally supported.
If any of the bytes from $070 to $077 in the file header are nonzero then bank switching is used. In this case, take the logical AND of the load address with $0FFF, and the result specifies the number of bytes of padding at the start of the ROM image. The ROM image should consist of a contiguous set of 4k banks, read directly from the NSF file beginning at $080 after inserting the requested number of pad bytes. If the file does not have enough data to fill the last bank completely, it may be padded out.
The 6502's address space is divided into 8 4k bank switchable blocks. For each block the current bank is controlled by writing the bank number to at corresponding register at $5FF8 through $5FFF. The initial bank assignment is determined by bytes $070 through $077 in the file.
NSF Address Register ==== ========== ======== $070 $8000-8FFF $5FF8 $071 $9000-9FFF $5FF9 $072 $A000-AFFF $5FFA $073 $B000-BFFF $5FFB $074 $C000-CFFF $5FFC $075 $D000-DFFF $5FFD $076 $E000-EFFF $5FFE $077 $F000-FFFF $5FFF
The initial bank assignment should be done before any call to the INIT routine. Once the ROM image has been built from the NSF file, this can be set up simply by writing the 8 values from the file header $070-077 to the corresponding registers $5FF8-$5FFF.
If the INIT routine needs to change the bank assignments based on the selected song, it may do so by writing the bank control registers.
If the FDS expansion is enabled, bank switching operates slightly differently. Two additional registers at $5FF6 and $5FF7 control the banks $6000-6FFF and $7000-7FFF respectively, and the initial load values at $076 and $077 now specify the banks used for $6000-7FFF as well as $E000-FFFF (these regions will both be set up to use the same banks before INIT is called).
Because the FDS has a RAM area at $8000-DFFF for the disk image to be loaded to, that means this area is writable when the FDS expansion is enabled. Some NSF player implementations will treat this like bankswitched RAM, and some players will treat an FDS bank switch operation as a copy into RAM. Hardware players are more likely to use bankswitched RAM.
This has a number of caveats:
See also the notes on multi-chip tunes below.
METROID.NSF will be used for the following explanation.
The file is set up like so: (starting at $070 in the file) $070: 05 05 05 05 05 05 05 05 $078: 00 00 00 00 00 00 00 00 $080: ... music data goes here...
Since $070-$077 are something other than $00, this NSF is using bank switching. The load address given is $8000. The load address AND $0FFF specifies 0 bytes of padding, so we set up our ROM image with contiguous data starting from $080 in the file.
This NSF has 6 4k banks in it, numbered 0 through 5. It specifies that each of the 8 memory regions should be switched to bank 5, which begins at $05 * $1000 bytes in the ROM image.
The desired song number is loaded into the accumulator register A, and the X register is set to specify specify PAL (X=1) or NTSC (X=0).
Valid song numbers are 0 to one less than the number of songs (specified at $006 in the header). The first selected song is in the header at $007. The NSF player should display to the user song numbers from 1 up to and including the number of songs, and these should correspond to the same number - 1 loaded into register A. Note that when choosing the first song from the value in $007, subtract 1 from it before loading that value into register A.
The INIT routine MUST finish with an RTS instruction before music playback will begin. At this point, the NSF player will begin executing the PLAY routine at the specified interval.
If this is a single standard tune (PAL or NTSC but not both) the INIT routine MAY ignore the X register. Otherwise, it SHOULD use this value to determine how to set pitches and tempo for the appropriate platform.
The use of the $4017 register is not well supported by existing NSF players. The NSF should not normally clear bit 6 (the IRQ disable bit), though the Pseudo-IRQ Technique relies on being able to do this.
While the NSF1 specification never guaranteed anything for Y on entry to INIT, for better forward compatibility with NSF2's non-returning INIT feature, it is recommended that the player set Y to 0, or at least some value that is not $80 or $81, before calling INIT.
Once the tune has been initialized, it can now be played. To do this, simply call the routine at the PLAY address at the rate determined by the file header at $06E-06F (NTSC) or $078-079 (PAL).
The playback rate is determined by this formula:
1000000 1000000 rate = --------- period = --------- period speed
Where period is the value you place at $06E-$06F in the file, and rate is how often the PLAY routine should be called in Hz.
The following playback rates are common:
Nonstandard rates may be difficult for hardware players. If the rate is much faster the PLAY routine may not be short enough to execute in the specified amount of time.
The PLAY routine will be called at the specified interval. If the X register passed to INIT was 1 (PAL), it will be called at the rate specified by $078-079, and if 0 (NTSC), it will use the rate at $06E-06F.
A PLAY routine should normally finish with an RTS instruction, but is not required to do so. A non-returning PLAY will cause problems for NSF players that use the same CPU to control the user interface and to run the NSF, such as NSF players that run on an NES. It is strongly recommended to return every few frames if at all possible, such as when no PCM is playing. If PLAY takes longer to finish than the specified interval, that interval may be skipped and PLAY may not be called again until the next one.
Some popular modern NSF engines use a non-returning PLAY to implement an output stream of PCM sound (e.g. SuperNSF, MUSE, Deflemask), and this can also be combined with a Pseudo-IRQ technique.
Byte $07B of the file stores the sound chip flags. If a particular flag is set, those sound registers should be enabled. If the flag is clear, then those registers should be disabled. All I/O registers within $8000-FFFF are write only and must not disrupt music code that happens to be stored there. Some audio register addresses have mirrors in their original hardware mappers, but NSF code should use only the lowest address for each register, listed here.
Notes:
Notes:
Multiple expansion chips can be used at the same time, but because this was not something that was ever supported by an original Famicom games, actual practice with multi-expansion NSF varies.
Some mappers mirror their audio registers at addresses that would conflict. Many NSF players only support the lowest address, which avoids these conflicts, but the following conflicts may need resolution in an attempted hardware multi-chip implementation:
These lists all the addresses which should be readable by the code in the NSF; no other addresses should ever be accessed for reading:
These lists all the addresses which should be writable by the code in the NSF; no other addresses should ever be accessed for writing:
Reading/writing anything other than specified here results in undefined behaviour.
Some modern NSFs use a trick[1] first made popular by Deflemask, primarily intended to support PCM sample playback. This technique is not universally supported, because it may rely on a lack of conflict with the player's implementation. Some hardware implementations do support it correctly (e.g. PowerPak), and it also works with several software NSF players.
The technique uses a non-returning PLAY in the following way:
Categories: Audio, File formats