/************************************************* * 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 code for outputting one bar */ #include "pmwhdr.h" #include "pagehdr.h" #include "outhdr.h" /************************************************* * Output one bar in a system * *************************************************/ /* The bar number is in out_bar. The yield is the number of the last bar output plus one, which may be greater than the value of out_bar plus one when multiple rests are involved. Arguments: none Returns: number of the next bar to be output */ int out_setbar(void) { int i; BOOL notfirst = FALSE; bstr *lastp = NULL; int numberwanted = 0; usint *notsuspend = out_sysblock->notsuspend; contstr *out_cont_save = out_cont; barposstr *bp = curmovt->posvector + out_bar; zcopystr *zcopy = curmovt->zcopy; DEBUG(("out_setbar() start: bar %d\n", out_bar)); out_ystave = out_yposition + out_sysblock->systemdepth; out_downgap = 24; out_postable = out_posptr = bp->vector; out_poslast = out_postable + bp->count - 1; out_posxRL = -bp->posxRL; /* (stored positive) */ out_barlinex = out_barx + out_poslast->xoff; out_repeatonbarline = out_lastbarwide; out_lastbarwide = FALSE; out_manyrest = bp->multi; out_lineendflag = (out_bar + out_manyrest - 1) == out_sysblock->barend; for (i = 0; i < dyn_max; i++) out_dynmovef[i] = out_dynmovex[i] = out_dynmovey[i] = 0; /* Decide if a bar number is wanted. If there was a [nocount] directive in this bar, then the next entry in the bar number vector is greater than the current one. For such bars, a bar number is never printed. For other bars, the logical bar number can be obtained from the true bar number, the bar number vector, and the offset. */ if (curmovt->barnovector[out_bar+1] <= curmovt->barnovector[out_bar]) { int bn = out_bar - curmovt->barnovector[out_bar] + curmovt->baroffset; int interval = curmovt->barno_interval; if (((interval > 0 && (bn % interval) == 0) || (interval < 0 && out_startlinebar) || bp->barnoforce == 1) && bn > 1 && bp->barnoforce != 255) numberwanted = bn; } /* Deal with the data on each stave, skipping unwanted staves. We do the printing from bottom to top so that each stave's stuff gets printed before the bar line gets drawn into it from above - otherwise the wiping stuff for beams may obliterate parts of the bar lines. */ for (out_stave = out_laststave; out_stave >= 0; out_stave--) { bstr *p; obeamstr *b; int barlinestyle = curmovt->barlinestyle; stavestr *ss = curmovt->stavetable[out_stave]; int nextstave = 0; BOOL breakbarline = mac_teststave(curmovt->breakbarlines, out_stave); BOOL another; DEBUG(("stave %d\n", out_stave)); /* Skip if stave is suspended */ if (mac_testNstave(notsuspend, out_stave)) goto CHECKZCOPY; /* Do start of bar things (PostScript generates a comment) */ ps_startbar(out_bar, out_stave); /* Each stave controls its own bit of barline */ out_omitbarline = FALSE; out_barchar = bar_single; out_prevbar = NULL; /* for omitempty previous bar lines */ /* Lastp gets left pointing to the data for the top stave */ lastp = p = (ss == NULL)? NULL : ss->barindex[out_bar]; /* Set relative stave size */ mac_setstavesize(out_stave); /* Reset hairpin starting halfway flag */ out_hairpinhalf = FALSE; /* Set the gaps for coupling - must find previous printing stave. As the gaps are in pitch units, they must be made relative to the stave magnification. */ if (out_stave == 0) out_upgap = 24; else { int previous; for (previous = out_stave - 1; previous > 0; previous--) { if (mac_teststave(notsuspend, previous) && out_sysblock->stavespacing[previous] != 0) break; } out_upgap = out_sysblock->stavespacing[previous]/main_stavemagn; } out_downgap = (out_sysblock->stavespacing[out_stave])/main_stavemagn; if (out_downgap == 0) { int next; for (next = out_stave + 1; next <= out_laststave; next++) { if (mac_teststave(notsuspend, next) && out_sysblock->stavespacing[next] != 0) { out_downgap = (out_sysblock->stavespacing[next])/main_stavemagn; break; } } } /* For all but the first to be printed (i.e. the bottom stave), move up by this stave's spacing */ if (notfirst) { out_ystave -= out_sysblock->stavespacing[out_stave]; } else notfirst = TRUE; /* Set the bar_cont data before skip testing; it is required to be left to the topmost stave for bar number printing. Also, we need to empty the beam continuation data if it set up. */ bar_cont = out_cont + out_stave; /* Set up beaming variables. The value of out_overbeam must only ever be true while out_setupbeam() is computing spanning beams. Hence we make sure it is FALSE here. */ beam_forceslope = BIGNUMBER; beam_offsetadjust = beam_accrit = 0; beam_overbeam = FALSE; /* If a beam has continued over a bar line, set up the various parameters; otherwise set no beaming. */ b = bar_cont->overbeam; if (b != NULL && b->count > 0) { /* At the start of a line the beam has not been drawn. The continued flag will ensure that even one note gets a beam, and the longestnote value will be taken from this block. */ if (out_startlinebar) { out_beaming = FALSE; beam_forceslope = b->slope; } /* For a non-start of line bar, the beam has already been drawn; set up the relevant parameters for the notes. */ else { beam_firstX = b->firstX; beam_firstY = b->firstY; beam_slope = b->slope; beam_count = b->count; beam_Xcorrection = b->Xcorrection; beam_splitOK = b->splitOK; beam_upflag = b->upflag; out_beaming = TRUE; } beam_seq = 0; beam_continued = TRUE; b->count = -1; } else out_beaming = beam_continued = FALSE; /* Determine if there is a following printing stave, for the purpose of extending bar lines down. We have to look down to find it, in case it is an [omitempty] stave with no data. If any of the suspended staves we skip over have got their break barline bit set, we must break the barline here. If the current stavespacing is zero, we don't want to extend bar lines. */ /* Searching the bit maps for a bit higher than this one is tedious. Maybe there should be a macro, but I think we do it just this once... Nope, it comes again in setwarn. */ another = (notsuspend[out_stave >> 5] & (-main_bit[out_stave & 0x1f])) > main_bit[out_stave & 0x1f]; if (!another) for (i = (out_stave >> 5) + 1; i < STAVE_BITVEC_SIZE; i++) if (notsuspend[i] != 0) { another = TRUE; break; } if (another && out_sysblock->stavespacing[out_stave] > 0) { for (i = out_stave + 1; i <= out_laststave; i++) { stavestr *sss; if (mac_testNstave(notsuspend, i)) { if (mac_teststave(curmovt->breakbarlines, i)) breakbarline = TRUE; } else { sss = curmovt->stavetable[i]; if (sss == NULL || !sss->omitempty || sss->barindex[out_bar] != NULL || (!out_lineendflag && sss->barindex[out_bar+1] != NULL)) nextstave = i; break; } } } /* Initialize miscellaneous global variables. */ out_pnum = 1; out_pden = 2; out_plet = NULL; out_tremolo = NULL; out_passedreset = out_lastnotebeamed = FALSE; out_lastnotex = -100000; /* for accidental stretching */ out_moff = out_lastmoff = out_Xadjustment = out_Yadjustment = 0; out_gracenotes = FALSE; n_gracecount = n_gracemoff = out_keycount = out_timecount = 0; out_drawqueueptr = 0; out_textqueueptr = out_textnextabove = out_textnextbelow = 0; out_textX = NULL; out_stavelines = ss->stavelines & 127; /* Without the "no clefs/keys" bit */ out_stavetop = stave_tops[out_stavelines]; out_stavebottom = stave_bottoms[out_stavelines]; n_pitch = 0; /* in case no items in the bar */ n_ornament = NULL; n_masq = -1; n_dotxadjust = 0; /* Calculate the bottom position of the bar line. We need to do this first because it is used within the bar sometimes (dotted lines, time signatures, repeats, etc.) If a [breakbarline] directive is encountered, the value will be reset to out_ystave; if [unbreakbarline] is found, the value will be reset to out_deepbarend. */ out_ybarend = out_deepybarend = out_ystave; if (nextstave > 0) { out_deepybarend += out_sysblock->stavespacing[out_stave] - 16*curmovt->stavesizes[nextstave]; if (!breakbarline) out_ybarend = out_deepybarend; } /* Loop through all items in the bar, if there are any */ if (p != NULL) { int type = p->type; while (type != b_End) { if (type == b_Jump) { p = (bstr *)(((b_Jumpstr *)p)->next); } /* Deal with a note or chord */ else if (type == b_note) { p = out_setnote((b_notestr *)p); } /* Deal with a non-note, and then switch off accidental stretching for the note which follows. */ else { out_setother(p); out_lastnotex = -100000; } /* Next item */ p = (bstr *)((uschar *)p + length_table[type]); type = p->type; } barlinestyle = ((b_Endstr *)p)->barlinestyle; } /* Non-existent bars take their barline style from the stave's default. This isn't entirely satisfactory, but copes with common cases. A value of 255 means no barlinestyle was ever set for the stave. */ else { if (ss->barlinestyle != 255) barlinestyle = ss->barlinestyle; } /* ---- End of loop through bar ---- */ /* If this was the last bar on the line, deal with things which can be continued onto the next line. */ if (out_lineendflag) { slurstr *s = bar_cont->slurs; int true_endline = out_barlinex; if (curmovt->tiesoverwarnings && (out_sysblock->flags & sysblock_warn) != 0) { if ((out_sysblock->flags & sysblock_stretch) != 0) { true_endline = curmovt->linelength; } else { if ((bp+1)->vector != NULL) /* BUG FIX 04-Apr-2003 */ true_endline += ((bp+1)->vector + 1)->xoff; } } /* Draw slurs to line end. Note that misc_drawslur frees the slur structure, and we must free the pointer so that freeing the whole cont structure works. */ bar_cont->slurs = NULL; while (s != NULL) { slurstr *snext = s->next; misc_drawslur(s, true_endline - 3000 + curmovt->endlinesluradjust, 0, TRUE); s = snext; } /* Draw ties and glissandos to line end. For glissandos, invent a right-hand pitch that is in the right direction usually. */ if ((n_prevtie = bar_cont->tie) != NULL) { int x = true_endline - 4*main_stavemagn + curmovt->endlinetieadjust; int flags = n_prevtie->flags; n_flags = n_acflags = n_accleft = 0; n_notetype = breve; n_nexttie = NULL; /* Deal with ties. For chords we have to look ahead to the start of the next line to get the list of notes in the first chord. If there isn't a next bar, or if it is empty, draw ties on all the notes. */ if ((flags & (tief_slur | tief_default)) != 0) { if (n_chordcount == 1) out_setnotetie(x, TRUE, flags); else { int count = 0; b_notestr *notelist[20]; if (out_bar < curmovt->barcount) { stavestr *st = curmovt->stavetable[out_stave]; bstr *pp = (st == NULL)? NULL : st->barindex[out_bar+1]; if (pp != NULL) { int type = pp->type; while (type != b_End) { if (type == b_Jump) pp = (bstr *)(((b_Jumpstr *)pp)->next); else if (type == b_note) { b_notestr *tp = (b_notestr *)pp; do { notelist[count++] = tp; mac_advancechord(tp); } while (tp->type == b_chord); break; } pp = (bstr *)((uschar *)pp + length_table[type]); type = pp->type; } } } if (count > 0) out_setchordtie(notelist, count, x, TRUE, flags); else out_setchordtie(out_notelist, n_chordcount, x, TRUE, flags); } } /* Deal with glissandos - single notes only */ if ((flags & tief_gliss) != 0 && n_chordcount == 1) { b_notestr *pp = (ss == NULL)? NULL : (b_notestr *)(ss->barindex[out_bar+1]); if (pp != NULL && pp->type != b_note) pp = misc_nextnote(pp, NULL); if (pp == NULL) n_pitch = (n_pitch > P_3L)? P_0S : P_5S; else n_pitch = pp->spitch; out_glissando(x + (45*main_stavemagn)/10, flags); } } /* If there is a hairpin outstanding, draw an incomplete one */ if (bar_cont->hairpin != NULL) out_drawhairpin(NULL, out_barlinex - 4*main_stavemagn); /* If there is an outstanding nth-time requirement at the end of the last bar on a line, output the marking so far. We have to search the next bar to see if it starts a new one, to determine whether to draw a right-hand jog or not. */ if (bar_cont->nbar != NULL) { BOOL flag = FALSE; if (out_bar >= curmovt->barcount) flag = TRUE; else { bstr *pp = ss->barindex[out_bar+1]; if (pp != NULL) { int ttype = pp->type; while (ttype != b_End) { if (ttype == b_Jump) pp = (bstr *)(((b_Jumpstr *)pp)->next); else if (ttype == b_nbar) { flag = TRUE; break; } pp = (bstr *)((uschar *)pp + length_table[ttype]); ttype = pp->type; } } } (void)out_drawnbar(flag, out_barlinex); out_freenbar(); } /* Deal with outstanding underlay extensions or rows of hyphens at the end of the last bar on a line. In the case of hyphens, we must ensure that at least one hyphen is always output. Extension lines are drawn note by note, so a line to the last note on the stave will have been drawn. However, if the syllable continues on the next system, we would like to draw the line a bit longer. If the preceding note did not have an "=" associated with it, the extender won't have been drawn. We must cope with this case too. */ while (bar_cont->ulay != NULL) { ulaystr *u = bar_cont->ulay; BOOL contflag = FALSE; BOOL overlay = u->level >= olay_offset; int xx = u->x; int yy = u->y; int fontsize = mac_muldiv(main_stavemagn, overlay? ((curmovt->fontsizes)->fontsize_text)[ff_offset_olay] : ((curmovt->fontsizes)->fontsize_text)[ff_offset_ulay], 1000); if (xx == 0) /* A complete system of hyphens or extender */ { xx = out_sysblock->firstnoteposition + out_sysblock->xjustify - 4000; yy = overlay? out_sysblock->olevel[out_stave] : out_sysblock->ulevel[out_stave]; contflag = TRUE; } /* Remove this block from the chain */ bar_cont->ulay = u->next; /* Deal with row of hyphens */ if (u->type == '-') { int xend = out_barlinex - 2000; if (xend - xx < 800) xend += 1000; if (xend - xx < 800) xend = xx + 801; /* In case xx < 0 */ if (u->htype == 0) out_hyphens(xx, xend, yy, fontsize, contflag); else out_repeatstring(xx, xend, yy, contflag, TRUE, u->htype); } /* Deal with extender line */ else if (n_pitch != 0) { BOOL extender_continues = FALSE; int xend; /* See if the syllable continues on to the next system; we assume it does if we find a note before any text; or if we find an underlay text string beginning with "=". */ if (out_bar < curmovt->barcount) { stavestr *st = curmovt->stavetable[out_stave]; bstr *pp = (st == NULL)? NULL : st->barindex[out_bar+1]; if (pp != NULL) { int type = pp->type; while (type != b_End) { if (type == b_Jump) pp = (bstr *)(((b_Jumpstr *)pp)->next); /* Note or chord => extender continues (unless rest) */ else if (type == b_note) { extender_continues = ((b_notestr *)pp)->spitch != 0; break; } /* Underlay text before any notes means the syllable does not continue, unless it is "=". */ else if (type == b_text) { b_textstr *t = (b_textstr *)pp; if ((t->flags & text_ul) != 0) { extender_continues = ((t->string)[0] == '='); break; } } /* Next item in the bar */ pp = (bstr *)((uschar *)pp + length_table[type]); type = pp->type; } } } /* End depends on whether continuing or not */ xend = extender_continues? out_barlinex - 4000 : n_x + 5*main_stavemagn; if (xend - xx > 4000) out_extension(xx, xend, yy, fontsize); } store_free(u); } } /* --- End of processing continued items --- */ /* First of all, we must extend ybarend if it is not extended and the option to have full barlines at the end of each system is set. */ if (out_lineendflag && out_ybarend == out_ystave && curmovt->fullbarend && nextstave > 0) out_ybarend = out_deepybarend; /* If we have just printed a multi-bar rest, we must use the appropriate kind of bar line for the *last* bar. This requires a scan of the last bar. The last bar is also permitted to contain a right-hand repeat mark. If this is found, we output it at the barline position, as we know there can be no notes in the bar. Thirdly, the last bar is permitted to contain a clef at the end, or an invisible bar line. */ if (out_manyrest > 1) { bstr *pp = (ss == NULL)? NULL : ss->barindex[out_bar+out_manyrest-1]; if (pp != NULL) { int type = pp->type; while (type != b_End) { if (type == b_Jump) pp = (bstr *)(((b_Jumpstr *)pp)->next); else if (type == b_dbar) out_barchar = bar_double; else if (type == b_rrepeat) { int magn = (curmovt->barlinesize > 0)? curmovt->barlinesize : main_stavemagn; out_omitbarline = out_lastbarwide = TRUE; out_writerepeat(out_barlinex - ((out_lineendflag? 68 : 50)*magn)/10, rep_right, magn); } else if (type == b_clef || type == b_ibar) { out_setother(pp); } pp = (bstr *)((uschar *)pp + length_table[type]); type = pp->type; } } } /* Now we can output appropriate bits of bar line. Do not print a barline for staff 0, or if already done for repeat, or for [omitempty] bars containing no data. Do, however, print a leading barline for non-line-starting omitempty bars with nothing preceding. */ if (out_stave != 0) { int ytop = out_ystave + ((barlinestyle == 2 || barlinestyle == 3)? 16*main_stavemagn : (ss->stavelines == 6)? - 4*main_stavemagn : 0); int ybarstart = ytop; int magn = (curmovt->barlinesize > 0)? curmovt->barlinesize : main_stavemagn; if (!out_omitbarline && (!ss->omitempty || (ss->barindex)[out_bar] != NULL)) { if ((barlinestyle == 1 || barlinestyle == 3) && out_barchar == bar_single) out_barchar = bar_dotted; if (out_ybarend >= ybarstart) { int x = 0; if (out_barchar == bar_double) x = 2*magn; else if (out_barchar == bar_thick || (out_bar + out_manyrest - 1 >= curmovt->barcount && !curmovt->unfinished)) { x = 3500; ps_barline(out_barlinex - (3*magn)/2, ybarstart, out_ybarend, bar_thick); } /* Deal with bar line styles that involve either or both of lines on the stave and lines between the staves. */ if (out_barchar == bar_thick) ps_barline(out_barlinex - x, ybarstart, out_ybarend, bar_single); else if (barlinestyle < 4 || out_barchar == bar_double) { ps_barline(out_barlinex - x, ybarstart, out_ybarend, out_barchar); } /* Deal with the special bar line styles that involve markings only on the current stave. */ else { ps_musstring((barlinestyle == 4)? US"~x\302\211yyyyyyx\302\211" : US"|\302\211yyyyyyxxxxx\302\211", 10*main_stavemagn, out_barlinex, out_ystave); } } } /* Flag wide bar line for next bar */ if (out_barchar == bar_double) out_lastbarwide = TRUE; /* For omitempty bars, output a bit of bar line at the start of the bar, if the previous bar was not printed. If we have encountered a prevbarstr in the bar, a pointer to it will have been saved. As the style may be different to the ending line, we have to compute everything again. */ if (ss->omitempty && (ss->barindex)[out_bar] != NULL) { int x = 0; if (!out_startlinebar && (ss->barindex)[out_bar - 1] == NULL) { int barchar = bar_single; int style = (ss->barlinestyle != 255)? ss->barlinestyle : curmovt->barlinestyle; if (out_prevbar != NULL) { if (out_prevbar->dbar) barchar = bar_double; if (out_prevbar->ibar) barchar = 0; style = out_prevbar->style; } ytop = (style == 2 || style == 3)? (out_ystave + 16*main_stavemagn) : out_ystave; ybarstart = ytop; if (out_ybarend >= ybarstart) { if ((style == 1 || style == 3) && barchar == bar_single) barchar = bar_dotted; if (barchar != 0) { if (style < 4 || barchar == bar_double) { if (barchar == bar_double) x = 2*main_stavemagn; ps_barline(out_lastbarlinex - x, ybarstart, out_ybarend, barchar); } else { ps_musstring((style == 4)? US"~x\302\211yyyyyyx\302\211" : US"|\302\211yyyyyyxxxxx\302\211", 10*main_stavemagn, out_lastbarlinex, out_ystave); } } } } /* For staves with [omitempty] set, we have to generate a bit of stave for this bar at this point. Other stave lines are printed as complete systems. */ if (ss->stavelines > 0) { ps_stave((!out_startlinebar)? out_lastbarlinex - x : out_sysblock->startxposition + out_sysblock->xjustify, out_ystave, out_barlinex, ss->stavelines & 127); } } } /* When we reach stave zero, we have to see which systems it is to be printed over. It can get printed several times, with vertical adjustments. If zcopy is NULL, we have completed the list. We have to maintain a separate contstr for each copy of stave zero; there is a space in the zcopy block for doing this. If this copy is required, set stave = 1 and break out of inner loop; the outer loop with then iterate for stave 0. If there is more than one stave zero being printed, we must switch in the separate contstr copies. */ CHECKZCOPY: if (out_stave <= 1) while (zcopy != NULL) { if (zcopy->level >= 0) { out_ystave = out_yposition + zcopy->level - zcopy->adjust - zcopy->baradjust; zcopy->baradjust = 0; if (out_zcopycount > 1) out_cont = (contstr *)zcopy->cont; zcopy = zcopy->next; out_stave = 1; break; } /* If this copy is not required, set stave = 0 so that if the inner loop now terminates, the outer one will too. */ out_stave = 0; zcopy = zcopy->next; } } /* Restore the contstr pointer that might have been changed when printing copies of stave zero. */ out_cont = out_cont_save; /* Output bar number if required, above the top stave */ if (numberwanted > 0) { uschar s[12]; int x = bp->barnoX; int y = 24000; int *matrix = (curmovt->fontsizes)->fontmatrix_barno; /* Adjust position for start and non-start bars */ if (out_startlinebar) { x += out_sysblock->startxposition + out_sysblock->xjustify; if (bar_cont->clef == clef_trebledescant) x += 15000; else if (bar_cont->clef == clef_soprabass) x += 9000; } else { b_notestr *next = (lastp == NULL)? NULL : (lastp->type == b_note)? (b_notestr *)lastp : misc_nextnote((b_notestr *)lastp, NULL); x += out_lastbarlinex; if (next != NULL && next->spitch > P_5L) y = (next->spitch - 120) * 1000; } /* Now print it */ y = ((y + bp->barnoY)*main_stavemagn)/1000 + curmovt->barno_level; sprintf(CS s, "%d", numberwanted); if (matrix != NULL) memcpy(font_transform, matrix, 4*sizeof(int)); out_string(s, curmovt->font_barnumber, (curmovt->fontsizes)->fontsize_barno, x, out_yposition - y, curmovt->barno_textflags); font_reset(); } /* Remember the position of the last barline, and return the number of the following bar. */ out_lastbarlinex = out_barlinex; DEBUG(("out_setbar() end\n")); return out_bar + out_manyrest; } /* End of setbar.c */