| Level 0 | Level 1 | Level 2 | Level 3 | Level 4 |
| Level 5 | Level 6 | Level 7 | Level 8 | Level 9 |
| Level 10 | Level 11 | Level 12 | Level 13 | Level 14 |
| Level 15 | Level 16 | Level 17 | Level 18 | Level 19 |
So far you've learned how to rip various NSF's based on company and many other basic methods that you can take with you no matter what NSF that you attempt to rip. You will not always be successful at ripping an NSF and maybe you can rip the NSF and it has emulation issues such as working in one emulator or player and not in another. Or maybe it sounds decent on one player and not the other, etc. It will be your job to try and make sure that a NSF is compatible with all players and emulators. Chances are that if your NSF plays in all NSF players and emulators, the rip will have a better chance of playing on the real hardware. Yes, there is a NSF hardware player designed by Kevin Horton, that's usable with CopyNES.
So now it comes to the point where you would like to rip NSF's from many different games. You can attempt to rip any NSF at will, given some determination and effort is given. Keep in mind the many different company formats, most of the time you can rip an NSF instantly when you run into such a game. Capcom, Data East, Tecmo, Nintendo, Sunsoft, etc - these are the companies that use the same music driver format for nearly all of their games. There are exceptions and don't expect a game to use the same format. Debug and have fun with it.
Now it's time to mention the basics again, I will cover a few of them below.
Load address is the origin, start of the program code, beginnings of the NSF. The load address is commonly and most likely at $8000, which is the starting address of active ROM in memory for the NES gaming system. If you have trimmed data from the beginning of the bank, the load address must be adjusted in the NSF header. Also, according to the NSF spec in bank switching which is the second step in initializing the tunes which would use load address AND 0FFF.
Play address. Usually this is quite simple, the entry point is almost always found in the NMI interrupt routine, using an emulator like FCEUXDSP can help by setting break points to sound registers and in tracing the NMI code itself. When the entry point is not found in the NMI interrupt, you can trace back in the code from the sound register break point. Using the stack viewer in FCEUXDSP can help trace back in the code.
Init address. The elusive init address call is the life and death of a successful NSF rip in most cases. If you cannot find or design a proper init address call, the NSF will not play or work properly. An init routine is code that initializes RAM addresses, sets up the data blocks and calls the tune based on the number of the tune, commonly from an index or LUT (Look Up Table). A game can also have more than one init address, I've seen this in games and in some that use expansion sound like FDS rips for example.
Also a game can have what is called a bootstrap routine. This "bootstrap" code is usually accessed from the Reset interrupt or just before the main init called is called somewhere in the game code. There are also games that do not have an init routine to speak of. These type of games sometimes require more effort in discovering what addresses change the tune and you may have to initialize other addresses to make sure the NSF will play. Other than the RAM address that changes the tune, I've seen some addresses that needed to be initialized with 00 or even FF before the NSF would play.
You also have games that initialize the index registers, X or Y and then intializing some addresses that don't appear to be related to the sound driver somewhere deep in the game code. However, if you're familiar with the sound driver, you can possibly track these routines down from looking at a disassembly and viewing debugger code from FCEUXDSP. You can set up a table and load theses values using custom made code. You can also use a Indirect Jump routine to jump to these addresses in the same bank, again using custom code.
Those three address calls are most important to the NSF, so I mention them again in recap and some explanation even a couple years later after the first writing of this document as I've gained a better understanding of NSF ripping. I continue to learn more and rip NSF's that can be very difficult or as easy as many stated in this document. Now we can go over a brief analysis of the levels to understand what we have learned.
Level 0 - Gather tools, documents, emulators, NSF players, etc. I would also like to add to the list the following tools - FCEU MOD, Unofficial Nintendulator, FDS Explorer, NSF Optimizer, FCEUXDSP (NSF version updated by UGETAB) You can rip NSFs the old school way by using a hex editor, Nesticle and a disassembler (the way I used to do it). However, with the new tools available will help you to make better and more accurate rips, as well as the process being speeded up greatly.
Level 1 - This level shows you NES bank sizes and how to rip a NSF from a rom using NES2NSF, or using a hex editor to extract certain banks that contain the music driver. Then you prepend an NSF header to the bank and assign the Load, Init and Play address respectively to produce a playing NSF file. Also shows you to count the tunes and adjust in the NSF header.
Level 2 - This level shows you how to design a bootstrap code that inits a tune as well as games that apparently only have sound effects (there are other reasons too). Also shows you how to arrange tunes and sound effects. Be aware that many companies use the same driver format, like Data East for example. Filling out the header, with the name of game, artist/composer, company, etc.
Level 3 - This level discusses setting up a folder for your NSF ripping, as well as setting up DCC6502 to use in dissassembling the banks that you have selected to examine. A brief analysis of the sound registers which was taken from the APU Reference doc, nearly verbatim. This level shows you how to place your own custom init code in a certain place in the NSF. Also shows you bank joining, and in this case makes sure that the DPCM is present in the rip.
Level 4 - A little more of Level 3 ripping with a bit more hex editing and code that is more complex. Technos is the theme in this level, as that's the type of driver you're dealing with there.
Level 5 - This level once again deals with a Technos driver. You'll learn how to use a debugger and dump the contents of active memory that can isolate most if not all of the sound driver. Again in this level you'll be using some previous level techniques to rip NSF's.
Level 6 - This level teaches a few more debugging techniques using FCEUD, to deduce the play address more effectively. Discussion of memory addresses and how to design a basic init routine where only one address need be initialized for the tune switch, and how to deduce the location of the main init routine.
Level 7 - How to deal with old Nintendo music drivers and how to deal with a game that uses several different addresses that switch the tunes. A way to design an init routine to make sure that you can include the music and sound effects in your rip.
Level 8 - This level shows you how to deal with indirect routines that have code stored in WRAM and how to trace and deduce address calls.
Level 9 - This level deals with a pirate game and one that uses tons of init entry points for the tunes and how to consolidate them using an indirect jump routine.
Level 10 - This level deals with initializing the sound registers in WRAM so that the NSF will play. Sometimes you will need to do this, other times you will not. Keep a close eye on the games that write to the sound registers in WRAM.
Level 11 - This level states a method where you can isolate and dump the correct banks that contain the sound driver when you're dealing with a game that writes indirectly to the sound registers. Back in the day, Nesten would not snap on a indirect write.
Level 12 - This is the optimization level. I have covered some methods briefly, including paging optimization which is a lot more work but trims the NSF as much as you can by trimming the first and the last banks based on how you're loading the banks into NES memory, respectively. A warning to all; you don't want to optimize too much as this can potentially comprimise some part of the rip. I've done this a few times myself and figured it out sometime later.
Using all of the previous levels, you can potentially rip nearly all non-bank switching games there are in existance. There are exceptions to this rule and of course you'll need to be inventive in dealing with some games. Also, I might add that if you're using this document to learn how to rip NSF's, if you've gotten to this point you could consider yourself a Level 13 NSF ripper :), assuming that you can use the methods described in this level.
Tricks of the Trade
We will examine the game Final Fantasy 1. We are going to use Unofficial Nintendulator in this example. Unofficial Nintendulator has a very useful debugger with some debug functions that are not available in other emulators. That is one reason why I use many emulators to rip NSFs.
First set a write breakpoint to the sound registers when you're on the first screen with music which happens to be the prelude I believe, I usually set a range $4000 - $4009 to be on the safe side. The following code will be shown in the debugger.
B0C1 8D 01 40 STA $4001 = #FF B0C4 A5 BE LDA $BE = #CF B0C6 8D 02 40 STA $4002 = #FF B0C9 A5 BF LDA $BF = #02 B0CB 8D 03 40 STA $4003 = #FF B0CE A9 80 LDA #$80 B0D0 85 BF STA $BF = #02 B0D2 4C E1 B0 JMP $B0E1
You can trace this all the way back to find the play entry address which is address $B000. Now the init entry point is what you want and here is what we will do. While the debugger is still frozen and emulation stopped, uncheck the breakpoint on the sound register writes. Now what you'll do is set a read break point for addresses $8000 - $BFFF. I have chosen this range because this is where the code is located at and this mapper is Mapper 1 which is a 16K bank sized select game. Sometimes data will be located in the $C000 - $FFF9 area, but not this game. You will get a few different snaps, one of them is for some misc sound data (that you can continue to debug if you wish) and other snaps are for the sound data being read that you're looking for, you'll have to click run a few times to see what I'm talking about. Now for the code.
B1A3 A0 00 LDY #$00 B1A5 B1 18 LDA ($18),Y @ $80E1 = #07 B1A7 C9 C0 CMP #$C0 B1A9 B0 11 BCS $B1BC B1AB 20 50 B2 JSR $B250 B1AE B5 00 LDA $00,X @ $00B0 = #E1 B1B0 18 CLC B1B1 69 01 ADC #$01 B1B3 95 00 STA $00,X @ $00B0 = #E1 B1B5 B5 01 LDA $01,X @ $00B1 = #80 B1B7 69 00 ADC #$00 B1B9 95 01 STA $01,X @ $00B1 = #80
Let's see, by looking at the code, the data for this tune is at $80E1. If you continue to debug and track the data, you'll eventually find out that the data has a pointer table for each sound channel per tune.
Now for the good part of Unofficial Nintendulator. We have confirmed that the data is being loaded from the $8xxx range and the code is being executed at the $Bxxx range. We look at the PRG area on the debugger and note that you have 8 boxes and that means that each box is a 4K bank, perfect for NSF rippers. Each box will tell you the Offset of the bank loaded, where the bank came from in the ROM. $8000, $9000, $A000, $B000, $C000, $D000, $E000, $F000 - These are the boxes that are viewable and what do you know, What's in the $8000 box is Offset 34010 (yes, the iNES header is accounted for, don't add it), $B000 is 37010. After quite a bit more debugging, I deduced that $8000 - $BFFF is used for this music driver, the end of the bank could be trimmed afterwards.
The point of using this feature is that you could select Offset 34010 - 3800F from a hex editor and extract this bank from the ROM, driver would be extracted and isolated. Also useful in picking out banks to use for bankswitching NSFs, as you will see later on in this document.
Out of curiosity and the fact that you could eventually debug to this point in the ROM, let's go to Offset 34010 in the ROM and take a look in a hex editor. What do you know, any person that does a lot of hex editing will immediately recognize the data as pointers. Ok, let's show ya a few bytes.
C080BD81BC820000C1820B835783
Let's break this data string down a bit. CO80, could that be $80C0? Sure enough, it is and it's a pointer to a string of data. Evenually you'll find out that a group of three pointers are for one tune and one pointer represents one sound channel. This game use Square 1, Square 2, Triangle channels. So we have $80C0, $81BD, $82BC. Let's set a read breakpoint to address $80C0 and what do you know, we have a snap when you reset the game. Here is the code.
B1A5 B1 18 LDA ($18),Y @ $80C0 = #FD ; This is what we are looking for. B1A7 C9 C0 CMP #$C0 B1A9 B0 11 BCS $B1BC B1AB 20 50 B2 JSR $B250
So we found out where the data point is being loaded at and it's using address $18 in WRAM as an indirect read. The code that we are looking at is located at $B1A5, so then let's look up in the disassembly or the debugger that you're using and see what we can find. Ok, here we go.
$B050:B1 10 LDA ($10),Y @ $0018 = #$00 $B052:95 00 STA $00,X @ $0000 = #$00 $B054:C8 INY $B055:B1 10 LDA ($10),Y @ $0018 = #$00 $B057:95 01 STA $01,X @ $0001 = #$00 $B059:20 89 B1 JSR $B189
Ok, we are hot on the tracks of the entry point to the init code, let's keep looking up and here is what we shall see.
$B007:29 3F AND #$3F $B009:85 4B STA $004B = #$02 $B00B:A9 00 LDA #$00 $B00D:85 4C STA $004C = #$00 $B00F:A9 00 LDA #$00 $B011:85 7E STA $007E = #$00 $B013:8D 02 40 STA $4002 = #$FF $B016:8D 03 40 STA $4003 = #$FF $B019:8D 06 40 STA $4006 = #$FF $B01C:8D 07 40 STA $4007 = #$FF $B01F:8D 0A 40 STA $400A = #$FF $B022:8D 0B 40 STA $400B = #$FF $B025:8D 0E 40 STA $400E = #$FF $B028:A9 30 LDA #$30 $B02A:8D 00 40 STA $4000 = #$FF $B02D:8D 04 40 STA $4004 = #$FF $B030:8D 08 40 STA $4008 = #$FF $B033:8D 0C 40 STA $400C = #$FF $B036:A5 4B LDA $004B = #$02
This code is right after the BCC opcode, let's try address $B007 as our init entry point and what do you know, music comes out so nice and sweet, success is at hand in your NSF ripping. Have fun listening to the rip and don't even try to submit this rip. It was ripped by Necrosaro in 1999. This is the address chosen for the rip and we could shift the address up a bit to $B003 and use some additional code to conform to the original logic structure, but just the same the rip works just fine as it was ripped.
In summary this is a method to use in tracking down init addresses and/or to know where the data is located at in the ROM. Knowing where the data is located at can be useful in tracking down the banks for bankswitching NSFs. This method is very useful for NES music hackers as well.
Another trick of the trade is that when you have an NSF that just won't play no matter what address you chose for the init entry point, or what addresses you are poking. Well, you can open two instances of FCEUXDSP, one with the NSF and one with the ROM open and playing music. Open the hex editor from tools in the FCEUXDSP that is running the ROM and select a page from WRAM, copy and paste into the FCEUXDSP version that is running the NSF, chances are that if you have the play address correctly, the NSF will begin to play, but not always. You can tinker with this page and change values, you can then deduce what you need to look for in the disassembly, or in writing your own code to boot up the NSF. Make sure that you carefully choose which page you are pasting into WRAM, you should know which one to paste after looking at the disassembly.
If a given ROM is not supported in FCEUXDSP, then you can use FCEU MOD to dump any page of WRAM that you wish. Find a select area in the NSF and paste it there, make sure that you do not go out of bounds of the NES address range. You may have to delete an equal section in order to accomodate this new piece of data. In your custom init code, you will have to write some code in order to load the data back into the page from which you dumped it from. For example, this code will load the entire page back into Zero Page WRAM.
PHA LDA #$00 TAX LDA $8000,X STA $00,X INX CPX #$FF BCC lda_8000 PLA RTS
There are many more tricks to figure out how to get an NSF to play and now I leave this up to you to figure these things out, hopefully you will be able to use what I have shown you to make some killer NSF rips. One more thing, make sure that you are very careful in your choice as to which game that you wish to rip, many have already been ripped and/or are imcomplete. UGETAB has made a list of NSF rips from various sites and collection files. I often refer to this list.