chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / tie.c
CommitLineData
69695f33
MW
1
2/* Copyright (c) 1995, 1997, 1998, 1999, 2001, 2002 by Arkkra Enterprises */
3/* All rights reserved */
4
5/* This file contains functions for handling ties and slurs.
6 * This includes doing error checking to make sure
7 * there is a note to tie/slur to.
8 * There is also code to add padding to make space for ties/slurs
9 * that are carried into second endings. */
10
11#include "defines.h"
12#include "structs.h"
13#include "globals.h"
14
15
16
17/* lengths of line segments of carried in tie marks */
18#define HALFTIEPAD (3 * STEPSIZE)
19
20/* infomation about a tied or slurred note that gets carried into an ending */
21struct TIECARRY {
22 short letter; /* pitch to be tied or slurred to */
23 short octave; /* octave of the pitch */
24 short curveno; /* slurto index or -1 for tie */
25 short is_bend; /* if slurto is actually a bend */
26 struct MAINLL *mll_p; /* points to first group */
27 struct GRPSYL *gs_p; /* group of first note */
28 struct TIECARRY *next; /* linked list */
29};
30
31/* linked list of tie carry info for each staff/voice */
32struct TIECARRY *Tiecarryinfolist_p [MAXSTAFFS + 1] [MAXVOICES];
33
34/* flag to mark if there are any carry ins */
35static short Have_carry_ins = NO;
36
37
38/* static functions */
39static void do_tie P((struct MAINLL *mll_p));
40static void do_group_ties P((struct GRPSYL *gs_p, struct MAINLL *mll_p));
41static void chk_slides P((struct NOTE *note_p, struct GRPSYL *gs_p,
42 struct MAINLL *mll_p));
43static void chk_following4slide P((struct NOTE *note_p, struct GRPSYL *gs_p,
44 struct MAINLL *mll_p));
45static struct MAINLL *do_carry_ties P((struct MAINLL *staff_mll_p,
46 struct MAINLL *bar_mll_p));
47static void savetieinfo P((struct MAINLL *mll_p, struct GRPSYL *gs_p));
48static void do_save_tieinfo P((int staffno, int vno, int letter, int octave,
49 int is_tie, struct MAINLL *mainll_p, struct GRPSYL *gs_p,
50 int is_bend));
51static void carryin_ties P((struct MAINLL *mll_p));
52static void add_carryin P((struct STAFF *staff_p));
53static void free_carryin_info P((void));
54static void free_cinfo P((struct TIECARRY *carryinfo_p));
55static void chk4xpose P((struct MAINLL *mll_p));
56static void chkxpstaff P((struct MAINLL *mll_p, int s));
57static void chkxpgrp P((struct GRPSYL *gs_p, char *inputfile, int lineno));
58static void set_inhibitprint_if_appropriate P((struct GRPSYL *gs_p,
59 struct MAINLL *mll_p));
60\f
61
62
63/* go through main list, checking each STAFF struct for ties and slurs.
64 * For each, do appropriate error checking */
65
66void
67tie()
68
69{
70 struct MAINLL * mll_p; /* walk through main list */
71
72
73 debug(2, "tie");
74
75 /* first check for any ties across transpositions, and delete them.
76 * Can't do inside the next loop, because by then a less informative
77 * message could be generated for the error */
78 initstructs();
79 for (mll_p = Mainllhc_p; mll_p != (struct MAINLL *) 0;
80 mll_p = mll_p->next) {
81 if (mll_p->str == S_SSV) {
82 chk4xpose(mll_p);
83 asgnssv(mll_p->u.ssv_p);
84 }
85 }
86
87 /* go through the main list again for other checks */
88 initstructs();
89 for (mll_p = Mainllhc_p; mll_p != (struct MAINLL *) 0;
90 mll_p = mll_p->next) {
91
92 /* process any GRPSYL lists with note info */
93 if (mll_p->str == S_STAFF) {
94 if ( (svpath(mll_p->u.staff_p->staffno, VISIBLE))
95 ->visible == YES) {
96 do_tie(mll_p);
97 }
98 }
99 else if (mll_p->str == S_SSV) {
100 asgnssv(mll_p->u.ssv_p);
101 }
102 }
103}
104\f
105
106/* do the ties and slurs on all groups off a STAFF struct */
107
108static void
109do_tie(mll_p)
110
111struct MAINLL *mll_p; /* the STAFF struct with list of GRPSYLs */
112
113{
114 struct GRPSYL *gs_p; /* walk through GRPSYL list */
115 int v; /* walk through voices per staff */
116 int is_tab; /* YES if tablature staff */
117
118
119 is_tab = is_tab_staff(mll_p->u.staff_p->staffno);
120
121 for (v = 0; v < MAXVOICES; v++) {
122 /* go through entire list of GRPSYLs */
123 for (gs_p = mll_p->u.staff_p->groups_p[v];
124 gs_p != (struct GRPSYL *) 0;
125 gs_p = gs_p->next) {
126
127 /* error check */
128 if (gs_p->grpcont != GC_NOTES) {
129 if (gs_p->tie == YES) {
130 l_warning(mll_p->inputfile,
131 mll_p->inputlineno,
132 "tie can only apply to notes");
133 gs_p->tie = NO;
134 }
135
136 /* if rest or space, nothing more to do */
137 continue;
138 }
139
140 do_group_ties(gs_p, mll_p);
141 if (is_tab == YES) {
142 set_inhibitprint_if_appropriate(gs_p, mll_p);
143 }
144 }
145 }
146}
147\f
148
149/* do ties on all notes in a group that have ties. While we're at it, also
150 * make sure any staffs with clefs not printed, don't have accidentals on any
151 * notes */
152
153static void
154do_group_ties(gs_p, mll_p)
155
156struct GRPSYL *gs_p; /* do ties from this group */
157struct MAINLL *mll_p; /* points to gs_p */
158
159{
160 struct GRPSYL *gs2_p; /* group to tie to */
161 register int n; /* walk through note list */
162 struct NOTE *note1_p; /* info about note */
163 struct NOTE *note2_p; /* note slurred to */
164 int slur; /* index into slurtolist */
165 int d; /* index for deleting illegal slurs */
166 short err = NO; /* error flag */
167 short inhibitprint; /* if to set inhibitprint flag on the
168 * tied-to group (tab staff only) */
169
170
171 /* if all notes in a group are tied on a tablature staff,
172 * then all the corresponding notes on the tied-to group
173 * should have their inhibitprint flag set. So we need to
174 * find out if that is a possibility */
175 if (is_tab_staff(gs_p->staffno) == YES) {
176 if (gs_p->tie == YES) {
177 inhibitprint = YES;
178 }
179 else {
180 /* first assume that all notes will be tied, then
181 * check them all. If any are found that are not
182 * tied, then turn the inhibitprint flag back off */
183 inhibitprint = YES;
184 for (n = 0; n < gs_p->nnotes; n++) {
185 if (gs_p->notelist[n].tie == NO) {
186 inhibitprint = NO;
187 break;
188 }
189 }
190 }
191 }
192 else {
193 /* inhibitprint flag is only used on tablature staffs */
194 inhibitprint = NO;
195 }
196
197 /* go through all notes in group, looking for ties */
198 gs2_p = (struct GRPSYL *) 0;
199 for (n = 0; n < gs_p->nnotes; n++) {
200
201 /* For staffs without clef, make sure there are no accidentals.
202 * But tab staffs keep accidentals, even with no clef.
203 * Philosophically, this isn't really a good place to
204 * do this, but since we're going through the list of notes
205 * anyway here, and time-wise in the scheme of the program
206 * this is the right time, rather than make yet another trip
207 * through the list later we do it here. But for MIDI
208 * purposes, we need to keep the accidental, or the wrong
209 * note will play! */
210 if (svpath(gs_p->staffno, STAFFLINES)->printclef != SS_NORMAL
211 && is_tab_staff(gs_p->staffno) == NO
212 && Doing_MIDI == NO) {
213 gs_p->notelist[n].accidental = '\0';
214 }
215
216 note1_p = &(gs_p->notelist[n]);
217 /* if this note's tie flag is set, check the tie */
218 if ( note1_p->tie == YES) {
219
220 /* if haven't yet found the group to tie to, do that.
221 * (If this is not the first note to be tied
222 * in this group, we would have already found
223 * the other group) */
224 if (gs2_p == (struct GRPSYL *) 0) {
225 gs2_p = find_next_group(mll_p, gs_p, "tie");
226 }
227
228 if (gs2_p == (struct GRPSYL *) 0) {
229 /* if nothing to tie to, cancel the tie. We
230 * will have already printed an error msg. */
231 note1_p->tie = NO;
232 gs_p->tie = NO;
233 }
234 else {
235 /* if the inhibitprint flag is set, set it
236 * in the tied-to group. However,
237 * if the groups have different numbers of
238 * notes and the inhibitprint flag is set,
239 * we have to cancel it, because that only
240 * applies when the tied-from and tied-to
241 * groups have identical notes in them */
242 if (inhibitprint == YES) {
243 if (gs_p->nnotes == gs2_p->nnotes) {
244 gs2_p->inhibitprint = YES;
245 }
246 /* turn flag off, so we don't
247 * waste time checking it
248 * again for each of the remaining
249 * notes in the group */
250 inhibitprint = NO;
251 }
252
253 if (find_matching_note(gs2_p, note1_p->letter,
254 note1_p->octave, "tie")
255 == (struct NOTE *) 0) {
256 note1_p->tie = NO;
257 gs_p->tie = NO;
258 }
259 }
260 }
261
262
263 /* handle all slurs from current note */
264 for (slur = 0; slur < note1_p->nslurto; slur++) {
265
266 /* slides to/from nowhere don't get processed here */
267 if (IS_NOWHERE(note1_p->slurtolist[slur].octave)) {
268 continue;
269 }
270
271 /* if haven't yet found the group to slur to, do that.
272 * (We may have already found it earlier) */
273 if (gs2_p == (struct GRPSYL *) 0) {
274 gs2_p = find_next_group(mll_p, gs_p, "slur");
275 }
276
277 if (gs2_p == (struct GRPSYL *) 0) {
278 /* if nothing to slur to, cancel all slurs */
279 note1_p->nslurto = 0;
280 continue;
281 }
282
283 /* special case of 'M' when a group 'slur'
284 * has been specified. Find matching note
285 * in the second chord */
286 if (note1_p->slurtolist[slur].letter == 'M') {
287 if (gs_p->nnotes != gs2_p->nnotes) {
288 /* only print message first time */
289 if (err == NO) {
290 l_warning(gs_p->inputfile,
291 gs_p->inputlineno,
292 "'slur' requires equal number of notes in each chord");
293 }
294 note2_p = (struct NOTE *) 0;
295
296 /* don't do any more on this
297 * chord, to avoid multiple
298 * error messages */
299 err = YES;
300 }
301 else {
302 note2_p = & (gs2_p->notelist[n]);
303 }
304 }
305 else {
306 note2_p = find_matching_note(gs2_p,
307 note1_p->slurtolist[slur].letter,
308 note1_p->slurtolist[slur].octave,
309 note1_p->is_bend ? "bend" : "slur");
310 }
311
312 if (note2_p != (struct NOTE *) 0) {
313 /* fill in the letter/octave if they had to
314 * be derived */
315 if ((note1_p->slurtolist[slur].letter == 'U')
316 || (note1_p->slurtolist[slur].letter == 'M')
317 || is_tab_staff(gs_p->staffno) == YES) {
318 note1_p->slurtolist[slur].letter =
319 note2_p->letter;
320 note1_p->slurtolist[slur].octave =
321 note2_p->octave;
322 }
323 }
324 else {
325 /* discard this slur--
326 * nothing to slur to */
327 for (d = slur + 1; d < note1_p->nslurto; d++) {
328 note1_p->slurtolist[d-1] =
329 note1_p->slurtolist[d];
330 }
331 (note1_p->nslurto)--;
332 }
333 }
334
335 /* do additional slide checks for tab and tabnote */
336 if (is_tab_staff(gs_p->staffno) == YES
337 || (gs_p->staffno < MAXSTAFFS
338 && is_tab_staff(gs_p->staffno + 1) == YES)) {
339 chk_slides(note1_p, gs_p, mll_p);
340 }
341 }
342}
343
344/* do extra checks for slide. There can be no more than one incoming and one
345 * outgoing slide for any given note */
346
347static void
348chk_slides(note_p, gs_p, mll_p)
349
350struct NOTE *note_p; /* this note might have slides */
351struct GRPSYL *gs_p; /* note is in this group */
352struct MAINLL *mll_p; /* group is tied to this main list struct */
353
354{
355 int s; /* index through slurtolist */
356 int incoming = 0, outgoing = 0; /* how many slides of each type */
357
358
359 /* go through list counting up incoming and outgoing slides */
360 for (s = 0; s < note_p->nslurto; s++) {
361 switch(note_p->slurtolist[s].octave) {
362
363 case OUT_UPWARD:
364 case OUT_DOWNWARD:
365 outgoing++;
366 break;
367
368 case IN_UPWARD:
369 case IN_DOWNWARD:
370 incoming++;
371 break;
372
373 default:
374 outgoing++;
375 /* make sure following group doesn't have any
376 * incoming nowhere slides */
377 chk_following4slide(note_p, gs_p, mll_p);
378 break;
379 }
380 }
381
382 if (incoming > 1) {
383 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
384 "can't have more than one slide into a note");
385 }
386 if (outgoing > 1) {
387 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
388 "can't have more than one slide from a note");
389
390 }
391}
392\f
393
394/* Given a note with a slide to a specific fret,
395 * if there is a following group, see if it has a matching note,
396 * and if so, check that note's slurtolist to see if it
397 * contains any incoming nowhere slides. If so, there is a
398 * problem, because we already have a slide to that note */
399
400static void
401chk_following4slide(note_p, gs_p, mll_p)
402
403struct NOTE *note_p; /* this note has a slide to a specific fret */
404struct GRPSYL *gs_p; /* note is in this group */
405struct MAINLL *mll_p; /* group is attached to this main list struct */
406
407{
408 struct GRPSYL *ngs_p; /* next group */
409 int n; /* index through notes */
410 int ns; /* index through slides on next group note */
411
412
413 if ((ngs_p = nextgrpsyl(gs_p, &mll_p)) == (struct GRPSYL *) 0) {
414 /* no next group, so no problem */
415 return;
416 }
417
418 /* check each note in next group */
419 for (n = 0; n < ngs_p->nnotes; n++) {
420 /* is this the matching note? If the letter matches and
421 * either it's a tab staff or the octave also matches,
422 * then it is the matching note. */
423 if (ngs_p->notelist[n].letter == note_p->letter &&
424 (is_tab_staff(gs_p->staffno) ||
425 ngs_p->notelist[n].octave == note_p->octave)) {
426
427 /* found the matching note. Check its slurtolist */
428 for (ns = 0; ns < ngs_p->notelist[n].nslurto; ns++) {
429 switch (ngs_p->notelist[n].slurtolist[ns].octave) {
430 case IN_UPWARD:
431 case IN_DOWNWARD:
432 l_yyerror(gs_p->inputfile,
433 gs_p->inputlineno,
434 "can't slide to note that has </n> or <\\n>");
435 break;
436 default:
437 break;
438 }
439 }
440 }
441 }
442}
443\f
444
445/* find note in following chord having specified pitch/octave.
446 * If the note is found, return pointer to it, otherwise 0
447 */
448
449struct NOTE *
450find_matching_note(gs_p, letter, octave, type)
451
452struct GRPSYL *gs_p; /* which GRPSYL we're tying to */
453int letter; /* find note with this pitch, 'a' to 'g' */
454int octave; /* find note with this octave */
455char *type; /* "tie", "slur", "slide", or "bend",
456 * or null if not to print any error messages */
457
458{
459 struct NOTE *note2_p; /* note to tie to */
460 register int n2; /* index through notelist of 2nd group */
461
462
463 if (gs_p == (struct GRPSYL *) 0) {
464 return( (struct NOTE *) 0);
465 }
466
467 /* we don't allow tie/slur into a measure repeat. */
468 if (is_mrpt(gs_p) == YES) {
469 l_warning(gs_p->inputfile, gs_p->inputlineno,
470 "tie/slur/bend not allowed into measure rpt");
471 return (struct NOTE *) 0;
472 }
473
474 /* special case. On slurto, if second group has only a single
475 * note, user doesn't have to specify it. We will have marked the
476 * pitch as 'U'. If second group has only one note in it, use that
477 * one. If not, error */
478 if ( letter == 'U') {
479 if ( gs_p->nnotes != 1) {
480 if (type != (char *) 0) {
481 l_warning(gs_p->inputfile, gs_p->inputlineno,
482 "note to %s to not specified", type);
483 }
484 return(struct NOTE *) 0;
485 }
486 else {
487 return( &(gs_p->notelist[0]) );
488 }
489 }
490
491 /* try to find matching note in second note group */
492 /* If first note has an accidental and the corresponding one in
493 * the next group doesn't, that's a
494 * match, 'cause we only print the accidental once.
495 */
496 for (n2 = 0; n2 < gs_p->nnotes; n2++) {
497
498 note2_p = &(gs_p->notelist[n2]);
499
500 if (is_tab_staff(gs_p->staffno) == YES) {
501 /* on tab staff, we just have to match
502 * the string number */
503 if (note2_p->letter == letter) {
504 return(note2_p);
505 }
506 else {
507 continue;
508 }
509 }
510
511 if ( (note2_p->letter == letter)
512 && (note2_p->octave == octave) ) {
513
514 if (type != (char *) 0 && (strcmp(type, "tie") == 0)
515 && (note2_p->accidental != '\0')
516 && is_tab_staff(gs_p->staffno) == NO) {
517 l_warning(gs_p->inputfile, gs_p->inputlineno,
518 "second note of tie not allowed to have an accidental");
519 /* fix it so in case we're called again on the
520 * same note (which is possible), we'll only
521 * print one error message */
522 note2_p->accidental = '\0';
523 }
524
525 /* found it! */
526 return(note2_p);
527 }
528 }
529
530 /* oh-oh. User goofed */
531 if (is_tab_staff(gs_p->staffno) == YES) {
532 if (type != (char *) 0) {
533 l_yyerror(gs_p->inputfile, gs_p->inputlineno,
534 "can't do %s: %s string not in chord%s",
535 type, stringname(letter, gs_p->staffno),
536 gs_p->nnotes == 0 ?
537 " (in fact no strings at all)" : "");
538 }
539 }
540 else {
541 if (type != (char *) 0) {
542 if (letter < 'a' || letter > 'g' || octave < MINOCTAVE
543 || octave > MAXOCTAVE) {
544 l_warning(gs_p->inputfile, gs_p->inputlineno,
545 "can't do %s: note not in chord",
546 type);
547 }
548 else {
549 l_warning(gs_p->inputfile, gs_p->inputlineno,
550 "can't do %s: %c%d not in chord%s",
551 type, letter, octave,
552 gs_p->nnotes == 0 ?
553 " (in fact no notes at all)" : "");
554 }
555 }
556 }
557 return( (struct NOTE *) 0 );
558}
559\f
560
561/* given one GRPSYL, find the next one in the same staff and voice,
562 * which might be in the next measure */
563
564struct GRPSYL *
565find_next_group(mll_p, gs_p, type)
566
567struct MAINLL *mll_p; /* current place in main list */
568struct GRPSYL *gs_p; /* group to tie from */
569char *type; /* "tie" or "slur" */
570
571{
572 struct MAINLL *ml_p;
573
574 ml_p = mll_p;
575 if ((gs_p = nextgrpsyl(gs_p, &ml_p)) == (struct GRPSYL *) 0) {
576 l_warning(mll_p->inputfile, mll_p->inputlineno,
577 "no chord to %s to", type);
578 }
579
580 return(gs_p);
581}
582\f
583
584/* go through main list. If we hit a bar that begins an ending, back up
585 * and go through the previous measure. If the final group of any voice
586 * has any tied or slurred notes, save information about them. Then for
587 * each additional beginning of an ending up until an endending, add
588 * user padding to allow for carried in tie mark. At the endending, free
589 * the information and continue through the rest of the main list */
590
591void
592tie_carry()
593
594{
595 struct MAINLL *mll_p; /* walk through main list */
596 struct MAINLL *first_staff_mll_p; /* points to first STAFF
597 * struct of measure */
598
599
600 debug(2, "tie_carry");
601
602 initstructs();
603 first_staff_mll_p = (struct MAINLL *) 0;
604 for (mll_p = Mainllhc_p; mll_p != (struct MAINLL *) 0;
605 mll_p = mll_p->next) {
606 switch (mll_p->str) {
607
608 case S_STAFF:
609 /* remember where list of staffs begins and skip
610 * the rest of the STAFFs */
611 first_staff_mll_p = mll_p;
612 for ( ; mll_p->next->str == S_STAFF;
613 mll_p = mll_p->next) {
614 ;
615 }
616 break;
617
618 case S_BAR:
619 if (mll_p->u.bar_p->endingloc == STARTITEM) {
620 mll_p = do_carry_ties(first_staff_mll_p, mll_p);
621 }
622 break;
623
624 case S_CLEFSIG:
625 /* actually, it should be impossible to hit this case,
626 * because clefsigs with pseudo-bar haven't been
627 * created yet at the time this is called, but if things
628 * are changed some day so things get done in a different
629 * order, this should then work. */
630 if (mll_p->u.clefsig_p->bar_p != (struct BAR *) 0 &&
631 mll_p->u.clefsig_p->bar_p->endingloc
632 == STARTITEM) {
633 mll_p = do_carry_ties(first_staff_mll_p, mll_p);
634 }
635 break;
636
637 case S_SSV:
638 asgnssv(mll_p->u.ssv_p);
639 break;
640 default:
641 break;
642 }
643 }
644}
645\f
646
647/* Save info about any ties and slurs on the last chords before the beginning
648 * of the ending. Then search forward in main list. If there are any more
649 * beginnings of endings, add padding to the appropriate groups.
650 * Return MAINLL at the end of the last ending processed. */
651
652static struct MAINLL *
653do_carry_ties(staff_mll_p, bar_mll_p)
654
655struct MAINLL *staff_mll_p; /* first staff in measure which ends on
656 * bar that begins an ending */
657struct MAINLL *bar_mll_p; /* the bar that begins an ending */
658
659{
660 struct MAINLL *mll_p; /* walk through list of staffs */
661 int v; /* voice number */
662
663
664 /* save all the tie / slur info */
665 for (mll_p = staff_mll_p; mll_p->str == S_STAFF; mll_p = mll_p->next) {
666
667 for (v = 0; v < MAXVOICES; v++) {
668 savetieinfo(mll_p, mll_p->u.staff_p->groups_p[v]);
669 }
670 }
671
672 /* now search ahead for other endings */
673 for (mll_p = bar_mll_p->next; mll_p != (struct MAINLL *) 0;
674 mll_p = mll_p->next) {
675 if (mll_p->str != S_BAR) {
676 continue;
677 }
678
679 switch (mll_p->u.bar_p->endingloc) {
680 case NOITEM:
681 case ENDITEM:
682 free_carryin_info();
683 return(mll_p);
684 case STARTITEM:
685 carryin_ties(mll_p->next);
686 break;
687 default:
688 break;
689 }
690 }
691 pfatal("fell off end of list while doing tie carries");
692 /*NOTREACHED*/
693 return( (struct MAINLL *) 0);
694}
695\f
696
697/* given a GRPSYL, save info about any notes in it that have ties or slurs */
698
699static void
700savetieinfo(mll_p, gs_p)
701
702struct MAINLL *mll_p; /* main list struct that gs_p is connected to */
703struct GRPSYL *gs_p; /* save info about ties/slurs on last group
704 * in this list */
705
706{
707 int n; /* note index */
708 int s; /* slurto index */
709
710
711 if (gs_p == (struct GRPSYL *) 0) {
712 return;
713 }
714
715 /* find last group in list */
716 for ( ; gs_p->next != (struct GRPSYL *) 0; gs_p = gs_p->next) {
717 ;
718 }
719
720 for (n = 0; n < gs_p->nnotes; n++) {
721
722 /* save tie info */
723 if (gs_p->notelist[n].tie == YES) {
724 do_save_tieinfo(gs_p->staffno, gs_p->vno,
725 gs_p->notelist[n].letter,
726 gs_p->notelist[n].octave, -1,
727 mll_p, gs_p, NO);
728 }
729
730 /* save slurto info */
731 for (s = 0; s < gs_p->notelist[n].nslurto; s++) {
732 do_save_tieinfo(gs_p->staffno, gs_p->vno,
733 gs_p->notelist[n].slurtolist[s].letter,
734 gs_p->notelist[n].slurtolist[s].octave,
735 s, mll_p, gs_p,
736 gs_p->notelist[n].is_bend);
737 }
738 }
739}
740\f
741
742/* save info about one tie or slur mark that will need to be carried into
743 * subsequent endings. Malloc space for info, fill it in, and put into table */
744
745static void
746do_save_tieinfo(staffno, vno, letter, octave, curveno, mll_p, gs_p, is_bend)
747
748int staffno;
749int vno;
750int letter; /* a to g */
751int octave;
752int curveno;
753struct MAINLL *mll_p; /* points to first group */
754struct GRPSYL *gs_p; /* group of first note */
755int is_bend; /* YES if is actually a bend rather than slur */
756
757{
758 struct TIECARRY *new_p;
759
760 MALLOC(TIECARRY, new_p, 1);
761 new_p->letter = (short) letter;
762 new_p->octave = (short) octave;
763 new_p->curveno = (short) curveno;
764 new_p->is_bend = is_bend;
765 new_p->mll_p = mll_p;
766 new_p->gs_p = gs_p;
767 new_p->next = Tiecarryinfolist_p [staffno] [vno - 1];
768 Tiecarryinfolist_p [staffno] [vno - 1] = new_p;
769
770 Have_carry_ins = YES;
771}
772\f
773
774/* Once an ending has been found that may have ties/slurs carried in, use
775 * the saved information to add padding. */
776
777static void
778carryin_ties(mll_p)
779
780struct MAINLL *mll_p; /* look for staffs from here for chords that may have
781 * things tied or slurred in */
782
783{
784 if (Have_carry_ins == NO) {
785 /* nothing to do */
786 return;
787 }
788
789 /* skip everything up to STAFFS */
790 for ( ; mll_p != (struct MAINLL *) 0; mll_p = mll_p->next) {
791 if (mll_p->str == S_STAFF) {
792 add_carryin(mll_p->u.staff_p);
793 }
794 else if (mll_p->str == S_BAR) {
795 break;
796 }
797 }
798}
799\f
800
801/* given a STAFF which is at the beginning of an ending that may have ties/slurs
802 * carried in, go through each voice. If there is anything to carry in,
803 * add appropriate padding, then generate curve */
804
805static void
806add_carryin(staff_p)
807
808struct STAFF *staff_p; /* which staff to do ties/slur carry in on */
809
810{
811 int staffno;
812 int v; /* voice number */
813 int n; /* index into notelist */
814 struct GRPSYL *gs_p; /* first chord in measure */
815 struct TIECARRY *info_p; /* info about things carried in */
816 int found; /* if matching note found in chord */
817 double padding; /* how much padding to add */
818
819
820 staffno = staff_p->staffno;
821 /* do each carried in item on each voice */
822 for (v = 0; v < MAXVOICES; v++) {
823
824 padding = HALFTIEPAD;
825
826 for (info_p = Tiecarryinfolist_p [staffno] [v];
827 info_p != (struct TIECARRY *) 0;
828 info_p = info_p->next) {
829
830 gs_p = staff_p->groups_p[v];
831
832 /* add padding to allow for carried-in mark */
833 gs_p->padding += padding;
834 /* only add padding once per chord! */
835 padding = 0.0;
836
837 /* mark any notes that will get carried-in mark */
838 for (found = NO, n = 0; n < gs_p->nnotes; n++) {
839 if (gs_p->notelist[n].letter
840 == info_p->letter &&
841 gs_p->notelist[n].octave
842 == info_p->octave) {
843
844 /* A carried-in tie on a tablature
845 * staff isn't printed, but the fret
846 * is put in parentheses. */
847 if (is_tab_staff(staff_p->staffno) == YES
848 && info_p->curveno == -1) {
849 gs_p->notelist[n].FRET_HAS_PAREN = YES;
850 }
851 found = YES;
852 break;
853 }
854 }
855
856 if (found == NO) {
857 l_warning(gs_p->inputfile, gs_p->inputlineno,
858 "can't carry tie/slur/bend into ending: %c%d not in chord",
859 info_p->letter, info_p->octave);
860 }
861 }
862 }
863}
864\f
865
866/* free all the tie carry in info */
867
868static void
869free_carryin_info()
870
871{
872 int s;
873 int v;
874
875
876 for (s = 1; s <= MAXSTAFFS; s++) {
877 for (v = 0; v < MAXVOICES; v++) {
878 free_cinfo(Tiecarryinfolist_p [s] [v]);
879 Tiecarryinfolist_p [s] [v] = (struct TIECARRY *) 0;
880 }
881 }
882
883 Have_carry_ins = NO;
884}
885
886
887/* recursively free list of tie carry information */
888
889static void
890free_cinfo(carryinfo_p)
891
892struct TIECARRY *carryinfo_p;
893
894{
895 if (carryinfo_p == (struct TIECARRY *) 0) {
896 return;
897 }
898
899 free_cinfo(carryinfo_p->next);
900 FREE(carryinfo_p);
901}
902\f
903
904/* check if a transposition occurred, and if so, see if there were any
905 * ties that would cross the bar. If so, print warning and discard the tie */
906
907static void
908chk4xpose(mll_p)
909
910struct MAINLL *mll_p; /* containing SSV that might contain transpose */
911
912{
913 struct SSV *ssv_p;
914 int s; /* staff index */
915 int intnum; /* transposition interval */
916 int inttype; /* transposition interval type */
917
918
919 if (mll_p->str != S_SSV) {
920 return;
921 }
922
923 ssv_p = mll_p->u.ssv_p;
924 if (ssv_p->used[TRANSPOSITION] == YES ||
925 ssv_p->used[ADDTRANSPOSITION] == YES) {
926 /* this SSV changes transpose value, need to check further */
927 if (ssv_p->context == C_STAFF) {
928 /* if staff now has a different transpose value than
929 * before, need to see if any notes tied over the
930 * previous bar */
931 s = ssv_p->staffno;
932 totaltrans(s, &inttype, & intnum);
933 if (ssv_p->inttype != inttype
934 || ssv_p->intnum != intnum) {
935 chkxpstaff(mll_p, s);
936 }
937 }
938 else {
939 /* must be score wide change. This is a little
940 * trickier. Go through each staff. If its transpose
941 * value is not set in staff context and it's
942 * different than the new transpose value, then
943 * we need to check for ties */
944 for (s = 1; s <= Score.staffs; s++) {
945 totaltrans(0, &inttype, & intnum);
946 if (Staff[s].used[TRANSPOSITION] == NO &&
947 Staff[s].used[ADDTRANSPOSITION] == NO &&
948 (ssv_p->inttype != inttype
949 || ssv_p->intnum != intnum)) {
950 chkxpstaff(mll_p, s);
951 }
952 }
953 }
954 }
955}
956\f
957
958/* check a specific staff for possible ties across transposition */
959
960static void
961chkxpstaff(mll_p, s)
962
963struct MAINLL *mll_p; /* look backward in main list from here */
964int s; /* which staff */
965
966{
967 int v;
968
969
970 /* back up to find appropriate staff */
971 for (mll_p = mll_p->prev; mll_p != (struct MAINLL *) 0;
972 mll_p = mll_p->prev) {
973 if (mll_p->str == S_STAFF) {
974 if (mll_p->u.staff_p->staffno == s) {
975 /* found the correct staff. check each voice */
976 for (v = 0; v < MAXVOICES; v++) {
977 chkxpgrp(mll_p->u.staff_p->groups_p[v],
978 mll_p->inputfile,
979 mll_p->inputlineno);
980 }
981 return;
982 }
983 else if (mll_p->u.staff_p->staffno < s) {
984 /* user must have increased the number of
985 * staffs as well, so the staff in question
986 * didn't exist in previous measure */
987 return;
988 }
989 }
990 }
991}
992\f
993
994/* find the last group in a list of grpsyls. If it has any ties on it,
995 * print warning message for trying to tie across a transposition, and discard
996 * the tie(s). */
997
998static void
999chkxpgrp(gs_p, inputfile, lineno)
1000
1001struct GRPSYL *gs_p; /* check this grpsyl list */
1002char *inputfile; /* for error message */
1003int lineno;
1004
1005{
1006 register int n; /* index through notelist */
1007
1008
1009 /* find last group in list */
1010 for ( ; gs_p != (struct GRPSYL *) 0; gs_p = gs_p->next) {
1011
1012 if (gs_p->next == (struct GRPSYL *) 0) {
1013 /* this is the last group in the measure. See if
1014 * it has any ties on it */
1015 for (n = 0; n < gs_p->nnotes; n++) {
1016 if (gs_p->notelist[n].tie == YES) {
1017 /* Aha! User tried to do a tie over
1018 * a transpose */
1019 l_warning(inputfile, lineno,
1020 "can't tie into transposition change (use slur)");
1021 /* cancel any and all ties on this grp,
1022 * and return, so we don't print more
1023 * than one error per group */
1024 for (n = 0; n < gs_p->nnotes; n++) {
1025 gs_p->notelist[n].tie = NO;
1026 }
1027 gs_p->tie = NO;
1028 return;
1029 }
1030 }
1031 }
1032 }
1033}
1034\f
1035
1036/* On tablature staffs, if two consecutive groups are tied together,
1037 * normally the frets are not printed for the second group, so we need
1038 * to set the inhibitprint flag on the group. However if there is any
1039 * reason why inhibiting printing on a given group isn't a good idea,
1040 * we won't set the inhibitprint flag. So this function checks all the
1041 * possible reasons for not setting inhibitprint, and if none of them
1042 * apply, then it is set.
1043 */
1044
1045static void
1046set_inhibitprint_if_appropriate(gs_p, mll_p)
1047
1048struct GRPSYL *gs_p;
1049struct MAINLL *mll_p;
1050
1051{
1052 struct GRPSYL *nextgs_p; /* the group after gs_p */
1053 struct GRPSYL *following_p; /* the group after next_gs_p */
1054 int n; /* index through notelist */
1055
1056
1057
1058 if ((nextgs_p = nextgrpsyl(gs_p, &mll_p)) == (struct GRPSYL *) 0) {
1059 /* no next group, so nothing to set */
1060 return;
1061 }
1062
1063 /* if this group and next group don't have same number of notes,
1064 * then there won't be an inhibitprint on the next group */
1065 if (gs_p->nnotes == 0 || gs_p->nnotes != nextgs_p->nnotes) {
1066 return;
1067 }
1068
1069 /* if next group has a "with" list, no inhibitprint */
1070 if (nextgs_p->nwith != 0) {
1071 return;
1072 }
1073
1074 for (n = 0; n < gs_p->nnotes; n++) {
1075 /* if any notes in this group are not tied, then there won't be
1076 * an inhibitprint on the next group */
1077 if (gs_p->notelist[n].tie == NO) {
1078 return;
1079 }
1080
1081 /* if next group has any slides to/from nowhere, or slurs
1082 * to the next group, it won't get inhibitprint set */
1083 if (nextgs_p->notelist[n].nslurto != 0) {
1084 return;
1085 }
1086 }
1087
1088 /* next group has a bend of any sort, it doesn't get inhibitprint */
1089 for (n = 0; n < nextgs_p->nnotes; n++) {
1090 if (HASBEND(nextgs_p->notelist[n]) == YES) {
1091 return;
1092 }
1093 }
1094
1095 /* if group following next group has a non-prebend bend, then the
1096 * next group does not get inhibitprint */
1097 if ((following_p = nextgrpsyl(nextgs_p, &mll_p)) != (struct GRPSYL *) 0) {
1098 for (n = 0; n < following_p->nnotes; n++) {
1099 if (HASBEND(following_p->notelist[n]) == YES &&
1100 following_p->notelist[n].FRETNO == NOFRET) {
1101 return;
1102 }
1103 }
1104 }
1105
1106 /* Whew! If we got here, the group passed all the tests to have its
1107 * inhibitprint flag set, so set it */
1108 nextgs_p->inhibitprint = YES;
1109}