package com.xenoage.zong.io.musicxml.in.readers; import com.xenoage.zong.core.instrument.PitchedInstrument; import com.xenoage.zong.core.instrument.Transpose; import com.xenoage.zong.core.music.InstrumentChange; import com.xenoage.zong.core.music.clef.Clef; import com.xenoage.zong.core.music.key.Key; import com.xenoage.zong.core.music.key.TraditionalKey; import com.xenoage.zong.core.music.key.TraditionalKey.Mode; import com.xenoage.zong.core.music.time.TimeSignature; import com.xenoage.zong.core.music.time.TimeType; import com.xenoage.zong.musicxml.types.*; import com.xenoage.zong.musicxml.types.choice.MxlTimeContent.MxlTimeContentType; import com.xenoage.zong.musicxml.types.enums.MxlTimeSymbol; import lombok.RequiredArgsConstructor; import static com.xenoage.utils.EnumUtils.getEnumValue; import static com.xenoage.utils.math.MathUtils.clamp; import static com.xenoage.zong.core.music.time.TimeType.timeSenzaMisura; import static com.xenoage.zong.core.music.time.TimeType.timeType; /** * Reads divisions, key signature, time signature, clefs * and transposition changes from {@link MxlAttributes}. * * @author Andreas Wenger */ @RequiredArgsConstructor public class AttributesReader { private final MxlAttributes mxlAttributes; /** * Reads the given attributes element. */ public void readToContext(Context context) { //divisions Integer divisions = mxlAttributes.getDivisions(); if (divisions != null) context.setDivisions(divisions); //key signature Key key = readKey(mxlAttributes.getKey()); if (key != null) context.writeColumnElement(key); //time signature TimeSignature time = readTime(mxlAttributes.getTime()); if (time != null) //TODO: attribute "number" for single staves context.writeColumnElement(time); //clefs if (mxlAttributes.getClefs() != null) { for (MxlClef mxlClef : mxlAttributes.getClefs()) { ClefReader clefReader = new ClefReader(mxlClef); Clef clef = clefReader.read(); int staff = clefReader.readStaff(); if (clef != null) context.writeMeasureElement(clef, staff); } } //transposition changes - TODO: clean solution for instrument changes PitchedInstrument instrument = readTransposedInstrument(mxlAttributes.getTranspose()); if (instrument != null) { //write to all staves of this part for (int staff = 0; staff < context.getPartStaffIndices().getCount(); staff++) context.writeMeasureElement(new InstrumentChange(instrument), staff); } } private Key readKey(MxlKey mxlKey) { if (mxlKey == null) return null; //read fifths. currently, only -7 to 7 is supported (clamp, if needed) int mxlFifths = clamp(mxlKey.fifths, -7, 7); //write to column header (TODO: attribute "number" for single staves) Mode mode = getEnumValue(mxlKey.mode, Mode.values()); Key key = new TraditionalKey(mxlFifths, mode); return key; } private TimeSignature readTime(MxlTime mxlTime) { if (mxlTime == null) return null; TimeSignature time = null; MxlTimeContentType type = mxlTime.getContent().getTimeContentType(); if (type == MxlTimeContentType.SenzaMisura) { //senza misura time = new TimeSignature(timeSenzaMisura); } else if (type == MxlTimeContentType.NormalTime) { //normal time MxlNormalTime mxlNormalTime = (MxlNormalTime) mxlTime.getContent(); //common, cut or fractional? if (mxlTime.getSymbol() == MxlTimeSymbol.Cut) time = new TimeSignature(TimeType.timeAllaBreve); else if (mxlTime.getSymbol() == MxlTimeSymbol.Common) time = new TimeSignature(TimeType.timeCommon); else //otherwise, we currently support only normal fractional time signatures time = new TimeSignature(timeType(mxlNormalTime.getBeats(), mxlNormalTime.getBeatType())); } return time; } private PitchedInstrument readTransposedInstrument(MxlTranspose mxlTranspose) { if (mxlTranspose == null) return null; Transpose transpose = new TransposeReader(mxlTranspose).read(); PitchedInstrument instrument = new PitchedInstrument("", 0); instrument.setTranspose(transpose); return instrument; } }