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

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

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


/* 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 *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 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 = buff;
BOOL ledgered = FALSE;
BOOL inverted = (n_flags & nf_invert) != 0;
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 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 && bar_cont->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 = TRUE;
  yy = out_ystave - (bot - 130)*main_stavemagn - n_pcorrection;
  if (n_fontsize == 10000 && !inverted)
    {
    uschar *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 */
    {
    uschar *p = buff;
    int yyy = yy;
    *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 &&
         bar_cont->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 = TRUE;
  yy = out_ystave - (top - 130)*main_stavemagn - n_pcorrection;
  if (n_fontsize == 10000 && !inverted)
    {
    uschar *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
    {
    uschar *p = buff;
    int yyy = yy;
    *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. */

if (n_notetype < dsquaver && n_stemlength == 0 &&
  bar_cont->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]);

  /* Notes with stems up */

  if (n_upflag)
    {
    if (yy <= y)    /* stem is lengthened */
      {
      int stemch = (bar_cont->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 (bar_cont->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 = (bar_cont->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 (bar_cont->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 (bar_cont->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*(bar_cont->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,
but the printing position should be in the correct place for a full size note
head. Arrange to output one at the cue size, with a relative position adjusted
to allow for the head size. */

if ((n_flags & nf_smallhead) != 0)
  {
  p = buff;
  x = y = 0;
  fontsize = ((curmovt->fontsizes)->fontsize_cue * main_stavemagn)/1000;

  if ((n_upflag && (n_flags & nf_invert) == 0) ||
      (!n_upflag && (n_flags & nf_invert) != 0))
    x += 6000 - 3 * ((curmovt->fontsizes)->fontsize_cue / 5);

  y += 2000 - (curmovt->fontsizes)->fontsize_cue / 5;

  *p++ = headchars[n_notetype + 8*(bar_cont->noteheadstyle)];
  *p = 0;
  ps_relmusstring(buff, 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;

/* 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;

if (notetype >= 0)
  ps_musstring(reststrings[n_notetype], fontsize,
    x, out_ystave - (yoffset*main_stavemagn)/1000);

else ps_muschar(x, out_ystave - (yoffset*main_stavemagn)/1000,
  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 x = 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, skip printing; just show accents, etc. */

if ((bar_cont->flags & cf_notes) != 0 && (n_flags & nf_hidden) == 0)
  {
  /* If printing a breve, move left to align with semibreve position */

  if (n_pitch != 0 && n_notetype == breve) x -= (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;
      }
    ps_muschar(x - mac_muldiv(n_accleft, n_fontsize, 10000),
      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(x, notetype);
    }
  else ledgered = show_note(x);

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

  if ((n_flags & (nf_dot+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) */

    ps_musstring(((n_flags & nf_plus) == 0)? US"?" : US"\302\207", fontsize,
      x + dotpos, out_ystave - dotlevel - n_pcorrection);

    if ((n_flags & nf_dot2) != 0)
      ps_musstring(US"?", fontsize, x + dotpos + (35*main_stavemagn)/10,
        out_ystave - dotlevel - n_pcorrection);
    }
  }

/* 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, x + 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,
      x + 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, x + 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, x + 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;
  int f = n_acflags << 3;        /* first bit to top position */

  /* 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 < 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 << 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++ = '(';

      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 */

      case or_trem3:
      *p++ = 146;

      case or_trem2:
      *p++ = 146;

      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 = (y + ((n_ornament->ornament == or_trem1)? 4 : 2))* 1000;
        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;
        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 */

    while ((++n_ornament)->type == b_Jump)
      n_ornament = (b_ornamentstr *)
        ((b_Jumpstr *)(((b_Jumpstr *)n_ornament)->next) + 1);

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

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

/* End of shownote.c */
