protected Node convert(Document doc, KeySignature signature) { Element keyEl = doc.createElement(KEY_TAG); Element fifthEl = doc.createElement(FIFTHS_TAG); Accidental[] acc = signature.getAccidentals(); if (Arrays.equals(acc, KEY_NO_ACCIDENTAL)) fifthEl.appendChild(doc.createTextNode("0")); else if (signature.hasOnlySharps()) { if (Arrays.equals(acc, KEY_SHARP_1ST)) fifthEl.appendChild(doc.createTextNode("1")); else if (Arrays.equals(acc, KEY_SHARP_2ND)) fifthEl.appendChild(doc.createTextNode("2")); else if (Arrays.equals(acc, KEY_SHARP_3RD)) fifthEl.appendChild(doc.createTextNode("3")); else if (Arrays.equals(acc, KEY_SHARP_4TH)) fifthEl.appendChild(doc.createTextNode("4")); else if (Arrays.equals(acc, KEY_SHARP_5TH)) fifthEl.appendChild(doc.createTextNode("5")); else if (Arrays.equals(acc, KEY_SHARP_6TH)) fifthEl.appendChild(doc.createTextNode("6")); else if (Arrays.equals(acc, KEY_SHARP_7TH)) fifthEl.appendChild(doc.createTextNode("7")); } else { if (Arrays.equals(acc, KEY_FLAT_1ST)) fifthEl.appendChild(doc.createTextNode("-1")); else if (Arrays.equals(acc, KEY_FLAT_2ND)) fifthEl.appendChild(doc.createTextNode("-2")); else if (Arrays.equals(acc, KEY_FLAT_3RD)) fifthEl.appendChild(doc.createTextNode("-3")); else if (Arrays.equals(acc, KEY_FLAT_4TH)) fifthEl.appendChild(doc.createTextNode("-4")); else if (Arrays.equals(acc, KEY_FLAT_5TH)) fifthEl.appendChild(doc.createTextNode("-5")); else if (Arrays.equals(acc, KEY_FLAT_6TH)) fifthEl.appendChild(doc.createTextNode("-6")); else if (Arrays.equals(acc, KEY_FLAT_7TH)) fifthEl.appendChild(doc.createTextNode("-7")); } keyEl.appendChild(fifthEl); Element modeEl = doc.createElement(MODE_TAG); switch (signature.getMode()) { case 0: modeEl.appendChild(doc.createTextNode("aeolian")); break; case 1: modeEl.appendChild(doc.createTextNode("dorian")); break; case 2: modeEl.appendChild(doc.createTextNode("ionian")); break; case 3: modeEl.appendChild(doc.createTextNode("locrian")); break; case 4: modeEl.appendChild(doc.createTextNode("lydian")); break; case 5: modeEl.appendChild(doc.createTextNode("major")); break; case 6: modeEl.appendChild(doc.createTextNode("minor")); break; case 7: modeEl.appendChild(doc.createTextNode("mixolydian")); break; case 8: modeEl.appendChild(doc.createTextNode("phrygian")); break; default: modeEl.appendChild(doc.createTextNode("major")); break; } keyEl.appendChild(modeEl); return keyEl; }
/** * 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; }
private static void updateKey(KeySignature key, Note note) { if (!note.getAccidental().isInTheKey()) { key.setAccidental(note.getStrictHeight(), note.getAccidental()); } }
protected Element convert(Document doc, Note note) { Element noteEl = doc.createElement(NOTE_TAG); Element durationEl = doc.createElement(DURATION_TAG); String stepValue = null; byte strictHeight = note.getStrictHeight(); int octave = note.getOctaveTransposition(); if (note.isRest()) { Element rest = doc.createElement(REST_TAG); noteEl.appendChild(rest); } else { switch (strictHeight) { case Note.C: stepValue = "C"; break; case Note.D: stepValue = "D"; break; case Note.E: stepValue = "E"; break; case Note.F: stepValue = "F"; break; case Note.G: stepValue = "G"; break; case Note.A: stepValue = "A"; break; case Note.B: stepValue = "B"; break; } octave = octave + 4; String octaveValue = new Integer(octave).toString(); // Element typeEl = doc.createElement(TYPE_TAG); // typeEl.appendChild(doc.createTextNode("quarter")); Element pitchEl = doc.createElement(PITCH_TAG); Element stepEl = doc.createElement(STEP_TAG); stepEl.appendChild(doc.createTextNode(stepValue)); pitchEl.appendChild(stepEl); if (keySignature != null) { Accidental accidental = note.getAccidental(); if (accidental.isInTheKey()) { accidental = keySignature.getAccidentalFor(note.getStrictHeight()); } if (accidental.isDefined()) { int alterValue = accidental.getNearestOccidentalValue(); Element alterEl = doc.createElement(ALTER_TAG); alterEl.appendChild(doc.createTextNode(Integer.toString(alterValue))); pitchEl.appendChild(alterEl); } } Element octaveEl = doc.createElement(OCTAVE_TAG); octaveEl.appendChild(doc.createTextNode(octaveValue)); pitchEl.appendChild(octaveEl); noteEl.appendChild(pitchEl); if (note.hasAccidental()) { Node acc = doc.createElement(ACCIDENTAL_TAG); Node accValue = null; if (note.getAccidental().isFlat()) accValue = doc.createTextNode("flat"); else if (note.getAccidental().isNatural()) accValue = doc.createTextNode("natural"); else if (note.getAccidental().isSharp()) accValue = doc.createTextNode("sharp"); // TODO double flat/sharp acc.appendChild(accValue); noteEl.appendChild(acc); } } int relDuration = note.getDuration() * DIVISIONS_PER_QUARTER_NOTE / Note.QUARTER; durationEl.appendChild(doc.createTextNode(new Integer(relDuration).toString())); noteEl.appendChild(durationEl); if (note.isTied()) { String type = null; if (note.isBeginningTie()) { type = "start"; } else if (note.isEndingTie()) { type = "stop"; } if (type != null) { Element tieEl = doc.createElement(TIE_TAG); tieEl.setAttribute(TYPE_ATTRIBUTE, type); noteEl.appendChild(tieEl); Element notationsEl = (Element) noteEl.getElementsByTagName(NOTATIONS_TAG).item(0); if (notationsEl == null) { notationsEl = doc.createElement(NOTATIONS_TAG); noteEl.appendChild(notationsEl); } Element tiedEl = doc.createElement(TIED_TAG); tiedEl.setAttribute(TYPE_ATTRIBUTE, type); notationsEl.appendChild(tiedEl); } } if (note.isPartOfTuplet()) { Tuplet tuplet = note.getTuplet(); Vector notes = tuplet.getNotesAsVector(); int d = 0; for (Iterator iterator = notes.iterator(); iterator.hasNext(); ) { Note n = (Note) iterator.next(); d += n.getStrictDuration(); } int gcd = MathUtils.pgcd(d, tuplet.getTotalDuration()); Element timeModificationEl = doc.createElement(TIMEMODIFICATION_TAG); Element actualNotesEl = doc.createElement(ACTUALNOTES_TAG); actualNotesEl.appendChild(doc.createTextNode(Integer.toString(d / gcd))); timeModificationEl.appendChild(actualNotesEl); Element normalNotesEl = doc.createElement(NORMALNOTES_TAG); normalNotesEl.appendChild( doc.createTextNode(Integer.toString(tuplet.getTotalDuration() / gcd))); timeModificationEl.appendChild(normalNotesEl); noteEl.appendChild(timeModificationEl); Element notationsEl = doc.createElement(NOTATIONS_TAG); Element tupletEl = doc.createElement(TUPLET_TAG); if (note.equals(notes.get(0))) { tupletEl.setAttribute(TYPE_ATTRIBUTE, "start"); notationsEl.appendChild(tupletEl); noteEl.appendChild(notationsEl); } else if (note.equals(notes.get(notes.size() - 1))) { tupletEl.setAttribute(TYPE_ATTRIBUTE, "stop"); notationsEl.appendChild(tupletEl); noteEl.appendChild(notationsEl); } } Node type = doc.createElement(TYPE_TAG); Node typeValue = null; switch (note.getStrictDuration()) { case Note.SIXTY_FOURTH: typeValue = doc.createTextNode("64th"); break; case Note.THIRTY_SECOND: typeValue = doc.createTextNode("32nd"); break; case Note.SIXTEENTH: typeValue = doc.createTextNode("16th"); break; case Note.EIGHTH: typeValue = doc.createTextNode("eighth"); break; case Note.QUARTER: typeValue = doc.createTextNode("quarter"); break; case Note.HALF: typeValue = doc.createTextNode("half"); break; case Note.WHOLE: typeValue = doc.createTextNode("whole"); break; } if (typeValue != null) { type.appendChild(typeValue); noteEl.appendChild(type); } if (note.countDots() >= 1) { for (int i = 0; i < note.countDots(); i++) { Node dot = doc.createElement(DOT_TAG); noteEl.appendChild(dot); } } return noteEl; }