/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */ /* From input file "mtx.pas" */ #include "p2c.h" #define MTX_G #include "mtx.h" #ifndef CONTROL_H #include "control.h" #endif #ifndef MTXLINE_H #include "mtxline.h" #endif #ifndef STRINGS_H #include "strings.h" #endif #ifndef STATUS_H #include "status.h" #endif #ifndef NOTES_H #include "notes.h" #endif #define flagged "8136" typedef boolean sticky['z' + 1 - 'a']; Static sticky note_attrib[maxvoices], rest_attrib[maxvoices]; Static short logTwo(short denom) { short l = 0; while (denom > 1) { l++; denom /= 2; } return l; } Local boolean dotted(short n) { boolean Result; /* p2c: mtx.pas: Note: Eliminated unused assignment statement [338] */ if (n == 0) return false; if (n != n / 3 * 3) return false; n /= 3; while ((n & 1) == 0) n /= 2; return (n == 1); } /* RESTS should have a third parameter OFFSET. At present we in effect assume OFFSET+LENGTH to be a multiple of METERDENOM. */ Char *rests(Char *Result, short len, short meterdenom, boolean blind) { Char r[256], bl[256]; Char STR1[256]; if (blind) strcpy(bl, "b"); else *bl = '\0'; if (len == 0) return strcpy(Result, ""); else { if (len == meterdenom * 128) { sprintf(Result, "r9%s ", bl); return Result; } else { if (dotted(len)) { rests(r, len - len / 3, meterdenom, false); r[2] = 'd'; sprintf(Result, "%s%s ", r, bl); return Result; } else if (len >= 64 / meterdenom) { sprintf(Result, "%sr%c%s ", rests(STR1, len - 64 / meterdenom, meterdenom, blind), durations[whole + logTwo(meterdenom) - 1], bl); return Result; } else return (rests(Result, len, meterdenom * 2, blind)); } } } Local Char *attribs(Char *Result, Char *note) { Char a[256]; short i = 2; short l; Char n; *a = '\0'; l = strlen(note); while (i <= l) { n = note[i-1]; if (n == 'x') i = l; else if (islower(n)) sprintf(a + strlen(a), "%c", n); i++; } return strcpy(Result, a); } Static void checkSticky(Char *note, boolean *attrib) { short i = 2; short l; Char c; Char a[256]; if (*note == '\0') return; l = strlen(note); while (i <= l) { c = note[i-1]; if (islower(c)) { if (i < l && note[i] == ':') { delete1(note, i + 1); l--; attrib[c - 'a'] = !attrib[c - 'a']; } else attrib[c - 'a'] = false; } i++; } attribs(a, note); for (c = 'z'; c >= 'a'; c--) { if (attrib[c - 'a'] && pos1(c, a) == 0) insertChar(c, note, 3); } } /* Routine was patched by Hiroaki Morimoto, revised 2003/08/15. Rewritten by DPL 2004/05/16 to be more understandable. octaveCode returns octave adjustments in the order [absolute or =],[relative] */ void checkOctave(voice_index voice, Char *note) { Char code; code = octaveCode(note); if (code == '=') { setOctave(voice); removeOctaveCode(code, note); } if (octave(voice) == blank) return; code = octaveCode(note); if (isdigit(code)) { resetOctave(voice); return; } while (code == '+' || code == '-') { newOctave(voice, code); removeOctaveCode(code, note); code = octaveCode(note); } if (code != ' ') error3(voice, "You may have only one absolute octave assignment"); insertOctaveCode(octave(voice), note); checkRange(voice, note); resetOctave(voice); } void markDebeamed(voice_index voice, Char *note) { if (isVocal(voice) && afterSlur(voice) == 0 && unbeamVocal() && pos1(duration(voice), flagged) > 0) insertChar('a', note, 2); } Static short barLength(Char *meter) { short n1, n2, pn1, pn2; getMeter(meter, &n1, &n2, &pn1, &pn2); return (n1 * (64 / n2)); } Static boolean isMultiBarRest(Char *rest_) { boolean Result; /* p2c: mtx.pas: Note: Eliminated unused assignment statement [338] */ if (strlen(rest_) < 3) return false; if (rest_[1] != 'm') return false; if (*multi_bar_rest != '\0') error("Only one multibar rest allowed per line", print); strcpy(multi_bar_rest, rest_); return true; } /* Double-length in xtuplet detected by a brute search for D anywhere. Could be more elegant. */ Static short macro_length[20]; Static Char macro_ID[20][3] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" }; /* Local variables for scanMusic: */ struct LOC_scanMusic { voice_index voice; Char note[256]; boolean doublex, store_macro; short bar, old_length, bar_length, count, l, mlen, ngrace, nmulti, macroID, playID; Char macro_type; } ; Local void decmulti(struct LOC_scanMusic *LINK) { if (LINK->doublex) LINK->nmulti -= 2; else LINK->nmulti--; } /* Local variables for countIt: */ struct LOC_countIt { struct LOC_scanMusic *LINK; } ; Local void incbar(short nl, struct LOC_countIt *LINK) { LINK->LINK->bar_length += nl; if (LINK->LINK->bar_length > LINK->LINK->bar && meternum > 0) error3(LINK->LINK->voice, "Bar end occurs in mid-note"); } Local void countIt(struct LOC_scanMusic *LINK) { struct LOC_countIt V; V.LINK = LINK; if (LINK->ngrace > 0) { LINK->ngrace--; return; } if (LINK->nmulti > 0) { decmulti(LINK); return; } if (LINK->count % 3 != 0 && (LINK->note[0] != rest && note_attrib[LINK->voice-1]['d' - 'a'] || LINK->note[0] == rest && rest_attrib[LINK->voice-1]['d' - 'a'])) LINK->count += LINK->count / 2; /* p2c: mtx.pas, line 150: * Note: Using % for possibly-negative arguments [317] */ incbar(LINK->count, &V); LINK->l = pos1(multi_group, LINK->note); if (LINK->l <= 0) return; predelete(LINK->note, LINK->l); getNum(LINK->note, &LINK->nmulti); decmulti(LINK); } Local void maybeGroup(struct LOC_scanMusic *LINK) { if (LINK->note[0] != grace_group) return; if (strlen(LINK->note) == 1) LINK->ngrace = 1; else LINK->ngrace = pos1(LINK->note[1], digits); /* bug if ngrace>9 */ if (LINK->ngrace > 0) LINK->ngrace--; } Local short identifyMacro(Char *s_, struct LOC_scanMusic *LINK) { Char s[256]; short k; strcpy(s, s_); predelete(s, 2); for (k = 1; k <= 20; k++) { if (!strcmp(s, macro_ID[k-1])) return k; } return 0; } Local void examineMacro(struct LOC_scanMusic *LINK) { if (!countMacro()) return; if (debugMode()) printf("%s: ", LINK->note); if (strlen(LINK->note) == 1) { LINK->mlen = LINK->bar_length - LINK->old_length; if (LINK->macroID < 1 || LINK->macroID > 20) error3(LINK->voice, "Invalid macro ID"); macro_length[LINK->macroID-1] = LINK->mlen; if (debugMode()) printf("Ending macro %d of type %c, length=%d\n", LINK->macroID, LINK->macro_type, LINK->mlen); if (LINK->macro_type == 'S') LINK->bar_length = LINK->old_length; LINK->store_macro = false; return; } LINK->playID = identifyMacro(LINK->note, LINK); if (LINK->playID < 1 || LINK->playID > 20) error3(LINK->voice, "Invalid macro ID"); if (LINK->note[1] == 'P') { if (debugMode()) printf("Playing macro %d of length %d\n", LINK->playID, macro_length[LINK->playID-1]); LINK->bar_length += macro_length[LINK->playID-1]; return; } if (pos1(LINK->note[1], "SR") <= 0) return; LINK->old_length = LINK->bar_length; LINK->macro_type = LINK->note[1]; LINK->macroID = LINK->playID; LINK->store_macro = true; if (debugMode()) printf("Defining macro %d of type %c\n", LINK->macroID, LINK->note[1]); } void scanMusic(voice_index voice_, short *left_over) { struct LOC_scanMusic V; Char buf[256], enote[256], xnote[256]; boolean has_next = false, done = false; Char dur1, lastdur; music_word nscan; Char STR1[256]; V.voice = voice_; strcpy(terminators, "d.x"); resetInfo(V.voice, buf); *left_over = 0; V.store_macro = false; V.bar = full_bar; V.bar_length = 0; V.ngrace = 0; V.nmulti = 0; if (meternum == 0) V.bar = 32000; dur1 = duration(V.voice); lastdur = dur1; do { getNextMusWord(buf, V.note, &nscan); if (*V.note == '\0') break; V.count = 0; /* if isNoteOrRest(note) and not (isPause(note) or isMultibarRest(note)) then note:=toStandard(note); */ V.doublex = (pos1('D', V.note) > 0 || pos1('F', V.note) > 0); if (nscan == mword) { if (*V.note == '\0') error3(V.voice, "You may not end a line with a meter change"); if (V.bar_length > 0) error3(V.voice, "Meter change only allowed at start of bar"); else V.bar = barLength(V.note); } else if (nscan == rword) { if (!(isPause(V.note) || isMultiBarRest(V.note) || V.ngrace + V.nmulti > 0)) { /*0.63: allow rests in xtuples*/ processNote(V.note, xnote, dur1, &lastdur, &V.count); checkSticky(V.note, rest_attrib[V.voice-1]); } } if (*V.note != '\0') appendNote(V.voice, nscan); strcpy(enote, V.note); if (nscan == macro || nscan == endmacro) examineMacro(&V); if (nscan == abcdefg) { if (*multi_bar_rest == '\0' && V.ngrace + V.nmulti == 0) { processNote(enote, xnote, dur1, &lastdur, &V.count); if (*xnote != '\0') { checkSticky(enote, note_attrib[V.voice-1]); appendToLine(V.voice, enote); appendNote(V.voice, nscan); strcpy(enote, xnote); } checkSticky(enote, note_attrib[V.voice-1]); } } appendToLine(V.voice, enote); if (*V.note == '\0') /* !!! else word_bound[here]:=length(line); */ done = true; sprintf(STR1, "%c", barsym); if (!strcmp(V.note, STR1)) { if (meternum == 0) error3(V.voice, "You may not use bar lines in barless music"); else if (V.bar_length == 0) markBar(V.voice); else if (numberOfBars(V.voice) == 0 && V.bar_length < V.bar) { if (has_next) has_next = false; /*TODO Should check whether pickups are equal*/ else if (*left_over > 0) error3(V.voice, "Bar is too short"); *left_over = V.bar_length; V.bar_length = 0; } } if (nscan == nextvoice) { if (V.bar_length > 0) error3(V.voice, "Next voice before bar is full"); else barForward(V.voice, -1); has_next = true; } else if (isPause(V.note)) V.bar_length += V.bar; else if (*multi_bar_rest == '\0') { /*do nothing*/ if (!done && isNoteOrRest(V.note)) countIt(&V); else maybeGroup(&V); } dur1 = lastdur; if (V.bar_length >= V.bar && V.ngrace + V.nmulti == 0 && !V.store_macro) { if (debugMode()) printf("%d %d\n", V.voice, V.bar_length); barForward(V.voice, V.bar_length / V.bar); V.bar_length %= V.bar; /* p2c: mtx.pas, line 269: * Note: Using % for possibly-negative arguments [317] */ } } while (!done); setExtraLength(V.voice, V.bar_length); resetDuration(V.voice, dur1); regroup(V.voice); } void initMTX(void) { voice_index i; Char j; for (i = 0; i <= maxvoices - 1; i++) { for (j = 'a'; j <= 'z'; j++) note_attrib[i][j - 'a'] = false; } memcpy(rest_attrib, note_attrib, maxvoices * sizeof(sticky)); } /* End. */