/// <summary> /// Determine if there should be a line through the note head because it is off the staff /// </summary> /// <param name="pitch">The pitch to check for a line</param> /// <param name="clefSign">The clef that is affecting the staff</param> /// <returns>True if there should be a line, false otherwise</returns> private static bool LineThroughNoteHead(Pitch pitch, ClefSign clefSign) { Pitch bottomOfStaff = null; Pitch topOfStaff = null; switch (clefSign) { case ClefSign.G: bottomOfStaff = Constants.Note.TrebelDefaults.BOTTOM_OF_STAFF; topOfStaff = Constants.Note.TrebelDefaults.TOP_OF_STAFF; break; case ClefSign.F: //todo: F values break; case ClefSign.C: //todo: C values break; //todo: all clefs } if (bottomOfStaff == null || topOfStaff == null) { return(false); } int bottomCompare = PitchComparer.CompareStatic(pitch, bottomOfStaff); int topCompare = PitchComparer.CompareStatic(pitch, topOfStaff); return((bottomCompare < 0 && bottomCompare % 2 == 0) || topCompare > 0 && topCompare % 2 == 0); }
public Clef(ClefSign sign, string line) { if (line == null) throw new ArgumentNullException("line"); this.Sign = sign; this.Line = line; }
public static Attributes CreateAttribute(AttributeProperties ai) { ObjectFactory factory = new ObjectFactory(); Attributes attributes = factory.createAttributes(); //create a key Key key = factory.createKey(); //create a time element Time time = factory.createTime(); //create a clef element Clef clef = factory.createClef(); //set the staffs attributes.setStaves(new BigInteger(ai.staves.ToString())); //now add the elements to the attributes if (ai.divisions != 0) { //set the divisions attributes.setDivisions(new BigDecimal(ai.divisions)); } if (ai.fifths != "") { //set the key key.setFifths(new BigInteger(ai.fifths)); key.setMode(ai.mode); //add the key attributes.getKey().add(key); } if (ai.BeatsPerMeasure != "") { //set the time signature time.getTimeSignature().add(factory.createTimeBeats(ai.BeatsPerMeasure)); time.getTimeSignature().add(factory.createTimeBeatType(ai.BeatType)); // add the time signature attributes.getTime().add(time); } // add the cleff if (ai.ClefSign != "") { //set the clef clef.setSign(ClefSign.fromValue(ai.ClefSign)); clef.setLine(new BigInteger(ai.ClefLine)); clef.setNumber(new BigInteger(ai.ClefStaff.ToString())); attributes.getClef().add(clef); } return(attributes); }
private static Pitch GetDefaultPitch(ClefSign clefSign) { Pitch pitch = Constants.Note.TrebelDefaults.PITCH; switch (clefSign) { case ClefSign.C: break; case ClefSign.F: break; case ClefSign.G: default: pitch = Constants.Note.TrebelDefaults.PITCH; break; //todo: bass clef //todo: more clef signs } return(pitch); }
public Clef(ClefSign sign, int line) { this.Sign = sign; this.Line = line.ToString(); }
//todo: put note rendering into its own class /// <summary> /// Parse the contents of a note and prepare the basic label /// </summary> /// <param name="note">The note to parse and create a label for</param> /// <param name="fontSize">The size of the font being used</param> /// <param name="clefSign">The sign of the clef for this note. Default is G</param> /// <returns>A label with the note in it</returns> public static Panel RenderNoteOrRest(Note note, double fontSize, ClefSign clefSign = ClefSign.G) { double yOffset = WPFRendering.GetFontFraction(-2, fontSize); //offset cause not exactly in right spot //todo: Render appropriate connectors //todo: render barline //todo: tuplets, triplets, beams //todo: likely remove this whole function because will need to draw own notes due to stem when beaming String noteChar = Constants.Note.Characters.WHOLE_NOTE; Panel grid = WPFRendering.CreateAutoSizingGrid(); //todo: if it has a rest, then parse as rest, otherwise parse as note bool isRest = note.Items.SingleOrDefault(i => i.GetType() == typeof(Rest)) != null; if (!isRest) { FrameworkElement noteHead = RenderNoteHead(note, fontSize); noteHead.Margin = new Thickness(noteHead.Margin.Left, noteHead.Margin.Top + yOffset, noteHead.Margin.Right, noteHead.Margin.Bottom); grid.Children.Add(noteHead); //todo: stems when beamed... This will likely require stems to be drawn after the note heads of the beaming // however, beaming is not supposed to go over measures so this will save some of the problems that this could have //get pitch object Pitch pitch = (Pitch)note.Items.SingleOrDefault(t => t.GetType() == typeof(Pitch)); if (pitch != null) { //todo: make into function //move grid up or down appropriately Pitch clefDefaultPitch = GetDefaultPitch(clefSign); int stepDifference = clefDefaultPitch.step - pitch.step + (int.Parse(Constants.Note.TrebelDefaults.PITCH.octave) - int.Parse(pitch.octave)) * 8; if (pitch.step == Step.A || pitch.step == Step.B) { stepDifference -= 7; } // todo: octave var difference = (int.Parse(pitch.octave) - int.Parse(clefDefaultPitch.octave)); if (difference != 0) { difference *= 7; stepDifference += (difference < 0) ? difference : -difference; } const double stepDistance = 5.5; double topOffset = WPFRendering.GetFontFraction(39, fontSize); double marginTop = noteHead.Margin.Top + (stepDifference * WPFRendering.GetFontFraction(stepDistance, fontSize)) + topOffset; // create and add note stem System.Windows.Shapes.Line noteStem = new System.Windows.Shapes.Line(); if (note.stem.Value != stemvalue.none) { noteStem = CreateNoteStem(yOffset, note, noteHead, fontSize); } grid.Children.Add(noteStem); // add the note head noteHead.Margin = new Thickness(noteHead.Margin.Left, marginTop, noteHead.Margin.Right, noteHead.Margin.Bottom); noteStem.Margin = new Thickness(noteStem.Margin.Left, marginTop, noteStem.Margin.Right, noteStem.Margin.Bottom); //debug: remove Console.Out.WriteLine("default: " + Constants.Note.TrebelDefaults.PITCH.step + " " + pitch.step + pitch.octave + " " + stepDifference); } // render ledger line if necessary if (LineThroughNoteHead(pitch, clefSign)) { FrameworkElement ledgerLine = RenderLedgerLine(noteHead, fontSize); grid.Children.Add(ledgerLine); } //todo: accidentals //todo: clef change on note //todo: other notes? //todo: make into function //todo: if is above half of the staff, rotate so everything points down // rotate head /* * RotateTransform rt = new RotateTransform(180); * rt.CenterX = noteHead.ActualWidth / 2; * rt.CenterY = 10 * 3 / 4; //todo: use note height calculation from render notehead * grid.RenderTransform = rt; */ } else { FrameworkElement restElement = RenderRest(note, fontSize); restElement.Margin = new Thickness(0, -WPFRendering.GetFontHeight(fontSize, Constants.MusicFonts.DEFAULT) / 4, 0, 0); grid.Children.Add(restElement); } //grid.VerticalAlignment = VerticalAlignment.Top; WPFRendering.RecalculateSize(grid); return(grid); }
/// <summary> /// Determine if there should be a line through the note head because it is off the staff /// </summary> /// <param name="pitch">The pitch to check for a line</param> /// <param name="clefSign">The clef that is affecting the staff</param> /// <returns>True if there should be a line, false otherwise</returns> private static bool LineThroughNoteHead(Pitch pitch, ClefSign clefSign) { Pitch bottomOfStaff = null; Pitch topOfStaff = null; switch(clefSign) { case ClefSign.G: bottomOfStaff = Constants.Note.TrebelDefaults.BOTTOM_OF_STAFF; topOfStaff = Constants.Note.TrebelDefaults.TOP_OF_STAFF; break; case ClefSign.F: //todo: F values break; case ClefSign.C: //todo: C values break; //todo: all clefs } if(bottomOfStaff == null || topOfStaff == null) return false; int bottomCompare = PitchComparer.CompareStatic(pitch, bottomOfStaff); int topCompare = PitchComparer.CompareStatic(pitch, topOfStaff); return ((bottomCompare < 0 && bottomCompare%2 == 0) || topCompare > 0 && topCompare%2 == 0); }
private static Pitch GetDefaultPitch(ClefSign clefSign) { Pitch pitch = Constants.Note.TrebelDefaults.PITCH; switch (clefSign) { case ClefSign.C: break; case ClefSign.F: break; case ClefSign.G: default: pitch = Constants.Note.TrebelDefaults.PITCH; break; //todo: bass clef //todo: more clef signs } return pitch; }
//todo: put note rendering into its own class /// <summary> /// Parse the contents of a note and prepare the basic label /// </summary> /// <param name="note">The note to parse and create a label for</param> /// <param name="fontSize">The size of the font being used</param> /// <param name="clefSign">The sign of the clef for this note. Default is G</param> /// <returns>A label with the note in it</returns> public static Panel RenderNoteOrRest(Note note, double fontSize, ClefSign clefSign = ClefSign.G) { double yOffset = WPFRendering.GetFontFraction(-2, fontSize); //offset cause not exactly in right spot //todo: Render appropriate connectors //todo: render barline //todo: tuplets, triplets, beams //todo: likely remove this whole function because will need to draw own notes due to stem when beaming String noteChar = Constants.Note.Characters.WHOLE_NOTE; Panel grid = WPFRendering.CreateAutoSizingGrid(); //todo: if it has a rest, then parse as rest, otherwise parse as note bool isRest = note.Items.SingleOrDefault(i => i.GetType() == typeof(Rest)) != null; if (!isRest) { FrameworkElement noteHead = RenderNoteHead(note, fontSize); noteHead.Margin = new Thickness(noteHead.Margin.Left, noteHead.Margin.Top + yOffset, noteHead.Margin.Right, noteHead.Margin.Bottom); grid.Children.Add(noteHead); //todo: stems when beamed... This will likely require stems to be drawn after the note heads of the beaming // however, beaming is not supposed to go over measures so this will save some of the problems that this could have //get pitch object Pitch pitch = (Pitch)note.Items.SingleOrDefault(t => t.GetType() == typeof (Pitch)); if (pitch != null) { //todo: make into function //move grid up or down appropriately Pitch clefDefaultPitch = GetDefaultPitch(clefSign); int stepDifference = clefDefaultPitch.step - pitch.step + (int.Parse(Constants.Note.TrebelDefaults.PITCH.octave) - int.Parse(pitch.octave)) * 8; if(pitch.step == Step.A || pitch.step == Step.B) { stepDifference -= 7; } // todo: octave var difference = (int.Parse(pitch.octave) - int.Parse(clefDefaultPitch.octave)); if (difference != 0) { difference *= 7; stepDifference += (difference < 0) ? difference : -difference; } const double stepDistance = 5.5; double topOffset = WPFRendering.GetFontFraction(39, fontSize); double marginTop = noteHead.Margin.Top + (stepDifference * WPFRendering.GetFontFraction(stepDistance, fontSize)) + topOffset; // create and add note stem System.Windows.Shapes.Line noteStem = new System.Windows.Shapes.Line(); if (note.stem.Value != stemvalue.none) noteStem = CreateNoteStem(yOffset, note, noteHead, fontSize); grid.Children.Add(noteStem); // add the note head noteHead.Margin = new Thickness(noteHead.Margin.Left, marginTop, noteHead.Margin.Right, noteHead.Margin.Bottom); noteStem.Margin = new Thickness(noteStem.Margin.Left, marginTop, noteStem.Margin.Right, noteStem.Margin.Bottom); //debug: remove Console.Out.WriteLine("default: " + Constants.Note.TrebelDefaults.PITCH.step + " " + pitch.step + pitch.octave + " " + stepDifference); } // render ledger line if necessary if(LineThroughNoteHead(pitch, clefSign)) { FrameworkElement ledgerLine = RenderLedgerLine(noteHead, fontSize); grid.Children.Add(ledgerLine); } //todo: accidentals //todo: clef change on note //todo: other notes? //todo: make into function //todo: if is above half of the staff, rotate so everything points down // rotate head /* RotateTransform rt = new RotateTransform(180); rt.CenterX = noteHead.ActualWidth / 2; rt.CenterY = 10 * 3 / 4; //todo: use note height calculation from render notehead grid.RenderTransform = rt; */ } else { FrameworkElement restElement = RenderRest(note, fontSize); restElement.Margin = new Thickness(0, -WPFRendering.GetFontHeight(fontSize, Constants.MusicFonts.DEFAULT) / 4, 0, 0); grid.Children.Add(restElement); } //grid.VerticalAlignment = VerticalAlignment.Top; WPFRendering.RecalculateSize(grid); return grid; }