chiark / gitweb /
Import upstream version 5.3.
[mup] / mup / mup / trnspose.c
1 /* Copyright (c) 1995, 1997, 1998, 1999, 2000, 2002, 2004, 2005 by Arkkra Enterprises */
2 /* All rights reserved */
3 /*
4  * Name:        trnspose.c
5  *
6  * Description: This file contains functions for transposing to different keys.
7  */
8
9 #include "defines.h"
10 #include "structs.h"
11 #include "globals.h"
12
13 #define BAD     (99)            /* a bad interval */
14
15 /*
16  * For each possible transposition, this table shows the change in the number
17  * of sharps in whatever key we are in.  Invalid intervals are marked as BAD.
18  */
19 static short Delshtab[5][8] = {
20        /*       1       2       3       4       5       6       7 */
21
22       { 0,      -7,     -12,    -10,    -8,     -6,     -11,    -9  },  /* d */
23       { 0,      BAD,    -5,     -3,     BAD,    BAD,    -4,     -2  },  /* m */
24       { 0,      0,      BAD,    BAD,    -1,     1,      BAD,    BAD },  /* P */
25       { 0,      BAD,    2,      4,      BAD,    BAD,    3,      5   },  /* M */
26       { 0,      7,      9,      11,     6,      8,      10,     12  },  /* A */
27 };
28
29 /* index this by an interval type to get a string naming it */
30 static char *Inttab[] =
31                 { "diminished", "minor", "perfect", "major", "augmented" };
32
33 /*
34  * The following hold the transposition information for the score and all the
35  * staffs.  After every bar line it is updated if the transposition changed.
36  * The score's info is stored in inttype[0], intnum[0], and octint[0].
37  */
38 static int inttype[MAXSTAFFS+1];        /* interval type of simple interval */
39 static int intnum[MAXSTAFFS+1];         /* simple interval (>0, octs removed)*/
40 static int octint[MAXSTAFFS+1];         /* number of octaves in interval */
41
42
43 static void transnote P((struct GRPSYL *g_p, struct NOTE *n_p, int inttype,
44                 int intnum, int octint));
45 static void translurto P((struct GRPSYL *g_p, struct NOTE *n_p, int tnum,
46                 int toct));
47 static void simptrans P((int origtype, int orignum, int *inttype_p,
48                 int *intnum_p, int *octint_p));
49 static void fixslurto P((int s, struct MAINLL *mainll_p, int nintnum,
50                 int noctint));
51 \f
52 /*
53  * Name:        transgroups()
54  *
55  * Abstract:    Transpose all GRPSYLs by the requested intervals.
56  *
57  * Returns:     void
58  *
59  * Description: This function loops through the main linked list, applying
60  *              SSVs to keep the transpositions of the score and each staff
61  *              up to date.  Whenever it hits a STAFF, it loops through all
62  *              the GRPSYLs in the linked list(s) for the voice(s), changing
63  *              all the affected information.  It also loops through all the
64  *              chords, transposing them.
65  */
66
67 void
68 transgroups()
69
70 {
71         struct MAINLL *mainll_p;        /* point along main LL */
72         struct GRPSYL *g_p;             /* point along LL of groups */
73         struct STUFF *stuff_p;          /* point at stuff, looking for chords*/
74         int tinttype, tintnum;          /* current total transposition */
75         int ninttype, nintnum, noctint; /* new transposition in standard form*/
76         int v;                          /* voice number */
77         int s;                          /* staff number */
78         int n;                          /* loop variable */
79         int gotssv;                     /* seen an SSV since the last STAFF? */
80         int rtran;                      /* rest "transposition" */
81
82
83         debug(16, "transgroups");
84         initstructs();                  /* clean out old SSV info */
85
86         /*
87          * Loop through the rest of the main linked list, applying SSVs to keep
88          * the tranposition info up to date, and processing linked lists of
89          * groups and STUFF.
90          */
91         gotssv = YES;   /* force init of arrays at start even if no SSVs */
92         for (mainll_p = Mainllhc_p; mainll_p != 0; mainll_p = mainll_p->next) {
93
94                 switch (mainll_p->str) {
95                 case S_SSV:
96                         asgnssv(mainll_p->u.ssv_p);
97                         gotssv = YES;
98                         break;
99
100                 case S_STAFF:
101                         if (gotssv == YES) {
102                                 /*
103                                  * This is the first staff encountered after
104                                  * hitting SSV(s).  If the transposition has
105                                  * changed on any staff, update any slurto
106                                  * lists in the previous measure that go across
107                                  * this bar line, and reset the transposition
108                                  * tables in preparation to processing this
109                                  * staff and the rest of the staffs in this
110                                  * measure.
111                                  */
112                                 for (s = 1; s <= Score.staffs; s++) {
113                                         /*
114                                          * Convert this staff's new transpostion
115                                          * to standard form, storing it in
116                                          * local variables.
117                                          */
118                                         totaltrans(s, &tinttype, &tintnum);
119                                         simptrans(tinttype, tintnum,
120                                              &ninttype, &nintnum, &noctint);
121
122                                         /*
123                                          * If num or oct changed since last
124                                          * measure, we have to fix up slurto
125                                          * lists.  Interval type is irrelevant.
126                                          */
127                                         if (nintnum != intnum[s] ||
128                                             noctint != octint[s])
129                                                 fixslurto(s, mainll_p,
130                                                         nintnum, noctint);
131
132                                         /* store whether changed or not */
133                                         inttype[s] = ninttype;
134                                         intnum[s] = nintnum;
135                                         octint[s] = noctint;
136                                 }
137
138                                 /* do the score; no slurtos to worry about */
139                                 totaltrans(0, &tinttype, &tintnum);
140                                 simptrans(tinttype, tintnum,
141                                         &inttype[0], &intnum[0], &octint[0]);
142
143                                 gotssv = NO;
144                         }
145
146                         /* the staff we're supposed to work on */
147                         s = mainll_p->u.staff_p->staffno;
148
149                         /* loop through stuff list, transposing chords */
150                         for (stuff_p = mainll_p->u.staff_p->stuff_p;
151                                         stuff_p != 0; stuff_p = stuff_p->next) {
152                                 if (stuff_p->string != 0 &&
153                                                 stuff_p->modifier == TM_CHORD)
154                                         stuff_p->string = tranchstr(stuff_p->
155                                                 string, stuff_p->all ? 0 : s);
156                         }
157
158                         /* never transpose tablature staff */
159                         if (is_tab_staff(s))
160                                 continue;
161
162                         /* don't transpose notes if a normal clef is not to */
163                         /*  be printed */
164                         if (svpath(s, STAFFLINES)->printclef != SS_NORMAL)
165                                 continue;
166
167                         /* loop through all voices that can exist */
168                         for (v = 0; v < MAXVOICES; v++) {
169                                 /*
170                                  * Loop through the voice's list of GRPSYLs.
171                                  * If the voice doesn't exist, the loop will
172                                  * execute 0 times.
173                                  */
174                                 for (g_p = mainll_p->u.staff_p->groups_p[v];
175                                                 g_p != 0; g_p = g_p->next) {
176
177                                         if (g_p->grpcont == GC_NOTES) {
178                                                 for (n = 0; n < g_p->nnotes;
179                                                                         n++) {
180                                                         transnote(g_p, &g_p->
181                                                                 notelist[n],
182                                                                 inttype[s],
183                                                                 intnum[s],
184                                                                 octint[s]);
185                                                 }
186                                         } else if (g_p->grpcont == GC_REST &&
187                                           g_p->restdist != NORESTDIST) {
188                                                 /*
189                                                  * The user hardcoded a rest's
190                                                  * position, so "transpose" it.
191                                                  * This is complicated by the
192                                                  * fact that we normally want
193                                                  * to force an even result so
194                                                  * that it will look good.
195                                                  */
196                                                 /* vertical stepsize shift */
197                                                 rtran = 7 * octint[s] +
198                                                                 intnum[s] - 1;
199
200                                                 if (EVEN(g_p->restdist)) {
201                                                         g_p->restdist += rtran;
202                                                         /*
203                                                          * Force even result,
204                                                          * rounded away from
205                                                          * center line.
206                                                          */
207                                                         if (ODD(g_p->restdist)){
208                                                                 g_p->restdist =
209                                                                 g_p->restdist > 0 ?
210                                                                 g_p->restdist + 1 :
211                                                                 g_p->restdist - 1;
212                                                         }
213                                                 } else {
214                                                         /* no rounding */
215                                                         g_p->restdist += rtran;
216                                                         
217                                                         /* warn if odd result*/
218                                                         if (ODD(g_p->restdist)){
219                                                                 l_warning(
220                                                                 g_p->inputfile,
221                                                                 g_p->inputlineno,
222                                                                 "'dist' on rest is an odd number, which may look bad");
223                                                         }
224                                                 }
225                                         }
226                                 }
227                         }
228                         break;
229                 }
230         }
231 }
232 \f
233 /*
234  * Name:        transnote()
235  *
236  * Abstract:    transpose a note
237  *
238  * Returns:     void
239  *
240  * Description: This function alters a NOTE structure according to the given
241  *              transposition.  This involves changing the note itself (letter,
242  *              accidental, and octave) and any notes in its slurred-to list
243  *              (letter and octave).
244  */
245
246 static void
247 transnote(g_p, n_p, ttype, tnum, toct)
248
249 struct GRPSYL *g_p;     /* ptr to note's group, used only in error messages */
250 register struct NOTE *n_p; /* pointer to the note structure */
251 int ttype;              /* interval type (DIMINISHED, MINOR, . . .) */
252 int tnum;               /* simple interval (positive, with octaves removed) */
253 int toct;               /* number of octaves in interval */
254
255 {
256         int oldaccnum;          /* old accidental number (&&=0, &=1, ...) */
257         int newaccnum;          /* new accidental number (&&=0, &=1, ...) */
258         int oldcircnum;         /* position of old note in circle of 5ths */
259         int newcircnum;         /* position of new note in circle of 5ths */
260         char newlet;            /* new note letter */
261         char newacc;            /* new accidental letter */
262         int newoct;             /* new octave number */
263
264
265         /*
266          * First do the note itself:  letter, accidental, octave.
267          */
268         /* calculate new note letter from old */
269         newlet = (n_p->letter - 'a' + tnum - 1) % 7 + 'a';
270
271         if (n_p->accidental == '\0') {
272                 newacc = '\0';  /* no acc before, so no acc now */
273                 /* set as if natural, for benefit of error messages later */
274                 oldaccnum = strchr(Acclets, 'n') - Acclets;
275         } else {
276                 /*
277                  * There was an accidental, so we need to get the proper
278                  * transposition of it.  Get position of the old note letter
279                  * in the circle of 5ths, and the old accidental index.
280                  * The index to the new note letter is shifted by delsh.
281                  * If this falls outside the circle string, change the index
282                  * and accidental until it lies within the string.
283                  */
284                 oldcircnum = strchr(Circle, n_p->letter) - Circle;
285                 oldaccnum = strchr(Acclets, n_p->accidental) - Acclets;
286                 newaccnum = oldaccnum;
287                 newcircnum = oldcircnum + Delshtab [ ttype ] [ tnum ];
288                 while (newcircnum < 0) {
289                         newaccnum--;            /* one more flat */
290                         newcircnum += 7;        /* 7 letters "sharper" */
291                 }
292                 while (newcircnum >= 7) {
293                         newaccnum++;            /* one more sharp */
294                         newcircnum -= 7;        /* 7 letters "flatter" */
295                 }
296
297                 /* test for accidental overflow */
298                 if (newaccnum < 0 || newaccnum > 4) {
299                         l_ufatal(g_p->inputfile, g_p->inputlineno,
300                                 "note %c%s%d is transposed to have triple sharp or flat",
301                                 n_p->letter, Acctostr[oldaccnum], n_p->octave);
302                 }
303
304                 newacc = Acclets[newaccnum];
305         }
306
307         /*
308          * Calculate the new octave.  Add toct (number of octaves to
309          * transpose) to the old octave.  Then, add tnum to the old note
310          * number.  If it exceeds a 7th, wrap into the next octave.
311          */
312         newoct = n_p->octave + toct;
313         if (Letshift[n_p->letter - 'a'] + tnum - 1 >= 7)
314                 newoct++;
315
316         /* check for octave overflow, and exit if so */
317         if (newoct < MINOCTAVE || newoct > MAXOCTAVE) {
318                 l_ufatal(g_p->inputfile, g_p->inputlineno,
319                                 "note %c%s%d octave is transposed out of range",
320                                 n_p->letter, Acctostr[oldaccnum], n_p->octave);
321         }
322
323         /* store away the new values */
324         n_p->letter = newlet;
325         n_p->accidental = newacc;
326         n_p->octave = (short)newoct;
327
328
329         /*
330          * Now do any notes in the slurred-to list, notes this note is slurred
331          * to:  letter, octave.  (There is never an accidental here.)
332          */
333         translurto(g_p, n_p, tnum, toct);
334 }
335 \f
336 /*
337  * Name:        translurto()
338  *
339  * Abstract:    transpose a note's slurred-to list
340  *
341  * Returns:     void
342  *
343  * Description: This function is given a pointer to a note and a transposition.
344  *              It transposes the note's slurto list.  Notice that the "type"
345  *              of transposition interval is not needed, since these lists
346  *              never contain accidentals.
347  */
348
349 static void
350 translurto(g_p, n_p, tnum, toct)
351
352 struct GRPSYL *g_p;     /* note's group, used only in error messages */
353 struct NOTE *n_p;       /* note whose slurto list is to be transposed */
354 int tnum;               /* transposition interval number */
355 int toct;               /* transposition interval octave */
356
357 {
358         int s;                  /* index into slurto list */
359         char newlet;            /* new note letter */
360         int newoct;             /* new octave number */
361
362
363         /* loop through each note (if any) in the slurred-to list */
364         for (s = 0; s < n_p->nslurto; s++) {
365
366                 /* if this is a slur to or from nowhere, don't change it */
367                 if (IS_NOWHERE(n_p->slurtolist[s].octave))
368                         continue;
369
370                 /* calculate new note letter from old */
371                 newlet = (n_p->slurtolist[s].letter - 'a' + tnum - 1) % 7 + 'a';
372
373                 newoct = n_p->slurtolist[s].octave + toct;
374                 if (Letshift[n_p->slurtolist[s].letter - 'a'] + tnum - 1 >= 7)
375                         newoct++;
376
377                 /* check for octave overflow, and exit if so */
378                 if (newoct < MINOCTAVE || newoct > MAXOCTAVE) {
379                         l_ufatal(g_p->inputfile, g_p->inputlineno,
380                                         "note in slurred-to list transposed to out of range octave (%c%d)",
381                                         newlet, newoct);
382                 }
383
384                 /* store away the new values */
385                 n_p->slurtolist[s].letter = newlet;
386                 n_p->slurtolist[s].octave = (short)newoct;
387         }
388 }
389 \f
390 /*
391  * Name:        tranchnote()
392  *
393  * Abstract:    transpose a note name that's inside a chord symbol
394  *
395  * Returns:     void
396  *
397  * Description: This function is given a letter and accidental that occur
398  *              inside a chord symbol.  It could be the main chord name itself,
399  *              or the name of a note, like the E in "C/E" or "DaddE".  It
400  *              returns a pointer to a static area containing the transposed
401  *              string.
402  */
403
404 char *
405 tranchnote(letter, acc, s)
406
407 int letter;             /* A to G */
408 int acc;                /* one of:  'x', '#', '\0', '&', 'B' */
409 int s;                  /* staff number, needed to get tranposition interval */
410                         /*  0 means the score as a whole ("all") */
411
412 {
413         static char circle[] = "FCGDAEB";       /* circle of 5ths */
414         static char newchord[3];        /* put transposed result here */
415
416         int oldaccnum;          /* old accidental number (&&=0, &=1, ...) */
417         int newaccnum;          /* new accidental number (&&=0, &=1, ...) */
418         int oldcircnum;         /* position of old note in circle of 5ths */
419         int newcircnum;         /* position of new note in circle of 5ths */
420         char newlet;            /* new note letter */
421         char newacc;            /* new accidental letter */
422
423
424         debug(32, "tranchnote letter=%c acc=%c s=%d", letter,
425                         acc==0 ? ' ' : acc, s);
426         /* need to translate naturals so that strchr can use Acclets[] */
427         if (acc == '\0')
428                 acc = 'n';
429
430         /* calculate new note letter from old */
431         newlet = (letter - 'A' + intnum[s] - 1) % 7 + 'A';
432
433         /*
434          * Get the proper transposition of the accidental.  Get position of the
435          * old note letter in the circle of 5ths, and the old accidental index.
436          * The index to the new note letter is shifted by delsh.  If this falls
437          * outside the circle string, change the index and accidental until it
438          * lies within the string.
439          */
440         oldcircnum = strchr(circle, letter) - circle;
441         oldaccnum = strchr(Acclets, acc) - Acclets;
442         newaccnum = oldaccnum;
443         newcircnum = oldcircnum + Delshtab [ inttype[s] ] [ intnum[s] ];
444         while (newcircnum < 0) {
445                 newaccnum--;            /* one more flat */
446                 newcircnum += 7;        /* 7 letters "sharper" */
447         }
448         while (newcircnum >= 7) {
449                 newaccnum++;            /* one more sharp */
450                 newcircnum -= 7;        /* 7 letters "flatter" */
451         }
452
453         /* test for accidental overflow */
454         if (newaccnum < 0 || newaccnum > 4)
455                 ufatal("chord note %c%s is transposed to have triple sharp or flat",
456                         letter, Acctostr[oldaccnum]);
457
458         newacc = Acclets[newaccnum];
459
460         /* store away the new values */
461         newchord[0] = newlet;
462         newchord[1] = (newacc == 'n' ? '\0' : newacc);
463         newchord[2] = '\0';
464
465         return (newchord);
466 }
467 \f
468 /*
469  * Name:        eff_key()
470  *
471  * Abstract:    Return the "effective key" (the key after any transposition).
472  *
473  * Returns:     the number of sharps in the effective key (flats are negative)
474  *
475  * Description: This function, given a staff number, returns the number of
476  *              sharps currently in effect, considering any transpostion that
477  *              may have been requested.  If given 0 for the staff number, it
478  *              does this for the score's key signature.  It assumes the SSVs
479  *              are up to date.
480  */
481
482 int
483 eff_key(staff)
484
485 int staff;                      /* staff number to do it for (0 = score) */
486
487 {
488         int sharps;             /* sharps in old key (flats count negative) */
489         int origtype;           /* original transposition interval type */
490         int orignum;            /* original transposition interval number */
491         int inttype;            /* interval type of simple interval */
492         int intnum;             /* simple interval (positive, octs removed) */
493         int octint;             /* number of octaves in interval */
494         int newsharps;          /* sharps in key after transposition */
495
496
497         /*
498          * If no normal clef is to be printed, always treat it like there is
499          * no key signature.
500          */
501         if (staff == 0) {
502                 if (Score.printclef != SS_NORMAL)
503                         return (0);
504         } else {
505                 if (svpath(staff, STAFFLINES)->printclef != SS_NORMAL)
506                         return (0);
507         }
508
509         /* viewpath to get this staff's current key and transposition */
510         if (staff == 0) {
511                 sharps = Score.sharps;
512         } else {
513                 sharps = svpath(staff, SHARPS)->sharps;
514         }
515         totaltrans(staff, &origtype, &orignum);
516
517         simptrans(origtype, orignum, &inttype, &intnum, &octint);
518
519         /*
520          * Change number of sharps by the appropriate delta.  We assume the
521          * interval isn't BAD, because the parser wouldn't have allowed it.
522          */
523         newsharps = sharps + Delshtab [ inttype ] [ intnum ];
524
525         /* make sure the resulting key is valid */
526         if (newsharps < -7 || newsharps > 7) {
527                 /*
528                  * Normally we take the final "else" here.  But for the "1"
529                  * interval there is an ambiguity.  If transpose + addtranspose
530                  * add up to an aug or dim 1, there are two ways to state the
531                  * result.  (Also for per 1, but in that case, we'd never have
532                  * an invalid key.)  So we state both ways of looking at it.
533                  */
534                 if (orignum == 1  && origtype == AUGMENTED ||
535                     orignum == -1 && origtype == DIMINISHED) {
536                         ufatal("staff %d: key of %d %s transposed up by augmented 1 or down diminished 1 results in %d %s",
537                                 staff,
538                                 abs(sharps),
539                                 (sharps >= 0 ? "sharps" : "flats"),
540                                 abs(newsharps),
541                                 (newsharps >= 0 ? "sharps" : "flats"));
542                 } else if (orignum == -1 && origtype == AUGMENTED ||
543                            orignum == 1  && origtype == DIMINISHED) {
544                         ufatal("staff %d: key of %d %s transposed down by augmented 1 or up diminished 1 results in %d %s",
545                                 staff,
546                                 abs(sharps),
547                                 (sharps >= 0 ? "sharps" : "flats"),
548                                 abs(newsharps),
549                                 (newsharps >= 0 ? "sharps" : "flats"));
550                 } else {
551                         ufatal("staff %d: key of %d %s transposed %s by %s %d results in %d %s",
552                                 staff,
553                                 abs(sharps),
554                                 (sharps >= 0 ? "sharps" : "flats"),
555                                 (orignum > 0 ? "up" : "down"),
556                                 Inttab[origtype],
557                                 abs(orignum),
558                                 abs(newsharps),
559                                 (newsharps >= 0 ? "sharps" : "flats"));
560                 }
561         }
562         return (newsharps);
563 }
564 \f
565 /*
566  * Name:        simptrans()
567  *
568  * Abstract:    Simplify a transpostion into standard form.
569  *
570  * Returns:     void
571  *
572  * Description: This function, given a transposition, converts it into
573  *              standard form (a "simple" upwards interval and an octave).
574  */
575
576 static void
577 simptrans(origtype, orignum, inttype_p, intnum_p, octint_p)
578
579 int origtype;           /* original transposition interval type */
580 int orignum;            /* original transposition interval number */
581 int *inttype_p;         /* interval type (DIMINISHED, MINOR, . . .) */
582 int *intnum_p;          /* simple interval (positive, with octaves removed) */
583 int *octint_p;          /* number of octaves in interval */
584
585 {
586         int direction;          /* UP or DOWN */
587
588
589         *inttype_p = origtype;
590         *intnum_p = orignum;
591
592         /* set direction; if down, make intnum positive */
593         if (*intnum_p > 0) {
594                 direction = UP;
595         } else {
596                 direction = DOWN;
597                 *intnum_p = -*intnum_p;
598         }
599
600         /* break interval into octaves plus a simple interval */
601         *octint_p = (*intnum_p - 1) / 7;
602         *intnum_p -= 7 * *octint_p;
603
604         /* if downwards, adjust so that *intnum_p is upwards */
605         if (direction == DOWN) {
606                 if (*intnum_p == 1) {
607                         /* for unison, negate octaves and reverse intvl type */
608                         *octint_p = -*octint_p;
609                         *inttype_p = 4 - *inttype_p;
610                 } else {
611                         /* for other intervals, octave becomes one less than */
612                         /* negation, and *intnum_p flips as does its type */
613                         *octint_p = -1 - *octint_p;
614                         *intnum_p = 9 - *intnum_p;
615                         *inttype_p = 4 - *inttype_p;
616                 }
617         }
618 }
619 \f
620 /*
621  * Name:        fixslurto()
622  *
623  * Abstract:    Fix transposition of notes in a slurred-to list.
624  *
625  * Returns:     void
626  *
627  * Description: Notes in a slurred-to list are initially transposed the same as
628  *              the regular notes in that measure.  But if they occur in a
629  *              group immediately before a bar line where the transposition
630  *              changes, they should have been transposed according to the new
631  *              transposition.  This function is called when entering the new
632  *              measure.  It searches back and finds any such slurred-to lists
633  *              in the previous measure and fixes their transposition.
634  */
635
636 static void
637 fixslurto(s, mainll_p, nintnum, noctint)
638
639 int s;                          /* staff number */
640 struct MAINLL *mainll_p;        /* initially points at current staff */
641 int nintnum;                    /* interval number of new transposition */
642 int noctint;                    /* octaves in new transposition */
643
644 {
645         struct GRPSYL *g_p;     /* point to a group */
646         int deltanum, deltaoct; /* change in transposition */
647         int v;                  /* voice number */
648         int n;                  /* loop index */
649
650
651         /* search back to the last staff of the preceding measure, if any */
652         for (mainll_p = mainll_p->prev; mainll_p != 0 &&
653                         mainll_p->str != S_STAFF; mainll_p = mainll_p->prev)
654                 ;
655         if (mainll_p == 0)
656                 return; /* no preceding measure; nothing to do */
657
658         /* search back to the matching staff in that measure, if any */
659         while (mainll_p != 0 && mainll_p->str == S_STAFF &&
660                                 mainll_p->u.staff_p->staffno != s)
661                 mainll_p = mainll_p->prev;
662         if (mainll_p == 0 || mainll_p->str != S_STAFF)
663                 return;         /* no matching staff (no. of staffs changed) */
664         /* we found a matching staff in the preceding measure */
665
666         /*
667          * "Subtract" the old transposition from the new one, to find the
668          * "delta" transposition.  This is what we need to apply to the
669          * slurred-to notes to change them from the old to new transposition.
670          */
671         deltanum = nintnum - intnum[s] + 1;
672         deltaoct = noctint - octint[s];
673         if (deltanum < 1) {
674                 deltanum += 7;
675                 deltaoct--;
676         }
677
678         /*
679          * mainll_p now points to the matching staff in the preceding measure.
680          * Loop through all voices that can exist.
681          */
682         for (v = 0; v < MAXVOICES; v++) {
683                 g_p = mainll_p->u.staff_p->groups_p[v];
684                 if (g_p == 0)
685                         continue;
686
687                 /* find the last grpsyl in this voice */
688                 while (g_p->next != 0)
689                         g_p = g_p->next;
690
691                 /* if it doesn't contain notes, there is nothing to do */
692                 if (g_p->grpcont != GC_NOTES)
693                         continue;
694
695                 /* found a group with notes at end of measure; process it */
696                 for (n = 0; n < g_p->nnotes; n++) {
697                         translurto(g_p, &g_p->notelist[n], deltanum, deltaoct);
698                 }
699         }
700 }
701 \f
702 /*
703  * Name:        totaltrans()
704  *
705  * Abstract:    Find the current total transposition of a staff or the score.
706  *
707  * Returns:     void
708  *
709  * Description: This function is given a staff number, or zero for the score.
710  *              It assumes that the SSVs are up to date.  It gets the two
711  *              tranposition parameters, and adds them to get the current
712  *              total transpostion.  If it's invalid, it does a ufatal.
713  */
714
715 void
716 totaltrans(s, type_p, num_p)
717
718 int s;                          /* staff number, or 0 for score */
719 int *type_p;                    /* return type of resulting transposition */
720 int *num_p;                     /* return number of resulting transposition */
721
722 {
723         /*
724          * inths is to be indexed by interval type and number (1 through 7).
725          * It gives the number of half steps in the interval.
726          */
727         static short inths[5][8] = {
728             /*  1       2       3       4       5       6       7 */
729
730            { 0, -1,     0,      2,      4,      6,      7,      9    }, /* d */
731            { 0, BAD,    1,      3,      BAD,    BAD,    8,      10   }, /* m */
732            { 0, 0,      BAD,    BAD,    5,      7,      BAD,    BAD  }, /* P */
733            { 0, BAD,    2,      4,      BAD,    BAD,    9,      11   }, /* M */
734            { 0, 1,      3,      5,      6,      8,      10,     12   }, /* A */
735         };
736
737         struct SSV *ssv_p;      /* point at the SSV hold a transposition */
738         int type[2];            /* interval types (DIMINISHED, MINOR, . . .) */
739         int num[2];             /* interval numbers (down is negative) */
740         int totalhs;            /* total half steps in resulting interval */
741         char place[15];         /* temp storage for error message use */
742         int offset;             /* like interval no. but counting from 0 */
743         int n;                  /* loop variable */
744
745
746         /* get the type and num of each transpostion interval */
747         ssv_p = svpath(s, TRANSPOSITION);
748         type[0] = ssv_p->inttype;
749         num[0] = ssv_p->intnum;
750         ssv_p = svpath(s, ADDTRANSPOSITION);
751         type[1] = ssv_p->addinttype;
752         num[1] = ssv_p->addintnum;
753
754         /*
755          * To get the interval number of the num of the transpostions, we
756          * basically add the two.  But musicians unfortunately start counting
757          * intervals from 1 instead of 0, so we have to play some games.
758          */
759         offset = (num[0] > 0 ? num[0] - 1 : num[0] + 1) + /* add true offsets*/
760                  (num[1] > 0 ? num[1] - 1 : num[1] + 1);
761         if (offset >= 0) {              /* get interval number from offset */
762                 *num_p = offset + 1;
763         } else {
764                 *num_p = offset - 1;
765         }
766
767         /* accumulate total half steps in both transpositions */
768         totalhs = 0;
769         for (n = 0; n < NUMELEM(num); n++) {
770                 if (num[n] > 0) {               /* interval is up */
771                         while (num[n] > 7) {
772                                 num[n] -= 7;    /* subtract an octave */
773                                 totalhs += 12;  /* add 12 half steps */
774                         }
775                         /* account for this simple interval */
776                         totalhs += inths[type[n]][num[n]];
777                 } else {                        /* interval is down */
778                         while (num[n] < -7) {
779                                 num[n] += 7;    /* add an octave */
780                                 totalhs -= 12;  /* subtract 12 half steps */
781                         }
782                         /* account for this simple interval */
783                         totalhs -= inths[type[n]][abs(num[n])];
784                 }
785         }
786
787         /* if interval is down, find the up version of offset and halfsteps */
788         if (offset < 0) {
789                 offset = -offset;
790                 totalhs = -totalhs;
791         }
792         /* bring it into the range of a simple interval */
793         totalhs -= (offset / 7) * 12;
794         offset %= 7;
795
796         /* make sure this simple interval is valid */
797         if (totalhs < inths[DIMINISHED][offset + 1] ||
798             totalhs > inths[AUGMENTED ][offset + 1]) {
799
800                 if (s == 0) {
801                         (void)sprintf(place, "score");
802                 } else {
803                         (void)sprintf(place, "staff %d", s);
804                 }
805                 ufatal("on %s, 'transpose' %s %s %d and 'addtranspose' %s %s %d add up to an invalid interval",
806                 place,
807                 num[0] > 0 ? "up" : "down", Inttab[type[0]], abs(num[0]),
808                 num[1] > 0 ? "up" : "down", Inttab[type[1]], abs(num[1]));
809         }
810
811         /* search table for the type of interval this is; it will be found */
812         for (n = DIMINISHED; n <= AUGMENTED; n++) {
813                 if (totalhs == inths[n][offset + 1]) {
814                         break;
815                 }
816         }
817
818         *type_p = n;
819 }