Music Step By Step

From Uzebox Wiki
Revision as of 07:37, 27 March 2010 by D3thAdd3r (talk | contribs)
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 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 could even create them yourself. If you have not already done so, you need read and understand Sound Engine before we get started. We will be using the tool midiconvert, get it here[1]. If you downloaded the whole kernel in a zip file it should be included. This tool requires that the source MIDI file be in format 0, where all events are in a single track. The 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.



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


  • 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 sound effect.


  • 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 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 an MIDI you like. Quite often you may wish to make an MIDI from an NSF using NSF2MIDI. Generally it makes MIDI files that require less manual processing to be usable by our conversion tool. Files you find around the net didn't have the Uzebox in mind so you may have some work to do getting those to sound right. We will discuss that later on. I will assume we will be working off an MIDI that we created with NSF2MIDI for this tutorial, but the same steps apply irregardless. 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 setting 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

Often it will occur where an MIDI needs 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 an MIDI 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 if 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 other 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 with to do is copy a channel like that and Paste Insert into another or a piece of another. Now the channel contain notes from both and you have just save 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. Here is an example of this midi after just a little workFile:Megabombercrippled.hex. See, this massage had a happy ending.


Overlap.png


Look at the above and keep in mind 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. If the entire song is polluted with these situations, you might be time ahead to look for a new source file. If you have your heart set on it, you will want to stop the long note at the start of the short note. Then at the exact end of the short note trigger the long note again so that it plays all the way to it's original end point. We split it into 2 notes 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". 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. In the case of multiple notes of the same length and position, keep the higher notes if it is a lead track. You will get the hang of it.

Another important item that needs mentioning is the event list. 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, and 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 an program change event pointing to a new patch(with the sound you want) 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 they 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
  • Tremelo //use a tremelo(volume shifting up and down) effect on the current note
  • Tremelo Rate //speed that the tremelo effect operates at


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 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), for channel 4 we never have to worry about a sound effect clobbering a whole 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 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. It doesn't matter which channels you use for the first 3 as long as the appropriate patch is used for the sound you want. The patch that will be played is the instrument number, so Acoustic Grand would play patch 0 etc. 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 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, who'd of thunk it?