/** * Returns the length of the note in ticks, thanks to the sequence resolution and the default note * length. */ protected static long getNoteLengthInTicks(Note note, Music staff) { short noteLength = note.getDuration(); if (note.isBeginningTie() && note.getTieDefinition().getEnd() != null) { noteLength += ((Note) staff.getElementByReference(note.getTieDefinition().getEnd())).getDuration(); } float numberOfQuarterNotesInThisNote = (float) noteLength / Note.QUARTER; float lengthInTicks = (float) SEQUENCE_RESOLUTION * numberOfQuarterNotesInThisNote; return (long) lengthInTicks; }
/** * Converts the given tune to a midi sequence. * * @param tune The tune to be converted. * @return The midi sequence of the tune. */ public Sequence toMidiSequence(Tune tune) { Sequence sequence = null; try { if (instrument == null) { Synthesizer synth = MidiSystem.getSynthesizer(); synth.open(); try { setInstrument(synth.getAvailableInstruments()[0]); } finally { synth.close(); } } // Sequence in ticks per quarter note : PPQ = Pulse Per Quarter Note // Resolution is expressed in ticks per beat. // Last parameter "1" is the number of tracks. sequence = new Sequence(Sequence.PPQ, SEQUENCE_RESOLUTION, 1); // Set the instrument on channel 0 ShortMessage sm = new ShortMessage(); sm.setMessage(ShortMessage.PROGRAM_CHANGE, 0, instrument.getPatch().getProgram(), 0); Track track = sequence.createTrack(); track.add(new MidiEvent(sm, 0)); // long trackLengthInTicks = track.ticks(); int lastRepeatOpen = -1; int repeatNumber = 1; boolean inWrongEnding = false; KeySignature tuneKey = null; KeySignature currentKey = null; Hashtable partsKey = new Hashtable(); long elapsedTime = 0; NoteAbstract[] graceNotes = null; Music staff = tune.getMusicForAudioRendition(); Iterator it = staff.getVoices().iterator(); while (it.hasNext()) { Voice voice = (Voice) it.next(); int i = 0; // StaffItem iterator while (i < voice.size()) { if (!inWrongEnding) { // ==================================================================== TEMPO if (voice.elementAt(i) instanceof abc.notation.Tempo) { addTempoEventsFor( track, elapsedTime, getMidiMessagesFor((Tempo) voice.elementAt(i))); // , trackLengthInTicks)); } else /*if (voice.elementAt(i) instanceof abc.notation.PartLabel) { //Imagine... part A in Gmaj, B in Amin //in tune you have K:G, P:A, ... P:B, K:Am //if you have part order ABA, when you return to A //you stay in Amin. This stores the tuneKey when a //new part appear, and restitute it when part is played again abc.notation.PartLabel pl = (abc.notation.PartLabel) voice.elementAt(i); if (partsKey.get(pl.getLabel()+"") == null) { partsKey.put(pl.getLabel()+"", tuneKey); } else { tuneKey = (KeySignature) partsKey.get(pl.getLabel()+""); } } else*/ // ==================================================================== KEY SIGNATURE if (voice.elementAt(i) instanceof abc.notation.KeySignature) { tuneKey = (KeySignature) (voice.elementAt(i)); currentKey = new KeySignature(tuneKey.getAccidentals()); } else // ==================================================================== NOTE // Notes ending ties should be ignored. Already taken into // account in getNoteLengthInTicks(Note) if (voice.elementAt(i) instanceof abc.notation.Note && !((abc.notation.Note) voice.elementAt(i)).isEndingTie()) { Note note = (Note) voice.elementAt(i); long noteDuration; boolean fermata = false; Vector decorationNotes = new Vector(); if (note.hasGeneralGracing() || note.hasDecorations()) { Decoration[] d = note.getDecorations(); for (int j = 0; j < d.length; j++) { switch (d[j].getType()) { case Decoration.FERMATA: case Decoration.FERMATA_INVERTED: fermata = true; break; case Decoration.LOWERMORDENT: case Decoration.UPPERMORDENT: case Decoration.DOUBLE_LOWER_MORDANT: case Decoration.DOUBLE_UPPER_MORDANT: case Decoration.TRILL: case Decoration.TURN: // GRUPETTO_UP case Decoration.TURN_INVERTED: // GRUPETTO_DOWN case Decoration.TURNX: case Decoration.TURNX_INVERTED: Note n = new Note(note.getHeight()); n.setAccidental(note.getAccidental(currentKey)); Note o = new Interval(Interval.SECOND, Interval.MAJOR, Interval.UPWARD) .calculateSecondNote(n); Note m = new Interval(Interval.SECOND, Interval.MAJOR, Interval.DOWNWARD) .calculateSecondNote(n); // TODO ornament templates: regular, musette, balkan... // n.setStrictDuration(Note.SIXTEENTH); // o.setDuration((short)(Note.EIGHTH+Note.SIXTEENTH)); o.setAccidental(Accidental.NONE); m.setAccidental(Accidental.NONE); n.setStrictDuration(Note.THIRTY_SECOND); m.setStrictDuration(Note.THIRTY_SECOND); o.setStrictDuration(Note.THIRTY_SECOND); switch (d[j].getType()) { case Decoration.DOUBLE_LOWER_MORDANT: decorationNotes.add(n); decorationNotes.add(m); case Decoration.LOWERMORDENT: decorationNotes.add(n); decorationNotes.add(m); break; case Decoration.DOUBLE_UPPER_MORDANT: case Decoration.TRILL: decorationNotes.add(n); decorationNotes.add(o); case Decoration.UPPERMORDENT: decorationNotes.add(n); decorationNotes.add(o); break; case Decoration.TURNX_INVERTED: case Decoration.TURN: decorationNotes.add(o); decorationNotes.add(n); decorationNotes.add(m); break; case Decoration.TURNX: case Decoration.TURN_INVERTED: decorationNotes.add(m); decorationNotes.add(n); decorationNotes.add(o); } break; } } // currently not used // future use: playing rolls, slides, etc. } long graceNotesDuration = 0; if (note.hasGracingNotes() || (decorationNotes.size() > 0)) { graceNotes = note.getGracingNotes(); // gracing are eighth note for graphical rendition // and because that's it in the parser // adapt duration to note length int divisor = 1; if (note.getStrictDuration() >= Note.HALF) divisor = 1; // grace is an eighth else if (note.getStrictDuration() >= Note.QUARTER) divisor = 2; // 16th else if (note.getStrictDuration() >= Note.EIGHTH) divisor = 4; // 32nd else divisor = 8; // 64th if (note.hasGracingNotes()) { for (int j = 0; j < graceNotes.length; j++) { noteDuration = getNoteLengthInTicks(graceNotes[j], staff) / divisor; graceNotesDuration += noteDuration; if (graceNotes[j] instanceof Note) playNote( (Note) graceNotes[j], i, currentKey, elapsedTime, noteDuration, track); else playMultiNote( (MultiNote) graceNotes[j], i, currentKey, /*elapsedTime,*/ noteDuration, track, staff); elapsedTime += noteDuration; } } for (int j = 0; j < decorationNotes.size(); j++) { noteDuration = getNoteLengthInTicks((Note) decorationNotes.elementAt(j), staff); graceNotesDuration += noteDuration; playNote( (Note) decorationNotes.elementAt(j), i, currentKey, elapsedTime, noteDuration, track); elapsedTime += noteDuration; } } // The note duration if the note isn't part of a tuplet. noteDuration = getNoteLengthInTicks(note, staff) - graceNotesDuration; if (noteDuration <= 0) // in case of too much grace notes noteDuration = getNoteLengthInTicks(note, staff); if (fermata) noteDuration *= 2; playNote(note, i, currentKey, elapsedTime, noteDuration, track); elapsedTime += noteDuration; } else // ==================================================================== MULTI NOTE if ((voice.elementAt(i) instanceof abc.notation.MultiNote)) { MultiNote multiNote = (MultiNote) voice.elementAt(i); playMultiNote(multiNote, i, currentKey, elapsedTime, track, staff); elapsedTime += getNoteLengthInTicks(multiNote, staff); } } // endif (!inWrongEnding) // ====================================================================== REPEAT BAR LINE if (voice.elementAt(i) instanceof abc.notation.RepeatBarLine) { RepeatBarLine bar = (RepeatBarLine) voice.elementAt(i); if (repeatNumber < bar.getRepeatNumbers()[0] && lastRepeatOpen != -1) { repeatNumber++; i = lastRepeatOpen; } else if (repeatNumber > bar.getRepeatNumbers()[0]) inWrongEnding = true; else inWrongEnding = false; } else // ====================================================================== BAR LINE OPEN / // CLOSE if (voice.elementAt(i) instanceof abc.notation.BarLine) { // currentKey = new KeySignature(tuneKey.getAccidentals()); switch (((BarLine) (voice.elementAt(i))).getType()) { case BarLine.SIMPLE: break; case BarLine.REPEAT_OPEN: lastRepeatOpen = i; repeatNumber = 1; break; case BarLine.REPEAT_CLOSE: if (repeatNumber < 2 && lastRepeatOpen != -1) { repeatNumber++; i = lastRepeatOpen; } else { repeatNumber = 1; lastRepeatOpen = -1; } break; // TODO case BarLine.BEGIN_AND_END_REPEAT } } // Whatever kind of bar line it is if (voice.elementAt(i) instanceof abc.notation.BarLine) { currentKey = new KeySignature(tuneKey.getAccidentals()); } i++; } // end while each element in voice } // end while each voice in music } catch (InvalidMidiDataException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return sequence; }
protected void convert(Document doc, Music music, Element musicElement) { int measureNb = 1; Element currentMeasureEl = doc.createElement(MEASURE_TAG); int addedMusicElement = 0; musicElement.appendChild(currentMeasureEl); Element lastShorterThanQuarterNote = null; // KeySignature key = null; // TimeSignature time = null; int voltaRunning = 0; currentMeasureEl.setAttribute(NUMBER_ATTRIBUTE, new Integer(measureNb).toString()); Iterator it = music.getVoices().iterator(); while (it.hasNext()) { Voice voice = (Voice) it.next(); for (int i = 0; i < voice.size(); i++) { // MusicElement current = (MusicElement) music.elementAt(i); if (voice.elementAt(i) instanceof Note) { Note note = (Note) voice.elementAt(i); Element noteElement = convert(doc, note); if (note.getStrictDuration() < Note.QUARTER) { if (lastShorterThanQuarterNote == null) { // this is the first note of a group lastShorterThanQuarterNote = noteElement; Element beamNode = doc.createElement(BEAM_TAG); beamNode.setAttribute(NUMBER_ATTRIBUTE, "1"); Node text = doc.createTextNode("begin"); beamNode.appendChild(text); noteElement.appendChild(beamNode); } else { // this is part of a previously created beam lastShorterThanQuarterNote = noteElement; Element beamNode = doc.createElement(BEAM_TAG); beamNode.setAttribute(NUMBER_ATTRIBUTE, "1"); // noteElement.appendChild(lastShorterThanQuarterNote); Node text = doc.createTextNode("continue"); beamNode.appendChild(text); noteElement.appendChild(beamNode); } } currentMeasureEl.appendChild(noteElement); addedMusicElement++; } else if (voice.elementAt(i) instanceof MultiNote) { Node[] nodes = convert(doc, (MultiNote) voice.elementAt(i)); for (int j = 0; j < nodes.length; j++) currentMeasureEl.appendChild(nodes[j]); addedMusicElement++; } else if (voice.elementAt(i) instanceof TimeSignature) { // time = (TimeSignature)music.elementAt(i); appendTo(currentMeasureEl, (TimeSignature) voice.elementAt(i), doc); } else if (voice.elementAt(i) instanceof KeySignature) { // key = (KeySignature)music.elementAt(i); appendTo(currentMeasureEl, (KeySignature) voice.elementAt(i), doc); } else if (voice.elementAt(i) instanceof BarLine) { BarLine barline = ((BarLine) voice.elementAt(i)); Element barLineNode = null; if (voltaRunning > 1) { // end of volta > 2 on the first bar // line we find barLineNode = doc.createElement(BAR_LINE_TAG); currentMeasureEl.appendChild(barLineNode); Element endingEl = doc.createElement("ending"); endingEl.setAttribute(NUMBER_ATTRIBUTE, Integer.toString(voltaRunning)); endingEl.setAttribute(TYPE_ATTRIBUTE, "discontinue"); barLineNode.appendChild(endingEl); voltaRunning = 0; } if (barline instanceof RepeatBarLine) { // start of volta RepeatBarLine repeatBarLine = (RepeatBarLine) barline; if (barLineNode == null) { barLineNode = doc.createElement(BAR_LINE_TAG); currentMeasureEl.appendChild(barLineNode); } Element endingEl = doc.createElement("ending"); endingEl.setAttribute( NUMBER_ATTRIBUTE, Integer.toString(repeatBarLine.getRepeatNumbers()[0])); endingEl.setAttribute(TYPE_ATTRIBUTE, "start"); barLineNode.appendChild(endingEl); voltaRunning = repeatBarLine.getRepeatNumbers()[0]; } if (barline.getType() == BarLine.REPEAT_CLOSE) { // Close // barline if (barline.toString().equals(":|")) { if (barLineNode == null) { barLineNode = doc.createElement(BAR_LINE_TAG); currentMeasureEl.appendChild(barLineNode); } if (voltaRunning == 1) { Element endingEl = doc.createElement("ending"); endingEl.setAttribute(NUMBER_ATTRIBUTE, Integer.toString(voltaRunning)); endingEl.setAttribute(TYPE_ATTRIBUTE, "stop"); barLineNode.appendChild(endingEl); voltaRunning = 0; } barLineNode.setAttribute(LOCATION_ATTRIBUTE, "right"); Element repeatNode = doc.createElement(REPEAT_TAG); repeatNode.setAttribute(DIRECTION_ATTRIBUTE, "backward"); barLineNode.appendChild(repeatNode); } } if (addedMusicElement == 0) { if (barline.getType() == BarLine.REPEAT_OPEN) { if (barLineNode == null) { barLineNode = doc.createElement(BAR_LINE_TAG); currentMeasureEl.appendChild(barLineNode); } barLineNode.setAttribute(LOCATION_ATTRIBUTE, "left"); Element repeatNode = doc.createElement(REPEAT_TAG); repeatNode.setAttribute(DIRECTION_ATTRIBUTE, "forward"); barLineNode.appendChild(repeatNode); } } else if (addedMusicElement > 0) { // a bar line has been // detected , do we create a // new measure ? currentMeasureEl = doc.createElement(MEASURE_TAG); measureNb++; currentMeasureEl.setAttribute(NUMBER_ATTRIBUTE, new Integer(measureNb).toString()); musicElement.appendChild(currentMeasureEl); if (barline.getType() == BarLine.REPEAT_OPEN) { if (barLineNode == null) { barLineNode = doc.createElement(BAR_LINE_TAG); barLineNode.setAttribute(LOCATION_ATTRIBUTE, "left"); } Element repeatNode = doc.createElement(REPEAT_TAG); repeatNode.setAttribute(DIRECTION_ATTRIBUTE, "forward"); barLineNode.appendChild(repeatNode); currentMeasureEl.appendChild(barLineNode); } addedMusicElement = 0; } } else if (voice.elementAt(i) instanceof EndOfStaffLine) { Element printEl = doc.createElement("print"); printEl.setAttribute("new-system", "yes"); currentMeasureEl.appendChild(printEl); } if (voice.elementAt(i) instanceof NotesSeparator) { // Node lastBeam=; if (lastShorterThanQuarterNote != null) { Element beamNode; if (lastShorterThanQuarterNote.getElementsByTagName(BEAM_TAG).getLength() == 0) beamNode = doc.createElement(BEAM_TAG); else beamNode = (Element) lastShorterThanQuarterNote.getElementsByTagName(BEAM_TAG).item(0); beamNode.setAttribute(NUMBER_ATTRIBUTE, "1"); beamNode.setTextContent("end"); lastShorterThanQuarterNote.appendChild(beamNode); lastShorterThanQuarterNote = null; } } } // end each element in voice } // end each voice in music }