@Override
 public String toString() {
   return String.format(
       "Stem duration=%1$s direction=%2$s top=%3$s bottom=%4$s end=%5$s"
           + " overlap=%6$s side=%7$s width_to_pair=%8$s receiver_in_pair=%9$s",
       duration,
       direction,
       top.toString(),
       bottom.toString(),
       end.toString(),
       notesoverlap,
       side,
       width_to_pair,
       receiver_in_pair);
 }
  /**
   * 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(Canvas canvas, Paint paint, 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;

      canvas.drawLine(xstart, y1, xstart, ystem, paint);
    } 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;

      canvas.drawLine(xstart, y1, xstart, ystem, paint);
    }
  }
 /** Calculate the vertical position (white note key) where the stem ends */
 public WhiteNote CalculateEnd() {
   if (direction == Up) {
     WhiteNote w = top;
     w = w.Add(6);
     if (duration == NoteDuration.Sixteenth) {
       w = w.Add(2);
     } else if (duration == NoteDuration.ThirtySecond) {
       w = w.Add(4);
     }
     return w;
   } else if (direction == Down) {
     WhiteNote w = bottom;
     w = w.Add(-6);
     if (duration == NoteDuration.Sixteenth) {
       w = w.Add(-2);
     } else if (duration == NoteDuration.ThirtySecond) {
       w = w.Add(-4);
     }
     return w;
   } else {
     return null; /* Shouldn't happen */
   }
 }
  /* 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(Canvas canvas, Paint paint, int ytop, WhiteNote topstaff) {
    paint.setStrokeWidth(SheetMusic.NoteHeight / 2);
    paint.setStrokeCap(Paint.Cap.BUTT);
    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) {

        canvas.drawLine(xstart, ystart, xend, yend, paint);
      }
      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);

        canvas.drawLine(x, y, xend, yend, paint);
      }

      if (duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) {

        canvas.drawLine(xstart, ystart, xend, yend, paint);
      }
      ystart += SheetMusic.NoteHeight;
      yend += SheetMusic.NoteHeight;

      if (duration == NoteDuration.ThirtySecond) {
        canvas.drawLine(xstart, ystart, xend, yend, paint);
      }
    } 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) {

        canvas.drawLine(xstart, ystart, xend, yend, paint);
      }
      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);

        canvas.drawLine(x, y, xend, yend, paint);
      }

      if (duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) {

        canvas.drawLine(xstart, ystart, xend, yend, paint);
      }
      ystart -= SheetMusic.NoteHeight;
      yend -= SheetMusic.NoteHeight;

      if (duration == NoteDuration.ThirtySecond) {
        canvas.drawLine(xstart, ystart, xend, yend, paint);
      }
    }
    paint.setStrokeWidth(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(Canvas canvas, Paint paint, int ytop, WhiteNote topstaff) {
    Path bezierPath;
    paint.setStrokeWidth(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) {

        bezierPath = new Path();
        bezierPath.moveTo(xstart, ystem);
        bezierPath.cubicTo(
            xstart,
            ystem + 3 * SheetMusic.LineSpace / 2,
            xstart + SheetMusic.LineSpace * 2,
            ystem + SheetMusic.NoteHeight * 2,
            xstart + SheetMusic.LineSpace / 2,
            ystem + SheetMusic.NoteHeight * 3);
        canvas.drawPath(bezierPath, paint);
      }
      ystem += SheetMusic.NoteHeight;

      if (duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) {

        bezierPath = new Path();
        bezierPath.moveTo(xstart, ystem);
        bezierPath.cubicTo(
            xstart,
            ystem + 3 * SheetMusic.LineSpace / 2,
            xstart + SheetMusic.LineSpace * 2,
            ystem + SheetMusic.NoteHeight * 2,
            xstart + SheetMusic.LineSpace / 2,
            ystem + SheetMusic.NoteHeight * 3);
        canvas.drawPath(bezierPath, paint);
      }

      ystem += SheetMusic.NoteHeight;
      if (duration == NoteDuration.ThirtySecond) {
        bezierPath = new Path();
        bezierPath.moveTo(xstart, ystem);
        bezierPath.cubicTo(
            xstart,
            ystem + 3 * SheetMusic.LineSpace / 2,
            xstart + SheetMusic.LineSpace * 2,
            ystem + SheetMusic.NoteHeight * 2,
            xstart + SheetMusic.LineSpace / 2,
            ystem + SheetMusic.NoteHeight * 3);
        canvas.drawPath(bezierPath, paint);
      }

    } 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) {

        bezierPath = new Path();
        bezierPath.moveTo(xstart, ystem);
        bezierPath.cubicTo(
            xstart,
            ystem - SheetMusic.LineSpace,
            xstart + SheetMusic.LineSpace * 2,
            ystem - SheetMusic.NoteHeight * 2,
            xstart + SheetMusic.LineSpace,
            ystem - SheetMusic.NoteHeight * 2 - SheetMusic.LineSpace / 2);
        canvas.drawPath(bezierPath, paint);
      }
      ystem -= SheetMusic.NoteHeight;

      if (duration == NoteDuration.Sixteenth || duration == NoteDuration.ThirtySecond) {

        bezierPath = new Path();
        bezierPath.moveTo(xstart, ystem);
        bezierPath.cubicTo(
            xstart,
            ystem - SheetMusic.LineSpace,
            xstart + SheetMusic.LineSpace * 2,
            ystem - SheetMusic.NoteHeight * 2,
            xstart + SheetMusic.LineSpace,
            ystem - SheetMusic.NoteHeight * 2 - SheetMusic.LineSpace / 2);
        canvas.drawPath(bezierPath, paint);
      }

      ystem -= SheetMusic.NoteHeight;
      if (duration == NoteDuration.ThirtySecond) {
        bezierPath = new Path();
        bezierPath.moveTo(xstart, ystem);
        bezierPath.cubicTo(
            xstart,
            ystem - SheetMusic.LineSpace,
            xstart + SheetMusic.LineSpace * 2,
            ystem - SheetMusic.NoteHeight * 2,
            xstart + SheetMusic.LineSpace,
            ystem - SheetMusic.NoteHeight * 2 - SheetMusic.LineSpace / 2);
        canvas.drawPath(bezierPath, paint);
      }
    }
    paint.setStrokeWidth(1);
  }