/// <summary> /// recursive function (for nested tuplets) /// </summary> /// <param name="tupletDef"></param> /// <param name="iuds"></param> /// <param name="octaveShift"></param> /// <returns>current octave shift (can be null)</returns> private OctaveShift GetTupletComponents(TupletDef tupletDef, List <IUniqueDef> iuds, OctaveShift octaveShift) { var tupletComponents = tupletDef.Components; Event firstEvent = (Event)tupletComponents.Find(e => e is Event); if (firstEvent.TupletDefs == null) { firstEvent.TupletDefs = new List <TupletDef>(); } firstEvent.TupletDefs.Add(tupletDef); foreach (var component in tupletComponents) { if (component is Event tupletEvt) { tupletEvt.OctaveShift = octaveShift; octaveShift = null; iuds.Add(tupletEvt as IUniqueDef); } else if (component is Grace g) { var graceComponents = g.Components; foreach (var graceCompt in graceComponents) { // Assuming that Grace groups can only contain Events and Directions... if (graceCompt is Event graceEvt) { graceEvt.OctaveShift = octaveShift; octaveShift = null; iuds.Add(graceEvt as IUniqueDef); } } } else if (component is TupletDef tplet) { // recursive call octaveShift = GetTupletComponents(tplet, iuds, octaveShift); } } return(octaveShift); }
public TupletDef(XmlReader r, bool isTopLevel) { M.Assert(r.Name == "tuplet"); _isTopLevel = isTopLevel; int count = r.AttributeCount; for (int i = 0; i < count; i++) { r.MoveToAttribute(i); switch (r.Name) { case "outer": OuterDuration = new MNXDurationSymbol(r.Value); break; case "inner": InnerDuration = new MNXDurationSymbol(r.Value); break; case "orient": Orient = GetMNXOrientation(r.Value); break; case "staff": int staff; int.TryParse(r.Value, out staff); if (staff > 0) { Staff = staff; } break; case "show-number": ShowNumber = GetTupletNumberDisplay(r.Value); break; case "show-value": ShowValue = GetTupletNumberDisplay(r.Value); break; case "bracket": Bracket = GetTupletBracketDisplay(r.Value); break; default: throw new ApplicationException("Unknown attribute"); } } M.ReadToXmlElementTag(r, "event", "grace", "forward", "tuplet"); while (r.Name == "event" || r.Name == "grace" || r.Name == "forward" || r.Name == "tuplet") { if (r.Name == "tuplet" && r.NodeType == XmlNodeType.EndElement) { break; // pop 1 level } if (r.NodeType != XmlNodeType.EndElement) { switch (r.Name) { case "event": Event e = new Event(r); Components.Add(e); break; case "grace": Grace grace = new Grace(r); Components.Add(grace); break; case "forward": Forward forward = new Forward(r); Components.Add(forward); break; case "tuplet": TupletDef tuplet = new TupletDef(r, false); Components.Add(tuplet); break; } } M.ReadToXmlElementTag(r, "event", "grace", "forward", "tuplet"); } M.Assert(IEventsAndGraces.Count > 0); M.Assert(r.Name == "tuplet"); // end of (nested) tuplet content if (_isTopLevel) { int outerTicks = this.OuterDuration.GetDefaultTicks(); this.OuterDuration.TicksDuration = outerTicks; SetTicksDurationsInContentIgnoringGraces(outerTicks); } }
public Sequence(XmlReader r, TimeSignature currentTimeSig, int measureindex, int sequenceIndex) { M.Assert(r.Name == "sequence"); Index = sequenceIndex; int count = r.AttributeCount; for (int i = 0; i < count; i++) { r.MoveToAttribute(i); switch (r.Name) { case "orient": if (r.Value == "up") { Orient = Orientation.up; } else if (r.Value == "down") { Orient = Orientation.down; } break; case "staff": StaffIndex = Int32.Parse(r.Value) - 1; //MNX indices start at 1, MNXtoSVG indices start at 0. break; case "voice": VoiceID = r.Value; break; default: throw new ApplicationException("Unknown attribute"); } } M.ReadToXmlElementTag(r, "event", "tuplet", "grace", "directions", "beams", "forward"); while (r.Name == "event" || r.Name == "tuplet" || r.Name == "grace" || r.Name == "directions" || r.Name == "beams" || r.Name == "forward") { if (r.NodeType != XmlNodeType.EndElement) { switch (r.Name) { case "event": Event e = new Event(r); Components.Add(e); break; case "tuplet": TupletDef tupletDef = new TupletDef(r, true); Components.Add(tupletDef); break; case "grace": Grace grace = new Grace(r); // Grace notes are initially given the normal TickDuration for their MNXDurationSymbol, // so that the different grace duration classes have different, proportional sizes. // All ticksPosInScore and ticksDuration values are updated for grace notes // when the whole score has been read (in MNX.AdjustForGraceNotes()) Components.Add(grace); break; case "directions": Directions = new SequenceDirections(r, currentTimeSig); break; case "beams": Components.Add(new BeamBlocks(r)); break; case "forward": Forward forward = new Forward(r); Components.Add(forward); break; } } M.ReadToXmlElementTag(r, "event", "tuplet", "grace", "directions", "beams", "forward", "sequence"); } M.Assert(IEventsAndGraces.Count > 0); M.Assert(r.Name == "sequence"); // end of sequence content }