#ifndef lint
static char *sccsid = "@(#)post_put.c	1.3 (UKC) 17/5/89";
#endif  lint
#include <stdio.h>
#include "post_mus.h"

extern struct barls barlv[];

#define BEAMTHICK 2
#define BEAMSPAN 4
#define HOOKSPAN 4


int	text_size,
	max_hooks,
	min_hooks,
	max_t_over,
        max_t_under;

putnote (beat) {		/* global staff used */
    int     i,
            j,
            k,
            x,
            y,
            l;
    float   x0,
            x1,
            x2,
            y0,
            y1,
            y2;
    float   m;
    int     ssx,
            ssy;		/* stick start x coord */
    float   voffset;
    struct notes   *notep = notev + beat;

 /* print summary for comment */
    if (put_monitor == 3)
	noteprint (beat);

 /* text over */
    if (notep -> n_tover)
	puttext (notep -> n_tover,
		0,
		staffv[stave][staff].sf_maxy - max_t_over,
		1, 0, bar, beat	/* over, rjust, bar, beat */
	    );

 /* text under */
    if (notep -> n_tunder)
	puttext (notep -> n_tunder,
		0,
		staffv[stave][staff].sf_miny + max_t_under + 2,
		0, 0, bar, beat
	    );

 /* text at */
    if (notep -> n_tnote) {
	switch (*(notep -> n_tnote)) {
	    case '<': 		/* text to left */
		puttext (notep -> n_tnote + 1,
			-hgap / 2,/* x-coord */
			notep -> n_y_wrt_staff - 1 - textheight ("a") / 2,
				/* y-coord */
			1, 1, bar, beat
		    );
		break;
	    case '>': 		/* text to right */
		puttext (notep -> n_tnote + 1,
			atom[SOLID].a_width + hgap + 2,/* x-coord */
			notep -> n_y_wrt_staff - 1 - textheight ("a") / 2,
			1, 0, bar, beat
		    );
		break;
	    case ESCAPE: 	/* various specials over or under */
		x = notep -> n_x_wrt_bar + notep -> n_head_x;
		y = notep -> n_y_wrt_staff;
		switch (*(notep -> n_tnote + 1)) {
		    case '.':
			y = (y % 6 ?
				 /* odd */ (notep -> stickup < 0 ? y + 6 : y - 6) :
				 /* even */ (notep -> stickup < 0 ? y + 6 : y - 6)
			    );
			barmove (x, y);
			putatom (DOT);
			break;
		    case '-': 
			y = (y % 6 ?
				 /* odd */ (notep -> stickup < 0 ? y + 6 : y - 6) :
				 /* even */ (notep -> stickup < 0 ? y + 9 : y - 9)
			    );
			barline (x, y, x + 6, y);
			break;
		    case '<': 
			l = 6;	/* length default */
			y = (y % 6 ?
				 /* odd */ (notep -> stickup < 0 ? y + 6 : y - 6) :
				 /* even */ (notep -> stickup < 0 ? y + 9 : y - 9)
			    );
			barline (x, y, x + l, y + 3);
			barline (x, y, x + l, y - 3);
			break;
		    case '>':
			l = 6;	/* length default */
			y = (y % 6 ?
				 /* odd */ (notep -> stickup < 0 ? y + 6 : y - 6) :
				 /* even */ (notep -> stickup < 0 ? y + 9 : y - 9)
			    );
			barline (x, y + 3, x + l, y);
			barline (x, y - 3, x + l, y);
			break;
		    default: 
			fprintf (stderr, "%s ?\n", notep -> n_tnote);
		}
		break;
	    default: 
		puttext (notep -> n_tnote,
			1,
			notep -> n_y_wrt_staff + (notep -> stickup < 0 ? 3 : -1),
			notep -> stickup < 0, 0, bar, beat
		    );
	}
    }

    barpos (notep -> n_x_wrt_bar, notep -> n_y_wrt_staff);
    if (notep -> n_pitch == IRESTSYM) {
	return;
    }

    if (notep -> n_pitch == RESTSYM) {
	putrest (notep -> n_length);
	return;
    }

 /* put n_accid */
    if (notep -> n_accid != ' ') {
	putatom (
		notep -> n_accid == '+' ? SHARP :
		notep -> n_accid == '-' ? FLAT :
		NATURAL
	    );
    }

    barpos (notep -> n_x_wrt_bar + notep -> n_head_x, notep -> n_y_wrt_staff);

    ssx = x_now;
    ssy = y_now;

 /* put ledger lines above */
    if (notep -> n_y_wrt_staff > HALFSTAVE + HALFLINE) {
	for (i = (notep -> n_y_wrt_staff / FULLLINE) * FULLLINE;
		i > HALFSTAVE + HALFLINE;
		i -= FULLLINE)
	    putledgerline (bar, beat, i );
    }
/* then below */
    if (notep -> n_y_wrt_staff < -(HALFSTAVE + HALFLINE)) {
	for (i = ((-notep -> n_y_wrt_staff) / FULLLINE) * FULLLINE;
		i > HALFSTAVE + HALFLINE;
		i -= FULLLINE)
	    putledgerline ( bar, beat, -i );
    }
    abspos (ssx, ssy);

 /* put blob */
    putatom (notep -> n_length >= 256 ? BREVE :
	    notep -> n_length >= 128 ? SEMIBREVE :
	    notep -> n_length >= 64 ? HOLLOW : SOLID);

 /* put any dots */
    for (i = 0; i < notep -> n_dots; i++) {
	absmove (x_now, y_now);
	if (notep -> n_y_wrt_staff % FULLLINE)
	    putatom (DOT);	/* dot in the gap */
	else
	    putatom (UPDOT);	/* dot just above the line */
    }

 /* put stick, ssx=stick-start-x */
    if (notep -> stickup > 0) {	/* stick up from RH of blob */
	ssx += atom[
		notep -> n_length >= 256 ? BREVE :
		notep -> n_length >= 64 ? HOLLOW :
		SOLID
	    ].a_width;
    }
    if (notep -> stickup > 0)	/* up */
	staveline (ssx, notep -> n_y_end_stick,
		ssx, notep -> n_y_wrt_staff + 1);
    else
	if (notep -> stickup < 0)/* down */
	    staveline (ssx, notep -> n_y_end_stick,
		    ssx, notep -> n_y_wrt_staff - 1);
    stavepos (ssx, notep -> n_y_end_stick);

 /* last note of a beam */
    if (notep -> n_beam < 0) {
	if (notep -> n_hooks > max_hooks)
	    max_hooks = notep -> n_hooks;
	else
	    if (notep -> n_hooks < min_hooks)
		min_hooks = notep -> n_hooks;
	if (min_hooks == 0)
	    fprintf (stderr,
		    "Can't beam zero hooks, stave %d bar %d\n",
		    stave, bar);
    /* print complete beams */
	x0 = notev[beat - in_beam].n_x_wrt_bar
	    + notev[beat - in_beam].n_x_stick;
	x1 = notep -> n_x_wrt_bar
	    + notep -> n_x_stick;
	y0 = notev[beat - in_beam].n_y_end_stick;
	y1 = notep -> n_y_end_stick;
	m = (y1 - y0) / (x1 - x0);
	for (j = 0; j < min_hooks; j++) {
	    if (put_monitor == 4)
		fprintf (stderr,
			"Full beam from %d to %d deep %d\n",
			beat - in_beam, beat, j);
	    voffset = notep -> stickup < 0 ? BEAMSPAN * j : -BEAMSPAN * j;
	    paragram (x0, y0 + voffset, x1, y1 + voffset,
		    notep -> stickup < 0 ? BEAMTHICK : -BEAMTHICK);
	}

    /* print any part beams */
	for (i = beat - in_beam, notep = notev + i; i < beat; i++, notep++) {
	    for (j = min_hooks; j < max_hooks; j++) {
		if (notep -> n_hooks > j && notev[i + 1].n_hooks > j) {
		    if (put_monitor == 4)
			fprintf (stderr,
				"Part beam from %d to %d deep %d\n",
				i, i + 1, j,
				notep -> n_hooks, notev[i + 1].n_hooks);
		    x1 = notep -> n_x_wrt_bar
			+ notep -> n_x_stick;
		    x2 = notev[i + 1].n_x_wrt_bar
			+ notev[i + 1].n_x_stick;
		    y1 = y0 + m * (x1 - x0);
		    y2 = y0 + m * (x2 - x0);
		    voffset = notep -> stickup < 0 ? BEAMSPAN * j : -BEAMSPAN * j;
		    paragram (x1, y1 + voffset, x2, y2 + voffset,
			    notep -> stickup < 0 ? BEAMTHICK : -BEAMTHICK);
		}
	    }
	}

    /* print any individual extra hooks */
	for (i = beat - in_beam, notep = notev + i; i <= beat; i++, notep++) {
	/* set j to level of first hook required */
	    if (i == beat - in_beam) {/* first note, hooks right */
		j = notev[i + 1].n_hooks;
		k = 1;
	    }
	    else
		if (i == beat) {/* last note, hooks left */
		    j = notev[i - 1].n_hooks;
		    k = 0;
		}
		else {		/* interior note ??? */
		    j = notev[i - 1].n_hooks;
		    k = 0;
		    if (j < notev[i + 1].n_hooks) {
			j = notev[i + 1].n_hooks;
			k = 1;
		    }
		    k = (i - beat + in_beam + 1) % 2;
		}
	    for (; j < notep -> n_hooks; j++) {
		voffset = notep -> stickup < 0 ? BEAMSPAN * j : -BEAMSPAN * j;
		if (put_monitor == 4)
		    fprintf (stderr,
			    "Hook note %d level %d %s\n",
			    i, j, k ? "right" : "left");
		if (k) {	/* to right */
		    x1 = notep -> n_x_wrt_bar + notep -> n_x_stick;
		    x2 = x1 + 5;
		    y1 = y0 + m * (x1 - x0);
		    y2 = y0 + m * (x2 - x0);
		}
		else {		/* to left */
		    x1 = notep -> n_x_wrt_bar + notep -> n_x_stick;
		    x2 = x1 - 5;
		    y1 = y0 + m * (x1 - x0);
		    y2 = y0 + m * (x2 - x0);
		}		/* end right or left */
		paragram (x1, y1 + voffset, x2, y2 + voffset,
			notep -> stickup < 0 ? BEAMTHICK : -BEAMTHICK);
	    }			/* for all hooks */
	}			/* for notes in beam */
	in_beam = 0;
    /* first note of beam or in a beam */
    }
    else
	if (notep -> n_beam > 0 || in_beam) {/* in a beam */
	    if (notep -> n_beam > 0 || in_beam == 0)/* first note */
		max_hooks = min_hooks = notep -> n_hooks;
	    else
		if (notep -> n_hooks > max_hooks)
		    max_hooks = notep -> n_hooks;
		else
		    if (notep -> n_hooks < min_hooks)
			min_hooks = notep -> n_hooks;
	    in_beam++;
	}
	else {
	/* put hooks if not in beam */
	    if (notep -> n_hooks > 0) {
		ssx = x_now;
		ssy = y_now;
		for (i = 0; i < notep -> n_hooks; i++) {
		    if (notep -> stickup > 0) {
			abspos (ssx, ssy - HOOKSPAN * i);
			putatom (TOPHOOK);
		    }
		    else {
			abspos (ssx, ssy + HOOKSPAN * i);
			putatom (BOTHOOK);
		    }		/* end if stick-up */
		}		/* for each hook */
	    }			/* end if some hooks */
	}
    stavepos (x_now, 0);
}

putpiece () {
    totalheight +=		/* height of this picture */
	(stavev[0].s_y_wrt_page + staffv[0][0].s_y_wrt_stave
	    + staffv[0][0].sf_maxy - staffv[n_staves - 1][n_staffs - 1].sf_miny)
	* 1.0 / reduction;
    if (piecev.left_title || piecev.right_title)
	totalheight +=		/* height of left_title */
	    14 * 1.0 / reduction;
    if (put_monitor == 1) {
	fprintf (stderr, "Start %d(%2d%%)sts, %2d(%2d%%)brs, %3d(%2d%%)nts;",
		n_staves, n_staves * 100 / NSTAVES,
		stavev[n_staves - 1].s_last_bar,
		stavev[n_staves - 1].s_last_bar * 100 / NBARS,
		barv[stavev[n_staves - 1].s_last_bar - 1].b_last_note,
		barv[stavev[n_staves - 1].s_last_bar - 1].b_last_note * 100 / NNOTES);
	fprintf (stderr, "bps %d; text %3d(%2d%%)\n",
		bps_now, textp - textv, (textp - textv) * 100 / MAXTEXT);
	fprintf (stderr, "Area %3.1fi wide x %3.1fi deep, %3.1fi deep so far",
		page_width * 1.0 / reduction,
		(stavev[0].s_y_wrt_page + staffv[0][0].s_y_wrt_stave
		    + staffv[0][0].sf_maxy - staffv[n_staves - 1][n_staffs - 1].sf_miny
		    + (piecev.left_title ? 14 : 0))
		* 1.0 / reduction,
		totalheight);
	fprintf (stderr, "\n");
    }
    text_size = textheight( "a" );
    tsig_n_now = piecev.p_tsig_n;
    tsig_d_now = piecev.p_tsigd;
    key_now = piecev.p_root;
    prev_key = piecev.p_root - 8;
    staff = 0;
    for (stave = 0, stavep = stavev; stave < n_staves; stave++, stavep++) {
	if (stave)
	    printf (".sp %5.2fi\n",
		    i_stave_gap * 1.0 / reduction - 0.24);
	puthead (stave == 0);
	putstave ();
	printf ("\n.PE\n.tm Pic end stave %d depth \\n(nl\n", stave );
    }
    totalheight += 6.0 / reduction;/* gap between .PE and .PS */
    if (put_monitor == 1) {
	if (piecev.left_title && *piecev.left_title)
	    fprintf (stderr, "Finished %s\n", piecev.left_title);
	else
	    if (piecev.right_title && *piecev.right_title)
		fprintf (stderr, "Finished %s\n", piecev.right_title);
	    else
		if (notev[0].n_tover)
		    fprintf (stderr, "Finished %s\n", notev[0].n_tover);
    }
}

putclef (c) {
    int     x = x_now;
    stavepos (x_now, 0);
    if (put_monitor == 2)
	fprintf (stderr, "Clef %d at x=%d\n", c, x_now);
    putatom (clef[c].atomno);
    stavepos (x + atom[clef[c].atomno].a_width, 0);
}

putsharp (i) {
    int     a_v_centre = clef[staffv[0][staff].s_clef].offset % 7;
    stavepos (x_now, (i - a_v_centre) * FULLLINE / 2);
    putatom (SHARP);
}

putflat (i) {
    int     a_v_centre = clef[staffv[0][staff].s_clef].offset % 7;
    stavepos (x_now, (i - a_v_centre) * FULLLINE / 2);
    putatom (FLAT);
}

putnat (i) {
    int     a_v_centre = clef[staffv[0][staff].s_clef].offset % 7;
    stavepos (x_now, (i - a_v_centre) * FULLLINE / 2);
    putatom (NATURAL);
}

putkey (n) {
    int     i;
    if (put_monitor == 2)
	fprintf (stderr, "Keysig %d at x=%d, last key was %d\n",
		n, x_now, prev_key);
    if (n > 6)
	n -= 12;
    if (nat_mode == 2 && prev_key > 0 && n >= 0 && n < prev_key) {
	for (i = n; i < prev_key; i++)
	    putnat (scale[7 + i][0] - 'a');
    }
    if (prev_key < 0 && n <= 0 && n > prev_key) {
	for (i = n; i < prev_key; i++)
	    putnat (scale[7 + i][0] - 'a');
    }
    for (i = 0; i < n; i++)
	putsharp (scale[7 + i][0] - 'a');
    for (i = 0; i > n; i--)
	putflat (scale[6 + i][0] - 'a');
    prev_key = n;
}

puttime (num, denom) {
    printf ("\"\\fB\\s%d%d\\s0\\fP\" at %d.5,%d ljust\n",
	    14 * height / HEIGHT, num,
	    x_now,
	    stavev[stave].s_y_wrt_page + staffv[0][staff].s_y_wrt_stave + 2);
    printf ("\"\\fB\\s%d%d\\s0\\fP\" at %d.5,%d ljust\n",
	    14 * height / HEIGHT, denom,
	    x_now,
	    stavev[stave].s_y_wrt_page + staffv[0][staff].s_y_wrt_stave - 10);
    if (put_monitor == 2)
	fprintf (stderr, "Tsig %d %d at x=%d\n",
		num, denom, x_now);
}

putbarline (f) {		/* put barline for current set of staffs 
				*/
 /* full line at lh margin if "f", otherwise as defined by "s_join_down" 
 */
 /* bar taken from global */
    int     st,
            line,
            type = 0;
    int     s_x_left = x_now;
    int     i,
            m;
    float   x,
            y,
            ymax,
            ymin;
    i = f
	? (n_staffs > 1 ? BLLEFT : BLPLAIN)
	: barv[bar].b_end_type;
    if (i == 32 || i == 0) {
	fprintf (stderr, "Resetting bar type from %d\n", i);
	i = 1;
    }
    printf ("# end bar %d\n", bar);

    type = i;
    s_x_left = x_now - barlv[type].offset;

    if (type >= NBL) {
	fprintf (stderr, "Invalid bar no %d bar.b_end_type %d type %d\n",
		bar, i, type);
	abandon (1);
    }
    for (line = 0; line < 3; line++) {
	x = s_x_left + barlv[type].fromwid[2 * line];
	m = barlv[type].fromwid[2 * line + 1];
	m = 2 * m - 1;
	for (i = 0; i < m; i++) {
	    for (st = 0; st < n_staffs; st++) {
		y = stavev[stave].s_y_wrt_page + staffv[stave][st].s_y_wrt_stave;
		ymax = y + HALFSTAVE;
		if (st < n_staffs - 1
			&& ((line == 2 && f) || staffv[0][st].s_join_down)
		    ) {
		    ymin = stavev[stave].s_y_wrt_page + staffv[stave][st + 1].s_y_wrt_stave
			+ HALFSTAVE;
		}
		else {
		    ymin = y - HALFSTAVE;
		}
		if (barlv[type].letter == 'H') {/* hatched line */
		    fabsline (x, ymax, x, ymax - 1.5);
		    for (y = ymax - 4.5; y > ymin + 3; y -= 6)
			fabsline (x, y, x, y - 3);
		    if (y > ymin)
			fabsline (x, y, x, ymin);
		}
		else
		    fabsline (x, ymax, x, ymin);
	    }			/* for each staff */
	    x += 0.5;
	}			/* for width of line */
    }				/* for each of lines */
}

putbarstart (type) {		/* put barline on current set of staffs */
    int     st,
            line;
    int     s_x_left = x_now;
    int     i,
            m;
    float   x,
            y,
            ymax,
            ymin;

    for (line = 0; line < 3; line++) {
	x = s_x_left + hgap + barlv[type].fromwid[2 * line];
	m = barlv[type].fromwid[2 * line + 1];
	m = 2 * m - 1;
	for (i = 0; i < m; i++) {
	    for (st = 0; st < n_staffs; st++) {
		y = stavev[stave].s_y_wrt_page + staffv[stave][st].s_y_wrt_stave;
		ymax = y + HALFSTAVE;
		ymin = y - HALFSTAVE;
		if (barlv[type].letter == 'H') {/* hatched line */
		    fabsline (x, ymax, x, ymax - 1.5);
		    for (y = ymax - 4.5; y > ymin + 3; y -= 6)
			fabsline (x, y, x, y - 3);
		    if (y > ymin)
			fabsline (x, y, x, ymin);
		}
		else
		    fabsline (x, ymax, x, ymin);
	    }			/* for each staff */
	    x += 0.5;
	}			/* for width of line */
    }				/* for each of lines */
    x_now = s_x_left;
}

putstave () {			/* print stave, number in global "stave" 
				*/
    if (put_monitor == 1)
	stavepr (stave);
    for (staff = 0; staff < n_staffs; staff++) {
	putstaff ();
	puttie (stave, staff);
    }
    putstbars ();
}

putstaff () {
    int     i,
            note;
    struct notes   *notep;
    if (put_monitor == 1)
	staffpr (stave, staff);
 /* five lines for staff */
    for (i = -2; i <= 2; i++)
	staveline (bar0start, i * FULLLINE,
		stavev[stave].s_x_right, i * FULLLINE);

    if (n_staffs > 1 && staffv[0][staff].s_instrument) {
	puttext (staffv[0][staff].s_instrument,
		2, -5,
		1, 0, -1, -1);
    }

    if (stavev[stave].s_first_bar == 1 && barv[0].b_last_note > barv[0].b_first_note)
	stavev[stave].s_first_bar = 0;

 /* find max text heights */
    max_t_over = max_t_under = 0;
    for (note = barv[stavev[stave].s_first_bar].b_first_note,
	    notep = notev + note;
	    note < barv[stavev[stave].s_last_bar - 1].b_last_note;
	    note++, notep++) {
	if (notep -> n_staff == staff
		&& notep -> n_tover
		&& max_t_over < textheight (notep -> n_tover))
	    max_t_over = textheight (notep -> n_tover);
	if (notep -> n_staff == staff
		&& notep -> n_tunder
		&& max_t_under < textheight (notep -> n_tunder))
	    max_t_under = textheight (notep -> n_tunder);
    }
    for (bar = stavev[stave].s_first_bar; bar < stavev[stave].s_last_bar; bar++) {
	putbar (staff);
    }
}

putbar (staff) {	 /* print bar, bar number in global "bar",
				   staff staff only */
 /* some things were only in the first bar */
    struct bars *barp = barv + bar;
    int     offset = hgap;
    if (put_monitor == 2)
	barprint (bar);

 /* put bar text */
    if (barp -> b_tover[staff]) {
	puttext (barp -> b_tover[staff],
		barp -> b_width, HALFSTAVE + HALFLINE,
		1, 0, bar, -1
	    );
    }
    if (barp -> b_tunder[staff]) {
	puttext (barp -> b_tunder[staff],
		barp -> b_width, -HALFSTAVE - HALFLINE,
		0, 0, bar, -1
	    );
    }

 /* put clefs etc as required */
    if (barp -> b_clef[staff]) {
	barpos (offset, 0);
	clefs_now[staff] = clef_now = barp -> b_clef[staff];
	putclef (clef_now);
	offset += atom[TCLEF].a_width + hgap;
    }
    if (barp -> b_key) {
	barpos (offset, 0);
	key_now = barp -> b_key + staffv[0][staff].s_key_offset;
	putkey (key_now - 8);
	offset += (key_now >= 8
		? atom[SHARP].a_width * (key_now - 8)
		: atom[FLAT].a_width * (8 - key_now))
	    + hgap;
    }
    if (barp -> b_n_tsig) {
	tsig_n_now = barp -> b_n_tsig;
	tsig_d_now = barp -> b_d_tsig;
	barpos (offset, 0);
	puttime (tsig_n_now, tsig_d_now);
	offset += atom[TSIG].a_width + hgap;
    }
    if (barp -> b_stt_type) {
	barmove (offset, 0);
	putbarstart (barp -> b_stt_type);
	putatom (barlv[barp -> b_stt_type].atomno);
    }

 /* print the notes */
    if (barp -> b_last_note > barp -> b_first_note && (bar || stave == 0)) {
	for (ALLBTS)
	    if (notev[beat].n_staff == staff)
		putnote (beat);
    }

 /* barline to terminate */
    barmove (
	barp -> b_width - atom[barlv[barp -> b_end_type].atomno].a_width,
	0 );

    if (bar >= piecev.p_bars && barp -> b_end_type == 0) {
	putatom (BLTHICKL);
    } else {
	putatom (barlv[barp -> b_end_type].atomno);
    }

    printf ("# end bar %d staff %d\n", bar, staff);
}

putstbars () {			/* put barlines for this stave */
    bar = 0;
    x_now = bar0start;
    putbarline (1);
    for (bar = stave == 0 && barv[0].b_last_note > barv[0].b_first_note
	    ? 0
	    : stavev[stave].s_first_bar;
	    bar < stavev[stave].s_last_bar;
	    bar++) {
	x_now = barv[bar].b_x_wrt_staff + barv[bar].b_width;
	putbarline (0);
    }
}

puthead (t) {			/* put left_title if t */
    FILE * f = fopen ("pic_default", "r");
    char    ch;
    printf (".PS\n");

    if (f == NULL)
	f = fopen ("/usr/local/lib/music/pic_default", "r");	/* LIBDIR */

    if (f == NULL) {
	fprintf (stderr, "No \"pic_default\" file\n");
    }
    else {
	while (fscanf (f, "%c", &ch) == 1)
	    putchar (ch);
	fclose (f);
    }
    printf ("scale = %d; right\n", reduction);
    if (put_monitor > 0) fprintf ( stderr, "x0 %d y1 %d x1 %d y0 %d\n",
	page_width,
	stavev[stave].s_y_wrt_page + staffv[stave][n_staffs-1].s_y_wrt_stave
	+ staffv[stave][n_staffs - 1].sf_miny,
	0,
	stavev[stave].s_y_wrt_page + staffv[stave][0].s_y_wrt_stave
	+ staffv[stave][0].sf_maxy
    );
    if (t && piecev.left_title && *piecev.left_title) {
	puttext (piecev.left_title, 2,
		staffv[0][0].sf_maxy,
		1, 0, -1, -1);
    }
    if (t && piecev.centre_title && *piecev.centre_title) {
	puttext (piecev.centre_title,
		page_width / 2,
		staffv[0][0].sf_maxy,
		1, 2, -1, -1);
    }
    if (t && piecev.right_title && *piecev.right_title) {
	puttext (piecev.right_title,
		page_width,
		staffv[0][0].sf_maxy,
		1, 1, -1, -1);
    }
}

absmove (x, y) {
    printf ("move to %d,%d;", x, y);
    x_now = x;
    y_now = y;
}

abspos (x, y) {
    x_now = x;
    y_now = y;
}

stavemove (x, y) {
    absmove (x,
	y + stavev[stave].s_y_wrt_page + staffv[stave][staff].s_y_wrt_stave);
}

stavepos (x, y) {
    abspos (x,
	y + stavev[stave].s_y_wrt_page + staffv[stave][staff].s_y_wrt_stave);
}

barmove (x, y) {
    stavemove (x + barv[bar].b_x_wrt_staff, y);
}

barpos( x, y )
{
    stavepos( x+barv[bar].b_x_wrt_staff, y );
}

absline (x0, y0, x1, y1) {
    printf ("line from %3d,%3d to %3d,%3d; ",
	    x0, y0, x1, y1);
    x_now = x1;
    y_now = y1;
}

staveline (x0, y0, x1, y1) {
    y0 += stavev[stave].s_y_wrt_page + staffv[stave][staff].s_y_wrt_stave;
    y1 += stavev[stave].s_y_wrt_page + staffv[stave][staff].s_y_wrt_stave;
    absline (x0, y0, x1, y1);
}

barline (x0, y0, x1, y1) {
    x0 += barv[bar].b_x_wrt_staff;
    x1 += barv[bar].b_x_wrt_staff;
    staveline (x0, y0, x1, y1);
}

fabsline (x0, y0, x1, y1) float x0,
                                y0,
                                x1,
                                y1;
{
    printf ("line from %4.1f,%4.1f to %4.1f,%4.1f\n",
	    x0, y0, x1, y1);
    x_now = x1;
    y_now = y1;
}

fbarline (x0, y0, x1, y1) float x0,
                                y0,
                                x1,
                                y1;
{
    x0 += barv[bar].b_x_wrt_staff;
    x1 += barv[bar].b_x_wrt_staff;
    y0 += stavev[stave].s_y_wrt_page + staffv[stave][staff].s_y_wrt_stave;
    y1 += stavev[stave].s_y_wrt_page + staffv[stave][staff].s_y_wrt_stave;
    printf ("line from %4.1f,%4.1f to %4.1f,%4.1f\n",
	    x0, y0, x1, y1);
    x_now = x1;
    y_now = y1;
}

putatom (i) {
    int y = y_now;
    if (atom_monitor == i || put_monitor == 4)
	fprintf (stderr,
		"atom type %2d, x=%3d, y=%3d\n",
		i, x_now, y_now);

    if (testing) {
	staveline (x_now, -12, x_now, 12);
	absmove (x_now, y );
    }

    if (atom[i].a_v_centre >= 2) {
	stavepos (x_now, 0);
    } else if (atom[i].a_v_centre) {
	stavemove (x_now, 0);
    }

    if (atom[i].proc) {
	(*atom[i].proc) ();
	return;
    }

    if (atom[i].name) {
	printf (atom[i].name,
		argval (atom[i].arg1, atom[i].arg2),
		argval (atom[i].arg3, atom[i].arg4),
		argval (atom[i].arg5, atom[i].arg6),
		argval (atom[i].arg7, atom[i].arg8)
	    );
	printf ("\n");
    }
    x_now += atom[i].a_width;
    return;
}

putledgerline (bar, beat, y) { /* y = y wrt staff */
    int x0 = notev[beat].n_x_wrt_bar;	/* delimiters of */
    int x1 = x0 + notev[beat].n_width;  /* note itself */
    int xl;
    int xr;
    int part = notev[beat].n_part;
    int prevnote = beat-1, nextnote = beat+1;
    while ( prevnote >= barv[bar].b_first_note
	&& notev[prevnote].n_part != part )
	prevnote--;
    xl = prevnote < barv[bar].b_first_note
	    ? 0
	    : notev[prevnote].n_x_wrt_bar + notev[prevnote].n_width;
    while ( nextnote < barv[bar].b_last_note
	&& notev[nextnote].n_part != part )
	nextnote++;
    xr = nextnote >= barv[bar].b_last_note /* next object to right */
	    ? barv[bar].b_width
	    : notev[nextnote].n_x_wrt_bar;
    xl = (xl + x0 + 1) / 2;
    if ( xl < x0-3 ) xl = x0 - 3;
    xr = ( x1 + xr ) / 2;
    if ( xr > x1 + 3 ) xr = x1 + 3;
    barline( xl, y, xr, y );
    printf (" # ledger line\n" );
}

paragram (x0, y0, x1, y1, dy) float x0,
                                    y0,
                                    x1,
                                    y1;
int     dy;
/* fill in ||gram corners (x0,y0), (x0,y0+dy), (x1,y1), (x1, y1+dy) */
{
    int     y;
    float   delta = 0.7 * FULLSTAVE / height;
    if (dy > 0) {
	for (y = 0; y * delta < dy; y++)
	    fbarline (x0, y0 + y * delta, x1, y1 + y * delta);
    }
    else {
	for (y = 0; y * delta > dy; y--)
	    fbarline (x0, y0 + y * delta, x1, y1 + y * delta);
    }
    fbarline (x0, y0, x0, y0 + dy);
    fbarline (x0, y0 + dy, x1, y1 + dy);
    fbarline (x1, y1 + dy, x1, y1);
}

argval (x, v) {
    if (x == X) return x_now + v;
    if (x == U) return x_now + v;
    if (x == Y) return y_now + v + 1 - height / 16;
    if (x == V) return y_now + v;
    if (x == S) return (int) (0.5 + scale_ht * v);
    if (x == 0) return v;
    ioerror ("Error in argval\n", 0, 0);
    return 0;
}

putstring (s, over) char   *s;
/* put a string, later replace "\+" by sharp etc */
/* drop text following slash for bass note with chord */
{
    char   *p = s - 1;
    char    down = 0;
    while (*++p)
	if (*p == '/' && chordtransp && !over) {
	    printf ("/\\d");
	    down = 1;
	}
	else
	    if (*p == ' ' && down) {
		printf ("\\u ");
		down = 0;
	    }
	    else
		if (*p == '\\') {
		    switch (*++p) {
			case '+': /* sharp */
			    printf ("%s", text_sharp);
			    break;
			case '-': /* flat */
			    printf ("%s", text_flat);
			    break;
			case '=': /* natural */
			    printf ("%s", text_natural);
			    break;
			default: 
			    putchar ('\\');
			    putchar (*p);
		    }
		}
		else
		    putchar (*p);
    if (down)
	printf ("\\u");
}

puttext (s, x, y, over, rjust, bar, beat) char *s;
/* put text "s" at [x,y] over bar 'bar' nor note 'beat' */
/* rjust = 1 for right just, 0 for left, 2 for centre, sorry */
/* bar<0 implies left_title, beat<0 implies bar text */
{
    int     yoff = stavev[stave].s_y_wrt_page + staffv[stave][staff].s_y_wrt_stave;
    int     nl = 1,
            width = 0,
            n,
	    b,
	    note, nn,
	    l;
    float   f;
    char   *p = s,
            c;
    while (*p) {		/* count how many lines */
	if (*p == '\n') {
	    nl++;
	    *p = 0;
	}
	p++;
    }
    if (bar >= 0)
	x += barv[bar].b_x_wrt_staff;
    if (beat >= 0)
	x += notev[beat].n_x_wrt_bar + notev[beat].n_head_x;
    if (over)
	yoff += 4;
    else
	yoff -= 8;
    if (*s == ESCAPE) {
	switch (*(s + 1)) {
	    case 'b': 		/* string starts "\b", box it */
		if (over)
		    yoff += 2;
		else
		    yoff -= 4;
		printf ( "move to %d,%d; right; box width %d height %d; ",
		  x - 2, yoff + y + 2,/* x, y */
		  6 + textwidth (s + 2), text_size + 4 ); /* box width, height */
		printf( "\"\\s%d%s\\s0\" at %d,%d center\n",
		  argval (S, 10), s + 2,
		  x + 1 + textwidth( s+2 )/2 , yoff + y
		);
		break;
	    case 'c': 		/* string starts "\c", circle */
		if (over)
		    yoff += 4;
		else
		    yoff -= 4;
		printf (
			"move to %d,%d; right; circle radius %d \"\\s%d%s\\s0\"\n",
			x - 2, yoff + y,/* x, y */
			8,	/* circle radius */
			argval (S, 10), s + 2);
		break;
	    case '@': 		/* print bar number */
		if (over)
		    yoff += 2;
		else
		    yoff -= 4;
		printf (
			"move to %d,%d; right; box width %d height %d \"\\s%d%d\\s0\"\n",
			x - 12, yoff + y,/* x, y */
			25, text_size + 4,/* box width, height */
			argval (S, 10), bar);
		break;
	    case '<': 
	    case '>': 
		l = 6;		/* length default */
		c = 0;
		n = sscanf (s + 2, "%f%c", &f, &c);
		if (n >= 1) {
		    switch (c) {
			case 'n': /* number of notes */
			    n = f;
			    b = bar;
			    note = beat;
			    nn = 0;
			    part = notev[beat].n_part;
			    while ( nn < n ) {
				if ( note >= barv[b].b_last_note ) {
				    l += barv[b].b_width;
				    b++;
				}
				if ( notev[note].n_part == part ) {
				    nn++;
				}
				note++;
			    }
			    l += notev[note-1].n_x_wrt_bar
				+ notev[note-1].n_head_x
				- notev[beat].n_x_wrt_bar
				- notev[beat].n_head_x;
			    break;
			case 'b': /* number of bars */
			    n = f;
			    while ( --n >= 0 ) {
				l += barv[bar+n].b_width;
fprintf( stderr, "b %d l %d\n", bar+n, l );
			    }
			    l -= notev[beat].n_x_wrt_bar
				+ notev[beat].n_head_x
				+ 6;
fprintf( stderr, "l %d\n", l );
			    break;
			case 'i': /* number of inches */
			    l = f * reduction;
			    break;
		    }
		}
		if (over)
		    yoff += 2;
		else
		    yoff += 0;
		if (*(s + 1) == '>') {
		    printf (
			    "line from %d,%d right %d up 3; line from %d,%d right %d down 3\n",
			    x, yoff + y - 3, l,/* x, y */
			    x, yoff + y + 3, l);/* x, y */
		}
		else {
		    printf (
			    "line from %d,%d right %d up 3; line from %d,%d right %d down 3\n",
			    x, yoff + y, l,/* x, y, l */
			    x, yoff + y, l);/* x, y, l */
		}
		break;
	    case 'p': 		/* pic commands */
		printf ("move to %d,%d; right; %s\n",
			x, yoff + y, s + 2);
		break;
	    case '1': 		/* 1. or 2. above */
	    case '2': 		/* 1. or 2. above */
	    case '3': 		/* 1. or 2. above */
		while (width += barv[bar].b_width,
			barv[bar].b_end_type == 1 && !barv[bar].b_new_stave) {
		    bar++;
		}
		width -= notev[beat].n_x_wrt_bar
		    + atom[barlv[barv[bar].b_end_type].atomno].a_width;
	    /* if ( width + x > width_now ) width = width_now - x; */
		printf (
			"\"\\s%d%s\\s0\" at %d,%d ljust; line from %d,%d up %d then right %d\n",
			argval (S, 10), s + 1,
			x + 2, yoff + y,/* text at */
			x - 2, yoff + y - 4,/* line from */
			text_size + 2,/* then up */
			width + 4);/* then right */
		break;
	    default: 		/* anything else */
		put_multi_text (s, x, y + yoff, over, rjust, nl);
	}
    }
    else {			/* if not starting backslash */
	put_multi_text (s, x, y + yoff, over, rjust, nl);
    }
}

put_multi_text (s, x, y, over, rjust, nl) char *s;
 /* put nl strings starting at *s */
{
    char   *just = rjust == 1 ? "rjust" : rjust == 2 ? "center" : "ljust";
    x -= 2;
    y += text_size * nl;
    if (!over)
	y -= (nl - 1) * text_size;
    while (--nl >= 0) {
	y -= text_size;
	printf ("\"\\s%d",
		argval (S, 10));
	putstring (s, over);
	printf ("\\s0\" at %d,%d %s\n",
		x, y,
		just
	    );
	while (*s++);
    }
}

putrest (l) {
    if ( l < 64 )
	stavepos (x_now, 0);
    else
	stavemove (x_now, 0);

    putatom (
	    l == piecev.p_bar_length ? BREREST :
	    l >= SBL ? SBRREST :
	    l >= 64 ? MINREST :
	    l >= 32 ? CROREST :
	    l >= 16 ? QUAREST :
	    l >= 8 ? SQUREST :
	    DSQREST
	);

    return;
}
