1 /* Copyright (c) 1995, 1997, 1998, 1999, 2000, 2002, 2004, 2005 by Arkkra Enterprises */
2 /* All rights reserved */
6 * Description: This file contains functions for transposing to different keys.
13 #define BAD (99) /* a bad interval */
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.
19 static short Delshtab[5][8] = {
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 */
29 /* index this by an interval type to get a string naming it */
30 static char *Inttab[] =
31 { "diminished", "minor", "perfect", "major", "augmented" };
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].
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 */
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,
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,
55 * Abstract: Transpose all GRPSYLs by the requested intervals.
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.
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" */
83 debug(16, "transgroups");
84 initstructs(); /* clean out old SSV info */
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
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) {
94 switch (mainll_p->str) {
96 asgnssv(mainll_p->u.ssv_p);
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
112 for (s = 1; s <= Score.staffs; s++) {
114 * Convert this staff's new transpostion
115 * to standard form, storing it in
118 totaltrans(s, &tinttype, &tintnum);
119 simptrans(tinttype, tintnum,
120 &ninttype, &nintnum, &noctint);
123 * If num or oct changed since last
124 * measure, we have to fix up slurto
125 * lists. Interval type is irrelevant.
127 if (nintnum != intnum[s] ||
128 noctint != octint[s])
129 fixslurto(s, mainll_p,
132 /* store whether changed or not */
133 inttype[s] = ninttype;
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]);
146 /* the staff we're supposed to work on */
147 s = mainll_p->u.staff_p->staffno;
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);
158 /* never transpose tablature staff */
162 /* don't transpose notes if a normal clef is not to */
164 if (svpath(s, STAFFLINES)->printclef != SS_NORMAL)
167 /* loop through all voices that can exist */
168 for (v = 0; v < MAXVOICES; v++) {
170 * Loop through the voice's list of GRPSYLs.
171 * If the voice doesn't exist, the loop will
174 for (g_p = mainll_p->u.staff_p->groups_p[v];
175 g_p != 0; g_p = g_p->next) {
177 if (g_p->grpcont == GC_NOTES) {
178 for (n = 0; n < g_p->nnotes;
180 transnote(g_p, &g_p->
186 } else if (g_p->grpcont == GC_REST &&
187 g_p->restdist != NORESTDIST) {
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.
196 /* vertical stepsize shift */
197 rtran = 7 * octint[s] +
200 if (EVEN(g_p->restdist)) {
201 g_p->restdist += rtran;
207 if (ODD(g_p->restdist)){
215 g_p->restdist += rtran;
217 /* warn if odd result*/
218 if (ODD(g_p->restdist)){
222 "'dist' on rest is an odd number, which may look bad");
236 * Abstract: transpose a note
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).
247 transnote(g_p, n_p, ttype, tnum, toct)
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 */
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 */
266 * First do the note itself: letter, accidental, octave.
268 /* calculate new note letter from old */
269 newlet = (n_p->letter - 'a' + tnum - 1) % 7 + 'a';
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;
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.
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" */
292 while (newcircnum >= 7) {
293 newaccnum++; /* one more sharp */
294 newcircnum -= 7; /* 7 letters "flatter" */
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);
304 newacc = Acclets[newaccnum];
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.
312 newoct = n_p->octave + toct;
313 if (Letshift[n_p->letter - 'a'] + tnum - 1 >= 7)
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);
323 /* store away the new values */
324 n_p->letter = newlet;
325 n_p->accidental = newacc;
326 n_p->octave = (short)newoct;
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.)
333 translurto(g_p, n_p, tnum, toct);
339 * Abstract: transpose a note's slurred-to list
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.
350 translurto(g_p, n_p, tnum, toct)
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 */
358 int s; /* index into slurto list */
359 char newlet; /* new note letter */
360 int newoct; /* new octave number */
363 /* loop through each note (if any) in the slurred-to list */
364 for (s = 0; s < n_p->nslurto; s++) {
366 /* if this is a slur to or from nowhere, don't change it */
367 if (IS_NOWHERE(n_p->slurtolist[s].octave))
370 /* calculate new note letter from old */
371 newlet = (n_p->slurtolist[s].letter - 'a' + tnum - 1) % 7 + 'a';
373 newoct = n_p->slurtolist[s].octave + toct;
374 if (Letshift[n_p->slurtolist[s].letter - 'a'] + tnum - 1 >= 7)
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)",
384 /* store away the new values */
385 n_p->slurtolist[s].letter = newlet;
386 n_p->slurtolist[s].octave = (short)newoct;
393 * Abstract: transpose a note name that's inside a chord symbol
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
405 tranchnote(letter, acc, s)
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") */
413 static char circle[] = "FCGDAEB"; /* circle of 5ths */
414 static char newchord[3]; /* put transposed result here */
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 */
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[] */
430 /* calculate new note letter from old */
431 newlet = (letter - 'A' + intnum[s] - 1) % 7 + 'A';
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.
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" */
448 while (newcircnum >= 7) {
449 newaccnum++; /* one more sharp */
450 newcircnum -= 7; /* 7 letters "flatter" */
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]);
458 newacc = Acclets[newaccnum];
460 /* store away the new values */
461 newchord[0] = newlet;
462 newchord[1] = (newacc == 'n' ? '\0' : newacc);
471 * Abstract: Return the "effective key" (the key after any transposition).
473 * Returns: the number of sharps in the effective key (flats are negative)
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
485 int staff; /* staff number to do it for (0 = score) */
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 */
498 * If no normal clef is to be printed, always treat it like there is
502 if (Score.printclef != SS_NORMAL)
505 if (svpath(staff, STAFFLINES)->printclef != SS_NORMAL)
509 /* viewpath to get this staff's current key and transposition */
511 sharps = Score.sharps;
513 sharps = svpath(staff, SHARPS)->sharps;
515 totaltrans(staff, &origtype, &orignum);
517 simptrans(origtype, orignum, &inttype, &intnum, &octint);
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.
523 newsharps = sharps + Delshtab [ inttype ] [ intnum ];
525 /* make sure the resulting key is valid */
526 if (newsharps < -7 || newsharps > 7) {
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.
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",
539 (sharps >= 0 ? "sharps" : "flats"),
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",
547 (sharps >= 0 ? "sharps" : "flats"),
549 (newsharps >= 0 ? "sharps" : "flats"));
551 ufatal("staff %d: key of %d %s transposed %s by %s %d results in %d %s",
554 (sharps >= 0 ? "sharps" : "flats"),
555 (orignum > 0 ? "up" : "down"),
559 (newsharps >= 0 ? "sharps" : "flats"));
568 * Abstract: Simplify a transpostion into standard form.
572 * Description: This function, given a transposition, converts it into
573 * standard form (a "simple" upwards interval and an octave).
577 simptrans(origtype, orignum, inttype_p, intnum_p, octint_p)
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 */
586 int direction; /* UP or DOWN */
589 *inttype_p = origtype;
592 /* set direction; if down, make intnum positive */
597 *intnum_p = -*intnum_p;
600 /* break interval into octaves plus a simple interval */
601 *octint_p = (*intnum_p - 1) / 7;
602 *intnum_p -= 7 * *octint_p;
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;
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;
623 * Abstract: Fix transposition of notes in a slurred-to list.
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.
637 fixslurto(s, mainll_p, nintnum, noctint)
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 */
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 */
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)
656 return; /* no preceding measure; nothing to do */
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 */
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.
671 deltanum = nintnum - intnum[s] + 1;
672 deltaoct = noctint - octint[s];
679 * mainll_p now points to the matching staff in the preceding measure.
680 * Loop through all voices that can exist.
682 for (v = 0; v < MAXVOICES; v++) {
683 g_p = mainll_p->u.staff_p->groups_p[v];
687 /* find the last grpsyl in this voice */
688 while (g_p->next != 0)
691 /* if it doesn't contain notes, there is nothing to do */
692 if (g_p->grpcont != GC_NOTES)
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);
705 * Abstract: Find the current total transposition of a staff or the score.
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.
716 totaltrans(s, type_p, num_p)
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 */
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.
727 static short inths[5][8] = {
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 */
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 */
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;
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.
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 */
767 /* accumulate total half steps in both transpositions */
769 for (n = 0; n < NUMELEM(num); n++) {
770 if (num[n] > 0) { /* interval is up */
772 num[n] -= 7; /* subtract an octave */
773 totalhs += 12; /* add 12 half steps */
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 */
782 /* account for this simple interval */
783 totalhs -= inths[type[n]][abs(num[n])];
787 /* if interval is down, find the up version of offset and halfsteps */
792 /* bring it into the range of a simple interval */
793 totalhs -= (offset / 7) * 12;
796 /* make sure this simple interval is valid */
797 if (totalhs < inths[DIMINISHED][offset + 1] ||
798 totalhs > inths[AUGMENTED ][offset + 1]) {
801 (void)sprintf(place, "score");
803 (void)sprintf(place, "staff %d", s);
805 ufatal("on %s, 'transpose' %s %s %d and 'addtranspose' %s %s %d add up to an invalid interval",
807 num[0] > 0 ? "up" : "down", Inttab[type[0]], abs(num[0]),
808 num[1] > 0 ? "up" : "down", Inttab[type[1]], abs(num[1]));
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]) {