/*************************************************
*    The PMW Music Typesetter - 3rd incarnation  *
*************************************************/

/* Copyright (c) Philip Hazel, 1991 - 2019 */

/* Written by Philip Hazel, starting November 1991 */
/* This file last modified: November 2020 */


/* This file contains the code for generating an image of one individual note
or rest. */


#include "pmwhdr.h"
#include "pagehdr.h"
#include "poshdr.h"
#include "outhdr.h"


/* Tables used only in this module */

static uschar common[] = {
  49, 50, 52, 54, 56, 58,       /* stems down */
  49, 50, 51, 53, 55, 57};      /* stems up */

static uschar *reststrings[] = {
  US"*", US"+", US",", US"-", US".", US"z.w{{y.",
  US"zzx.w{{y.w{{y.", US"zzzx.w{{y.w{{y.w{{y." };

static uschar *multireststrings[] = {  /* Start for 2, last is for 8 */
  US"*", US"*z+", US"*{{w*", US"*{{w*xz+", US"*{{w*xz*",
  US"*{{w*xz*z+", US"*{{w*xz*{{w*" };

static uschar *tailstrings[] = {
  US"",  US"",       US"",            US"",
  US"H", US"<xv<v|", US"<xv<xv<v|v|", US"<xv<xv<xv<v|v|v|",
  US"",  US"",       US"",            US"",
  US"E", US";v|;xv", US";v|;v|;xvxv", US";v|;v|;v|;xvxvxv" };

static uschar headchars[] = {
  '1', '2', 'M', 'L', 'L', 'L', 'L', 'L',    /* normal */
  'n', 'n', 'n', 'n', 'n', 'n', 'n', 'n',    /* cross */
  'm', 'm', 'm', 'l', 'l', 'l', 'l', 'l',    /* harmonic */
   0,   0,   0,   0,   0,   0,   0,   0,     /* none */
  '1', '2', 'M', 'L', 'L', 'L', 'L', 'L',    /* only = normal */
  178, 178, 178, 178, 178, 178, 178, 178     /* direct */
};

/* These next tables are accent-specific adjustments, for accents that go
outsice the stave, in the order > v tp down up. */

static uschar *accabovestrings[] = { US"U", US"Y", US"W", US"\302\234", US"e",
  US"g" };
static uschar *accbelowstrings[] = { US"U", US"Z", US"X", US"\302\234", US"f",
  US"h" };

static int accaboveadjusts[] = { -6000, -1000, -2000, -1000, -1000, -1000 };
static int accbelowadjusts[] = { -2000,  3000,     0,  2000,  1000,  1000 };

/* Further per-accidental adjustments for accents */

                                 /* -   ##     $      $$     %      # */
static int accaccaboveadjusts[] = { 0, 0000, -3000, -3000, -3000, -3000 };
static int accaccbelowadjusts[] = { 0, 0000,  0000,  0000,  3000,  3000 };

/* Dot position adjustments for rests */

static int restdotadjusts[] = { -20, 0, 0, -25, -20, -10, -10, 0 };

/* Table of dynamic numbers in order of printing outside dynamics */

static uschar dyn_list[] = { dyn_gt, dyn_wedge, dyn_tp, dyn_vline,
  dyn_down, dyn_up };

/* Table for x adjustments for brackets for outside dynamics */

static int outdynxbadjusts[] = { 2000,  0,  2000, 0,  2000,  2000 };
static int outdynybadjusts[] = { -4000, 0, -1500, 0, -1000, -1000 };


/* These tables are for the straightforward ornaments. Those with blank strings
are not straightforward, and have individual code. Note that characters greater
than 127 must be represented as UTF-8. */

static const char *ornament_strings[] = {
/* ferm  tr  trsh trfl trnat trem1 trem2 trem3 */
    "",  "",  "",  "",  "",   "",   "",   "",
/* mord  dmord  imord dimord turn iturn arp arpu arpd spread */
   "O",   "P",   "Q",  "R",   "S", "i", "",   "", "",   "",
/* dsharp      dsharprb                       dsharpsb */
   "&",        "~v\xc2\x8dv&~v\xc2\x8e",      "~v\xc2\x8bv&~v\xc2\x8c",
/* flat        flatrb                         flatsb */
   "\'",       "~\xc2\x8d|\'~\xc2\x8e",       "~\xc2\x8b|\'~\xc2\x8c",
/* dflat       dflatrb                        dflatsb */
   "\'\'",     "~\xc2\x8d|\'\'~\xc2\x8e",     "~\xc2\x8b|\'\'~\xc2\x8c",
/* nat         natrb                          natsb */
   "(",        "\xc2\x8d(\xc2\x8e",           "\xc2\x8b(\xc2\x8c",
/* sharp       sharprb                        sharpsb */
   "%",        "\xc2\x8d%\xc2\x8e",           "\xc2\x8b%\xc2\x8c",
/* hflat       hflatrb                        hflatsb   (style 0) */
   "\xc2\xbf", "~\xc2\x8d|\xc2\xbf~\xc2\x8e", "~\xc2\x8b|\xc2\xbf~\xc2\x8c",
/* hsharp      hsharprb                       hsharpsb    (style 0) */
   "\xc2\xbd", "\xc2\x8d\xc2\xbd\xc2\x8e",    "\xc2\x8b\xc2\xbd\xc2\x8c",
/* hflat       hflatrb                        hflatsb   (style 1) */
   "\xc3\x80", "~\xc2\x8d|\xc3\x80~\xc2\x8e", "~\xc2\x8b|\xc3\x80~\xc2\x8c",
/* hsharp      hsharprb                       hsharpsb    (style 1) */
   "\xc2\xbe", "\xc2\x8d\xc2\xbe\xc2\x8e",    "\xc2\x8b\xc2\xbe\xc2\x8c" };

static int ornament_xadjusts[] = {
  0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0,
  1, -2, -2,  /* dsharps */
  2, -1, -1,  /* flats */
  0, -3, -3,  /* dflats */
  2, -1, -1,  /* naturals */
  1, -1, -1,  /* sharps */
  2, -1, -1,  /* hflats (0) */
  1, -1, -1,  /* hsharps (0) */
  2, -1, -1,  /* hflats (1) */
  1, -1, -1,  /* hsharps (1) */
};

/* Amount by which to adjust the brackets when bracketing */

static int ornament_yaadjusts[] = {
  0,
  -1000,     /* Trill */
  -4000,
  -4000,
  -4000,
  0, 0, 0,
  0, 0, -2000, -2000, -1000, -1000, 0, 0, 0, 0,
  1000, 2000, 2000,  /* dsharps */
  1000, 1000, 1000,  /* flats */
  1000, 1000, 1000,  /* dflats */
  3000, 3000, 3000,  /* naturals */
  3000, 3000, 3000,  /* sharps */
  1000, 1000, 1000,  /* hflats (0) */
  3000, 3000, 3000,  /* hsharps (0) */
  1000, 1000, 1000,  /* hflats (1) */
  3000, 3000, 3000   /* hsharps (1) */
};

static int ornament_ybadjusts[] = {
  0,
  -1000,     /* Trill */
  2000,
  2000,
  2000,
  0, 0, 0,
  0, 0, 2000, 2000, 1000, 1000, 0, 0, 0, 0,
  0,     -3000, -3000,  /* dsharps */
  -3000, -4000, -4000,  /* flats */
  -3000, -4000, -4000,  /* dflats */
  -2000, -2000, -2000,  /* naturals */
  -2000, -2000, -2000,  /* sharps */
  -3000, -4000, -4000,  /* hflats (0) */
  -2000, -2000, -2000,  /* hsharps(0) */
  -3000, -4000, -4000,  /* hflats (1) */
  -2000, -2000, -2000   /* hsharps(1) */
};

/* These tables need only go up to or_iturn, as accidentals are handled
specially and already have a bracketting facility, and arpeggios and spread
chords can't be bracketed. */

static int ornament_xbrackadjustsL[] = {
  4000,    /* Fermata */
  3000,    /* Trill */
  3000,    /* Trill with sharp */
  3000,    /* Trill with flat */
  3000,    /* Trill with natural */
  0, 0, 0, /* Tremolos - never bracketed */
  2500,    /* Mordent */
  2500,    /* Double mordent */
  2500,    /* Inverted mordent */
  2500,    /* Double inverted mordent */
  2500,    /* Turn */
  2500     /* Inverted turn */
};

static int ornament_xbrackadjustsR[] = {
  4000,    /* Fermata */
  3000,    /* Trill */
  3000,    /* Trill with sharp */
  3000,    /* Trill with flat */
  3000,    /* Trill with natural */
  0, 0, 0, /* Tremolos - never bracketed */
  2600,    /* Mordent */
  5500,    /* Double mordent */
  2600,    /* Inverted mordent */
  5500,    /* Double inverted mordent */
  3500,    /* Turn */
  3500     /* Inverted turn */
};




/*************************************************
*   Print a possibly bracketed accent/ornament   *
*************************************************/

/* The bracket characters have width, but accent and ornament characters do
not.

Arguments:
  str       the string for the accent/ornament
  fontsize  the font size
  x         x-position for accent/ornament
  y         y-position for accent/ornament
  flags     bracket flags
  yadjust   general y adjustment if bracketed
  byadjust  specific y adjustment for brackets
  bxadjustL additional x left adjustment for brackets
  bxadjustR additional x right adjustment for brackets

Returns:    nothing
*/

static void
show_brack_acc(uschar *str, int fontsize, int x, int y, int flags, int yadjust,
  int byadjust, int bxadjustL, int bxadjustR)
{
int yb;

if ((flags & (DO_RBRA|DO_RKET|DO_SBRA|DO_SKET)) != 0) y += yadjust;
yb = y + byadjust;

if ((flags & DO_RBRA) != 0)
  ps_wtext(US"\302\215", font_mu, fontsize,
  x - (35*main_stavemagn)/100 - bxadjustL, yb, 0);
else if ((flags & DO_SBRA) != 0)
  ps_wtext(US"\302\213", font_mu, fontsize,
  x - (35*main_stavemagn)/100 - bxadjustL, yb, 0);

ps_musstring(str, fontsize, x, y);

if ((flags & (DO_RKET|DO_SKET)) != 0)
  {
  int swidth = font_stringwidth(str, font_mf, fontsize);
  if (swidth == 0) swidth = (58*fontsize)/100;
  ps_wtext(((flags & DO_RKET) != 0)? US"\302\216" : US"\302\214", font_mu,
    fontsize, x + mac_muldiv(swidth, main_stavemagn, 1000) + bxadjustR, yb, 0);
  }
}




/*************************************************
*         Actually print one note                *
*************************************************/

/* The data about the note is in the n_* global variables. This function just
prints the note head and stems. Dots, accents, etc are done elsewhere.

Argument:   the x coordinate for the note
Returns:    TRUE if one or more ledger lines were used
*/

static BOOL
show_note(int x)
{
uschar buff[100];
uschar *p;
BOOL positioned = FALSE;
BOOL ledgered = FALSE;
BOOL inverted = (n_flags & nf_invert) != 0;
int noteheadstyle;
int top = P_6L;
int bot = P_0L;
int fontsize = (n_fontsize*main_stavemagn)/1000;
int y = out_ystave - (n_pitch - 130)*main_stavemagn - n_pcorrection;
int yy;

DEBUG(("show_note() start\n"));

/* Set the notehead style */

noteheadstyle = ((n_flags & nf_nhharmonic) != 0)? nh_harmonic :
                ((n_flags & nf_nhcross) != 0)? nh_cross :
                bar_cont->noteheadstyle;

/* Set up for coupled notes */

if ((n_flags & nf_coupleU) != 0)
  {
  top += out_upgap;
  bot += out_upgap;
  }
else if ((n_flags & nf_coupleD) != 0)
  {
  top -= out_downgap;
  bot -= out_downgap;
  }

/* First deal with ledger lines if required. We repeat the code for above &
below, as there seems no tidy way of combining it owing to the requirement for
<= or >= comparisons. We can optimize into a single music-font string if the
size is standard. The existence of breves makes this messy! */

if (n_pitch <= bot && out_stavelines >= 5 && noteheadstyle != nh_none)
  {
  int breve_right = 0;
  int xx = x;

  if (n_notetype == breve)
    {
    xx -= ((((curmovt->breveledgerextra - 2300)*main_stavemagn)/1000) *
      n_fontsize)/10000;
    breve_right = mac_muldiv(2*curmovt->breveledgerextra, fontsize, 10000);
    }

  ledgered = positioned = TRUE;
  yy = out_ystave - (bot - 130)*main_stavemagn - n_pcorrection;
  if (n_fontsize == 10000 && !inverted)
    {
    p = buff;
    while (n_pitch <= bot)
      {
      *p++ = curmovt->ledger;
      *p++ = 'w';
      bot -= 4;
      }
    *(--p) = 0;  /* removes redundant last move */
    ps_musstring(buff, fontsize, xx, yy);
    if (n_notetype == breve)
      ps_musstring(buff, fontsize, xx + breve_right, yy);
    }
  else  /* Have to position each line separately */
    {
    int yyy = yy;
    p = buff;
    *p++ = curmovt->ledger;
    if (inverted)
      {
      p += sprintf(CS p, n_upflag? "}" : "yy{");
      *p++ = curmovt->ledger;
      }
    *p = 0;
    while (yy <= y)
      {
      ps_musstring((yy == y && !n_upflag && inverted)? buff+1 : buff,
        fontsize, xx, yy);
      yy += 4*main_stavemagn;
      }
    if (n_notetype == breve)
      {
      yy = yyy;
      xx += breve_right;
      while (yy <= y)
        {
        ps_musstring((yy == y && !n_upflag && inverted)? buff+1 : buff,
          fontsize, xx, yy);
        yy += 4*main_stavemagn;
        }
      }
    }
  }

else if (n_pitch >= top && out_stavelines >= 5 && noteheadstyle != nh_none)
  {
  int breve_right = 0;
  int xx = x;

  if (n_notetype == breve)
    {
    xx -= ((((curmovt->breveledgerextra - 2300)*main_stavemagn)/1000) *
      n_fontsize)/10000;
    breve_right = mac_muldiv(2*curmovt->breveledgerextra, fontsize, 10000);
    }

  ledgered = positioned = TRUE;
  yy = out_ystave - (top - 130)*main_stavemagn - n_pcorrection;
  if (n_fontsize == 10000 && !inverted)
    {
    p = buff;
    while (n_pitch >= top)
      {
      *p++ = curmovt->ledger;
      *p++ = 'x';
      top += 4;
      }
    *(--p) = 0;  /* removes redundant last move */
    ps_musstring(buff, fontsize, xx, yy);
    if (n_notetype == breve)
      ps_musstring(buff, fontsize, xx + breve_right, yy);
    }
  else
    {
    int yyy = yy;
    p = buff;
    *p++ = curmovt->ledger;
    if (inverted)
      {
      p += sprintf(CS p, n_upflag? "}" : "yy{");
      *p++ = curmovt->ledger;
      }
    *p = 0;
    while (yy >= y)
      {
      ps_musstring((yy == y && n_upflag && inverted)? buff+1 : buff,
        fontsize, xx, yy);
      yy -= 4*main_stavemagn;
      }

    if (n_notetype == breve)
      {
      yy = yyy;
      xx += breve_right;
      while (yy >= y)
        {
        ps_musstring((yy == y && n_upflag && inverted)? buff+1 : buff,
          fontsize, xx, yy);
        yy -= 4*main_stavemagn;
        }
      }
    }
  }

/* Optimize the common case where there is a complete character available in
the music font. */

p = buff;
if (n_notetype < dsquaver && n_stemlength == 0 && noteheadstyle == nh_normal &&
    (n_flags & (nf_invert|nf_stem|nf_smallhead)) == nf_stem)
  {
  if ((n_flags & nf_appogg) != 0) *p++ = n_upflag? 129 : 130;
  *p++ = common[n_notetype + n_upflag*6];
  *p = 0;
  ps_musstring(buff, fontsize, x, y);
  return ledgered;
  }

/* Deal with rarer cases, first dealing with stems & tails. We impose a minimum
stemlength at this point. */

if (n_stemlength < -8000) n_stemlength = -8000;

if ((n_flags & nf_stem) != 0)
  {
  int direction = n_upflag? -1 : +1;
  int font10 = fontsize;   /* 10pt at font scale */
  int font2  = font10/5;   /* 2pt at font scale */
  int font1  = font2/2;    /* 1pt at font scale */

  if ((n_flags & nf_appogg) != 0) *p++ = n_upflag? 129 : 130;

  yy = y + (direction*n_stemlength*main_stavemagn)/1000;
  p += sprintf(CS p, "%s", tailstrings[n_notetype + n_upflag*8]);
  positioned = TRUE;

  /* Notes with stems up */

  if (n_upflag)
    {
    if (yy <= y)    /* stem is lengthened */
      {
      int stemch = (noteheadstyle == nh_cross)? 'o' : 'J';
      int z = yy;
      while (z <= y)
        {
        p += sprintf(CS p, "%cww|", stemch);
        z += font10;
        }
      p -= 3;
      *p = 0;
      ps_musstring(buff, fontsize, x, yy);
      p = buff;
      if (z < y + font10) *p++ = stemch;
      if (noteheadstyle == nh_harmonic) *p++ = 'q';
      }

    else            /* stem is shortened */
      {
      int z = yy - font10 - font2;
      p += sprintf(CS p, "xxx");
      while (z <= y)
        {
        p += sprintf(CS p, "q|");
        z += font2;
        }
      *(--p) = 0;
      ps_musstring(buff, fontsize, x, yy);
      p = buff;
      if (z > y) *p++ = 'q';
      }
    }

  /* Notes with stems down */

  else
    {
    if (yy >= y)    /* stem is lengthened */
      {
      int stemch = (noteheadstyle == nh_cross)? 'p' : 'K';
      int z = yy;
      while (z >= y)
        {
        p += sprintf(CS p, "%cxx~", stemch);
        z -= font10;
        }
      p -= 3;
      *p = 0;
      ps_musstring(buff, fontsize, x, yy);
      p = buff;
      if (z > y - font10) *p++ = stemch;
      if (noteheadstyle == nh_harmonic) *p++ = 'r';
      }

    else            /* stem is shortened */
      {
      int z = yy + font10 + font2;
      p += sprintf(CS p, "www");
      while (z >= y)
        {
        p += sprintf(CS p, "r~v");
        z -= font1;
        }
      *(--p) = 0;
      ps_musstring(buff, fontsize, x, yy);
      p = buff;
      if (z < y) *p++ = 'r';
      }
    }
  }

/* Now add the note head */

if (noteheadstyle != nh_none)
  {
  if (inverted)
    {
    if (n_upflag)
      {
      if (n_notetype == breve)
        p += sprintf(CS p, "}}}}{{{{z");
      else *p++ = 125;
      }
    else
      {
      if (n_notetype == breve)
        p += sprintf(CS p, "{yyyyyyyyyyyy}");
      else
        {
        *p++ = 123;
        *p++ = 121;
        *p++ = 121;
        }
      }
    }

  /* The special case of a small note head is dealt with below; just omit
  the note head at this point. */

  if ((n_flags & nf_smallhead) == 0)
    {
    *p++ = headchars[n_notetype + 8*noteheadstyle];

    /* When printing right-to-left, we put some redundant spacing *after*
    inverted noteheads. This is just a fudge to fool the x-coordinate adjusting
    code into doing (approximately) the right thing. */

    if (main_righttoleft && inverted)
      p += sprintf(CS p, n_upflag? "{{{" : "zzzz");
    }
  }

/* Output the music font string. */

*p = 0;
ps_musstring(buff, fontsize, x, y);

/* In the special case of a small note head, the note head was skipped above.
The printing position should be in the correct place for a full size note head
if a stem or ledger lines were output above. Arrange to output the notehead at
the cue size, with a relative position adjusted to allow for the head size. */

if ((n_flags & nf_smallhead) != 0)
  {
  int cue_fontsize = (curmovt->fontsizes)->fontsize_cue;
  int sm_fontsize = (cue_fontsize * main_stavemagn)/1000;

  p = buff;
  *p++ = headchars[n_notetype + 8*noteheadstyle];
  *p = 0;

  if (positioned && (n_flags & nf_stem) != 0)
    {
    x = 0;
    if ((n_upflag && (n_flags & nf_invert) == 0) ||
        (!n_upflag && (n_flags & nf_invert) != 0))
      x += 6000 - 3 * (cue_fontsize / 5);
    y = 2000 - cue_fontsize / 5;
    ps_relmusstring(buff, sm_fontsize, x, y);
    }

  else
    {
    x += (((n_notetype == breve)? 19:11)*main_stavemagn)/10;
    y -= (5*main_stavemagn)/10;
    ps_musstring(buff, sm_fontsize, x, y);
    }
  }

/* Return whether ledger lines or not */

DEBUG(("show_note() end\n"));
return ledgered;
}


/*************************************************
*         Actually print one rest                *
*************************************************/

/* This function just prints the actual rest (possibly with ledger lines). Dots
are handled elsewhere.

Arguments:
  x           x coordinate for the rest
  notetype    length of rest

Returns:      nothing
*/

static void
show_rest(int x, int notetype)
{
int fontsize = (n_fontsize*main_stavemagn)/1000;
int yoffset = n_restlevel;
int y;

/* Rests longer than a crotchet have to have ledger lines when they are printed
off the stave. Also move a semibreve rest down on a 1-line stave and up on a
3-line stave. We must also adjust the position of breve and semibreve rests for
cue sizes. */

if (notetype <= minim)
  {
  int loffset = 0;
  yoffset += 8000;

  switch (notetype)
    {
    case -1:     /* long rest */
    yoffset -= 2000;
    break;

    case breve:
    yoffset += n_pcorrection;
    /* Fall through */

    case minim:
    if (yoffset > 16000 || yoffset < 0) loffset = -2000;
    break;

    case semibreve:
    if (out_stavelines == 1) yoffset -= 4000;
      else if (out_stavelines == 3) yoffset += 4000;
    yoffset += 2*n_pcorrection;
    if (yoffset > 12000 || yoffset < -4000) loffset = 2000;
    break;
    }

  if (loffset)
    ps_musstring(US"=", fontsize, x - (10*main_stavemagn)/10, out_ystave -
      ((yoffset + loffset)*main_stavemagn)/1000);
  }

else yoffset += 4000 + n_pcorrection;

y = out_ystave - (yoffset*main_stavemagn)/1000;

/* Output a single rest, taking care of the special cases that are used for
conventional repeat signs. */

if (notetype >= 0)
  {
  uschar *s;
  if ((n_flags & nf_restrep) == 0) s = reststrings[n_notetype];
  else if (n_notetype == crotchet) s = US"\217";
  else
    {
    s = US"\220\217";
    y += 4*main_stavemagn;
    }
  ps_musstring(s, fontsize, x, y);
  }

/* Output a multirest sign */

else if (curmovt->codemultirests && out_manyrest < 9)
  {
  ps_musstring(multireststrings[out_manyrest - 2], fontsize, x, y - 2000);
  }

/* Output a |----| long rest sign. If the bar is unusually long or unusually
short, draw the long rest symbol; note that ps_line() works in conventional
coordinates relative to the base line of the stave. The variable n_longrestmid
contains the mid-point of the long rest. */

else
  {
  int wide;
  int rs = out_barlinex - n_longrestmid;

  if ((wide = rs > 40*main_stavemagn) || x - out_barx < 6000)
    {
    posstr *p;
    int xl, xr;
    int vthick = (3*main_stavemagn)/10;
    int hthick = 3*main_stavemagn;
    int adjust = 0;
    int min = wide? 15000 : 12000;

    /* Calculate an adjustment for anything at the end of the bar, e.g. a clef
    change. */

    for (p = out_posptr + 1; p->moff <= 0; p++); /* Skip preceding */
    for (; p < out_poslast; p++)
      adjust += p[1].xoff - p->xoff;

    /* Place the right hand end with respect to the the barline, nearer for a
    narrow bar, then place the left hand end symmetrically. */

    if (adjust < min) adjust = min + adjust/3;
      else adjust += 5000;

    xr = out_barlinex - mac_muldiv(adjust, main_stavemagn, 1000);
    xl = 2*n_longrestmid - xr;

    ps_line(xl, 8*main_stavemagn, xr, 8*main_stavemagn, hthick, 0);
    ps_line(xl, 4*main_stavemagn, xl, 12*main_stavemagn, vthick, 0);
    ps_line(xr, 4*main_stavemagn, xr, 12*main_stavemagn, vthick, 0);
    }

  /* Use the long rest character */

  else ps_muschar(x, y, mc_longrest, fontsize);
  }
}


/*************************************************
*    Generate one note/rest + dots & accents     *
*************************************************/

/* The relevant data about the note/rest is all in the n_* global variables.

Arguments:  none
Returns:    nothing
*/

void
out_shownote(void)
{
int fontsize = (n_fontsize*main_stavemagn)/1000;
int xn = n_x + n_cueadjust;
int yyabove, yybelow;
int acc_level, acc_upflag;
BOOL ledgered = FALSE;

DEBUG(("out_shownote() start\n"));

/* If the note is invisible, we skip printing and just show accents, etc.
below. This test is for notes on and this note not hidden. */

if ((bar_cont->flags & cf_notes) != 0 && (n_flags & nf_hidden) == 0)
  {
  int x_acc = 0;
  int x_dot = 0;

  /* If printing a breve, move left to align with semibreve position */

  if (n_pitch != 0 && n_notetype == breve) xn -= (23*main_stavemagn)/10;

  /* First, any accidental is set, prior to the given position */

  if (n_acc)
    {
    int offset = n_acc;
    if ((n_flags & nf_accrbra) != 0) offset += 6;
      else if ((n_flags & nf_accsbra) != 0) offset += 12;
    if ((n_flags & nf_halfacc) != 0)
      {
      offset += ((n_acc == ac_sharp)? (curmovt->hsharpstyle == 0) :
        (curmovt->hflatstyle == 0))? 18:36;
      }
    x_acc = xn - mac_muldiv(n_accleft, n_fontsize, 10000);
    ps_muschar(x_acc,
      out_ystave - (n_pitch - 130)*main_stavemagn - n_pcorrection,
        out_acctable[offset], fontsize);
     }

  /* Now we can output the note or rest. */

  if (n_pitch == 0)
    {
    int notetype;
    if (out_manyrest == 1) notetype = n_notetype; else
      {
      notetype = -1;
      n_flags &= ~(nf_dot+nf_plus);   /* Kill dots for many bar rest */
      }
    show_rest(xn, notetype);
    }
  else ledgered = show_note(xn);

  /* Deal with horizontal dots/plus - fudge for quavers and breves */

  if ((n_flags & (nf_dot+nf_plus)) != 0)
    {
    BOOL dotplus = (n_flags & nf_plus) != 0;
    int dotpos = 84;
    int dotlevel;

    if (n_pitch == 0)
      {
      dotlevel = mac_muldiv(L_3S + n_restlevel, main_stavemagn, 1000);
      dotpos += restdotadjusts[n_notetype];
      }

    else
      {
      int dotpitch = n_pitch | 2;  /* force into space above */

      if ((n_flags & nf_lowdot) != 0 && (n_pitch & 2) == 0) dotpitch -= 4;
      if ((n_flags & nf_highdot) != 0 && (n_pitch & 2) != 0) dotpitch += 4;

      dotlevel = (dotpitch - 130)*main_stavemagn;
      if (n_notetype == breve) dotpos += 50;
      }

    if ((n_flags & nf_dotright) != 0) dotpos += 60;
      else if (n_upflag && n_notetype >= quaver && n_pitch != 0) dotpos += 16;

    dotpos = (dotpos*main_stavemagn)/10 + n_dotxadjust;

    /* For cue notes there are two choices: either to scale the position
    according to the cue size, or to align the dots with full-sized notes that
    may be above or below (alignment by centre of dot). */

    if ((n_flags & nf_cuesize) != 0)
      {
      if ((n_flags & nf_cuedotalign) != 0)
        dotpos += mac_muldiv(640 - mac_muldiv(640, n_fontsize, 10000),
          main_stavemagn, 1000) - n_cueadjust;
      else
        dotpos = mac_muldiv(dotpos, n_fontsize, 10000);
      }

    /* Output the dot(s). The '+' character is 135 in the music font; we have
    to specify this as a UTF-8 string. */

    x_dot = xn + dotpos;
    ps_musstring(dotplus? US"\302\207" : US"?", fontsize, x_dot,
      out_ystave - dotlevel - n_pcorrection);

    if ((n_flags & nf_dot2) != 0)
      {
      x_dot += (35*main_stavemagn)/10;
      ps_musstring(US"?", fontsize, x_dot, out_ystave - dotlevel - n_pcorrection);
      }
    if (dotplus) x_dot += 4*main_stavemagn;  /* Extra for ) */
    }

  /* Deal with bracketed notehead */

  if ((n_flags & nf_headbra) != 0)
    {
    int adjustbra = 0;
    int adjustket = 0;
    int bfontsize = (6*fontsize)/10;
    int yb = out_ystave - (n_pitch - 130)*main_stavemagn -
      (9*main_stavemagn/10);
    uschar *bra = main_righttoleft? US"\302\216" : US"\302\215";
    uschar *ket = main_righttoleft? US"\302\215" : US"\302\216";

    if (x_acc == 0) x_acc = xn + main_stavemagn;
    if (x_dot == 0) x_dot = xn + 5*main_stavemagn;

    if (n_notetype == breve) adjustket += 5*main_stavemagn;

    if ((n_flags & nf_smallhead) != 0)
      {
      if ((n_flags & nf_stem) != 0)
        {
        if (n_upflag) adjustbra += 2*main_stavemagn;
          else adjustket -= 2*main_stavemagn;
        }
      else
        {
        adjustbra += 2*main_stavemagn;
        adjustket -= 2*main_stavemagn;
        }

      if (ledgered)
        {
        adjustbra -= (15*main_stavemagn)/10;
        adjustket += main_stavemagn;
        }
      }

    ps_musstring(bra, bfontsize,
      x_acc - (35*main_stavemagn)/10 + adjustbra, yb);

    ps_musstring(ket, bfontsize,
      x_dot + (40*main_stavemagn)/10 + adjustket, yb);
    }
  }

/* If there are no dynamics and no ornaments, there's nothing more to do */

if ((n_acflags & af_dynamics) == 0 && n_ornament == NULL) return;

/* Now set up a level and up flag for expression marks - normally these are
from the standard note values, but they are different if the accents are
flagged for printing on the same side of the note as the stem. For chords it is
arranged that the accents come with the appropriate note head. */

acc_level = (n_pitch - 130)*main_stavemagn;

if ((n_acflags & af_opposite) == 0)
  {
  acc_upflag = n_upflag;
  }
else
  {
  acc_upflag = !n_upflag;
  if ((n_flags & nf_stem) != 0)
    acc_level +=
      n_upfactor * mac_muldiv((12000+n_stemlength), main_stavemagn, 1000);
  }

/* Staccato, staccatissimo, ring, & bar go inside the staff. Except for
staccato and staccatissimo, they are allowed together - the staccat{issim}o is
nearest to the note. We don't need to compensate for ties as the ties
themselves are moved in this case. */

if ((n_acflags & af_dyninside) != 0)
  {
  int adjust = 4*main_stavemagn;
  int p = acc_level;

  if (acc_upflag)
    {
    adjust = -adjust;
    p -= 8*main_stavemagn;

    /* Accent at notehead; ensure not on line; not for 0 or 1-line staves or
    for staccatissimo. */

    if (out_stavelines >= 2 && (n_acflags & af_staccatiss) == 0)
      {
      if (acc_upflag == n_upflag)
        {
        if (((n_pitch & 2) == 0) && n_pitch != P_1L &&
          (!ledgered || n_pitch >
            (P_5L - ((n_flags & nf_coupleD)? out_downgap : 0))))
              p -= 2*main_stavemagn;
        }

      /* Accent at stem end; ensure not on line; rather assumes stemlength
      adjustments will be in whole points... */

      else
        {
        int pp = p/main_stavemagn;
        if (pp >= (-6) && pp <= 10 && (pp & 2) != 0)
          p -= 2*main_stavemagn;
        }
      }
    }
  else  /* !acc_upflag */
    {
    /* Accent at notehead; ensure not on line; not for 0 or 1-line staves or
    for staccatissimo. */

    if (out_stavelines >= 2 && (n_acflags & af_staccatiss) == 0)
      {
      if (acc_upflag == n_upflag)
        {
        if (((n_pitch & 2) == 0) && n_pitch != P_5L &&
          (!ledgered || n_pitch <
            (P_1L + ((n_flags & nf_coupleU)? out_upgap : 0))))
              p += 2*main_stavemagn;
        }

      /* Accent at stem end; ensure not on line (rather assumes stemlength
      adjustments will be in whole points... */

      else
        {
        int pp = p/main_stavemagn;
        if (pp >= (-6) && pp <= 10 && (pp & 2) != 0)
          p += 2*main_stavemagn;
        }
      }
    }

  if (out_beaming && (acc_upflag != n_upflag)) p += n_upfactor * 1000;

  if ((n_acflags & af_staccato) != 0)
    {
    show_brack_acc(US">", fontsize, xn + out_dynmovex[dyn_staccato],
      out_ystave - p - out_dynmovey[dyn_staccato], out_dynmovef[dyn_staccato],
      acc_upflag? 4*main_stavemagn:(-4)*main_stavemagn,
      -4*main_stavemagn, 0, 0);
    p += adjust;
    out_dynmovex[dyn_staccato] = out_dynmovey[dyn_staccato] =
      out_dynmovef[dyn_staccato] = 0;
    }

  /* Leave p the same value as for staccato, with a small adjustment, but we
  need some further adjustment to cope with the position of the characters in
  the font. */

  else if ((n_acflags & af_staccatiss) != 0)
    {
    int pp = (acc_upflag? 25:55)*main_stavemagn/10;
    if (acc_upflag != n_upflag) pp += (acc_upflag? 1:-1)*main_stavemagn;
    show_brack_acc(acc_upflag? US"\303\203":US"\303\202", fontsize,
      xn + out_dynmovex[dyn_staccatiss],
      out_ystave - p - pp - out_dynmovey[dyn_staccatiss],
      out_dynmovef[dyn_staccatiss],
      acc_upflag? 3*main_stavemagn:(-3)*main_stavemagn, 0, 0, 0);
    p += adjust + (acc_upflag? -1:1)*main_stavemagn;
    out_dynmovex[dyn_staccatiss] = out_dynmovey[dyn_staccatiss] =
      out_dynmovef[dyn_staccatiss] = 0;
    }

  /* The ring character prints 4 points lower than the other two, and a bit
  further away from the notehead when clear of stave or ledger lines. */

  if ((n_acflags & af_ring) != 0)
    {
    int yy = 0;
    if ((n_flags & nf_couple) == 0)
      {
      if (acc_upflag)
        {
        if (n_upflag && n_pitch <= P_1S) yy = main_stavemagn;
        }
      else
        {
        if (!n_upflag && n_pitch >= P_4S) yy = -main_stavemagn;
        }
      }

    show_brack_acc(US"\302\206", fontsize, xn + out_dynmovex[dyn_ring],
      out_ystave - p - 4*main_stavemagn + yy - out_dynmovey[dyn_ring],
      out_dynmovef[dyn_ring],
      acc_upflag? 4*main_stavemagn:(-4)*main_stavemagn,
      0, 0, 0);
    p += adjust + yy;
    out_dynmovex[dyn_ring] = out_dynmovey[dyn_ring] =
      out_dynmovef[dyn_ring] = 0;
    }

  if ((n_acflags & af_bar) != 0)
    {
    show_brack_acc(US"T", fontsize, xn + out_dynmovex[dyn_bar],
      out_ystave - p - out_dynmovey[dyn_bar], out_dynmovef[dyn_bar],
      acc_upflag? 4*main_stavemagn:-4*main_stavemagn, -4*main_stavemagn,
      2*main_stavemagn, 2*main_stavemagn);
    out_dynmovex[dyn_bar] = out_dynmovey[dyn_bar] =
      out_dynmovef[dyn_bar] = 0;
    }
  }

/* Set up y values for things that print above or below the stave; there is a
different set for the accents and the ornaments, but we compute the basic
values here for both of them. Set the stemlength to the value for the first
note of a chord, which will be the bit that sticks out. */

n_stemlength = n_orig_stemlength;
yybelow = misc_ybound(TRUE, n_nexttie, TRUE, FALSE);
yyabove = misc_ybound(FALSE, n_nexttie, TRUE, FALSE);

/* We can common up the code for the other accents and bowing marks into a
loop. This is dependent on the order of the flags in the word, and the bowing
marks must come last, because the above/below control is different. All these
items print above or below the stave. */

if ((n_acflags & af_dynoutside) != 0)
  {
  int i;
  int yextra = 0;
  int upflag = acc_upflag;

  /* Sanitizing compilers may complain about shifting top bits off words, so be
  pedantic here. Start by getting the first relevant bit to the top position.
  */

  usint f = (n_acflags & 0x1fffffff) << 3;

  /* The order is: > v V ' down up. We assume that only one of the first four
  will exist, possibly with one of the last two. */

  for (i = 0; i < 6; i++)
    {
    int xadjust = 0;
    int ayybelow = yybelow;
    int ayyabove = yyabove;

    if (i == 0) xadjust = main_stavemagn; else if (i == 4)
      {
      int newupflag = (bar_cont->flags & cf_bowingabove) == 0;
      if (newupflag != upflag) yextra = 0;
      upflag = newupflag;
      }

    /* Further adjustments when accents are not on the stem side and there are
    no "inside" accidentals. Effectively we cancel some of the space put in for
    accidental signs. We can't take this out of the loop, because the up/down
    bows may be different to other accents. */

    if (upflag == n_upflag && (n_acflags & af_dyninside) == 0)
      {
      ayybelow += accaccbelowadjusts[n_acc];
      ayyabove += accaccaboveadjusts[n_acc];
      }

    ayybelow = ((ayybelow <= out_stavebottom)? ayybelow :
      out_stavebottom) - 8000;
    ayyabove = ((ayyabove > out_stavetop)? ayyabove :
      out_stavetop) + 3000;

    /* Print the accent if its bit is set. */

    if ((f & 0x80000000) != 0)
      {
      int d = dyn_list[i]; /* standard accent number */
      int y;
      uschar *s;

      if (upflag)
        {
        s = accbelowstrings[i];
        y = ayybelow + accbelowadjusts[i] - yextra;
        }
      else
        {
        s = accabovestrings[i];
        y = ayyabove + accaboveadjusts[i] + yextra;
        }

      show_brack_acc(s, fontsize, n_x + xadjust + out_dynmovex[d],
        out_ystave - mac_muldiv(y, main_stavemagn, 1000) - out_dynmovey[d],
        out_dynmovef[d],
        0,
        mac_muldiv(outdynybadjusts[i], main_stavemagn, 1000),
        mac_muldiv(outdynxbadjusts[i], main_stavemagn, 1000),
        mac_muldiv(outdynxbadjusts[i], main_stavemagn, 1000));
      if (i < 4) yextra = 4000;
      out_dynmovex[d] = out_dynmovey[d] = out_dynmovef[d] = 0;
      }

    f = (f & 0x7fffffff) << 1;
    }
  }

/* Deal with ornaments. There are only *very* rarely more than one, so don't
bother about the recomputation that then happens. */

if (n_ornament != NULL)
  {
  yybelow = ((yybelow <= out_stavebottom)? yybelow : out_stavebottom) - 8000;
  yyabove = ((yyabove > out_stavetop)? yyabove : out_stavetop) + 3000;

  while (n_ornament != NULL)
    {
    uschar s[100];
    uschar *p = s;
    BOOL below = (n_acflags & af_opposite) != 0;
    int size = fontsize;
    int ornament = n_ornament->ornament;
    int x = n_ornament->x + n_x;
    int y = n_ornament->y;

    /* Above/below accidentals are special */

    if (ornament >= or_dsharp)
      {
      size = ((curmovt->fontsizes)->fontsize_vertacc * main_stavemagn)/1000;
      if (ornament >= or_accbelow)
        {
        below = TRUE;
        y += yybelow + 8000 - (8*size)/10;
        ornament -= or_accbelow - or_dsharp;
        }
      else
        {
        below = FALSE;
        y += yyabove;
        }
      }

    /* Adjust y for other ornaments */

    else y += below? yybelow : yyabove;

    /* Particular code for each ornament */

    switch (ornament)
      {
      case or_trsh:
      *p++ = '%';
      goto TR;

      case or_trfl:
      *p++ = '\'';
      goto TR;

      case or_trnat:
      *p++ = '(';
      /* Fall through */

      case or_tr:
      TR:
        {
        int tsize = (curmovt->fontsizes)->fontsize_trill;
        int asize = (6*tsize)/10;
        int *matrix = (curmovt->fontsizes)->fontmatrix_trill;
        if (matrix != NULL) memcpy(font_transform, matrix, 4*sizeof(int));
        out_string(curmovt->trillstring, font_it, tsize, x,
          out_ystave - mac_muldiv(y, main_stavemagn, 1000), 0);

        /* For a bracketed trill, use the show_brack_acc() function with
        an empty string. */

        if (n_ornament->bflags != 0)
          show_brack_acc(US"", size, x,
            out_ystave - mac_muldiv(y, main_stavemagn, 1000),
            n_ornament->bflags,
            0,
            below? ornament_ybadjusts[ornament] :
                   ornament_yaadjusts[ornament],
            ornament_xbrackadjustsL[ornament],
            ornament_xbrackadjustsR[ornament]);

        font_reset();
        size = asize;
        if (below) y -= asize;
          else if (n_ornament->ornament == or_trfl) y += (8*tsize)/10;
            else y += tsize;
        x += 2*main_stavemagn;
        }
      break;

      case or_ferm:
      if (n_pitch == 0) x -= main_stavemagn;
      *p++ = below? '/' : ')';
      break;

      case or_arp:
      case or_arpu:
      case or_arpd:
        {
        int h = (n_maxpitch - n_minpitch + 2)/4;
        if ((n_minpitch & 2) != 0 && (n_maxpitch & 2) != 0) h++;

        if (ornament == or_arpd)
          {
          *p++ = 165;
          h--;
          }
        do *p++ = 145; while (--h >= 0);
        if (ornament == or_arpu) p[-1] = 164;

        y = n_minpitch - 130;
        if ((y & 2) == 0) y -= 2;
          else if ((n_maxpitch & 2) != 0) y--;
        y = y*1000 + n_ornament->y;

        if (n_maxaccleft) x -= n_maxaccleft;
          else if (n_invertleft) x -= (55*main_stavemagn)/10;
        }
      break;

      case or_spread:
        {
        int co;
        int y0 = n_minpitch - 128;
        int y1 = n_maxpitch - 128;

        if (0 <= y0 && y0 <= 16 && (y0 & 3) == 0) y0--;
        if (0 <= y1 && y1 <= 16 && (y1 & 3) == 0) y1++;

        co = (4000 * (y1 - y0))/14;
        if (co > 4000) co = 4000;

        y0 = mac_muldiv(y0 * 1000 + n_ornament->y, main_stavemagn, 1000);
        y1 = mac_muldiv(y1 * 1000 + n_ornament->y, main_stavemagn, 1000);

        x -= 5000;
        if (n_maxaccleft) x -= n_maxaccleft;
          else if (n_invertleft) x -= 4*main_stavemagn;

        out_slur(x, y0, x, y1, 0, co, 0, 1000);
        }
      break;

      /* Tremolos are handled with their own code. Vertical movement is
      permitted. */

      case or_trem3:
      *p++ = 146;
      /* Fall through */

      case or_trem2:
      *p++ = 146;
      /* Fall through */

      case or_trem1:
      *p++ = 146;

      y = n_pitch - 124;
      if (n_notetype >= minim) x += (n_upfactor*255*main_stavemagn)/100;

      if (n_upflag)
        {
        int yy = (n_ornament->ornament == or_trem3)? 4000 : 2000;
        y += (n_ornament->ornament == or_trem1)? 4 : 2;
        y = y*1000 + n_ornament->y;
        if (out_beaming && n_stemlength >= yy) y += (n_stemlength - yy)/2;
        if (main_righttoleft) x -= 5000;
        }
      else
        {
        int yy = 2000;
        switch (n_ornament->ornament)
          {
          case or_trem3: y -= 18; yy = 4000; break;
          case or_trem2: y -= 14; break;
          case or_trem1: y -= (y & 2)? 10 : 12; break;
          }
        y = y*1000 + n_ornament->y;
        if (out_beaming && n_stemlength >= yy) y -= (n_stemlength - yy)/2;
        if (main_righttoleft) x += 5000;
        }
      break;

      /* Handle those cases that have no complications, but just require
      setting a string and a position. This includes accidentals printed above
      and below, though we have a small fudge for half accidental styles. */

      default:
      if (ornament >= or_hflat && ornament <= or_hflatsb)
        ornament += curmovt->hflatstyle * 6;
      else if (ornament >= or_hsharp && ornament <= or_hsharpsb)
        ornament += curmovt->hsharpstyle * 6;
      p += sprintf(CS p, "%s", ornament_strings[ornament]);
      x += ornament_xadjusts[ornament] * main_stavemagn;
      y += below? ornament_ybadjusts[ornament] :
        ornament_yaadjusts[ornament];
      break;
      }

    /* Output the string which has been set up (if any). The accidentals
    treated as ornaments are those printed above notes, and they have their own
    arrangements for bracketing, so we do not call show_brack_acc for them.
    Also, bracketing is not available for tremolos, trills, arpeggios, or
    spread chords. */

    if (p > s)
      {
      int ybadjust = 0;
      *p = 0;
      switch (ornament)
        {
        case or_ferm:
        ybadjust = below? -2000 : 1000;
        /* Fall through */
        case or_mord:
        case or_dmord:
        case or_imord:
        case or_dimord:
        case or_turn:
        case or_iturn:
        show_brack_acc(s, size, x,
          out_ystave - mac_muldiv(y, main_stavemagn, 1000),
          n_ornament->bflags,
          0,
          ybadjust,
          ornament_xbrackadjustsL[ornament],
          ornament_xbrackadjustsR[ornament]);
        break;

        default:
        ps_musstring(s, size, x,
          out_ystave - mac_muldiv(y, main_stavemagn, 1000));
        break;
        }
      }

    /* Move on to next ornament, if any */

    n_ornament = (b_ornamentstr *)
      ((uschar *)n_ornament + length_table[b_ornament]);
    if (n_ornament->type == b_Jump)
      n_ornament = (b_ornamentstr *)
        ((uschar *)(((b_Jumpstr *)n_ornament)->next) + length_table[b_Jump]);

    if (n_ornament->type != b_ornament) break;
    }
  }

DEBUG(("out_shownote() end\n"));
}

/* End of shownote.c */
