Music Step By Step

From Uzebox Wiki
Jump to navigation Jump to search

Music Step By Step

Let's face it, even a great game can feel pretty lifeless without music. The goal today is to learn how to make music for your game. We will be using MIDI files and converting them to the format the Uzebox kernel requires. You can get these files anywhere, or you can even create them yourself. If you have not already done so, you need to read and understand Sound Engine before we get started.

We will be using the tool "midiconvert", get it here[1]. If you have downloaded the whole Uzebox kernel in a zip file "midiconvert" should be included. This tool requires that the source MIDI file be in format 0, where all events are in a single track. This tool works best when you have 120 ticks per quarter note. Let's jump into the process from the start, below are some tool's you will find useful for the tutorial.

Please note, this whole tutorial is only my understanding of how things work. I do not guarantee that every detail is accurate, but it should at least help you just starting out. Please note that the process is not entirely Anvil Studio specific. If you choose to use another program, it is likely it has the same capabilities but you'll need to figure it out yourself. I've come to like Anvil even with a few of it's quirks. Linux users should likely find this tutorial useful, as it appears the available programs mentioned below are pretty good.


  • Anvil Studio[2] - This is a good free MIDI development tool(Windows). Ubuntu users should find Rosegarden or Muse in normal repositories(seem pretty good).


  • NSF2MIDI[3] - This tool will convert NSF(NES Sound Format) files to MIDI files. The method I will describe is a way to use the created MIDI as a base for your music.


  • NSF File[4] - You will need a NSF file that has the music you want to reproduce.


  • MidiConv - This is the final tool turning your work into something compatible with the Uzebox Kernel. You will need java installed.


If you have completed Sound Effects An Easy Way you should already have most of these items setup. I recommend that you do glance at the Anvil Studio basic parts, I wont repeat them here.

Acquire MIDI

Find or create a MIDI file. Quite often you may wish to make a MIDI file from an NSF (NES Sound Format) file using the NSF2MIDI converter. Generally it makes MIDI files that require less manual processing to be usable by our conversion tool. MIDI files you find around the net did not have the Uzebox in mind when they were created, so you may have some work to do getting those files to sound right. If you are using such an MIDI, I HIGHLY recommend you open up a second instance of Anvil Studio and create a new blank song with the same number of tracks as your song. Then use copy and paste to move each track into the corresponding track in your new midi. This often times eliminates various problems you might have using the original. See the trouble shooting section or post on the forums if you still run into problems.

For this tutorial I will assume we will be working with a MIDI file that was created with NSF2MIDI, but the same steps apply regardless. Using NSF2MIDI is hopefully pretty straight forward so I wont get into every last detail on that. What I will mention is that once you find the song you like in that program, you should check out the patch editor.

Patchedit.png


This is the only place you might have to do some work. You'll see that there are 5 tabs representing 5 channels from the original music. You might not want to use the PCM from the original, you should click that tab and deactivate it. Alternatively, you could keep it and once you are inside Anvil Studio mix it into the 4th(Noise) channel. If you choose this method be prepared to manually set each of those PCM "notes" to the correct MIDI note representing the patch you want played for every MIDI event. This will be discussed in the next section.

You should also look into the other channels, the settings here could have huge impact on the size of the final output. This is because some song will have a lot of controllers for every note!!! On top of this the Uzebox does not currently support all these controllers. So if you are looking to keep the music small and you find that the song is doing this, cut some/all controllers. Don't worry you can still get it to sound very similar by creating the patches that will be played for the notes with controllers similar to the ones used. Now you only need to describe the controllers once, instead of for every note.

There is definitely some trial and error involved in this process but the results are worth it. I recommend(of course ;) ) you listen to the main level music in Adventures_Of_Lolo. Uze himself converted this song for me and created a patch for each channels that has controllers to mimic the original sound. If you have not played the original, rest assured this result is a dead ringer for it. The whole song takes only ~1.8k of flash to store, where as with all the controllers for every note...who knows.

Massage The MIDI

Sometimes, your MIDI file will need to be "massaged" to sound good on the Uzebox. Here are some common problems and how to fix them.


Clutter.png


Whoa! This does not fit into our 4 channels at all! This is what you'll often see if you just pull a MIDI file off the net. You will probably be able to make this useful still, but it could be a lot of work. First off, use headphones. Secondly, with that many channels it is likely that some of them are actually the same notes played with different instruments. The process you will need to do here is to mute every channel but one, and listen to it carefully. After you have done this back and forth you should have a pretty good idea of which channels are duplicates and which channels are the most important.

Some channels might only play when others do not(so you could combine the data into 1 using paste mix and appropriate instrument changing events). You need to figure out that process, but what you may wish to do is copy a channel like that and Paste Insert into another or a piece of another. Now the channel contains notes from both, and you have just saved one channel. Repeat this process, and scrap anything you don't need until you end up with all the most important stuff in 4 tracks(4th track being your percussion track of course). Here is an example of this MIDI file after just a little workFile:Megabombercrippled.hex. See, this massage had a happy ending.


Overlap.png


Look at the above and keep in mind that the Uzebox kernel will only play 1 note at a time per channel. If it is playing a note on a channel it will immediately start playing another one when it gets the command. So if you have the Piano Roll Editor up, you might notice notes whose duration overlaps the beginning of other notes. It will not work this way on the Uzebox.

For most songs this is ok and will sound good. Only in rare situations, where the long note needs to be held, we could split it into 2 notes. This is because when the short notes takes over the channel, there is not a new note event to tell the kernel to "keep the long note going". Of course the patch will play a second time, with any attack it has that might sound unnatural. You can skip the short note, or make a patch that sounds ok being triggered rapidly like that(instant attack). This is truly dependent on the song and you will understand after a while. After reading through my own tutorial, the less I say about this part to confuse you the better. Just leave it alone until you run across the need to figure it out :)

I hope that makes sense. Also looking closer at this music we see that 3 notes are triggered at once! This is a junk source file!!! At this point you would have to decide which notes to cut or put into different channels. If you are impetuous enough to fix everything, ..well good luck and have fun! But seriously, it's not that time consuming once you get a feel for everything and what needs to be removed and what stays. In the case of multiple notes of the same length and position, keep the higher notes if it is a lead melody track and lower if it is bass track. You will get the hang of it.


AnvilEventList.PNG


Another important item that needs mentioning is the event list seen above. In Anvil it is easily found by going to view->event list, and you can see all the events in each channel. This is really important because some songs will have a large amount of controllers at work. Often you will find multiple expression events for each note,(although the kernel handles expression?) the amount of extra space required is probably not worth it. If you really need to get a different sound for a certain part of a song, insert a program change event pointing to a new patch(with the sound you want, using pitch bends to simulate controllers if necessary) then point it back when you're done. Also I have noticed sometimes when you change the channel of a track to an existing channel, interesting things can happen! Not sure why, but Anvil does not always clean up the event list properly.

So if you are at loss for why you can't seem to control a channel, it is likely another channel has an event modifying the channel. It is pretty crazy and until I figured it out, I was totally at loss and very frustrated. Just a tip, when you want to swap the channels of 2 tracks make sure you point them each at a different unused channel. Then point them to their correct channels, this avoid any events getting mixed up. When you find an event you want to modify or delete, simply double click on it. From there you can change it's parameters or delete it. For quick deletion of multiple events, double click on each event and hit Alt-D. There are a lot of events in Midi but you only have to worry about the ones Uzebox handles. Anything else you should just delete for clarity, for your convenience the table below indicated the events that the Uzebox kernel will use. If you want to understand this better, I suggest you look at uzeboxSoundEngine.c where the whole midi stream is processed.


  Program Change - set the patch that will be triggered for channel
  Note On - triggers a patch on the channel
  Note Off - turns a patch off
  Note Volume - indicated the volume of the current note
  Tremolo - use a tremolo(volume shifting up and down) effect on the current note
  Tremolo Rate - speed that the tremolo effect operates at
  Slide/Slide_speed - use these to emulate expression events


The last piece you will likely need to work on is the percussion. This will play on the 4th channel on the Uzebox, but the kernel expects the notes to be specific values depending on what patch you want to play for each "hit". As example midi note 0 will trigger patch 0, note 1/patch 1, etc. Luckily there will usually be only a few or even one pattern through out the whole song, though the single note limit still applies so you may need to clean it up. What you can do is manually convert the notes to the patches you want played for one entire loop. Then copy that loop by dragging over all the notes horizontally and pressing ctr-c. Now delete all the notes, and start paste-inserting by clicking on the time bar above the notes and choosing it from the edit menu.

If you find your percussion is not lined up when you are done, you may not have selected the correct length of the pattern. You will want to double check it and make sure when you paste it, it will line up time-wise with the song. I wish I could explain it better but it will be easy after a little experimentation. When there are multiple patterns at work an easier approach may be to select all the notes in the track, and go to Edit->Transpose->Selected Notes. Make sure the diatonic box is not checked! Now you can move all your percussion notes downwards by a set value which is likely pretty close to midi note 0. Now you will still have to vertically align the proper notes to trigger the proper patches but at least you needn't drag them down many octaves.


The very last advanced advice I have comes from Uze. Essentially the method is to find all the patterns in the song, and create patches that match them. So instead of having separate midi events trigger separate noise patches, you merely need to trigger 1 patch at the beginning of wherever the pattern appears in your song. This really saves considerable space, and might actually be easier than tweaking all the individual notes. Here's an example from BC Dash[5]. Notice the patch has delays between the events matching a particular beat so you aren't storing redundant events over and over. You could probably apply this to the first channel as well(since sound effects wont steal that channel). If we don't use the 4th channel for effects we never have to worry about a sound effect clobbering a whole drum sequence. I really think the is the best way to go if you feel comfortable with it.

Now let's get back to the simple case where our NSF file turns out relatively good without too much screwing around. I'll assume you have already taken care of any parts described above.


Anvschannels.png


Once the file is in good shape you must set the channels as shown above. The conversion program will convert them directly like this, so whatever is track 1 will play on channel 1 on the Uzebox. Make sure you have the correct tracks in place. For this example I use channel 1&2 for the lead parts which will be played using an appropriate sounding patch. Channel 3 is a bass track using a patch similar to a bass guitar. Channel 4 will be the percussion. For channels 1-3 the patch that will be played is the instrument number, so if Channel 2 has the Acoustic Grand instrument in the editor, each note would play patch 0 on the Uzebox. Once you have it set up like this, save your file. Now go to File->Export MIDI-Format 0 file and save it to wherever you will be doing the conversion process. We are ready for the final step.

Final Conversion

This is the last thing you need to do to the MIDI, and it is the easiest. I will assume you understand how to use a command prompt/terminal and that you have the conversion program setup(Java installed correctly). You can run the converter with no arguments to see a print out of the flags you will be using, they are also described here Sound_Engine. I will only describe the ones you need to calculate.

Notetime.png

  • -f

This is the speed factor. As of right now I do not have a way to calculate the correct value(let me figure it out). If the song plays back too slow you will want to decrease this value, if it plays too fast then increase it. The normal value is 30 and 15 should play it back at twice the speed as example(?).

  • -s

This flag tells the kernel where the start of the song loop is. If you want the whole song repeated then you will set this to 0 to start from the very beginning. If there is an intro in the song that you only want played the first time, then you will enter the first MIDI tick after the intro. See the above example.

  • -e

This flag tells the kernel where the end of the song loop is. When this MIDI tick is reached, the kernel will jump to the position in the song defined with the -s flag.


Now what you should have is the converted song in the file you specified to the converter. Open this file up and copy it's contents to your game's source or a skeleton project(for faster compilation). Play back your song and listen. You will want to listen for notes that get stuck. If this occurs, you will want to apply one of the solutions mention in the sound engine section of the wiki. If you notice strange static continuously plays or your game crashes, you almost certain have the instrument numbers wrong or the percussion is wrong. What happens then is the kernel tries to play a patch that does not exist and you hear static from some piece of progmem. Follow the procedures described above. It does get easier, once you are through the trial and error of learning/remembering the key stuff, you will be putting out quality music easily.


Finishing Touches

Now you have your song converted, your notes playing correctly, and the speed is correct. Now begins the trial and error. What you will need to do is design patches that emulate the original sound of notes played in the song(on the NES). There is not much that can be written in stone on the subject, what I will do is list the patches (Uze created) that were used in Lolo. This is a general example but does sound good for a lot of songs as is. It assumes you included the default kernel waves.

  //INST: lead fast env       Channel 1....
  const char patch00[] PROGMEM ={ 
  0,PC_WAVE,4,
  0,PC_ENV_SPEED,-35,
  0,PATCH_END
  };
  //INST: lead slow env       Channel 2....
  const char patch01[] PROGMEM ={ 
  0,PC_WAVE,4,
  0,PC_ENV_SPEED,-10,
  0,PATCH_END
  };
  //INST: bass -  triangular  Channel 3...
  const char patch02[] PROGMEM ={	
  0,PC_WAVE,2,
  1,PC_NOTE_HOLD,0,
  1,PC_ENV_SPEED,-32,
  0,PATCH_END
  };
  //INST: hi-hat              Channel 4...
  const char patch03[] PROGMEM ={	
  0,PC_NOISE_PARAMS,1,
  0,PC_ENV_VOL,0x90,
  0,PC_ENV_SPEED,-30, 
  8,PC_NOTE_CUT,0,
  0,PATCH_END
  }; 
  const struct PatchStruct patches[] PROGMEM = {
  {0,NULL,patch00,0,0},
  {0,NULL,patch01,0,0},
  {0,NULL,patch02,0,0},
  {1,NULL,patch03,0,0},
  {0,NULL,patch04,0,0},
  };

From experience I have found that these are really good starting points for basically anything. I wont duplicate information that is available on the structure of patches. What I would recommend is you change the PC_ENV_SPEED first, for instance:

0,PC_ENV_SPEED,-45,

In the bomber man example above, I changed this in the lead 1 patch. What this does is give the note a sharper sound where it quickly stops after it starts. This was ideal due to the very rapid notes, and you may need to experiment a bit to find something close to the original. For the lead 2 I wanted a slightly more lazy sound so I set it to -20, this way your lead instruments each have a very distinct sound and it feels fuller.

The last part I will discuss on patches is PC_WAVE. This drastically alters the sound of the patch, because it changes what wave the patch works off. Look inside data\sounds.inc to see the different waves available. Experiment and you will acquire a good sense of how to get what you want, or just look at an existing patch with a sound close to what you want. Personally, I feel like I can get most songs to sound "right" by only modifying these 2 things. I spent a lot of trial and error and it turned out just to be that simple.