Commit | Line | Data |
---|---|---|
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 */ | |
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 | } |