Commit | Line | Data |
---|---|---|
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 */ | |
12 | static double Last_x_arrow[MAXSTAFFS + 1], Last_y_arrow[MAXSTAFFS + 1]; | |
13 | ||
14 | static double pr_tab_note P((int note_index, struct GRPSYL *gs_p, | |
15 | double y_adjust, struct MAINLL *mll_p)); | |
16 | static double pr_bstring P((struct GRPSYL *gs_p, struct NOTE *note_p, | |
17 | int note_index, double y_adjust, struct MAINLL *mll_p)); | |
18 | static void pr_b_arrow P((struct GRPSYL *gs_p, struct MAINLL *mll_p, | |
19 | double y_adjust)); | |
20 | static void pr_b_curve P((float *xlist, float *ylist, struct GRPSYL *gs_p, | |
21 | double y_adjust)); | |
22 | static void pr_arrowhead P((struct GRPSYL *gs_p, double y_adjust, int headchar)); | |
23 | static int bends_up P((struct GRPSYL *gs_p, int n, struct GRPSYL *pgs_p, | |
24 | int carried_in)); | |
25 | static 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 | ||
32 | void | |
33 | pr_tab_groups(gs_p, mll_p) | |
34 | ||
35 | struct GRPSYL *gs_p; | |
36 | struct 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 | ||
244 | static double | |
245 | pr_tab_note(note_index, gs_p, y_adjust, mll_p) | |
246 | ||
247 | int note_index; /* which note in gs_p */ | |
248 | struct GRPSYL *gs_p; | |
249 | double y_adjust; /* to account for bend string space */ | |
250 | struct 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 | ||
297 | static double | |
298 | pr_bstring(gs_p, note_p, note_index, y_adjust, mll_p) | |
299 | ||
300 | struct GRPSYL *gs_p; /* group having a bend */ | |
301 | struct NOTE *note_p; /* which note in gs_p has the bend */ | |
302 | int note_index; /* index into gs_p->notelist of note_p */ | |
303 | double y_adjust; /* to account for bend strings done previously | |
304 | * for this group (on other notes in the group */ | |
305 | struct 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 | ||
352 | static void | |
353 | pr_b_arrow(gs_p, mll_p, y_adjust) | |
354 | ||
355 | struct GRPSYL *gs_p; | |
356 | struct MAINLL *mll_p; | |
357 | double 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 | ||
523 | static void | |
524 | pr_b_curve(xlist, ylist, gs_p, y_adjust) | |
525 | ||
526 | float *xlist; /* arrays of x & y coordinates, with 6 members */ | |
527 | float *ylist; | |
528 | struct GRPSYL *gs_p; | |
529 | double 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 | ||
560 | static void | |
561 | pr_arrowhead(gs_p, y_adjust, headchar) | |
562 | ||
563 | struct GRPSYL *gs_p; | |
564 | double y_adjust; | |
565 | int 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 | ||
582 | static int | |
583 | bends_up(gs_p, n, pgs_p, carried_in) | |
584 | ||
585 | struct GRPSYL *gs_p; /* group having a continuation bend */ | |
586 | int n; /* the note index in gs_p having the bend */ | |
587 | struct GRPSYL *pgs_p; /* previous group */ | |
588 | int 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 | ||
649 | static int | |
650 | is_carried_in_bend(mll_p, prev_mll_p) | |
651 | ||
652 | struct MAINLL *mll_p; /* where group with a bend is attached */ | |
653 | struct 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 | ||
710 | char * | |
711 | bend_string(note_p) | |
712 | ||
713 | struct 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 | ||
757 | char * | |
758 | fret_string(note_p, gs_p) | |
759 | ||
760 | struct NOTE *note_p; | |
761 | struct 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 | ||
799 | double | |
800 | pr_tabclef(staffno, x, really_print, size) | |
801 | ||
802 | int staffno; | |
803 | double x; | |
804 | int really_print; | |
805 | int 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 | } |