chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / map.c
CommitLineData
fac14bbe
MW
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. */
31struct 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. */
38struct 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 */
45static struct MAP *Map_p;
46/* This points to where to add to the map list */
47static struct MAP **End_map_p_p = &Map_p;
48
49/* This is where to insert the next NOTEMAP */
50static 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. */
58static struct NOTEMAP Sv_notemap = {
59 (struct SVRANGELIST *) 0, (struct NOTEMAP *) 0
60};
61static 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 */
66static short Input_style[MAXSTAFFS][MAXVOICES];
67
68static int map_groups P((void));
69static void clean_map_data P((void));
70static void free_maps P((struct MAP *map_p));
71static void free_notemaps P((struct NOTEMAP *notemap_p));
72static struct NOTEMAP *find_notemap P((int num_notes));
73static void map1note P((struct GRPSYL *from_gs_p, int n, int staff, int voice,
74 short allocated[MAXSTAFFS][MAXVOICES]));
75static void do_link_groups P((void));
76static void link_a_grouplist P((int staffno, int vno, int copies));
77static void convert_rest_space P((struct GRPSYL *grpsyl_p, int staffno, int vno));
78static void conv_grpsyl P((struct GRPSYL *grpsyl_p, int staffno, int vno));
79static void mult_def P((int staff, int voice));
80\f
81
82/* Initialize Input_style to default of IS_VOICE_INPUT */
83
84void
85reset_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
101int
102input_style(staff, voice)
103
104int staff;
105int 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
114void
115begin_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
136void
137map_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
157void
158end_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
173static int
174map_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
456static void
457map1note(from_gs_p, n, staff, voice, allocated)
458
459struct GRPSYL *from_gs_p; /* copy from here */
460int n; /* copy the nth note in from_gs_p, or if -1,
461 * create a space group */
462int staff;
463int voice;
464short 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
602static void
603clean_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
617static void
618free_maps(map_p)
619
620struct 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
640static void
641free_notemaps(notemap_p)
642
643struct 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
659static struct NOTEMAP *
660find_notemap(num_notes)
661
662int 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
682void
683link_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
714static void
715do_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
752static void
753link_a_grouplist(staffno, vno, copies)
754
755int staffno;
756int vno;
757int 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
806static void
807convert_rest_space(grpsyl_p, staffno, vno)
808
809struct GRPSYL *grpsyl_p;
810int staffno;
811int 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
823static void
824conv_grpsyl(grpsyl_p, staffno, vno)
825
826struct GRPSYL *grpsyl_p;
827int staffno;
828int 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
947struct SSV *
948get_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
1030int
1031timelists_equal(list1_p, list2_p)
1032
1033struct TIMELIST *list1_p;
1034struct 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
1053int
1054is_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
1111void
1112merge_dup_notes(gs_p, n)
1113
1114struct GRPSYL *gs_p; /* remove duplicate from here */
1115int 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
1231static void
1232mult_def(staff, voice)
1233
1234int staff;
1235int 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}