chiark / gitweb /
Merge branch 'arkkra' into shiny
[mup] / mup / mup / trnspose.c
CommitLineData
69695f33
MW
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 */
19static 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 */
30static 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 */
38static int inttype[MAXSTAFFS+1]; /* interval type of simple interval */
39static int intnum[MAXSTAFFS+1]; /* simple interval (>0, octs removed)*/
40static int octint[MAXSTAFFS+1]; /* number of octaves in interval */
41
42
43static void transnote P((struct GRPSYL *g_p, struct NOTE *n_p, int inttype,
44 int intnum, int octint));
45static void translurto P((struct GRPSYL *g_p, struct NOTE *n_p, int tnum,
46 int toct));
47static void simptrans P((int origtype, int orignum, int *inttype_p,
48 int *intnum_p, int *octint_p));
49static 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
67void
68transgroups()
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
246static void
247transnote(g_p, n_p, ttype, tnum, toct)
248
249struct GRPSYL *g_p; /* ptr to note's group, used only in error messages */
250register struct NOTE *n_p; /* pointer to the note structure */
251int ttype; /* interval type (DIMINISHED, MINOR, . . .) */
252int tnum; /* simple interval (positive, with octaves removed) */
253int 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
349static void
350translurto(g_p, n_p, tnum, toct)
351
352struct GRPSYL *g_p; /* note's group, used only in error messages */
353struct NOTE *n_p; /* note whose slurto list is to be transposed */
354int tnum; /* transposition interval number */
355int 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
404char *
405tranchnote(letter, acc, s)
406
407int letter; /* A to G */
408int acc; /* one of: 'x', '#', '\0', '&', 'B' */
409int 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
482int
483eff_key(staff)
484
485int 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
576static void
577simptrans(origtype, orignum, inttype_p, intnum_p, octint_p)
578
579int origtype; /* original transposition interval type */
580int orignum; /* original transposition interval number */
581int *inttype_p; /* interval type (DIMINISHED, MINOR, . . .) */
582int *intnum_p; /* simple interval (positive, with octaves removed) */
583int *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
636static void
637fixslurto(s, mainll_p, nintnum, noctint)
638
639int s; /* staff number */
640struct MAINLL *mainll_p; /* initially points at current staff */
641int nintnum; /* interval number of new transposition */
642int 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
715void
716totaltrans(s, type_p, num_p)
717
718int s; /* staff number, or 0 for score */
719int *type_p; /* return type of resulting transposition */
720int *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}