chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / prnttab.c
CommitLineData
fac14bbe
MW
1/* Copyright (c) 1997, 1998, 1999, 2001, 2003, 2004 by Arkkra Enterprises */
2/* All rights reserved. */
3
4/* functions to support printing of tab staffs */
5
6#include "defines.h"
7#include "structs.h"
8#include "globals.h"
9
10/* position of the last bend arrow for each staff, or 0.0 if no
11 * arrow on previous group */
12static double Last_x_arrow[MAXSTAFFS + 1], Last_y_arrow[MAXSTAFFS + 1];
13
14static double pr_tab_note P((int note_index, struct GRPSYL *gs_p,
15 double y_adjust, struct MAINLL *mll_p));
16static double pr_bstring P((struct GRPSYL *gs_p, struct NOTE *note_p,
17 int note_index, double y_adjust, struct MAINLL *mll_p));
18static void pr_b_arrow P((struct GRPSYL *gs_p, struct MAINLL *mll_p,
19 double y_adjust));
20static void pr_b_curve P((float *xlist, float *ylist, struct GRPSYL *gs_p,
21 double y_adjust));
22static void pr_arrowhead P((struct GRPSYL *gs_p, double y_adjust, int headchar));
23static int bends_up P((struct GRPSYL *gs_p, int n, struct GRPSYL *pgs_p,
24 int carried_in));
25static int is_carried_in_bend P((struct MAINLL *mll_p,
26 struct MAINLL *prev_mll_p));
27\f
28
29
30/* given a GRPSYL list for a tab staff, print all the notes in the list */
31
32void
33pr_tab_groups(gs_p, mll_p)
34
35struct GRPSYL *gs_p;
36struct MAINLL *mll_p;
37
38{
39 int n;
40 double y_adjust; /* to account for bend string space */
41 struct GRPSYL *ngs_p; /* next group */
42 struct MAINLL *m_p;
43
44
45 /* go through the list of groups */
46 for ( ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) {
47
48 /* if inhibitprint flag is set (because this is a tied-to
49 * group), skip this group */
50 if (gs_p->inhibitprint == YES) {
51 continue;
52 }
53
54 /* measure repeats are special */
55 if (is_mrpt(gs_p) == YES) {
56 pr_mrpt(gs_p, mll_p->u.staff_p);
57 continue;
58 }
59
60 /* multirests are special. Print on tab staff only if its
61 * corresponding tabnote staff is not printed */
62 if (gs_p->basictime < -1) {
63 if (svpath(gs_p->staffno - 1, VISIBLE)->visible == NO) {
64 pr_multirest(gs_p, mll_p->u.staff_p);
65 }
66 continue;
67 }
68
69 /* print the fret number and bend string
70 * for each note in the group. The
71 * y_adjust gets changed to account for space taken up
72 * by bend text strings */
73 y_adjust = 0.0;
74 for (n = 0; n < gs_p->nnotes; n++) {
75 y_adjust = pr_tab_note(n, gs_p, y_adjust, mll_p);
76 }
77
78 /* if there were any bends, draw the arrow. Otherwise
79 * remember that there are no bends in progress */
80 if (y_adjust > 0.0) {
81 pr_b_arrow(gs_p, mll_p, y_adjust);
82 }
83 else {
84 Last_y_arrow[gs_p->staffno] = 0.0;
85 Last_x_arrow[gs_p->staffno] = 0.0;
86 }
87
88 /* print any slashes */
89 if (gs_p->slash_alt > 0) {
90 /* slashes on tab staff get hard-coded
91 * tilt value of 2.2 * Stdpad. */
92 if (gs_p->stemdir == UP) {
93 pr_slashes(gs_p, (double) gs_p->c[AX],
94 (double) (gs_p->notelist[gs_p->nnotes - 1].c[AY]
95 + gs_p->stemlen), (double) -1.0,
96 (double) 0.0, (double) (2.2 * Stdpad));
97 }
98 else {
99 pr_slashes(gs_p, (double) gs_p->c[AX],
100 (double) (gs_p->notelist[0].c[AY]
101 - gs_p->stemlen), (double) 1.0,
102 (double) 0.0, (double) (2.2 * Stdpad));
103 }
104 }
105
106 if (gets_roll(gs_p, mll_p->u.staff_p, 0) == YES) {
107 print_roll(gs_p);
108 }
109
110 /* print any "with" list items */
111 pr_withlist(gs_p);
112
113 /* on last group in measure, have to look ahead to next group
114 * if any to see if it has a bend from this note and is on
115 * the next score. If so, have to draw a horizontal line for
116 * the bend out to near the end of the current score */
117 if (gs_p->next == (struct GRPSYL *) 0) {
118 /* is the last group in the measure. See if we are
119 * at a scorefeed. First search for end of current
120 * measure. */
121 for (m_p = mll_p; m_p != (struct MAINLL *) 0 &&
122 m_p->str != S_BAR; m_p = m_p->next) {
123 ;
124 }
125
126 /* now go until we find either a feed or a staff */
127 for ( ; m_p != (struct MAINLL *) 0;
128 m_p = m_p->next) {
129 if (m_p->str == S_FEED || m_p->str == S_STAFF) {
130 break;
131 }
132 }
133 if (m_p == (struct MAINLL *) 0 || m_p->str != S_FEED) {
134 /* no next group or not at a scorefeed */
135 continue;
136 }
137
138 /* See if there is another group in the next measure */
139 if ((ngs_p = nextgrpsyl(gs_p, &mll_p))
140 == (struct GRPSYL *) 0) {
141 /* no next group */
142 continue;
143 }
144 if (ngs_p->nnotes == 0) {
145 continue;
146 }
147
148 for (n = 0; n < ngs_p->nnotes; n++) {
149 if (HASREALBEND(ngs_p->notelist[n]) &&
150 ngs_p->notelist[n].FRETNO == NOFRET) {
151 /* next group has a real, non-prebend
152 * bend, so have to deal with it */
153 break;
154 }
155 else if (HASNULLBEND(ngs_p->notelist[n])) {
156 /* has null bend. have to do this one */
157 break;
158 }
159 }
160 if (n == ngs_p->nnotes) {
161 /* no non-prebend bend */
162 continue;
163 }
164
165 /* if we got here, this is the special case where we
166 * do need to draw the line, so do it */
167 do_linetype(L_NORMAL);
168 if (Last_y_arrow[gs_p->staffno] != 0.0) {
169 draw_line( (double) (Last_x_arrow[gs_p->staffno]),
170 (double) (Last_y_arrow[gs_p->staffno]),
171 (double) (PGWIDTH
172 - eff_rightmargin(mll_p) - Stepsize),
173 (double) (Last_y_arrow[gs_p->staffno]));
174 Last_x_arrow[gs_p->staffno] =
175 PGWIDTH - eff_rightmargin(mll_p)
176 - Stepsize;
177 }
178 else {
179 /* the bend is on the next score, but not a
180 * continuation bend. so draw an arrow towards
181 * the margin, followed by a short
182 * dashed line */
183 float xlist[6], ylist[6]; /* curve coords */
184 struct GRPSYL dummy_gs; /* for curve end */
185
186
187 /* set place for beginning of curve */
188 xlist[0] = gs_p->notelist[n].c[AX] + Stdpad +
189 notehorz(gs_p, &(gs_p->notelist[n]), RE);
190 ylist[0] = gs_p->notelist[n].c[AY];
191
192 /* fill in a dummy GRPSYL struct with just
193 * the pieces of information that pr_b_curve
194 * will need to draw a bend curve */
195 dummy_gs.c[AX] = PGWIDTH
196 - eff_rightmargin(mll_p)
197 - 2.5 * Stepsize;
198 dummy_gs.c[AN] = ylist[0] + 2.4 * Stepsize
199 * TABRATIO;
200 /* if we're too close to the margin, make the
201 * curve a little longer, so it will look
202 * decent, even if it runs into the margin
203 * a little ways */
204 if (dummy_gs.c[AX] - xlist[0]
205 < 3.0 * Stepsize) {
206 dummy_gs.c[AX] = 3.0 * Stepsize;
207 /* If that still didn't move it enough
208 * to avoid having the bend backwards,
209 * adjust some more */
210 if (dummy_gs.c[AX] - xlist[0]
211 < 2.0 * Stepsize) {
212 dummy_gs.c[AX] = xlist[0]
213 + 2.0 * Stepsize;
214 }
215 }
216
217 /* draw the curve */
218 pr_b_curve(xlist, ylist, &dummy_gs, 0.0);
219
220 /* draw an arrow at the end of the curve */
221 pr_muschar( (double) dummy_gs.c[AX],
222 (double) (dummy_gs.c[AN] -
223 (height(FONT_MUSIC, DFLT_SIZE, C_UWEDGE)
224 / 2.0)), C_UWEDGE, DFLT_SIZE, FONT_MUSIC);
225
226 /* draw a short dashed line to the right
227 * from the arrow, to indicate the actual
228 * bend is on the next score */
229 do_linetype(L_DASHED);
230 ylist[5] += 2.0 * Stdpad;
231 draw_line( (double) xlist[5] + Stdpad,
232 (double) ylist[5],
233 (double) xlist[5] + 3.5 * Stepsize,
234 (double) ylist[5]);
235 }
236 }
237 }
238}
239\f
240
241/* print things for a tab staff note. Return any adjustment to North needed
242 * to account for bend string */
243
244static double
245pr_tab_note(note_index, gs_p, y_adjust, mll_p)
246
247int note_index; /* which note in gs_p */
248struct GRPSYL *gs_p;
249double y_adjust; /* to account for bend string space */
250struct MAINLL *mll_p; /* main list struct pointing to gs_p */
251
252{
253 struct NOTE *note_p;
254 char *fretstr; /* text string to print for fret number */
255
256 note_p = &(gs_p->notelist[note_index]);
257
258 /* print fret number (with parentheses if appropriate) */
259 fretstr = fret_string(note_p, gs_p);
260 if ( *fretstr != '\0') {
261
262 if (vvpath(gs_p->staffno, gs_p->vno, TABWHITEBOX)->tabwhitebox == YES) {
263 /* Put a white box behind the number, so the line
264 * doesn't go through it, making it easier to read. */
265 do_whitebox( note_p->c[AX] - strwidth(fretstr) / 2.0,
266 note_p->c[AY] - strheight(fretstr) / 2.0,
267 note_p->c[AX] + strwidth(fretstr) / 2.0,
268 note_p->c[AY] + strheight(fretstr) / 2.0);
269 }
270
271 pr_string( (double) (note_p->c[AX] - (strwidth(fretstr) / 2.0)),
272 (double) (note_p->c[AY] + (strheight(fretstr) / 2.0)
273 - strascent(fretstr)),
274 fretstr, J_LEFT, gs_p->inputfile, gs_p->inputlineno);
275 }
276
277 /* print a bend string if appropriate */
278 if ( HASBEND((*note_p)) ) {
279 if (HASREALBEND(*note_p)) {
280 y_adjust += pr_bstring(gs_p, note_p, note_index,
281 y_adjust, mll_p);
282 }
283 else {
284 /* need to return a little bit, so later code
285 * knows that there was a bend of some sort */
286 if (y_adjust == 0.0) {
287 y_adjust = STDPAD;
288 }
289 }
290 }
291 return (y_adjust);
292}
293\f
294
295/* print the bend string ("full", "1/2", etc). Return its height */
296
297static double
298pr_bstring(gs_p, note_p, note_index, y_adjust, mll_p)
299
300struct GRPSYL *gs_p; /* group having a bend */
301struct NOTE *note_p; /* which note in gs_p has the bend */
302int note_index; /* index into gs_p->notelist of note_p */
303double y_adjust; /* to account for bend strings done previously
304 * for this group (on other notes in the group */
305struct MAINLL *mll_p; /* main list struct pointing to gs_p */
306
307{
308 char *bstring;
309 double x_adjust; /* to center upward and left justify
310 * downward, to not collide with curve */
311 struct GRPSYL *pgs_p; /* previous group */
312 int n; /* index through notelist */
313
314
315 /* get what to print for the bend */
316 bstring = bend_string(note_p);
317
318 /* generally, the string should be centered. */
319 x_adjust = strwidth(bstring) / 2.0;
320
321 /* However, if not a prebend and the bend is downward,
322 * then we have to move the bend string over so it
323 * doesn't collide with the curve. So first get the previous group
324 * and see it is has a bend too. If it does, see if the bend is
325 * downward, and if so, change to left justify rather than center */
326 if (note_p->FRETNO == NOFRET && (pgs_p = prevgrpsyl(gs_p, &mll_p))
327 != (struct GRPSYL *) 0) {
328
329 for (n = 0; n < pgs_p->nnotes; n++) {
330 if (pgs_p->notelist[n].STRINGNO
331 == gs_p->notelist[note_index].STRINGNO
332 && HASBEND(pgs_p->notelist[n])) {
333 if (bends_up(gs_p, note_index, pgs_p, NO) == NO) {
334 x_adjust = 0.0;
335 }
336 }
337 }
338 }
339
340 /* print the bend string */
341 pr_string( (double) (gs_p->c[AX] - x_adjust),
342 (double) (gs_p->c[AN] - strascent(bstring) - y_adjust),
343 bstring, J_LEFT, gs_p->inputfile, gs_p->inputlineno);
344
345 /* return the height of what was just printed */
346 return(strheight(bstring));
347}
348\f
349
350/* print bend arrow */
351
352static void
353pr_b_arrow(gs_p, mll_p, y_adjust)
354
355struct GRPSYL *gs_p;
356struct MAINLL *mll_p;
357double y_adjust;
358
359{
360 struct GRPSYL *pgs_p; /* previous grpsyl */
361 struct MAINLL *prev_mll_p; /* where pgs_p is connected */
362 float xlist[6], ylist[6]; /* coords of bend curve */
363 int n; /* note index */
364 int staffno;
365 int carried_in; /* YES if bend is carried in */
366
367
368 staffno = gs_p->staffno;
369
370 /* leave a little room between bend string and the arrow. This is
371 * especially needed when bending down, so the string and curve
372 * don't collide */
373 y_adjust += 2.0 * Stdpad;
374
375 /* find the first note with a bend on it */
376 for (n = 0; n < gs_p->nnotes; n++) {
377 if (HASBEND(gs_p->notelist[n])) {
378 break;
379 }
380 }
381
382 /* the function isn't supposed to get called unless there really
383 * is a bend somewhere on the group */
384 if (n == gs_p->nnotes) {
385 pfatal("pr_b_arrow couldn't find note with bend");
386 }
387
388 /* check if prebend or non-prebend */
389 if (gs_p->notelist[n].FRETNO != NOFRET
390 && ! HASNULLBEND(gs_p->notelist[n])) {
391 /* this is a prebend */
392 /* draw the line straight up from the fret number */
393 do_linetype(L_NORMAL);
394 draw_line( (double) (gs_p->c[AX]),
395 (double) (gs_p->notelist[n].c[AN] + Stdpad),
396 (double) (gs_p->c[AX]),
397 (double) (gs_p->c[AN] - y_adjust));
398
399 /* draw triangle at top */
400 pr_arrowhead(gs_p, y_adjust, C_UWEDGE);
401 return;
402 }
403
404 /* a normal bend, not a prebend */
405 prev_mll_p = mll_p;
406 if ((pgs_p = prevgrpsyl(gs_p, &prev_mll_p)) == (struct GRPSYL *) 0) {
407 l_ufatal(gs_p->inputfile, gs_p->inputlineno,
408 "no previous chord for bend");
409 }
410
411 carried_in = is_carried_in_bend(mll_p, prev_mll_p);
412
413 if (Last_y_arrow[staffno] == 0.0) {
414 /* not the continuation of an in-progress bend */
415
416 /* do each note that has a bend */
417 for (n = 0; n < gs_p->nnotes; n++) {
418 if ( ! HASBEND(gs_p->notelist[n])) {
419 continue;
420 }
421
422 if ((mll_p != prev_mll_p && pgs_p->c[AE] > gs_p->c[AX])
423 || carried_in == YES) {
424
425 /* either an intervening scorefeed or
426 * carried in to subsequent ending,
427 * so just start a bit west
428 * of the current group */
429 xlist[0] = gs_p->c[AW] - 2.0 * Stepsize;
430 ylist[0] = gs_p->c[AY] +
431 gs_p->notelist[n].stepsup
432 * Stepsize * TABRATIO;
433 }
434 else {
435 /* beginning of bend arrow is at east
436 * and just a bit
437 * above the center of the fret number
438 * of the previous group */
439 xlist[0] = pgs_p->c[AE] + Stdpad;
440 ylist[0] = gs_p->notelist[n].c[AY] + Stdpad;
441 }
442
443 pr_b_curve(xlist, ylist, gs_p, y_adjust);
444 }
445 pr_arrowhead(gs_p, y_adjust, C_UWEDGE);
446 }
447 else {
448 /* continuation of an in-progress bend */
449
450 /* find the note that has a bend. Only allowed to be
451 * one note with a continuation bend, or could be a release,
452 * in which case we use the first note we find */
453 for (n = 0; n < gs_p->nnotes; n++) {
454 if ( HASBEND(gs_p->notelist[n])) {
455 break;
456 }
457 }
458 if (n == gs_p->nnotes) {
459 pfatal("unable to find note with continuation bend");
460 }
461
462 /* find the starting point of the bend curve */
463 if ((mll_p != prev_mll_p && pgs_p->c[AE] > gs_p->c[AX])
464 || carried_in == YES) {
465
466 /* must have been an intervening scorefeed,
467 * so just start a bit west
468 * of the current group */
469 xlist[0] = gs_p->c[AW] - 2.0 * Stepsize;
470 Last_y_arrow[staffno] = gs_p->c[AN] - y_adjust;
471
472 /* need to adjust more if bending is actually up */
473 if (bends_up(gs_p, n, pgs_p, carried_in)) {
474 Last_y_arrow[staffno] -= 3.0 * Stepsize;
475 }
476
477 /* null bends carried over a scorefeed
478 * have to be done specially */
479 if (HASNULLBEND(gs_p->notelist[n])) {
480 Last_y_arrow[staffno] = gs_p->notelist[n].c[AN]
481 + (2 * gs_p->notelist[n].STRINGNO
482 * Stepsize * TABRATIO);
483 if (gs_p->notelist[n].STRINGNO == 0) {
484 Last_y_arrow[staffno] += 2.0 * Stepsize
485 * TABRATIO;
486 }
487 }
488 }
489 else {
490 /* beginning of bend curve is where last
491 * one left off */
492 xlist[0] = Last_x_arrow[staffno];
493 }
494 ylist[0] = Last_y_arrow[staffno];
495
496 /* determine whether curve goes up or down
497 * and find its endpoint */
498 if (bends_up(gs_p, n, pgs_p, carried_in) == YES) {
499 /* bending up some more */
500 pr_b_curve(xlist, ylist, gs_p, y_adjust);
501 pr_arrowhead(gs_p, y_adjust, C_UWEDGE);
502 }
503 else { /* bending back downwards */
504
505 if ( ! HASREALBEND(gs_p->notelist[n])) {
506 /* null bend. Have to draw curve all the way
507 * down to the appropriate "note" */
508 y_adjust = gs_p->c[AN] -
509 gs_p->notelist[n].c[AN] - Stdpad -
510 height(FONT_MUSIC, DFLT_SIZE, C_WEDGE)
511 / 2.0;
512 }
513 pr_b_curve(xlist, ylist, gs_p, y_adjust);
514 pr_arrowhead(gs_p, y_adjust, C_WEDGE);
515 }
516 }
517}
518\f
519
520/* given the first point of a bend curve, plus the gs_p and y adjustment for
521 * the end of the curve, figure out the points of the curve and draw it */
522
523static void
524pr_b_curve(xlist, ylist, gs_p, y_adjust)
525
526float *xlist; /* arrays of x & y coordinates, with 6 members */
527float *ylist;
528struct GRPSYL *gs_p;
529double y_adjust; /* how far from the north of the gs_p the curve is */
530
531{
532 float xlen, ylen;
533
534
535 /* last point of bend arrow is just below
536 * the bend string */
537 xlist[5] = gs_p->c[AX];
538 ylist[5] = gs_p->c[AN] - y_adjust - Stdpad;
539
540 /* fill in intermediate points */
541 xlen = xlist[5] - xlist[0];
542 ylen = ylist[5] - ylist[0];
543 xlist[1] = xlist[0] + xlen * 0.15;
544 ylist[1] = ylist[0];
545 xlist[2] = xlist[0] + xlen * 0.7;
546 ylist[2] = ylist[0] + ylen * 0.2;
547 xlist[3] = xlist[5] - xlen * 0.2;
548 ylist[3] = ylist[5] - ylen * 0.7;
549 xlist[4] = xlist[5];
550 ylist[4] = ylist[5] - ylen * 0.15;
551
552 /* draw the curve */
553 do_linetype(L_NORMAL);
554 pr_allcurve(xlist, ylist, 6, W_NORMAL, NO);
555}
556\f
557
558/* print arrowhead at the end of a bend curve */
559
560static void
561pr_arrowhead(gs_p, y_adjust, headchar)
562
563struct GRPSYL *gs_p;
564double y_adjust;
565int headchar; /* C_WEDGE or C_UWEDGE */
566
567{
568 pr_muschar( (double) gs_p->c[AX],
569 (double) (gs_p->c[AN] - y_adjust -
570 (height(FONT_MUSIC, DFLT_SIZE, headchar) / 2.0)),
571 headchar, DFLT_SIZE, FONT_MUSIC);
572
573 Last_y_arrow[gs_p->staffno] = gs_p->c[AN] - y_adjust;
574 Last_x_arrow[gs_p->staffno] = gs_p->c[AX];
575}
576\f
577
578/* given a GRPSYL that has a continuation bend, or is a carried-in bend,
579 * return YES if it is bending
580 * upwards from the previous bend, NO if not */
581
582static int
583bends_up(gs_p, n, pgs_p, carried_in)
584
585struct GRPSYL *gs_p; /* group having a continuation bend */
586int n; /* the note index in gs_p having the bend */
587struct GRPSYL *pgs_p; /* previous group */
588int carried_in; /* YES if bend is carried in */
589
590{
591 RATIONAL thisgrp_bend; /* rational version of bend on this group */
592 RATIONAL prevgrp_bend; /* rational version of bend on previous group */
593 int i; /* index through pgs_p notes */
594
595
596 if (gs_p == (struct GRPSYL *) 0 || pgs_p == (struct GRPSYL *) 0) {
597 pfatal("null pointer passed to bends_up");
598 }
599
600 /* get rational version of the bend distance on continuation note */
601 thisgrp_bend = ratbend( &(gs_p->notelist[n]) );
602
603 /* find the corresponding note in the previous group */
604 for (i = 0; i < pgs_p->nnotes; i++) {
605 if (pgs_p->notelist[i].STRINGNO == gs_p->notelist[n].STRINGNO) {
606 break;
607 }
608 }
609 if (i == pgs_p->nnotes) {
610 pfatal("couldn't find the note being bent from");
611 }
612
613 /* get rational version of that bend */
614 if ( ! HASBEND(pgs_p->notelist[i]) ) {
615 /* if this is a carried-in bend, it may not be a continuation
616 * bend, but in that case, it has to be bending up */
617 if (carried_in == YES) {
618 return(YES);
619 }
620 else {
621 l_ufatal(gs_p->inputfile, gs_p->inputlineno,
622 HASNULLBEND(gs_p->notelist[n]) ?
623 "bend release not preceded by a bend" :
624 "no bend on note supposedly being bent from");
625 }
626 }
627 prevgrp_bend = ratbend( &(pgs_p->notelist[i]) );
628
629 /* compare the bends */
630 if (GT(thisgrp_bend, prevgrp_bend)) {
631 return(YES);
632 }
633 else if (LT(thisgrp_bend, prevgrp_bend)) {
634 return(NO);
635 }
636 else {
637 l_ufatal(gs_p->inputfile, gs_p->inputlineno,
638 "can't bend to the same distance as previous bend");
639 /*NOTREACHED*/
640 return(NO);
641 }
642}
643\f
644
645/* Return YES if the bend is carried in to a subsequent ending, NO if just
646 * an ordinary bend.
647 */
648
649static int
650is_carried_in_bend(mll_p, prev_mll_p)
651
652struct MAINLL *mll_p; /* where group with a bend is attached */
653struct MAINLL *prev_mll_p; /* where the previous group is attached */
654
655{
656 int num_startitems; /* how many endingloc==STARTITEM were found */
657
658
659 /* if both groups are in the same measure, then it's definitely
660 * not a carried in bend */
661 if (mll_p == prev_mll_p) {
662 return(NO);
663 }
664
665 /* go forward from prev_mll_p until we get to mll_p. If we encounter
666 * more than 1 STARTITEM in endingloc, checking both normal and
667 * pseudo bars, then this was a carried in bend. */
668 num_startitems = 0;
669 for ( ; prev_mll_p != (struct MAINLL *) 0 && prev_mll_p != mll_p;
670 prev_mll_p = prev_mll_p->next) {
671
672 switch (prev_mll_p->str) {
673
674 case S_BAR:
675 if (prev_mll_p->u.bar_p->endingloc == STARTITEM) {
676 if (++num_startitems > 1) {
677 /* it is carried in bend */
678 return(YES);
679 }
680 }
681 break;
682
683 case S_CLEFSIG:
684 if (prev_mll_p->u.clefsig_p->bar_p != (struct BAR *) 0) {
685 if (prev_mll_p->u.clefsig_p->bar_p->endingloc
686 == STARTITEM) {
687 if (++num_startitems > 1) {
688 return(YES);
689 }
690 }
691 }
692 break;
693
694 default:
695 /* nothing else is relevant at this point */
696 break;
697 }
698 }
699
700 /* fell out without finding 2 STARTITEMS, so not carried in */
701 return(NO);
702}
703\f
704
705/* given internal representation of bend info,
706 * return string representation. Returns string in
707 * static area that is overwritten on each call.
708 */
709
710char *
711bend_string(note_p)
712
713struct NOTE *note_p;
714
715{
716 static char buff[12];
717 int intpart, num, den;
718
719 /* separate internal representation into integer, numerator,
720 * and denominator */
721 intpart = BENDINT(*note_p);
722 num = BENDNUM(*note_p);
723 den = BENDDEN(*note_p);
724
725 /* construct the string representation */
726 buff[0] = FONT_HR;
727 buff[1] = adj_size(DFLT_SIZE, Staffscale, (char *) 0, -1);
728
729 if (intpart == 1 && num == 0) {
730 (void) strcpy(buff+2, "full");
731 }
732 else if (intpart == 0 && num == 0) {
733 /* no bend at all */
734 buff[0] = '\0';
735 }
736 else if (num == 0) {
737 /* integer part only, no fraction */
738 (void) sprintf(buff+2, "%d", intpart);
739 }
740 else if (intpart == 0) {
741 /* fraction only */
742 (void) sprintf(buff+2, "%d/%d", num, den);
743 }
744 else {
745 /* both integer and fractional parts */
746 (void) sprintf(buff+2, "%d %d/%d", intpart, num, den);
747 }
748 return(buff);
749}
750\f
751
752/* given a NOTE on a tab staff, return char * of what is to be printed
753 * for the fret number. Returned string is a static area
754 * that is overwritten on each call.
755 */
756
757char *
758fret_string(note_p, gs_p)
759
760struct NOTE *note_p;
761struct GRPSYL *gs_p; /* group containing the note */
762
763{
764 static char fretbuff[8];
765 int size;
766
767
768 /* if no fret, return "" */
769 if (note_p->FRETNO == NOFRET) {
770 fretbuff[0] = '\0';
771 return(fretbuff);
772 }
773
774 size = adj_size((note_p->notesize == GS_SMALL ? SMFRETSIZE : DFLT_SIZE),
775 Staffscale, gs_p->inputfile, gs_p->inputlineno);
776
777 /* make proper string for X-note or normal fret number, in parentheses
778 * if appropriate */
779 if (IS_MUSIC_FONT(note_p->headfont)) {
780 (void) sprintf(fretbuff,
781 (note_p->FRET_HAS_PAREN ? "%c%c(%c%c%c)" : "%c%c%c%c%c"),
782 FONT_HB, size, mfont2str(note_p->headfont),
783 size, note_p->headchar);
784 }
785 else {
786 (void) sprintf(fretbuff,
787 (note_p->FRET_HAS_PAREN ? "%c%c(%d)" : "%c%c%d"),
788 FONT_HB, size, note_p->FRETNO);
789 }
790 return(fretbuff);
791}
792\f
793
794/* print a TAB "clef" which is really just the word "TAB" written vertically.
795 * By convention, this only gets printed once per staff at the very beginning
796 * of the song. To keep things simple, the width of the clef is always
797 * returned as if the clef was printed even when it really isn't */
798
799double
800pr_tabclef(staffno, x, really_print, size)
801
802int staffno;
803double x;
804int really_print;
805int size;
806
807{
808 static int did_tab_clef[MAXSTAFFS + 1]; /* set to YES once we print a
809 * TAB clef on a given staff. Convention is to print
810 * this "clef" only at the very beginning of a song. */
811 int stafflines;
812 int ptsize; /* point size to use for "TAB" */
813 double width, widest; /* of the letters in "TAB" */
814 double height = 0.0;
815 char letter[4]; /* internal format version of one letter of "TAB" */
816 char *tabstr; /* pointer through "TAB" */
817 double y = 0.0;
818
819
820 /* adjust the size based on how many stafflines there are */
821 stafflines = svpath(staffno, STAFFLINES)->stafflines;
822 if (stafflines < 4) {
823 ptsize = 7;
824 }
825 else if (stafflines == 4) {
826 ptsize = 13;
827 }
828 else if (stafflines == 5) {
829 ptsize = 16;
830 }
831 else {
832 ptsize = 20;
833 }
834
835 /* if small clef, adjust the size (actually, this shouldn't
836 * ever happen unless we change some other things some day, but this
837 * way we will be prepared if/when that happens). */
838 if (size != DFLT_SIZE) {
839 ptsize = (int) (ptsize * (size / DFLT_SIZE));
840 }
841 ptsize = adj_size(ptsize, Staffscale, (char *) 0, -1);
842
843 /* print/get width of "TAB" */
844 for (widest = 0, tabstr = "TAB"; *tabstr != '\0'; tabstr++) {
845
846 /* create internal format string for current letter */
847 (void) sprintf(letter, "%c%c%c", FONT_HB, ptsize, *tabstr);
848 /* get its width */
849 width = strwidth(letter);
850
851 /* save the widest letter width */
852 if (width > widest) {
853 widest = width;
854 }
855
856 /* if we're really supposed to print,
857 * print this letter of "TAB" */
858 if (really_print == YES && did_tab_clef[staffno] == NO) {
859
860 /* figure out where to place vertically */
861 if (*tabstr == 'T') {
862 /* place the top letter */
863 height = strheight(letter);
864 y = Staffs_y[staffno] + height / 2.0
865 + Stdpad;
866 }
867 else {
868 /* move subsequent letters down by height
869 * of the previous */
870 y -= height;
871 }
872
873 /* print the letter with a little space before */
874 pr_string(x + 3.0 * Stdpad, y, letter, J_LEFT,
875 (char *) 0, -1);
876 }
877 }
878
879 /* only print once per staff */
880 if (really_print == YES) {
881 did_tab_clef[staffno] = YES;
882 }
883
884 /* allow some space on either side */
885 return(widest + 6.0 * Stdpad);
886}