package us.pconrad; import java.io.*; import java.util.ArrayList; import java.util.regex.Pattern; import java.util.regex.Matcher; public class MidiToGamma { private int currentVoice = 0; private double currentTime = 0; public class Note { public double freq; public double start; public double dur; public Note(double freq, double start, double dur) { this.freq = freq; this.start = start; this.dur = dur; } } private ArrayList> voices = new ArrayList>(); private void addNote(int voice, Note n) { if (voice >= voices.size()) { for (int i=voices.size(); i<= voice; i++) voices.add(new ArrayList()); } voices.get(voice).add(n); } public void parse(String s) { String tokens[] = s.split(" "); for (String t: tokens) { this.handleToken(t); } } private void handleToken(String s) { boolean debug = false; Matcher m = Pattern.compile("^V([0-9])$").matcher(s); if (m.matches()) { this.currentVoice = Integer.parseInt(m.group(1)); if (debug) { System.out.println("V" + this.currentVoice); } return; } m = Pattern.compile("^@([0-9]+)$").matcher(s); if (m.matches()) { this.currentTime = Integer.parseInt(m.group(1))/1000.0; if (debug) { System.out.println("@" + this.currentTime); } return; } m = Pattern.compile("^([ABCDEFG](#|b)?[0-9]+)/([0-9]+(\\.[0-9]+)?)(a[0-9]+)?(d[0-9]+)$").matcher(s); if (m.matches()) { String noteName = (m.group(1)); double freq = WellTempered.freq(noteName); double duration = Double.parseDouble(m.group(3)); if (debug) { System.out.println(noteName+"/"+duration+"("+freq+")"); } addNote(this.currentVoice,new Note(freq,this.currentTime,duration)); return; } System.out.println("Unknown: " + s); } public void writeGammaFile(String outfile) throws java.io.IOException { PrintWriter out = new PrintWriter(new File(outfile)); out.println("// Before your main, define a function like this."); out.println("// Add as many cases as you have voices. Each voice can"); out.println("// have different parameters, or use a different instrument, "); out.println("// e.g. SineEnv, FM, PluckedString, etc. "); out.println("// void note(Scheduler &s, int voice, double start, double dur, double freq) {"); out.println("// double amp=0.1, attack=0.02, decay=0.02, pan=0.0;"); out.println("// switch (voice) {"); out.println("// case 0:"); out.println("// s.add(start).set(dur, freq, amp, attack, decay, pan); break;"); out.println("// case 1:"); out.println("// s.add(start).set(dur, freq, amp, attack, decay, pan); break;"); out.println("// case 2:"); out.println("// s.add(start).set(dur, freq, amp, attack, decay, pan); break;"); out.println("// default:"); out.println("// s.add(start).set(dur, freq, amp, attack, decay, pan);"); out.println("// }\n\n\n"); out.println("// #include this as your notelist "); for (int i=0; i< voices.size(); i++) { out.println("\n// Voice " + i + "\n"); for (Note n: voices.get(i)) { out.printf("note(s,%d,%f,%f,%f);\n",i,n.start,n.dur,n.freq); } } out.close(); } public MidiToGamma(String infilename) { String notes=null; org.jfugue.Player player = new org.jfugue.Player(); org.jfugue.Pattern pattern = null; try { pattern = player.loadMidi(new java.io.File(infilename)); notes = pattern.toString(); this.parse(notes); // sets state of this object } catch (java.io.IOException e) { e.printStackTrace(); } catch (javax.sound.midi.InvalidMidiDataException e) { e.printStackTrace(); } } public static void main (String [] args) { if (args.length != 2) { System.err.println("Usage: java MidiToGamma infile.mid outfile.cpp"); System.exit(1); } MidiToGamma mg= new MidiToGamma(args[0]); try { mg.writeGammaFile(args[1]); } catch (java.io.IOException e) { e.printStackTrace(); } } // main } // class