package com.PP.LunarTabsAndroid.InstrumentModels; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.herac.tuxguitar.song.models.TGBeat; import org.herac.tuxguitar.song.models.TGNote; import com.PP.LunarTabsAndroid.APIs.TuxGuitarUtil; public class ChordRecognizer { public static String getChordName(List<TGNote> notes) { //convert notes to name of notes list List<String> chordNotes = getChordNoteNames(notes); //get unique elements and sort input into lex order chordNotes = ListUtil.unique(chordNotes); Collections.sort(chordNotes); //look up in hash table first String chordHash = ChordDB.chordHash(chordNotes); if(ChordDB.getInstance().getChordHashToName().containsKey(chordHash)) { return ChordDB.getInstance().getChordHashToName().get(chordHash); } else { //else do approximate matching String bestMatch = getClosestMatch(chordNotes); //store solution in hash table for efficient use later ChordDB.getInstance().getChordHashToName().put(chordHash, bestMatch); //return return bestMatch; } } /** * Function for getting match target out of beat. * @param beat * @return */ public static String getMatchTarget(TGBeat beat) { if(beat.isRestBeat()) { return ""; } else { //get notes in beat List<TGNote> notes = TuxGuitarUtil.getNotesForBeat(beat); //convert notes to name of notes list List<String> chordNotes = getChordNoteNames(notes); //get unique elements and sort input into lex order chordNotes = ListUtil.unique(chordNotes); Collections.sort(chordNotes); //convert to string String target = ""; for(int x=0; x < chordNotes.size(); x++) { target = target + chordNotes.get(x) + " "; } //return return target.trim(); } } protected static List<String> getChordNoteNames(List<TGNote> notes) { List<String> rtn = new ArrayList<String>(); for(int x=(notes.size()-1); x >= 0; x--) { TGNote note = notes.get(x); String[] noteNames = GuitarModel.getInstance().getNoteName(note.getString(),note.getValue()+1); rtn.add(noteNames[0]); } return rtn; } protected static String getClosestMatch(List<String> chordNotes) { //debug /* String rtn=""; for(String str : chordNotes) { rtn = rtn+ " " + str; } */ //get db (init if not inited) List<List<String>> chordDB = ChordDB.getInstance().getChordNotes(); List<String> chordNames = ChordDB.getInstance().getChordNames(); //compute scores double[] scores = new double[chordDB.size()]; for(int x=0; x < chordDB.size(); x++) { List<String> chord = chordDB.get(x); //compute match and mismatch scores and ratio double match_score = ListUtil.computeMatchScore(chordNotes,chord); double mismatch_score = (chordNotes.size()-match_score) + (chord.size()-match_score); scores[x] = match_score / mismatch_score; } //find max double maxScore=scores[0]; String bestMatch = chordNames.get(0); for(int x=1; x < scores.length; x++) { if(scores[x] > maxScore) { maxScore = scores[x]; bestMatch = chordNames.get(x); } } //return best match return bestMatch; // return rtn + " : " + bestMatch + " : " + maxScore; } /** * Converts Midi hash to chord hash * @param str * @return */ public static String getChordHash(String str) { //remove numbers StringBuffer rtn = new StringBuffer(); for(int x=0; x < str.length(); x++) { char c = str.charAt(x); if(!(c >= '0' && c<= '9')) { rtn.append(str.charAt(x)); } } //tokenize and sort String[] toks = rtn.toString().split(" "); List<String> chordNotes = Arrays.asList(toks); chordNotes = ListUtil.unique(chordNotes); Collections.sort(chordNotes); //recreate hash String hash = ""; for(int x=0; x < chordNotes.size(); x++) { hash = hash + chordNotes.get(x) + " "; } hash = hash.trim(); //return return hash; } public static boolean robustMidiMatch(String played, String target) { //get parts String[] playedNotes = played.split(" "); String[] targetNotes = target.split(" "); //checks outer:for(String playedNote : playedNotes) { for(String targetNote : targetNotes) { //if target note, matched. if(targetNote.equalsIgnoreCase(playedNote)) { continue outer; } //if half-pertubation of target note, matched. int playedIndex = GuitarModel.getInstance().getNoteIndex(playedNote); int targetIndex = GuitarModel.getInstance().getNoteIndex(targetNote); int distance = Math.abs(playedIndex - targetIndex); if(distance==1 || distance==11) { continue outer; } } //failed because not matched. return false; } //success because all matched. return true; } }