package org.herac.tuxguitar.midiinput; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import org.apache.log4j.Logger; import org.herac.tuxguitar.gui.editors.tab.TGBeatImpl; import org.herac.tuxguitar.gui.editors.tab.TGChordImpl; import org.herac.tuxguitar.gui.editors.tab.TGNoteImpl; import org.herac.tuxguitar.song.models.TGBeat; import org.herac.tuxguitar.song.models.TGChord; import org.herac.tuxguitar.song.models.TGNote; class MiBuffer { /** The Logger for this class. */ public static final transient Logger LOG = Logger.getLogger(MiBuffer.class); static void dump(List<MiNote> inList, String inTitle) { LOG.debug(""); LOG.debug("dumping " + inTitle + "..."); // LOG.debug("Started at: " + f_StartTime); // LOG.debug("Stopped at: " + f_StopTime); LOG.debug(""); for (MiNote n : inList) { LOG.debug("str: " + n.getString() + ", fret: " + n.getFret() + ", pitch: " + n.getPitch() + ", vel: " + n.getVelocity() + ", on: " + n.getTimeOn() + ", off: " + n.getTimeOff() + ", dur: " + n.getDuration()); } } private ArrayList<MiNote> f_NoteOffMap = new ArrayList<MiNote>(); // time-ordered // map of // NOTE_OFF events private ArrayList<MiNote> f_Notes = new ArrayList<MiNote>(); // time-ordered // list of notes private long f_StartTime = -1; // first MIDI time stamp [microseconds] private long f_StopTime = -1; // last MIDI time stamp [microseconds] private boolean s_TESTING = true; public void addEvent(byte inString, byte inFret, byte inPitch, byte inVelocity, long inTimeStamp) { if (inVelocity == 0) this.f_NoteOffMap.add(new MiNote(inString, inFret, inPitch, inVelocity, inTimeStamp)); else this.f_Notes.add(new MiNote(inString, inFret, inPitch, inVelocity, inTimeStamp)); } private void addEventDebug(int inTempo, long inTick, int inString, int inPitch, int inVelocity) { // to facilitate tests using output from Midi2Mtx addEvent((byte) inString, (byte) MiProvider.getFret(inPitch, inString), (byte) inPitch, (byte) inVelocity, MiStaff.ticksToTimestamp(inTempo, inTick)); } public int finalize(byte inMinVelocity, long inMinDuration) { if (this.s_TESTING) { int tempo = MiRecorder.instance().getTempo(); this.f_StartTime = MiStaff.ticksToTimestamp(tempo, 0); this.f_StopTime = MiStaff.ticksToTimestamp(tempo, 15698); /* * // a very long note addEventDebug(tempo, 0, 4, 50, 81); * addEventDebug(tempo, 15698, 4, 50, 0); */ // a short piece addEventDebug(tempo, 873, 1, 66, 96); addEventDebug(tempo, 1054, 1, 66, 0); addEventDebug(tempo, 1056, 1, 67, 81); addEventDebug(tempo, 1307, 1, 67, 0); addEventDebug(tempo, 1310, 1, 68, 67); addEventDebug(tempo, 1369, 1, 68, 0); addEventDebug(tempo, 2549, 1, 69, 78); addEventDebug(tempo, 2841, 1, 69, 0); addEventDebug(tempo, 852, 2, 62, 106); addEventDebug(tempo, 1301, 2, 62, 0); addEventDebug(tempo, 1304, 2, 61, 32); addEventDebug(tempo, 1389, 2, 61, 0); addEventDebug(tempo, 2545, 2, 62, 81); addEventDebug(tempo, 2765, 2, 62, 0); addEventDebug(tempo, 3418, 2, 65, 78); addEventDebug(tempo, 4172, 2, 65, 0); addEventDebug(tempo, 4281, 2, 67, 56); addEventDebug(tempo, 4433, 2, 67, 0); addEventDebug(tempo, 6027, 2, 59, 79); addEventDebug(tempo, 6627, 2, 59, 0); addEventDebug(tempo, 7657, 2, 60, 114); addEventDebug(tempo, 7879, 2, 60, 0); addEventDebug(tempo, 7881, 2, 59, 81); addEventDebug(tempo, 8434, 2, 59, 0); addEventDebug(tempo, 9780, 2, 62, 103); addEventDebug(tempo, 10072, 2, 62, 0); addEventDebug(tempo, 10074, 2, 63, 40); addEventDebug(tempo, 10146, 2, 63, 0); addEventDebug(tempo, 10266, 2, 66, 107); addEventDebug(tempo, 11002, 2, 66, 0); addEventDebug(tempo, 11535, 2, 64, 76); addEventDebug(tempo, 13661, 2, 64, 0); addEventDebug(tempo, 473, 3, 57, 51); addEventDebug(tempo, 1241, 3, 57, 0); addEventDebug(tempo, 1242, 3, 56, 9); addEventDebug(tempo, 1424, 3, 56, 0); addEventDebug(tempo, 2540, 3, 58, 68); addEventDebug(tempo, 2772, 3, 58, 0); addEventDebug(tempo, 3412, 3, 60, 73); addEventDebug(tempo, 4227, 3, 60, 0); addEventDebug(tempo, 6024, 3, 60, 58); addEventDebug(tempo, 6427, 3, 60, 0); addEventDebug(tempo, 6430, 3, 59, 17); addEventDebug(tempo, 6591, 3, 59, 0); addEventDebug(tempo, 6594, 3, 55, 1); addEventDebug(tempo, 6612, 3, 55, 0); addEventDebug(tempo, 7660, 3, 57, 103); addEventDebug(tempo, 8096, 3, 57, 0); addEventDebug(tempo, 8099, 3, 57, 107); addEventDebug(tempo, 8200, 3, 57, 0); addEventDebug(tempo, 8203, 3, 56, 79); addEventDebug(tempo, 8230, 3, 56, 0); addEventDebug(tempo, 8232, 3, 55, 77); addEventDebug(tempo, 8491, 3, 55, 0); addEventDebug(tempo, 9407, 3, 57, 87); addEventDebug(tempo, 10048, 3, 57, 0); addEventDebug(tempo, 10255, 3, 61, 74); addEventDebug(tempo, 10874, 3, 61, 0); addEventDebug(tempo, 10877, 3, 60, 23); addEventDebug(tempo, 10973, 3, 60, 0); addEventDebug(tempo, 10975, 3, 55, 17); addEventDebug(tempo, 11084, 3, 55, 0); addEventDebug(tempo, 11531, 3, 62, 70); addEventDebug(tempo, 13649, 3, 62, 0); addEventDebug(tempo, 0, 4, 50, 81); addEventDebug(tempo, 1405, 4, 50, 0); addEventDebug(tempo, 1750, 4, 53, 98); addEventDebug(tempo, 2763, 4, 53, 0); addEventDebug(tempo, 3884, 4, 50, 51); addEventDebug(tempo, 4678, 4, 50, 0); addEventDebug(tempo, 5597, 4, 55, 77); addEventDebug(tempo, 6392, 4, 55, 0); addEventDebug(tempo, 8975, 4, 50, 71); addEventDebug(tempo, 11023, 4, 50, 0); addEventDebug(tempo, 11081, 4, 50, 46); addEventDebug(tempo, 11311, 4, 50, 0); addEventDebug(tempo, 11524, 4, 55, 76); addEventDebug(tempo, 14489, 4, 55, 0); addEventDebug(tempo, 4783, 5, 45, 90); addEventDebug(tempo, 8521, 5, 45, 0); addEventDebug(tempo, 3430, 6, 46, 94); addEventDebug(tempo, 4506, 6, 46, 0); addEventDebug(tempo, 4509, 6, 40, 17); addEventDebug(tempo, 6680, 6, 40, 0); addEventDebug(tempo, 6868, 6, 41, 99); addEventDebug(tempo, 8180, 6, 41, 0); addEventDebug(tempo, 8182, 6, 40, 83); addEventDebug(tempo, 8486, 6, 40, 0); addEventDebug(tempo, 8587, 6, 43, 95); addEventDebug(tempo, 10010, 6, 43, 0); addEventDebug(tempo, 10275, 6, 46, 99); addEventDebug(tempo, 10302, 6, 46, 0); addEventDebug(tempo, 10304, 6, 47, 99); addEventDebug(tempo, 10943, 6, 47, 0); addEventDebug(tempo, 10946, 6, 40, 51); addEventDebug(tempo, 11350, 6, 40, 0); addEventDebug(tempo, 11492, 6, 45, 114); addEventDebug(tempo, 15698, 6, 45, 0); } Iterator<MiNote> onIt; // determine notes duration onIt = this.f_Notes.iterator(); while (onIt.hasNext()) { MiNote on = (MiNote) onIt.next(); Iterator<MiNote> offIt = this.f_NoteOffMap.iterator(); boolean found = false; while (offIt.hasNext() && !found) { MiNote off = (MiNote) offIt.next(); if (on.getString() == off.getString() && on.getFret() == off.getFret()) { on.setTimeOff(off.getTimeOn()); offIt.remove(); found = true; } } // if a note is still playing, set its end time if (!found) on.setTimeOff(this.f_StopTime); } // remove notes with insufficient velocity or duration onIt = this.f_Notes.iterator(); while (onIt.hasNext()) { MiNote on = (MiNote) onIt.next(); /* * LOG.debug( "str: " + on.getString() + ", fret: " + on.getFret() + * ", pitch: " + on.getPitch() + ", vel: " + on.getVelocity() + ", dur: " * + on.getDuration()); */ if (on.getVelocity() < inMinVelocity || on.getDuration() < inMinDuration) { /* * LOG.debug( "removed " + "str: " + on.getString() + ", fret: " + * on.getFret() + ", pitch: " + on.getPitch() + ", vel: " + * on.getVelocity() + ", dur: " + on.getDuration()); */ onIt.remove(); } } return (this.f_Notes.size()); } public void startRecording(long inTimeStamp) { this.f_StartTime = inTimeStamp; this.f_StopTime = -1; this.f_Notes.clear(); this.f_NoteOffMap.clear(); } public void stopRecording(long inTimeStamp) { this.f_StopTime = inTimeStamp; } public TGBeat toBeat() { TGBeat tgBeat = new TGBeatImpl(); for (final MiNote note : this.f_Notes) { TGNote tgNote = new TGNoteImpl(); tgNote.setString(note.getString()); tgNote.setValue(note.getFret()); tgBeat.getVoice(0).addNote(tgNote); } return tgBeat; } public TGChord toChord(int inStringsCount) { TGChord tgChord = new TGChordImpl(inStringsCount); for (final MiNote note : this.f_Notes) { tgChord.addFretValue(note.getString() - 1, note.getFret()); } return tgChord; } public SortedSet<Byte> toPitchesSet() { SortedSet<Byte> pitches = new TreeSet<Byte>(); for (final MiNote note : this.f_Notes) { pitches.add(new Byte(note.getPitch())); } return pitches; } public void toTrack(int inTempo, long inStartPosition, String inTrackName) { /* MiStaff staff = */new MiStaff(this.f_Notes, inTempo, this.f_StartTime, this.f_StopTime, inStartPosition, inTrackName); } }