chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / tie.c
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 */
21 struct 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 */
32 struct TIECARRY *Tiecarryinfolist_p [MAXSTAFFS + 1] [MAXVOICES];
33
34 /* flag to mark if there are any carry ins */
35 static short Have_carry_ins = NO;
36
37
38 /* static functions */
39 static void do_tie P((struct MAINLL *mll_p));
40 static void do_group_ties P((struct GRPSYL *gs_p, struct MAINLL *mll_p));
41 static void chk_slides P((struct NOTE *note_p, struct GRPSYL *gs_p,
42                 struct MAINLL *mll_p));
43 static void chk_following4slide P((struct NOTE *note_p, struct GRPSYL *gs_p,
44                 struct MAINLL *mll_p));
45 static struct MAINLL *do_carry_ties P((struct MAINLL *staff_mll_p,
46                 struct MAINLL *bar_mll_p));
47 static void savetieinfo P((struct MAINLL *mll_p, struct GRPSYL *gs_p));
48 static 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));
51 static void carryin_ties P((struct MAINLL *mll_p));
52 static void add_carryin P((struct STAFF *staff_p));
53 static void free_carryin_info P((void));
54 static void free_cinfo P((struct TIECARRY *carryinfo_p));
55 static void chk4xpose P((struct MAINLL *mll_p));
56 static void chkxpstaff P((struct MAINLL *mll_p, int s));
57 static void chkxpgrp P((struct GRPSYL *gs_p, char *inputfile, int lineno));
58 static 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
66 void
67 tie()
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
108 static void
109 do_tie(mll_p)
110
111 struct 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
153 static void
154 do_group_ties(gs_p, mll_p)
155
156 struct GRPSYL *gs_p;            /* do ties from this group */
157 struct 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
347 static void
348 chk_slides(note_p, gs_p, mll_p)
349
350 struct NOTE *note_p;            /* this note might have slides */
351 struct GRPSYL *gs_p;            /* note is in this group */
352 struct 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
400 static void
401 chk_following4slide(note_p, gs_p, mll_p)
402
403 struct NOTE *note_p;    /* this note has a slide to a specific fret */
404 struct GRPSYL *gs_p;    /* note is in this group */
405 struct 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
449 struct NOTE *
450 find_matching_note(gs_p, letter, octave, type)
451
452 struct GRPSYL *gs_p;    /* which GRPSYL we're tying to */
453 int letter;             /* find note with this pitch, 'a' to 'g' */
454 int octave;             /* find note with this octave */
455 char *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
564 struct GRPSYL *
565 find_next_group(mll_p, gs_p, type)
566
567 struct MAINLL *mll_p;           /* current place in main list */
568 struct GRPSYL *gs_p;            /* group to tie from */
569 char *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
591 void
592 tie_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
652 static struct MAINLL *
653 do_carry_ties(staff_mll_p, bar_mll_p)
654
655 struct MAINLL *staff_mll_p;     /* first staff in measure which ends on
656                                  * bar that begins an ending */
657 struct 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
699 static void
700 savetieinfo(mll_p, gs_p)
701
702 struct MAINLL *mll_p;           /* main list struct that gs_p is connected to */
703 struct 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
745 static void
746 do_save_tieinfo(staffno, vno, letter, octave, curveno, mll_p, gs_p, is_bend)
747
748 int staffno;
749 int vno;
750 int letter;     /* a to g */
751 int octave;
752 int curveno;
753 struct MAINLL *mll_p;   /* points to first group */
754 struct GRPSYL *gs_p;    /* group of first note */
755 int 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
777 static void
778 carryin_ties(mll_p)
779
780 struct 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
805 static void
806 add_carryin(staff_p)
807
808 struct 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
868 static void
869 free_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
889 static void
890 free_cinfo(carryinfo_p)
891
892 struct 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
907 static void
908 chk4xpose(mll_p)
909
910 struct 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
960 static void
961 chkxpstaff(mll_p, s)
962
963 struct MAINLL *mll_p;   /* look backward in main list from here */
964 int 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
998 static void
999 chkxpgrp(gs_p, inputfile, lineno)
1000
1001 struct GRPSYL *gs_p;    /* check this grpsyl list */
1002 char *inputfile;        /* for error message */
1003 int 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
1045 static void
1046 set_inhibitprint_if_appropriate(gs_p, mll_p)
1047
1048 struct GRPSYL *gs_p;
1049 struct 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 }