/* Output from p2c 1.21alpha-07.Dec.93, the Pascal-to-C translator */ /* From input file "prepmx.pas" */ #include "p2c.h" #ifndef CONTROL_H #include "control.h" #endif #ifndef STRINGS_H #include "strings.h" #endif #ifndef GLOBALS_H #include "globals.h" #endif #ifndef PREAMBLE_H #include "preamble.h" #endif #ifndef LYRICS_H #include "lyrics.h" #endif #ifndef MTX_H #include "mtx.h" #endif #ifndef ANALYZE_H #include "analyze.h" #endif #ifndef MTXLINE_H #include "mtxline.h" #endif #ifndef STATUS_H #include "status.h" #endif #ifndef UPTEXT_H #include "uptext.h" #endif #ifndef NOTES_H #include "notes.h" #endif #ifndef MULTFILE_H #include "multfile.h" #endif #ifndef FILES_H #include "files.h" #endif #ifndef UTILITY_H #include "utility.h" #endif /* CMO: addition/change by Christian Mondrup */ /** M-Tx preprocessor to PMX Dirk Laurie */ #define version "0.63a" #define version_date "<8 April 2018>" /** See file "Corrections" for updates */ /** To do next: {* Current bugs: {* Old bugs: Does not check PMX syntax {* Weaknesses that may later cause bugs: Decisions sometimes made on note, sometimes on scan Can 'here' overrun? Where does one note stop and the next begin? See comment on '!' in uptext */ #define chord_flat 't' #define chord_left 'l' #define blind true #define visible false Static boolean last_bar; Static Char repeat_sign[256]; /*, bars_of_rest*/ Static short bar_of_line; /* --------------- Bars and rests --------------- */ Static void writeRepeat(Char *bar) { Char repcode[256]; Char STR1[256]; if (*bar == '\0') return; *repcode = '\0'; if (!strcmp(bar, "||")) strcpy(repcode, "Rd"); else if (!strcmp(bar, "|]")) strcpy(repcode, "RD"); else if (!strcmp(bar, "|:")) strcpy(repcode, "Rl"); else if (!strcmp(bar, ":|:")) strcpy(repcode, "Rlr"); else if (!strcmp(bar, ":|")) strcpy(repcode, "Rr"); else if (last_bar && !strcmp(bar, "|")) strcpy(repcode, "Rb"); if (*repcode != '\0') { sprintf(STR1, " %s", repcode); putLine(STR1); } *bar = '\0'; } Static void supplyRests(voice_index voice) { Char STR2[4]; Char STR3[256]; if (bar_of_line == 1 && pedanticWarnings()) { printf("Bar %d Voice %d", bar_no, voice); warning(" Filling missing voice with rests", !print); } if (pickup > 0) put(rests(STR3, pickup, meterdenom, visible), nospace); sprintf(STR2, "%s ", pause); put(STR2, putspace); } /* Local variables for processLine: */ struct LOC_processLine { voice_index voice; Char chords[256], note[256], cutnote[256], pretex[256]; short ngrace, nmulti; boolean no_chords, no_uptext; short l; boolean in_group; } ; Local void output(Char *note_, struct LOC_processLine *LINK) { Char note[256]; Char STR2[256]; strcpy(note, note_); if (*note != '\0') { /* pretex is saved up until a spacing note or rest comes */ if (endsWith(note, "\\") && note[1] != '\\') { curtail(note, '\\'); strcat(LINK->pretex, note); *note = '\0'; return; } if (*LINK->pretex != '\0' && isNoteOrRest(note)) { sprintf(note, "%s\\ %s", LINK->pretex, strcpy(STR2, note)); *LINK->pretex = '\0'; } if (outlen > 0 && note[0] != ' ') sprintf(note, " %s", strcpy(STR2, note)); put(note, nospace); } if (thisNote(LINK->voice) == nextvoice) putLine(""); } Local void maybeDotted(Char *note, struct LOC_processLine *LINK) { if (strlen(note) < 2) return; if (note[1] == '"') { note[1] = note[0]; strcat(LINK->pretex, "\\mtxDotted"); } } /* Local variables for addChords: */ struct LOC_addChords { struct LOC_processLine *LINK; Char nt[256], labels[256]; boolean tieme; Char lab; int5 pitches; } ; Local void outChord(struct LOC_addChords *LINK) { short k; Char STR2[256]; short FORLIM; if (*LINK->nt == '\0') return; LINK->tieme = (LINK->nt[0] == '{'); if (LINK->tieme) predelete(LINK->nt, 1); if (*LINK->nt == '\0' || LINK->nt[0] < 'a' || LINK->nt[0] > 'g') { sprintf(STR2, "Must have a note name at the start of \"%s\", not \"%c\"", LINK->nt, LINK->nt[0]); error(STR2, print); } renewChordPitch(LINK->LINK->voice, LINK->nt); sprintf(LINK->LINK->chords + strlen(LINK->LINK->chords), " z%s", LINK->nt); *LINK->nt = '\0'; FORLIM = strlen(LINK->labels); for (k = 0; k <= FORLIM - 1; k++) { if (chordPitch(LINK->LINK->voice) == LINK->pitches[k]) { sprintf(LINK->LINK->chords + strlen(LINK->LINK->chords), " s%ct", LINK->labels[k]); LINK->labels[k] = ' '; } } if (LINK->tieme) { chordTie(LINK->LINK->voice, &LINK->lab); sprintf(LINK->LINK->chords + strlen(LINK->LINK->chords), " s%ct", LINK->lab); } } Local void addChords(struct LOC_processLine *LINK) { struct LOC_addChords V; Char w[256]; short j = 1; short mus_line; paragraph_index0 chord_line; boolean arpeggio; Char STR1[256]; short FORLIM; V.LINK = LINK; saveStatus(LINK->voice); getChordTies(LINK->voice, V.pitches, V.labels); *LINK->chords = '\0'; chord_line = chordLineNo(LINK->voice); if (chord_line == 0) LINK->no_chords = true; if (LINK->no_chords) return; GetNextWord(w, P[chord_line-1], blank, dummy); sprintf(STR1, "%c", barsym); if (!strcmp(w, STR1) || *w == '\0') LINK->no_chords = true; sprintf(STR1, "%c", tilde); if (!strcmp(w, STR1) || LINK->no_chords) return; mus_line = line_no; line_no = orig_line_no[chord_line-1]; arpeggio = (w[0] == '?'); if (arpeggio) { strcpy(LINK->chords, " ?"); predelete(w, 1); } *V.nt = '\0'; while (j <= strlen(w)) { if (w[j-1] == '{' || strcmp(V.nt, "{") && w[j-1] >= 'a' && w[j-1] <= 'g') outChord(&V); else if (w[j-1] == chord_flat) w[j-1] = 'f'; else if (w[j-1] == chord_left) w[j-1] = 'e'; sprintf(V.nt + strlen(V.nt), "%c", w[j-1]); j++; } if (*V.nt != '\0') outChord(&V); if (arpeggio) strcat(LINK->chords, " ?"); strcat(LINK->note, LINK->chords); FORLIM = strlen(V.labels); for (j = 0; j <= FORLIM - 1; j++) { if (V.labels[j] != ' ') error("Tie on chord note started but not finished", print); } line_no = mus_line; } Local Char *processOther(Char *Result, Char *note_, struct LOC_processLine *LINK) { Char note[256]; strcpy(note, note_); switch (thisNote(LINK->voice)) { case other: if (note[0] == grace_group) { if (strlen(note) == 1) LINK->ngrace = 1; else LINK->ngrace = pos1(note[1], digits); if (LINK->ngrace > 0) LINK->ngrace--; } break; /* For a zword, take note of pitch but do not change the contents */ /* Add spurious duration because repitch expects duration to be present */ case zword: strcpy(LINK->cutnote, note); predelete(LINK->cutnote, 1); insertChar('4', LINK->cutnote, 2); checkOctave(LINK->voice, LINK->cutnote); renewPitch(LINK->voice, LINK->cutnote); break; case lyrtag: extractLyrtag(LINK->voice, note); break; case rbrac: endBeam(LINK->voice); break; case rparen: case rlparen: endSlur(LINK->voice, note); break; case lbrac: beginBeam(LINK->voice, note); break; case lparen: maybeDotted(note, LINK); beginSlur(LINK->voice, note); break; case mword: error3(LINK->voice, "Meter change must be the first word of its bar"); break; case atword: lyricsAdjust(LINK->voice, note); break; } return strcpy(Result, note); } Local void lookahead(struct LOC_processLine *LINK) { Char STR2[256]; Char STR3[256]; while (bind_left[(long)nextNote(LINK->voice)]) sprintf(LINK->note + strlen(LINK->note), " %s", processOther(STR2, getMusicWord(STR3, LINK->voice), LINK)); } Local void processUsual(struct LOC_processLine *LINK) { if (hasVerseNumber(LINK->voice)) strcat(LINK->pretex, "\\mtxVerse"); LINK->l = pos1(multi_group, LINK->note); if (LINK->l > 0) scan1(LINK->note, LINK->l + 1, &LINK->nmulti); activateBeamsAndSlurs(LINK->voice); LINK->in_group = false; if (LINK->ngrace > 0) { LINK->in_group = true; LINK->ngrace--; } else { if (LINK->nmulti > 0) { LINK->in_group = true; LINK->nmulti--; } } checkOctave(LINK->voice, LINK->note); renewPitch(LINK->voice, LINK->note); if (!LINK->in_group) { resetDuration(LINK->voice, durationCode(LINK->note)); markDebeamed(LINK->voice, LINK->note); } lookahead(LINK); getSyllable(LINK->voice, LINK->pretex); addUptext(LINK->voice, &LINK->no_uptext, LINK->pretex); addChords(LINK); } /* ---------------------------------------------------------------- */ Static void processLine(voice_index voice_, short bar_no) { struct LOC_processLine V; paragraph_index par_line; Char STR1[256]; V.voice = voice_; *V.pretex = '\0'; V.no_chords = false; V.no_uptext = false; par_line = musicLineNo(V.voice); V.nmulti = 0; V.ngrace = 0; line_no = orig_line_no[par_line-1]; do { getMusicWord(V.note, V.voice); if (*V.note == '\0') return; /* if debugMode then writeln(voice,' ',note); */ switch (thisNote(V.voice)) { case rword: if (*multi_bar_rest != '\0') { if (uptextOnRests()) addUptext(V.voice, &V.no_uptext, V.pretex); } else { V.l = pos1(multi_group, V.note); if (V.l > 0) scan1(V.note, V.l + 1, &V.nmulti); if (V.nmulti > 0) { V.in_group = true; V.nmulti--; } if (uptextOnRests()) addUptext(V.voice, &V.no_uptext, V.pretex); if (!(isPause(V.note) || V.in_group)) /*0.63: allow rests in xtuples*/ resetDuration(V.voice, durationCode(V.note)); } break; case abcdefg: processUsual(&V); break; case barword: if (V.voice == nvoices) { if (endOfBar(V.voice, bar_no)) strcpy(repeat_sign, V.note); else writeRepeat(V.note); } sprintf(STR1, "%c", barsym); if (strcmp(V.note, STR1)) *V.note = '\0'; V.no_chords = false; break; case FirstOnly: if (V.voice != nvoices) *V.note = '\0'; else strcpy(V.note, processOther(STR1, V.note, &V)); break; default: strcpy(V.note, processOther(STR1, V.note, &V)); break; } output(V.note, &V); } while (!endOfBar(V.voice, bar_no)); if (!V.no_chords) skipChordBar(V.voice); } /* ------------------------------------------------------------------- */ Static void getMeterChange(voice_index voice, Char *new_meter) { short pn1, pn2; Char w[256], new_command[256]; if (nextNote(voice) != mword) return; getMusicWord(w, voice); getMeter(w, &meternum, &meterdenom, &pn1, &pn2); full_bar = meternum * (64 / meterdenom); /* CMO: process denominator value with function PMXmeterdenom */ meterWord(new_command, meternum, PMXmeterdenom(meterdenom), pn1, pn2); if (*new_meter != '\0' && strcmp(new_meter, new_command)) error3(voice, "The same meter change must appear in all voices"); strcpy(new_meter, new_command); } /* Local variables for musicParagraph: */ struct LOC_musicParagraph { Char new_meter[256]; } ; Local void putPMXlines(struct LOC_musicParagraph *LINK) { paragraph_index i, FORLIM; FORLIM = para_len; for (i = 0; i <= FORLIM - 1; i++) { if (startsWith(P[i], double_comment)) { predelete(P[i], 2); putLine(P[i]); strcpy(P[i], "%"); } } } Local void processOneBar(struct LOC_musicParagraph *LINK) { paragraph_index0 m, cm; voice_index voice, cvoice; boolean ignore_voice; boolean wrote_repeat = false; boolean alone; Char STR2[256]; Char STR3[256]; if (bar_of_line > 1) { sprintf(STR3, "%cBar %s", comment, toString(STR2, bar_no)); putLine(STR3); } last_bar = (bar_of_line == nbars && final_paragraph); if (last_bar && !strcmp(repeat_sign, "|")) *repeat_sign = '\0'; writeRepeat(repeat_sign); *LINK->new_meter = '\0'; for (voice = nvoices; voice >= 1; voice--) { if (musicLineNo(voice) > 0) { gotoBar(voice, bar_of_line); getMeterChange(voice, LINK->new_meter); } } if (last_bar && *LINK->new_meter == '\0' && nleft > pickup && meternum > 0) meterChange(LINK->new_meter, nleft, 64, true); if (*LINK->new_meter != '\0') putLine(LINK->new_meter); for (voice = nvoices; voice >= 1; voice--) { ignore_voice = !selected[voice-1]; cvoice = companion(voice); m = musicLineNo(voice); cm = musicLineNo(cvoice); alone = (voice == cvoice || m > 0 && cm == 0 || m == 0 && cm == 0 && voice < cvoice || !selected[cvoice-1]); if (selected[voice-1]) { if (m > 0) processLine(voice, bar_of_line); else if (alone) supplyRests(voice); else ignore_voice = true; if (last_bar && *repeat_sign != '\0' && !wrote_repeat) { writeRepeat(repeat_sign); wrote_repeat = true; } if (!ignore_voice) { if (alone || voicePos(voice) == 1) putLine(" /"); else putLine(" //"); } } } bar_no++; pickup = 0; putLine(""); } Local void putMeter(Char *new_meter_word, struct LOC_musicParagraph *LINK) { if (strcmp(new_meter_word, old_meter_word)) putLine(new_meter_word); strcpy(old_meter_word, new_meter_word); } Local void processMBR(struct LOC_musicParagraph *LINK) { short s, bars_of_rest; Char mbr[256]; short FORLIM; Char STR1[256]; Char STR3[256]; strcpy(mbr, multi_bar_rest); predelete(mbr, 2); getNum(mbr, &bars_of_rest); bar_no += bars_of_rest; FORLIM = nstaves; for (s = 1; s <= FORLIM; s++) { if (pickup > 0) put(rests(STR1, pickup, meterdenom, visible), nospace); sprintf(STR3, "rm%s /", toString(STR1, bars_of_rest)); putLine(STR3); } putLine(""); } Static void musicParagraph(void) { struct LOC_musicParagraph V; voice_index0 j, nvoice; Char lyrassign[256]; Char STR1[256]; Char STR2[256]; Char STR3[256], STR4[256], STR5[256]; voice_index0 FORLIM; short FORLIM1; paragraphSetup(&nvoice); if (nvoice == 0) { nonMusic(); return; } if (nvoice > nvoices) { if (nvoice == 0) error("No voices! Did you remember to to supply a Style?", !print); sprintf(STR4, "Paragraph has %s voices but Style allows only %s", toString(STR1, nvoice), toString(STR2, nvoices)); error(STR4, !print); return; } if (first_paragraph) includeStartString(); if (pmx_preamble_done && (!final_paragraph || nvoice > 0)) { sprintf(STR5, "%c Paragraph %s line %s bar %s", comment, toString(STR1, paragraph_no), toString(STR2, orig_line_no[0]), toString(STR3, bar_no)); putLine(STR5); } testParagraph(); rememberDurations(); if (beVerbose()) describeParagraph(); /* ---- Knowing the score, we can start setting music ---------------- */ if (!pmx_preamble_done) { doPMXpreamble(); sprintf(STR3, "%c Paragraph %s line %s bar ", comment, toString(STR1, paragraph_no), toString(STR2, orig_line_no[0])); put(STR3, putspace); if (pickup > 0) putLine("0"); else putLine("1"); } putPMXlines(&V); if (must_restyle) restyle(); if (some_vocal && (nvoice > 0 || !final_paragraph)) { FORLIM = ninstr; for (j = 1; j <= FORLIM; j++) { assignLyrics(j, lyrassign); if (*lyrassign != '\0') { sprintf(STR2, "\\\\%s\\", lyrassign); putLine(STR2); } } } if (must_respace) respace(); if (meternum == 0) putMeter(meterChange(STR2, beatsPerLine(), meterdenom, true), &V); if (nleft > 0) nbars++; if (nbars == 0 && *multi_bar_rest != '\0') processMBR(&V); else { FORLIM1 = nbars; for (bar_of_line = 1; bar_of_line <= FORLIM1; bar_of_line++) processOneBar(&V); } restoreDurations(); } /* ----------------------------------------------------------------------- */ Static boolean no_commands_yet; Static void doMusic(void) { Char STR1[256], STR2[256]; Char STR4[256]; first_paragraph = true; pmx_preamble_done = false; bar_no = 1; *repeat_sign = '\0'; must_respace = false; must_restyle = false; do { final_paragraph = endOfInfile(); memcpy(orig_P, P, sizeof(paragraph)); if (para_len > 0 && !ignore_input && thisCase()) { if (no_commands_yet) { interpretCommands(); printFeatures(false); one_beat = 64 / meterdenom; full_bar = meternum * one_beat; if (nvoices > standardPMXvoices) { sprintf(STR4, "You have %s voices; standard PMX can only handle %s", toString(STR1, nvoices), toString(STR2, standardPMXvoices)); warning(STR4, !print); } initMTX(); initUptext(); initStatus(); initLyrics(); no_commands_yet = false; } if (startsWithBracedWord(P[0])) lyricsParagraph(); else { musicParagraph(); first_paragraph = false; writeRepeat(repeat_sign); } } readParagraph(P, orig_line_no, ¶_len); } while (para_len != 0); } Static boolean control_paragraph, no_report_errors; Static boolean isControlParagraph(Char (*P)[256], paragraph_index para_len) { paragraph_index0 commands = 0, labels = 0, voices = 0, guff = 0; paragraph_index0 i; Char w[256]; /* p2c: prepmx.pas: Note: Eliminated unused assignment statement [338] */ for (i = 0; i <= para_len - 1; i++) { if (!startsWith(P[i], "%")) { NextWord(w, P[i], ' ', ':'); if (!endsWith(w, ":")) guff++; else if (strlen(w) < 3 || findVoice(w) > 0) voices++; else if (isCommand(w)) commands++; else labels++; } } if (voices + guff > commands) return false; return true; } Static void topOfPMXfile(void) { Char STR2[24]; Char STR3[30]; putLine("---"); sprintf(STR2, "\\def\\mtxversion{%s}", version); putLine(STR2); sprintf(STR3, "\\def\\mtxdate{%s}", version_date); putLine(STR3); putLine("\\input mtx"); } main(int argc, Char *argv[]) { /* ---- Main program ------------------------ */ PASCAL_MAIN(argc, argv); strcpy(this_version, version); strcpy(this_version_date, version_date); printf("==> This is M-Tx %s (Music from TeXt) %s\n", version, version_date); mtxLevel(version); OpenFiles(); no_commands_yet = true; preambleDefaults(); no_report_errors = false; topOfPMXfile(); do { readParagraph(P, orig_line_no, ¶_len); control_paragraph = isControlParagraph(P, para_len); if (control_paragraph) { augmentPreamble(no_report_errors); no_report_errors = true; if (para_len == 0) error("No music paragraphs!", !print); } } while (control_paragraph); doPreamble(); doMusic(); if (!pmx_preamble_done) error("No music paragraphs!", !print); putLine("% Coded by M-Tx"); CloseFiles(); printf("PrePMX done. Now run PMX.\n"); _Escape(0); exit(EXIT_SUCCESS); } /* End. */