Midi Rendering and Sound Library

I wrote this library a number of years ago. This code was used in some homebrew code on portable gaming platforms like the GP2X.

Just like with my image library, this one is supposed to be self contained, and compile without any dependencies, on small or embeded systems.

Here is the library source code:

This library can read and write most basic MIDI and WAV files. It can also talk to sound hardware on Linux platforms. For MIDI, it uses wavetable synthesis, and reads SF2 Soundfont data for its instrument definitions.

Here’s some sample code to play a MIDI file in a loop. It’s pretty straight forward as you can see:

sound = R_InitSound(1, 16, 44100, 8196); // 8K buffer, 16bit samples at 44100 kHz
mixer = R_InitMixer();
bankset = readSF2("MINI.SF2"); // read instruments
buffersize = R_GetSoundDeviceBufferSize(sound);
rendered = R_CreateBlankSample(1, 16, 44100, buffersize);
R_InitSequence(sequence); // init sequencer

while(1){
ready = R_SendSoundBuffers(sound);
if (ready && R_IsMixerChannelReady(mixer, 0)){
R_SilenceSample(rendered);
R_RenderSequencetoSample(rendered, sequence, bankset, buffersize);
R_SetMixerChannelSample(mixer, 0, rendered);
}
R_MixSoundVoices(sound, mixer);
}

Here’s how you can convert a MIDI file to a WAV file without using any sound hardware.

bankset = readSF2("MINI.SF2"); 
sequence = readMIDI("input.mid");
R_InitSequence(sequence);
lastevent = sequence->lastevent->time;
buffersize = (lastevent + 1.0) * 2 * 44100; // 44100 kHz 16-bit samples

rendered = R_CreateBlankSample(1, 16, 44100, buffersize);
R_SilenceSample(rendered);
R_RenderSequencetoSample(rendered, sequence, bankset, buffersize);
writeWAV("output.wav", rendered);

Here are some sample MIDI renderings from Final Fantasy game MIDI files. This conversion was done using a 3MB sound font file.

FF3 – Locke Theme
FF2 – Zeromus Battle
FF3 – Airship Blackjack
FF2 – Toroia
FF2 – Big Whale

The original MIDI files are here: