package com.PP.MidiServer; import java.util.ArrayList; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import org.jfugue.Note; public class MidiServer { //const public static final long CHORD_BUFFER_TIME = 500; //data protected LinkedBlockingQueue<NoteEvent> noteQueue; protected List<ChordRecognitionListener> chordRecListeners; //state protected boolean running; //stop/resume state protected volatile boolean onStop_state = false; //singleton protected MidiServer() { noteQueue = new LinkedBlockingQueue<NoteEvent>(); chordRecListeners = new ArrayList<ChordRecognitionListener>(); running = false; } protected static MidiServer instance = null; public static MidiServer getInstance() { if(instance==null) { instance = new MidiServer(); } return instance; } /** * Adds note events to queue. * @param noteEvent */ public void addNoteEvent(NoteEvent noteEvent) { noteQueue.add(noteEvent); } /** * Starts up server processing of MiDi. */ public void start() { if(!running) { Thread t = new Thread(new Runnable() { @Override public void run() { queue_thread(); } }); t.start(); } } /** * Stops midi processing. */ public void stop() { running = false; } /** * Queue thread processing function */ public void queue_thread() { //init state String chord=""; long lastTS = -1; long lastSysTS = -1; //start loop running = true; while(running) { //something in queue while(!noteQueue.isEmpty()) { //get next note event NoteEvent noteEvent = noteQueue.remove(); String noteName = parseNoteName(noteEvent.getNote()); if(noteName.equals("")) { continue; } //no notes before if(lastTS==-1) { chord = noteName; lastTS = noteEvent.getTimestamp(); lastSysTS = System.currentTimeMillis(); } else { long diffTS = Math.abs(noteEvent.getTimestamp()-lastTS); System.out.println(lastTS + " " + noteEvent.getTimestamp() + " " + diffTS); if(diffTS <= CHORD_BUFFER_TIME) { if(chord.indexOf(noteName)==-1) { chord = chord + " " + noteName; } } else { notifyRecognizers(chord); chord = noteName; lastTS = -1; lastSysTS = System.currentTimeMillis(); } } } //check case when nothing in queue and chord in progress if(!chord.equals("") && lastTS!=-1) { try { //wait time for buffer long elapsedTime = (System.currentTimeMillis()-lastSysTS); if(elapsedTime < CHORD_BUFFER_TIME) { long remainingTime = CHORD_BUFFER_TIME-elapsedTime; Thread.sleep(remainingTime); } //recheck queue to see if empty or if first elem is past time. if(noteQueue.isEmpty() || Math.abs(noteQueue.peek().getTimestamp()-lastTS) > CHORD_BUFFER_TIME) { if(!noteQueue.isEmpty()) { System.out.println(Math.abs(noteQueue.peek().getTimestamp()-lastTS)); } notifyRecognizers(chord); chord = ""; lastTS = -1; lastSysTS = System.currentTimeMillis(); } } catch(Exception e) { e.printStackTrace(); } } } } /** * Parse Note Names * @param n Note * @return */ public String parseNoteName(Note n) { String ms = n.getMusicString(); for(int x=0; x < ms.length(); x++) { try { Integer.parseInt(""+ms.charAt(x)); return ms.substring(0,x+1); } catch(Exception e) {} } //failure return ""; } /** * Adds Chord Recognition Listener * @param l */ public void addChordRecognitionListener(ChordRecognitionListener l) { if(!chordRecListeners.contains(l)) { chordRecListeners.add(l); } } /** * Removes Chord Recognition Listener * @param l */ public void removeChordRecognitionListener(ChordRecognitionListener l) { chordRecListeners.remove(l); } public void clearChordRecognitionListeners() { chordRecListeners.clear(); } /** * Notify listeners that particular sequence of notes has been recognized. * @param chord */ protected void notifyRecognizers(String chord) { for(ChordRecognitionListener l : chordRecListeners) { l.chordRecognized(chord); } } /** * @return the running */ public boolean isRunning() { return running; } /** * @param running the running to set */ public void setRunning(boolean running) { this.running = running; } public void onStop() { onStop_state = running; if(onStop_state) { this.stop(); } } public void onResume() { if(onStop_state) { this.start(); } } }