Here is the quick and nasty converter I used to convert some NES midi files from http://www.vgmusic.com:
The converter takes two arguments, first the midi file and second a channel map. The channel map is the midi channel to scan for note commands for the synth channel.
Eg:
MidiConvert mario.mid 1,2,3,10
Would scan the file mario.mid and any messages on Midi channel 1 would go to the synth channel 1. Messages on midi channel 10 would go to synth channel 4. etc.
Note that the default synth config channels are set up for:
1 - Melody
2 - Harmony
3 - Bass
4 - Snare Drum
5 - Kick Drum
Also only a very small subset of midi is compatible with my synth. It is monophonic, not velocity sensitive, doesn’t support pitch bending, has no note-off capability. More complicated midi files will come out sounding rubbish.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Track;
public class MidiConvert {
private static final int QUATER_NOTE_STEPS = 32;
private static final int QUATER_NOTES_PER_SEC = 2;
public static void main(String[] args) {
if (args.length < 2){
System.out.println("Usage: MidiConvert filename channelmap");
return;
}
MidiConvert mc = new MidiConvert();
try {
Sequence sequence = MidiSystem.getSequence(new File(args[0]));
printSequenceInfo(sequence);
String[] channelFields = args[1].split("\\,");
int[] channelMap = new int[channelFields.length];
for(int i = 0; i < channelMap.length; i++){
channelMap[i] = Integer.parseInt(channelFields[i]);
}
// 0 = melody
// 1 = harmony
// 2 = bass
// 3 = beat
String s = mc.process(sequence, channelMap);
System.out.println(s);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void printSequenceInfo(Sequence sequence){
int events[] = new int[16];
for(Track track : sequence.getTracks()){
for(int i = 0; i < track.size(); i++){
MidiMessage m = track.get(i).getMessage();
if (m instanceof ShortMessage){
events[((ShortMessage)m).getChannel()]++;
}
}
}
for(int i = 0; i < events.length; i++){
System.out.println("Ch " + i + ": " + events[i] + " events");
}
}
private ArrayList<Integer> commands;
public int getStep(Sequence sequence, long midiTick) {
float timing = sequence.getDivisionType();
int res = sequence.getResolution();
if (timing == Sequence.PPQ) {
return (int) ((midiTick * QUATER_NOTE_STEPS) / res);
} else {
int stepsPerSec = QUATER_NOTE_STEPS * QUATER_NOTES_PER_SEC; // assume 120bpm
int ticksPerStep = Math.round((timing * sequence.getResolution())/ stepsPerSec);
return (int) (midiTick / ticksPerStep);
}
}
public void noteOn(int channel, int key, int velocity) {
if (velocity != 0) {
key -= 36;
while (key < 0) {
System.out.println("Adjusting note into range +12");
key += 12;
}
while (key > 63) {
System.out.println("Adjusting note into range -12");
key -= 12;
}
velocity = (velocity >> 2);
commands.add((1 << 6) | key);
}
}
public String process(Sequence sequence, int[] channelMap) {
commands = new ArrayList<Integer>();
for (int outChannel = 0; outChannel < channelMap.length; outChannel++) {
if (channelMap[outChannel] < 0) {
continue;
}
int lastStep = 0;
commands.add(0xC080 | outChannel);
for (Track track : sequence.getTracks()) {
for (int i = 0; i < track.size(); i++) {
MidiEvent event = track.get(i);
if (event.getMessage() instanceof ShortMessage) {
ShortMessage sm = (ShortMessage) event.getMessage();
if (sm.getChannel() == channelMap[outChannel] &&
sm.getCommand() == ShortMessage.NOTE_ON &&
sm.getData2() != 0) {
int step = getStep(sequence, event.getTick());
int delta = step - lastStep;
while (delta > 63) {
commands.add(63);
delta -= 63;
}
if (delta > 0) {
commands.add(delta);
}
lastStep = step;
noteOn(outChannel, sm.getData1(), sm.getData2());
}
}
}
}
}
StringBuilder sb = new StringBuilder();
sb.append("String data = \"");
for (int i = 0; i < commands.size(); i++) {
int val = commands.get(i);
if (val == 10){
sb.append("\\n");
} else if (val == 13){
sb.append("\\r");
} else if (val == 34){
sb.append("\\\"");
} else if (val == 92){
sb.append("\\\\");
} else if (val > 31 && val < 127){
sb.append((char)val);
} else {
String ucode = Integer.toHexString(val);
while (ucode.length() < 4) ucode = "0" + ucode;
sb.append("\\u" + ucode);
}
}
System.out.println();
sb.append("\";");
return sb.toString();
}
}