SGI Audio Tools: Difference between revisions

m (A small clarity edit)
 
(18 intermediate revisions by the same user not shown)
Line 1:
== Introduction ==
The Nintendo 64 SDK comes with two "batteries included" audio libraries, the SGI Audio Tools and the N64SoundTools. The SGI Audio Tools are a collection of command-line tools for preparing samples and MIDI sequences for playback on the Nintendo 64. The N64SoundTools was written by Acclaim Studios Manchester (formerly Software Creations) and encompasses a kind of DAW for authoring and editing songs for the Nintendo 64.
TODO
 
This article hopes to give a step-by-step reference for authoring sounds and music with the SGI Audio Tools and playing them in a NuSystem-based game. While not as intuitive and straightforward as the N64SoundTools, there are advantages to having a collection of command-line tools as they're entirely scriptable and can help automate compiling/editing of sound data.
 
== Prerequisites ==
This article assumes you're familiar with the following terms/concepts:
* Audio samples
* ADSR and envelopes
* Sample rate
* MIDI
Line 29 ⟶ 32:
=== Compressing Sequence Data ===
==== Converting Your MIDI File(s) ====
MIDI files are generally either '''Type 0''' or '''Type 1'''. The former specifies all of the notes in a single "track" while the latter has multiple tracks, typically for each instrument. The SGI tools require MIDI files to be in Type 0 and provides the `<code>midicvt`</code> tool to convert to it. Programs such as [https://musescore.org/ MuseScore] likely export in Type 1, so it's usually a good idea to convert to Type 0 before continuing.
 
Programs such as [https://musescore.org/ MuseScore] likely export in Type 1, so it's usually a good idea to convert to Type 0 before continuing.
 
[[File:Midicvt_sample_image.png|frameless|Screenshot of <code>midicvt</code> run successfully.|alt=|500x500px]]
 
For each of your original MIDI files, run the following:
Line 38 ⟶ 45:
==== Compressing Your MIDI File(s) ====
Once your MIDI files have been converted to Type 0, we'll be converting them to a compressed sequence format specialized for embedded playback on the Nintendo 64.
 
The NuSystem library is written to use compressed MIDI files for songs. If you inspect the library, you'll notice that it uses a <code> ALCSPlayer</code> for storing/playing songs. It is possible to use uncompressed Type 0 MIDI, but you'll need to look into editing/rebuilding NuSystem or your own audio code with Nintendo's core audio library.
 
[[File:Midicomp usage.png|frameless|Midicomp being successfully used.|alt=|600x600px]]
 
For each of your converted MIDI files, run the following:
Line 45 ⟶ 56:
 
==== Compiling Your MIDI File(s) ====
Now that we've compressed each MIDI file, its time to compile them into one "song bank". This will be added to your ROM and loaded in at runtime. To do this, we'll be using the <code><sbc></code> tool.
 
Run the following command with each of your <code>cmf</code> files as parameters.
<br ><code>sbc -Osongs.sbk first_song_compressed.cmf second_song_compressed.cmf third_song_compressed.cmf</code>
 
[[File:Sbc used.png|frameless|sbc successfully used here|alt=|600x600px]]
 
The '''ordering is important''' here! Keep note of the order of each parameter, as when you're selecting your songs in your game's source code, you'll be indexing them as they're ordered here (eg: <code>first_song_compressed.cmf</code> will be <code>0</code>, second_song_compressed.cmf </code> will be <code>1</code>, etc.).
Line 92 ⟶ 105:
 
==== The Instrument Bank File ====
An instrument bank file usually has the file extension of <code>.ins</code>. Inside it contains one or more of each of the following:
* <code>envelope</code> section(s), indicating an [https://en.wikipedia.org/wiki/Envelope_(music) ADSR]
* <code>keymap</code> section(s), indicating the range of "piano keys" a sound occupies, as well as other data
* <code>sound</code> section(s), indicating a sampled sound as well as the <code>envelope</code> and <code>keymap</code> it uses
* <code>instrument</code> section(s), indicating a "MIDI instrument" with a volume, pan, and various <code>sound</code>s
* A single <code>bank</code> section, indicating the sample rate, and which <code>instrument</code>s correspond to which MIDI instrument numbers in your sequences. This will include a specialized instrument for the drumset channel.
 
==== envelope ====
The SGI Audio Tools represent an [https://en.wikipedia.org/wiki/Envelope_(music) ADSR] with <code>envelope</code>s. Volume for each of the ADSR points ranges from <code>0</code> to <code>127</code>. Time is modelled in microseconds for each of the ADSR points.
 
Different samples and sounds can use the same <code>envelope</code>, but your tracks will generally sound better if you ensure that each sample has a matching envelope. If you're unsure, it doesn't
 
An <code>envelope</code> looks like the following:
envelope AnExampleEnvelope
{
attackTime = 10000;
attackVolume = 127;
decayTime = 500000;
decayVolume = 100;
releaseTime = 200000;
}
 
In the example above, the volume goes from <code>0</code> to <code>127</code> in 10000 microseconds (the attack), then decays to 100 over <code>500000</code> microseconds. When the sound using is envelope ends, the sound fades out over <code>200000</code> microseconds. This should generally match up to your sample.
 
For more information, review the N64 SDK Documentation at [http://n64devkit.square7.ch/pro-man/pro18/18-01.htm#02-05 18.1.2.5].
 
==== keymap ====
A <code>keymap</code> represents a range of "keys" for a sound to cover. The [https://www.inspiredacoustics.com/en/MIDI_note_numbers_and_center_frequencies MIDI Standard] represents each of the western music pitches from <code>0</code> to <code>127</code>. <code>60</code> can be considered middle C.
 
A <code>keymap</code> looks like the following:
keymap AnExampleKeymap
{
velocityMin = 0;
velocityMax = 127;
keyMin = 0;
keyMax = 127;
keyBase = 60;
detune = 0;
}
The example above maps to every available pitch as <code>keyMin</code> is <code>0</code> and <code>keyMax</code> is <code>127</code>. <code>keyBase</code> represents the "reference pitch" to scale when changing keys. In the example above, a sample with the pitch of middle C should be used. Samples at different frequencies will require a different <code>keyBase</code> value.
 
For more information, review the N64 SDK Documentation at [http://n64devkit.square7.ch/pro-man/pro18/18-01.htm#02-04 18.1.2.4].
 
==== sound ====
A <code>sound</code> combines a <code>keymap</code>, <code>envelope</code>, and a compressed sample file together into a unit. A <code>sound</code> also has properties for stereo panning and volume from <code>0</code> to <code>127</code> each.
 
An example might look like:
sound AnExampleSound
{
use ("your/particular/path/to/compressed_song_sample.aifc");
pan = 64;
volume = 127;
keymap = AnExampleKeymap;
envelope = AnExampleEnvelope;
}
 
Note how the <code>keymap</code> and <code>envelope</code> parts correspond to names of our examples above.
 
For more information, review the N64 SDK Documentation at [http://n64devkit.square7.ch/pro-man/pro18/18-01.htm#02-03 18.1.2.3].
 
==== instrument ====
An <code>instrument</code> models a single MIDI instrument. It consists of one or more <code>sound</code>s.
 
An example <code>instrument</code> might look like:
 
instrument AnExampleInstrument
{
volume = 127;
pan = 64;
sound = AnExampleSound;
}
 
Note how <code>sound</code> property matches the name of an existing sound above.
 
An <code>instrument</code> can specify multiple <code>sound</code>s. For example, <code>GenMidiBank.inst</code> in the N64 SDK uses four sounds for a MIDI Cello:
 
instrument Cello
{
volume = 127;
pan = 64;
vibratoType = 128; /* 128, 129, 130, 131 */
vibratoRate = 222; /* 0 to 255 */
vibratoDepth = 6; /* 0 to 255 */
vibratoDelay = 1; /* 1 to 255 */
sound = Cello00;
sound = Cello01;
sound = Cello02;
sound = Cello03;
}
Each of the corresponding <code>sound</code>s have different <code>keymap</code>s and samples that cover different ranges of notes. This can produce nicer-quality audio as the pitch of a sample doesn't need to be distorted as much. The tradeoff being more audio memory required for your <code>instrument</code>, especially at higher sampling frequencies such as 44100Hz.
 
For more information, review the N64 SDK Documentation at [http://n64devkit.square7.ch/pro-man/pro18/18-01.htm#02-02 18.1.2.2].
 
==== bank ====
The <code>bank</code> section is a collection of <code>instrument</code> and the final piece of the puzzle for our file. Each [http://fmslogo.sourceforge.net/manual/midi-instrument.html MIDI instrument number] gets assigned a particular <code>instrument</code>.
 
An example <code>bank</code> might look like:
bank SongBank
{
sampleRate = 32000;
percussionDefault = Percussion_Kit;
instrument [0] = AnExampleSound;
instrument [65] = AnExampleAltoSax;
instrument [107] = AnExampleKoto;
}
Here we associate various <code>instrument</code>s with different MIDI instrument numbers. <code>0</code> represents MIDI notes that are played with an Acoustic Grand Piano, and we've told the audio library that we should use <code>AnExampleSound</code> as the voice of Acoustic Grand Piano. MIDI notes that use instrument <code>65</code> get associated with an instrument called <code> AnExampleAltoSax</code>.
 
You'll want the value for <code>sampleRate</code> to match the frequency your sample files are tuned to. This is the reason we converted all of our samples to the same rate with SoX above.
 
<code>percussionDefault</code> is explained in the following section.
 
Note that you aren't required to have an <code>instrument</code> associated with every MIDI instrument number. If your song, for example, is only a solo piano piece then you'd only need to worry about an <code>instrument</code> for <code>0</code>. It's best to only include sounds for MIDI instruments that you need. Anything else is audio memory that could be better spent elsewhere, such as sound effects or higher-frequency samples.
 
For more information, review the N64 SDK Documentation at [http://n64devkit.square7.ch/pro-man/pro18/18-01.htm#02-01 18.1.2.1]. Note that the example for <code>bank</code> in the manual says to use <code>program</code> for referencing an <code>instrument</code>. This isn't correct and the <code>ic</code> tool will give you an error if <code>program</code> is used.
 
==== Percussion Sounds ====
Percussion in MIDI is a bit unique in that [https://en.wikipedia.org/wiki/General_MIDI#Percussion channel 10 is reserved for percussion] and that each note maps to a specific instrument. "Middle C" has a note number of 60 which is always a high bongo sound on the percussion channel.
 
To accommodate this, we create a special <code>instrument</code> for percussive sounds. Each different instrument will have its own <code>sound</code>, <code>envelope</code>, and <code>keymap</code> that only covers its corresponding key.
 
An example percussion setup for an Electric Base Drum (MIDI key <code>36</code>) might look like the following:
keymap Percussive_Bass_Drum_1Keymap
{
velocityMin = 0;
velocityMax = 127;
keyMin = 36;
keyMax = 36;
keyBase = 36;
detune = 0;
}
 
sound Percussive_Bass_Drum_1Sound
{
use ("electric_bass_drum_sample.aifc");
pan = 64;
volume = 127;
keymap = Percussive_Bass_Drum_1Keymap;
envelope = SomeBassDrumEnvelope;
}
 
Which would then integrate into an example percussion <code>instrument</code>:
instrument Percussion_Kit
{
volume = 127;
pan = 64;
sound = Percussive_Bass_Drum_1Sound;
sound = Percussive_Acoustic_SnareSound;
sound = Percussive_Low_TomSound;
sound = Percussive_Open_Hi_HatSound;
sound = Percussive_High_Mid_TomSound;
sound = Percussive_Crash_Cymbal_1Sound;
sound = Percussive_High_TomSound;
sound = Percussive_Ride_Cymbal_1Sound;
sound = Percussive_High_BongoSound;
sound = Percussive_Low_BongoSound;
sound = Percussive_CabasaSound;
sound = Percussive_MaracasSound;
sound = Percussive_ShakerSound;
}
 
The <code>bank</code> would then set <code>percussionDefault</code> to be <code>Percussion_Kit</code>.
 
==== N64 SDK Example Instrument Bank ====
The N64 SDK has reference Instrument Banks at <code>ultra/usr/src/pr/assets/banks</code>. If you're ever stuck on how something should look or are getting errors with <code>ic</code>, they can be a helpful guide to see how things are done.
 
==== Compiling the Instrument Bank ====
We use the instrument compiler program (<code>ic</code>) to turn our Instrument Bank file into <code>.tbl</code> and <code>.ctl</code> files for running ingame.
 
Run <code>ic</code> on your <code>.ins</code> file like the following:
ic -OSongBank SongBank.ins
Note that <code>SongBank</code> in this case whatever you called your <code>.ins</code> file. Also, note the lack of space before the <code>-O</code> argument. This seems to be correct for the tool.
 
If your <code>.ins</code> file doesn't have any errors, you should see an output like this:
 
[[File:Ic success.png|frameless|A bunch of garbled output from the instrument compiler, but no specific line numbers.|alt=|600x600px]]
 
You should also then have <code>.tbl</code> and <code>.ctl</code> files in the same directory with the name you put before the <code>-O</code> parameter.
 
[[File:Ic new files.png|frameless|The CTL and TBL output files shown via the DIR command.|alt=|500x500px]]
 
If there are syntax or other errors in your <code>.ins</code> file, you might get an error message like this:
 
[[File:Ic error.png|frameless|The instrument compiler showing an error.|alt=|600x600px]]
 
Even though the output looks garbled, try not to be discouraged! The final bit of output will show the line number of the error. The first place to look is often the associated line.
 
[[File:Screen Shot 2020-10-06 at 10.05.28 PM.png|frameless|An Instrument Bank file with a missing semicolon on line 28/29.|alt=|500x500px]]
 
In this case, the example error message was caused by a missing semicolon on line 28/29.
 
Much like the C-family of programming languages, semicolons indicate the start/end of statements. If you're missing one, the instrument compiler might associate two lines as a whole. Be sure to check the lines above and below if you're not initially sure where the error might be.
 
=== Finishing up ===
Line 103 ⟶ 305:
 
== Playing a song with NuSystem ==
TODO
 
=== Linking the Audio Library ===
TODO
 
=== Setting up playback ===
TODO
 
=== Starting/stoping playback ===
TODO
 
== Making an Instrument Bank for Sound Effects ==
TODO
 
=== Looping ===
==== Looping Compressed Audio ====
TODO
 
See [http://n64devkit.square7.ch/pro-man/pro20/20-05.htm#01 20.5] of the N64 SDK for more information on this.
 
==== Looping Non-Compressed Audio ====
As NuSystem is primarily compiled to use compressed sequenced audio, this is outside the scope of this article. However, [http://n64devkit.square7.ch/pro-man/pro17/17-03.htm#04 17.3.4] in the N64 SDK can help with non-compressed sequences.
84

edits