private int width; /** Width of symbol */ #endregion Fields #region Constructors /** * Create a new AccidSymbol with the given accidental, that is * displayed at the given note in the given clef. */ public AccidSymbol(Accid accid, WhiteNote note, Clef clef) { this.accid = accid; this.whitenote = note; this.clef = clef; width = MinWidth; }
private int width_to_pair; /** The width (in pixels) to the chord pair */ #endregion Fields #region Constructors /** Create a new stem. The top note, bottom note, and direction are * needed for drawing the vertical line of the stem. The duration is * needed to draw the tail of the stem. The overlap boolean is true * if the notes in the chord overlap. If the notes overlap, the * stem must be drawn on the right side. */ public Stem(WhiteNote bottom, WhiteNote top, NoteDuration duration, int direction, bool overlap) { this.top = top; this.bottom = bottom; this.duration = duration; this.direction = direction; this.notesoverlap = overlap; if (direction == Up || notesoverlap) side = RightSide; else side = LeftSide; end = CalculateEnd(); pair = null; width_to_pair = 0; receiver_in_pair = false; }
/** Get the letter (A, A#, Bb) representing this note */ private string Letter(int notenumber, WhiteNote whitenote) { int notescale = NoteScale.FromNumber(notenumber); switch(notescale) { case NoteScale.A: return "A"; case NoteScale.B: return "B"; case NoteScale.C: return "C"; case NoteScale.D: return "D"; case NoteScale.E: return "E"; case NoteScale.F: return "F"; case NoteScale.G: return "G"; case NoteScale.Asharp: if (whitenote.Letter == WhiteNote.A) return "A#"; else return "Bb"; case NoteScale.Csharp: if (whitenote.Letter == WhiteNote.C) return "C#"; else return "Db"; case NoteScale.Dsharp: if (whitenote.Letter == WhiteNote.D) return "D#"; else return "Eb"; case NoteScale.Fsharp: if (whitenote.Letter == WhiteNote.F) return "F#"; else return "Gb"; case NoteScale.Gsharp: if (whitenote.Letter == WhiteNote.G) return "G#"; else return "Ab"; default: return ""; } }
/** Calculate the stem direction (Up or down) based on the top and * bottom note in the chord. If the average of the notes is above * the middle of the staff, the direction is down. Else, the * direction is up. */ private static int StemDirection(WhiteNote bottom, WhiteNote top, Clef clef) { WhiteNote middle; if (clef == Clef.Treble) middle = new WhiteNote(WhiteNote.B, 5); else middle = new WhiteNote(WhiteNote.D, 3); int dist = middle.Dist(bottom) + middle.Dist(top); if (dist >= 0) return Stem.Up; else return Stem.Down; }
/** Draw the black circle notes. * @param ytop The ylocation (in pixels) where the top of the staff starts. * @param topstaff The white note of the top of the staff. */ public void DrawNotes(Graphics g, Pen pen, int ytop, WhiteNote topstaff) { pen.Width = 1; foreach (NoteData note in notedata) { /* Get the x,y position to draw the note */ int ynote = ytop + topstaff.Dist(note.whitenote) * SheetMusic.NoteHeight/2; int xnote = SheetMusic.LineSpace/4; if (!note.leftside) xnote += SheetMusic.NoteWidth; /* Draw rotated ellipse. You must first translate (0,0) * to the center of the ellipse. */ g.TranslateTransform(xnote + SheetMusic.NoteWidth/2 + 1, ynote - SheetMusic.LineWidth + SheetMusic.NoteHeight/2); g.RotateTransform(-45); if (sheetmusic != null) { pen.Color = sheetmusic.NoteColor(note.number); } else { pen.Color = Color.Black; } if (note.duration == NoteDuration.Whole || note.duration == NoteDuration.Half || note.duration == NoteDuration.DottedHalf) { g.DrawEllipse(pen, -SheetMusic.NoteWidth/2, -SheetMusic.NoteHeight/2, SheetMusic.NoteWidth, SheetMusic.NoteHeight-1); g.DrawEllipse(pen, -SheetMusic.NoteWidth/2, -SheetMusic.NoteHeight/2 + 1, SheetMusic.NoteWidth, SheetMusic.NoteHeight-2); g.DrawEllipse(pen, -SheetMusic.NoteWidth/2, -SheetMusic.NoteHeight/2 + 1, SheetMusic.NoteWidth, SheetMusic.NoteHeight-3); } else { Brush brush = Brushes.Black; if (pen.Color != Color.Black) { brush = new SolidBrush(pen.Color); } g.FillEllipse(brush, -SheetMusic.NoteWidth/2, -SheetMusic.NoteHeight/2, SheetMusic.NoteWidth, SheetMusic.NoteHeight-1); if (pen.Color != Color.Black) { brush.Dispose(); } } pen.Color = Color.Black; g.DrawEllipse(pen, -SheetMusic.NoteWidth/2, -SheetMusic.NoteHeight/2, SheetMusic.NoteWidth, SheetMusic.NoteHeight-1); g.RotateTransform(45); g.TranslateTransform( - (xnote + SheetMusic.NoteWidth/2 + 1), - (ynote - SheetMusic.LineWidth + SheetMusic.NoteHeight/2)); /* Draw a dot if this is a dotted duration. */ if (note.duration == NoteDuration.DottedHalf || note.duration == NoteDuration.DottedQuarter || note.duration == NoteDuration.DottedEighth) { g.FillEllipse(Brushes.Black, xnote + SheetMusic.NoteWidth + SheetMusic.LineSpace/3, ynote + SheetMusic.LineSpace/3, 4, 4); } /* Draw horizontal lines if note is above/below the staff */ WhiteNote top = topstaff.Add(1); int dist = note.whitenote.Dist(top); int y = ytop - SheetMusic.LineWidth; if (dist >= 2) { for (int i = 2; i <= dist; i += 2) { y -= SheetMusic.NoteHeight; g.DrawLine(pen, xnote - SheetMusic.LineSpace/4, y, xnote + SheetMusic.NoteWidth + SheetMusic.LineSpace/4, y); } } WhiteNote bottom = top.Add(-8); y = ytop + (SheetMusic.LineSpace + SheetMusic.LineWidth) * 4 - 1; dist = bottom.Dist(note.whitenote); if (dist >= 2) { for (int i = 2; i <= dist; i+= 2) { y += SheetMusic.NoteHeight; g.DrawLine(pen, xnote - SheetMusic.LineSpace/4, y, xnote + SheetMusic.NoteWidth + SheetMusic.LineSpace/4, y); } } /* End drawing horizontal lines */ } }
/** Draw the note letters (A, A#, Bb, etc) next to the note circles. * @param ytop The ylocation (in pixels) where the top of the staff starts. * @param topstaff The white note of the top of the staff. */ public void DrawNoteLetters(Graphics g, Pen pen, int ytop, WhiteNote topstaff) { bool overlap = NotesOverlap(notedata, 0, notedata.Length); pen.Width = 1; foreach (NoteData note in notedata) { if (!note.leftside) { /* There's not enought pixel room to show the letter */ continue; } /* Get the x,y position to draw the note */ int ynote = ytop + topstaff.Dist(note.whitenote) * SheetMusic.NoteHeight/2; /* Draw the letter to the right side of the note */ int xnote = SheetMusic.NoteWidth + SheetMusic.LineSpace/4; if (note.duration == NoteDuration.DottedHalf || note.duration == NoteDuration.DottedQuarter || note.duration == NoteDuration.DottedEighth || overlap) { xnote += SheetMusic.NoteWidth/2; } g.DrawString(NoteName(note.number, note.whitenote), SheetMusic.LetterFont, Brushes.Black, xnote, ynote - SheetMusic.NoteHeight/2); } }
/** Get the name for this note */ private string NoteName(int notenumber, WhiteNote whitenote) { if (sheetmusic.ShowNoteLetters == MidiOptions.NoteNameLetter) { return Letter(notenumber, whitenote); } else if (sheetmusic.ShowNoteLetters == MidiOptions.NoteNameFixedDoReMi) { string[] fixedDoReMi = { "La", "Li", "Ti", "Do", "Di", "Re", "Ri", "Mi", "Fa", "Fi", "So", "Si" }; int notescale = NoteScale.FromNumber(notenumber); return fixedDoReMi[notescale]; } else if (sheetmusic.ShowNoteLetters == MidiOptions.NoteNameMovableDoReMi) { string[] fixedDoReMi = { "La", "Li", "Ti", "Do", "Di", "Re", "Ri", "Mi", "Fa", "Fi", "So", "Si" }; int mainscale = sheetmusic.MainKey.Notescale(); int diff = NoteScale.C - mainscale; notenumber += diff; if (notenumber < 0) { notenumber += 12; } int notescale = NoteScale.FromNumber(notenumber); return fixedDoReMi[notescale]; } else if (sheetmusic.ShowNoteLetters == MidiOptions.NoteNameFixedNumber) { string[] num = { "10", "11", "12", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; int notescale = NoteScale.FromNumber(notenumber); return num[notescale]; } else if (sheetmusic.ShowNoteLetters == MidiOptions.NoteNameMovableNumber) { string[] num = { "10", "11", "12", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; int mainscale = sheetmusic.MainKey.Notescale(); int diff = NoteScale.C - mainscale; notenumber += diff; if (notenumber < 0) { notenumber += 12; } int notescale = NoteScale.FromNumber(notenumber); return num[notescale]; } else { return ""; } }
/** Draw the vertical line of the stem * @param ytop The y location (in pixels) where the top of the staff starts. * @param topstaff The note at the top of the staff. */ private void DrawVerticalLine(Graphics g, Pen pen, int ytop, WhiteNote topstaff) { int xstart; if (side == LeftSide) xstart = SheetMusic.LineSpace/4 + 1; else xstart = SheetMusic.LineSpace/4 + SheetMusic.NoteWidth; if (direction == Up) { int y1 = ytop + topstaff.Dist(bottom) * SheetMusic.NoteHeight/2 + SheetMusic.NoteHeight/4; int ystem = ytop + topstaff.Dist(end) * SheetMusic.NoteHeight/2; g.DrawLine(pen, xstart, y1, xstart, ystem); } else if (direction == Down) { int y1 = ytop + topstaff.Dist(top) * SheetMusic.NoteHeight/2 + SheetMusic.NoteHeight; if (side == LeftSide) y1 = y1 - SheetMusic.NoteHeight/4; else y1 = y1 - SheetMusic.NoteHeight/2; int ystem = ytop + topstaff.Dist(end) * SheetMusic.NoteHeight/2 + SheetMusic.NoteHeight; g.DrawLine(pen, xstart, y1, xstart, ystem); } }
/* Draw a horizontal beam stem, connecting this stem with the Stem pair. * @param ytop The y location (in pixels) where the top of the staff starts. * @param topstaff The note at the top of the staff. */ private void DrawHorizBarStem(Graphics g, Pen pen, int ytop, WhiteNote topstaff) { pen.Width = SheetMusic.NoteHeight/2; int xstart = 0; int xstart2 = 0; if (side == LeftSide) xstart = SheetMusic.LineSpace/4 + 1; else if (side == RightSide) xstart = SheetMusic.LineSpace/4 + SheetMusic.NoteWidth; if (pair.side == LeftSide) xstart2 = SheetMusic.LineSpace/4 + 1; else if (pair.side == RightSide) xstart2 = SheetMusic.LineSpace/4 + SheetMusic.NoteWidth; if (direction == Up) { int xend = width_to_pair + xstart2; int ystart = ytop + topstaff.Dist(end) * SheetMusic.NoteHeight/2; int yend = ytop + topstaff.Dist(pair.end) * SheetMusic.NoteHeight/2; if (duration == NoteDuration.Eighth || duration == NoteDuration.DottedEighth || duration == NoteDuration.Triplet || duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) { g.DrawLine(pen, xstart, ystart, xend, yend); } ystart += SheetMusic.NoteHeight; yend += SheetMusic.NoteHeight; /* A dotted eighth will connect to a 16th note. */ if (duration == NoteDuration.DottedEighth) { int x = xend - SheetMusic.NoteHeight; double slope = (yend - ystart) * 1.0 / (xend - xstart); int y = (int)(slope * (x - xend) + yend); g.DrawLine(pen, x, y, xend, yend); } if (duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) { g.DrawLine(pen, xstart, ystart, xend, yend); } ystart += SheetMusic.NoteHeight; yend += SheetMusic.NoteHeight; if (duration == NoteDuration.ThirtySecond) { g.DrawLine(pen, xstart, ystart, xend, yend); } } else { int xend = width_to_pair + xstart2; int ystart = ytop + topstaff.Dist(end) * SheetMusic.NoteHeight/2 + SheetMusic.NoteHeight; int yend = ytop + topstaff.Dist(pair.end) * SheetMusic.NoteHeight/2 + SheetMusic.NoteHeight; if (duration == NoteDuration.Eighth || duration == NoteDuration.DottedEighth || duration == NoteDuration.Triplet || duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) { g.DrawLine(pen, xstart, ystart, xend, yend); } ystart -= SheetMusic.NoteHeight; yend -= SheetMusic.NoteHeight; /* A dotted eighth will connect to a 16th note. */ if (duration == NoteDuration.DottedEighth) { int x = xend - SheetMusic.NoteHeight; double slope = (yend - ystart) * 1.0 / (xend - xstart); int y = (int)(slope * (x - xend) + yend); g.DrawLine(pen, x, y, xend, yend); } if (duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) { g.DrawLine(pen, xstart, ystart, xend, yend); } ystart -= SheetMusic.NoteHeight; yend -= SheetMusic.NoteHeight; if (duration == NoteDuration.ThirtySecond) { g.DrawLine(pen, xstart, ystart, xend, yend); } } pen.Width = 1; }
/** Draw a curvy stem tail. This is only used for single chords, not chord pairs. * @param ytop The y location (in pixels) where the top of the staff starts. * @param topstaff The note at the top of the staff. */ private void DrawCurvyStem(Graphics g, Pen pen, int ytop, WhiteNote topstaff) { pen.Width = 2; int xstart = 0; if (side == LeftSide) xstart = SheetMusic.LineSpace/4 + 1; else xstart = SheetMusic.LineSpace/4 + SheetMusic.NoteWidth; if (direction == Up) { int ystem = ytop + topstaff.Dist(end) * SheetMusic.NoteHeight/2; if (duration == NoteDuration.Eighth || duration == NoteDuration.DottedEighth || duration == NoteDuration.Triplet || duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) { g.DrawBezier(pen, xstart, ystem, xstart, ystem + 3*SheetMusic.LineSpace/2, xstart + SheetMusic.LineSpace*2, ystem + SheetMusic.NoteHeight*2, xstart + SheetMusic.LineSpace/2, ystem + SheetMusic.NoteHeight*3); } ystem += SheetMusic.NoteHeight; if (duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) { g.DrawBezier(pen, xstart, ystem, xstart, ystem + 3*SheetMusic.LineSpace/2, xstart + SheetMusic.LineSpace*2, ystem + SheetMusic.NoteHeight*2, xstart + SheetMusic.LineSpace/2, ystem + SheetMusic.NoteHeight*3); } ystem += SheetMusic.NoteHeight; if (duration == NoteDuration.ThirtySecond) { g.DrawBezier(pen, xstart, ystem, xstart, ystem + 3*SheetMusic.LineSpace/2, xstart + SheetMusic.LineSpace*2, ystem + SheetMusic.NoteHeight*2, xstart + SheetMusic.LineSpace/2, ystem + SheetMusic.NoteHeight*3); } } else if (direction == Down) { int ystem = ytop + topstaff.Dist(end)*SheetMusic.NoteHeight/2 + SheetMusic.NoteHeight; if (duration == NoteDuration.Eighth || duration == NoteDuration.DottedEighth || duration == NoteDuration.Triplet || duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) { g.DrawBezier(pen, xstart, ystem, xstart, ystem - SheetMusic.LineSpace, xstart + SheetMusic.LineSpace*2, ystem - SheetMusic.NoteHeight*2, xstart + SheetMusic.LineSpace, ystem - SheetMusic.NoteHeight*2 - SheetMusic.LineSpace/2); } ystem -= SheetMusic.NoteHeight; if (duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) { g.DrawBezier(pen, xstart, ystem, xstart, ystem - SheetMusic.LineSpace, xstart + SheetMusic.LineSpace*2, ystem - SheetMusic.NoteHeight*2, xstart + SheetMusic.LineSpace, ystem - SheetMusic.NoteHeight*2 - SheetMusic.LineSpace/2); } ystem -= SheetMusic.NoteHeight; if (duration == NoteDuration.ThirtySecond) { g.DrawBezier(pen, xstart, ystem, xstart, ystem - SheetMusic.LineSpace, xstart + SheetMusic.LineSpace*2, ystem - SheetMusic.NoteHeight*2, xstart + SheetMusic.LineSpace, ystem - SheetMusic.NoteHeight*2 - SheetMusic.LineSpace/2); } } pen.Width = 1; }
/** Draw this stem. * @param ytop The y location (in pixels) where the top of the staff starts. * @param topstaff The note at the top of the staff. */ public void Draw(Graphics g, Pen pen, int ytop, WhiteNote topstaff) { if (duration == NoteDuration.Whole) return; DrawVerticalLine(g, pen, ytop, topstaff); if (duration == NoteDuration.Quarter || duration == NoteDuration.DottedQuarter || duration == NoteDuration.Half || duration == NoteDuration.DottedHalf || receiver_in_pair) { return; } if (pair != null) DrawHorizBarStem(g, pen, ytop, topstaff); else DrawCurvyStem(g, pen, ytop, topstaff); }
/** Change the direction of the stem. This function is called by * ChordSymbol.MakePair(). When two chords are joined by a horizontal * beam, their stems must point in the same direction (up or down). */ public void ChangeDirection(int newdirection) { direction = newdirection; if (direction == Up || notesoverlap) side = RightSide; else side = LeftSide; end = CalculateEnd(); }
/** Create the Accidental symbols for this key, for * the treble and bass clefs. */ private void CreateSymbols() { int count = Math.Max(num_sharps, num_flats); treble = new AccidSymbol[count]; bass = new AccidSymbol[count]; if (count == 0) { return; } WhiteNote[] treblenotes = null; WhiteNote[] bassnotes = null; if (num_sharps > 0) { treblenotes = new WhiteNote[] { new WhiteNote(WhiteNote.F, 5), new WhiteNote(WhiteNote.C, 5), new WhiteNote(WhiteNote.G, 5), new WhiteNote(WhiteNote.D, 5), new WhiteNote(WhiteNote.A, 6), new WhiteNote(WhiteNote.E, 5) }; bassnotes = new WhiteNote[] { new WhiteNote(WhiteNote.F, 3), new WhiteNote(WhiteNote.C, 3), new WhiteNote(WhiteNote.G, 3), new WhiteNote(WhiteNote.D, 3), new WhiteNote(WhiteNote.A, 4), new WhiteNote(WhiteNote.E, 3) }; } else if (num_flats > 0) { treblenotes = new WhiteNote[] { new WhiteNote(WhiteNote.B, 5), new WhiteNote(WhiteNote.E, 5), new WhiteNote(WhiteNote.A, 5), new WhiteNote(WhiteNote.D, 5), new WhiteNote(WhiteNote.G, 4), new WhiteNote(WhiteNote.C, 5) }; bassnotes = new WhiteNote[] { new WhiteNote(WhiteNote.B, 3), new WhiteNote(WhiteNote.E, 3), new WhiteNote(WhiteNote.A, 3), new WhiteNote(WhiteNote.D, 3), new WhiteNote(WhiteNote.G, 2), new WhiteNote(WhiteNote.C, 3) }; } Accid a = Accid.None; if (num_sharps > 0) a = Accid.Sharp; else a = Accid.Flat; for (int i = 0; i < count; i++) { treble[i] = new AccidSymbol(a, treblenotes[i], Clef.Treble); bass[i] = new AccidSymbol(a, bassnotes[i], Clef.Bass); } }