chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / restsyl.c
1 /* Copyright (c) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 by Arkkra Enterprises */
2 /* All rights reserved */
3 /*
4  * Name:        restsyl.c
5  *
6  * Description: This file contains functions for setting the relative
7  *              horizontal and vertical coordinates of all groups that
8  *              contain a rest or space (grpcont != GC_NOTES), and the relative
9  *              horizontal coordinates of syllables.  It then completes
10  *              the relative horizontal work by setting the relative
11  *              horizontal coords of chords.  But before it does that last
12  *              step, it scales all the relative coords set so far according
13  *              to staffscale.
14  */
15
16 #include "defines.h"
17 #include "structs.h"
18 #include "globals.h"
19
20 #define PK_LEFT         (0)
21 #define PK_RIGHT        (1)
22 #define PK_CENTER       (2)
23 #define PK_NONE         (3)
24
25 static double highcoord P((struct GRPSYL *gs_p, struct GRPSYL *altgs_p));
26 static double lowcoord P((struct GRPSYL *gs_p, struct GRPSYL *altgs_p));
27 static void procrests P((struct CHORD *ch_p, struct STAFF *staff_p,
28                 struct GRPSYL *gs_p, double limhigh, double limlow));
29 static void procspaces P((struct GRPSYL *gs_p));
30 static struct GRPSYL *finalgroupproc P((struct GRPSYL *gs1_p));
31 static int v3pack P((struct GRPSYL *g_p[], int numgrps));
32 static void fixclef P((struct GRPSYL *gs1_p));
33 static void restsize P((struct GRPSYL *gs_p, float *wid_p, float *asc_p,
34                 float *des_p));
35 static void procsyls P((struct GRPSYL *gs_p));
36 static void apply_staffscale P((void));
37 static void relxchord P((void));
38 static double effwest P((struct MAINLL *mainll_p, struct CHORD *ch_p,
39                 struct GRPSYL *gs_p));
40 static double effeast P((struct CHORD *ch_p, struct GRPSYL *gs_p));
41 static int collision_danger P((struct GRPSYL *g1_p, struct GRPSYL *g2_p));
42 static struct CHORD *prevchord P((struct MAINLL *mainll_p, struct CHORD *ch_p));
43 static struct GRPSYL *nextchsyl P((struct GRPSYL *gs_p, struct CHORD *ch_p));
44 static struct GRPSYL *prevchsyl P((struct GRPSYL *gs_p,
45                 struct CHORD *prevch_p));
46 static void pedalroom P((void));
47 static struct CHORD *closestchord P((double count, struct CHORD *firstch_p));
48 static double rightped P((int pedstyle, int pedchar));
49 static double leftped P((int pedstyle, int pedchar));
50 static void fixspace P((void));
51 \f
52 /*
53  * Name:        restsyl()
54  *
55  * Abstract:    Sets all relative coords for rests and spaces, and horizontal
56  *              ones for syllables; set relative horz. coords of chords.
57  *
58  * Returns:     void
59  *
60  * Description: This function loops through the main linked list, finding every
61  *              STAFF structure.  For groups, it calls procrests() to process
62  *              every rest in the linked list, and procspaces() to process
63  *              every space in the linked list.  For syllables, it calls
64  *              procsyls().  At the end it calls apply_staffscale() to apply
65  *              staffscale to all the relative coords set so far, and then
66  *              relxchord() to set the relative horizontal coords of chords.
67  */
68
69 void
70 restsyl()
71
72 {
73         register struct MAINLL *mainll_p; /* point item in main linked list */
74         struct MAINLL *mll_p;           /* another MLL pointer */
75         struct STAFF *staff_p;          /* point at a staff */
76         struct STAFF *stafflist[MAXSTAFFS + 1]; /* point to this meas's staffs*/
77         float limhigh[MAXSTAFFS + 1];   /* high y coord of limit of groups */
78         float limlow[MAXSTAFFS + 1];    /* low y coord of limit of groups */
79         int vscheme;                    /* voice scheme */
80         int v;                          /* index into verse headcell array */
81         struct CHORD *ch_p;             /* point at a chord */
82         struct GRPSYL *gs1_p;           /* point at a group */
83
84
85         debug(16, "restsyl");
86         initstructs();
87
88
89         /*
90          * Loop down the main linked list looking for each chord list
91          * headcell.
92          */
93         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
94
95                 if (mainll_p->str == S_SSV) {
96                         asgnssv(mainll_p->u.ssv_p);
97                         continue;
98                 }
99
100                 if (mainll_p->str != S_CHHEAD)
101                         continue;       /* skip everything but chord HC */
102
103                 /*
104                  * For each visible staff in this measure, find the high and
105                  * low limits of the relevant voices, so that we know what to
106                  * avoid when placing rests in other voices.
107                  */
108                 for (mll_p = mainll_p->next; mll_p->str == S_STAFF;
109                                 mll_p = mll_p->next) {
110
111                         staff_p = mll_p->u.staff_p;
112                         stafflist[staff_p->staffno] = staff_p;
113                         vscheme = svpath(staff_p->staffno, VSCHEME)->vscheme;
114                         if (staff_p->visible == NO) {
115                                 continue;
116                         }
117
118                         /*
119                          * If there is more than one voice, each voice's rests
120                          * have to worry about avoiding other voices' notes.
121                          * So find how high voice 2 and how low voice 1, get,
122                          * in this measure.  But voice 3 can "stand in" for
123                          * either, so pass that in too.  If it's null, that's
124                          * okay, the subroutines handle that.
125                          */
126                         if (vscheme != V_1) {
127                                 limhigh[staff_p->staffno] =
128                                         highcoord(staff_p->groups_p[1],
129                                         staff_p->groups_p[2]);
130                                 limlow[staff_p->staffno] =
131                                         lowcoord(staff_p->groups_p[0],
132                                         staff_p->groups_p[2]);
133                         } else {
134                                 /* prevent uninitialized var, though not used*/
135                                 limhigh[staff_p->staffno] = 0;
136                                 limlow[staff_p->staffno] = 0;
137                         }
138                 }
139
140                 /*
141                  * Loop through each chord in this list.
142                  */
143                 for (ch_p = mainll_p->u.chhead_p->ch_p; ch_p != 0;
144                                         ch_p = ch_p->ch_p) {
145                         /*
146                          * Loop through the linked list of GRPSYLs hanging off
147                          * this chord.  Skip the syllables; just deal with the
148                          * groups.  Upon finding the first group on a staff
149                          * (which could be for any of the voices, since not all
150                          * might be present in this chord), call procrests and
151                          * finalgroupproc to process the groups.
152                          */
153                         gs1_p = ch_p->gs_p;
154                         for (;;) {
155                                 /* find first group on a staff */
156                                 while (gs1_p != 0 &&
157                                                 gs1_p->grpsyl == GS_SYLLABLE)
158                                         gs1_p = gs1_p->gs_p;
159                                 if (gs1_p == 0)
160                                         break;
161
162                                 /*
163                                  * Call procrests() to place any rest in the
164                                  * voice on this staff in this chord.
165                                  */
166                                 procrests(ch_p, stafflist[gs1_p->staffno],
167                                                 gs1_p, limhigh[gs1_p->staffno],
168                                                 limlow[gs1_p->staffno]);
169
170                                 /* set gs1_p to after this staff's groups */
171                                 gs1_p = finalgroupproc(gs1_p);
172                         }
173                 }
174         }
175
176         initstructs();
177
178         /*
179          * Loop once for each item in the main linked list.  Now that we're all
180          * done with notes and rests, do the spaces and syllables.
181          */
182         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
183
184                 if (mainll_p->str == S_SSV) {
185
186                         asgnssv(mainll_p->u.ssv_p);
187
188                 } else if (mainll_p->str == S_STAFF &&
189                                         mainll_p->u.staff_p->visible == YES) {
190
191                         /* for each voice that exists, process the spaces */
192                         for (v = 0; v < MAXVOICES; v++) {
193                                 if (mainll_p->u.staff_p->groups_p[v] != 0) {
194                                         procspaces(mainll_p->u.staff_p->
195                                                         groups_p[v]);
196                                 }
197                         }
198
199                         /* set relative horizontal coords for syllables */
200                         for (v = 0; v < mainll_p->u.staff_p->nsyllists; v++) {
201                                 procsyls(mainll_p->u.staff_p->syls_p[v]);
202                         }
203                 }
204         }
205
206         /* scale all relative coords set so far according to staffscale */
207         apply_staffscale();
208
209         /* now we are ready to set relative horizontal coords for all chords */
210         relxchord();
211 }
212 \f
213 /*
214  * Name:        highcoord()
215  *
216  * Abstract:    Find highest relative y coord of a group in one GRPSYL list.
217  *
218  * Returns:     void
219  *
220  * Description: This function goes down one of the linked lists of GRPSYLs,
221  *              one that is for groups, not syllables, and finds the highest
222  *              relative y coordinate of any group containing notes.  If there
223  *              are no notes but there are rests, it returns 0.  If there are
224  *              only spaces, it returns -100.  The answer, though, is rounded
225  *              off to the nearest staff line.  Besides the primary linked list
226  *              of GRPSYLs, it also looks for GRPSYLs in the alternate list
227  *              (voice 3 if it exists) and considers ones that are "standing in"
228  *              for the first list's voice.
229  */
230
231 static double
232 highcoord(gs_p, altgs_p)
233
234 register struct GRPSYL *gs_p;   /* starts pointing at first GRPSYL in list */
235 register struct GRPSYL *altgs_p;/* first GRPSYL of voice 3, if any */
236
237 {
238         float result;
239         int normvoice;          /* main voice we are dealing with, 1 or 2 */
240         float edge;             /* of a group in the other voice */
241
242
243         debug(32, "highcoord file=%s line=%d", gs_p->inputfile,
244                         gs_p->inputlineno);
245         result = -100;          /* init as if only spaces */
246         normvoice = gs_p->vno;  /* remember the voice we're dealing with */
247
248         /* 
249          * Loop through all groups (even grace), moving result up when
250          * something higher is found.  Rests count as 0 (the middle line).
251          */
252         for ( ; gs_p != 0; gs_p = gs_p->next) {
253                 switch (gs_p->grpcont) {
254                 case GC_NOTES:
255                         edge = gs_p->c[RN];
256                         /* if wrong way stem, account for it as best we can */
257                         if (gs_p->stemdir == UP) {
258                                 edge += (stemroom(gs_p) - 1.0) * STEPSIZE;
259                         }
260                         if (edge > result) {
261                                 result = edge;
262                         }
263                         break;
264                 case GC_REST:
265                         if (result < 0)
266                                 result = 0;
267                         break;
268                 /* ignore spaces */
269                 }
270         }
271
272         /*
273          * Look at every GRPSYL in voice 3, if any.  If it is "standing in" for
274          * the normal voice, move result up if need be.
275          */
276         for ( ; altgs_p != 0; altgs_p = altgs_p->next) {
277                 if (altgs_p->pvno == normvoice) {
278                         switch (altgs_p->grpcont) {
279                         case GC_NOTES:
280                                 if (altgs_p->c[RN] > result)
281                                         result = altgs_p->c[RN];
282                                 break;
283                         case GC_REST:
284                                 if (result < 0)
285                                         result = 0;
286                                 break;
287                         /* ignore spaces */
288                         }
289                 }
290         }
291
292         return (nearestline(result));
293 }
294 \f
295 /*
296  * Name:        lowcoord()
297  *
298  * Abstract:    Find lowest relative y coord of a group in one GRPSYL list.
299  *
300  * Returns:     void
301  *
302  * Description: This function goes down one of the linked lists of GRPSYLs,
303  *              one that is for groups, not syllables, and finds the lowest
304  *              relative y coordinate of any group containing notes.  If there
305  *              are no notes but there are rests, it returns 0.  If there are
306  *              only spaces, it returns 100.  The answer, though, is rounded
307  *              off to the nearest staff line.  Besides the primary linked list
308  *              of GRPSYLs, it also looks for GRPSYLs in the alternate list
309  *              (voice 3 if it exists) and considers ones that are "standing in"
310  *              for the first list's voice.
311  */
312
313 static double
314 lowcoord(gs_p, altgs_p)
315
316 register struct GRPSYL *gs_p;   /* starts pointing at first GRPSYL in list */
317 register struct GRPSYL *altgs_p;/* first GRPSYL of voice 3, if any */
318
319 {
320         float result;
321         int normvoice;          /* main voice we are dealing with, 1 or 2 */
322         float edge;             /* of a group in the other voice */
323
324
325         debug(32, "lowcoord file=%s line=%d", gs_p->inputfile,
326                         gs_p->inputlineno);
327         result = 100;           /* init as if only spaces */
328         normvoice = gs_p->vno;  /* remember the voice we're dealing with */
329
330         /* 
331          * Loop through all groups (even grace), moving result down when
332          * something lower is found.  Rests count as 0 (the middle line).
333          */
334         for ( ; gs_p != 0; gs_p = gs_p->next) {
335                 switch (gs_p->grpcont) {
336                 case GC_NOTES:
337                         edge = gs_p->c[RS];
338                         /* if wrong way stem, account for it as best we can */
339                         if (gs_p->stemdir == DOWN) {
340                                 edge -= (stemroom(gs_p) - 1.0) * STEPSIZE;
341                         }
342                         if (edge < result) {
343                                 result = edge;
344                         }
345                         break;
346                 case GC_REST:
347                         if (result > 0)
348                                 result = 0;
349                         break;
350                 /* ignore spaces */
351                 }
352         }
353
354         /*
355          * Look at every GRPSYL in voice 3, if any.  If it is "standing in" for
356          * the normal voice, move result up if need be.
357          */
358         for ( ; altgs_p != 0; altgs_p = altgs_p->next) {
359                 if (altgs_p->pvno == normvoice) {
360                         switch (altgs_p->grpcont) {
361                         case GC_NOTES:
362                                 if (altgs_p->c[RS] < result)
363                                         result = altgs_p->c[RS];
364                                 break;
365                         case GC_REST:
366                                 if (result > 0)
367                                         result = 0;
368                                 break;
369                         /* ignore spaces */
370                         }
371                 }
372         }
373
374         return (nearestline(result));
375 }
376 \f
377 /*
378  * Name:        procrests()
379  *
380  * Abstract:    Sets relative coordinates for rests in one CHORD/STAFF.
381  *
382  * Returns:     void
383  *
384  * Description: This function is given the top GRPSYL on a STAFF in a CHORD.
385  *              It sets the relative coordinates of each rest GRPSYL on this
386  *              STAFF/CHORD.
387  */
388
389 static void
390 procrests(ch_p, staff_p, gs1_p, limhigh, limlow)
391
392 struct CHORD *ch_p;             /* the chord we are in */
393 struct STAFF *staff_p;          /* the staff we are processing */
394 struct GRPSYL *gs1_p;           /* point at top GRPSYL in chord */
395 double limhigh;                 /* highest relative y coord below v1 */
396 double limlow;                  /* lowest relative y coord above v2 */
397
398 {
399         RATIONAL endtime;       /* time at the end of the rest */
400         struct GRPSYL *g_p[MAXVOICES + 1]; /* index by vno, point at GRPSYL */
401         struct GRPSYL *gs_p;    /* a GRPSYL we are now working on */
402         struct GRPSYL *ogs_p;   /* other voice to be considered */
403         float wid, asc, des;    /* width, ascent, and descent of a rest */
404         int vscheme;            /* voice scheme */
405         int restsabove;         /* are these rests above another voice? */
406         int stafflines;         /* no. of lines in staff */
407         int v;                  /* voice number */
408         float y;                /* relative y coord for this rest */
409
410
411         debug(32, "procrests file=%s line=%d limhigh=%f limlow=%f",
412                 gs1_p->inputfile, gs1_p->inputlineno,
413                 (float)limhigh, (float)limlow);
414
415
416         /* get voice scheme and number of lines in staff */
417         vscheme = svpath(gs1_p->staffno, VSCHEME)->vscheme;
418         stafflines = svpath(gs1_p->staffno, STAFFLINES)->stafflines;
419
420         /* set pointers to all nonspace groups in this chord on this staff */
421         for (v = 1; v <= MAXVOICES; v++) {
422                 g_p[v] = 0;
423         }
424         for (gs_p = gs1_p; gs_p != 0 && gs_p->staffno == gs1_p->staffno &&
425                             gs_p->grpsyl == GS_GROUP; gs_p = gs_p->gs_p) {
426                 if (gs_p->grpcont != GC_SPACE) {
427                         g_p[gs_p->vno] = gs_p;
428                 }
429         }
430
431         y = 0.0;        /* to avoid useless 'used before set' warning */
432         ogs_p = 0;      /* to avoid useless 'used before set' warning */
433
434         /*
435          * Loop through each possible voice, setting its coords if it is a rest.
436          */
437         for (v = 1; v <= MAXVOICES; v++) {
438
439                 gs_p = g_p[v];
440
441                 if (gs_p == 0 || gs_p->grpcont != GC_REST) {
442                         continue;
443                 }
444
445                 /* find the time at the end of the rest */
446                 endtime = radd(ch_p->starttime, gs_p->fulltime);
447
448                 /* find width, ascent, and descent of the rest */
449                 restsize(gs_p, &wid, &asc, &des);
450
451                 /*
452                  * Find out if another voice needs to be considered in the
453                  * placement of this rest, and set ogs_p to that voice's first
454                  * GRPSYL if so.
455                  */
456                 ogs_p = 0;
457                 if (vscheme == V_2FREESTEM ||
458                                 vscheme == V_3FREESTEM && gs_p->pvno != 3) {
459                         ogs_p = gs_p->pvno == 1 ? staff_p->groups_p[1] :
460                                                   staff_p->groups_p[0];
461                 }
462
463                 /* 
464                  * Find the RY of the rest.
465                  */
466                 if (vscheme == V_1 || (vscheme == V_2FREESTEM ||
467                                 vscheme == V_3FREESTEM) &&
468                                 hasspace(ogs_p, ch_p->starttime, endtime)) {
469                         /*
470                          * There is either only 1 voice, or we are 2f/3f and the
471                          * other voice is all spaces during this time.  Usually
472                          * RY should be 0.  But for one-line staffs, whole
473                          * rest characters need to be lowered so that they hang
474                          * under the line.
475                          */
476                         if (stafflines == 1 && gs_p->basictime == 1) {
477                                 y = -2 * STEPSIZE;
478                         } else {
479                                 y = 0;
480                         }
481                 } else {
482                         /*
483                          * We are 2o, or 2f/3f with notes/rests in the other
484                          * voice that we must avoid hitting.  Set up the
485                          * relative y coord, based on whether gs_p is acting
486                          * as v1 or v2.  We also have to set up restsabove
487                          * for use below.
488                          */
489                         restsabove = NO;        /* default value for now */
490                         switch (gs_p->pvno) {
491                         case 1:
492                                 y = limhigh < -4 * STEPSIZE ?
493                                                 0 : limhigh + 4 * STEPSIZE;
494                                 restsabove = ! hasspace(staff_p->groups_p[1],
495                                                 Zero, Maxtime);
496                                 /* also check for v3 groups acting as v2 */
497                                 for (ogs_p = staff_p->groups_p[2];
498                                                 ogs_p != 0 && restsabove == NO;
499                                                 ogs_p = ogs_p->next) {
500                                         if (ogs_p->pvno == 2 &&
501                                         ogs_p->grpcont != GC_SPACE) {
502                                                 restsabove = YES;
503                                                 break;
504                                         }
505                                 }
506                                 break;
507                         case 2:
508                                 y = limlow > 4 * STEPSIZE ?
509                                                 0 : limlow - 4 * STEPSIZE;
510                                 break;
511                         }
512
513                         /*
514                          * Usually RY should be the y was set above.  But
515                          * if this is the upper voice, half rests and longer
516                          * should be lower to fall within the staff when
517                          * feasible, since they don't take much space
518                          * vertically and we don't want needless ledger lines.
519                          * (But nothing should ever be lowered if already on
520                          * the center line.)  Short rests need to be moved
521                          * away from the other voice by varying amounts,
522                          * depending on how tall they are.  Quad whole rests
523                          * below need to be raised a notch.
524                          */
525                         if (restsabove == YES) {
526                                 /* lower whole & double only if above middle */
527                                 if (gs_p->basictime <= 2 && y > 0)
528                                         y -= 2 * STEPSIZE;
529                                 if (gs_p->basictime >= 16)
530                                         y += 2 * STEPSIZE;
531                                 if (gs_p->basictime == 256)
532                                         y += 2 * STEPSIZE;
533                         } else {
534                                 if (gs_p->basictime >= 128)
535                                         y -= 2 * STEPSIZE;
536                                 if (gs_p->basictime == -1)
537                                         y += 2 * STEPSIZE;
538                         }
539                 }
540
541                 /*
542                  * If restdist was set by the user, use that instead of
543                  * whatever we calculated above.
544                  */
545                 if (gs_p->restdist != NORESTDIST) {
546                         y = gs_p->restdist * STEPSIZE;
547                 }
548
549                 /* set all the relative coords */
550                 gs_p->c[RX] = 0;
551                 gs_p->c[RE] = wid / 2;
552                 gs_p->c[RW] = -wid / 2 - gs_p->padding -
553                                 vvpath(gs_p->staffno, gs_p->vno, PAD)->pad;
554                 gs_p->c[RY] = y;
555                 gs_p->c[RN] = y + asc;
556                 gs_p->c[RS] = y - des;
557
558                 /* if there are dot(s), add their widths to the east side */
559                 if (gs_p->dots > 0) {
560                         gs_p->c[RE] += gs_p->dots * (width(FONT_MUSIC,
561                                         DFLT_SIZE, C_DOT) + 2 * STDPAD);
562                 }
563         }
564 }
565 \f
566 /*
567  * Name:        procspaces()
568  *
569  * Abstract:    Sets relative coordinates for spaces in one GRPSYL list.
570  *
571  * Returns:     void
572  *
573  * Description: This function goes down one of the linked lists of GRPSYLs,
574  *              one that is for groups, not syllables, and sets the relative
575  *              coordinates for each space found.  Usually these coords will
576  *              be left as 0, the way they were calloc'ed, but not when there
577  *              is padding or uncompressible spaces.
578  */
579
580 static void
581 procspaces(gs_p)
582
583 register struct GRPSYL *gs_p;   /* starts pointing at first GRPSYL in list */
584
585 {
586         static float half_us_width;     /* half width of uncompressible space*/
587         char headchar;                  /* char representing a note head */
588         int headfont;                   /* music font for head char */
589
590
591         /*
592          * Loop, setting all relative coords of spaces, except that if they are
593          * to be zero there's no need to set them, since calloc zeroed them.
594          * The vertical ones are always zero, and so is RX.
595          */
596         for ( ; gs_p != 0; gs_p = gs_p->next) {
597                 if (gs_p->grpcont != GC_SPACE)
598                         continue;
599
600                 if (gs_p->uncompressible == YES) {
601                         /*
602                          * If this is the first time in here, set this to half
603                          * a blank quarter note head plus standard pad.
604                          */
605                         if (half_us_width == 0.0) {
606                                 headchar = nheadchar(get_shape_num("blank"),
607                                                 4, UP, &headfont);
608                                 half_us_width = width(headfont, DFLT_SIZE,
609                                                 headchar) / 2.0 + STDPAD;
610                         }
611
612                         /* center the imaginary note head */
613                         gs_p->c[RE] = half_us_width / 2;
614                         gs_p->c[RW] = -half_us_width / 2;
615
616                         /* apply global user requested padding; notice that
617                          * normal spaces (s) don't get this */
618                         gs_p->c[RW] -= vvpath(gs_p->staffno,
619                                                 gs_p->vno, PAD)->pad;
620                 }
621
622                 /* add any user requested padding */
623                 gs_p->c[RW] -= gs_p->padding;
624         }
625 }
626 \f
627 /*
628  * Name:        finalgroupproc()
629  *
630  * Abstract:    Do final processing of groups.
631  *
632  * Returns:     pointer to the first GRPSYL after these groups, 0 if none
633  *
634  * Description: This function is given the GRPSYL for the first (topmost) voice
635  *              that is on this staff in this chord.  It find what other
636  *              GRPSYLs exist.  For all the nonspace groups, it applies any
637  *              horizontal offsets needed.
638  */
639
640 static struct GRPSYL *
641 finalgroupproc(gs1_p)
642
643 struct GRPSYL *gs1_p;           /* first voice on this staff in this chord */
644
645 {
646         struct GRPSYL *g_p[MAXVOICES];  /* point at nonspace voices' groups */
647         struct GRPSYL *gs_p;            /* point at groups in the chord */
648         struct GRPSYL *last_p;          /* point at last nonspace group */
649         int numgrps;                    /* how many nonspace groups are here */
650         int staffno;                    /* staff these groups are on */
651         int n;                          /* loop variable */
652         float offset;                   /* of each when + and - are used */
653         float edge;                     /* west or east coord of group 1 or 2 */
654         int pack;                       /* optimization for voice 3 */
655
656
657         staffno = gs1_p->staffno;       /* remember staffno of first group */
658         numgrps = 0;                    /* no groups found yet */
659         last_p = 0;                     /* no last nonspace group yet */
660
661         /* find all groups in this chord on this staff; remember nonspaces */
662         for (gs_p = gs1_p; gs_p != 0 && gs_p->staffno == staffno &&
663                             gs_p->grpsyl == GS_GROUP; gs_p = gs_p->gs_p) {
664                 if (gs_p->grpcont != GC_SPACE) {
665                         g_p[numgrps++] = gs_p;
666                         last_p = gs_p;
667                 }
668         }
669
670         /*
671          * If all groups on this staff were spaces, just make sure clef is
672          * marked correctly and return, though it's unlikely we have a clef
673          * change before a space.
674          */
675         if (numgrps == 0) {
676                 fixclef(gs1_p);
677                 return (gs_p);
678         }
679
680         /* nothing to do for tab, since "ho" is ignored and rests invisible */
681         if (is_tab_staff(g_p[0]->staffno))
682                 return (gs_p);
683
684         /* for any voice with a user supplied offset value, apply it now */
685         for (n = 0; n < numgrps; n++) {
686                 if (g_p[n]->ho_usage == HO_VALUE)
687                         shiftgs(g_p[n], g_p[n]->ho_value * STEPSIZE);
688         }
689
690         /*
691          * If both voices 1 and 2 are nonspace, handle any ho "+" or "-".
692          */
693         if (numgrps >= 2 && g_p[0]->vno == 1 && g_p[1]->vno == 2) {
694                 /*
695                  * Verify and fix offsets.  We did this in setgrps.c for note
696                  * groups so that compatible note groups could then be handled
697                  * together.  But we need to check again in case rest groups
698                  * are involved.
699                  */
700                 vfyoffset(g_p);
701
702                 /*
703                  * Check each of these 2 groups:  If it has "+" or "-" and the
704                  * other one doesn't, shift it to be next to the other one on
705                  * the appropriate side.
706                  */
707                 for (n = 0; n < 2; n++) {
708                         if ((g_p[n]->ho_usage == HO_LEFT ||
709                              g_p[n]->ho_usage == HO_RIGHT) &&
710                           ! (g_p[1-n]->ho_usage == HO_LEFT ||
711                              g_p[1-n]->ho_usage == HO_RIGHT)) {
712
713                                 if (g_p[n]->ho_usage == HO_LEFT) {
714                                         shiftgs(g_p[n],
715                                         g_p[1-n]->c[RW] - g_p[n]->c[RE]);
716                                 } else {
717                                         shiftgs(g_p[n],
718                                         g_p[1-n]->c[RE] - g_p[n]->c[RW]);
719                                 }
720                         }
721                 }
722
723                 /*
724                  * If one has "+" and one has "-", shift them each by half of
725                  * the amount of space needed to avoid a collision.
726                  */
727                 if (g_p[0]->ho_usage == HO_LEFT &&
728                     g_p[1]->ho_usage == HO_RIGHT) {
729
730                         offset = (g_p[0]->c[RE] - g_p[1]->c[RW]) / 2.0;
731                         shiftgs(g_p[0], -offset);
732                         shiftgs(g_p[1], offset);
733                 }
734                 if (g_p[0]->ho_usage == HO_RIGHT &&
735                     g_p[1]->ho_usage == HO_LEFT) {
736
737                         offset = (g_p[1]->c[RE] - g_p[0]->c[RW]) / 2.0;
738                         shiftgs(g_p[0], offset);
739                         shiftgs(g_p[1], -offset);
740                 }
741
742         } else if (g_p[0]->vno != 3) {
743                 /*
744                  * If only one of groups 1 and 2 is nonspace, check whether it
745                  * has "+" or "-", and warn if so.
746                  */
747                 if (g_p[0]->ho_usage == HO_LEFT || g_p[0]->ho_usage == HO_RIGHT)
748                 {
749                         l_warning(
750                                 g_p[0]->inputfile, g_p[0]->inputlineno,
751                                 "voice %d cannot have horizontal offset '%c' since voice %d is not present; ignoring it",
752                                 g_p[0]->vno,
753                                 g_p[0]->ho_usage == HO_LEFT ? '-' :'+',
754                                 3 - g_p[0]->vno);
755
756                         g_p[0]->ho_usage = HO_NONE;
757                 }
758         }
759
760         /*
761          * If voice 3 and at least one other voice exist here, and the user
762          * didn't state an offset value for voice 3, offset it next to the
763          * other voices, on the left or right, as requested.  But exclude the
764          * case where voice 3 was being treated as 1 or 2, by checking pvno
765          * instead of vno.
766          */
767         if (numgrps > 1 && last_p->pvno == 3 && last_p->ho_usage != HO_VALUE) {
768                 /*
769                  * See if we can pack v3 tightly against v1 and v2.  (This will
770                  * not be allowed if ho_usage != HO_NONE for any voice, or any
771                  * other of many conditions doesn't hold true.)
772                  */
773                 pack = v3pack(g_p, numgrps);
774                 if (pack != PK_NONE) {
775                         /*
776                          * Yes, we can; shift v3 a little if necessary.  Make
777                          * it so that v3's stem is one stepsize away from the
778                          * group that its stem is pointing toward.
779                          */
780                         switch (pack) {
781                         case PK_LEFT:
782                                 /* since v3 is on left, v2 must exist, and is
783                                  * the voice preceding v3 in g_p */
784                                 shiftgs(last_p, -STEPSIZE +
785                                         widest_head(last_p) / 2.0 +
786                                         g_p[numgrps-2]->c[RW]);
787                                 break;
788                         case PK_RIGHT:
789                                 /* since v3 is on right, v1 must exist, and is
790                                  * the first voice in g_p */
791                                 shiftgs(last_p, STEPSIZE +
792                                         g_p[0]->c[RE] -
793                                         widest_head(last_p) / 2.0);
794                                 break;
795                         /* for PK_CENTER, nothing to do */
796                         }
797
798                 } else if (last_p->ho_usage == HO_LEFT) {
799
800                         /* find leftmost edge of the other voice(s) */
801                         edge = g_p[0]->c[RW];
802                         for (n = 1; n < numgrps - 1; n++) {
803                                 if (g_p[n]->c[RW] < edge)
804                                         edge = g_p[n]->c[RW];
805                         }
806                         /* set right edge of voice 3 == left edge of others */
807                         shiftgs(last_p, edge - last_p->c[RE]);
808
809                 } else { /* HO_RIGHT, or HO_NONE which defaults to HO_RIGHT */
810
811                         /* find rightmost edge of the other voice(s) */
812                         edge = g_p[0]->c[RE];
813                         for (n = 1; n < numgrps - 1; n++) {
814                                 if (g_p[n]->c[RE] > edge)
815                                         edge = g_p[n]->c[RE];
816                         }
817                         /* set left edge of voice 3 == right edge of others */
818                         shiftgs(last_p, edge - last_p->c[RW]);
819                 }
820         } else if (g_p[0]->vno == 3 && (g_p[0]->ho_usage == HO_LEFT ||
821                                         g_p[0]->ho_usage == HO_RIGHT)) {
822                 /*
823                  * If the first (and thus only) voice is 3, it should not have
824                  * ho "+" or "-".
825                  */
826                 l_warning(
827                         g_p[0]->inputfile, g_p[0]->inputlineno,
828                         "voice 3 cannot have horizontal offset '%c' since voices 1 and 2 are not present; ignoring it",
829                         g_p[0]->ho_usage == HO_LEFT ? '-' :'+');
830
831                 g_p[0]->ho_usage = HO_NONE;
832         }
833
834         /* in case of midmeasure clef change, make sure it's marked right */
835         fixclef(gs1_p);
836
837         /* return the first GRPSYL after the groups we processed */
838         return (gs_p);
839 }
840 \f
841 /*
842  * Name:        v3pack()
843  *
844  * Abstract:    Decide whether v3 can be packed tighter than the default.
845  *
846  * Returns:     PK_NONE         no, it can't
847  *              PK_LEFT         pack tightly on left
848  *              PK_RIGHT        pack tightly on right
849  *              PK_CENTER       pack in the center
850  *
851  * Description: This function decides whether the voice 3 group can be packed
852  *              in more tightly against voices 1 and 2 than the usual default
853  *              of just putting v3's group's rectangle to the right of the
854  *              other voices.  If there seems to be any danger that v3 would
855  *              collide with v1 or v2, it gives up and returns PK_NONE.  It
856  *              could be made a lot more sophisticated and not give up so soon
857  *              in many cases.  However many of these improvements can't be
858  *              done very well at this stage of the game, where we don't know
859  *              yet about stem lengths, beam positions, etc.
860  */
861
862 static int
863 v3pack(g_p, numgrps)
864
865 struct GRPSYL *g_p[];           /* point at nonspace voices' groups */
866 int numgrps;                    /* how many nonspace groups are here */
867
868 {
869         struct GRPSYL *gs_p;            /* point at a group */
870         struct GRPSYL *v3_p;            /* point at v3's group */
871         struct NOTE *v3note_p;          /* v3 note that neighbors other voice*/
872         struct NOTE *onote_p;           /* v1/v2 note that neighbors v3 */
873         float north;                    /* highest coord of note or acc */
874         float south;                    /* lowest coord of note or acc */
875         float topdesc;                  /* descent of acc of top group */
876         float botasc;                   /* ascent of acc of bottom group */
877         int v3hasacc, otherhasacc;      /* do v3 and other voice have acc(s)?*/
878         int pack;
879         int n;                          /* loop variable */
880         int k;                          /* loop variable */
881
882
883         /* either v1 or v2 must be nonspace */
884         if (numgrps == 1) {
885                 return (PK_NONE);
886         }
887
888         /* point at v3's group for convenience */
889         v3_p = g_p[numgrps - 1];
890
891         /* set up what the answer will be if we can apply the optimization */
892         if (v3_p->basictime >= 2) {
893                 /* there is a stem, so offset such that stem will avoid v1/v2 */
894                 if (v3_p->stemdir == UP) {
895                         pack = PK_RIGHT;
896                 } else {        /* DOWN */
897                         pack = PK_LEFT;
898                 }
899         } else {
900                 pack = PK_CENTER;       /* no stem, so we can center v3 */
901         }
902
903         /* v3 must not be standing in for v1 or v2 */
904         if (v3_p->pvno != 3) {
905                 return (PK_NONE);
906         }
907
908         /* if v3 would be on left, it must not have a flag or be start of beam*/
909         if (pack == PK_LEFT && (v3_p->basictime >= 8 && v3_p->beamloc == NOITEM
910                                 || v3_p->beamloc == STARTITEM)) {
911                 return (PK_NONE);
912         }
913
914         /* if v3 would be on right, it must not have grace groups preceding */
915         if (pack == PK_RIGHT && v3_p->prev != 0 &&
916                                 v3_p->prev->grpvalue == GV_ZERO) {
917                 return (PK_NONE);
918         }
919
920         /* v3 cannot have slashes or alternation */
921         if (v3_p->slash_alt != 0) {
922                 return (PK_NONE);
923         }
924
925         /*
926          * Loop through all voices, checking for rule violations.  We do it
927          * in reverse so that we know v3 is notes (the first check) before
928          * checking the other voices.
929          */
930         for (n = numgrps - 1; n >= 0; n--) {
931                 gs_p = g_p[n];  /* set to current voice for convenience */
932
933                 /* voice must be notes, and not measure repeat */
934                 if (gs_p->grpcont != GC_NOTES || gs_p->is_meas) {
935                         return (PK_NONE);
936                 }
937
938                 /* voice cannot have user requested horizontal offset */
939                 if (gs_p->ho_usage != HO_NONE) {
940                         return (PK_NONE);
941                 }
942
943                 /* voice cannot have a "with" list */
944                 if (gs_p->nwith != 0) {
945                         return (PK_NONE);
946                 }
947
948                 /* voice cannot have a roll */
949                 if (gs_p->roll != NOITEM) {
950                         return (PK_NONE);
951                 }
952
953                 /* do voice specific checks */
954                 switch (gs_p->vno) {
955
956                 case 1:
957                         /* stem must be up */
958                         if (gs_p->stemdir != UP) {
959                                 return (PK_NONE);
960                         }
961
962                         /* find neighboring notes of v1 and v3 */
963                         v3note_p = &v3_p->notelist[0];
964                         onote_p = &gs_p->notelist[gs_p->nnotes - 1];
965
966                         /* neighboring notes in v1 & v3 must not be too close */
967                         if (onote_p->stepsup < v3note_p->stepsup + 2 ||
968                         onote_p->stepsup == v3note_p->stepsup + 2 &&
969                         pack != PK_CENTER &&
970                         (v3_p->basictime < 1 || gs_p->basictime < 1)) {
971                                 return (PK_NONE);
972                         }
973
974                         /* if 2 steps apart and on lines and v3 would not be on
975                          * right, v1 can't have dots and v3 can't unless it
976                          * is on the right */
977                         if (onote_p->stepsup == v3note_p->stepsup + 2 &&
978                         EVEN(v3note_p->stepsup) &&
979                         (gs_p->dots != 0 ||
980                         pack != PK_RIGHT && v3_p->dots != 0)) {
981                                 return (PK_NONE);
982                         }
983
984                         /*
985                          * Find the lowest extension of any accidental in v1.
986                          * If no accidentals, the initial value for "south"
987                          * will remain.  It's not good enough to check accs
988                          * only on the neighboring notes, because some of them
989                          * stick out pretty far.  We have to go through these
990                          * gyrations because group boundaries do not consider
991                          * accidentals that stick out up or down.
992                          */
993                         otherhasacc = NO;
994                         south = onote_p->c[RY] - STEPSIZE + 0.001;
995                         for (k = 0; k < gs_p->nnotes; k++) {
996                                 accdimen(&gs_p->notelist[k], (float *)0,
997                                                 &topdesc, (float *)0);
998                                 if (gs_p->notelist[k].c[RY] - topdesc < south) {
999                                         south = gs_p->notelist[k].c[RY]
1000                                                         - topdesc;
1001                                 }
1002                                 if (gs_p->notelist[k].accidental != '\0') {
1003                                         otherhasacc = YES;
1004                                 }
1005                         }
1006                         /* similarly, find highest extension of v3 accs */
1007                         v3hasacc = NO;
1008                         north = v3note_p->c[RY] + STEPSIZE - 0.001;
1009                         for (k = 0; k < v3_p->nnotes; k++) {
1010                                 accdimen(&v3_p->notelist[k], &botasc,
1011                                                 (float *)0, (float *)0);
1012                                 if (v3_p->notelist[k].c[RY] + botasc > north) {
1013                                         north = v3_p->notelist[k].c[RY]
1014                                                         + botasc;
1015                                 }
1016                                 if (v3_p->notelist[k].accidental != '\0') {
1017                                         v3hasacc = YES;
1018                                 }
1019                         }
1020                         /* if v1 and v3 overlap due to acc(s), fail */
1021                         if (south < north) {
1022                                 switch (pack) {
1023                                 case PK_RIGHT:
1024                                         if (v3hasacc == YES) {
1025                                                 return (PK_NONE);
1026                                         }
1027                                         break;
1028                                 case PK_CENTER:
1029                                         if (v3hasacc == YES &&
1030                                             otherhasacc == YES) {
1031                                                 return (PK_NONE);
1032                                         }
1033                                         break;
1034                                 case PK_LEFT:
1035                                         if (otherhasacc == YES) {
1036                                                 return (PK_NONE);
1037                                         }
1038                                         break;
1039                                 }
1040                         }
1041
1042                         /* if left or right offset, neighboring notes in v1 &
1043                          * v3 must not have parentheses when accs exist */
1044                         if ((pack != PK_CENTER || v3hasacc == YES || otherhasacc == YES) &&
1045                            (v3note_p->note_has_paren || onote_p->note_has_paren)) {
1046                                 return (PK_NONE);
1047                         }
1048
1049                         break;
1050
1051                 case 2:
1052                         if (gs_p->stemdir != DOWN) {
1053                                 return (PK_NONE);
1054                         }
1055
1056                         /* find neighboring notes of v2 and v3 */
1057                         v3note_p = &v3_p->notelist[v3_p->nnotes - 1];
1058                         onote_p = &gs_p->notelist[0];
1059
1060                         /* neighboring notes in v1 & v3 must not be too close */
1061                         if (onote_p->stepsup > v3note_p->stepsup - 2 ||
1062                         onote_p->stepsup == v3note_p->stepsup - 2 &&
1063                         pack != PK_CENTER &&
1064                         (v3_p->basictime < 1 || gs_p->basictime < 1)) {
1065                                 return (PK_NONE);
1066                         }
1067
1068                         /* if 2 steps apart and on lines and v3 would not be on
1069                          * right, neither can have dots */
1070                         if (onote_p->stepsup == v3note_p->stepsup - 2 &&
1071                                         EVEN(v3note_p->stepsup) &&
1072                                         pack != PK_RIGHT &&
1073                                         (gs_p->dots != 0 || v3_p->dots != 0)) {
1074                                 return (PK_NONE);
1075                         }
1076
1077                         /*
1078                          * Find the highest extension of any accidental in v2.
1079                          * If no accidentals, the initial value for "north"
1080                          * will remain.
1081                          */
1082                         otherhasacc = NO;
1083                         north = onote_p->c[RY] + STEPSIZE - 0.001;
1084                         for (k = 0; k < gs_p->nnotes; k++) {
1085                                 accdimen(&gs_p->notelist[k], &botasc,
1086                                                 (float *)0, (float *)0);
1087                                 if (gs_p->notelist[k].c[RY] + botasc > north) {
1088                                         north = gs_p->notelist[k].c[RY]
1089                                                         + botasc;
1090                                 }
1091                                 if (gs_p->notelist[k].accidental != '\0') {
1092                                         otherhasacc = YES;
1093                                 }
1094                         }
1095                         /* similarly, find highest extension of v3 accs */
1096                         v3hasacc = NO;
1097                         south = v3note_p->c[RY] - STEPSIZE + 0.001;
1098                         for (k = 0; k < v3_p->nnotes; k++) {
1099                                 accdimen(&v3_p->notelist[k], (float *)0,
1100                                                 &topdesc, (float *)0);
1101                                 if (v3_p->notelist[k].c[RY] - topdesc < south) {
1102                                         south = v3_p->notelist[k].c[RY]
1103                                                         - topdesc;
1104                                 }
1105                                 if (v3_p->notelist[k].accidental != '\0') {
1106                                         v3hasacc = YES;
1107                                 }
1108                         }
1109                         /* if v2 and v3 overlap due to acc(s), fail */
1110                         if (south < north) {
1111                                 switch (pack) {
1112                                 case PK_RIGHT:
1113                                         if (v3hasacc == YES) {
1114                                                 return (PK_NONE);
1115                                         }
1116                                         break;
1117                                 case PK_CENTER:
1118                                         if (v3hasacc == YES &&
1119                                             otherhasacc == YES) {
1120                                                 return (PK_NONE);
1121                                         }
1122                                         if (v3hasacc == YES &&
1123                                         gs_p->nnotes >= 2 &&
1124                                         onote_p->stepsup ==
1125                                         gs_p->notelist[1].stepsup + 1) {
1126                                                 return (PK_NONE);
1127                                         }
1128                                         break;
1129                                 case PK_LEFT:
1130                                         if (otherhasacc == YES) {
1131                                                 return (PK_NONE);
1132                                         }
1133                                         break;
1134                                 }
1135                         }
1136
1137                         /* if left or right offset, neighboring notes in v2 &
1138                          * v3 must not have parentheses when accs exist */
1139                         if ((pack != PK_CENTER || v3hasacc == YES || otherhasacc == YES) &&
1140                            (v3note_p->note_has_paren || onote_p->note_has_paren)) {
1141                                 return (PK_NONE);
1142                         }
1143
1144                         break;
1145                 }
1146         }
1147
1148         /* all checks passed, so return the answer */
1149         return (pack);
1150 }
1151 \f
1152 /*
1153  * Name:        fixclef()
1154  *
1155  * Abstract:    If midmeasure clef change at this chord, mark in right GRPSYL.
1156  *
1157  * Returns:     void
1158  *
1159  * Description: This function is given the GRPSYL for the first (topmost) voice
1160  *              that is on this staff in this chord.  If the clef changed at
1161  *              this time value, locllnotes() in setnotes.c will have set the
1162  *              "clef" field in each of the GRPSYLs in this chord on this
1163  *              staff (actually in their first preceding grace group, if
1164  *              any).  But it should only be set in the GRPSYL that has the
1165  *              westernmost west boundary.  So this function erases it from
1166  *              any other GRPSYLs.
1167  */
1168
1169 static void
1170 fixclef(gs1_p)
1171
1172 struct GRPSYL *gs1_p;           /* starts at first voice on this staff */
1173
1174 {
1175         struct GRPSYL *g_p[MAXVOICES];  /* point at voices' groups */
1176         struct GRPSYL *gs_p;            /* point at groups in the chord */
1177         int numgrps;                    /* how many groups are in the chord */
1178         struct GRPSYL *westgs_p;        /* remember westernmost */
1179         int staffno;                    /* staff number */
1180         int n;                          /* loop variable */
1181
1182
1183         staffno = gs1_p->staffno;       /* remember staffno of first group */
1184
1185         /* point at all groups in this chord on this staff */
1186         numgrps = 0;                    /* no groups found yet */
1187         for (gs_p = gs1_p; gs_p != 0 && gs_p->staffno == staffno &&
1188                             gs_p->grpsyl == GS_GROUP; gs_p = gs_p->gs_p) {
1189                 g_p[numgrps++] = gs_p;
1190         }
1191
1192         /*
1193          * For each that is preceded by grace group(s), change the pointer to
1194          * point at the first in that sequence of grace groups.  Any clef
1195          * change would occur at that group.
1196          */
1197         for (n = 0; n < numgrps; n++) {
1198                 while (g_p[n]->prev != 0 && g_p[n]->prev->grpvalue == GV_ZERO) {
1199                         g_p[n] = g_p[n]->prev;
1200                 }
1201         }
1202
1203         /* if clef not marked in first, it's not marked in any, so return */
1204         if (g_p[0]->clef == NOCLEF) {
1205                 return;
1206         }
1207
1208         westgs_p = 0;   /* prevent useless "used before set" warning */
1209
1210         /*
1211          * Find the westernmost group of notes, if any; if it's a tie, use the
1212          * first one.  We don't want to put clefs in front of rests, spaces, or
1213          * mrpt, unless we have no choice.
1214          */
1215         for (n = 0; n < numgrps; n++) {
1216                 if (g_p[n]->grpcont == GC_NOTES && g_p[n]->is_meas == NO) {
1217                         if (westgs_p == 0 || g_p[n]->c[RW] < westgs_p->c[RW]) {
1218                                 westgs_p = g_p[n];
1219                         }
1220                 }
1221         }
1222         /* we have no choice; arbitrarily choose the first voice */
1223         if (westgs_p == NULL) {
1224                 westgs_p = g_p[0];
1225         }
1226
1227         /* erase clef from all but the group found above */
1228         for (n = 0; n < numgrps; n++) {
1229                 if (g_p[n] != westgs_p) {
1230                         g_p[n]->clef = NOCLEF;
1231                 }
1232         }
1233
1234         /* if there were no notes, there will be no clef here */
1235         if (westgs_p == 0) {
1236                 return;
1237         }
1238
1239         /* move western boundary of GRPSYL to allow room to print the clef */
1240         westgs_p->c[RW] -= clefwidth(westgs_p->clef, YES) + CLEFPAD;
1241
1242         /*
1243          * If this is a grace group, we also have to alter its main group's
1244          * boundary, because the main group's boundary needs to enclose all
1245          * its grace groups.
1246          */
1247         for (gs_p = westgs_p; gs_p->grpvalue == GV_ZERO; gs_p = gs_p->next) {
1248                 ;
1249         }
1250         if (gs_p != westgs_p) {
1251                 gs_p->c[RW] -= clefwidth(westgs_p->clef, YES) + CLEFPAD;
1252         }
1253 }
1254 \f
1255 /*
1256  * Name:        restsize()
1257  *
1258  * Abstract:    Find the size of a rest.
1259  *
1260  * Returns:     void
1261  *
1262  * Description: This function is given a GRPSYL which is a rest.  It returns
1263  *              the width, ascent, and descent through pointers.
1264  */
1265
1266 static void
1267 restsize(gs_p, wid_p, asc_p, des_p)
1268
1269 register struct GRPSYL *gs_p;   /* the GRPSYL containing the rest */
1270 float *wid_p, *asc_p, *des_p;   /* return width, ascent, and descent of rest */
1271
1272 {
1273         char rchar;             /* char for the rest */
1274         int size;               /* font size */
1275
1276
1277         /* multirest has no music character; just return the answer */
1278         if (gs_p->basictime < -1) {
1279                 *wid_p = MINMULTIWIDTH;
1280                 *asc_p = 2 * STEPSIZE;
1281                 *des_p = 2 * STEPSIZE;
1282                 return;
1283         }
1284
1285         /* on a tab staff rests are invisible, so set to a very small size */
1286         if (is_tab_staff(gs_p->staffno)) {
1287                 *wid_p = *asc_p = *des_p = 0.01;
1288                 return;
1289         }
1290
1291         /*
1292          * The "normal" rest case.  Find the name of the character.  Then get
1293          * the width, ascent, and descent of the rest.
1294          */
1295         rchar = restchar(gs_p->basictime);
1296         size = (gs_p->grpsize == GS_NORMAL ? DFLT_SIZE : SMALLSIZE);
1297         *wid_p = width(FONT_MUSIC, size, rchar);
1298         *asc_p = ascent(FONT_MUSIC, size, rchar);
1299         *des_p = descent(FONT_MUSIC, size, rchar);
1300 }
1301 \f
1302 /*
1303  * Name:        procsyls()
1304  *
1305  * Abstract:    Sets relative horizontal coords for syllables in 1 GRPSYL list.
1306  *
1307  * Returns:     void
1308  *
1309  * Description: This function goes down one of the linked lists of GRPSYLs,
1310  *              one that is for syllables, not groups, and sets the relative
1311  *              horizontal coordinates for each syllable found.
1312  */
1313
1314 static void
1315 procsyls(gs_p)
1316
1317 register struct GRPSYL *gs_p;   /* starts pointing at first GRPSYL in list */
1318
1319 {
1320         float wid_b4_syl;       /* width of leading non-lyrics */
1321         float wid_real_syl;     /* width of actual lyric */
1322         float wid_after_syl;    /* width of trailing non-lyrics */
1323         float lyricsalign;      /* fraction of syl to go left of chord center*/
1324         int font, size;         /* of the last char in a syllable */
1325         char lc;                /* last char of syllable */
1326
1327
1328         debug(32, "procsyls file=%s line=%d", gs_p->inputfile,
1329                         gs_p->inputlineno);
1330         /* find what fraction of each syl should go left of center of chord */
1331         lyricsalign = svpath(gs_p->staffno, LYRICSALIGN)->lyricsalign;
1332
1333         /*
1334          * Set coords for every syllable.  A syllable can consist of 3 parts.
1335          * The middle part is the actual lyric.  The optional first and last
1336          * parts are surrounded in the user's input by angle brackets.  The
1337          * syllable is to be positioned such that "lyricsalign" of the middle
1338          * part goes to the left of the chord's center, and the rest goes to
1339          * the right; unless sylposition is set, in which case the left edge of
1340          * the actual lyric is offset by that many points from the chord's
1341          * center.  Then adjust the east side for padding purposes.
1342          */
1343         for ( ; gs_p != 0; gs_p = gs_p->next) {
1344                 sylwidth(gs_p->syl, &wid_b4_syl, &wid_real_syl, &wid_after_syl);
1345
1346                 gs_p->c[RX] = 0;
1347                 if (gs_p->sylposition == NOSYLPOSITION) {
1348                         gs_p->c[RW] = -lyricsalign * wid_real_syl - wid_b4_syl;
1349                         gs_p->c[RE] = (1 - lyricsalign) * wid_real_syl +
1350                                         wid_after_syl;
1351                 } else {
1352                         gs_p->c[RW] = gs_p->sylposition * POINT - wid_b4_syl;
1353                         gs_p->c[RE] = gs_p->sylposition * POINT + wid_real_syl +
1354                                         wid_after_syl;
1355                 }
1356
1357                 /* get last char of syl; if null syl don't alter RE any more */
1358                 lc = last_char(gs_p->syl);
1359                 if (lc == '\0')
1360                         continue;
1361
1362                 /*
1363                  * If this is not the last syllable of the measure, and it
1364                  * doesn't end in '-', leave space for a blank after it, to
1365                  * separate it from the next syllable.
1366                  */
1367                 if ( gs_p->next != 0 && lc != '-') {
1368                         end_fontsize(gs_p->syl, &font, &size);
1369                         gs_p->c[RE] += width(font, size, ' ');
1370                 }
1371
1372                 /*
1373                  * If this is the last syllable of the measure, and it ends in
1374                  * '-', back up a space, letting the '-' go into the bar line.
1375                  */
1376                 if ( gs_p->next == 0 && lc == '-' ) {
1377                         end_fontsize(gs_p->syl, &font, &size);
1378                         gs_p->c[RE] -= width(font, size, ' ');
1379                 }
1380         }
1381 }
1382 \f
1383 /*
1384  * Name:        apply_staffscale()
1385  *
1386  * Abstract:    Scale all relative coordinates according to staffscale.
1387  *
1388  * Returns:     void
1389  *
1390  * Description: Throughout Mup, we are able to almost entirely avoid dealing
1391  *              with the "scale" parameter, by the following trick:  We pretend
1392  *              the paper is a different size than it really is, by the inverse
1393  *              of the "scale" factor, place and print everything at standard
1394  *              size, and then at the end apply the scale to everything at
1395  *              once, in PostScript.  (Margins are exempt from scaling, hence
1396  *              the EFF_* macros to cancel it out.)
1397  *
1398  *              But for the "staffscale" parameter, this kind of trick only
1399  *              works up to a point.  As long as we are dealing only with
1400  *              relative coords on one staff at a time, as we have up to this
1401  *              point in the program, we can ignore staffscale.  But now we're
1402  *              about to start dealing with chord coords, and chords span
1403  *              staffs.  So the jig is up.
1404  *
1405  *              This function goes through all the relative coords set so far,
1406  *              and scales them according to staffscale.  It also scales the
1407  *              font sizes in strings.  From this point on staffscale must
1408  *              always be considered.
1409  */
1410
1411 static void
1412 apply_staffscale()
1413
1414 {
1415         struct MAINLL *mainll_p;        /* point at items in main linked list*/
1416         struct STAFF *staff_p;          /* point at a staff structure */
1417         register float staffscale;      /* current staffscale */
1418         register struct GRPSYL *gs_p;   /* point at groups */
1419         register struct NOTE *note_p;   /* point at notes */
1420         struct STUFF *stuff_p;          /* point at a stuff structure */
1421         int n;                          /* loop variable */
1422         int v;                          /* voice number, 0 to 2 */
1423
1424
1425         debug(16, "apply_staffscale");
1426
1427         initstructs();
1428
1429         /*
1430          * Loop down the main linked list looking for each staff.
1431          */
1432         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1433
1434                 switch (mainll_p->str) {
1435                 case S_SSV:
1436                         /* apply SSVs to keep staffscale up to date */
1437                         asgnssv(mainll_p->u.ssv_p);
1438                         continue;
1439
1440                 case S_STAFF:
1441                         staff_p = mainll_p->u.staff_p;
1442                         break;          /* break out to handle staffs */
1443
1444                 default:
1445                         continue;       /* nothing to do */
1446                 }
1447
1448                 /* get staffscale for this staff in this measure */
1449                 staffscale = svpath(staff_p->staffno, STAFFSCALE)->staffscale;
1450
1451                 /* go through each voice this staff has */
1452                 for (v = 0; v < MAXVOICES; v++) {
1453
1454                         /* and each group in each voice */
1455                         for (gs_p = staff_p->groups_p[v]; gs_p != 0;
1456                                         gs_p = gs_p->next) {
1457
1458                                 /* scale the group's relative coords */
1459                                 gs_p->c[RX] *= staffscale;
1460                                 gs_p->c[RN] *= staffscale;
1461                                 gs_p->c[RY] *= staffscale;
1462                                 gs_p->c[RS] *= staffscale;
1463
1464                                 /* but don't disturb this E,W constant value */
1465                                 /* (see setgrps.c and abshorz.c) */
1466                                 if (gs_p->c[RE] != TEMPMRPTWIDTH / 2.0) {
1467                                         gs_p->c[RE] *= staffscale;
1468                                         gs_p->c[RW] *= staffscale;
1469                                 }
1470
1471                                 gs_p->xdotr *= staffscale;
1472
1473                                 /* usually we're done caring about padding */
1474                                 /*  by now, but not always, so scale it */
1475                                 gs_p->padding *= staffscale;
1476
1477                                 if (gs_p->grpcont == GC_NOTES) {
1478                                         for (n = 0; n < gs_p->nnotes; n++) {
1479                                                 note_p = &gs_p->notelist[n];
1480
1481                                                 /* scale note's rel. coords */
1482                                                 note_p->c[RW] *= staffscale;
1483                                                 note_p->c[RX] *= staffscale;
1484                                                 note_p->c[RE] *= staffscale;
1485                                                 note_p->c[RN] *= staffscale;
1486                                                 note_p->c[RY] *= staffscale;
1487                                                 note_p->c[RS] *= staffscale;
1488
1489                                                 note_p->waccr *= staffscale;
1490                                                 note_p->ydotr *= staffscale;
1491                                                 note_p->wlparen *= staffscale;
1492                                                 note_p->erparen *= staffscale;
1493
1494                                                 /* this isn't really scaling,
1495                                                  * but it's a convenient place
1496                                                  * to undo CSS_STEPS */
1497                                                 if (gs_p->stemto == CS_ABOVE &&
1498                                                     n <= gs_p->stemto_idx) {
1499                                                         gs_p->notelist[n].stepsup -= CSS_STEPS;
1500                                                         gs_p->notelist[n].ydotr -=
1501                                                         CSS_STEPS * STEPSIZE * staffscale;
1502                                                 } else if (gs_p->stemto == CS_BELOW &&
1503                                                     n >= gs_p->stemto_idx) {
1504                                                         gs_p->notelist[n].stepsup += CSS_STEPS;
1505                                                         gs_p->notelist[n].ydotr +=
1506                                                         CSS_STEPS * STEPSIZE * staffscale;
1507                                                 }
1508                                         }
1509                                 }
1510
1511                                 for (n = 0; n < gs_p->nwith; n++) {
1512                                         (void)resize_string(gs_p->withlist[n],
1513                                                 staffscale,
1514                                                 gs_p->inputfile,
1515                                                 gs_p->inputlineno);
1516                                 }
1517                         }
1518                 }
1519
1520                 /* scale the syllables' coords and font sizes */
1521                 for (v = 0; v < staff_p->nsyllists; v++) {
1522                         for (gs_p = staff_p->syls_p[v]; gs_p != 0;
1523                                                         gs_p = gs_p->next) {
1524                                 gs_p->c[RW] *= staffscale;
1525                                 gs_p->c[RX] *= staffscale;
1526                                 gs_p->c[RE] *= staffscale;
1527                                 gs_p->c[RN] *= staffscale;
1528                                 gs_p->c[RY] *= staffscale;
1529                                 gs_p->c[RS] *= staffscale;
1530
1531                                 (void)resize_string(gs_p->syl, staffscale,
1532                                         gs_p->inputfile, gs_p->inputlineno);
1533                         }
1534                 }
1535
1536                 /* scale the STUFF structures' font sizes */
1537                 /* (their coords won't be set until we get to stuff.c) */
1538                 for (stuff_p = staff_p->stuff_p; stuff_p != 0;
1539                                 stuff_p = stuff_p->next) {
1540                         if (stuff_p->string != 0) {
1541                                 (void)resize_string(
1542                                         stuff_p->string,
1543                                         stuff_p->all == YES ? Score.staffscale
1544                                                         : staffscale,
1545                                         stuff_p->inputfile,
1546                                         stuff_p->inputlineno);
1547                         }
1548                 }
1549         }
1550 }
1551 \f
1552 /*
1553  * Name:        relxchord()
1554  *
1555  * Abstract:    Set relative horizontal coordinates of each chord.
1556  *
1557  * Returns:     void
1558  *
1559  * Description: This function goes through the chord lists, and for each chord,
1560  *              sets its horizontal relative coordinates, by going down the
1561  *              list of GRPSYLs hanging off it.
1562  */
1563
1564 static void
1565 relxchord()
1566
1567 {
1568         struct CHORD *ch_p;             /* point at a chord */
1569         struct CHORD *pch_p;            /* point at previous chord */
1570         struct CHORD *ppch_p;           /* point at chord before that */
1571         struct MAINLL *mainll_p;        /* point at items in main linked list*/
1572         struct GRPSYL *gs_p;            /* point at groups */
1573         struct GRPSYL *nsyl_p;          /* point at next syl */
1574         struct GRPSYL *psyl_p;          /* point at previous syl */
1575         float stealable;                /* from previous chord */
1576         float eff;                      /* effective coord */
1577
1578
1579         debug(16, "relxchord");
1580         initstructs();
1581
1582         /*
1583          * Loop down the main linked list looking for each chord list headcell.
1584          */
1585         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
1586
1587                 /* need to keep "pad" up to date */
1588                 if (mainll_p->str == S_SSV)
1589                         asgnssv(mainll_p->u.ssv_p);
1590
1591                 if (mainll_p->str != S_CHHEAD)
1592                         continue;       /* skip everything but chord HC */
1593
1594                 /*
1595                  * Pretend that all the chords will be jammed tightly together,
1596                  * starting at absolute coordinate zero.  We set absolute
1597                  * coords here for the benefit of effwest(), but they will be
1598                  * overwritten with their true values later in abshorz().
1599                  */
1600                 mainll_p->u.chhead_p->ch_p->c[AW] = 0.0; /* west of 1st chord*/
1601
1602                 /*
1603                  * First, loop forwards through the chord list, setting the
1604                  * boundaries and widths of each chord based only on its
1605                  * groups.  The chord is to extend outwards just enough to
1606                  * contain every group.
1607                  */
1608                 for (ch_p = mainll_p->u.chhead_p->ch_p; ch_p != 0;
1609                                         ch_p = ch_p->ch_p) {
1610
1611                         /* start chord as if 0 width */
1612                         ch_p->c[RX] = 0;
1613                         ch_p->c[RE] = 0;
1614                         ch_p->c[RW] = 0;
1615
1616                         /* loop through groups, expanding chord when necessary*/
1617                         for (gs_p = ch_p->gs_p; gs_p != 0; gs_p = gs_p->gs_p) {
1618                                 if (gs_p->grpsyl == GS_GROUP) {
1619                                         /*
1620                                          * If last chord in measure, add pad
1621                                          * parameter on right side of groups;
1622                                          * but not for collapseable spaces (s).
1623                                          */
1624                                         if (ch_p->ch_p == 0 &&
1625                                            (gs_p->grpcont != GC_SPACE ||
1626                                            gs_p->uncompressible == YES)) {
1627                                                 gs_p->c[RE] += vvpath(gs_p->
1628                                                 staffno, gs_p->vno, PAD)->pad *
1629                                                 svpath(gs_p->staffno,
1630                                                 STAFFSCALE)->staffscale;
1631                                         }
1632
1633                                         eff = effwest(mainll_p, ch_p, gs_p);
1634                                         if (eff < ch_p->c[RW])
1635                                                 ch_p->c[RW] = eff;
1636                                         eff = effeast(ch_p, gs_p);
1637                                         if (eff > ch_p->c[RE])
1638                                                 ch_p->c[RE] = eff;
1639                                 }
1640                         }
1641
1642                         /* store width; will be updated later to include syls */
1643                         ch_p->width = ch_p->c[RE] - ch_p->c[RW];
1644
1645                         /* set phony absolute coords for effwest() */
1646                         ch_p->c[AX] = ch_p->c[AW] - ch_p->c[RW];
1647                         ch_p->c[AE] = ch_p->c[AX] + ch_p->c[RE];
1648                         if (ch_p->ch_p != 0)
1649                                 ch_p->ch_p->c[AW] = ch_p->c[AE];
1650                 }
1651
1652                 /*
1653                  * Loop again through each chord in this list, this time
1654                  * expanding chords when necessary to include eastward
1655                  * extensions of syllables.  Work right to left, so that when
1656                  * a syllable steals space from the following chord, the
1657                  * following chord has already been widened eastwards, if it
1658                  * needed to be, based on its syllables.
1659                  */
1660                 /* find last chord in the chord LL */
1661                 ch_p = mainll_p->u.chhead_p->ch_p;      /* first chord */
1662                 while (ch_p->ch_p != 0)
1663                         ch_p = ch_p->ch_p;
1664
1665                 /* loop backwards through them (too bad there's no back ptr) */
1666                 for ( ; ch_p != 0; ch_p = prevchord(mainll_p, ch_p)) {
1667                         /*
1668                          * Loop through the linked list of GRPSYLs hanging off
1669                          * this chord, altering RE when finding a syl that
1670                          * sticks out farther.  There is one exception to
1671                          * this.  If a syllable extends farther east than any
1672                          * one so far, a test is made so that it can steal
1673                          * space from the following chord if that chord has
1674                          * no syllable there.
1675                          */
1676                         for (gs_p = ch_p->gs_p; gs_p != 0; gs_p = gs_p->gs_p) {
1677
1678                                 /* if not a syl or not sticking out east */
1679                                 if (gs_p->grpsyl != GS_SYLLABLE ||
1680                                                 gs_p->c[RE] <= ch_p->c[RE])
1681                                         continue;
1682
1683                                 /* syl seems to be sticking out east */
1684
1685                                 /*
1686                                  * If this is the last chord in the measure,
1687                                  * the chord boundary must include the syl.
1688                                  */
1689                                 if (ch_p->ch_p == 0) {
1690                                         ch_p->c[RE] = gs_p->c[RE];
1691                                         continue;
1692                                 }
1693
1694                                 /*
1695                                  * The syl is sticking out east of the current
1696                                  * chord boundary, and this is not the last
1697                                  * chord in the measure.  See if the next
1698                                  * chord contains the next syl of this verse.
1699                                  * If not, there's an empty space there, and
1700                                  * we can let the current syl steal space from
1701                                  * the next chord.
1702                                  */
1703                                 nsyl_p = nextchsyl(gs_p, ch_p);
1704                                 if (nsyl_p == 0) {
1705                                         /*
1706                                          * Next chord has no syl here.  We can
1707                                          * steal its space.  If the syl is so
1708                                          * long that even that isn't enough
1709                                          * room, we'll force the current chord
1710                                          * boundary far enough out to contain
1711                                          * the excess.
1712                                          */
1713                                         if (gs_p->c[RE] > ch_p->c[RE] +
1714                                                         ch_p->ch_p->width) {
1715                                                 ch_p->c[RE] = gs_p->c[RE] -
1716                                                         ch_p->ch_p->width;
1717                                         }
1718                                 } else {
1719                                         /*
1720                                          * Next chord has a syl, so we can't
1721                                          * steal its space.  Extend this chord.
1722                                          */
1723                                         ch_p->c[RE] = gs_p->c[RE];
1724                                 }
1725                         }
1726
1727                         /* revise width; will be revised again later */
1728                         ch_p->width = ch_p->c[RE] - ch_p->c[RW];
1729
1730                 } /* end of backwards loop through chords in this measure */
1731
1732                 /*
1733                  * Loop again through each chord in this list, this time
1734                  * expanding chords when necessary to include westward
1735                  * extensions of syllables.  Work left to right, so that when
1736                  * a syllable steals space from the preceding chord, the
1737                  * preceding chord has already been widened westwards, if it
1738                  * needed to be, based on its syllables.
1739                  */
1740                 for (ch_p = mainll_p->u.chhead_p->ch_p; ch_p != 0;
1741                                         ch_p = ch_p->ch_p) {
1742                         /*
1743                          * Loop through the linked list of GRPSYLs hanging off
1744                          * this chord, altering RW when finding a syl that
1745                          * sticks out farther.  There is one exception to
1746                          * this.  If a syllable extends farther west than any
1747                          * one so far, a test is made so that it can steal
1748                          * space from the following chord if that chord has
1749                          * no syllable there.
1750                          */
1751                         for (gs_p = ch_p->gs_p; gs_p != 0; gs_p = gs_p->gs_p) {
1752
1753                                 /* if not a syl or not sticking out west */
1754                                 if (gs_p->grpsyl != GS_SYLLABLE ||
1755                                                 gs_p->c[RW] >= ch_p->c[RW])
1756                                         continue;
1757
1758                                 /* syl seems to be sticking out west */
1759
1760                                 /*
1761                                  * If this is the first chord in the measure,
1762                                  * the chord boundary must include the syl.
1763                                  */
1764                                 if (prevchord(mainll_p, ch_p) == 0) {
1765                                         ch_p->c[RW] = gs_p->c[RW];
1766                                         continue;
1767                                 }
1768
1769                                 /*
1770                                  * The syl is sticking out west of the current
1771                                  * chord boundary, and this is not the first
1772                                  * chord in the measure.  See if the previous
1773                                  * chord contains the previous syl of this
1774                                  * verse, or if the one before that stole
1775                                  * space from it.  If not, there's an empty
1776                                  * space there, and we can let the current syl
1777                                  * steal space from the previous chord.  Even
1778                                  * if the previous chord has no syl but the one
1779                                  * before stole some space from it, we can use
1780                                  * the part of the space it didn't steal.
1781                                  */
1782                                 /* get prev chord, & prev syl in this verse */
1783                                 pch_p = prevchord(mainll_p, ch_p);
1784                                 psyl_p = prevchsyl(gs_p, pch_p);
1785
1786                                 if (psyl_p == 0) {
1787                                         /* first, assume all of the previous */
1788                                         /*  chord's width is available */
1789                                         stealable = pch_p->width;
1790
1791                                         /*
1792                                          * Get the chord before the previous.
1793                                          * If it exists and contains a syl,
1794                                          * syl may already be stealing space
1795                                          * east of it, in which case we can
1796                                          * only steal what's left over.
1797                                          */
1798                                         ppch_p = prevchord(mainll_p, pch_p);
1799                                         if (ppch_p != 0) {
1800                                                 psyl_p = prevchsyl(gs_p,
1801                                                                 ppch_p);
1802
1803                                                 if (psyl_p != 0 && psyl_p->c[RE]
1804                                                 > ppch_p->c[RE]) {
1805                                                         stealable -= (psyl_p->
1806                                                         c[RE] - ppch_p->c[RE]);
1807                                                 }
1808                                         }
1809
1810                                         /*
1811                                          * If our syl needs more space than is
1812                                          * available for stealing, widen our
1813                                          * chord by the necessary amount.
1814                                          */
1815                                         if (gs_p->c[RW] < ch_p->c[RW] -
1816                                                                 stealable)
1817                                                 ch_p->c[RW] = gs_p->c[RW] +
1818                                                                 stealable;
1819                                 } else {
1820                                         /*
1821                                          * Prev chord has a syl, so we can't
1822                                          * steal its space.  Extend this chord.
1823                                          */
1824                                         ch_p->c[RW] = gs_p->c[RW];
1825                                 }
1826                         }
1827
1828                         /* final revision of width */
1829                         ch_p->width = ch_p->c[RE] - ch_p->c[RW];
1830
1831                 } /* end of forwards loop through chords in this measure */
1832
1833         } /* end of loop through each CHHEAD in main linked list */
1834
1835         pedalroom();            /* make room for "Ped." and "*" if need be */
1836
1837         fixspace();             /* set a width for certain space chords */
1838 }
1839 \f
1840 /*
1841  * Name:        effwest()
1842  *
1843  * Abstract:    Find the effective west boundary of a group.
1844  *
1845  * Returns:     the RW to be used for the group
1846  *
1847  * Description: This function returns an "effective" RW for the given group.
1848  *              Sometimes this is just the true RW.  But if the previous chord
1849  *              has no groups on this staff that are in danger of colliding, we
1850  *              pretend it is a smaller number, so that our group can overlap
1851  *              horizonally with previous ones that have no possibly colliding
1852  *              groups.
1853  */
1854
1855 static double
1856 effwest(mainll_p, ch_p, gs_p)
1857
1858 struct MAINLL *mainll_p;        /* point at MLL item for this chord */
1859 struct CHORD *ch_p;             /* point at this chord */
1860 struct GRPSYL *gs_p;            /* point at this group */
1861
1862 {
1863         struct CHORD *pch_p;    /* point at previous chord */
1864         struct CHORD *ech_p;    /* point at earlier chord */
1865         struct GRPSYL *pgs_p;   /* point a group in previous chord */
1866         float small;            /* small number to be used */
1867         int found;              /* found a chord with a group on our staff? */
1868         float ourax;            /* tentative value for our chord's AX */
1869         float temp;             /* temp variable */
1870
1871
1872         pch_p = prevchord(mainll_p, ch_p);      /* find previous chord */
1873
1874         /* if we are the first chord, return our group's true RW */
1875         if (pch_p == 0)
1876                 return (gs_p->c[RW]);
1877
1878         /* set default to -1.5 stepsize */
1879         small = -1.5 * STEPSIZE * svpath(gs_p->staffno, STAFFSCALE)->staffscale;
1880
1881         /* if already closer to 0 than "small", return true RW */
1882         if (gs_p->c[RW] > small)
1883                 return (gs_p->c[RW]);
1884
1885         /*
1886          * Loop through the previous chord's GRPSYLs to see if it has any
1887          * groups on this staff.  If so, return our true RW, if there is a
1888          * danger of collision.  If there isn't a group, or it's far enough
1889          * away vertically that we know we won't collide with it, we will leave
1890          * the loop and later return a phony RW.
1891          */
1892         for (pgs_p = pch_p->gs_p; pgs_p != 0; pgs_p = pgs_p->gs_p) {
1893                 /* skip cases where there can't be any interference */
1894                 if (pgs_p->staffno > gs_p->staffno)
1895                         break;          /* nothing more could be on our staff*/
1896                 if (pgs_p->staffno < gs_p->staffno)
1897                         continue;       /* ignore if wrong staff */
1898                 if (pgs_p->grpsyl == GS_SYLLABLE)
1899                         continue;       /* ignore if not a group */
1900                 if (collision_danger(pgs_p, gs_p) == NO)
1901                         continue;
1902
1903                 /* found a group that might collide, return our true RW */
1904                 return (gs_p->c[RW]);
1905         }
1906
1907         /*
1908          * There is no group on our staff in the preceding chord, or at least
1909          * none that we're in danger of colliding with.  We'd like to
1910          * let our group overlap into that space if necessary.  But there
1911          * might be a group in some earlier chord, and if there are enough dots
1912          * on it, or enough accidentals on our group, they could still
1913          * interfere.  Find the first earlier chord, looking right to left,
1914          * that has a group neighboring our group that might collide.
1915          */
1916         found = NO;
1917         for (ech_p = prevchord(mainll_p, pch_p); ech_p != 0;
1918                                 ech_p = prevchord(mainll_p, ech_p)) {
1919
1920                 for (pgs_p = ech_p->gs_p; pgs_p != 0; pgs_p = pgs_p->gs_p) {
1921
1922                         if (pgs_p->staffno > gs_p->staffno)
1923                                 break;  /* nothing more could be on our staff*/
1924                         if (pgs_p->staffno < gs_p->staffno)
1925                                 continue;       /* ignore if wrong staff */
1926                         if (pgs_p->grpsyl == GS_SYLLABLE)
1927                                 continue;       /* ignore if not a group */
1928                         if (collision_danger(pgs_p, gs_p) == NO)
1929                                 continue;
1930
1931                         /* found a group that might collide */
1932                         found = YES;
1933                         break;
1934                 }
1935                 if (found == YES)
1936                         break;
1937         }
1938
1939         if (ech_p == 0)
1940                 pfatal("no preceding group in effwest()");
1941
1942         /*
1943          * Since there could be multiple voices on this staff, there could be
1944          * multiple groups on this staff in the chord we found.  Loop through
1945          * each of them, keeping track of the max value our chord's AX would
1946          * have to be to keep our group from overlapping that group.
1947          */
1948         ourax = 0.0;
1949         for ( ; pgs_p != 0 && pgs_p->staffno == gs_p->staffno &&
1950                         pgs_p->grpsyl == GS_GROUP; pgs_p = pgs_p->gs_p) {
1951
1952                 /* ignore ones that are vertically out of the way */
1953                 if (collision_danger(pgs_p, gs_p) == NO)
1954                         continue;
1955
1956                 temp = ech_p->c[AX] + pgs_p->c[RE] - gs_p->c[RW];
1957                 if (temp > ourax)
1958                         ourax = temp;
1959         }
1960
1961         /* find what that value for our AX would make our RW be */
1962         temp = ch_p->c[AW] - ourax;
1963
1964         /* return that amount, but not more than "small" */
1965         return (MIN(temp, small));
1966 }
1967 \f
1968 /*
1969  * Name:        effeast()
1970  *
1971  * Abstract:    Find the effective east boundary of a group.
1972  *
1973  * Returns:     the RE to be used for the group
1974  *
1975  * Description: This function returns an "effective" RE for the given group.
1976  *              Sometimes this is just the true RE.  But if the next chord
1977  *              has no groups on this staff that are in danger of colliding, we
1978  *              pretend it is a smaller number, so that our group can overlap
1979  *              horizonally with the next chord.  Don't worry about colliding
1980  *              with a group in a later chord; effwest() will handle that when
1981  *              processing that later group.
1982  */
1983
1984 static double
1985 effeast(ch_p, gs_p)
1986
1987 struct CHORD *ch_p;             /* point at this chord */
1988 struct GRPSYL *gs_p;            /* point at this group */
1989
1990 {
1991         struct CHORD *nch_p;    /* point at next chord */
1992         struct GRPSYL *ngs_p;   /* point a group in next chord */
1993         float small;            /* small number to be used */
1994         float onestep;          /* a stepsize, scaled */
1995
1996
1997         nch_p = ch_p->ch_p;     /* find next chord */
1998
1999         /* if we are the last chord, return our group's true RE */
2000         if (nch_p == 0)
2001                 return (gs_p->c[RE]);
2002
2003         /* set default to 1.5 stepsize */
2004         onestep = STEPSIZE * svpath(gs_p->staffno, STAFFSCALE)->staffscale;
2005         small = 1.5 * onestep;
2006
2007         /* if already closer to 0 than "small", return true RE */
2008         if (gs_p->c[RE] < small)
2009                 return (gs_p->c[RE]);
2010
2011         /*
2012          * Loop through the next chord's GRPSYLs to see if it has any
2013          * groups on this staff.  If so, return our true RE, unless they are
2014          * not in danger of colliding.
2015          */
2016         for (ngs_p = nch_p->gs_p; ngs_p != 0; ngs_p = ngs_p->gs_p) {
2017                 /* skip cases where there can't be any interference */
2018                 if (ngs_p->staffno > gs_p->staffno)
2019                         break;          /* nothing more could be on our staff*/
2020                 if (ngs_p->staffno < gs_p->staffno)
2021                         continue;       /* ignore if wrong staff */
2022                 if (ngs_p->grpsyl == GS_SYLLABLE)
2023                         continue;       /* ignore if not a group */
2024                 if (collision_danger(gs_p, ngs_p) == NO)
2025                         continue;
2026
2027                 /* found a group that might collide, return true RE */
2028                 return (gs_p->c[RE]);
2029         }
2030
2031         return (small);
2032 }
2033 \f
2034 /*
2035  * Name:        collision_danger()
2036  *
2037  * Abstract:    Find whether the given groups are in danger of colliding.
2038  *
2039  * Returns:     YES or NO
2040  *
2041  * Description: This function is given two groups, a left and a right group,
2042  *              that are on the same staff.  If they are in the same voice, it
2043  *              just returns YES (we don't want one note of a voice to go under
2044  *              another in the same voice, and it would rarely work anyhow due
2045  *              to stem directions).  Otherwise it decides whether they are so
2046  *              close vertically that they are in danger of colliding unless
2047  *              kept apart horizontally.
2048  */
2049
2050 static int
2051 collision_danger(g1_p, g2_p)
2052
2053 struct GRPSYL *g1_p;            /* ptr to left group */
2054 struct GRPSYL *g2_p;            /* ptr to right group */
2055
2056 {
2057         float staffscale;
2058         float stepsize;                 /* adjusted by staff scale */
2059         float north[2], south[2];       /* RN and RS of the groups */
2060         float dotoutside;               /* RY just beyond outside edge of dot*/
2061         float ascent, descent;          /* of an accidental */
2062         struct GRPSYL *g_p[2];          /* point at these two groups */
2063         int k, j;                       /* loop variables */
2064         float accedge;                  /* RN or RS of edge of accidental */
2065
2066
2067         /* same voice, always assume collideable */
2068         if (g1_p->vno == g2_p->vno) {
2069                 return (YES);
2070         }
2071
2072         /* a space can't collide with anything */
2073         if (g1_p->grpcont == GC_SPACE || g2_p->grpcont == GC_SPACE) {
2074                 return (NO);
2075         }
2076
2077         /* if measure repeat, there won't be anything else to collide with */
2078         if (is_mrpt(g1_p) || is_mrpt(g2_p)) {
2079                 return (NO);
2080         }
2081
2082         staffscale = svpath(g1_p->staffno, STAFFSCALE)->staffscale;
2083         stepsize = STEPSIZE * staffscale;
2084         g_p[0] = g1_p;
2085         g_p[1] = g2_p;
2086
2087         /* find the RN and RS of the groups */
2088         for (k = 0; k < 2; k++) {
2089                 if (g_p[k]->grpcont == GC_REST) {
2090                         /* for rests, simply use the group boundaries */
2091                         north[k] = g_p[k]->c[RN];
2092                         south[k] = g_p[k]->c[RS];
2093
2094                 /*
2095                  * We can't use the group boundaries for notes.  For one thing,
2096                  * we don't know the stem length yet.  Assume the worst, that
2097                  * they are way long.  It won't usually negatively impact the
2098                  * result, nor will the fact that some notes don't have stems,
2099                  * because most collisions would be on the non-stem side of the
2100                  * groups.  On the non-stem side, we can't use the group
2101                  * boundary because it includes padding which would often make
2102                  * it seem like there'd be a collision, when really there won't
2103                  * be.
2104                  */
2105                 } else if (g_p[k]->stemdir == UP) {
2106
2107                         north[k] = 10000.;      /* way long stem */
2108
2109                         /* one step below lowest note */
2110                         south[k] = (g_p[k]->notelist[g_p[k]->nnotes-1].
2111                                         stepsup - 1) * stepsize;
2112
2113                         /* if dots, and lower than current RS, lower the RS */
2114                         if (k == 0 && g_p[k]->dots > 0) {
2115                                 dotoutside = g_p[k]->notelist[g_p[k]->nnotes-1].
2116                                                 ydotr - 0.6 * stepsize;
2117                                 if (dotoutside < south[k]) {
2118                                         south[k] = dotoutside;
2119                                 }
2120                         }
2121
2122                         /* if any note has acc going below RS, lower the RS */
2123                         if (k == 1) {
2124                                 for (j = 0; j < g_p[k]->nnotes; j++) {
2125                                         if (g_p[k]->notelist[j].accidental !=
2126                                                                 '\0') {
2127                                                 accdimen(&g_p[k]->notelist[j],
2128                                                         (float *)0, &descent,
2129                                                         (float *)0);
2130                                                 descent *= staffscale;
2131
2132                                                 /* bottom edge of acc */
2133                                                 accedge = stepsize *
2134                                                 g_p[k]->notelist[j].stepsup -
2135                                                 descent;
2136
2137                                                 if (accedge < south[k]) {
2138                                                         south[k] = accedge;
2139                                                 }
2140                                         }
2141                                 }
2142                         }
2143
2144                         /* if bottom note has parens, the group boundary shows
2145                          * close to how far down they go; extend to there */
2146                         if (g_p[k]->notelist[g_p[k]->nnotes-1].note_has_paren
2147                                         && g_p[k]->c[RS] < south[k]) {
2148                                 south[k] = g_p[k]->c[RS];
2149                         }
2150
2151                 } else {        /* stemdir == DOWN */
2152
2153                         south[k] = -10000.;     /* way long stem */
2154
2155                         /* one step above highest note */
2156                         north[k] = (g_p[k]->notelist[0].
2157                                         stepsup + 1) * stepsize;
2158
2159                         /* if dots, and higher than current RN, raise the RN */
2160                         if (k == 0 && g_p[k]->dots > 0) {
2161                                 dotoutside = g_p[k]->notelist[0].
2162                                                 ydotr + 0.6 * stepsize;
2163                                 if (dotoutside > north[k]) {
2164                                         north[k] = dotoutside;
2165                                 }
2166                         }
2167
2168                         /* if any note has acc going above RN, raise the RN */
2169                         if (k == 1) {
2170                                 for (j = 0; j < g_p[k]->nnotes; j++) {
2171                                         if (g_p[k]->notelist[j].accidental !=
2172                                                                 '\0') {
2173                                                 accdimen(&g_p[k]->notelist[j],
2174                                                         &ascent, (float *)0,
2175                                                         (float *)0);
2176                                                 ascent *= staffscale;
2177
2178                                                 /* top edge of acc */
2179                                                 accedge = stepsize *
2180                                                 g_p[k]->notelist[j].stepsup +
2181                                                 ascent;
2182
2183                                                 if (accedge > north[k]) {
2184                                                         north[k] = accedge;
2185                                                 }
2186                                         }
2187                                 }
2188                         }
2189
2190                         /* if top note has parens, the group boundary shows
2191                          * close to how far up they go; extend to there */
2192                         if (g_p[k]->notelist[0].note_has_paren
2193                                         && g_p[k]->c[RN] > north[k]) {
2194                                 north[k] = g_p[k]->c[RN];
2195                         }
2196                 }
2197         }
2198
2199         /* if the groups don't overlap vertically, no collision danger */
2200         if (south[0] >= north[1] || north[0] <= south[1]) {
2201                 return (NO);
2202         }
2203
2204         return (YES);           /* collision danger */
2205 }
2206 \f
2207 /*
2208  * Name:        prevchord()
2209  *
2210  * Abstract:    Find chord preceding the given one.
2211  *
2212  * Returns:     pointer to previous chord, or 0 if none
2213  *
2214  * Description: This function is given a pointer to a chord headcell and a
2215  *              chord in that list.  It finds the preceding chord, returning
2216  *              it, or 0 if none.  If chord linked lists were doubly linked,
2217  *              we wouldn't have to go through this aggravation.
2218  */
2219
2220 static struct CHORD *
2221 prevchord(mainll_p, ch_p)
2222
2223 struct MAINLL *mainll_p;        /* ptr to current syllable */
2224 struct CHORD *ch_p;             /* ptr to current chord */
2225
2226 {
2227         register struct CHORD *prevch_p;
2228
2229
2230         prevch_p = mainll_p->u.chhead_p->ch_p;  /* get first chord in list */
2231
2232         /* if current chord is first chord, there is none before it */
2233         if (prevch_p == ch_p)
2234                 return (0);
2235
2236         /* loop until we find it, then return */
2237         while (prevch_p->ch_p != ch_p)
2238                 prevch_p = prevch_p->ch_p;
2239         return (prevch_p);
2240 }
2241 \f
2242 /*
2243  * Name:        nextchsyl()
2244  *
2245  * Abstract:    Find following syllable if it is in the next chord.
2246  *
2247  * Returns:     pointer to next syllable, or 0 if none
2248  *
2249  * Description: This function is given a pointer to a syllable, and the chord
2250  *              it is in.  It looks in the next chord, to see if there is a
2251  *              syllable there that follows this syllable.  If there is, it
2252  *              returns it.  Otherwise it returns 0.
2253  *              Note:  if the next syllable is was given as a space, it counts
2254  *              as if it weren't there at all (return 0).
2255  */
2256
2257 static struct GRPSYL *
2258 nextchsyl(gs_p, ch_p)
2259
2260 struct GRPSYL *gs_p;    /* ptr to current syllable */
2261 struct CHORD *ch_p;     /* ptr to current chord */
2262
2263 {
2264         struct GRPSYL *nextgs_p;        /* point, looking for next syl */
2265
2266
2267         /* if last chord in measure, return no next syllable */
2268         if (ch_p->ch_p == 0)
2269                 return (0);
2270
2271         /*
2272          * Look down next chord until we hit either the end, or the syllable
2273          * that follows the given one.  Return what was found.
2274          */
2275         for (nextgs_p = ch_p->ch_p->gs_p;
2276                         nextgs_p != 0 && nextgs_p != gs_p->next;
2277                         nextgs_p = nextgs_p->gs_p)
2278                 ;
2279
2280         /* if syl doesn't exist or is a space, return 0 */
2281         if (nextgs_p == 0 || nextgs_p->syl == 0)
2282                 return (0);
2283
2284         return (nextgs_p);
2285 }
2286 \f
2287 /*
2288  * Name:        prevchsyl()
2289  *
2290  * Abstract:    Find preceding syllable if it is in the previous chord.
2291  *
2292  * Returns:     pointer to previous syllable, or 0 if none
2293  *
2294  * Description: This function is given a pointer to a syllable, and the chord
2295  *              it is in.  It looks in the previous chord, to see if there is a
2296  *              syllable there that precedes this syllable.  If there is, it
2297  *              returns it.  Otherwise it returns 0.
2298  *
2299  *              Note:  if the prev syllable is given as a space, it counts
2300  *              as if it weren't there at all (return 0).
2301  *
2302  *              Also note:  unlike nextchsyl, this function compares against
2303  *              not only the given GRPSYL, but the also the previous GRPSYL.
2304  *              It has to, because it is sometimes called with the previous
2305  *              chord, and sometimes with the one before that.
2306  */
2307
2308 static struct GRPSYL *
2309 prevchsyl(gs_p, prevch_p)
2310
2311 struct GRPSYL *gs_p;            /* ptr to current syllable */
2312 struct CHORD *prevch_p;         /* ptr to previous chord */
2313
2314 {
2315         struct GRPSYL *prevgs_p;        /* point, looking for next syl */
2316
2317
2318         /* if first chord in measure, return no previous syllable */
2319         if (prevch_p == 0)
2320                 return (0);
2321
2322         /*
2323          * Look down previous chord until we hit either the end, or the syllable
2324          * that precedes the given one.  Return what was found.
2325          * "Precede" here means either directly precedes, or precedes in two
2326          * steps.
2327          */
2328         for (prevgs_p = prevch_p->gs_p;
2329                         prevgs_p != 0 && ! (prevgs_p == gs_p->prev ||
2330                         (gs_p->prev != 0 && prevgs_p == gs_p->prev->prev));
2331                         prevgs_p = prevgs_p->gs_p)
2332                 ;
2333
2334         /* if syl doesn't exist or is a space, return 0 */
2335         if (prevgs_p == 0 || prevgs_p->syl == 0)
2336                 return (0);
2337
2338         return (prevgs_p);
2339 }
2340 \f
2341 /*
2342  * Name:        pedalroom()
2343  *
2344  * Abstract:    Increase some chords' width to make room for pedal characters.
2345  *
2346  * Returns:     void
2347  *
2348  * Description: This function tries to make room for "Ped." and "*", so that
2349  *              they don't overwrite each other.  For each "pedstar" style
2350  *              pedal mark, it finds the chord it's closest to.  If two of them
2351  *              are on neighboring chords, it may widen the left chord to
2352  *              provide enough room.  The problem is, the best it can do is
2353  *              assume that the pedal marks are exactly aligned with their
2354  *              closest chords.  It doesn't do anything about marks that are
2355  *              not on neighboring chords, since that would be quite a bit
2356  *              more work and would rarely be necessary.  Worst of all, if two
2357  *              marks' closest chords are the same chord, nothing can be done.
2358  */
2359
2360 static void
2361 pedalroom()
2362
2363 {
2364         struct MAINLL *mainll_p;        /* point at items in main linked list*/
2365         struct CHHEAD *chhead_p;        /* point at a chord head cell */
2366         struct STAFF *staff_p;          /* point at a staff */
2367         struct STUFF *stuff_p;          /* point at a stuff */
2368         struct CHORD *pedch_p;          /* point at a chord near a pedal mark*/
2369         struct CHORD *opedch_p;         /* point at prev chord near pedal */
2370         int pedstyle;                   /* P_* */
2371         int pedchar, opedchar;          /* current and previous pedal char */
2372         int font, size;                 /* of a pedal char */
2373         char *string;                   /* for pedal char */
2374         float needed;                   /* amount of room needed */
2375
2376
2377         debug(16, "pedalroom");
2378         initstructs();
2379
2380         chhead_p = 0;           /* prevent useless 'used before set' warning */
2381
2382         /*
2383          * Loop down the main linked list looking for each chord list headcell.
2384          */
2385         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
2386
2387                 switch (mainll_p->str) {
2388                 case S_SSV:
2389                         /* need to keep pedstyle and timeden up to date */
2390                         asgnssv(mainll_p->u.ssv_p);
2391                         continue;       /* go to next MLL structure */
2392
2393                 case S_CHHEAD:
2394                         /* remember this measure's chord list */
2395                         chhead_p = mainll_p->u.chhead_p;
2396                         continue;       /* go to next MLL structure */
2397
2398                 case S_STAFF:
2399                         pedstyle = svpath(mainll_p->u.staff_p->staffno,
2400                                         PEDSTYLE)->pedstyle;
2401                         if (pedstyle != P_LINE) {
2402                                 staff_p = mainll_p->u.staff_p;
2403                                 break;          /* break out and handle this */
2404                         }
2405
2406                         continue;       /* not pedstar, ignore this staff */
2407
2408                 default:
2409                         continue;       /* skip everything else */
2410                 }
2411
2412                 /*
2413                  * At this point we are at a staff that has a pedstyle that
2414                  * uses "Ped." and "*".  Loop down the stuff list, looking for
2415                  * pedal marks.
2416                  */
2417                 opedch_p = 0;           /* no pedal mark yet in measure */
2418                 opedchar = '\0';/* prevent useless 'used before set' warning */
2419                 for (stuff_p = staff_p->stuff_p; stuff_p != 0;
2420                                         stuff_p = stuff_p->next) {
2421                         /*
2422                          * If it is not a pedal stuff, or it has no character,
2423                          * like a continuation from the previous score, skip.
2424                          */
2425                         if (stuff_p->stuff_type != ST_PEDAL ||
2426                             stuff_p->string == 0)
2427                                 continue;
2428                         /*
2429                          * Find the chord that is closest to this pedal mark,
2430                          * and which character this pedal mark is.
2431                          * But following the usual policy of applying "steps"
2432                          * offsets only after everything else is done, we
2433                          * ignore start.steps and use only start.count.
2434                          */
2435                         pedch_p = closestchord(stuff_p->start.count,
2436                                         chhead_p->ch_p);
2437                         font = stuff_p->string[0];
2438                         size = stuff_p->string[1];
2439                         string = stuff_p->string + 2;
2440                         pedchar = next_str_char(&string, &font, &size) & 0xff;
2441
2442                         /* if first pedal mark in measure, nothing more to do*/
2443                         if (opedch_p == 0) {
2444                                 /* remember as previous chord with pedal */
2445                                 opedch_p = pedch_p;
2446                                 opedchar = pedchar;
2447                                 continue;
2448                         }
2449
2450                         /*
2451                          * If this pedal mark and the previous one are by
2452                          * neighboring chords, assume these marks are exactly
2453                          * aligned with their chords.  Make sure the east half
2454                          * of the previous chord plus the west half of this
2455                          * chord is enough room for them.  If it isn't, enlarge
2456                          * the east half of the previous chord.  (Note: RW is
2457                          * negative, so it must be negated.)
2458                          */
2459                         if (pedch_p == opedch_p->ch_p) {
2460                                 needed = rightped(pedstyle, opedchar) +
2461                                          leftped(pedstyle, pedchar);
2462                                 if (stuff_p->all == YES) {
2463                                         needed *= Score.staffscale;
2464                                 } else {
2465                                         needed *= svpath(staff_p->staffno,
2466                                                 STAFFSCALE)->staffscale;
2467                                 }
2468                                 if (opedch_p->c[RE] - pedch_p->c[RW] < needed){
2469                                         opedch_p->c[RE] = needed +
2470                                                         pedch_p->c[RW];
2471                                         opedch_p->width = opedch_p->c[RE] -
2472                                                         opedch_p->c[RW];
2473                                 }
2474                         }
2475
2476                         /* remember previous chord with pedal, and its char */
2477                         opedch_p = pedch_p;
2478                         opedchar = pedchar;
2479                 }
2480         }
2481 }
2482 \f
2483 /*
2484  * Name:        closestchord()
2485  *
2486  * Abstract:    Find closest chord to given time value.
2487  *
2488  * Returns:     pointer to the closest chord
2489  *
2490  * Description: This function finds the CHORD in the given linked list that is
2491  *              closest, timewise, to the given count number.
2492  */
2493
2494 static struct CHORD *
2495 closestchord(count, firstch_p)
2496
2497 double count;                   /* which count of the measure */
2498 struct CHORD *firstch_p;        /* first CHORD in this measure */
2499
2500 {
2501         RATIONAL reqtime;       /* time requested */
2502         struct CHORD *ch_p;     /* point along chord list */
2503         struct CHORD *och_p;    /* (old) point along chord list */
2504
2505
2506         /* if at or before the first count, it's closest to first group */
2507         if (count <= 1)
2508                 return (firstch_p);
2509
2510         /* get requested time to nearest tiny part of a count, in lowest terms*/
2511         reqtime.n = 4 * MAXBASICTIME * (count - 1) + 0.5;
2512         reqtime.d = 4 * MAXBASICTIME * Score.timeden;
2513         rred(&reqtime);
2514
2515         /*
2516          * Loop through the chord list.  As soon as a chord starts at or after
2517          * the requested time value, check whether the requested time is closer
2518          * to the new chord's time, or the previous chord's.  Return the
2519          * closest one.
2520          */
2521         for (och_p = firstch_p, ch_p = och_p->ch_p; ch_p != 0;
2522                                 och_p = ch_p, ch_p = ch_p->ch_p) {
2523                 if (GE(ch_p->starttime, reqtime)) {
2524                         if (GT( rsub(reqtime, och_p->starttime),
2525                                         rsub(ch_p->starttime, reqtime) ))
2526                                 return (ch_p);
2527                         else
2528                                 return (och_p);
2529                 }
2530         }
2531
2532         /* requested time is after last chord; return last chord */
2533         return (och_p);
2534 }
2535 \f
2536 /*
2537  * Name:        rightped()
2538  *
2539  * Abstract:    Find the size of the right side of a pedstar pedal char.
2540  *
2541  * Returns:     the size
2542  *
2543  * Description: This function finds the size of the part of the given pedal
2544  *              character (pedstar style) that is to the right of where it
2545  *              should be centered.
2546  */
2547
2548 static double
2549 rightped(pedstyle, pedchar)
2550
2551 int pedstyle;                   /* pedstar or alt pedstar */
2552 int pedchar;                    /* the given char */
2553
2554 {
2555         switch (pedchar) {
2556         case C_BEGPED:
2557                 return (strwidth(Ped_start) / 2.0);
2558         case C_PEDAL:
2559                 if (pedstyle == P_PEDSTAR)
2560                         return (strwidth(Ped_start) - ped_offset());
2561                 else /* P_ALTPEDSTAR */
2562                         return (strwidth(Ped_start) / 2.0);
2563         case C_ENDPED:
2564                 return (strwidth(Ped_stop) / 2.0);
2565         default:
2566                 pfatal("bad pedal character passed to rightped()");
2567         }
2568         return (0);     /* to keep lint happy */
2569 }
2570 \f
2571 /*
2572  * Name:        leftped()
2573  *
2574  * Abstract:    Find the size of the left side of a pedstar pedal char.
2575  *
2576  * Returns:     the size
2577  *
2578  * Description: This function finds the size of the part of the given pedal
2579  *              character (pedstar style) that is to the left of where it
2580  *              should be centered.
2581  */
2582
2583 static double
2584 leftped(pedstyle, pedchar)
2585
2586 int pedstyle;                   /* pedstar or alt pedstar */
2587 int pedchar;                    /* the given char */
2588
2589 {
2590         switch (pedchar) {
2591         case C_BEGPED:
2592                 return (strwidth(Ped_start) / 2.0);
2593         case C_PEDAL:
2594                 if (pedstyle == P_PEDSTAR)
2595                         return (strwidth(Ped_stop) + ped_offset());
2596                 else /* P_ALTPEDSTAR */
2597                         return (strwidth(Ped_start) / 2.0);
2598         case C_ENDPED:
2599                 return (strwidth(Ped_stop) / 2.0);
2600         default:
2601                 pfatal("bad pedal character passed to leftped()");
2602         }
2603         return (0);     /* to keep lint happy */
2604 }
2605 \f
2606 /*
2607  * Name:        fixspace()
2608  *
2609  * Abstract:    Reset width, if need be, for chords of all spaces.
2610  *
2611  * Returns:     void
2612  *
2613  * Description: This function loops through chord lists, looking for each chord
2614  *              that is all spaces (as shown by the fact that its width is 0).
2615  *              If any voice has a nonspace during the time value of this
2616  *              chord, we reset its width to a very small positive number, to
2617  *              prevent abshorz from treating it like it "deserves" no width
2618  *              (rather than what its duration would imply).
2619  */
2620
2621 static void
2622 fixspace()
2623
2624 {
2625         struct CHORD *ch_p;             /* point at a chord */
2626         struct MAINLL *mainll_p;        /* point at items in main linked list*/
2627         struct MAINLL *m2_p;            /* another pointer down the MLL */
2628         int crunch;                     /* should chord be crunched to 0 width*/
2629         int v;                          /* voice number, 0 or 1 */
2630
2631
2632         debug(16, "fixspace");
2633         /*
2634          * Loop down the main linked list looking for each chord list headcell.
2635          */
2636         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
2637
2638                 if (mainll_p->str != S_CHHEAD)
2639                         continue;       /* skip everything but chord HC */
2640
2641                 /*
2642                  * Loop through the chord list, looking for all-space chords.
2643                  * Skip the first one in the list; we always want that one to
2644                  * be crunched to zero width, since there's nothing earlier
2645                  * that could extend into it.
2646                  */
2647                 for (ch_p = mainll_p->u.chhead_p->ch_p->ch_p; ch_p != 0;
2648                                         ch_p = ch_p->ch_p) {
2649
2650                         if (ch_p->width != 0)
2651                                 continue;       /* skip nonspace chord */
2652
2653                         crunch = YES;           /* init to crunch */
2654
2655                         /* loop through every staff and every voice in meas */
2656                         for (m2_p = mainll_p->next; m2_p->str == S_STAFF;
2657                                         m2_p = m2_p->next) {
2658
2659                                 for (v = 0; v < MAXVOICES && m2_p->u.staff_p->
2660                                                         groups_p[v] != 0; v++) {
2661
2662                                         /* if voice has nonspace, don't crunch*/
2663                                         if ( ! hasspace(m2_p->u.staff_p->
2664                                         groups_p[v], ch_p->starttime,
2665                                         radd(ch_p->starttime, ch_p->duration))){
2666                                                 crunch = NO;
2667                                                 break;
2668                                         }
2669                                 }
2670
2671                                 if (crunch == NO)
2672                                         break;
2673                         }
2674
2675                         /* if should not crunch, set nonzero width to stop it */
2676                         if (crunch == NO)
2677                                 ch_p->width = 0.001;
2678
2679                 } /* for every chord in this measure */
2680
2681         } /* looping through MLL, dealing with chord headcells */
2682 }