| 1 | |
| 2 | /* Copyright (c) 1999, 2000, 2001, 2002, 2003, 2004, 2006 by Arkkra Enterprises */ |
| 3 | /* All rights reserved */ |
| 4 | |
| 5 | /* This file contains functions for mapping input to individual voices. |
| 6 | * The user can give a single line of input |
| 7 | * that gets expanded into several voices. |
| 8 | * There are two flavors of this: |
| 9 | * voice-at-a-time input and chord-at-a-time input. |
| 10 | * For the former, the GRPSYL list just gets cloned and altered as needed. |
| 11 | * For the latter, brand new GRPSYL lists are created |
| 12 | * by distributing individual notes from the user's input. |
| 13 | * For any given staff/voice, only one type of input can be used per measure. |
| 14 | * For chord-at-a-time, a given staff/voice can appear more than once |
| 15 | * within a single input line, but not on multiple input lines per measure. |
| 16 | */ |
| 17 | |
| 18 | #include "defines.h" |
| 19 | #include "structs.h" |
| 20 | #include "globals.h" |
| 21 | |
| 22 | /* mark whether we mapped user data, only mapped implicit spaces, or nothing */ |
| 23 | #define MAPPED_NOTHING (0) |
| 24 | #define MAPPED_IMPLICIT (1) |
| 25 | #define MAPPED_EXPLICIT (2) |
| 26 | |
| 27 | /* This struct tells how to map one note for chord-at-a-time input, |
| 28 | * i.e., which staff/voice combinations it should be mapped to. |
| 29 | * Each map item in input (semicolon-separated) |
| 30 | * gets saved in one of these. */ |
| 31 | struct NOTEMAP { |
| 32 | struct SVRANGELIST *svlist_p; /* staffs/voices to map this note to */ |
| 33 | struct NOTEMAP *next; /* linked list */ |
| 34 | }; |
| 35 | |
| 36 | /* This struct gives the mapping for a particular number of notes. |
| 37 | * The set of things inside a pair of brackets gets saved in one of these. */ |
| 38 | struct MAP { |
| 39 | int num_entries; /* how many item in list */ |
| 40 | struct NOTEMAP *notemap_p; /* one entry for each note in chord */ |
| 41 | struct MAP *next; /* linked list */ |
| 42 | }; |
| 43 | |
| 44 | /* This points to the list of maps, or to 0 if doing voice-at-a-time input */ |
| 45 | static struct MAP *Map_p; |
| 46 | /* This points to where to add to the map list */ |
| 47 | static struct MAP **End_map_p_p = &Map_p; |
| 48 | |
| 49 | /* This is where to insert the next NOTEMAP */ |
| 50 | static struct NOTEMAP **Note_p_p; |
| 51 | |
| 52 | /* It is handy to be able to treat both input styles identically |
| 53 | * as much as possible. So for when input is voice-at-a-time, it can be handy |
| 54 | * to have a MAP that just points to Svrangelist_p. These two structs are |
| 55 | * used for that purpose. Since the value of Svrangelist_p changes |
| 56 | * at runtime, we have to set Sv_notemap->svlist_p each time |
| 57 | * before these are used. */ |
| 58 | static struct NOTEMAP Sv_notemap = { |
| 59 | (struct SVRANGELIST *) 0, (struct NOTEMAP *) 0 |
| 60 | }; |
| 61 | static struct MAP Voice_at_a_time_map = { |
| 62 | 1, &Sv_notemap, (struct MAP *) 0 |
| 63 | }; |
| 64 | |
| 65 | /* Keep track of which input style was used */ |
| 66 | static short Input_style[MAXSTAFFS][MAXVOICES]; |
| 67 | |
| 68 | static int map_groups P((void)); |
| 69 | static void clean_map_data P((void)); |
| 70 | static void free_maps P((struct MAP *map_p)); |
| 71 | static void free_notemaps P((struct NOTEMAP *notemap_p)); |
| 72 | static struct NOTEMAP *find_notemap P((int num_notes)); |
| 73 | static void map1note P((struct GRPSYL *from_gs_p, int n, int staff, int voice, |
| 74 | short allocated[MAXSTAFFS][MAXVOICES])); |
| 75 | static void do_link_groups P((void)); |
| 76 | static void link_a_grouplist P((int staffno, int vno, int copies)); |
| 77 | static void convert_rest_space P((struct GRPSYL *grpsyl_p, int staffno, int vno)); |
| 78 | static void conv_grpsyl P((struct GRPSYL *grpsyl_p, int staffno, int vno)); |
| 79 | static void mult_def P((int staff, int voice)); |
| 80 | \f |
| 81 | |
| 82 | /* Initialize Input_style to default of IS_VOICE_INPUT */ |
| 83 | |
| 84 | void |
| 85 | reset_input_style() |
| 86 | |
| 87 | { |
| 88 | int staff; |
| 89 | int voice; |
| 90 | |
| 91 | for (staff = 0; staff < MAXSTAFFS; staff++) { |
| 92 | for (voice = 0; voice < MAXVOICES; voice++) { |
| 93 | Input_style[staff][voice] = IS_VOICE_INPUT; |
| 94 | } |
| 95 | } |
| 96 | } |
| 97 | \f |
| 98 | |
| 99 | /* Return the current input style for a given staff/voice */ |
| 100 | |
| 101 | int |
| 102 | input_style(staff, voice) |
| 103 | |
| 104 | int staff; |
| 105 | int voice; |
| 106 | |
| 107 | { |
| 108 | return(Input_style[staff-1][voice-1]); |
| 109 | } |
| 110 | \f |
| 111 | |
| 112 | /* This is called when a '[' is encountered in input, starting a new map */ |
| 113 | |
| 114 | void |
| 115 | begin_map() |
| 116 | |
| 117 | { |
| 118 | struct MAP *new_p; |
| 119 | |
| 120 | |
| 121 | /* allocate space for a new map */ |
| 122 | CALLOC(MAP, new_p, 1); |
| 123 | |
| 124 | /* Keep track of where to link on the first NOTEMAP */ |
| 125 | Note_p_p = &(new_p->notemap_p); |
| 126 | |
| 127 | /* Add to MAP list */ |
| 128 | *End_map_p_p = new_p; |
| 129 | |
| 130 | begin_sv_list(); |
| 131 | } |
| 132 | \f |
| 133 | |
| 134 | /* Save one item of a map. Items are the semicolon-separated specifications. */ |
| 135 | |
| 136 | void |
| 137 | map_item() |
| 138 | { |
| 139 | CALLOC(NOTEMAP, *Note_p_p, 1); |
| 140 | |
| 141 | /* Save the current range */ |
| 142 | (*Note_p_p)->svlist_p = Svrangelist_p; |
| 143 | ((*End_map_p_p)->num_entries)++; |
| 144 | |
| 145 | /* prepare for another, if any */ |
| 146 | Note_p_p = &( (*Note_p_p)->next); |
| 147 | |
| 148 | begin_sv_list(); |
| 149 | begin_range(PL_UNKNOWN); |
| 150 | } |
| 151 | \f |
| 152 | |
| 153 | /* At the end of a map specification, this function is called to save the |
| 154 | * info about the map for later use, and prepare for another map, if any. |
| 155 | */ |
| 156 | |
| 157 | void |
| 158 | end_map() |
| 159 | |
| 160 | { |
| 161 | /* prepare for another map, if any */ |
| 162 | End_map_p_p = &( (*End_map_p_p)->next); |
| 163 | |
| 164 | begin_range(Place); |
| 165 | } |
| 166 | \f |
| 167 | |
| 168 | /* Map chord-at-a-time input so it looks just like voice-at-a-time input. |
| 169 | * Return YES if current measure is chord-at-a-time, and thus |
| 170 | * mapping was done, NO if current measure is voice-at-a-time. |
| 171 | */ |
| 172 | |
| 173 | static int |
| 174 | map_groups() |
| 175 | |
| 176 | { |
| 177 | struct MAP *map_p; |
| 178 | /* Multiple notes in a chord might get mapped to a single staff/voice. |
| 179 | * In that case, after the first note for that staff/voice, |
| 180 | * we need to just add a note to the existing GRPSYL rather than |
| 181 | * allocating a new one. This keeps track of whether we have already |
| 182 | * allocated a GRPSYL for the current chord of a given staff/voice. */ |
| 183 | short allocated[MAXSTAFFS][MAXVOICES]; |
| 184 | /* This array tells us which staffs/voices we are mapping things to */ |
| 185 | short used[MAXSTAFFS][MAXVOICES]; |
| 186 | /* This array will have MAPPED_EXPLICIT |
| 187 | * in entries where we mapped actual user data. |
| 188 | * If we only mapped implicit spaces (MAPPED_IMPLICIT), |
| 189 | * we can treat things as if user didn't use the voice |
| 190 | * on this input line. */ |
| 191 | short mapped_something[MAXSTAFFS][MAXVOICES]; |
| 192 | /* This says if we've printed an error yet for multiply defined voice, |
| 193 | * to make sure we only print it once. */ |
| 194 | short printed_mult_err[MAXSTAFFS][MAXVOICES]; |
| 195 | /* This tells which numbers of notes we have maps for. */ |
| 196 | short have_map[MAXHAND]; |
| 197 | int s; /* staff number */ |
| 198 | int v; /* voice number */ |
| 199 | int n; /* note index */ |
| 200 | struct NOTEMAP *notemap_p; /* how to map notes to voices */ |
| 201 | struct SVRANGELIST *svr_p; |
| 202 | struct RANGELIST *sr_p; /* range of staffs being defined */ |
| 203 | struct RANGELIST *vr_p; /* range of vno's being defined */ |
| 204 | struct GRPSYL *gs_p; |
| 205 | struct GRPSYL *g_p; |
| 206 | int errors; |
| 207 | |
| 208 | |
| 209 | if (Map_p == (struct MAP *) 0) { |
| 210 | /* not chord-at-a-time mapping, so nothing to do here */ |
| 211 | return(NO); |
| 212 | } |
| 213 | |
| 214 | /* remember current error count */ |
| 215 | errors = Errorcount; |
| 216 | |
| 217 | /* Initialize arrays. These will later tell us |
| 218 | * which GRPSYL lists we are mapping to, and whether we mapped |
| 219 | * any actual user input, or just implicit spaces. */ |
| 220 | for (s = 0; s < Score.staffs; s++) { |
| 221 | for (v = 0; v < MAXVOICES; v++) { |
| 222 | used[s][v] = NO; |
| 223 | mapped_something[s][v] = MAPPED_NOTHING; |
| 224 | printed_mult_err[s][v] = NO; |
| 225 | } |
| 226 | } |
| 227 | /* This tells for which numbers of notes we have maps */ |
| 228 | for (n = 0; n < MAXHAND; n++) { |
| 229 | have_map[n] = NO; |
| 230 | } |
| 231 | |
| 232 | /* Do some error checking on the MAP list */ |
| 233 | for (map_p = Map_p; map_p != (struct MAP *) 0; map_p = map_p->next) { |
| 234 | |
| 235 | if (have_map[map_p->num_entries] == YES) { |
| 236 | l_yyerror(Curr_filename, yylineno, |
| 237 | "more than one map for chords with %d notes", |
| 238 | map_p->num_entries); |
| 239 | continue; |
| 240 | } |
| 241 | else { |
| 242 | have_map[map_p->num_entries] = YES; |
| 243 | } |
| 244 | |
| 245 | for (notemap_p = map_p->notemap_p; |
| 246 | notemap_p != (struct NOTEMAP *) 0; |
| 247 | notemap_p = notemap_p->next) { |
| 248 | for (svr_p = notemap_p->svlist_p; |
| 249 | svr_p != (struct SVRANGELIST *) 0; |
| 250 | svr_p = svr_p->next) { |
| 251 | for (sr_p = svr_p->stafflist_p; sr_p != 0; |
| 252 | sr_p = sr_p->next) { |
| 253 | for (s = sr_p->begin; s <= sr_p->end; s++) { |
| 254 | |
| 255 | if (s > Score.staffs) { |
| 256 | l_yyerror(Curr_filename, |
| 257 | yylineno, |
| 258 | "staff %d does not exist", |
| 259 | s); |
| 260 | continue; |
| 261 | } |
| 262 | |
| 263 | for (vr_p = svr_p->vnolist_p; vr_p != 0; |
| 264 | vr_p = vr_p->next) { |
| 265 | for (v = vr_p->begin; |
| 266 | v <= vr_p->end; v++) { |
| 267 | |
| 268 | /* make sure voice exists */ |
| 269 | if (v > 1 && svpath(s, VSCHEME) |
| 270 | ->vscheme == V_1) { |
| 271 | l_yyerror(Curr_filename, |
| 272 | yylineno, |
| 273 | "there is no voice %d on staff %d", |
| 274 | v, s); |
| 275 | } |
| 276 | used[s-1][v-1] = YES; |
| 277 | Input_style[s-1][v-1] |
| 278 | = IS_CHORD_INPUT; |
| 279 | } |
| 280 | } |
| 281 | } |
| 282 | } |
| 283 | } |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | if (Errorcount > errors) { |
| 288 | clean_map_data(); |
| 289 | return(YES); |
| 290 | } |
| 291 | |
| 292 | /* process each chord in the GRPSYL list */ |
| 293 | for (gs_p = Curr_gs_list_p; gs_p != (struct GRPSYL *) 0; |
| 294 | gs_p = gs_p->next) { |
| 295 | /* initialize the allocation array for current chord */ |
| 296 | for (s = 0; s < Score.staffs; s++) { |
| 297 | for (v = 0; v < MAXVOICES; v++) { |
| 298 | allocated[s][v] = NO; |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | /* With voice-at-a-time input, we allow the first group |
| 303 | * to have no pitch specified iff it is on a 1-line staff. |
| 304 | * For chord-at-a-time, to allow that |
| 305 | * we would have to allow a mapping of zero notes, |
| 306 | * which doesn't make sense, or map an implicit note, |
| 307 | * which seems questionable at best. |
| 308 | * If there is a mixture of 1-line and not-1-line |
| 309 | * staffs being mapped, things get even more confusing. |
| 310 | * So we disallow implicit pitch on chord-at-at-time. */ |
| 311 | if (gs_p->nnotes == 1 && gs_p->notelist[0].letter == PP_NO_PITCH) { |
| 312 | l_yyerror(Curr_filename, yylineno, "no notes specified"); |
| 313 | notemap_p = (struct NOTEMAP *) 0; |
| 314 | } |
| 315 | else { |
| 316 | /* Find the pattern matching the number of notes. |
| 317 | * If none is found, this will return 0, and the 'for' |
| 318 | * below will get skipped, and we'll add spaces */ |
| 319 | notemap_p = find_notemap(gs_p->nnotes); |
| 320 | } |
| 321 | |
| 322 | /* Go through each note in the chord, and copy it |
| 323 | * to the appropriate staffs/voices */ |
| 324 | for (n = 0; notemap_p != (struct NOTEMAP *) 0; |
| 325 | n++, notemap_p = notemap_p->next) { |
| 326 | for (svr_p = notemap_p->svlist_p; |
| 327 | svr_p != (struct SVRANGELIST *) 0; |
| 328 | svr_p = svr_p->next) { |
| 329 | for (sr_p = svr_p->stafflist_p; sr_p != 0; |
| 330 | sr_p = sr_p->next) { |
| 331 | for (s = sr_p->begin; s <= sr_p->end; s++) { |
| 332 | for (vr_p = svr_p->vnolist_p; vr_p != 0; |
| 333 | vr_p = vr_p->next) { |
| 334 | for (v = vr_p->begin; |
| 335 | v <= vr_p->end; v++) { |
| 336 | /* If we have not yet mapped |
| 337 | * anything from the current |
| 338 | * input line, yet there is |
| 339 | * something in the grpsyl |
| 340 | * list for this staff/voice, |
| 341 | * that means user must have |
| 342 | * already defined data for |
| 343 | * this staff/voice on some |
| 344 | * other input line, and thus |
| 345 | * is not allowed to map |
| 346 | * anything from the current |
| 347 | * line. */ |
| 348 | if (mapped_something[s-1][v-1] |
| 349 | == MAPPED_NOTHING |
| 350 | && Staffmap_p[s]->u.staff_p->groups_p[v-1] != 0 |
| 351 | && printed_mult_err[s-1][v-1] == NO) { |
| 352 | mult_def(s, v); |
| 353 | printed_mult_err[s-1][v-1] = YES; |
| 354 | continue; |
| 355 | } |
| 356 | map1note(gs_p, n, s, v, |
| 357 | allocated); |
| 358 | mapped_something[s-1][v-1] |
| 359 | = MAPPED_EXPLICIT; |
| 360 | } |
| 361 | } |
| 362 | } |
| 363 | } |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | /* For any staff/voice that is being mapped to, but which |
| 368 | * didn't get anything mapped for this particular chord, |
| 369 | * add a space group. This could happen either because |
| 370 | * user specified several patterns and some patterns don't |
| 371 | * contain all the staffs/voices, which implies they want |
| 372 | * us to fill in spaces, or because there was an error in |
| 373 | * input. If there was an error, it's still nice to add the |
| 374 | * space, because it prevents extra error messages */ |
| 375 | for (s = 1; s <= Score.staffs; s++) { |
| 376 | for (v = 1; v <= MAXVOICES; v++) { |
| 377 | /* If we haven't mapped anything to this |
| 378 | * voice, but there is something there, |
| 379 | * user must have defined it on an earlier |
| 380 | * input line. In that case we should leave |
| 381 | * it be, because either (1) user didn't |
| 382 | * actually use any pattern that uses this |
| 383 | * voice, or (2) they multiply defined the |
| 384 | * voice, in which case the error is caught |
| 385 | * elsewhere. In either case, their |
| 386 | * earlier input should stand. */ |
| 387 | if (mapped_something[s-1][v-1] == MAPPED_NOTHING |
| 388 | && Staffmap_p[s]->u.staff_p->groups_p[v-1] != 0) { |
| 389 | continue; |
| 390 | } |
| 391 | |
| 392 | if (used[s-1][v-1] == YES && |
| 393 | allocated[s-1][v-1] == NO) { |
| 394 | map1note(gs_p, -1, s, v, allocated); |
| 395 | if (mapped_something[s-1][v-1] != |
| 396 | MAPPED_EXPLICIT) { |
| 397 | mapped_something[s-1][v-1] |
| 398 | = MAPPED_IMPLICIT; |
| 399 | } |
| 400 | } |
| 401 | } |
| 402 | } |
| 403 | } |
| 404 | |
| 405 | /* If this particular input line didn't actually use some of the |
| 406 | * patterns, some voices might not *really* have been used--we |
| 407 | * merely filled in implicit spaces for it. So we can undo that |
| 408 | * so user can specify the voice via voice-at-a-time if they want to. |
| 409 | * If they don't, the regular filling in of missing voices with |
| 410 | * implicit spaces will happen later. */ |
| 411 | for (s = 0; s < Score.staffs; s++) { |
| 412 | for (v = 0; v < MAXVOICES; v++) { |
| 413 | if (used[s][v] == YES && |
| 414 | mapped_something[s][v] != MAPPED_EXPLICIT) { |
| 415 | used[s][v] = NO; |
| 416 | Input_style[s][v] = IS_VOICE_INPUT; |
| 417 | |
| 418 | /* If only implict, we free that up */ |
| 419 | if (mapped_something[s][v] == MAPPED_IMPLICIT) { |
| 420 | free_grpsyls(Staffmap_p[s+1]->u.staff_p->groups_p[v]); |
| 421 | Staffmap_p[s+1]->u.staff_p->groups_p[v] = 0; |
| 422 | } |
| 423 | } |
| 424 | } |
| 425 | } |
| 426 | |
| 427 | /* Now we can go through and free up any wasted space */ |
| 428 | for (s = 0; s < Score.staffs; s++) { |
| 429 | for (v = 0; v < MAXVOICES; v++) { |
| 430 | if (used[s][v] == YES) { |
| 431 | /* Rests and spaces get moved from |
| 432 | * NOTE pseudo-pitches to GRPSYL */ |
| 433 | convert_rest_space(Staffmap_p[s+1]->u. |
| 434 | staff_p->groups_p[v], s+1, v+1); |
| 435 | for (g_p = Staffmap_p[s+1]->u.staff_p->groups_p[v]; |
| 436 | g_p != (struct GRPSYL *) 0; |
| 437 | g_p = g_p->next) { |
| 438 | resize_notelist(g_p); |
| 439 | } |
| 440 | } |
| 441 | } |
| 442 | } |
| 443 | |
| 444 | clean_map_data(); |
| 445 | |
| 446 | /* Everything in the original GRPSYL list |
| 447 | * has been copied to other lists, so original can be freed */ |
| 448 | free_grpsyls(gs_p); |
| 449 | |
| 450 | return(YES); |
| 451 | } |
| 452 | \f |
| 453 | |
| 454 | /* map one note to one staff/voice */ |
| 455 | |
| 456 | static void |
| 457 | map1note(from_gs_p, n, staff, voice, allocated) |
| 458 | |
| 459 | struct GRPSYL *from_gs_p; /* copy from here */ |
| 460 | int n; /* copy the nth note in from_gs_p, or if -1, |
| 461 | * create a space group */ |
| 462 | int staff; |
| 463 | int voice; |
| 464 | short allocated[MAXSTAFFS][MAXVOICES]; /* tracks whether to allocate a new |
| 465 | * GRPSYL; may be updated */ |
| 466 | |
| 467 | { |
| 468 | struct GRPSYL *to_gs_p; /* where to map note to */ |
| 469 | struct GRPSYL **add_p_p; /* where to add to_gs_p */ |
| 470 | struct NOTE *from_note_p; |
| 471 | struct NOTE *to_note_p; |
| 472 | struct GRPSYL *prev; /* value to set to_gs_p->prev to */ |
| 473 | |
| 474 | |
| 475 | /* If original group is a grace group, we don't need to add a |
| 476 | * space group, since grace already take no time */ |
| 477 | if (n == -1 && from_gs_p->grpvalue == GV_ZERO) { |
| 478 | return; |
| 479 | } |
| 480 | |
| 481 | /* If this is the first note allocated to this staff/voice for |
| 482 | * current chord, have to allocate a GRPSYL for it. */ |
| 483 | if (allocated [staff - 1] [voice - 1] == NO) { |
| 484 | to_gs_p = newGRPSYL(GS_GROUP); |
| 485 | copy_attributes(to_gs_p, from_gs_p); |
| 486 | /* by the time we get here, we've already gone past the |
| 487 | * newline, so the input line number is one too much */ |
| 488 | to_gs_p->inputlineno--; |
| 489 | |
| 490 | allocated [staff - 1] [voice - 1] = YES; |
| 491 | |
| 492 | /* Add to end of list */ |
| 493 | prev = (struct GRPSYL *) 0; |
| 494 | for (add_p_p = &(Staffmap_p[staff]->u.staff_p->groups_p[voice-1]); |
| 495 | *add_p_p != (struct GRPSYL *) 0; |
| 496 | add_p_p = &((*add_p_p)->next) ) { |
| 497 | prev = *add_p_p; |
| 498 | } |
| 499 | to_gs_p->prev = prev; |
| 500 | *add_p_p = to_gs_p; |
| 501 | |
| 502 | /* copy the other attributes */ |
| 503 | to_gs_p->staffno = staff; |
| 504 | to_gs_p->vno = voice; |
| 505 | to_gs_p->basictime = from_gs_p->basictime; |
| 506 | to_gs_p->fulltime = from_gs_p->fulltime; |
| 507 | to_gs_p->dots = from_gs_p->dots; |
| 508 | to_gs_p->is_meas = from_gs_p->is_meas; |
| 509 | to_gs_p->tuploc = from_gs_p->tuploc; |
| 510 | to_gs_p->tupcont = from_gs_p->tupcont; |
| 511 | to_gs_p->tupside = from_gs_p->tupside; |
| 512 | to_gs_p->beamloc = from_gs_p->beamloc; |
| 513 | to_gs_p->breakbeam = from_gs_p->breakbeam; |
| 514 | to_gs_p->beamto = from_gs_p->beamto; |
| 515 | to_gs_p->printtup = from_gs_p->printtup; |
| 516 | to_gs_p->tie = from_gs_p->tie; |
| 517 | to_gs_p->inhibitprint = from_gs_p->inhibitprint; |
| 518 | to_gs_p->ho_usage = from_gs_p->ho_usage; |
| 519 | to_gs_p->ho_value = from_gs_p->ho_value; |
| 520 | } |
| 521 | else { |
| 522 | /* find the last group for this staff/voice */ |
| 523 | for (to_gs_p = Staffmap_p[staff]->u.staff_p->groups_p[voice-1]; |
| 524 | to_gs_p->next != (struct GRPSYL *) 0; |
| 525 | to_gs_p = to_gs_p->next) { |
| 526 | ; |
| 527 | } |
| 528 | } |
| 529 | |
| 530 | /* Special case: If n == -1, make this a space group */ |
| 531 | if (n == -1) { |
| 532 | to_gs_p->grpcont = GC_SPACE; |
| 533 | /* some things don't make sense with space, |
| 534 | * so nullify the things that just apply to notes */ |
| 535 | to_gs_p->grpvalue = GV_NORMAL; |
| 536 | to_gs_p->headshape = HS_UNKNOWN; |
| 537 | to_gs_p->grpsize = GS_NORMAL; |
| 538 | to_gs_p->stemdir = UNKNOWN; |
| 539 | to_gs_p->stemlen = STEMLEN_UNKNOWN; |
| 540 | to_gs_p->roll = NOITEM; |
| 541 | to_gs_p->beamloc = NOITEM; |
| 542 | to_gs_p->breakbeam = NO; |
| 543 | to_gs_p->beamto = CS_SAME; |
| 544 | to_gs_p->stemto = CS_SAME; |
| 545 | to_gs_p->slash_alt = 0; |
| 546 | return; |
| 547 | } |
| 548 | |
| 549 | from_note_p = &(from_gs_p->notelist[n]); |
| 550 | if (Doing_tab_staff == YES) { |
| 551 | /* fret, nticks, and bendstring exist in from_note_p |
| 552 | * in an internal format, whereas add_note() needs them |
| 553 | * in something close to user input format, |
| 554 | * so we have to reconstruct |
| 555 | * what the user input must have been. */ |
| 556 | add_note(to_gs_p, from_gs_p->notelist[n].letter, |
| 557 | from_note_p->accidental, |
| 558 | TMP_FRET(from_note_p), |
| 559 | TMP_NTICKS(from_note_p), |
| 560 | from_note_p->acc_has_paren, |
| 561 | (HASBEND(from_gs_p->notelist[n]) |
| 562 | ? bend_string(from_note_p) |
| 563 | : (char *) 0) ); |
| 564 | } |
| 565 | else { |
| 566 | add_note(to_gs_p, from_gs_p->notelist[n].letter, |
| 567 | from_note_p->accidental, |
| 568 | from_note_p->octave, |
| 569 | 0, |
| 570 | from_note_p->acc_has_paren, |
| 571 | (char *) 0); |
| 572 | } |
| 573 | |
| 574 | /* copy remaining note attributes: tie, slur, etc */ |
| 575 | to_note_p = &(to_gs_p->notelist[to_gs_p->nnotes - 1]); |
| 576 | to_note_p->tie = from_note_p->tie; |
| 577 | to_note_p->tiestyle = from_note_p->tiestyle; |
| 578 | to_note_p->tiedir = from_note_p->tiedir; |
| 579 | to_note_p->nslurto = from_note_p->nslurto; |
| 580 | if (from_note_p->nslurto > 0) { |
| 581 | /* slurto lists cannot be safely shared, so make copy */ |
| 582 | MALLOC(SLURTO, to_note_p->slurtolist, |
| 583 | from_note_p->nslurto); |
| 584 | (void) memcpy(to_note_p->slurtolist, |
| 585 | from_note_p->slurtolist, |
| 586 | sizeof(struct SLURTO) * |
| 587 | from_note_p->nslurto); |
| 588 | } |
| 589 | else { |
| 590 | to_note_p->slurtolist = (struct SLURTO *) 0; |
| 591 | } |
| 592 | to_note_p->notesize = from_note_p->notesize; |
| 593 | to_note_p->note_has_paren = from_note_p->note_has_paren; |
| 594 | to_note_p->is_bend = from_note_p->is_bend; |
| 595 | to_note_p->smallbend = from_note_p->smallbend; |
| 596 | } |
| 597 | \f |
| 598 | |
| 599 | /* When done with temporary map data, clean everything up, to prepare |
| 600 | * for potentially getting another set of data */ |
| 601 | |
| 602 | static void |
| 603 | clean_map_data() |
| 604 | |
| 605 | { |
| 606 | /* free up the lists */ |
| 607 | free_maps(Map_p); |
| 608 | |
| 609 | /* reset pointers to be ready for more data */ |
| 610 | Map_p = (struct MAP *) 0; |
| 611 | End_map_p_p = &Map_p; |
| 612 | } |
| 613 | \f |
| 614 | |
| 615 | /* free up the MAP list and everything hanging off of it */ |
| 616 | |
| 617 | static void |
| 618 | free_maps(map_p) |
| 619 | |
| 620 | struct MAP *map_p; |
| 621 | |
| 622 | { |
| 623 | if (map_p == (struct MAP *) 0) { |
| 624 | /* end recursion */ |
| 625 | return; |
| 626 | } |
| 627 | |
| 628 | /* free the list hanging off of this struct */ |
| 629 | free_notemaps(map_p->notemap_p); |
| 630 | |
| 631 | /* recurse */ |
| 632 | free_maps(map_p->next); |
| 633 | |
| 634 | /* free the passed-in struct */ |
| 635 | FREE(map_p); |
| 636 | } |
| 637 | |
| 638 | /* free up a NOTEMAP list and everything hanging off of it */ |
| 639 | |
| 640 | static void |
| 641 | free_notemaps(notemap_p) |
| 642 | |
| 643 | struct NOTEMAP *notemap_p; |
| 644 | |
| 645 | { |
| 646 | if (notemap_p == (struct NOTEMAP *) 0) { |
| 647 | return; |
| 648 | } |
| 649 | |
| 650 | free_sv_list(notemap_p->svlist_p); |
| 651 | free_notemaps(notemap_p->next); |
| 652 | FREE(notemap_p); |
| 653 | } |
| 654 | \f |
| 655 | |
| 656 | /* Given a number of notes, find the NOTEMAP list for that many and return it. |
| 657 | * If not found, return 0. */ |
| 658 | |
| 659 | static struct NOTEMAP * |
| 660 | find_notemap(num_notes) |
| 661 | |
| 662 | int num_notes; |
| 663 | |
| 664 | { |
| 665 | struct MAP *m_p; |
| 666 | |
| 667 | for (m_p = Map_p; m_p != (struct MAP *) 0; m_p = m_p->next) { |
| 668 | if (m_p->num_entries == num_notes) { |
| 669 | return(m_p->notemap_p); |
| 670 | } |
| 671 | } |
| 672 | |
| 673 | l_yyerror(Curr_filename, yylineno, |
| 674 | "there is no bracketed mapping for chords containing %d note%s", num_notes, num_notes == 1 ? "" : "s"); |
| 675 | return ((struct NOTEMAP *) 0); |
| 676 | } |
| 677 | \f |
| 678 | |
| 679 | /* Once a measure-worth of data is gathered for one or more staffs/voices, |
| 680 | * link copies onto the appropriate STAFF structs */ |
| 681 | |
| 682 | void |
| 683 | link_groups() |
| 684 | |
| 685 | { |
| 686 | /* if haven't yet set up the STAFFs for this measure, do so now */ |
| 687 | create_staffs(); |
| 688 | |
| 689 | /* if we are in this function, user specified some music data */ |
| 690 | Got_some_data = YES; |
| 691 | Got_group = YES; |
| 692 | |
| 693 | /* do error check--can't have notes and multirest in same measure */ |
| 694 | if (Got_multirest == 1) { |
| 695 | report_mix_error(); |
| 696 | return; |
| 697 | } |
| 698 | |
| 699 | /* Do either chord-to-voice-mapping or standard voice mapping, |
| 700 | * as appropriate. */ |
| 701 | if (map_groups() == NO) { |
| 702 | do_link_groups(); |
| 703 | } |
| 704 | |
| 705 | /* re-initialize for next measure */ |
| 706 | Curr_gs_list_p = (struct GRPSYL *) 0; |
| 707 | free_rlists(); |
| 708 | } |
| 709 | \f |
| 710 | |
| 711 | /* Go through Svrangelist, creating copies of the GRPSYL lists and |
| 712 | * linking them to the appropriate STAFFs. */ |
| 713 | |
| 714 | static void |
| 715 | do_link_groups() |
| 716 | |
| 717 | { |
| 718 | struct SVRANGELIST *svr_p; /* list of ranges of staffs and vnos */ |
| 719 | register int s; /* staff index */ |
| 720 | register int v; /* voice index */ |
| 721 | struct RANGELIST *sr_p; /* range of staffs being defined */ |
| 722 | struct RANGELIST *vr_p; /* range of vno's being defined */ |
| 723 | int copies = 0; /* how many copies of grpsyl list made so far */ |
| 724 | |
| 725 | |
| 726 | for (svr_p = Svrangelist_p; svr_p != (struct SVRANGELIST *) 0; |
| 727 | svr_p = svr_p->next) { |
| 728 | |
| 729 | for (sr_p = svr_p->stafflist_p; sr_p != (struct RANGELIST *) 0; |
| 730 | sr_p = sr_p->next) { |
| 731 | |
| 732 | for (s = sr_p->begin; s <= sr_p->end; s++) { |
| 733 | |
| 734 | for (vr_p = svr_p->vnolist_p; |
| 735 | vr_p != (struct RANGELIST *) 0; |
| 736 | vr_p = vr_p->next) { |
| 737 | |
| 738 | for (v = vr_p->begin; |
| 739 | v <= vr_p->end; v++) { |
| 740 | link_a_grouplist(s, v, copies++); |
| 741 | } |
| 742 | } |
| 743 | } |
| 744 | } |
| 745 | } |
| 746 | } |
| 747 | \f |
| 748 | |
| 749 | /* connect list of GRPSYLs to a staff. If copies == 0, use the current |
| 750 | * grpsyl list, otherwise make a copy of it and use the copy */ |
| 751 | |
| 752 | static void |
| 753 | link_a_grouplist(staffno, vno, copies) |
| 754 | |
| 755 | int staffno; |
| 756 | int vno; |
| 757 | int copies; /* if non-zero, need to make a copy */ |
| 758 | |
| 759 | { |
| 760 | if (rangecheck(staffno, MINSTAFFS, Score.staffs, "staff number") |
| 761 | == NO) { |
| 762 | return; |
| 763 | } |
| 764 | |
| 765 | if (rangecheck(vno, MINVOICES, MAXVOICES, "voice number") == NO) { |
| 766 | return; |
| 767 | } |
| 768 | |
| 769 | if (Staffmap_p[staffno] == (struct MAINLL *) 0) { |
| 770 | return; |
| 771 | } |
| 772 | |
| 773 | if (Staffmap_p[staffno]->u.staff_p == (struct STAFF *) 0) { |
| 774 | pfatal("null staff pointer while linking group list"); |
| 775 | } |
| 776 | |
| 777 | if (Staffmap_p[staffno]->u.staff_p->groups_p[vno-1] |
| 778 | != (struct GRPSYL *) 0) { |
| 779 | mult_def(staffno, vno); |
| 780 | return; |
| 781 | } |
| 782 | |
| 783 | /* the first time through, we can use the |
| 784 | * existing list. After that we need to |
| 785 | * make a clone of the list */ |
| 786 | if (copies == 0) { |
| 787 | (Staffmap_p[staffno])->u.staff_p->groups_p[vno-1] |
| 788 | = Curr_gs_list_p; |
| 789 | convert_rest_space(Staffmap_p[staffno]->u. |
| 790 | staff_p->groups_p[vno-1], staffno, vno); |
| 791 | } |
| 792 | else { |
| 793 | (Staffmap_p[staffno])->u.staff_p->groups_p[vno-1] |
| 794 | = clone_gs_list(Curr_gs_list_p, YES); |
| 795 | } |
| 796 | } |
| 797 | \f |
| 798 | |
| 799 | /* With chord-at-a-time input style, it is legal to have |
| 800 | * a mixture of pitches, spaces, and rests. However, once |
| 801 | * everything has been distributed to individual voices, we need to check |
| 802 | * that there aren't still any mixtures, and convert the rest and |
| 803 | * space pseudo-notes into rest and space groups. Some error checks |
| 804 | * also get done that couldn't be done till after this conversion. */ |
| 805 | |
| 806 | static void |
| 807 | convert_rest_space(grpsyl_p, staffno, vno) |
| 808 | |
| 809 | struct GRPSYL *grpsyl_p; |
| 810 | int staffno; |
| 811 | int vno; |
| 812 | |
| 813 | { |
| 814 | for ( ; grpsyl_p != (struct GRPSYL *) 0; grpsyl_p = grpsyl_p->next) { |
| 815 | conv_grpsyl(grpsyl_p, staffno, vno); |
| 816 | } |
| 817 | } |
| 818 | \f |
| 819 | |
| 820 | /* Given a GRPSYL, convert all the rest and space |
| 821 | * pseudo notes to groups and do related error checking */ |
| 822 | |
| 823 | static void |
| 824 | conv_grpsyl(grpsyl_p, staffno, vno) |
| 825 | |
| 826 | struct GRPSYL *grpsyl_p; |
| 827 | int staffno; |
| 828 | int vno; |
| 829 | |
| 830 | { |
| 831 | int notes, rests, spaces, rpts;/* count how many of each in chord */ |
| 832 | int n; /* index through notes */ |
| 833 | |
| 834 | /* Count how many notes, rests, and spaces in the group */ |
| 835 | rests = spaces = notes = rpts = 0; |
| 836 | for (n = 0; n < grpsyl_p->nnotes; n++) { |
| 837 | if (grpsyl_p->notelist[n].letter == PP_REST) { |
| 838 | rests++; |
| 839 | } |
| 840 | else if (grpsyl_p->notelist[n].letter == PP_SPACE) { |
| 841 | spaces++; |
| 842 | } |
| 843 | else if (grpsyl_p->notelist[n].letter == PP_RPT) { |
| 844 | rpts++; |
| 845 | } |
| 846 | else { |
| 847 | notes++; |
| 848 | } |
| 849 | } |
| 850 | |
| 851 | /* Group may not mix space, rest, rpt, and notes */ |
| 852 | if (spaces > 0 && spaces != grpsyl_p->nnotes) { |
| 853 | l_yyerror(grpsyl_p->inputfile, grpsyl_p->inputlineno, |
| 854 | "staff %d voice %d: mixture of space and non-space", |
| 855 | staffno, vno); |
| 856 | return; |
| 857 | } |
| 858 | if (rests > 0 && rests != grpsyl_p->nnotes) { |
| 859 | l_yyerror(grpsyl_p->inputfile, grpsyl_p->inputlineno, |
| 860 | "staff %d voice %d: mixture of rest and non-rest", |
| 861 | staffno, vno); |
| 862 | return; |
| 863 | } |
| 864 | if (rpts > 0 && rpts != grpsyl_p->nnotes) { |
| 865 | l_yyerror(grpsyl_p->inputfile, grpsyl_p->inputlineno, |
| 866 | "staff %d voice %d: mixture of rpt and non-rpt", |
| 867 | staffno, vno); |
| 868 | return; |
| 869 | } |
| 870 | |
| 871 | /* convert rest, space, and rpt pseudo-notes to groups */ |
| 872 | if (notes < grpsyl_p->nnotes) { |
| 873 | if (rests > 0) { |
| 874 | /* This is actually a rest group */ |
| 875 | grpsyl_p->grpcont = GC_REST; |
| 876 | grpsyl_p->tie = NO; |
| 877 | /* If entire group was marked cue, leave it that way. |
| 878 | * Otherwise, if multiple rests map to this group, |
| 879 | * grpsize should be the biggest of them. |
| 880 | * So initialize to small size, |
| 881 | * and if we find any normal size, |
| 882 | * set to normal and jump out of the loop. */ |
| 883 | if (grpsyl_p->grpsize != GS_SMALL) { |
| 884 | grpsyl_p->grpsize = GS_SMALL; |
| 885 | for (n = 0; n < grpsyl_p->nnotes; n++) { |
| 886 | if (grpsyl_p->notelist[n].notesize == GS_NORMAL) { |
| 887 | |
| 888 | grpsyl_p->grpsize = GS_NORMAL; |
| 889 | break; |
| 890 | } |
| 891 | } |
| 892 | } |
| 893 | } |
| 894 | else if (spaces > 0) { |
| 895 | /* This is actually a space group */ |
| 896 | grpsyl_p->grpcont = GC_SPACE; |
| 897 | grpsyl_p->tie = NO; |
| 898 | /* Uncompressibility was temporarily saved |
| 899 | * in octave, so move it now. If multiple spaces |
| 900 | * mapped to this group, if any of them are |
| 901 | * uncompressible, make the group uncompressible. */ |
| 902 | for (n = 0; n < grpsyl_p->nnotes; n++) { |
| 903 | if (grpsyl_p->notelist[n].octave == YES) { |
| 904 | grpsyl_p->uncompressible = YES; |
| 905 | break; |
| 906 | } |
| 907 | } |
| 908 | } |
| 909 | else if (rpts > 0) { |
| 910 | /* This is actually a rpt. Internally, that is stored |
| 911 | * as a note group with no notes (nnotes gets zeroed |
| 912 | * a few lines down from here). This should |
| 913 | * already be notes but doesn't hurt to set again. */ |
| 914 | grpsyl_p->grpcont = GC_NOTES; |
| 915 | } |
| 916 | if (grpsyl_p->notelist[0].slurtolist != (struct SLURTO *) 0) { |
| 917 | l_yyerror(grpsyl_p->inputfile, grpsyl_p->inputlineno, |
| 918 | "can't have slur on rest, space, or rpt"); |
| 919 | } |
| 920 | free_notelist(grpsyl_p); |
| 921 | grpsyl_p->notelist = 0; |
| 922 | grpsyl_p->nnotes = 0; |
| 923 | } |
| 924 | |
| 925 | if (grpsyl_p->grpcont == GC_NOTES) { |
| 926 | if (grpsyl_p->is_meas == YES && grpsyl_p->nnotes > 0) { |
| 927 | l_yyerror(grpsyl_p->inputfile, grpsyl_p->inputlineno, |
| 928 | "'m' can only be used with rest, space, or rpt, not notes"); |
| 929 | return; |
| 930 | } |
| 931 | } |
| 932 | |
| 933 | /* grace can only apply to notes */ |
| 934 | if (grpsyl_p->grpvalue == GV_ZERO && (grpsyl_p->grpcont != GC_NOTES || |
| 935 | grpsyl_p->nnotes == 0)) { |
| 936 | l_yyerror(grpsyl_p->inputfile, grpsyl_p->inputlineno, |
| 937 | "grace can only be used with notes"); |
| 938 | } |
| 939 | } |
| 940 | \f |
| 941 | |
| 942 | /* If first group of a measure has no time value specified, we have to use |
| 943 | * the default. This is complicated by the fact that the user could be |
| 944 | * defining mulitples staffs/voices at once. If they are, we need to make |
| 945 | * sure that all of them have the same default. */ |
| 946 | |
| 947 | struct SSV * |
| 948 | get_dflt_timeunit_ssv() |
| 949 | |
| 950 | { |
| 951 | struct MAP *map_p; /* list of maps */ |
| 952 | struct NOTEMAP *notemap_p; /* list of notemaps per map */ |
| 953 | struct SVRANGELIST *svr_p; /* list of staff/voice ranges */ |
| 954 | struct RANGELIST *sr_p; /* list of staffs being defined */ |
| 955 | struct RANGELIST *vr_p; /* list of voices being defined */ |
| 956 | int s; /* staff number */ |
| 957 | int v; /* voice */ |
| 958 | int got_one = NO; /* YES if have found a dflt value */ |
| 959 | RATIONAL this_timeunit; /* value for current staff/voice */ |
| 960 | RATIONAL dflt_timeunit; /* the default time unit to use */ |
| 961 | struct SSV *tu_ssv_p; /* SSV containing relevent timeunit */ |
| 962 | struct SSV *ref_ssv_p; /* SSV we had checked on prev |
| 963 | * staff/voice being defined together */ |
| 964 | |
| 965 | |
| 966 | /* If doing voice-at-a-time input, use the special MAP for that case, |
| 967 | * otherwise use the Map_p */ |
| 968 | if (Map_p == (struct MAP *) 0) { |
| 969 | map_p = &Voice_at_a_time_map; |
| 970 | map_p->notemap_p->svlist_p = Svrangelist_p; |
| 971 | } |
| 972 | else { |
| 973 | map_p = Map_p; |
| 974 | } |
| 975 | |
| 976 | /* score value is the ultimate default */ |
| 977 | dflt_timeunit = Score.timeunit; |
| 978 | tu_ssv_p = ref_ssv_p = &Score; |
| 979 | |
| 980 | /* check each map/notemap/svrangelist/svrange/staff/voice combination */ |
| 981 | for ( ; map_p != (struct MAP *) 0; map_p = map_p->next) { |
| 982 | for (notemap_p = map_p->notemap_p; |
| 983 | notemap_p != (struct NOTEMAP *) 0; |
| 984 | notemap_p = notemap_p->next) { |
| 985 | for (svr_p = notemap_p->svlist_p; |
| 986 | svr_p != (struct SVRANGELIST *) 0; |
| 987 | svr_p = svr_p->next) { |
| 988 | for (sr_p = svr_p->stafflist_p; |
| 989 | sr_p != (struct RANGELIST *) 0; |
| 990 | sr_p = sr_p->next) { |
| 991 | for (s = sr_p->begin; s <= sr_p->end; s++) { |
| 992 | for (vr_p = svr_p->vnolist_p; |
| 993 | vr_p != (struct RANGELIST *) 0; |
| 994 | vr_p = vr_p->next) { |
| 995 | for (v = vr_p->begin; v <= vr_p->end; v++) { |
| 996 | |
| 997 | /* find default timeunit for |
| 998 | * this staff/voice */ |
| 999 | tu_ssv_p = vvpath(s, v, TIMEUNIT); |
| 1000 | this_timeunit = tu_ssv_p->timeunit; |
| 1001 | |
| 1002 | if (got_one == NO) { |
| 1003 | /* now we have one to |
| 1004 | * compare against */ |
| 1005 | dflt_timeunit = this_timeunit; |
| 1006 | ref_ssv_p = tu_ssv_p; |
| 1007 | got_one = YES; |
| 1008 | } |
| 1009 | else if ( NE(this_timeunit, dflt_timeunit) |
| 1010 | || timelists_equal( |
| 1011 | tu_ssv_p->timelist_p, |
| 1012 | ref_ssv_p->timelist_p) |
| 1013 | == NO) { |
| 1014 | yyerror("timeunit value must be the same for all staffs being defined on the same input line"); |
| 1015 | } |
| 1016 | } |
| 1017 | } |
| 1018 | } |
| 1019 | } |
| 1020 | } |
| 1021 | } |
| 1022 | } |
| 1023 | |
| 1024 | return(tu_ssv_p); |
| 1025 | } |
| 1026 | \f |
| 1027 | |
| 1028 | /* Return YES if the given lists are equivalent, NO if they aren't. */ |
| 1029 | |
| 1030 | int |
| 1031 | timelists_equal(list1_p, list2_p) |
| 1032 | |
| 1033 | struct TIMELIST *list1_p; |
| 1034 | struct TIMELIST *list2_p; |
| 1035 | |
| 1036 | { |
| 1037 | for ( ; list1_p != 0 && list2_p != 0; |
| 1038 | list1_p = list1_p->next, list2_p = list2_p->next) { |
| 1039 | if ( NE(list1_p->fulltime, list2_p->fulltime) ) { |
| 1040 | return(NO); |
| 1041 | } |
| 1042 | } |
| 1043 | return((list1_p == 0 && list2_p == 0) ? YES : NO); |
| 1044 | } |
| 1045 | \f |
| 1046 | |
| 1047 | /* Return YES if the current staff range is for all tablature staffs. |
| 1048 | * Return NO if not. If there are a mixture, this is an error, so print |
| 1049 | * a message. It still returns NO in this case, so if the user wanted tab, |
| 1050 | * they may get a lot of errors. Oh well. After all, they did make an error. |
| 1051 | */ |
| 1052 | |
| 1053 | int |
| 1054 | is_tab_range() |
| 1055 | |
| 1056 | { |
| 1057 | struct MAP *map_p; |
| 1058 | struct NOTEMAP *notemap_p; |
| 1059 | struct SVRANGELIST *svr_p; |
| 1060 | struct RANGELIST *sr_p; |
| 1061 | int s; /* staff number */ |
| 1062 | int found_tab_staff = NO; |
| 1063 | int found_non_tab_staff = NO; |
| 1064 | |
| 1065 | /* If doing voice-at-a-time input, use the special MAP for that case, |
| 1066 | * otherwise use the Map_p */ |
| 1067 | if (Map_p == (struct MAP *) 0) { |
| 1068 | map_p = &Voice_at_a_time_map; |
| 1069 | map_p->notemap_p->svlist_p = Svrangelist_p; |
| 1070 | } |
| 1071 | else { |
| 1072 | map_p = Map_p; |
| 1073 | } |
| 1074 | |
| 1075 | /* check each map/notemap/svrangelist/svrange/staff/voice combination */ |
| 1076 | for ( ; map_p != (struct MAP *) 0; map_p = map_p->next) { |
| 1077 | for (notemap_p = map_p->notemap_p; |
| 1078 | notemap_p != (struct NOTEMAP *) 0; |
| 1079 | notemap_p = notemap_p->next) { |
| 1080 | for (svr_p = notemap_p->svlist_p; |
| 1081 | svr_p != (struct SVRANGELIST *) 0; |
| 1082 | svr_p = svr_p->next) { |
| 1083 | for (sr_p = svr_p->stafflist_p; |
| 1084 | sr_p != (struct RANGELIST *) 0; |
| 1085 | sr_p = sr_p->next) { |
| 1086 | for (s = sr_p->begin; s <= sr_p->end; s++) { |
| 1087 | if (is_tab_staff(s) == YES) { |
| 1088 | found_tab_staff = YES; |
| 1089 | } |
| 1090 | else { |
| 1091 | found_non_tab_staff = YES; |
| 1092 | } |
| 1093 | } |
| 1094 | } |
| 1095 | } |
| 1096 | } |
| 1097 | } |
| 1098 | |
| 1099 | if (found_tab_staff == YES && found_non_tab_staff == YES) { |
| 1100 | yyerror("mixture of tab and non-tab staffs not allowed"); |
| 1101 | } |
| 1102 | |
| 1103 | return(found_tab_staff); |
| 1104 | } |
| 1105 | \f |
| 1106 | |
| 1107 | /* When two notes in a chord are duplicates from chord-at-a-time input, |
| 1108 | * we want to merge the notes, and get rid of the extra. This function will |
| 1109 | * change the value of gs_p->nnotes and the size of the notelist array. */ |
| 1110 | |
| 1111 | void |
| 1112 | merge_dup_notes(gs_p, n) |
| 1113 | |
| 1114 | struct GRPSYL *gs_p; /* remove duplicate from here */ |
| 1115 | int n; /* merge note n and n+1 into slot n, then remove |
| 1116 | * the note in slot n+1 by moving any remaining |
| 1117 | * notes down. */ |
| 1118 | |
| 1119 | { |
| 1120 | int i; |
| 1121 | int sn, sn1; /* slurto index */ |
| 1122 | struct NOTE *note_p, *extra_p; |
| 1123 | |
| 1124 | |
| 1125 | /* get shorter names for what we will use a lot */ |
| 1126 | note_p = &(gs_p->notelist[n]); |
| 1127 | extra_p = &(gs_p->notelist[n+1]); |
| 1128 | /* Merge the data between the two as best we can. |
| 1129 | * In general, if one has a "stronger" version of some attribute, |
| 1130 | * go with that one. We check the second; if it is "stronger", |
| 1131 | * force the result to that--if it was already set the same, fine-- |
| 1132 | * probably faster to just assign than check and maybe assign. |
| 1133 | * If second wasn't stronger, go with whatever the first was. */ |
| 1134 | |
| 1135 | /* If one is normal, one small, override the small */ |
| 1136 | if (extra_p->notesize == GS_NORMAL) { |
| 1137 | note_p->notesize = GS_NORMAL; |
| 1138 | } |
| 1139 | |
| 1140 | /* If either has a tie, do a tie */ |
| 1141 | if (extra_p->tie == YES) { |
| 1142 | note_p->tie = YES; |
| 1143 | } |
| 1144 | /* Consider normal tie the strongest, then dashed, then dotted */ |
| 1145 | if (extra_p->tiestyle == L_NORMAL) { |
| 1146 | note_p->tiestyle = L_NORMAL; |
| 1147 | } |
| 1148 | else if (extra_p->tiestyle == L_DASHED && |
| 1149 | note_p->tiestyle != L_NORMAL) { |
| 1150 | note_p->tiestyle = L_DASHED; |
| 1151 | } |
| 1152 | if ( (extra_p->tiedir == UP && note_p->tiedir == DOWN) || |
| 1153 | (extra_p->tiedir == DOWN && note_p->tiedir == UP)) { |
| 1154 | /* It would be nice to allow both up and down tie, |
| 1155 | * especially since we can do that for slurs, |
| 1156 | * but we only support one tie per note. */ |
| 1157 | l_yyerror(gs_p->inputfile, gs_p->inputlineno, |
| 1158 | "duplicate notes with opposite tie direction not allowed"); |
| 1159 | } |
| 1160 | else if (extra_p->tiedir != UNKNOWN) { |
| 1161 | note_p->tiedir = extra_p->tiedir; |
| 1162 | } |
| 1163 | |
| 1164 | |
| 1165 | /* Parentheses around an accidental means "just in case you forgot..." |
| 1166 | * which is weaker than no parentheses, so only use parentheses if |
| 1167 | * both have it. */ |
| 1168 | if (extra_p->acc_has_paren == NO) { |
| 1169 | note_p->acc_has_paren = NO; |
| 1170 | } |
| 1171 | /* Parentheses around a note generally means the note is optional. |
| 1172 | * An optional merged with a non-optional, is non-optional. */ |
| 1173 | if (extra_p->note_has_paren == NO) { |
| 1174 | note_p->note_has_paren = NO; |
| 1175 | } |
| 1176 | |
| 1177 | /* Sorry, we don't deal with incompatible bends */ |
| 1178 | if (note_p->is_bend != extra_p->is_bend || |
| 1179 | extra_p->smallbend != note_p->smallbend) { |
| 1180 | l_yyerror(gs_p->inputfile, gs_p->inputlineno, |
| 1181 | "duplicate notes with bend mismatch not allowed"); |
| 1182 | } |
| 1183 | |
| 1184 | /* Slurs... If duplicate between the two slurto lists, just leave |
| 1185 | * the one, but use strongest slurstyle. If there is one in the |
| 1186 | * NOTE to be deleted but not in the one to keep, move it. */ |
| 1187 | for (sn1 = 0; sn1 < extra_p->nslurto; sn1++) { |
| 1188 | for (sn = 0; sn < note_p->nslurto; sn++) { |
| 1189 | if (note_p->slurtolist[sn].letter == |
| 1190 | extra_p->slurtolist[sn1].letter && |
| 1191 | note_p->slurtolist[sn].slurdir == |
| 1192 | extra_p->slurtolist[sn1].slurdir && |
| 1193 | note_p->slurtolist[sn].octave == |
| 1194 | extra_p->slurtolist[sn1].octave) { |
| 1195 | /* duplicate; just fix style if necessary */ |
| 1196 | if (extra_p->slurtolist[sn1].slurstyle |
| 1197 | == L_NORMAL) { |
| 1198 | note_p->slurtolist[sn].slurstyle |
| 1199 | = L_NORMAL; |
| 1200 | } |
| 1201 | else if (extra_p->slurtolist[sn1].slurstyle |
| 1202 | == L_DASHED && |
| 1203 | note_p->slurtolist[sn].slurstyle |
| 1204 | != L_NORMAL) { |
| 1205 | note_p->slurtolist[sn].slurstyle |
| 1206 | = L_DASHED; |
| 1207 | } |
| 1208 | break; |
| 1209 | } |
| 1210 | } |
| 1211 | if (sn == note_p->nslurto) { |
| 1212 | /* wasn't on the list to keep, so add it */ |
| 1213 | add_slurto(gs_p, extra_p->slurtolist[sn1].letter, |
| 1214 | extra_p->slurtolist[sn1].octave, |
| 1215 | sn, |
| 1216 | extra_p->slurtolist[sn1].slurstyle); |
| 1217 | } |
| 1218 | } |
| 1219 | |
| 1220 | /* Move things down in the notelist to remove the extra */ |
| 1221 | for (i = n + 1; i < gs_p->nnotes - 1; i++) { |
| 1222 | gs_p->notelist[i] = gs_p->notelist[i+1]; |
| 1223 | } |
| 1224 | (gs_p->nnotes)--; |
| 1225 | REALLOC(NOTE, gs_p->notelist, gs_p->nnotes); |
| 1226 | } |
| 1227 | \f |
| 1228 | |
| 1229 | /* print error message for multiply defined voice */ |
| 1230 | |
| 1231 | static void |
| 1232 | mult_def(staff, voice) |
| 1233 | |
| 1234 | int staff; |
| 1235 | int voice; |
| 1236 | |
| 1237 | { |
| 1238 | l_yyerror(Curr_filename, yylineno, |
| 1239 | "staff %d voice %d multiply defined (first defined on line %d)", |
| 1240 | staff, voice, |
| 1241 | Staffmap_p[staff]->u.staff_p->groups_p[voice-1]->inputlineno); |
| 1242 | } |