package com.xenoage.zong.musicxml.types; import com.xenoage.utils.annotations.NonNull; import com.xenoage.utils.xml.XmlReader; import com.xenoage.utils.xml.XmlWriter; import com.xenoage.zong.core.music.Pitch; import com.xenoage.zong.musicxml.types.choice.MxlFullNoteContent; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; import static com.xenoage.zong.core.music.Pitch.pi; import static com.xenoage.zong.musicxml.util.error.InvalidCore.invalidCore; /** * MusicXML pitch. * * @author Andreas Wenger */ @AllArgsConstructor @Getter @Setter public final class MxlPitch implements MxlFullNoteContent { public static final String elemName = "pitch"; @NonNull private final Pitch pitch; @Override public MxlFullNoteContentType getFullNoteContentType() { return MxlFullNoteContentType.Pitch; } @NonNull public static MxlPitch read(XmlReader reader) { int step = 0, alter = 0, octave = 0; while (reader.openNextChildElement()) { String n = reader.getElementName(); switch (n) { case "alter": alter = Math.round(reader.getTextFloatNotNull()); //microtones are not supported break; case "octave": octave = reader.getTextIntNotNull(); break; case "step": step = readStep(reader); break; } reader.closeElement(); } return new MxlPitch(pi(step, alter, octave)); } @Override public void write(XmlWriter writer) { writer.writeElementStart(elemName); writer.writeElementText("step", writeStep(pitch.getStep())); writer.writeElementText("alter", pitch.getAlter()); writer.writeElementText("octave", pitch.getOctave()); writer.writeElementEnd(); } private static int readStep(XmlReader reader) { String s = reader.getTextNotNull(); if (s.length() > 0) { switch (s.charAt(0)) { case 'C': return 0; case 'D': return 1; case 'E': return 2; case 'F': return 3; case 'G': return 4; case 'A': return 5; case 'B': return 6; } } throw reader.dataException("unknown step: " + s); } private static char writeStep(int step) { switch (step) { case 0: return 'C'; case 1: return 'D'; case 2: return 'E'; case 3: return 'F'; case 4: return 'G'; case 5: return 'A'; case 6: return 'B'; } throw invalidCore(step); } }