/** * Within the given set of notes find the one that is the leftmost one and that is nearest to the * given pitch, but exclude notes that have the same pitch. * * @param pitch * @param notes * @return */ private static Note nearestNote(int pitch, List<Note> notes) { Note result = null; int smallestPitchdiff = Integer.MAX_VALUE; long nearestPos = Long.MAX_VALUE; for (Note n : notes) { int thisPitchDiff = Math.abs(pitch - n.getPitch()); long thisPos = n.getTickPos(); if (thisPos < nearestPos) { result = n; nearestPos = thisPos; smallestPitchdiff = thisPitchDiff; } else { if (nearestPos == thisPos) { if (thisPitchDiff < smallestPitchdiff) { result = n; smallestPitchdiff = thisPitchDiff; } } } } if (smallestPitchdiff != 0) { return result; } else { return null; } }
private static void handleTrack( Track outputTrack, Track inputTrack, long startTick, long endTick) { // handle all other events for (int eventI = 0; eventI < inputTrack.size(); eventI++) { MidiEvent midEvent = inputTrack.get(eventI); if (!Note.isNoteOnEvent(midEvent)) { if (!Note.isNoteOffEvent(midEvent)) { outputTrack.add(midEvent); } } } // handle all note events NoteTrack noteTrack = new NoteTrack(inputTrack); for (int i = 0; i < noteTrack.size(); i++) { Note thisNote = noteTrack.get(i); List<Note> followingNotes = findFollowingNotes(noteTrack, i); Note newNote = handleNote(thisNote, followingNotes, startTick, endTick); outputTrack.add(newNote.getNoteOnEvent()); outputTrack.add(newNote.getNoteOffEvent()); } }
/** * Collect all the notes that follow the given note, within a range correspondin to the minimum * rest. * * @param noteTrack * @param index * @return */ private static List<Note> findFollowingNotes(NoteTrack noteTrack, int index) { ArrayList<Note> result = new ArrayList<>(); long posStart = noteTrack.get(index).getTickPos(); long noteDur = noteTrack.get(index).getDuration(); long posEnd = posStart + noteDur; long maxSearch = posEnd + minimumRest; for (int i = index + 1; i < noteTrack.size(); i++) { Note note = noteTrack.get(i); if (note.getTickPos() > maxSearch) { // the note is outside our search area, as the note are sorted in ascending order, we have // finished. break; } // all notes that follow the end of the given note are added to the list // remarque: we allow for an overlap of five ticks because of the impression of some Midi // editors. if (note.getTickPos() >= (posEnd - 5)) { result.add(note); } } return result; }
/** * Within the set set of following notes find one that we can link with. * * @param note * @param follwoingNotes * @return */ private static Note noteToLinkWith(Note note, List<Note> follwoingNotes) { if (follwoingNotes.isEmpty()) { return null; } Note candidate = nearestNote(note.getPitch(), follwoingNotes); if (candidate == null) { return null; } // avoid collision with a following note long newNoteEnd = note.getTickPos() + prolongatedDuration(note, candidate); for (Note fNote : follwoingNotes) { if (fNote.getPitch() == note.getPitch()) { if (fNote.getTickPos() <= newNoteEnd) { return null; } } } return candidate; }
private static Note handleNote( Note note, List<Note> follwoingNotes, long startTick, long endTick) { if (note.getTickPos() < startTick) { return note; } if (note.getTickPos() + note.getDuration() > endTick) { return note; } Note noteToLinkWith = noteToLinkWith(note, follwoingNotes); if (noteToLinkWith != null) { long newDuration = prolongatedDuration(note, noteToLinkWith); Note newNote = new Note( note.getChannel(), note.getPitch(), note.getVelocity(), note.getTickPos(), newDuration); slurEndNotes.add(noteToLinkWith); slurEndNotes.remove(note); return newNote; } if (slurEndNotes.contains(note)) { Note newNote = new Note( note.getChannel(), note.getPitch(), (note.getVelocity() * 80) / 100, note.getTickPos(), (note.getDuration() * 80) / 100); slurEndNotes.remove(note); return newNote; } return note; }
private static long prolongatedDuration(Note note, Note noteToLinkWith) { return (noteToLinkWith.getTickPos() - note.getTickPos()) + noteOverlap; }