25. Importing a MIDI to Famitracker

I’ve read every webpage on this subject, and not one explains how to do this. It’s not easy, because they never got the Import MIDI feature working right in Famitracker…In fact, they removed that feature. You have to download version 0.4.2 to use that feature.

http://famitracker.com/downloads.php

I create MIDI files by connecting a MIDI keyboard to my computer with a MIDI to USB cable. I record with a program called REAPER. It costs $60, and you can use it for free for 60 days… (I’m using version 5.12 for this example). I highly recommend it for all music production, except sound editing…for that I use Audacity. Here’s the REAPER website.

http://www.reaper.fm/

First thing…you’re going to want to use a virtual instrument VST or VSTi. This has no effect on the output file, but it will help you hear the MIDI track. I’m pretty sure that Reaper has some default VST instruments that would work fine. But, I also found this one, which simulates the 2A03 chip (NES sound).

http://www.mattmontag.com/projects-page/nintendo-vst

Go to OPTIONS/PREFERENCES/MIDI/ and change the ‘Ticks per Quarter Note’ to 96.

Click INSERT / Virtual Instrument. Find the VST-NES. (I set it to polyphonic). Listen to a metronome set to 120 BPM (the same as the project speed). Try to hit every note in beat with the metronome. By default the VST track you just added should be ‘Armed for record’ (the red circle by the name of the track). That’s what we want. Now, hit record (it’s sort of in the middle on the left – by the play/pause buttons.)

Reaper1

I prefer to play on a MIDI keyboard (while listening to the headphone output of the keyboard — and a metronome — rather than listening to the computer…because there will always be some annoying latency). You can also play using the virtual keyboard (you have to click on it for it to work). It is mapped to letters on your computer keyboard. You can change the mapping by right clicking on the virtual keyboard.

When done recording, hit stop.

Now, double-click on the MIDI track. If you did a fair job of playing on the beat, the notes will be mostly lined up to the grid. Now, click EDIT/QUANTIZE…’use the grid’, ‘all events’, and ‘position and note end’. Now all the notes should be perfectly lined up. If some of them are out of position, move them around as needed.

Quantizing works better with certain grid settings than others. At the bottom of the MIDI editor, where it says ‘Grid’…set it to 1/8, or something similar.

You might want to only record a single note at a time (ie, no chords). In my example here there will be up to 2 notes at the same time. To get it to load correctly in Famitracker, you have to put the second note on a different channel. By default all the notes will be on channel 1. Select all the notes you want to switch channels. (I like to put bass notes in the triangle channel, because it can go an octave lower than the square channel.) To select notes (from the piano roll MIDI editor) right-click and drag while holding down CTRL. Once you’ve selected all the notes, right-click one of them, click ‘Note Channel’, 3 (for example).

Reaper2

OK, now we’re almost done…

While still in the MIDI editor screen, click… FILE/EXPORT TO NEW MIDI FILE, and save it.

Now, Open Famitracker 0.4.2. (the last version to have a MIDI import feature).

Click FILE/IMPORT MIDI, and I have the lower notes (Channel 3) going to the Triangle Channel, and the rest (Channel 1) going to square one. The default pattern length of 128 is probably going to work fine, we’ll keep it there.

Famitracker usually calculates the number of frames wrong, just click ‘arrow up’ next to ‘Frames’ to see the last bits of the MIDI track.

Set the speed to about 5 – 10, tempo 150. Add 3 new instruments (with volume and duty sequences). Now save, and close Famitracker, and open the file with the newest (more stable) version of Famitracker.

All the Triangle channel notes will be an Octave too low. Click somewhere on the Triangle track. CTRL-A (select all) and then Right-Click on the Triangle track. TRANSPOSE/INCREASE OCTAVE. If you have multiple frames, you will probably have to repeat this for every frame.

And, we’re done. Sounds right to me. That was easy, right?

FT3

If you need to bump things up or down… INSERT moves everything down from the highlighted point. BACKSPACE will move everything up from the highlighted point (deleting the one above it).

I’ve tried this with some freeware MIDI editors, but they just don’t have the features of REAPER. I’m sure many of the better DAWs out there will do the same thing, but you just can’t beat the $60 price tag.

(Thanks to Bavi_H for improving this technique / added information).

Advertisements

24. MMC3, Bank-switching, IRQs

(Thanks to thefox for pointing out an error in my example code, see note at the very bottom of the page)

So far, all I’ve been using is small NROM sized .nes files. I’m going to show how to set up a much larger .nes file using the MMC3 mapper. I don’t know every mapper, but I know the MMC3, so I’ll use that for my example. NROM was the first cartridge design, but they soon used up the 32k bytes of PRG ROM (code), and especially the 8k of CHR ROM (graphics). A mapper is a way to trick the NES into accessing more ROM, by swapping (mapping) banks in and out of the CPU memory.

I’m going to pretend that I’m designing for a real actual NES cartridge, and use the actual size of an actual MMC3 board. According to this website…

http://kevtris.org/mappers/mmc3/

The choices we have, are…

Max. 64K PRG, 64K CHR
Max. 512K PRG, 64K CHR
Max. 512K PRG, VRAM
Max. 512K PRG, 256K CHR
Max. 128K PRG, 64K CHR, 8K CHR RAM

(and some others that I omitted). I’m going to use the smallest example, 64k and 64k. First, we have to set this up correctly in the header. The header is a few bytes of metadata that is used by emulators, so it knows which mapper we’re using, and how many banks, etc. Here’s how it should look for our 64/64 MMC3…

.byte $4e,$45,$53,$1a
.byte $04   ; = 4 x $4000 bytes of PRG ROM
.byte $08  ; = 8 x $2000 bytes of CHR ROM
.byte $40  ; = mapper # 4 = MMC3

Now, we need to set up the .cfg file for multiple banks…

#ROM Addresses:
#they are all at $8000, because I will be swapping them into that bank
PRG0: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG1: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG2: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG3: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG4: start = $8000, size = $2000, file = %O ,fill = yes, define = yes;
PRG5: start = $a000, size = $2000, file = %O ,fill = yes, define = yes;
PRG6: start = $c000, size = $2000, file = %O ,fill = yes, define = yes;
PRG7: start = $e000, size = $1ffa, file = %O ,fill = yes, define = yes;

# Hardware Vectors at end of the ROM
VECTORS: start = $fffa, size = $6, file = %O, fill = yes;

Actually, what the $8000 does here, is every label inside that bank will be given an address indexing from the start of that bank + $8000. I actually only have code in the last bank, so I could put the start address anywhere, and it would work the same, but you will probably have code in some of these banks, and so you need to give the code the correct addresses for where it will actually be going when it’s swapped in.

And, defined these segments in the .cfg file…

 

SEGMENTS {
HEADER:   load = HEADER,         type = ro;
CODE0:    load = PRG0,           type = ro,  define = yes;
CODE1:    load = PRG1,           type = ro,  define = yes;
CODE2:    load = PRG2,           type = ro,  define = yes;
CODE3:    load = PRG3,           type = ro,  define = yes;
CODE4:    load = PRG4,           type = ro,  define = yes;
CODE5:    load = PRG5,           type = ro,  define = yes;
CODE6:    load = PRG6,           type = ro,  define = yes;
STARTUP:  load = PRG7,           type = ro,  define = yes;
CODE:     load = PRG7,           type = ro,  define = yes;
VECTORS:  load = VECTORS,        type = ro;
CHARS:    load = CHR,            type = rw;

BSS:      load = RAM,            type = bss, define = yes;
HEAP:     load = RAM,            type = bss, optional = yes;
ZEROPAGE: load = ZP,             type = zp;
#OAM:   load = OAM1,    type = bss, define = yes;
}

(the OAM segment is not used in this example).

Ok, now I’m going to write something in each bank, so we can see how it loads into the ROM file. I’m writting the words “Bank0”, “Bank1”, etc. in every bank. And, I’m going to load those words onto the screen, so we can see the switch visually. (I set it to be triggered by pressing ‘Start’).

I had to write a bunch of PRAGMAs so that each bank will be compiled into the correct bank. Like this…

#pragma rodata-name (“CODE0”)
#pragma code-name (“CODE0”)
const unsigned char TEXT1[]={
“Bank0”};

#pragma rodata-name (“CODE1”)
#pragma code-name (“CODE1”)
const unsigned char TEXT2[]={
“Bank1”};

#pragma rodata-name (“CODE2”)
#pragma code-name (“CODE2”)
const unsigned char TEXT3[]={
“Bank2”};

etc. And when START is pressed, it will switch banks into CPU addresses $8000-9fff, and then load the first 5 bytes of that bank and write it to the screen, with this code…

void Draw_Bank_Num(void){ //this draws some text to the screen
PPU_ADDRESS = 0x20;
PPU_ADDRESS = 0xa6;
for (index = 0;index < 5;++index){
PPU_DATA = TEXT1[index];
}
PPU_ADDRESS = 0;
PPU_ADDRESS = 0;
}

When this compiles, it will write the address of TEXT1 into the code. It’s the only thing in the first bank (bank #0), and in the .cfg file, I defined that bank to start at $8000. So, it will be fetching the first 5 bytes from $8000-8004. That is the bank that I keep switching, so every time it goes here, it will be pulling those 5 bytes from whatever bank is mapped to $8000. Here’s the code that switches which bank will be mapped to addresses $8000-9fff…

if (((joypad1old & START) == 0)&&((joypad1 & START) != 0)){
++PRGbank;
if (PRGbank > 7) PRGbank = 0;
*((unsigned char*)0x8000) = 6; //bankswitch a PRG bank into $8000
*((unsigned char*)0x8001) = PRGbank;
Draw_Bank_Num(); //re-writes the text on the screen

I know, it looks like we’re storing 6 at address $8000. But, you can’t do that, because that’s a ROM address. What this does is send a signal to the MMC mapper that we want to switch a PRG bank into $8000. The next line defines which bank will be swapped in. You can get some more detailed info on the wiki…

http://wiki.nesdev.com/w/index.php/MMC3

I feel like this may be confusing. It’s an unfortunate coincidence, that the bank we’re swapping and the MMC3 register are both called $8000. If you wanted to instead swap a bank into the CPU address $a000-bfff, you would do this…

*((unsigned char*)0x8000) = 7; //bankswitch a PRG bank into $a000
*((unsigned char*)0x8001) = which_PRG_bank;

Is that clearer? Bank swapping is done with a $8000 / $8001 write combination.

I also added a few lines at the start of the main() function, which sets the initial state how everything should be mapped at the start. I don’t know for sure, but I think that the only bank that is certain at RESET is…that last PRG bank will definitely be at $e000-ffff. All our startup code should (ie. MUST) be located in that bank.

Now, that’s cool and all, but you will not be using bank swapping like this (having every bank have things located at fixed positions, like $8000). In reality, you will probably have an array of addresses at the start of every bank, which point to the location of data within the bank (that way, the data can be anywhere within the bank). If you have code in that bank, you will perhaps put a ‘JUMP TABLE’ at the start of the bank…that’s an array of addresses of the start of every function inside the bank. Essentially, the code in a fixed bank will read the address, and then jump (indirect) to that address. Or maybe, use the ‘push address to the stack and RTS’ Trick…

http://wiki.nesdev.com/w/index.php/RTS_Trick

That’s kind of complicated ASM stuff, but it might be worthwhile learning it, if you’re going to make the most of using multiple banks.

Anyway, I wanted to add a cool ‘moving background’ effect. This effect can be done several ways, but I think bank swapping CHR ROM is the easiest. This code waits 4 frames, and then switches which CHR banks will be mapped to $0000-$03ff of the PPU. When the PPU goes to draw tile #23 to the screen, the mapper will direct it to tile #23 of a specific CHR bank in the ROM.

MMC3 actually breaks the CHR ROM into $400 byte chunks (64 tiles), so bank 0 = the first $400 bytes, 1 = the next $400 bytes, etc. It takes multiple MMC map writes to fill the PPU full of new tiles. I’m just changing that first $400 bytes (PPU addresses 0-$3ff). I made a little waterfall. There are 4 nearly identical CHR ROM banks, with the water tiles shifted downward 1 pixel each bank down.

lesson19

Here’s the link to the source code. Press ‘START’ to see the PRG ROM bank switch.

http://dl.dropboxusercontent.com/s/gl73mp2nr1rpdzl/lesson19.zip

 

Now, that’s not all MMC3 can do…it can also count scanlines. Normally, you would need to set up a Sprite Zero hit to time something to happen midframe, and you can only do that once. With MMC3, you can time multiple things to happen midframe, like changing the Scroll, or swapping CHR ROM, or other cool tricks. I’m going to change the scroll, about every 20 lines. You don’t have to sit and wait for those 20 lines, the MMC3 mapper will count for you, and you can go on to do other things (game logic). It will generate an IRQ, and jump to the IRQ code. I have the IRQ code changing the Horizontal Scroll (several times a frame).

Things we need to do…The first line of every NES game (startup code) is to turn off interrupts. But, that’s what an IRQ is, so in our main() function, I turned interrupts back on.

asm (“cli”); //turns ON IRQ interrupts

Also, I have to make sure that the vectors at the end of the reset.s code is pointing to the address of the IRQ code.

Now, during V-blank (you can turn this on any time, I just wanted to start it at the top of the screen) I set the MMC3 to start counting scanlines with this code…

*((unsigned char*)0xe000) = 1; //turn off MMC3 IRQ
*((unsigned char*)0xc000) = 20; //count 20 scanlines, then IRQ
*((unsigned char*)0xc001) = 20;
*((unsigned char*)0xe001) = 1; //turn on MMC3 IRQ

Note: I think it skips the first scanline, so it actually doesn’t generate an IRQ until at the end of scanline 21. Now, I want to change the horizontal scroll, which isn’t a problem, but if I immediately tried to change the scroll, there would be a slight glitch (misalignment) of the screen at that point. I’m always amazed at how many professional games have these kind of glitches. Anyway, to avoid the glitch, you have to change the scroll during the very very very short H-blank period. What’s an H-blank? When the PPU is drawing the picture to your TV, it goes left to right, then it jumps from right to left (not drawing) very quickly. That’s the H-blank period.

Well, the MMC3 IRQ triggers right at the H-blank period, but by the time it jumps to the IRQ code, and you load a number to the scroll, it’s already drawing the next scanline. So, in order to get it to change the scroll during H-blank, we have to wait for the next one. I wrote a tiny little loop, to wait about 100 CPU cycles, and then switch the scroll position. I think I’m timing it just right, but each emulator seems to be just a tiny bit different (ie. inaccurate), so I can’t be sure.

After the H-scroll is changed, I set up another ‘wait 20 scanlines and IRQ’ bit. It’s a bit tricky to get it to split exactly where you want. I’ve noticed that actual games don’t do the wait loop like I’m doing here. What they do is have nothing but a flat single color at the scroll split point across the entire scanline, so the glitch isn’t visible. Or, they just have a big glitch and don’t worry about it.

If you want to see the glitch (so you know what I’m talking about), edit that tiny wait loop (in the IRQ code in reset.s) to be just 1 number bigger, or 1 number smaller. Recompile it. Glitches at every split! The H-blank is really that small.

lesson20

I still have ‘START’ change the bank number on screen…if you can read it. Here’s the link to the source code…

http://dl.dropboxusercontent.com/s/1435iwsn62kixvg/lesson20.zip

 

EDIT:

It occurred to me that, maybe people won’t want to recompile this, but still want to see the glitch thing I’ve been yapping about. Here’s an animated gif, with the wait loop off by just 1 loop. Look at the right side of the screen, the last scanline of each segment is misaligned, and that misalignment changes each frame, so it kind of dances around oddly. That’s just being a few pixels off on the scroll split…imagine if the Scroll split was done halfway into the scanline. You’d have one scanline of each segment be as much as 80-100 pixels out of alignment. That would look terrible, and be distracting.

Glitch

You might wonder why we would split the screen like this anyway? For parallax scrolling. Go to YouTube, and search for NES and Parallax Scrolling. You’ll notice also, what I mentioned earlier, about most games do their scroll splits at a flat mono-color portion of the screen so glitches aren’t noticable. That would have been better (and easier) than trying to carefully time an H-blank split.

 

NOTE about the error I made (and fixed). I named the first bank “CODE” in the .cfg file and defined it to be at $8000, and it was a swappable bank. Apparently “CODE” is the default name that the C compiler uses to put all the C library functions. We can’t have that in a swappable bank, because if you go to call one of those C library functions (really, most code in C uses them) the bank that contains them might not be in place, and the game would crash. So, I called the last bank “CODE”. That’s the fixed bank. It will always be in place. Now, our C library functions will always be in the right position.

The other error that I fixed, was the IRQ code in “lesson20/reset.s”. If the C code was doing anything that required the C stack or the C variables when the IRQ was called…doing any more C functions inside the IRQ handler will screw up the stack/variables, and when the IRQ is finished, and it jumps back to the MAIN() function, the game will promptly crash. So, I rewrote the entire IRQ code in ASM, to make sure none of the C stack / C variables are affected. Here’s a link about that…

http://www.cc65.org/faq.php#IntHandlers

 

23. Using DMC Sounds

I’m going to explain how to use Famitone2 and Famitracker to add DMC sound samples to your game…first let’s review how the DMC channel works…here’s some code…

*((unsigned char*)0x4015) = 0x0f; //turn off DMC

//this controls which channels are on/off, DMC is the 0x10 bit

*((unsigned char*)0x4010) = 0x0f; //set the sample rate, f = highest

ADDRESS = 0xf000; //or whatever is the location of the DMC sample in the ROM

//the DMC samples MUST be located between c000 and ffff in the ROM

*((unsigned char*)0x4012) = (ADDRESS & 0x3fff) >> 6; // 0xf000 => 0xc0

LENGTH = 0x0101; //Actual length of a sample (in hex)

*((unsigned char*)0x4013) = LENGTH >> 4; // 0x0101 => 0x10

*((unsigned char*)0x4015) = 0x1f; //turn back on DMC channel

//any time DMC channel is turned on, it triggers the DMC sample to play

Ok, well, Famitone2 does all this for you, but if you ever wanted to add a DMC sample without Famitone2, this would the sequence of code to make it work. Here’s some more thoughts about DMC usage. Keep the samples very short. I use 0.1-0.5 second samples. You can use more/longer samples with a slower sample rate, but they will all have an annoying buzzing sound in them and poor quality. Also, DMC samples are only about half as loud as the other music channels…so if you want to balance the mix, you should cut the volume of the other channels by half.

 

Anyway. We are going to use the simple platformer code again, and add a Famitracker song that uses DMC samples for drums. I’m using some royalty free sounds samples that I got on a free CD many years ago. I edited them for length (shorter = better). Then I imported them into Famitracker. (You have to click on instrument #0, and then the DPCM tab).

DMC2

After importing the files, save them as DMC files. Assign each sample to a Key (on the left) and now you can enter them into the song under the DPCM column. Save the finished song, and export it as a .txt file. Bring that over to Famitone2/tools, and run the text2data program to convert it into a .s and .dmc file. (It’s a command prompt .exe)

text2data DMCmusic.txt -ca65

Now, I had to do a few things to get it to play…I enabled DMC (and SoundFx) for Famitone2 (.define in my reset.s file). And, I defined the start location “FT_DPCM_OFF” to be at $f000. Then, I included the files at the bottom of the reset.s file. I made sure the DMC samples were in the .segment “SAMPLES” which I had to add to the .CFG file (and define it to be at $f000).

At this point, Famitone2 takes care of the rest. I’m just playing the song the same as we did on the “Adding Music” page, and it will trigger the DMC samples for you in the music code of famitone.s.

I also added a non-DMC sound effect by making a Famitracker file and saving as NSF file, and using the famitone2/tools/nsf2data program (see “Adding Sound Effects”), triggered when the character jumps. There, done.

http://dl.dropboxusercontent.com/s/k00shsgd63f9a09/lesson17.zip

 

Now, I want to use some DMC sound effects. I decided to use the same song, but I changed the drums to Noise Channel (so it won’t cut in and out when a sound effect is played).

Famitone2 makes you add DMC sound effects into the song. Must be on instrument #0. I exported a .txt from Famitracker, and used text2data again. It created a .s and .dmc file. Basically same as above, exept I didn’t use the DMC sample in the song.

DMC3

Now, to call the sound effect from the C code, we need to do a fastcall to the famitone2.s label FamiToneSamplePlay but we need to add an underscore, I just added this above it…_DMC_PLAY (and added the line .export _DMC_PLAY). Now, I added a ‘fastcall’ function to the C code…

void __fastcall__ DMC_PLAY(unsigned char effect);

And, we need to give it a 1 byte value, equal to the DMC samples value. Now, I thought that their values would be #1 and #2. When I tried that, I got nothing. So, I looked closely at the DMCmusic2.s file (which defines each sample), and for some reason, it put the samples at #25 and #27. Here, look…

DMC

I don’t know why they’re at 25 and 27, but…whatever.

* It was because I chose note C-3 and D-3, which are the 25th and 27th notes on the scale…Shiru starts it at C-1,  I think.

You call them in the C code like this…

DMC_PLAY(27);

I have it set to play sample 1 when you jump, and play sample 2 when you press ‘START’.

Here’s the link…

http://dl.dropboxusercontent.com/s/eo92hyp4ms5mqhs/lesson18.zip