/************************************************* * The PMW Music Typesetter - 3rd incarnation * *************************************************/ /* Copyright (c) Philip Hazel, 1991 - 2020 */ /* Written by Philip Hazel, starting November 1991 */ /* This file last modified: January 2020 */ /* This file contains the main code typesetting one note or chord */ #include "pmwhdr.h" #include "pagehdr.h" #include "poshdr.h" #include "outhdr.h" /************************************************* * Static variables * *************************************************/ /* For saving beaming state while setting grace notes */ static BOOL save_beaming; static int save_beam_count; static int save_beam_firstX; static int save_beam_firstY; static int save_beam_seq; static int save_beam_slope; static int save_beam_splitOK; static int save_beam_upflag; static int save_beam_Xcorrection; /************************************************* * Main line for setting one note/chord * *************************************************/ /* The data for notes is put into global variables so they can easily be shared between the various functions. Note that chords have been sorted so that the note nearest the stem comes first. The variables n_prevtie and n_nexttie point to the incoming and outgoing ties, respectively. Argument: pointer to the first note Returns: pointer after the last note */ bstr * out_setnote(b_notestr *p) { int accleftnum = 0; DEBUG(("out_setnote() start\n")); n_lastnote = p; n_notetype = p->notetype; n_pitch = p->spitch; n_length = p->length; n_acc = n_firstacc = n_lastacc = p->acc; n_accleft = n_maxaccleft = (p->accleft * main_stavemagn)/1000; n_flags = n_chordflags = p->flags; n_acflags = n_chordacflags = p->acflags; /* Set parameters for a rest. We preserve the stem up flag from the previous note. This is useful in obscure cases such as tieing over rests. A rest also kills any outstanding underlay block for underlay extension (but not for hyphens). */ if (n_pitch == 0) { ulaystr **uu = &(bar_cont->ulay); ulaystr *u = *uu; while (u != NULL) { if (u->type == '=') { *uu = u->next; store_free(u); } else uu = &(u->next); u = *uu; } n_restlevel = p->yextra; n_prevtie = n_nexttie = NULL; n_upflag = out_laststemup[out_stave]; DEBUG(("rest level=%d upflag=%d\n", n_restlevel, n_upflag)); } /* Set parameters for a note, and find the number of notes in a chord. This is needed for tie direction computations, even for single notes. At the same time we can find the maximum accidental offset for the note/chord. This is also a convenient place for setting up the next and previous tie pointers. */ else { b_notestr *tp = p; n_chordcount = 1; n_stemlength = p->yextra; n_upflag = (n_flags & nf_stemup) != 0; n_upfactor = n_upflag? (+1):(-1); n_invertleft = (!n_upflag && (n_flags & nf_invert) != 0); n_invertright = (n_upflag && (n_flags & nf_invert) != 0); /* Don't use the couplepitch macro, as want to test the distances. */ if ((n_flags & (nf_coupleU | nf_coupleD)) != 0) { if ((n_flags & nf_coupleU) != 0) { n_pitch += out_upgap - 24; if ((out_upgap & 3) != 0) error_111 = TRUE; } else { n_pitch += 24 - out_downgap; if ((out_downgap & 3) != 0) error_111 = TRUE; } } n_maxpitch = n_minpitch = n_pitch; out_notelist[0] = tp; mac_advancechord(tp); while (tp->type == b_chord) { int pitch = tp->spitch; int accleft = (tp->accleft * main_stavemagn)/1000; if (accleft > n_maxaccleft) n_maxaccleft = accleft; n_lastacc = tp->acc; mac_couplepitch(pitch, tp->flags); if (pitch > n_maxpitch) n_maxpitch = pitch; else if (pitch < n_minpitch) n_minpitch = pitch; if (n_upflag) n_invertright |= (tp->flags & nf_invert) != 0; else n_invertleft |= (tp->flags & nf_invert) != 0; n_chordflags |= tp->flags; n_chordacflags |= tp->acflags; if (abs(tp->yextra) > abs(n_stemlength)) n_stemlength = tp->yextra; out_notelist[n_chordcount++] = tp; mac_advancechord(tp); } n_prevtie = bar_cont->tie; bar_cont->tie = NULL; if (tp->type == b_tie) { n_nexttie = (b_tiestr *)tp; if (n_upflag) n_nhtied = n_nexttie->belowcount > 0; else n_nhtied = n_nexttie->abovecount > 0; } else { n_nexttie = NULL; n_nhtied = FALSE; } DEBUG(("note chordcount=%d upflag=%d\n", n_chordcount, n_upflag)); } /* Deal with grace notes. If this is the first in a sequence, preserve the beaming state; after the last, restore it. */ if (n_length == 0) { posstr *pp; if (n_gracecount == 0) { save_beam_count = beam_count; save_beam_firstX = beam_firstX; save_beam_firstY = beam_firstY; save_beam_seq = beam_seq; save_beam_slope = beam_slope; save_beam_splitOK = beam_splitOK; save_beam_upflag = beam_upflag; save_beam_Xcorrection = beam_Xcorrection; save_beaming = out_beaming; out_beaming = FALSE; out_gracenotes = TRUE; out_grace_fudge = 0; } /* Set up the font size and the vertical & horizontal corrections */ if ((n_flags & nf_cuesize) != 0) n_fontsize = (curmovt->fontsizes)->fontsize_cuegrace; else n_fontsize = (curmovt->fontsizes)->fontsize_grace; n_cueadjust = 0; n_pcorrection = (2*main_stavemagn*(10000 - n_fontsize))/10000; n_gracemoff = posx_gracefirst + n_gracecount++; n_x = out_findXoffset(out_moff + n_gracemoff); /* If there was an accidental on the next note or chord ON ANY STAVE, then the grace note position may have been set to the left of this, if there were grace notes on that stave too. We must correctly position the grace note on THIS stave. If no staves with accidentals had grace notes, then the grace note position will be the same as the accidental position, as no space will have been left for grace notes. However, if the accidentals are on chords, they may be far wider than grace notes. We must check the final grace note's position; if it is the same as the accidental's position, allow for one accidental's width (5 points). This is all very nasty. */ if (n_gracecount == 1 && (pp = out_findTentry(out_moff + posx_acc)) != NULL) { int acc_x = pp->xoff; int next_x = out_findXoffset(out_moff); int maxaccleft; b_notestr *b = misc_nextnote(p, NULL); while (b->length == 0) b = misc_nextnote(b, NULL); maxaccleft = b->accleft; mac_advancechord(b); while (b->type == b_chord) { if (b->accleft > maxaccleft) maxaccleft = b->accleft; mac_advancechord(b); } out_grace_fudge = (next_x - acc_x) - maxaccleft; if ((pp-1)->xoff + out_grace_fudge > next_x - curmovt->gracespacing[0]) out_grace_fudge = next_x - curmovt->gracespacing[0] - (pp-1)->xoff; if (out_grace_fudge < 0) out_grace_fudge = 0; } /* Incorporate any adjustment, and make relative to bar */ out_Xadjustment += out_grace_fudge; n_x += out_barx + out_Xadjustment; } /* Deal with non-grace notes, first restoring beaming state after gracenotes have been encountered. */ else { if (n_gracecount) { beam_count = save_beam_count; beam_firstX = save_beam_firstX; beam_firstY = save_beam_firstY; beam_seq = save_beam_seq; beam_slope = save_beam_slope; beam_splitOK = save_beam_splitOK; beam_upflag = save_beam_upflag; beam_Xcorrection = save_beam_Xcorrection; out_beaming = save_beaming; out_gracenotes = FALSE; out_grace_fudge = 0; } /* Sort out the font size and horizontals & vertical corrections for small notes. */ if ((n_flags & nf_cuesize) != 0) { n_fontsize = (curmovt->fontsizes)->fontsize_cue; n_cueadjust = mac_muldiv(3500 - mac_muldiv(3500, n_fontsize, 10000), main_stavemagn, 1000); n_pcorrection = (2*main_stavemagn*(10000 - n_fontsize))/10000; } /* Full-sized note */ else { n_fontsize = 10000; n_pcorrection = n_cueadjust = 0; } /* Set the horizontal position - centred rests and (semi)breves are a special case */ if ((n_flags & nf_centre) != 0) { int leftx = 4*main_stavemagn; if (out_findTentry(posx_RLright) != NULL) leftx += out_barx + out_findXoffset(posx_RLright); else if (out_findTentry(posx_timefirst) != NULL) leftx += out_barx + out_findXoffset(posx_timefirst); else if (out_findTentry(posx_keyfirst) != NULL) leftx += out_barx + out_findXoffset(posx_keyfirst); else if (out_startlinebar) { /* Move back to the key signature if no left repeat, else add width of repeat */ leftx = (out_findTentry(posx_RLleft) == NULL)? out_barx - PAGE_LEFTBARSPACE : out_barx + 6 * main_stavemagn; } else leftx = out_lastbarlinex; if (out_manyrest == 1) { n_x = (leftx + out_barlinex)/2 - 3*main_stavemagn; /* Adjustments to centred notes to align with centred rest. */ if (n_pitch != 0) { n_x -= (((n_notetype == breve)? 12 : (n_notetype == semibreve)? 13 : 10) * main_stavemagn)/10; } else if (curmovt->breverests) { int t = bar_cont->time; int d = t & 255; int crotchets = 4 * (t >> 16); /* 4 times multiplier */ if (d != time_common && d != time_cut) crotchets = (crotchets * ((t >> 8) & 255)) / d; if (crotchets == 8 || crotchets == 12) n_notetype = breve; if (crotchets == 6 || crotchets == 12) n_flags |= nf_dot; } } else if ((n_flags & nf_hidden) == 0) /* No number if Q-type rests */ { uschar s[12]; int font = curmovt->font_longrest; int size = (((curmovt->fontsizes)->fontsize_restct)*main_stavemagn)/1000; int *matrix = (curmovt->fontsizes)->fontmatrix_restct; int i = (curmovt->codemultirests && out_manyrest < 9)? out_manyrest : 0; n_x = (leftx + out_barlinex - mac_muldiv(longrest_widths[i], main_stavemagn, 1000))/2; if (matrix != NULL) memcpy(font_transform, matrix, 4*sizeof(int)); /* Remember the mid-point where the long rest count is output to make it easier to draw a suitable sign when the bar is wide or narrow. */ n_longrestmid = out_Xadjustment + (leftx + out_barlinex)/2; sprintf(CS s, "%d", out_manyrest); out_string(s, font, size, n_longrestmid - (font_stringwidth(s, font, size))/2, out_ystave - 18*main_stavemagn - out_Yadjustment, 0); font_reset(); } } /* The normal, non-centred case. Unless outputting a grace note, search for either the first gracenote position, or (if not found) the note itself. */ else { if (curmovt->gracestyle != 0 && n_gracecount == 0) n_x = out_barx + out_findGoffset(out_moff + posx_gracefirst, out_moff) + out_Xadjustment; else n_x = out_barx + out_findXoffset(out_moff) + out_Xadjustment; if (n_pitch == 0) n_x += 1000; /* rests all need adjusting */ } n_gracecount = n_gracemoff = out_keycount = out_timecount = 0; } /* Compute accidental spacing adjustment factors. If the space between adjacent notes is large, we stretch a bit. Note that out_lastnotex is set very large and negative when the preceding object was not a note. */ if (n_maxaccleft > 0) { int accgap = n_x - out_lastnotex - n_maxaccleft; accleftnum = n_maxaccleft; if (out_lastnotex > 0 && accgap > 20*main_stavemagn) accleftnum = (11*n_maxaccleft)/10; n_accleft = (n_accleft * accleftnum)/n_maxaccleft; } /* Remember beginning of plet if necessary */ if (out_plet_x < 0) out_plet_x = n_x; /* Deal with beamed note. Take care with the messy code for keeping track of beamed sequences for plets. The variable beam_seq is maintained for this purpose: beam_seq = 0 => not in a beamed sequence -1 => at start (first note) of plet 1 => had beamed sequence in plet 2 => had rest in beamed sequence We reset 2 back to 1 if another beamed note is encountered. */ if (n_notetype >= quaver) { /* Deal with non-rests, either outside or inside beams */ if (n_pitch != 0) { /* If not beaming, see if this is the start of one, and cause the beam to be output if it is. */ if (!out_beaming && (bar_cont->flags & cf_noteheads) == 0) out_beaming = out_setupbeam(p, out_moff + n_gracemoff, FALSE, FALSE); /* If beaming, compute the correct stem length and turn the note type into a crotchet. Note that the units of n_stemlength are unmagnified; i.e. they are relative to the stave. */ if (out_beaming) { n_stemlength = (n_upfactor*(beam_firstY + mac_muldiv(beam_slope, out_findXoffset(out_moff+n_gracemoff) + out_Xadjustment + (75*main_stavemagn)/100 + (n_upflag? beam_Xcorrection : 0) - beam_firstX, 1000) - (n_pitch - 128)*main_stavemagn - (n_upfactor*14*n_fontsize*main_stavemagn)/10000)*1000)/ main_stavemagn; if (n_upflag != beam_upflag) n_stemlength += curmovt->beamdepth; n_notetype = crotchet; /* We can handle a beamed note turning into a minim by masquerade, but not anything else. */ if (n_masq == minim) n_notetype = minim; /* If beam_splitOK is true, then we can have notes on the other side of the beam. In this case there may be additional stem length adjustments to make to any note. */ if (beam_splitOK) n_stemlength += beam_stemadjusts[beam_count] * 1000; if (beam_seq != 0) beam_seq = 1; } /* Not a beamed note */ else beam_seq = 0; } /* Deal with rests. We need to check if rests at beam starts are permitted and we are not currently in a beam. See if this is the start of a beam, and if so, fudge up a note for the beam-handling code to start off with. Otherwise, check for masquerading within a beam. */ else { if (curmovt->beamendrests && !out_beaming) { b_notestr *next = misc_nextnote(p, NULL); while (next != NULL && next->spitch == 0 && next->notetype >= quaver) next = misc_nextnote(next, NULL); if (next != NULL && next->notetype >= quaver) { int save_yextra = p->yextra; int pextra = save_yextra/1000; int nextra = next->yextra/1000; int save_flags = p->flags; usint save_acflags = p->acflags; p->spitch = next->spitch; /* pretend it's as for the real note */ p->yextra = next->yextra; p->flags = n_flags = next->flags; p->acflags = n_acflags = next->acflags; n_upflag = (n_flags & nf_stemup) != 0; n_upfactor = n_upflag? (+1):(-1); if (n_upflag) { int tt = ((n_notetype > squaver)? 134 : 130) + pextra; int ss = p->spitch; if (ss < 122) ss = 122; ss += nextra; if (ss < tt) p->yextra += (tt - ss)*1000; } else { int tt = ((n_notetype > quaver)? 138 : 142) + pextra; int ss = p->spitch; if (ss > 150) ss = 150; ss -= nextra; if (ss > tt) p->yextra += (ss - tt)*1000; } out_beaming = out_setupbeam(p, out_moff + n_gracemoff, FALSE, TRUE); p->spitch = 0; p->yextra = save_yextra; n_flags = p->flags = save_flags; n_acflags = p->acflags = save_acflags; } } /* Handle masquerading rests within a beam -- outside a beam they are handled with ordinary notes. Any masquerade is allowed. */ if (out_beaming && n_masq >= 0) n_notetype = n_masq; } } /* Maintain beam_seq in the cases of long notes and rests */ else if (n_notetype < quaver) beam_seq = 0; else if (beam_seq == -1) beam_seq = 0; else if (beam_seq == 1) beam_seq = 2; /* Remember whether this note was beamed or not */ DEBUG(("beaming=%d beam_seq=%d\n", out_beaming, beam_seq)); n_beamed = out_beaming; /* If not beaming, compute some automatic stem length adjustments, and alter the note type if masquerading. */ if (!out_beaming) { if (n_notetype >= minim) { int xl = curmovt->tailadjusts[n_notetype]; if ((n_ornament != NULL && n_ornament->ornament == or_trem3) || (n_upflag && (n_flags & nf_invert) != 0 && n_notetype >= quaver)) xl += 4000; /* The stems of unbeamed, uncoupled notes must reach the centre of the stave if pointing that way. */ if ((n_flags & nf_couple) == 0) { int minxl = 0; if (n_upflag) { if (n_pitch < P_0L - 2) minxl = (P_0L - 2 - n_pitch)*1000; } else { if (n_pitch > P_6L + 2) minxl = (n_pitch - P_6L - 2)*1000; } if (xl < minxl) xl = minxl; } n_stemlength += xl; } /* Deal with masquerade */ if (n_masq >= 0) n_notetype = n_masq; } /* Remember horizontal information for hairpins if needed. This must be done for both visible and invisible things. */ if (out_hairpinhalf && bar_cont->hairpin != NULL) { hairpinstr *h = bar_cont->hairpin; b_hairpinstr *hh = h->hairpin; h->x += 6*main_stavemagn + mac_muldiv(out_barx + out_findXoffset(out_moff + n_length) - h->x - 6*main_stavemagn, hh->h, 1000); out_hairpinhalf = FALSE; } /* Remember data for marks that need to know what notes are under or above them. We must do this for rests as well as for real notes, but not for invisible things. */ if ((n_flags & nf_hidden) == 0) { slurstr *ss = bar_cont->slurs; int pt = misc_ybound(FALSE, n_nexttie, TRUE, TRUE); int pb = misc_ybound(TRUE, n_nexttie, TRUE, TRUE); /* Remember data for slur(s) if first note after start. We don't want any accidental on the note to influence the bounding pitch in this case. We must, however, use the combined accent flags for computing the bounding pitches. (Note: this code is for the true start only - restarts on a new line are different, as the accidental then is wanted.) */ if (out_slurstarted) /* This flag saves unnecessary work */ { slurstr *s = ss; int flagsave = n_flags; usint acflagsave = n_acflags; n_flags = n_chordflags; n_acflags = n_chordacflags; while (s != NULL) { if (s->count == 0 && s->x != 0) { int flags = (s->slur)->flags; int below = (flags & sflag_b) != 0; s->moff = out_moff; s->x = n_x; if (!below && /* Slur above */ (flags & sflag_l) == 0 && /* Not a line (i.e. a slur) */ (n_flags & nf_stem) != 0 && /* Note has a stem */ n_upflag && /* Stem is up */ !main_righttoleft) /* Not right-to-left */ s->x += 5*main_stavemagn; s->lastx = s->x; s->y = misc_ybound(below, n_nexttie, FALSE, TRUE); /* If the note is beamed, and the slur is on the same side as the beam, we need to put in an additional bit of space for clearance. Also, if the slur is on the opposite side to the stem, ditto. */ if (below) { if (n_upflag || out_beaming) s->y -= 1000; } else { if (!n_upflag || out_beaming) s->y += 1000; } /* Initialize max/min verticals */ s->maxy = s->miny = s->lasty = s->y; } s = s->next; } out_slurstarted = FALSE; n_flags = flagsave; n_acflags = acflagsave; } /* Remember data at the start of continued slurs. If this note is not tied onwards, take note of an incoming tie. */ if (out_moff == 0 && out_startlinebar && !out_passedreset) { slurstr *s = ss; int ptt, pbb; if (n_nexttie == NULL && n_prevtie != NULL) { ptt = misc_ybound(FALSE, n_prevtie, TRUE, TRUE); pbb = misc_ybound(TRUE, n_prevtie, TRUE, TRUE); } else { ptt = pt; pbb = pb; } while (s != NULL) { if (s->x == 0) { int below = ((s->slur)->flags & sflag_b) != 0; int pbbb = pbb; int pttt = ptt; if (below) { if (n_upflag || out_beaming) pbbb -= 1000; } else { if (!n_upflag || out_beaming) pttt += 1000; } s->lastx = n_x; s->y = s->lasty = s->maxy = s->miny = (below)? pbbb : pttt; } s = s->next; } } /* Remember data for slurs */ while (ss != NULL) { BOOL below = ((ss->slur)->flags & sflag_b) != 0; /* Compute slope from start and current slope (for use at the end). Skip if at same x offset, which can happen after a reset. */ if (ss->count != 0) /* first time is different */ { int xx = n_x - ss->lastx; if (xx > 0) ss->sloperight = mac_muldiv((below? pb : pt) - ss->lasty, 1000, xx); xx = n_x - ss->x; if (xx > 0) { int t = mac_muldiv((below? pb : pt) - ss->y, 1000, xx); if (below) { if (t < ss->slopeleft) ss->slopeleft = t; } else if (t > ss->slopeleft) ss->slopeleft = t; } /* Keep max/min y value -- note: we don't obey this for the first note as they have been set already, ignoring any accidental on the first note. We don't actually want to include the final note in here, so we actually operate one note behind here. */ if (below) { if (ss->lasty < ss->miny) ss->miny = ss->lasty; } else { if (ss->lasty > ss->maxy) ss->maxy = ss->lasty; } /* Keep the last pitch and x position, for slope calculation */ ss->lastx = n_x; ss->lasty = below? pb : pt; } /* Count notes under the slur and advance to next */ ss->count++; ss = ss->next; } /* Remember data for plet */ if (out_plet != NULL) { if (pt > out_plet_highest) out_plet_highest = pt; if (pb < out_plet_lowest) out_plet_lowest = pb; if (n_pitch > out_plet_highest_head) out_plet_highest_head = n_pitch; } /* Remember vertical data for hairpin */ if (bar_cont->hairpin != NULL) { hairpinstr *h = bar_cont->hairpin; if (pt > h->maxy) h->maxy = pt; if (pb < h->miny) h->miny = pb; } /* Remember data for numbered repeat bars; a non-scaled value is required. */ if (bar_cont->nbar != NULL) { nbarstr *b = bar_cont->nbar; if (pt > b->maxy) b->maxy = pt; } } /* Output all saved up text that was waiting to find out about this note/chord's pitch and accents, etc. We clear the above/below counts afterwards, for the benefit of end-of-bar text. They are initially cleared at the start of a bar. */ { int i; int save_flags = n_flags; usint save_acflags = n_acflags; n_flags = n_chordflags; n_acflags = n_chordacflags; for (i = 0; i < out_textqueueptr; i++) { out_textX = out_textXqueue[i]; out_text(out_textqueue[i], FALSE); } out_textqueueptr = out_textnextabove = out_textnextbelow = 0; out_textX = NULL; n_flags = save_flags; n_acflags = save_acflags; } /* Output any draw items that were waiting likewise */ if (out_drawqueueptr > 0) { int i; draw_ox = n_x + n_cueadjust; /* Set origin */ draw_oy = 0; for (i = 0; i < out_drawqueueptr; i++) { b_drawstr *d = out_drawqueue[i]; out_dodraw(d->item, d->args, d->overflag); } out_drawqueueptr = 0; } /* Now we can reset the adjustment; it is left till after text and draw output. */ out_Xadjustment = 0; out_Yadjustment = 0; /* Set the note or rest, first setting up the stemlength that will be used for all accents etc. in a chord. */ n_orig_stemlength = n_stemlength; out_shownote(); out_lastnotex = n_x; /* Print tremolo bars if required. Note that the x-values required by ps_beam() are relative to the bar start. Ignore if inside a beam, and if this note is a rest. (The first can't be a rest if we have got this far.) We make use of the beam drawing routine. */ if (out_tremolo != NULL) { if (!out_beaming && n_pitch != 0) { int i, y; int x0 = out_tremx - out_barx + (75*main_stavemagn)/100; int x1 = n_x - out_barx + (115*main_stavemagn)/100; beam_Xcorrection = (51*main_stavemagn)/10; if (n_notetype < minim) { beam_upflag = out_tremupflag = FALSE; out_tremolo->join = 0; /* Force no join */ x0 += beam_Xcorrection; } else beam_upflag = n_upflag; y = misc_ybound(!beam_upflag, NULL, FALSE, FALSE); beam_firstY = out_tremy; if (beam_upflag) { if (out_tremupflag) { x0 += beam_Xcorrection; beam_firstY -= 3*main_stavemagn; } else beam_firstY += 2*main_stavemagn; x1 += beam_Xcorrection; y -= 3*main_stavemagn; } else /* !beam_upflag */ { if (out_tremupflag) { x0 += beam_Xcorrection; y -= main_stavemagn; beam_firstY -= 4*main_stavemagn; } y += 3*main_stavemagn; beam_firstY += 3*main_stavemagn; } beam_firstX = x0; beam_slope = mac_muldiv(y - beam_firstY, 1000, x1 - x0); /* Now draw the beams. At the end of the joined ones, shorten the x values. If the right-hand note is a semibreve (no stem) and has accidentals, shorten even further. */ for (i = 0; i < out_tremolo->count; i++) { if (i == out_tremolo->join) { int xx = (n_x - out_tremx)/5; x0 += xx; x1 -= xx; if ((n_flags & nf_stem) == 0) x1 -= n_accleft; } ps_beam(x0, x1, i, 0); } } out_tremolo = NULL; } /* Clear ornament before printing the rest of a chord */ n_ornament = NULL; /*** Finished with single note ***/ /* Deal with the remaining notes of a chord. Save and re-instate the note flags for the main note, if they are printed on the stem side, because these contain data about accents which is relevant to slurs that end on the note. */ if (n_chordcount > 1) { int lastpitch = n_pitch; usint n_orig_acflags = n_acflags; b_notestr *tp = p; mac_advancechord(tp); while (tp->type == b_chord) { n_pitch = tp->spitch; n_flags = tp->flags & ~nf_appogg; /* No slashes on inside chord notes */ n_acflags = tp->acflags; n_acc = tp->acc; n_accleft = (tp->accleft*main_stavemagn)/1000; mac_couplepitch(n_pitch, n_flags); n_stemlength = (abs(n_pitch - lastpitch) - (14*n_fontsize)/10000) * 1000; if (n_stemlength < n_orig_stemlength) n_stemlength = n_orig_stemlength; if (n_accleft) n_accleft = (n_accleft * accleftnum)/n_maxaccleft; n_notetype = (n_masq >= 0)? n_masq : tp->notetype; if (n_notetype >= quaver) n_notetype = crotchet; if ((bar_cont->flags & cf_notes) != 0) out_shownote(); p = tp; /* p must be left pointing to last note */ mac_advancechord(tp); lastpitch = n_pitch; } n_stemlength = n_orig_stemlength; /* restore for slur etc. calculations */ /* Restore first accents if printed on stem side, else leave last ones */ if ((n_orig_acflags & af_opposite) != 0) n_acflags = n_orig_acflags; } /* Output a tie or glissando that ends on this note or chord */ if (n_prevtie != NULL) { int flags = n_prevtie->flags; if ((flags & (tief_slur|tief_default)) != 0) { b_notestr *prevnote = n_prevtie->note; mac_advancechord(prevnote); if (n_chordcount == 1 && prevnote->type != b_chord) out_setnotetie(n_x, FALSE, flags); else out_setchordtie(out_notelist, n_chordcount, n_x, FALSE, flags); } if ((flags & tief_gliss) != 0 && n_chordcount == 1) out_glissando(n_x, flags); } /* Cancel the dot adjustment unless a tie follows */ if (n_nexttie == NULL) n_dotxadjust = 0; /* Cancel masquerade and update last stem flag */ n_masq = -1; out_laststemup[out_stave] = n_upflag; /* Reset beaming flag if beam completed. Reset the beaming adjustments so as to ignore directives that appear in the middle of beams. This is relevant when beams may be split over a line end; adjustments at the start of the second bar are ignored unless it is at the start of a line. */ if ((out_lastnotebeamed = out_beaming) == TRUE && --beam_count <= 0) { out_beaming = beam_continued = FALSE; beam_forceslope = BIGNUMBER; beam_offsetadjust = 0; } /* Advance musical offset */ out_lastmoff = out_moff; out_moff += n_length; DEBUG(("out_setnote() end\n")); return (bstr *)p; /* Pointer to last note of chord */ } /* End of setnote.c */