Commit | Line | Data |
---|---|---|
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 | */ | |
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 | } |