/************************************************* * The PMW Music Typesetter - 3rd incarnation * *************************************************/ /* Copyright (c) Philip Hazel, 1991 - 2008 */ /* Written by Philip Hazel, starting November 1991 */ /* This file last modified: December 2019 */ /* This file contains code for outputting hairpins */ #include "pmwhdr.h" #include "outhdr.h" #include "pagehdr.h" /************************************************* * Deal with start of hairpin * *************************************************/ /* This remembers the hairpin parameters for later use. Arguments: h the hairpin data for the start of the hairpin x the x coordinate of the start of the hairpin Returns: nothing */ void out_setstarthairpin(b_hairpinstr *h, int x) { hairpinstr *hh = store_Xget(sizeof(hairpinstr)); hh->hairpin = h; hh->x = x; hh->maxy = -BIGNUMBER; hh->miny = BIGNUMBER; bar_cont->hairpin = hh; if ((h->flags & hp_bar) != 0) hh->x = out_startlinebar? (out_sysblock->timexposition + out_sysblock->xjustify) : out_lastbarlinex; /* The /bar option overrides /h */ else if ((h->flags & hp_halfway) != 0) out_hairpinhalf = TRUE; /* And /h overrides /lc and /rc. Adjust the x coordinate by looking for the relevant musical offset. If x == 0 it means we are setting up for a continuation hairpin while paginating, so don't do anything. */ else if (h->offset != 0 && x != 0) { int offset = mac_muldiv(len_crotchet, h->offset, 1000); hh->x = out_barx + out_findAoffset(out_moff + offset); } } /************************************************* * Draw a hairpin * *************************************************/ /* This actually draws the hairpin. Arguments: h1 the data for the end of the hairpin x1 the x coordinate of the end of the hairpin Returns: nothing */ void out_drawhairpin(b_hairpinstr *h1, int x1) { hairpinstr *hh = bar_cont->hairpin; b_hairpinstr *h0 = hh->hairpin; BOOL skip = FALSE; int flags = h0->flags; int abs = (flags & hp_abs) != 0; int cwidth = h0->width/2; int dwidth = cwidth; int thickness = curmovt->hairpinlinewidth; int x0 = hh->x; int offset, y0, y1, y0hole, y1hole; /* Compute basic offset from stave base */ if ((flags & hp_below) == 0) { offset = abs? 16000 : (((hh->maxy > 16000)? hh->maxy + 6000 : 22000) + (h0->width - 7000)/2); } else { offset = abs? 0 : (((hh->miny < 0)? hh->miny - 6000 : -6000) - (h0->width - 7000)/2); if ((flags & hp_middle) != 0 && out_stave < out_laststave) { int gap = out_sysblock->stavespacing[out_stave]/2; int st = out_stave + 1; while (gap == 0 && st < out_laststave) if (mac_teststave(out_sysblock->notsuspend, st)) gap = out_sysblock->stavespacing[st++]/2; gap -= 8 * main_stavemagn; if (-gap < offset) offset = -gap; } } /* At start of line, start just before first note; also set small gap at start of hairpin. If continued decrescendo, start at smaller width. */ if (x0 == 0) { x0 = out_sysblock->firstnoteposition - 4*main_stavemagn; y0 = h0->y + ((h1 == NULL)? 0 : h1->su); y0hole = main_stavemagn; dwidth = (80*dwidth)/100; } else /* not start of line */ { x0 += h0->x; y0 = h0->y; y0hole = 0; } /* Add manual right-hand adjustment; at end of line we use the left-hand value. Set small gap in decrescendo at end of line. */ if (h1 != NULL) { if ((h1->flags & hp_bar) != 0) /* /bar overrides /h */ { x1 = out_barlinex; } else if ((h1->flags & hp_halfway) != 0) { x1 += mac_muldiv(out_barx + out_findXoffset(out_moff) - x1 - 6*main_stavemagn, h1->h, 1000); } else if (h1->offset != 0) { int xoffset = mac_muldiv(len_crotchet, h1->offset, 1000); x1 = out_barx + out_findAoffset(out_moff + xoffset); } x1 += h1->x; y1 = h0->y + h1->y; y1hole = 0; } else /* end of line; reduce crescendo width a bit */ { y1 = h0->y + h0->su; y1hole = main_stavemagn; cwidth = (cwidth*80)/100; } /* Final y values */ y0 = ((y0 + offset)*main_stavemagn)/1000; y1 = ((y1 + offset)*main_stavemagn)/1000; /* Draw the hairpin, enforcing a minimum length of 10 points, except at the end of line where we can suppress a decrescendo. We can't suppress a crescendo - the user will have to fix. */ if (x1 - x0 < 10*main_stavemagn) { if (h1 != NULL || h0->opt == '<') x1 = x0 + 10*main_stavemagn; else skip = TRUE; } if (!skip) { if (h0->opt == '>') { ps_line(x0, y0 + dwidth, x1, y1 + y1hole, thickness, 0); ps_line(x0, y0 - dwidth, x1, y1 - y1hole, thickness, 0); } else { ps_line(x0, y0 + y0hole, x1, y1 + cwidth, thickness, 0); ps_line(x0, y0 - y0hole, x1, y1 - cwidth, thickness, 0); } } /* Free the dynamic store and clear its pointer. */ store_free(hh); bar_cont->hairpin = NULL; } /* End of sethairpin.c */