/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This file is part of jcabc2ps, * Copyright (C) 1996,1997,1998 Michael Methfessel * See file jcabc2ps.c for details. */ #include #include #include #include "jcabc2ps.h" #include "util.h" #include "format.h" #include "subs.h" #include "text.h" #include "parse.h" int syntaxErrors = 0; // Count the error messages int errorLimit = 100; // Give up after this many errors int middleadj (char note); int ksigcancel = 0; // Flag controlling ksig-cancel code. Ksig *lastks = 0; // For remembering Ksig struct struct clef_desc { char *name; int val; } clefname[] = { // We do case-insensitive compares {"TREBLE", 0}, {"TREBLE", 10}, {"TREBLE-8", 11}, // Treble-8 {"TREBLE+8", 12}, // Treble+8 {"ALTO", 20}, {"ALTO-8", 21}, // Alto-8 {"ALTO+8", 22}, // Alto+8 {"TENOR", 13}, // Tenor = Treble-8 {"BASS", 30}, {"BASS-8", 31}, // Bass-8 {"BASS+8", 32}, // Bass+8 {"NOCLEF", 90}, // Don't show clef at all {"NOCLEF-8", 91}, // These are for completeness, {"NOCLEF+8", 92}, // but we don't expect to see them. {0,0} }; char *SymClef(n) { int i; for (i=0; clefname[i].name; i++) { if (clefname[i].val == n) { return clefname[i].name; } } return ""; } char *symname[] = { "[0]", /* 0 */ "INVISIBLE", /* 1 valid symbol types */ "NOTE", /* 2 */ "REST", /* 3 */ "BAR", /* 4 */ "CLEF", /* 5 */ "TIMESIG", /* 6 */ "KEYSIG", /* 7 */ "ACHORD", /* 8 */ "KEYSGN", /* 9 */ "ANNOT", /* 10 */ "[11]", /* 11 */ "[12]", /* 12 */ "[13]", /* 13 */ "[14]", /* 14 */ "[15]", /* 15 */ "[16]", /* 16 */ }; char * SymName(n) { if (n < 0 || n > 16) return "UNKNOWN"; return symname[n]; } extern char *dmpKsig(); int note_pos( char note, int clef); int achp = 0; /* Position (above, below) of current accompaniment chord */ int decos = 0; /* Number of decorations on current symbol */ int dtype[30]; /* Decoration types */ int oldks = 0; /* Whether to use old keysig code */ int unexpsym = 0; /* Line number for "Unexpected symbol" messages */ /* * for each note A..G, these tables tell how many sharps (resp. flats) * the keysig must have to get the accidental on this note. Phew. */ int sh_tab[] = {5,7,2,4,6,1,3}; // Position of sharps on treble staff. int fl_tab[] = {3,1,6,4,2,7,5}; // Position of flats on treble staff. char sh_val[] = {'f','c','g','d','A','e','B'}; char fl_val[] = {'B','e','A','d','G','c','F'}; /* subroutines connected with parsing the input file */ /* ----- sytax: print message for syntax errror -------- */ void syntax( char *msg, char *q) { char *F="syntax"; int i,n,len,m1,m2,pp,qq,maxcol = 65; V6 "%s: Called for msg=\"%s\" q=\"%s\"\n",F,(msg?msg:""),(q?q:"") V; if (verbose <= 2) fprintf(stderr,"\n"); unless (Q) Q= q; qq = q-Q+1; if (qq<0) qq = 0; fprintf(stderr,"+++ %s in line %d.%d \n", msg, linenum, qq); m1 = 0; m2 = len = strlen(Q); n = q-Q; if (m2>maxcol) { if (nlen) m2 = len; } } fprintf(stderr,"%4d ", linenum); pp = 5; if (m1>0) { fprintf(stderr,"..."); pp += 3; } for (i = m1;i= 0 && n<200) { for (i = 0;iksig) { V3 "%s: Free s->ksig for %d\n",F,d V; Free(s->ksig,"Ksig"); V6 "Forget s->ksig=%08X",s->ksig V; s->ksig = 0; } if (s->ann) { V3 "%s: Free s->ann for %d\n",F,d V; zapText(s->ann,"ann"); V6 "Forget s->ann=%08X",s->ann V; s->ann = 0; } // for (j = 0; j < NWLINE; j++ ) { // if (s->wordp[j]) { // V3 "%s: Free s->wordp[%d] for %d\n",F,j,d V; // Free(s->wordp[j],"wordp"); // This isn't allocated. // s->wordp[j] = 0; // } // } bzero(s,sizeof(Sym)); s->ylo = 12; s->yhi = 12; s->p = -1; V3 "%s: Zeroed sym %08X \"%s\".\n",F,s,d V; } /* ----- add_sym: returns index for new symbol at end of list ---- */ int add_sym (type) int type; { char *F = "add_sym"; int k; V6 "%s: Called for sym %d=%s\n",F,type,symname[type] V; k = voice[ivc].nsym; if (k >= maxSyms) rxi("Too many symbols; increase maxSyms, now ",maxSyms); voice[ivc].nsym++; zeroSym(&symv[ivc][k],"symv/add_sym"); symv[ivc][k].type = type; if (!symv[ivc][k].ksig) { symv[ivc][k].ksig = newKsig(F); V6 "%s: Copied new Ksig %X to symv[%d][%d].ksig\n",F,symv[ivc][k].ksig,ivc,k V; } // TextInit(&ann,64); return k; } /* ----- insert_sym: returns index for new symbol inserted at k --- */ int insert_sym (type,k) int type,k; { int i,n; n = voice[ivc].nsym; if (n >= maxSyms) rxi("insert_sym: maxSyms exceeded: ",maxSyms); for (i = n; i > k; i--) { symv[ivc][i] = symv[ivc][i-1]; } n++; zeroSym(&symv[ivc][k],"symv/insert_sym"); symv[ivc][k].type = type; voice[ivc].nsym = n; return k; } /* ----- get_xref: get xref from string ----- */ int get_xref (str) char str[]; { int a,ok; char *q; if (strlen(str) == 0) { wng ("xref string is empty", ""); return 0; } q = str; ok = 1; while (*q != '\0') { if (!isdigit(*q)) ok = 0; q++; } if (!ok) { wng ("xref string has invalid symbols: ", str); return 0; } sscanf (str, "%d", &a); return a; } /* ----- set_meter: interpret meter string, store in struct ---- */ void set_meter (str,meter) char *str; Msig *meter; { char *F="set_meter"; int m1=0, m2=0, m1a=0, m1b=0, m1c=0, d=0, l=0; char *q; int meter1=0, meter2=0, dlen=0, mflag=0, lflag=0; char meter_top[31]; l = strlen(str); if (l == 0) { V3 "Null meter.\n" V; meter1 = meter2 = 4; dlen = EIGHTH; mflag = 4; strcpy(meter_top,"-"); } elsif (!strcasecmp(str,"none")) { V3 "Free meter.\n" V; meter1 = meter2 = 4; dlen = EIGHTH; mflag = 4; strcpy(meter_top,"-"); } elsif (str[0] == 'C') { if (str[1] == '|') { V3 "Common meter.\n" V; meter1 = meter2 = 4; dlen = EIGHTH; mflag = 2; strcpy(meter_top,"C"); } else { V3 "Cut meter.\n" V; meter1 = meter2 = 4; dlen = EIGHTH; mflag = 1; strcpy(meter_top,"C"); } } else { strcpy (meter_top, str); q = strchr(meter_top,'/'); if (!q) { wng("Cannot identify meter, missing /: ", str); m1 = m2 = 1; return; } *q++ = '\0'; if (strchr(meter_top,'+')) { sscanf(str,"%d+%d+%d/", &m1a, &m1b, &m1c); V2 "%s; '+' m1a=%d m1b=%d m1c=%d\n",F,m1a,m1b,m1c V; m1 = m1a + m1b + m1c; } else { sscanf(str,"%d %d %d/", &m1a, &m1b, &m1c); V2 "%s; ddd/ m1a=%d m1b=%d m1c=%d\n",F,m1a,m1b,m1c V; m1 = m1a; if (m1b>m1) m1 = m1b; if (m1c>m1) m1 = m1c; if (m1>30) { /* handle things like 78/8 */ m1a = m1 / 100; m1c = m1 - 100 * m1a; m1b = m1c / 10; m1c = m1c - 10 * m1b; m1 = m1a; if (m1b>m1) m1 = m1b; if (m1c>m1) m1 = m1c; } } while (*q == '/') q++; // [jc] We sometimes see repeated / sscanf (q, "%d", &m2); V2 "%s; q=\"%s\" m1a=%d m1b=%d m1c=%d m2=%d\n",F,q,m1a,m1b,m1c,m2 V; if (m1*m2 == 0) { V1 "Cannot identify meter: \"%s\" (m1=%d m2=%d q=\"%s\")\n",str,m1,m2,q V; if (!m1) m1 = 1; if (!m2) m2 = 1; } d = BASE/m2; if (d*m2 != BASE) { V2 "Warning: Meter not recognized: \"%s\" (BASE=%d m1=%d m2=%d d=%d)\n",str,BASE,m1,m2,d V; } meter1 = m1; meter2 = m2; dlen = EIGHTH; if (4*meter1 < 3*meter2) dlen = SIXTEENTH; mflag = 0; } V3 "%s: Meter <%s> is %d over %d with default length 1/%d\n",F,str,meter1,meter2,BASE/(dlen?dlen:1) V; /* handle old-style change of default length */ // lflag = 0; if (str[l-1] == 's') { dlen = dlen*2; lflag = 1; } if (str[l-1] == 'l') { dlen = dlen/2; lflag = -1; } /* store parsed data in struct */ meter->meter1 = meter1; meter->meter2 = meter2; meter->mflag = mflag; if (!meter->dlen) { // Set the default length only if not yet known. V3 "%s: Change meter->dlen from %d to %d.\n",F,meter->dlen,dlen V; meter->dlen = dlen; } meter->lflag = lflag; strcpy(meter->top, meter_top); } /* ----- set_dlen: set default length for parsed notes ---- */ void set_dlen (str,meter) char str[]; Msig *meter; { char *F = "set_dlen"; int l1,l2,d,dlen; l1 = 0; l2 = 1; sscanf(str,"%d/%d ", &l1, &l2); if (l1 == 0) { return; /* empty string.. don't change default length */ } else { d = BASE/l2; if (d*l2 != BASE) { wng("Length incompatible with BASE, using 1/8: ",str); dlen = BASE/8; } else { dlen = d*l1; } } V3 "%s: <%s> sets default note length to %d/%d = 1/%d\n",F,str,dlen,BASE,BASE/dlen V; meter->dlen = dlen; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Caseless string comparison. This was done so that we can insert debug info, * which isn't feasible with the library strcasecmpn() routine. */ nocasecmpn(s1,s2,n) char *s1, *s2; int n; { char *F="nocasecmpn"; char *p1, *p2; int c1, c2, i; // V8 "%s: n=%d \"%s\" \"%s\"\n",F,n,s1,s2 V; for (i=0; i c2) { // s1 is greater // V8 "%s: Return %d at char %d ('%c','%c')\n",F,-(i+1),i,c1,c2 V; return -(i+1); } } // V8 "%s: Return 0 at char %d (EQUAL)\n",F,i,c1,c2 V; return 0; } /* ----------- parseKey: interpret keysig string, store in struct ----------- * This part was adapted from abc2mtex by Chris Walshaw updated 03 Oct 1997 * Wil Macaulay - support all modes Returns 1 if key was actually specified, * because then we want to transpose. Returns zero if this is just a clef * change. * * Modified by John Chambers to allow for accidentals after the tonic and mode * fields. The result is a Ksig struct in the symbol that lists the * accidentals explicitly. This could be an implementation of "global * accidentals" if we were following the 1.6 standard, or it could be used for * arbitrary key signatures, as in the newer standard. */ int parseKey(s,ks,init) char *s; Ksig *ks; int init; { char *F = "parseKey"; int a = 0; int accs = 0; int c = 0; // Current char in s int c1, c2; // Assorted chars int i, j, k, l; // Assorted ints int ok = 0; int sf = 0; // Sharps or flats for classical key signatures. int tonic = 'C'; // Tonic note int tacc = ' '; // Tonic accidental char w[81]; // Holds one "word" from line char *eksp = 0; // Start of explicit key signature int clef = 0; // Clef code int middle; // Middle note of staff int gotmiddle=0; // True if middle has been set by someone char *mode = "maj"; // Mode if none specified. int octadj; // Adjust note-to-staff mapping for octave. int clfadj; // Adjust note-to-staff mapping for clef. int pitadj; // Sum of octadj and clfadj int root; int racc; int gottonic = 0; // We've parsed a tonic note. int gotmode = 0; // We've parsed a mode string. int gotclef = 0; // We've parsed a clef description. int gotaccs = 0; // We've found one or more accidentals. int half = 0; // Tonic quarter tone accidental mark. V5 "%s: init=%d \"%s\" %s\n",F,init,s,dmpKsig(ks) V; /* * Maybe initialize with key 'none' (which is equivalent to C) */ ks->data.accs = accs = sf = 0; // if (!ks->knum) ks->knum = ++ksignum; // Count the Ksig structs if (init) { V5 "%s: Initialize the key signature.\n",F V; V6 "%s: Init new ksig=%lX to sf=0 clef=TREBLE=%d root=2 racc=0.\n",F,ks,TREBLE V; ks->data.sf = 0; // No sharps or flats ks->data.clef = 0; // Default clef will be treble ks->data.middle = 'B'; // Default middle note will be 'B' ks->data.octadj = 0; // Default octave will have plain notes on staff ks->data.clfadj = 0; // Staff position relative to middle=B ks->data.pitadj = 0; // Total pitch adjustment ks->data.root = 2; // Default tonic is C ks->data.rootAc = 0; // Rood accidentals (???) ks->data.accs = 0; // No accidentals } lastks = ks; clef = ks->data.clef; middle = ks->data.middle; octadj = ks->data.octadj; clfadj = ks->data.clfadj; pitadj = ks->data.pitadj; accs = ks->data.accs; racc = ks->data.rootAc; root = ks->data.root; sf = ks->data.sf; V6 "%s: clef=%d middle='%c' clfadj=%d octadj=%d pitadj=%d accs=%d root=%d racc=%d sf=%d.\n", F,clef,middle,clfadj,octadj,pitadj,accs,root,racc,sf V; /* * check for "treble" "bass" "alto" with or without octave suffix */ if (!nocasecmpn(s+c,"clef=", 5)) { gotclef = 1; // Note we have some sort of clef s += 5; V5 "%s: Ignore \"clef=\"\n",F V; } // For treble/alto/tenor/bass, "clef=" isn't required: if (!nocasecmpn(s+c,"bass", 4)) { gotclef = 1; clfadj = 2; octadj = 0; middle='d'; V6 "%s: Set middle to '%c' (Line %d)\n",F,middle,__LINE__ V; } elsif (!nocasecmpn(s+c,"alto", 4)) { gotclef = 1; clfadj = 1; octadj = 0; middle='c'; V6 "%s: Set middle to '%c' (Line %d)\n",F,middle,__LINE__ V; } elsif (!nocasecmpn(s+c,"treble",6) || !nocasecmpn(s+c,"tenor",5)) { gotclef = 1; clfadj = 0; octadj = 0; middle='B'; V6 "%s: Set middle to '%c' (Line %d)\n",F,middle,__LINE__ V; } elsif (gotclef && !nocasecmpn(s+c,"none",4)) { clfadj = 0; octadj = 0; middle='B'; V6 "%s: Set middle to '%c' (Line %d)\n",F,middle,__LINE__ V; } // if (!strcasecmp(s,"treble")) {clef = TREBLE; clfadj = 0; octadj = 0; gotclef = 1;} // if (!strcasecmp(s,"treble+8")) {clef = TREBLEu8; clfadj = 0; octadj = 0; gotclef = 1;} // if (!strcasecmp(s,"treble-8")) {clef = TREBLEd8; clfadj = 0; octadj = 0; gotclef = 1;} // if (!strcasecmp(s,"bass")) {clef = BASS; clfadj = 2; octadj = 0; gotclef = 1;} // if (!strcasecmp(s,"bass-8")) {clef = BASSd8; clfadj = 2; octadj = 0; gotclef = 1;} // if (!strcasecmp(s,"bass+8")) {clef = BASSu8; clfadj = 2; octadj = 0; gotclef = 1;} // if (!strcasecmp(s,"alto")) {clef = ALTO; clfadj = 1; octadj = 0; gotclef = 1;} // if (!strcasecmp(s,"alto-8")) {clef = ALTOd8; clfadj = 1; octadj = 0; gotclef = 1;} // if (!strcasecmp(s,"alto+8")) {clef = ALTOu8; clfadj = 1; octadj = 0; gotclef = 1;} /* * If we got a clef without a key signature, this is just a clef change. * We must leave the key signature alone. */ if (gotclef) { V6 "%s: Got clef %s, reuse keysig %s\n",F,s,dmpKsig(ks) V; gottonic = gotmode = 1; ks->data.clef = clef; ks->data.clfadj = clfadj; ks->data.octadj = octadj; ks->data.pitadj = clfadj + octadj; V6 "%s: Got clef %s, reuse keysig %s\n",F,s,dmpKsig(ks) V; } else { V4 "%s: Parse the keysig string \"%s\"\n",F,s V; bagpipe = 0; /* * Check for a tonic, which should be a note letter or 'H' for highland pipe keys. */ if (gottonic) { V6 "%s: Tonic %c%c c=%d sf=%d root=%d racc=%d already determined.\n",F,tonic,tacc,c,sf,root,racc V; } else { V6 "%s: Get tonic from \"%s\"\n",F,s+c V; switch (tonic = s[c]) { case 'F': case 'f': sf = -1; root = 5; ++c; gottonic++; break; case 'C': case 'c': sf = 0; root = 2; ++c; gottonic++; break; case 'G': case 'g': sf = 1; root = 6; ++c; gottonic++; break; case 'D': case 'd': sf = 2; root = 3; ++c; gottonic++; break; case 'A': case 'a': sf = 3; root = 0; ++c; gottonic++; break; case 'E': case 'e': sf = 4; root = 4; ++c; gottonic++; break; case 'B': case 'b': sf = 5; root = 1; ++c; gottonic++; break; case 'H': case 'h': bagpipe = 1; c++; if (s[c] == 'P') { sf = 0; root = 2; } elsif (s[c] == 'p') { sf = 2; root = 3; } else wng("unknown bagpipe-like key: ",s); gottonic++; break; default: V3 "%s: Key not recognised: \"%s\"\n",F,s V; sf = 0; root = 2; /* Default to C */ } V3 "%s: Tonic %c%c at c=%d has sf=%d root=%d.\n",F,tonic,tacc,c,sf,root V; /* * Check for an accidental after the tonic, either # or b. */ // racc = A_NT; /*Check for quarter tone*/ half = 0; if (s[c] == '/') { half = 1; c += 1; } if (s[c] == '#') { tacc = '#'; sf += 7; c += 1; racc = (half ? A_HSH : A_SH); V6 "%s: racc=A_%sSH=%d\n",F,(half?"S":""),racc V; } elsif (s[c] == 'b') { tacc = 'b'; sf -= 7; c += 1; racc = (half ? A_HFT : A_FT); V6 "%s: racc=A_%sFT=%d\n",F,(half?"S":""),racc V; } V6 "%s: Tonic %c%c at c=%d has sf=%d root=%d racc=%d.\n",F,tonic,tacc,c,sf,root,racc V; } } V6 "%s: Keysig %s\n",F,dmpKsig(ks) V; if (gottonic && sf) { V6 "%s: Got tonic %c%c with sf=%d.\n",F,'A'+root,tacc,sf V; // ks->data.accs = 0; // ks->data.accs = accs = sf = 0; } // if (sf != 0) { // V3 "%s: Add %d accidentals to key signature.\n",F,sf V; // addMode(ks,sf); // ks->data.root = root; // ks->data.rootAc = racc; // } V6 "%s: Keysig %s\n",F,dmpKsig(ks) V; /* * Loop over blank-delimited words: get the next token. The first token after * the tonic may be a mode or a list of accidentals. Note that we fill w[] * with the word, but we can still find the origin at s[c-j]. */ V6 "%s: parse \"%s\" ...\n",F,s+c V; for (;;) { V6 "%s: Parse \"%s\"\n",F,s+c V; while (isspace(s[c])) c++; // Skip over spaces if (s[c] == '%') break; // Stop at comment if (s[c] == '\0') break; // Stop at end of line V5 "%s: Next: \"%s\"\n",F,s+c V; j = 0; // Offset to current char in w[] while (!(isspace(s[c]) || (s[c]=='\0'))) { w[j++] = s[c++]; // Copy to w[] } w[j] = '\0'; // w[] is the next word V6 "%s: Word: \"%s\"\n",F,w V; if (!gotmode) { V6 "%s: Check for mode.\n",F V; if (w[0] == '*') { // Kludge to fake a missing mode V6 "%s: Explicit key signature \"%s\"\n",F,w V; sf = 0; // mode = ""; // ks->data.accs = accs = sf = 0; eksp = w; // Note start of check for explicit keysig continue; } elsif ((w[0] == '^') || (w[0] == '=') || (w[0] == '_')) { V6 "%s: Explicit key signature \"%s\"\n",F,w V; sf = 0; // mode = ""; // ks->data.accs = accs = sf = 0; eksp = w; // Start of explicit keysig V6 "%s: Explicit key signature \"%s\"\n",F,eksp V; } elsif (!nocasecmpn(w,"exp",3) || !nocasecmpn(w,"oct",3)) { V6 "%s: Explicit key signature \"%s\"\n",F,w V; sf = 0; eksp = w+3; // Start of explicit keysig V6 "%s: Explicit key signature \"%s\"\n",F,w V; } elsif ((nocasecmpn(w,"mix",3)) == 0) { sf -= 1; ok = gotmode = 1; eksp = w+3; /* dorian mode on the second note (D in C scale) */ } elsif ((nocasecmpn(w,"dor",3)) == 0) { sf -= 2; ok = gotmode = 1; eksp = w+3; /* phrygian mode on the third note (E in C scale) */ } elsif ((nocasecmpn(w,"phr",3)) == 0) { sf -= 4; ok = gotmode = 1; eksp = w+3; /* lydian mode on the fourth note (F in C scale) */ } elsif ((nocasecmpn(w,"lyd",3)) == 0) { sf += 1; ok = gotmode = 1; eksp = w+3; /* locrian mode on the seventh note (B in C scale) */ } elsif ((nocasecmpn(w,"loc",3)) == 0) { sf -= 5; ok = gotmode = 1; eksp = w+3; /* major and ionian are the same ks */ } elsif ((nocasecmpn(w,"maj",3)) == 0) { ok = gotmode = 1; eksp = w+3; } elsif ((nocasecmpn(w,"ion",3)) == 0) { ok = gotmode = 1; eksp = w+3; /* aeolian, m, minor are the same ks - sixth note (A in C scale) */ } elsif ((nocasecmpn(w,"aeo",3)) == 0) { sf -= 3; ok = gotmode = 1; eksp = w+3; } elsif ((nocasecmpn(w,"min",3)) == 0) { sf -= 3; ok = gotmode = 1; eksp = w+3; } elsif ((nocasecmpn(w,"m",1)) == 0) { sf -= 3; ok = gotmode = 1; eksp = w+1; } } V5 "%s: Check \"%s\" for \"middle=\" (middle='%c')\n",F,w,middle V; if (!(i = nocasecmpn(w,"m=",k=2)) || !(i = nocasecmpn(w,"middle=",k=7))) { V5 "%s: Recognized 'middle='\n",F V; ++gotmiddle; if ((c1 = w[k]) && (within('A',c1,'G') || within('a',c1,'g'))) { V5 "%s: Found note '%c' middle was '%c'\n",F,c1,middle V; ++k; clfadj = middleadj(middle = c1); V5 "%s: octadj=%d clfadj=%d pitadj=%d after '%c' note.\n",F,octadj,clfadj,pitadj,c1 V; while ((c2 = w[k]) && ((c2 == ',') || ( c2 == '\''))) { if (c2 == ',') octadj += 7; if (c2 == '\'') octadj -= 7; V5 "%s: octadj=%d clfadj=%d pitadj=%d after '%c' octave.\n",F,octadj,clfadj,pitadj,c2 V; ++k; } } else { V1 "%s: Unrecognized note '%c' in \"%s\"\n",F,c1,w V; } continue; } V5 "%s: Check \"%s\" for clef= ...\n",F,w V; k = 0; // Offset into w[] for tests if (!nocasecmpn(w,"clef=",5)) { gotclef = 1; k = 5; octadj = clfadj = pitadj = 0; V5 "%s: Ignore %d chars of \"%s\"\n",F,k,w V; } V6 "%s: Check \"%s\" for clef name (middle='%c')\n",F,w+k,middle V; if (!nocasecmpn(w+k,"bass",4)) {k += 4; middle = 'd'; octadj = 0; clef = BASS; clfadj = 2; } elsif (!nocasecmpn(w+k,"alto",4)) {k += 4; middle = 'c'; octadj = 0; clef = ALTO; clfadj = 1; } elsif (!nocasecmpn(w+k,"treble",6)) {k += 6; middle = 'B'; octadj = 0; clef = TREBLE; } elsif (!nocasecmpn(w+k,"tenor",6)) {k += 6; middle = 'B'; octadj = 0; clef = TENOR; } elsif (!nocasecmpn(w+k,"F",1)) {k += 1; middle = 'd'; octadj = 0; clef = BASS; clfadj = 2; } elsif (!nocasecmpn(w+k,"G",1)) {k += 1; middle = 'B'; octadj = 0; clef = TREBLE; } elsif (!nocasecmpn(w+k,"C",1)) {k += 1; middle = 'c'; octadj = 0; clef = ALTO; clfadj = 1; } elsif (!nocasecmpn(w+k,"none",4)) { if (gotclef) {k += 4; middle = 'B'; octadj = clfadj = 0; clef = NOCLEF;} } else { V5 "%s: No clef in key specifier: \"%s\"\n",F,w+k V; } V5 "%s: k=%d clef=%d middle='%c' clfadj=%d octadj=%d after clef check.\n",F,k,clef,middle,clfadj,octadj V; /* check for "+8" or "-8" */ if (!nocasecmpn(w+k,"-8",2)) {k += 2; clef += 1; // clfadj = -7; } elsif (!nocasecmpn(w+k,"+8",2)) {k += 2; clef += 2; // clfadj = 7; } else { V6 "%s: No octave in key specifier: \"%s\"\n",F,w+k V; } V5 "%s: Got k=%d root=%d sf=%d clef=%d clfadj=%d octadj=%d pitadj=%d.\n", F,k,root,sf,clef,clfadj,octadj,pitadj V; ks->data.clef = clef; if (sf) { accs = fillKsig(ks,sf); V6 "%s: Ksig=%lX has sf=%d accs=%d.\n",F,ks,sf,ks->data.accs V; } if (eksp) { V6 "%s: Keysig check at \"%s\"\n",F,eksp V; if (a = parseKsig(ks,eksp)) { gotaccs += a; V6 "%s: Keysig now has %d accidentals.\n",F,a V; if (a > accs) { V6 "%s: Keysig changed from %d to %d accidentals.\n",F,accs,a V; sf = a; /* Explicit list always has positive count */ } else { V6 "%s: Keysig left at sf=%d.\n",F,sf V; } } else { V6 "%s: No explicit keysig.\n",F V; } } } /* end of loop over blank-delimted words */ V3 "%s: Done with parse; gottonic=%d gotmode=%d gotaccs=%d sf=%d accs=%d clfadj=%d octadj=%d.\n", F,gottonic,gotmode,gotaccs,sf,accs,clfadj,octadj V; if (!gotmiddle) { V6 "%s: Middle note '%c' not parsed.\n",F,middle V; if (middle && within('A',middle,'G') || within('a',middle,'g')) { V5 "%s: Found note '%c'\n",F,middle V; ++k; clfadj = middleadj(middle); V5 "%s: octadj=%d clfadj=%d after '%c' note.\n",F,octadj,clfadj,middle V; } else { V1 "%s: Unrecognized note '%c' in \"%s\"\n",F,middle,w V; } } if (!clfadj) { V6 "%s: Get clef offset clfadj=%d for middle='%c'...\n",F,clfadj V; clfadj = middleadj(middle); } V6 "%s: Got clef offset clfadj=%d for middle='%c'\n",F,clfadj,middle V; if (!gotmode && !gotaccs) { V3 "%s: Default key is %c%c major.\n",F,tonic,tacc V; ks->data.accs = 0; if (sf != 0) { V3 "%s: Add %d accidentals to key signature.\n",F,sf V; addMode(ks,sf); } } /* copy to struct */ ks->data.sf = 0; ks->data.clef = clef; ks->data.middle = middle; ks->data.octadj = octadj; ks->data.clfadj = clfadj; ks->data.pitadj = clfadj + octadj; // Total "pitch" adjustment to position notes correctly ks->data.root = root; ks->data.rootAc = racc; V6 "%s: Ksig has sf=%d, %d accidentals, root=%d rootAc=%d clfadj=%d octadj=%d pitadj=%d.\n", F,ks->data.sf,ks->data.accs,ks->data.root,ks->data.rootAc, ks->data.clfadj,ks->data.octadj,ks->data.pitadj V; for (i = 1; idata.accs; i++) { if (ks->data.atyp[i] != ks->data.atyp[i-1]) { ks->data.clef = A_MX; V3 "%s: This keysig has mixed accidentals.\n",F V; break; } } V6 "%s: %s done.\n",F,dmpKsig(ks) V; return 1; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Calculate the adjustment for a specified "middle=" note. * This is in "pitch" units. */ int middleadj(char note) { char *F = "middleadj"; int off = 0; switch (note) { case 'C': off = 6; break; case 'D': off = 5; break; case 'E': off = 4; break; case 'F': off = 3; break; case 'G': off = 2; break; case 'A': off = 1; break; case 'B': off = 0; break; // Default treble note-staff map. case 'c': off = -1; break; case 'd': off = -2; break; case 'e': off = -3; break; case 'f': off = -4; break; case 'g': off = -5; break; case 'a': off = -6; break; case 'b': off = -7; break; default: V1 "%s: Char '%c' is not a note.\n",F,note V; } V6 "%s: Note '%c' is %d.\n",F,note,off V; return off; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ int addMode( Ksig *ks, // Ksig struct int sf, // Sharps or flats int cl) // Clef type { char *F = "addMode"; int a, n; n = ks->data.accs; V6 "%s: Add %d accidentals to %d in key signature.\n",F,sf,n V; if (sf < 0) { V6 "%s: Add %d flats.\n",F,sf V; for (a=0; a<-sf; a++) { ks->data.atyp[n] = A_FT; ks->data.aval[n] = fl_val[a]; ks->data.apos[n] = note_pos(fl_val[a],cl); V6 "%s: Add flat %d val='%c' pos=%d.\n",F,n,ks->data.aval[n],ks->data.apos[n] V; n++; } } elsif (sf > 0) { V6 "%s: Add %d sharps.\n",F,sf V; for (a=0; adata.atyp[n] = A_SH; ks->data.aval[n] = sh_val[a]; ks->data.apos[n] = note_pos(sh_val[a],cl); V6 "%s: Add sharp %d val='%c' pos=%d.\n",F,n,ks->data.aval[n],ks->data.apos[n] V; n++; } } else { V6 "%s: No accidentals to add (sf=%d)\n",F,sf V; } V6 "%s: There are now %d accidentals in the key signature.\n",F,n V; ks->data.accs = n; return n; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This calculates the note position on the staff from the note name. The scale * used has the bottom line at 0 and 6 units per line. */ int note_pos( char note, int clef) { char *F = "note_pos"; int offset = 0; int val; V6 "%s: offset=%d.\n",F,offset V; switch (note) { case 'E': val = 0; break; case 'F': val = 3; break; case 'G': val = 6; break; case 'A': val = 9; break; case 'B': val = 12; break; case 'c': val = 15; break; case 'd': val = 18; break; case 'e': val = 21; break; case 'f': val = 24; break; case 'g': val = 27; break; default: val = -3; break; } V6 "%s: offset=%d val=%d return %d.\n",F,offset,val,val+offset V; return (val+offset); } /* ------- parseKsig: Parse explicit key signatures and add to keysig ------- * This handles an explicit keysig (a list of notes with accidentals), and * fills in ks->data with the results. Added by jc 2000-06. */ int parseKsig( Ksig *ks, // Key signature struct char *s, // Original copy of current word, not terminated int clef) // Clef type { char *F = "parseKsig"; char c, d; /* Chars being examined */ int a = ks->data.accs; /* Accidental counter */ int half; V6 "%s: Called for s=\"%s\"\n",F,s V; while ((c = *s) && ((c == '*') || isspace(c) || isalpha(c))) { V6 "%s: Skip '%c'\n",F,c V; ++s; } if (!c) { V3 "%s: No extra stuff on keysig.\n",F V; return a; } V6 "%s: Keysig \"%s\"\n",F,s V; c = d = 0; while (c = *s) { V6 "%s: Parse \"%s\"\n",F,s V; while ((c = *s) && isspace(c)) ++s; V6 "%s: '%c' ...\n",F,c V; switch (c) { case '^': case '=': case '_': if (half = (s[1] == '/')) s++; /*look for half sharp/flat*/ if ((d = s[1]) && (('A' <= d && d <= 'G') || ('a' <= d && d <= 'g'))) { V6 "%s: Accidental '%c' note '%c'.\n",F,c,d V; ks->data.atyp[a] = (c == '^') ? (half ? A_HSH : A_SH) : (c == '_' ) ? (half ? A_HFT : A_FT) : A_NT; ks->data.aval[a] = d; ks->data.apos[a] = note_pos(d,clef); V6 "%s: ks[%d] '%c%c' atyp=%d apos=%d.\n",F, a,c,ks->data.aval[a],ks->data.atyp[a],ks->data.apos[a] V; a++; s += 2; } elsif (d) { V1 "%s: %02X='%c' followed by invalid char %02X='%c'\n",F,c,c,d,d V; ++s; } else { V1 "%s: %02X='%c' followed by funny char '%02X'\n",F,c,c,d V; ++s; } continue; default: V4 "%s: %02X='%c' ends tonic+mode portion of keysig.\n",F,c,c V; c = d = 0; break; } if (c == 0) break; } if (c) { V6 "%s: '%c' terminates explicit keysig at \"%s\".\n",F,c,s V; } ks->data.accs = a; V3 "%s: There are %d accidentals in this key signature; \"%s\" left.\n",F,ks->data.accs,s V; if ((c = *s) && (d = tolower(c)) && ('a' <= d) && (d <= 'g')) { V3 "%s: Tonic note '%c'.\n",F,c V; ks->data.root = (d - 'a'); if ((c = *++s) && (d = tolower(c)) && (d == 'b' || d == '#')) { V3 "%s: Tonic note '%c%c' .\n",F,c V; ks->data.rootAc = (d == '#') ? A_SH : A_FT; if(s[1] == '/') { ks->data.rootAc = (d == '#') ? A_HSH : A_HFT; ++s; } ++s; } } elsif (*s) { V3 "%s: Can't parse remainder of keysig \"%s\"\n",F,s V; } while ((c = *s) && isspace(c)) ++s; /* Skip spaces looking for mode */ if (c = *s) { if (isalpha(c)) { strncpy(ks->data.mode,s,15); V3 "%s: Mode \"%s\"\n",F,ks->data.mode V; } elsif (*s) { V3 "%s: No mode in remainder of keysig \"%s\"\n",F,s V; } } if (c = *s) { V3 "%s: Tail of keysig \"%s\" unused.\n",F,s V; } return a; } /* ----- get_halftones: figure out how by many halftones to transpose --- */ /* In the transposing routines: pitches A..G are coded as with 0..7 */ int get_halftones (key, transpose) Ksig key; char transpose[]; { int pit_old,pit_new,direction,stype,root_new,racc_new,nht; int root_old, racc_old; char *q; /* pit_tab associates true pitches 0-11 with letters A-G */ int pit_tab[] = {0,2,3,5,7,8,10}; if (strlen(transpose) == 0) return 0; root_old = key.data.root; racc_old = key.data.rootAc; /* parse specification for target key */ q = transpose; direction = 0; if (*q == '^') { direction = 1; q++; } elsif (*q == '_') { direction = -1; q++; } stype = 1; if (strchr("ABCDEFG",*q)) { root_new = *q-'A'; q++; stype = 2; } elsif (strchr("abcdefg",*q)) { root_new = *q-'a'; q++; stype = 2; } /* first case: offset was given directly as numeric argument */ if (stype == 1) { sscanf(q,"%d", &nht); if (direction<0) nht = -nht; if (nht == 0) { if (direction<0) nht = -12; if (direction>0) nht = +12; } return nht; } /* second case: root of target key was specified explicitly */ racc_new = 0; if (*q == 'b') { racc_new = A_FT; q++; if(*q == '/') { racc_new = A_HFT; q++;} } elsif (*q == '#') { racc_new = A_SH; q++; if(*q == '/') { racc_new = A_HSH; q++;} } elsif (*q != '\0') wng ("expecting accidental in transpose spec: ", transpose); /* get pitch as number from 0-11 for root of old key */ pit_old = pit_tab[root_old]; if (racc_old == A_FT) pit_old--; if (racc_old == A_SH) pit_old++; /*todo: if (racc_old == A_HFT) pit_old -= 0.5; if (racc_old == A_HSH) pit_old += 0.5; */ if (pit_old<0) pit_old += 12; if (pit_old>11) pit_old -= 12; /* get pitch as number from 0-11 for root of new key */ pit_new = pit_tab[root_new]; if (racc_new == A_FT) pit_new--; if (racc_new == A_SH) pit_new++; /*todo: if (racc_new == A_HFT) pit_new-=0.5; if (racc_new == A_HSH) pit_new+=0.5; */ if (pit_new<0) pit_new += 12; if (pit_new>11) pit_new -= 12; /* number of halftones is difference */ nht = pit_new-pit_old; if (direction == 0) { if (nht>6) nht -= 12; if (nht<-5) nht += 12; } if (direction>0 && nht <= 0) nht += 12; if (direction<0 && nht >= 0) nht -= 12; return nht; } /* ----- shift_key: make new key by shifting nht halftones --- */ void shift_key (sf_old,nht,sfnew,addt) int sf_old,nht,*sfnew,*addt; { int sf_new,r_old,r_new,add_t, dh,dr; int skey_tab[] = {2,6,3,0,4,1,5,2}; int fkey_tab[] = {2,5,1,4,0,3,6,2}; char root_tab[] = {'A','B','C','D','E','F','G'}; /* get sf_new by adding 7 for each halftone, then reduce mod 12 */ sf_new = sf_old+nht*7; sf_new = (sf_new+240)%12; if (sf_new >= 6) sf_new = sf_new-12; /* get old and new root in ionian mode, shift is difference */ r_old = 2; if (sf_old>0) r_old = skey_tab[sf_old]; if (sf_old<0) r_old = fkey_tab[-sf_old]; r_new = 2; if (sf_new>0) r_new = skey_tab[sf_new]; if (sf_new<0) r_new = fkey_tab[-sf_new]; add_t = r_new-r_old; /* fix up add_t to get same "decade" as nht */ dh = (nht+120)/12; dh = dh-10; dr = (add_t+70)/7; dr = dr-10; add_t = add_t+7*(dh-dr); V3 "shift_key: sf_old = %d new %d root: old %c new %c shift by %d\n", sf_old, sf_new, root_tab[r_old], root_tab[r_new], add_t V; *sfnew = sf_new; *addt = add_t; } /* * tables for pretty printout only */ char root_tab[] = {'A','B','C','D','E','F','G'}; char acc_tab[][3] ={"bb","b "," ","# ","x "}; /* ----- set_transtab: setup for transposition by nht halftones --- */ void set_transtab (nht,key) int nht; Ksig *key; { char *F = "set_transtab"; int a,b,sf_old,sf_new,add_t,i,j,acc_old,acc_new,root_old,rootAc; char c1[6],c2[6],c3[6]; /* nop if no transposition is wanted */ if (nht == 0) { key->data.add_transp = 0; for (i = 0;i<7;i++) key->data.add_acc[i] = 0; return; } /* get new sharps_flats and shift of numeric pitch; copy to key */ sf_old = key->data.sf; root_old = key->data.root; rootAc = key->data.rootAc; shift_key (sf_old, nht, &sf_new, &add_t); key->data.sf = sf_new; key->data.add_transp = add_t; /* set up table for conversion of accidentals */ for (i = 0;i<7;i++) { j = i+add_t; j = (j+70)%7; acc_old = 0; if ( sf_old >= sh_tab[i]) acc_old = 1; if (-sf_old >= fl_tab[i]) acc_old = -1; acc_new = 0; if ( sf_new >= sh_tab[j]) acc_new = 1; if (-sf_new >= fl_tab[j]) acc_new = -1; key->data.add_acc[i] = acc_new-acc_old; } /* printout keysig change */ if (verbose >= 3) { i = root_old; j = i+add_t; j = (j+70)%7; acc_old = 0; if ( sf_old >= sh_tab[i]) acc_old = 1; if (-sf_old >= fl_tab[i]) acc_old = -1; acc_new = 0; if ( sf_new >= sh_tab[j]) acc_new = 1; if (-sf_new >= fl_tab[j]) acc_new = -1; strcpy(c3,"s"); if (nht == 1 || nht == -1) strcpy(c3,""); strcpy(c1,""); strcpy(c2,""); if (acc_old == -1) strcpy(c1,"b"); if (acc_old == 1) strcpy(c1,"#"); if (acc_new == -1) strcpy(c2,"b"); if (acc_new == 1) strcpy(c2,"#"); fprintf(stderr,"Transpose root from %c%s to %c%s (shift by %d halftone%s)\n", root_tab[i],c1,root_tab[j],c2,nht,c3); } /* printout full table of transformations */ if (verbose >= 4) { fprintf(stderr,"old & new keysig conversions\n"); for (i = 0;i<7;i++) { j = i+add_t; j = (j+70)%7; acc_old = 0; if ( sf_old >= sh_tab[i]) acc_old = 1; if (-sf_old >= fl_tab[i]) acc_old = -1; acc_new = 0; if ( sf_new >= sh_tab[j]) acc_new = 1; if (-sf_new >= fl_tab[j]) acc_new = -1; fprintf(stderr,"%c%s-> %c%s ", root_tab[i],acc_tab[acc_old+2], root_tab[j],acc_tab[acc_new+2]); for (a = -1;a <= 1;a++) { b = a+key->data.add_acc[i]; fprintf(stderr,"%c%s-> %c%s ",root_tab[i],acc_tab[a+2],root_tab[j],acc_tab[b+2]); } fprintf(stderr,"\n"); } } } /* ----- do_transpose: transpose numeric pitch and accidental --- */ void do_transpose ( Ksig *key, int *pitch, int *acc) { char *F="do_transpose"; int pitch_old,pitch_new,sf_old,sf_new,acc_old,acc_new,i,j; V6 "%s: Ksig %s\n",F,dmpKsig(key) V; pitch_old = *pitch; acc_old = *acc; pitch_new = pitch_old + key->data.pitadj; // No tranpose for now [jc] + key->data.add_transp; i = (pitch_old+70)%7; j = (pitch_new+70)%7; V6 "%s: Pitch old=%d new=%d.\n",F,pitch_old,pitch_new V; if (acc_old) { if (acc_old == A_DF) sf_old = -2; /*todo: if (acc_old == A_HFT) sf_old = -0.5;*/ if (acc_old == A_FT) sf_old = -1; if (acc_old == A_NT) sf_old = 0 ; /*todo: if (acc_old == A_HSH) sf_old = 0.5; */ if (acc_old == A_SH) sf_old = 1; if (acc_old == A_DS) sf_old = 2; sf_new = sf_old+key->data.add_acc[i]; if (sf_new == -2) acc_new = A_DF; if (sf_new == -1) acc_new = A_FT; /*todo: if (sf_new == -0.5) acc_new = A_HFT; */ if (sf_new == 0) acc_new = A_NT; /*todo: if (sf_new == 0.5) acc_new = A_HSH;*/ if (sf_new == 2) acc_new = A_DS; } else { acc_new = 0; } *pitch = pitch_new; *acc = acc_new; } /* ----- ach_transpose: transpose accomp chord string in ach --- */ void ach_transpose ( Ksig *key) { char *q,*r; char str[201]; int root_old,root_new,sf_old,sf_new,ok; char root_tab[] = {'A','B','C','D','E','F','G'}; char root_tub[] = {'a','b','c','d','e','f','g'}; if (halftones == 0) return; /* try to avoid some common abuses of achord string */ if (strstr(ach,"capo")) return; if (strstr(ach,"Capo")) return; if (strstr(ach,"Fine")) return; if (strstr(ach,"fine")) return; q = ach; r = str; for (;;) { while (*q == ' ' || *q == '(') { *r = *q; q++; r++; } if (*q == '\0') break; ok = 0; if (strchr("ABCDEFG",*q)) { root_old = *q-'A'; q++; ok = 1; } elsif (strchr("abcdefg",*q)) { root_old = *q-'a'; q++; ok = 2; } if (ok) { sf_old = 0; if (*q == 'b') { sf_old = -1; q++; } if (*q == '#') { sf_old= 1; q++; } root_new = root_old + key->data.add_transp; root_new = (root_new+28)%7; sf_new = sf_old + key->data.add_acc[root_old]; if (ok == 1) { *r = root_tab[root_new]; r++; } if (ok == 2) { *r = root_tub[root_new]; r++; } if (sf_new == -1) { *r = 'b'; r++; } if (sf_new == 1) { *r = '#'; r++; } } while (*q != ' ' && *q != '/' && *q != '\0') {*r = *q; q++; r++; } if (*q == '/') {*r = *q; q++; r++; } } *r = '\0'; /*| fprintf(stderr,"tr_ch: <%s> <%s>\n", ach, str); |*/ strcpy (ach,str); } /* ----- init_parse_params: initialize variables for parsing --- */ void init_parse_params () { char *F = "init_parse_params"; int i; slur = 0; voice[0].end_slur = 0; voice[0].rem_slur = 0; // Added by jc to stop remembering slurs from previous tune nwpool = nwline = 0; ntinext = 0; /* for continuation after output: reset nsym, switch to first voice */ for (i = 0;i= NTEXT) { wng ("No more room for text line <%s>", str); return; } strcpy (text[ntext], str); text_type[ntext] = type; ntext++; } /* ----- reset_info ---- */ void reset_info (inf) Info *inf; { /* reset all info fields except info.xref */ strcpy(inf->parts, ""); strcpy(inf->area, ""); inf->nbook = 0; inf->ncomp = 0; strcpy(inf->disc, ""); strcpy(inf->group, ""); strcpy(inf->hist, ""); strcpy(inf->info, ""); strcpy(inf->key, "C"); strcpy(inf->meter, "4/4"); strcpy(inf->notes, ""); strcpy(inf->orig, ""); strcpy(inf->rhyth, ""); strcpy(inf->src, ""); /* strcpy(inf->title, "(untitled)"); */ strcpy(inf->title, ""); strcpy(inf->title2, ""); strcpy(inf->title3, ""); strcpy(inf->title4, ""); strcpy(inf->title5, ""); strcpy(inf->title6, ""); strcpy(inf->trans, ""); strcpy(inf->tempo, ""); } /* ----- get_default_info: set info to default, except xref field --- */ void get_default_info () { char savestr[STRL]; strcpy (savestr, info.xref); info = default_info; strcpy (info.xref, savestr); } /* ----- is_info_field: identify any type of info field ---- */ int is_info_field(str) char str[]; { if (strlen(str)<2) return 0; if (str[1] != ':') return 0; if (str[0] == '|') return 0; /* |: at start of music line */ return 1; } /* ----- is_end_line: identify eof ----- */ int is_end_line (str) char str[]; { if (strlen(str)<3) return 0; if (str[0] == 'E' && str[1] == 'N' && str[2] == 'D') return 1; return 0; } /* ----- is_pseudocomment ----- */ int is_pseudocomment (str) char str[]; { if (strlen(str)<2) return 0; if ((str[0] == '%')&&(str[1] == '%')) return 1; return 0; } /* ----- is_comment ----- */ int is_comment (str) char str[]; { if (strlen(str)<1) return 0; if (str[0] == '%') return 1; if (str[0] == '\\') return 1; return 0; } /* ----- trim_title: move trailing "The" to front ------------ */ void trim_title (s,s0) char s[],s0[]; { char *q; char rest[81],str[301]; int done; strcpy (str, s0); done = 0; if ((q = strchr(str,','))) { if (*q != '\0') { strip(rest,q+1); if (!strcmp(rest,"The")) { strcpy (s, rest); *q = '\0'; strcat (s, " "); strcat (s, str); done = 1; } } } if (!done) strcpy (s,s0); } Ksig* asgnKsig( Ksig *dstkey, Ksig *srckey) { return copyKsig(srckey,dstkey); } Ksig* copyKsig( Ksig *srckey, Ksig *dstkey) { char *F = "copyKsig"; int a; if (!dstkey) {dstkey = newKsig(F);} // if (!srckey->knum) srckey->knum = ++ksignum; // if (!dstkey->knum) dstkey->knum = ++ksignum; dstkey->data.clef = srckey->data.clef; dstkey->data.sf = srckey->data.sf; dstkey->data.middle = srckey->data.middle; dstkey->data.octadj = srckey->data.octadj; dstkey->data.clfadj = srckey->data.clfadj; dstkey->data.pitadj = srckey->data.pitadj; dstkey->data.root = srckey->data.root; dstkey->data.rootAc = srckey->data.rootAc; dstkey->data.accs = srckey->data.accs; for (a=0; adata.accs; a++) { dstkey->data.atyp[a] = srckey->data.atyp[a]; dstkey->data.aval[a] = srckey->data.aval[a]; dstkey->data.apos[a] = srckey->data.apos[a]; } strcpy(dstkey->data.mode, srckey->data.mode); V3 "%s: <- %s\n",F,dmpKsig(srckey) V; V3 "%s: -> %s\n",F,dmpKsig(dstkey) V; return dstkey; } /* ----- find_voice ----- */ int find_voice(vid,new) char vid[]; int *new; { char *F = "find_voice"; int v; Ksig *ks = 0; for (v = 0; v < nvoice; v++) { V6 "%s: Is voice v=%d new?\n",F,v V; if (!strcmp(vid,voice[v].id)) { V6 "%s: Old voice v=%d.\n",F,v V; *new = 0; return v; } } v = nvoice; V6 "%s: New voice v=%d.\n",F,v V; if (v >= maxVc) rxi("Too many voices; use -maxv to increase limit, now ",maxVc); strcpy(voice[v].id, vid); strcpy(voice[v].name, ""); strcpy(voice[v].sname, ""); voice[v].stems = 0; voice[v].staves = 0; voice[v].brace = 0; voice[v].bracket = 0; voice[v].do_ach = 1; voice[v].select = 1; voice[v].sep = 0.0; voice[v].meter = default_meter; voice[v].nsym = 0; V3 "%s: Voice %d use default_key is %s\n",F,v,dmpKsig(&default_key) V; voice[v].key = asgnKsig(voice[v].key,&default_key); lastks = ks = voice[v].key; V3 "%s: Voice[%d].key is %s from default_key.\n",F,v,dmpKsig(ks) V; nvoice++; *new = 1; V3 "%s: Made new voice v=%d with id \"%s\"\n",F, v,voice[v].id V; return v; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * switch_voice: read spec for a voice, return voice number */ int switch_voice (str) char str[]; { char *F = "switch_voice"; int j, np, new, octadj=0, clfadj=0; int middle='B'; int options=0; char c, *e, *r, *q; char *t0, t1[201], t2[201]; char *t1z = t1+200; // Last byte of t1 [jc] char *t2z = t2+200; // Last byte of t2 [jc] V5 "%s: \"%s\"\n",F,str V; if (!do_this_tune) return 0; j = -1; /* start loop over vioce options: parse t1 = t2 */ r = str; np = 0; for (;;) { while (isspace(*r)) r++; V5 "%s: Parse \"%s\"\n",F,r V; if (*r == '\0') break; t0 = r; strcpy(t1,""); strcpy(t2,""); q = t1; while (*r != ' ' && *r != '\0' && *r != '=' && q < t1z) { *q = *r; r++; q++; } *q = '\0'; V5 "%s: t1=\"%s\"\n",F,t1 V; if (*r == '=') { r++; q = t2; if (*r == '"') { r++; while (*r != '"' && *r != '\0' && q < t2z) { *q = *r; r++; q++; } if (*r == '"') r++; } else { while (*r != ' ' && *r != '\0' && q < t2z) { *q = *r; r++; q++; } } *q = '\0'; } np++; V5 "%s: t2=\"%s\" np=%d.\n",F,t2,np V; /* * interpret the parsed option. First case is identifier. */ if (np == 1) { j = find_voice(t1,&new); lastks = voice[j].key; } else { /* interpret option */ ++options; V6 "%s: Option t1=\"%s\" t2=\"%s\"\n",F,t1,t2 V; if (j<0) bug("j invalid in switch_voice",1); lastks = voice[j].key; if (!strcmp(t1,"name") || !strcmp(t1,"nm")) {strcpy(voice[j].name, t2); } elsif (!strcmp(t1,"sname") || !strcmp(t1,"snm")) {strcpy(voice[j].sname, t2); } elsif (!strcmp(t1,"staves") || !strcmp(t1,"stv")) {voice[j].staves = atoi(t2); } elsif (!strcmp(t1,"brace") || !strcmp(t1,"brc")) {voice[j].brace = atoi(t2); } elsif (!strcmp(t1,"bracket") || !strcmp(t1,"brk")) {voice[j].bracket = atoi(t2); } elsif (!strcmp(t1,"achords") || !strcmp(t1,"ach")) {g_logv (str,t2,&voice[j].do_ach); // New term } elsif (!strcmp(t1,"gchords") || !strcmp(t1,"gch")) {g_logv (str,t2,&voice[j].do_ach); // Deprecated } elsif (!strcmp(t1,"annotation") || !strcmp(t1,"ann")) {g_logv (str,t2,&voice[j].do_ach); /* * for sspace: add 2000 as flag if not incremental */ } elsif (!strcmp(t1,"space") || !strcmp(t1,"spc")) { g_unum (str,t2,&voice[j].sep); if (t2[0] != '+' && t2[0] != '-') voice[j].sep += 2000.0; } elsif (!strcmp(t1,"clef") || !strcmp(t1,"cl")) { octadj = clfadj = 0; V6 "%s: t2=\"%s\"\n",F,t2 V; e = t2 + strlen(t2) - 1; // Check for commas or apostrophes while ((c = *e) && (c == ',' || c == '\'')) { if (c == ',') octadj += 7; else if (c == '\'') octadj -= 7; *e-- = 0; } V6 "%s: clfadj=%d octadj=%d '%c'\n",F,clfadj,octadj,c V; if (!strcmp(t2,"bass")) {lastks->data.clef = BASS; clfadj = -2; middle = 'd';} elsif (!strcmp(t2,"bass+8")) {lastks->data.clef = BASSu8; clfadj = -2; middle = 'd';} elsif (!strcmp(t2,"bass-8")) {lastks->data.clef = BASSd8; clfadj = -2; middle = 'd';} elsif (!strcmp(t2,"bass+16")) {lastks->data.clef = BASS; clfadj = -2; middle = 'd';} elsif (!strcmp(t2,"bass-16")) {lastks->data.clef = BASS; clfadj = -2; middle = 'd';} elsif (!strcmp(t2,"alto")) {lastks->data.clef = ALTO; clfadj = -1; middle = 'c';} elsif (!strcmp(t2,"alto+8")) {lastks->data.clef = ALTOu8; clfadj = -1; middle = 'c';} elsif (!strcmp(t2,"alto-8")) {lastks->data.clef = ALTOd8; clfadj = -1; middle = 'c';} elsif (!strcmp(t2,"alto+16")) {lastks->data.clef = ALTO; clfadj = -1; middle = 'c';} elsif (!strcmp(t2,"alto-16")) {lastks->data.clef = ALTO; clfadj = -1; middle = 'c';} elsif (!strcmp(t2,"none")) {lastks->data.clef = NOCLEF; clfadj = 0;} elsif (!strcmp(t2,"treble")) {lastks->data.clef = TREBLE; clfadj = 0; middle = 'B';} elsif (!strcmp(t2,"treble+8")) {lastks->data.clef = TREBLEu8; clfadj = 0; middle = 'B';} elsif (!strcmp(t2,"treble-8")) {lastks->data.clef = TREBLEd8; clfadj = 0; middle = 'B';} elsif (!strcmp(t2,"treble+16")) {lastks->data.clef = TREBLE; clfadj = 0; middle = 'B';} elsif (!strcmp(t2,"treble-16")) {lastks->data.clef = TREBLE; clfadj = 0; middle = 'B';} elsif (!strcmp(t2,"tenor")) {lastks->data.clef = TENOR; clfadj = 0; middle = 'B';} else wng("Unknown clef in voice spec: ",t2); V6 "%s: clfadj=%d octadj=%d middle='%c'.\n",F,clfadj,octadj,middle V; lastks->data.middle = middle; lastks->data.clfadj = clfadj; lastks->data.octadj = octadj; lastks->data.pitadj = octadj + clfadj; V6 "%s: Voice %d clfadj=%d octadj=%d pitadj=%d Ksig %s\n", F, j, lastks->data.clfadj, lastks->data.octadj, lastks->data.pitadj, dmpKsig(lastks) V; } elsif (!strcmp(t1,"stems") || !strcmp(t1,"stm")) { if (!strcmp(t2,"up")) voice[j].stems = 1; elsif (!strcmp(t2,"down")) voice[j].stems = -1; elsif (!strcmp(t2,"free")) voice[j].stems = 0; else wng("Unknown stem setting in voice spec: ",t2); } elsif (!strcasecmp(t1,"middle") || !strcasecmp(t1,"m")) { int k, c1, c2; V4 "%s: Recognized \"middle\" with t2=\"%s\"\n",F,t2 V; octadj = clfadj = k = 0; if ((c1 = t2[k]) && (('A' <= c1 && c1 <= 'G') || ('a' <= c1 && c1 <= 'g'))) { middle = c1; V5 "%s: Found middle note '%c'\n",F,middle V; ++k; clfadj = middleadj(middle); V5 "%s: clfadj=%d after '%c' note.\n",F,clfadj,middle V; while ((c2 = t2[k]) && ((c2 == ',') || ( c2 == '\''))) { if (c2 == ',') octadj += 7; if (c2 == '\'') octadj -= 7; V5 "%s: octadj=%d clfadj=%d after '%c' octave.\n",F,octadj,clfadj,c2 V; ++k; } lastks->data.middle = middle; lastks->data.clfadj = clfadj; lastks->data.octadj = octadj; lastks->data.pitadj = clfadj + octadj; V6 "%s: Voice %d clfadj=%d octadj=%d pitadj=%d.\n", F,j,lastks->data.clfadj,lastks->data.octadj,lastks->data.pitadj V; } else { V1 "%s: Unrecognized note '%c' in \"%s\"\n",F,c1,t2 V; } V4 "%s: Voice %d Ksig %s (line %d)\n",F,j,dmpKsig(lastks),__LINE__ V; } elsif (!strcmp(t1,"treble,") || !strcmp(t1,"tenor")) { V6 "%s: TREBLE clef\n" V; lastks->data.clef = TREBLE; // Was TREBLEd8 [jc] lastks->data.octadj = 0; lastks->data.clfadj = 0; lastks->data.pitadj = middleadj(lastks->data.middle = 'B'); V4 "%s: Voice %d key %s (line %d)\n",F,j,dmpKsig(lastks),__LINE__ V; } elsif (!strcmp(t1,"alto,")) { V6 "%s: ALTO clef\n" V; lastks->data.clef = ALTO; lastks->data.octadj = 0; lastks->data.pitadj = lastks->data.clfadj = middleadj(lastks->data.middle = 'c'); V4 "%s: Voice %d key %s (line %d)\n",F,j,dmpKsig(lastks),__LINE__ V; } elsif (!strcmp(t1,"bass,,")) { V6 "%s: BASS clef\n" V; lastks->data.clef = BASS; lastks->data.octadj = 0; lastks->data.pitadj = lastks->data.clfadj = middleadj(lastks->data.middle = 'd'); V4 "%s: Voice %d key %s (line %d)\n",F,j,dmpKsig(lastks),__LINE__ V; } else { wng("Unknown option in voice spec: ",t1); } } } V6 "%s: options=%d middle='%c' key=%s\n",F,options,middle,dmpKsig(voice[j].key0) V; if (!voice[j].key && !options) { // If no keysig options specified, use default lastks = voice[j].key; V6 "%s: Set voice[%d].key to default_key.\n",F,j V; asgnKsig(lastks,&default_key); V6 "%s: Voice %d adjust: clef=%d octave=%d pit=%d.\n", F,j,lastks->data.clfadj,lastks->data.octadj,lastks->data.pitadj V; } /* if new voice was initialized, save settings im meter0, key0 */ if (new) { V6 "%s: New voice %d.\n",F,j V; voice[j].meter0 = voice[j].meter; // voice[j].key0 = voice[j].key; V6 "%s: voice[%d].key is %s (Line %d)\n",F,j,dmpKsig(lastks),__LINE__ V; voice[j].key0 = asgnKsig(voice[j].key0,lastks); V6 "%s: voice[%d].key0 is %s\n",F,j,dmpKsig(voice[j].key0) V; } V3 "%s: Switch to voice %d <%s> <%s> <%s> clef=%d ksig %s\n",F, j,voice[j].id,voice[j].name,voice[j].sname, lastks->data.clef,dmpKsig(voice[j].key0) V; nsym0 = voice[j].nsym; /* set nsym0 to decide about eoln later.. ugly */ return j; } /* ----- info_field: identify info line, store in proper place ---- */ /* switch within_block: either goes to default_info or info. * Only xref ALWAYS goes to info. * * 2000-05-31 jc * Long series of if tests rewritten as a switch. */ int info_field(str) char* str; { char* F = "info_field"; char t[STRL]; char *p; Info* inf; int i; V3 "%s: Info \"%s\"\n",F,str V; for (i = 0;iarea, str+2); break; case 'B': if (inf->nbook >= NBOOK) { wng("Too many B: book lines",""); } else { strip(inf->book[inf->nbook],str+2); inf->nbook++; } break; case 'C': if (inf->ncomp >= NCOMP) { wng("Too many C: composer lines",""); } else { strip(inf->comp[inf->ncomp],str+2); inf->ncomp++; } break; case 'D': strip(inf->disc, str+2); add_text(str+2, TEXT_D); break; case 'F': V3 "%s: F header line ignored.\n",F V; break; case 'G': strip(inf->group, str+2); break; case 'H': strip(inf->hist, str+2); add_text (str+2, TEXT_H); return HISTORY; case 'W': add_text (str+2, TEXT_W); return WORDS; case 'I': strip(inf->info, str+2); break; case 'K': V5 "%s: K field \"%s\"\n",F,str V; strip(inf->key, str+2); V5 "%s: Key signature \"%s\"\n",F,str+2 V; return KEY; case 'L': strip(inf->len, str+2); return DLEN; case 'M': strip(inf->meter, str+2); return METER; case 'N': strip(inf->notes, str+2); add_text (str+2, TEXT_N); break; case 'O': strip(inf->orig, str+2); break; case 'R': strip(inf->rhyth, str+2); break; case 'P': strip(inf->parts, str+2); return PARTS; case 'S': strip(inf->src, str+2); break; case 'T': strip(t, str+2); numtitle++; if (numtitle>6) numtitle = 6; if (numtitle == 1) trim_title (inf->title, t); elsif (numtitle == 2) trim_title (inf->title2, t); elsif (numtitle == 3) trim_title (inf->title3, t); elsif (numtitle == 4) trim_title (inf->title4, t); elsif (numtitle == 5) trim_title (inf->title5, t); elsif (numtitle == 6) trim_title (inf->title6, t); return TITLE; case 'U': V4 "%s: Macro ...\n",F V; return MACRO; case 'V': V4 "%s: Voice ...\n",F V; strip(lvoiceid, str+2); return VOICE; case 'Z': strip(inf->trans, str+2); add_text (str+2, TEXT_Z); break; case 'Q': strip(inf->tempo, str+2); return TEMPO; case 'E': case 'w': return 0; // Tells caller that there's more parsing to do. default: V1 "Unknown header line \"%s\"\n",str V; return 0; } return INFO; } /* ----- append_meter: add meter to list of symbols -------- */ void append_meter (meter) Msig meter; { int kk; kk = add_sym(TIMESIG); zeroSym(&symv[ivc][kk],"symv/append_meter"); symv[ivc][kk].type = TIMESIG; symv[ivc][kk].u = meter.meter1; symv[ivc][kk].v = meter.meter2; symv[ivc][kk].w = meter.mflag; strcpy(symv[ivc][kk].ach,meter.top); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Allocate a new Ksig struct, and add it to the end of the list */ Ksig * newKsig( char *C) /* Our caller */ { char *F = "newKsig"; Ksig *ks = 0; /* Return value */ if (!(ks = (Ksig*)Malloc(sizeof(Ksig),"Ksig"))) { V1 "%s: Can't get %d bytes for new Ksig (from %s)\n",F,sizeof(Ksig),C V; return 0; } bzero(ks,sizeof(Ksig)); /* Make sure it's clean */ // ksiglast->next = ks; /* Insert at end of list */ // ks->knum = ++ksignum; /* Bump the Ksig counter */ // ksiglast = ks; /* New end of list */ V6 "%s: New %s\n",F,dmpKsig(ks) V; return ks; } /* ----- append_key_change: append change of key to sym list ------ */ void append_key_change(oldkey,newkey) Ksig *oldkey; Ksig *newkey; { char *F = "append_key_change"; int a, accs, n1,n2,t1,t2,kk; Ksig *ks; V6 "%s: Called.\n",F V; V6 "%s: Old %s\n",F,dmpKsig(oldkey) V; V6 "%s: New %s\n",F,dmpKsig(newkey) V; if (oldks) { // V3 "%s: Using old ksig code.\n",F V; // n1 = oldkey->data.sf; // t1 = A_SH; // if (n1 < 0) { // n1 = -n1; /* Number of flats */ // t1 = A_FT; /* Type is flats */ // } } else { V3 "%s: Using new ksig code.\n",F V; n1 = oldkey->data.accs; /* Number of accidentals */ t1 = A_MX; /* Keysig type */ } V6 "%s: n1=%d t1=%d.\n",F,n1,t1 V; if (oldks) { // n2 = newkey->data.sf ? newkey->data.sf : newkey->data.sf; // t2 = A_SH; // if (n2 < 0) { // n2 = -n2; /* Number of flats */ // t2 = A_FT; /* Type is flats */ // } } else { n2 = newkey->data.accs; /* Number of accidentals */ t2 = A_MX; /* Keysig type */ } V6 "%s: n2=%d t2=%d.\n",F,n2,t2 V; if (newkey->data.clef != oldkey->data.clef) { /* clef change */ kk = add_sym(CLEF); symv[ivc][kk].u = newkey->data.clef; symv[ivc][kk].v = 1; symv[ivc][kk].clef = newkey->data.clef; V3 "%s: Clef change for symv[%d][%d] to u=clef=%d v=1.\n",F,ivc,kk,newkey->data.clef V; } // if (oldks && t1 == t2 && t1 != A_MX) { /* here if old and new have same type */ // V6 "%s: Same type %d, change from %d to %d accidentals.\n",F,t1,n1,n2 V; // if (n2 > n1) { /* more new symbols ..*/ // kk = add_sym(KEYSIG); /* draw all of them */ // ks = symv[ivc][kk].ksig = newKsig(F); // copyKsig(newkey,ks); // symv[ivc][kk].u = 1; /* Clef type */ // symv[ivc][kk].acc1 = n2; // symv[ivc][kk].acc2 = 100; // symv[ivc][kk].v = -1; /* Was n2 */ // symv[ivc][kk].w = -1; /* Was 100 */ // symv[ivc][kk].t = t1; // symv[ivc][kk].q = newkey->data.sf; // } elsif (n2 < n1) { /* less new symbols .. */ // kk = add_sym(KEYSIG); /* draw all new symbols and neutrals */ // ks = symv[ivc][kk].ksig = newKsig(F); // copyKsig(newkey,ks); // symv[ivc][kk].u = 1; /* Clef type */ // symv[ivc][kk].acc1 = n1; // symv[ivc][kk].acc2 = n2+1; // symv[ivc][kk].v = -1; /* Was n1 */ // symv[ivc][kk].w = -1; /* Was n2+1 */ // symv[ivc][kk].t = t2; // symv[ivc][kk].q = newkey->data.sf; // } elsif (n1 == n2) { // V6 "%s: n1=%d == n2=%d.\n",F,n1,n2 V; // kk = add_sym(KEYSIG); /* draw all new symbols and neutrals */ // ks = symv[ivc][kk].ksig = newKsig(F); // copyKsig(newkey,ks); // symv[ivc][kk].u = 1; /* Clef type */ // symv[ivc][kk].acc1 = n1; // symv[ivc][kk].acc2 = n2+1; // symv[ivc][kk].v = -1; /* Was n1 */ // symv[ivc][kk].w = -1; /* Was n2+1 */ // symv[ivc][kk].t = t2; // symv[ivc][kk].q = newkey->data.sf; // } // } else { /* here for change s->f or f->s */ V6 "%s: New type ksig %d->%d, accidentals %d->%d.\n",F,t1,t2,n1,n2 V; if (ksigcancel) { kk = add_sym(KEYSIG); /* neutralize all old symbols */ symv[ivc][kk].t = A_NT; /* Change accidental type to natural */ symv[ivc][kk].u = 1; symv[ivc][kk].u = 1; symv[ivc][kk].acc1 = n1; symv[ivc][kk].acc2 = 1; if (!(ks = symv[ivc][kk].ksig)) { V6 "%s: Alloc Ksig structure for voice %d.\n",F,ivc V; if (!(ks = symv[ivc][kk].ksig = newKsig(F))) { V1 "%s: ### OUT OF MEMORY (can't get Ksig) ###\n",F V; return; } copyKsig(oldkey,ks); } V6 "%s: symv[%d][%d].ksig [%s] exists.\n",F,ivc,kk,dmpKsig(ks) V; ks->data.accs = n1; ks->data.accs = 0; ks->data.clef = oldkey->data.clef; accs = fillKsig(ks,n1); for (a=0; adata.atyp[a] = A_NT; ks->data.aval[a] = oldkey->data.aval[a]; ks->data.apos[a] = oldkey->data.apos[a]; V6 "%s: symv[%d][%d].atyp[%d]=%d=A_NT aval=%c apos=%d.\n",F ,ivc,kk,a,A_NT,ks->data.aval[a],ks->data.apos[a] V; } V3 "%s: Old symv[%d][%d].ksig = [%s]\n",F,ivc,kk,dmpKsig(symv[ivc][kk].ksig) V; symv[ivc][kk].v = -1; /* Was n1 */ symv[ivc][kk].w = -1; /* Was 1 */ symv[ivc][kk].t = t1; } kk = add_sym(KEYSIG); /* add all new symbols */ if (!(ks = symv[ivc][kk].ksig)) { V6 "%s: symv[%d][%d] needs a ksig.\n",F,ivc,kk V; if (!(ks = newKsig(F))) { V1 "%s: ### OUT OF MEMORY (can't get Ksig) ###\n",F V; return; } } V3 "%s: Set up new %s with %d accidentals.\n",F,dmpKsig(ks),n2 V; copyKsig(newkey,ks); // ks->data = newkey->data; symv[ivc][kk].u = 1; symv[ivc][kk].acc1 = n2; symv[ivc][kk].acc2 = 100; symv[ivc][kk].v = -1; /* Was n2 */ symv[ivc][kk].w = -1; /* Was 100 */ symv[ivc][kk].t = t2; symv[ivc][kk].q = newkey->data.sf; V3 "%s: New symv[%d][%d].ksig = [%s]\n",F,ivc,kk,dmpKsig(symv[ivc][kk].ksig) V; // } V6 "%s: Done.\n",F V; } #if 0 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * This routine calculates the number of scale steps above a nominal lowest * note ("A,,"), adjusted for the clef and octave of the current staff. */ int calc_numeric_pitch(char note) { char *F = "calc_numeric_pitch"; int pitch = 0; if (note == 'z') { pitch = 14; } elsif (within('C',note,'G')) { pitch = note - 'C' + 16 + voice[ivc].key->data.octadj + voice[ivc].key->data.clfadj; } elsif (within('A',note,'B')) { pitch = note - 'A' + 21 + voice[ivc].key->data.octadj + voice[ivc].key->data.clfadj; } elsif (within('c',note,'g')) { pitch = note - 'c' + 23 + voice[ivc].key->data.octadj + voice[ivc].key->data.clfadj; } elsif (within('a',note,'b')) { pitch = note - 'a' + 28 + voice[ivc].key->data.octadj + voice[ivc].key->data.clfadj; } else { V1 "%s: numeric_pitch: cannot identify <%c>\n",F,note V; } V6 "%s: Note '%c' pitch %d adjust by oct=%d clef=%d pit=%d.\n", F,note,pitch,voice[ivc].key->data.octadj,voice[ivc].key->data.clfadj,voice[ivc].key->data.pitadj V; return pitch; } #endif /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The numeric pitch of a note is the number of scale steps above our nominal * lowest note. The lowest note corresponds to "A,," which is pitch 0. */ int numeric_pitch(char note) { char *F="numeric_pitch"; int pitch = 0; if (note == 'z') { pitch = 14; } elsif (within('C',note,'G')) { pitch = note - 'C' + 16; // + voice[ivc].key->data.pitadj; } elsif (within('A',note,'B')) { pitch = note - 'A' + 21; // + voice[ivc].key->data.pitadj; } elsif (within('c',note,'g')) { pitch = note - 'c' + 23; // + voice[ivc].key->data.pitadj; } elsif (within('a',note,'b')) { pitch = note - 'a' + 28; // + voice[ivc].key->data.pitadj; } else { V1 "%s: cannot identify <%c>\n",F,note V; } V6 "%s: Note '%c' is pitch %d.\n",F,note,pitch V; return pitch; } /* * ----- symbolic_pitch: translate numeric pitch back to symbol ------ */ int symbolic_pitch(pit,str) int pit; char str[]; { char *F="symbolic_pitch"; int p,r,s; char ltab1[7] = {'C','D','E','F','G','A','B'}; char ltab2[7] = {'c','d','e','f','g','a','b'}; p = pit-16; r = (p+700)%7; /* Note within octave */ s = (p-r)/7; /* Octave */ if (p<7) { sprintf (str,"%c,,,,,",ltab1[r]); str[1-s] = '\0'; } else { sprintf (str,"%c'''''",ltab2[r]); str[s] = '\0'; } return 0; } char *A2acc[] = { ".", /* 0 */ "^", /* 1 A_SH */ "", /* 2 A_NT */ "_", /* 3 A_FT */ "^^", /* 4 A_DS */ "__", /* 5 A_DF */ "_^", /* 6 A_MX */ "^/", /* 7 A_HSH */ "_/", /* 8 A_HFT */ "?", /* 9 */ }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Produce a printable dump string for a key signature. */ char *dmpKsig( Ksig *ks) { int a; char *bp; static char ksbuf[1000]; if (!ks) {return "[[NULL]]";} sprintf(ksbuf,"Ksig %08lX: [\0",ks); bp = ksbuf + strlen(ksbuf); // if (ks->data.root) { *bp++ = 'A' + ks->data.root; if (ks->data.rootAc) { if (ks->data.rootAc == A_HSH || ks->data.rootAc == A_HFT) *bp++ = '/'; *bp++ = (ks->data.rootAc == A_SH | ks->data.rootAc == A_HSH) ? '#' : (ks->data.rootAc == A_FT | ks->data.rootAc == A_HFT) ? 'b' : (ks->data.rootAc == A_NT) ? ' ' : '?'; } if (ks->data.mode) { sprintf(bp,"%s\0",ks->data.mode); bp += strlen(bp); } *bp++ = ' '; *bp = 0; // } sprintf(bp,"%s accs=%d \0",SymClef(ks->data.clef),ks->data.accs); bp += strlen(bp); if (ks->data.clfadj || ks->data.octadj || ks->data.pitadj || ks->data.middle) { sprintf(bp,"adj:c=%d/o=%d:p=%d:'%c' \0", ks->data.clfadj,ks->data.octadj,ks->data.pitadj,ks->data.middle); bp += strlen(bp); } for (a = 0; a < ks->data.accs; a++) { sprintf(bp,"%s\0",A2acc[ks->data.atyp[a]]); bp += strlen(bp); *bp++ = ks->data.aval[a]; } *bp++ = ']'; *bp = 0; return ksbuf; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Fill in a Ksig struct with the standard key signature for ks sharps or flats. */ fillKsig( Ksig *ks, /* Ksig struct */ int sf) /* Sharps or flats */ { char *F = "fillKsig"; int i; if (sf > 0) { V5 "%s: Key has %d sharps.\n",F,sf V; for (i = 0; idata.atyp[i] = A_SH; ks->data.aval[i] = sh_val[i]; ks->data.apos[i] = note_pos(ks->data.aval[i],ks->data.clef); V6 "%s: Acc %d atyp=%d=A_SH apos=%d aval='%c'\n",F,i,ks->data.atyp[i],ks->data.apos[i],ks->data.aval[i] V; } ks->data.accs = sf; } elsif (sf < 0) { V5 "%s: Key has %d flats.\n",F,-sf V; for (i = 0; i<-sf; i++) { ks->data.atyp[i] = A_FT; ks->data.aval[i] = fl_val[i]; ks->data.apos[i] = note_pos(ks->data.aval[i],ks->data.clef); V6 "%s: Acc %d atyp=%d=A_FT apos=%d aval='%c'\n",F,i,ks->data.atyp[i],ks->data.apos[i],ks->data.aval[i] V; } ks->data.accs = -sf; } else { ks->data.accs = 0; } V6 "%s: Ksig=%lX has sf=%d accs=%d.\n",F,ks,sf,ks->data.accs V; return ks->data.accs; } static Ksig savekey; static Ksig newksig; /* ----- handle_inside_field: act on info field inside body of tune --- */ void handle_inside_field(type) int type; { char *F = "handle_inside_field"; int rc; V6 "%s: Called for type %d.\n",F,type V; if (type == METER) { if (nvoice == 0) ivc = switch_voice(DEFVOICE); set_meter(info.meter,&voice[ivc].meter); append_meter(voice[ivc].meter); } elsif (type == DLEN) { if (nvoice == 0) ivc = switch_voice(DEFVOICE); set_dlen (info.len, &voice[ivc].meter); } elsif (type == KEY) { V5 "%s: Key signature in nvoice %d.\n",F,nvoice V; if (nvoice == 0) { ivc = switch_voice(DEFVOICE); } // savekey = *voice[ivc].key; V6 "%s: voice[%d].key is %s\n",F,ivc,dmpKsig(voice[ivc].key) V; asgnKsig(&savekey,voice[ivc].key); V6 "%s: savekey is %s\n",F,dmpKsig(&savekey) V; if (!voice[ivc].key) voice[ivc].key = newKsig(F); V6 "%s: Parse key \"%s\" into voice[%d].key = %s\n",F,info.key,ivc,dmpKsig(voice[ivc].key) V; rc = parseKey(info.key,voice[ivc].key,0); V6 "%s: Voice %d has %s\n",F,ivc,dmpKsig(voice[ivc].key) V; V6 "%s: Saved %s\n",F,dmpKsig(&savekey) V; if (rc) { V6 "%s: Call set_transtab for %d halftones voice %d.\n",F,halftones,ivc V; set_transtab(halftones,voice[ivc].key); } V6 "%s: Call append_key_change for savekey, voice[%d].key\n",F,ivc V; append_key_change(&savekey,voice[ivc].key); } elsif (type == VOICE) { ivc = switch_voice (lvoiceid); } } /* ----- prsUInt: parse for unsigned integer ----- */ int prsUInt() { char *F="prsUInt"; int number=0, ndig; // char num[21]; if (!isdigit(*P)) return 0; ndig = 0; while (isdigit(*P)) { // num[ndig] = *P; ndig++; // num[ndig] = 0; number = (number * 10) + (*P - '0'); P++; } // sscanf (num, "%d", &number); V3 "%s: parsed unsigned int %d\n",F,number V; return number; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * prsBar: parse for some kind of bar. We eat up the bar-line chars, and also * any ending label that may be present. */ int prsBar() { char *F="prsBar"; int c, i, k, r; int ngr=0,pgr[30],agr[30]; Sym *sp; V3 "%s: Called at <%s>\n",F,P V; // ngr = prsGrSeq(pgr,agr); /* grace notes */ // while ((c = *P) && isspace(c)) ++P; V3 "%s: Bar sym has %d grace notes at <%s>.\n",F,ngr,P V; prsAnn(); // Allow annotations on par lines prsAch(); // Allow "chords" on bar lines // special cases: [ and digit or quote without a preceeding bar, [ ending if (*P == '[') { V3 "%s: [\n",F V; if ((c = P[1]) && (isdigit(c) || c=='"')) { V3 "%s: [%c\n",F,c V; k = add_sym(BAR); symv[ivc][k].u = B_INVIS; V3 "%s: symv[%d][%d] made invisible.\n",F,ivc,k V; // ++P; prsEnd(k); V3 "%s: Return 1.\n",F V; return 1; } } if ((*P == '[') && (*(P+1) == '|') && (*(P+2) == ':')) { V3 "%s: [|: reduced.\n",F V; ++P; // Ignore spurious '[' } /* identify valid standard bar types */ if (*P == '|') { k = add_sym(BAR); symv[ivc][k].u = B_SNGL; P++; while (isspace(*P)) ++P; while (*P == '|') { // Eat up any number of bar lines symv[ivc][k].u = B_DBL; P++; } if (*P == ':') { // Start repeat symv[ivc][k].u = B_LREP; while (*P == ':') { // Count the colons [jc] ++symv[ivc][k].lrep; // Number of colons found P++; } V3 "%s: symv[ivc=%d][k=%d].lrep=%d.\n",F,ivc,k,symv[ivc][k].lrep V; V3 "%s: Found bar line with %d left repeats.\n",F,symv[ivc][k].lrep V; } elsif (*P == ']') { /* code |] for fat end bar */ symv[ivc][k].u = B_FAT2; P = P+1; if (*P == '|') { /* |]| for for fat middle bar */ symv[ivc][k].u = B_FAT3; P++; } } elsif (*P == '[' && P[1] == '|') { /* code |[| for fat middle bar */ symv[ivc][k].u = B_FAT3; P += 2; } } elsif (*P == ':') { // End repeat r = 0; while (*P == ':') { // Count the colons [jc] r++; /* Number of colons found */ P++; } V3 "%s: Found %d colons.\n",F,r V; if (r == 2 && *P != '|') { V3 "%s: ::\n",F,r V; k = add_sym(BAR); symv[ivc][k].u = B_DREP; symv[ivc][k].lrep = symv[ivc][k].lrep = 0; } elsif (*P == '|') { V3 "%s: Found bar line after %d colons.\n",F,r V; k = add_sym(BAR); symv[ivc][k].u = B_RREP; symv[ivc][k].lrep = r; P++; while (*P == ']') { // Eat up ] fat bars V3 "%s: ] ignored.\n",F,r V; ++P; } // if (*P == ']') { // Ignore spurious ']' // V3 "%s: :|] reduced.\n",F,r V; // ++P; // } } else { V3 "%s: Found no bar line after %d colons.\n",F,r V; k = add_sym(BAR); symv[ivc][k].u = B_DREP; symv[ivc][k].lrep = symv[ivc][k].rrep = r; P++; } } elsif ((*P == '[') && (*(P+1) == '|') && (*(P+2) == ']')) { /* code [|] invis */ k = add_sym(BAR); symv[ivc][k].u = B_INVIS; P = P+3; } elsif ((*P == '[') && (*(P+1) == '|')) { /* code [| for thick-thin bar */ k = add_sym(BAR); symv[ivc][k].u = B_FAT1; P = P+2; while (isspace(*P)) ++P; while (*P == '|') { // Ignore extra '|' V3 "%s: [|| reduced.\n",F,r V; ++P; } } else { V3 "%s: Return 0.\n",F V; return 0; } V3 "%s: Bar symv[%d][%d] has %d grace notes.\n",F,ivc,k,ngr V; sp = &symv[ivc][k]; sp->gr.n = ngr; /* Grace note count */ V3 "%s: Bar symv[%d][%d] has %d decorations and %d grace notes.\n",F,ivc,k,sp->dc.n,sp->gr.n V; for (i = 0;igr.p[i] = pgr[i]; sp->gr.a[i] = agr[i]; } prsEnd(k); /* * Add the accompaniment chord to the text. */ symv[ivc][k].ach[0] = 0; if (strlen(ach)>0) { V3 "%s: ach=\"%s\"\n",F,ach V; strcat(symv[ivc][k].ach, " "); strcat(symv[ivc][k].ach, ach); V3 "%s: symv[%d][%d].ach=\"%s\"\n",F,ivc,k,symv[ivc][k].ach V; ach[0] = 0; /* Make sure we don't use it twice */ } /* * If we found an annotation before the bar line, add the annotation to the bar's text. */ if (ann && ann->t && (ann->l > 0)) { V3 "%s: Init annotation for voice %d sym %d.\n",F,ivc,k V; if (!TextInit(&symv[ivc][k].ann,64)) { V1 "%s: Can't initialize symv[%d][%d].ann\n",F,ivc,k V; V3 "%s: Return 0.\n",F V; return 0; } V3 "%s: ann=\"%s\"\n",F,ann V; TextAppend(symv[ivc][k].ann, " "); TextAppend(symv[ivc][k].ann, ann->t); symv[ivc][k].ann->y = ann->y; symv[ivc][k].ann->p = ann->p; V3 "%s: symv[%d][%d] ann=!%s! at %6.3f pos %d.\n",F,ivc,k,TextStr(symv[ivc][k].ann),symv[ivc][k].ann->y,symv[ivc][k].ann->p V; } TextInit(&ann,64); /* Make sure we don't use it twice */ V3 "%s: Return 1.\n",F V; return 1; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Test a char for being legal in an unquoted ending label. We now recognize * only digits, commas and hyphens; you must use quotes around everything else. */ isrepstr(c) int c; { if (isdigit(c) || (c == ',') // Default ending-label chars || (c == '-') || (c == 'x') // Someone requested 'x'; what does it mean? ) return 1; return 0; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Parse an ending string. This eats up whatever isrepstr() considers a valid * (unquoted) ending indicator string, copies it to the vtxt string for the * current symbol, and returns a pointer to the char that ended the scan. */ char *repstr(k,p) int k; char *p; { char *F = "repstr"; int c, i=0; while (isrepstr(c = *p)) { symv[ivc][k].vtxt[i++] = c; symv[ivc][k].vtxt[i ] = 0; // Only needed for V message: V5 "%s: vtxt=\"%s\"\n",F,symv[ivc][k].vtxt V; p++; } symv[ivc][k].vtxt[i] = 0; symv[ivc][k].v = 9; // Kludge: Old ending number must be nonzero V5 "%s: vtxt=\"%s\"\n",F,symv[ivc][k].vtxt V; return p; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Parse a quoted ending string. This eats up characters until the matching * '"', copies it to the vtxt string for the current symbol, and returns a * pointer to the char after the quote that ended the scan. */ char *repquot(k,p) int k; char *p; { char *F = "repstr"; int c, i=0; while ((c = *p) && (c != '"')) { symv[ivc][k].vtxt[i++] = c; symv[ivc][k].vtxt[i ] = 0; // Only needed for V message: V5 "%s: vtxt=\"%s\"\n",F,symv[ivc][k].vtxt V; p++; } if (c == '"') p++; // Eat up the final quote symv[ivc][k].vtxt[i] = 0; symv[ivc][k].v = 9; // Kludge: Old ending number must be nonzero V5 "%s: vtxt=\"%s\"\n",F,symv[ivc][k].vtxt V; return p; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * See if valid bar is followed by specifier for first or second ending * Called with: * k == index of BAR symbol. * p -> first char ('[', '"' or digit) of ending label. * * Modified to accept any string of digits [jc 2000-04-22] * Modified to accept quoted string [jc 2002-05-20] */ prsEnd(k) int k; { char *F = "prsEnd"; char *q = P; // Remember starting point int c=0, d=0, i; int quoted=0; // Type of ending (quoted or not) V5 "%s: Parse %8.8s...\n",F,P V; if (!(c = *P)) return; while (isspace(c)) // Skip white stuff c = *++P; if (!c) return; V5 "%s: Parse '%c'\n",F,c V; if (isdigit(c)) { // Just a digit is degenerate ending V5 "%s: Ending digit %02X='%c'.\n",F,c,c V; symv[ivc][k].v = (c - '0'); P++; // Skip over one digit } elsif (c == '[') { V5 "%s: Ending bracket.\n",F V; if (((d = P[1]) && isdigit(d))) { V5 "%s: [ Ending digit %02X='%c'.\n",F,d,d V; // P += 2; // Skip [ and one digit P = repstr(k,P+1); } elsif ((d = P[1]) && (d == '"')) { V5 "%s: [ Ending quote %02X='%c'.\n",F,d,d V; P = repquot(k,P+2); // quoted = 1; // Ending is quoted // P += 2; // Skip [" } else { V5 "%s: Not an ending.\n",F V; return; // It's not an ending label } } else { V5 "%s: Not an ending.\n",F V; P = q; // Return to starting point return; // It's not an ending label } V5 "%s: Continue with \"%8.8s\"...\n",F,P V; if (c = *P) { V5 "%s: Next repeat char %02X='%c'.\n",F,c,c V; if (quoted) { // Quoted ending? V5 "%s: Quoted repeat syntax at %02X='%c'.\n",F,c,c V; P = repquot(k,P); } elsif (isrepstr(c)) { V5 "%s: Extended repeat syntax at %02X='%c'.\n",F,c,c V; P = repstr(k,P-1); } } } /* ----- parse_space: parse for whitespace ---- * Added by JC: Ignore ` (grave accent) chars entirely. */ int parse_space () { int c, rc; rc = 0; while ((c = *P) && (c == ' ') || (c == '\t') || (c == '`')) { if (c != '`') // Ignore graves rc = 1; P++; } if (db>3) if (rc) fprintf(stderr," parsed whitespace\n"); return rc; } /* ----- parse_esc: parse for escape sequence ----- */ int parse_esc () { int nseq; char *pp; if (*P == '\\') { /* try for \...\ sequence */ P++; nseq = 0; while ((*P != '\\') && (*P != 0)) { escseq[nseq] = *P; nseq++; P++; } if (*P == '\\') { P++; escseq[nseq] = 0; V3 " parsed esc sequence <%s>\n", escseq V; return ESCSEQ; } else { if (cfmt.breakall) return DUMMY; V3 " parsed esc to EOL.. continuation\n" V; } return CONTINUE; } /* next, try for [..] sequence */ if ((*P == '[') && (*(P+1) >= 'A') && (*(P+1) <= 'Z') && (*(P+2) == ':')) { pp = P; P++; nseq = 0; while ((*P != ']') && (*P != 0)) { escseq[nseq] = *P; nseq++; P++; } if (*P == ']') { P++; escseq[nseq] = 0; V3 " parsed esc sequence <%s>\n", escseq V; return ESCSEQ; } syntax("Escape sequence [..] not closed", pp); return ESCSEQ; } return 0; } /* ----- parse_nl: parse for newline ----- */ int parse_nl () { if ((*P == '\\')&&(*(P+1) == '\\')) { P += 2; return 1; } else { return 0; } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Parse an accompaniment chord. */ int prsAch () { char *F = "prsAch"; char *q; int c, n; V3 "%s: Called for <%3.3s>\n",F,P V; if (*P != '"') {V5 "%s: No achord\n",F V; return 0;} q = P; /* Note position of opening quote */ P++; /* Skip to first char of string */ switch (c = *P) { /* Check for position char */ case '^': /* Above staff */ V3 " Chord position '%c' above staff.\n",c V; P++; break; case '<': /* Left of note */ V3 " Chord position '%c' left of note.\n",c V; P++; break; case '=': /* Next to note */ V3 " Chord position '%c' next to note.\n",c V; P++; break; case '>': /* Right of note */ V3 " Chord position '%c' right of note.\n",c V; P++; break; case '_': /* Below staff */ V3 " Chord position '%c' below staff.\n",c V; P++; break; } n = strlen(ach); /* Length of chord so far */ if (n > 0) syntax("Overwrite unused accomp chord", q); while ((*P != '"') && (*P != 0)) { ach[n] = *P; n++; if (n >= 200) { syntax("String for accomp chord too long", q); V5 "%s: Return 1 [String for accomp chord too long].\n",F V; return 1; } P++; } if (*P == 0) { syntax("EOL reached while parsing accomp chord", q); V5 "%s: Return 1 [EOL reached while parsing accomp chord].\n",F V; return 1; } P++; ach[n] = 0; V3 " parse accomp chord <%s>\n", ach V; /*| ach_transpose (voice[ivc].key); |*/ V5 "%s: Return 1.\n",F V; return 1; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * prsLen: parse length specifer for note or rest */ int prsLen() { char *F="prsLen"; int len,fac; len = voice[ivc].meter.dlen; /* start with default length */ V5 "%s: len=%d (default)\n",F,len V; if (len <= 0) { fprintf(stderr,"!!! parse_len: got len = %d\n", len); } if (isdigit(*P)) { /* multiply note length */ fac = prsUInt (); if (fac == 0) fac = 1; len *= fac; V5 "%s: len=%d (*= fac=%d)\n",F,len,fac V; } if (*P == '/') { /* divide note length */ while (*P == '/') { P++; if (isdigit(*P)) { fac = prsUInt(); } else { fac = 2; } V5 "%s: fac=%d\n",F,fac V; if (len%fac) { syntax("Bad length divisor", P-1); return len; } len = len/fac; V5 "%s: len=%d (/= fac=%d)\n",F,len,fac V; } } V5 "%s: len=%d (result)\n",F,len V; return len; } /* ----- prsGrSeq --------- */ int prsGrSeq (pgr,agr) int pgr[],agr[]; { char *F="prsGrSeq"; char *p0; int c, n,len; V5 "%s: Called at <%s>\n",F,P V; p0 = P; while ((c = *P) && isspace(c)) P++; if (c != '{') { V5 "%s: '%c' not a grace sequence.\n",F,c V; return 0; } P++; n = 0; while (*P != '}') { if (*P == '\0') { V5 "%s: NULL encountered.\n",F V; syntax("Unbalanced grace note sequence", p0); return 0; } if (!isnote(*P)) { if (unexpsym != linenum) syntax("Unexpected symbol in grace note sequence", P); unexpsym = linenum; P++; } agr[n] = 0; if (*P == '=') agr[n] = A_NT; if (*P == '^') { if (*(P+1) == '^') { agr[n] = A_DS; P++; } elsif (*(P+1) == '/') { agr[n] = A_HSH; P++; } else agr[n] = A_SH; } if (*P == '_') { if (*(P+1) == '_') { agr[n] = A_DF; P++; } elsif (*(P+1) == '/') { agr[n] = A_HFT; P++; } else agr[n] = A_FT; } if (agr[n]) P++; pgr[n] = numeric_pitch(*P); P++; while (*P == '\'') {pgr[n] += 7; P++; if (lastks) lastks->shup++;} while (*P == ',') {pgr[n] -= 7; P++; if (lastks) lastks->shdn++;} if (lastks) V2 "%s: shdn=%d shup=%d.\n",F,lastks->shdn,lastks->shup V; // do_transpose (voice[ivc].key, &pgr[n], &agr[n]); len = prsLen (); /* ignore any length specifier */ n++; } P++; V5 "%s: Return %d\n",F,n V; return n; } /* ----- identify_note: set head type, dots, flags for note --- */ void identify_note (s,q) Sym *s; char *q; { char *F = "identify_note"; int head,base,len,flags,dots; if (s->len == 0) s->len = s->lens[0]; len = s->len; /* set flag if duration equals length of one measure */ if (nvoice>0) { V6 "%s: nvoice=%d ivc=%d WHOLE=%d.\n",F,nvoice,ivc,WHOLE V; V6 "%s: voice[%d].meter.meter1=%d meter2=%d.\n",F, ivc,voice[ivc].meter.meter1,voice[ivc].meter.meter2 V; if (voice[ivc].meter.meter2 > 0) if (len == (WHOLE*voice[ivc].meter.meter1)/voice[ivc].meter.meter2) s->fullmes = 1; } base = WHOLE; if (len >= WHOLE) base = WHOLE; elsif (len >= HALF) base = HALF; elsif (len >= QUARTER) base = QUARTER; elsif (len >= EIGHTH) base = EIGHTH; elsif (len >= SIXTEENTH) base = SIXTEENTH; elsif (len >= THIRTYSECOND) base = THIRTYSECOND; elsif (len >= SIXTYFOURTH) base = SIXTYFOURTH; else { V2 "%s: Cannot identify head for note, base=%d len=%d \"%s\"\n",F,base,len,q V; syntax("Cannot identify head for note",q); } if (base == WHOLE) head = H_OVAL; elsif (base == HALF) head = H_EMPTY; else head = H_FULL; if (base == SIXTYFOURTH) flags = 4; elsif (base == THIRTYSECOND) flags = 3; elsif (base == SIXTEENTH) flags = 2; elsif (base == EIGHTH) flags = 1; else flags = 0; dots = 0; if (len == base) dots = 0; elsif (2*len == 3*base) dots = 1; elsif (4*len == 7*base) dots = 2; elsif (8*len == 15*base) dots = 3; else syntax("Cannot handle note length for note",q); V5 "%s: length %d gives head %d, dots %d, flags %d\n",F,len,head,dots,flags V; s->head = head; s->dots = dots; s->flags = flags; } /* ----- double_note: change note length for > or < char --- */ /* Note: if symv[ivc][i] is a chord, the length shifted to the following note is taken from the first note head. Problem: the crazy syntax permits different lengths within a chord. */ void double_note (i,num,sign,q) int i,num,sign; char *q; { int m,shift,j,len; if ((symv[ivc][i].type != NOTE) && (symv[ivc][i].type != REST)) bug("sym is not NOTE or REST in double_note", 1); shift = 0; len = symv[ivc][i].lens[0]; for (j = 0;jshup++; V6 "%s: Note '%c' pit=%d after \"'\"\n",F,*P,pit V; if (lastks) V2 "%s: shdn=%d shup=%d.\n",F,lastks->shdn,lastks->shup V; P++; } while (*P == ',') { /* eat up following , chars */ pit -= 7; if (lastks) lastks->shdn++; V6 "%s: Note '%c' pit=%d after \",\"\n",F,*P,pit V; if (lastks) V2 "%s: shdn=%d shup=%d.\n",F,lastks->shdn,lastks->shup V; P++; } len = prsLen(); V6 "%s: Note '%c' pit=%d len=%d.\n",F,*P,pit,len V; // do_transpose (voice[ivc].key, &pit, &acc); *pitch = pit; *length = len; *accidental = acc; V3 "%s: Parsed basic note, length %d/%d=1/%d, pitch %d\n",F,len,BASE,BASE/(len?len:1),pit V; return 1; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Parse for one note or rest with all trimmings. */ int prsNote() { char *F = "prsNote"; int c,cl,k,i,chord,m,type,rc,sl1,sl2,j; int pitch,length,accidental,invis; int num, den; // Length multiplier int ngr,pgr[30],agr[30]; char *q,*q0; Sym *sp; V6 "%s: \"%s\"\n",F,P V; ngr = prsGrSeq(pgr,agr); /* grace notes */ prsAch(); // permit chord after graces prsDeco(); // decorations prsAnn(); // permit annotation after graces V5 "%s: %d graces %d decos found.\n",F,ngr,decos V; prsAnn(); /* permit annotation after decoration */ prsAch(); /* permit chord after decoration */ while (isspace(*P)) P++; chord = 0; /* determine if chord */ q = P; if ((*P == '[') // Standard multi-note chord notation // || (*P == '+') // Obsolete chord notation ) { V5 "%s: Chord start %8.8s...\n",F,P V; chord = 1; P++; } type = invis = 0; if (isnote(*P)) type = NOTE; // if (chord && (*P == '(')) type = NOTE; // Why was this here twice? if (chord && (*P == ')')) type = NOTE; /* this just for better error msg */ if ((*P == 'z')||(*P == 'Z')) {type = REST; } if ((*P == 'x')||(*P == 'X')) {type = REST; invis = 1; } /* Invisible played rest */ if ((*P == 'y')||(*P == 'Y')) {type = REST; invis = 1; } /* Invisible unplayed rest */ if (!type) return 0; // if (!type) { // V2 "%s: No note; assuming y\n",F V; // type = REST; invis = 1; // } V5 "%s: Type %d at <%s>\n",F,type,P V; k = add_sym(type); /* add new symbol to list */ sp = &symv[ivc][k]; for (i = 0;idc.t[i] = dtype[i]; V5 "%s: symv[%d][%d] decoration %d is type %d.\n",F,ivc,k,i,sp->dc.t[i] V; } sp->dc.n = decos; /* Decoration count */ sp->gr.n = ngr; /* Grace note count */ V5 "%s: Bar symv[%d][%d] has %d decorations and %d grace notes.\n",F,ivc,k,sp->dc.n,sp->gr.n V; for (i = 0;igr.p[i] = pgr[i]; sp->gr.a[i] = agr[i]; } if (strlen(ach)>0) { /* Copy achord to voice */ ach_transpose (voice[ivc].key); strcpy (sp->ach, ach); V3 "%s: symv[%d][%d].ach=\"%s\"\n",F,ivc,k,sp->ach V; strcpy (ach, ""); } if (ann && (ann->l > 0)) { /* Copy annotation to voice */ V6 "%s: Init annotation for voice %d sym %d.\n",F,ivc,k V; TextInit(&sp->ann,64); /* Make sure the sym has an annotation struct */ V6 "%s: Copy ann=!%s! to voice %d sym %d.\n",F,TextStr(ann),ivc,k V; TextAppend(sp->ann,ann->t); /* Copy the string */ sp->ann->y = ann->y; /* Note its Y position */ sp->ann->p = ann->p; /* Note its position */ V3 "%s: symv[%d][%d].ann=!%s! at %6.3f pos %d.\n",F,ivc,k,TextStr(sp->ann),sp->ann->y,sp->ann->p V; V6 "%s: Init annotation for ann.\n",F V; TextInit(&ann,64); /* Forget the global annotation */ } if (vb > 7) { int v, s; for (v = 0; v < nvoice; v++) { for (s = 0; s <= voice[v].nsym; s++) { V8 "%s: Voice %d symv %d has ann !%s!\n",F,v,s,TextStr(symv[v][s].ann) V; } } } q0 = P; if (type == REST) { P++; sp->lens[0] = prsLen(); sp->npitch = 1; sp->invis = invis; V3 " parsed rest, length %d/%d=1/%d\n",sp->lens[0],BASE,BASE/sp->lens[0] V; } else { m = 0; /* get pitch and length */ sl1 = sl2 = 0; for (;;) { V6 "%s: %8.8s ...\n",F,P V; if (chord && (*P == '(')) { sl1++; sp->sl1[m] = sl1; P++; } prsDeco(); /* for extra decorations within chord */ V5 "%s: %d decos found in chord.\n",F,decos V; for (i = 0;idc.t[i+sp->dc.n] = dtype[i]; sp->dc.n = decos; if ((rc = parse_basic_note(&pitch,&length,&accidental)) == 0) { voice[ivc].nsym--; return 0; } V6 "%s: voice[%d].key=%X lastks=%X pitadj=%d.\n",F,ivc,voice[ivc].key,lastks,lastks->data.pitadj V; V6 "%s: voice[%d].key is %s pitadj=%d\n",F,ivc,dmpKsig(voice[ivc].key),voice[ivc].key->data.pitadj V; sp->pitadj = voice[ivc].key->data.pitadj; sp->pits[m] = pitch; sp->vpos[m] = pitch + sp->pitadj; sp->lens[m] = length; sp->accs[m] = accidental; sp->ti1[m] = sp->ti2[m] = 0; V6 "%s: symv[%d][%d] m=%d pitadj=%d pits=%d vpos=%d lens=%d accs=%d ti1=%d ti2=%d\n", F,ivc,k,m,sp->pitadj,sp->pits[m],sp->vpos[m], sp->lens[m],sp->accs[m],sp->ti1[m],sp->ti2[m] V; for (j = 0;jvpos[m]) sp->ti2[m] = 1; } if (chord && (*P == '-')) { sp->ti1[m] = 1; P++; } if (chord && (*P == ')')) { sl2++; sp->sl2[m] = sl2; P++; } if (chord && (*P == '-')) { sp->ti1[m] = 1; P++; } m++; if (!chord) break; if ((*P == ']') // || (*P == '+') // Obsolete chord notation ) { V5 "%s: Chord end %8.8s...\n",F,P V; c = *++P; // Skip over ] and look for length. V5 "%s: Chord next char '%c'\n",F,c V; if (isdigit(c) || c=='/') { V5 "%s: Chord length %8.8s...\n",F,P V; } break; } if (*P == '\0') { if (chord) syntax("Chord not closed", q); return type; } } ntinext = 0; for (j = 0;jti1[j]) { tinext[ntinext] = sp->vpos[j]; ntinext++; } sp->npitch = m; } for (m = 0; mnpitch; m++) { /* add carryover from > or < */ if (sp->lens[m]+carryover <= 0) { syntax("> leads to zero or negative note length",q0); } else { sp->lens[m] += carryover; V6 "%s: Symv[%d][%d] lens[%d]=%d\n",F,ivc,k,m,sp->lens[m] V; } } if ((c = *P) && isdigit(c) || c=='/') { // Does the chord have a length? V5 "%s: Chord length %8.8s...\n",F,P V; prsMul(&num,&den); // Parse the multiplier V5 "%s: Chord multiplier %d/%d\n",F,num,den V; for (m = 0; mnpitch; m++) { // Adjust the chord's note lengths sp->lens[m] *= num; sp->lens[m] /= den; V6 "%s: sp->lens[%d]=%d\n",F,m,sp->lens[m] V; } } carryover = 0; cl = voice[ivc].key->data.clef; V3 "%s: Voice %d sym %d is note with %d decos, ach <%s> ann <%s> clef=%d=%s.\n",F, ivc,k,sp->dc.n,sp->ach,TextStr(sp->ann),cl,SymClef(cl) V; sp->yadd = 0; V3 "%s: Init yadd to %d.\n",F,sp->yadd V; switch (voice[ivc].key->data.clef) { case ALTO: case ALTOu8: case ALTOd8: sp->yadd = -3; break; case BASS: case BASSu8: case BASSd8: sp->yadd = -6; break; } V3 "%s: Symv[%d][%d] Adjust yadd to %d.\n",F,ivc,k,sp->yadd V; #if 0 #endif identify_note(&symv[ivc][k],q0); V3 "%s: symv[%d][%d] returns type %d with annotation !%s!\n",F,ivc,k,type,TextStr(sp->ann) V; return type; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Parse a note length, returning a numerator and a denominator. The general * * form is "num/den", where num and den are integers, and both may be missing. * * The default value for num and den are both 1. The '/' may be repeated; each * * '/' cuts the length in half (by doubling den). The return value is the * * number of chars consumed, though this isn't actually used. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ prsMul( int *nump, // Numerator int *denp) // Denominator { int c, chars=0; int denv=0, numv=0; int dens=0, nums=0, slashes=0; // Number of chars in each class char*F="prsMul"; *nump = *denp = 1; // In case we don't find anything while (c = *P) { V6 "%s: c=%02X='%c'\n",F,c,c V; switch (c) { case '/': ++slashes; ++chars; ++P; V6 "%s: slashes=%d.\n",F,slashes V; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (slashes) { denv = (10*denv) + (c - '0'); V6 "%s: denv=%d.\n",F,denv V; } else { numv = (10*numv) + (c - '0'); V6 "%s: numv=%d.\n",F,numv V; } ++chars; ++P; break; default: Done; } } done: if (numv) {*nump = numv; V6 "%s: *nump=%d.\n",F,*nump V;} if (denv) {*denp = denv; V6 "%s: *denp=%d.\n",F,*denp V;} while (slashes-- > 1) { *denp *= 2; V6 "%s: *denp=%d.\n",F,*denp V; } V6 "%s: Return %d with *nump=%d *denp=%d.\n",F,chars,*nump,*denp V; return chars; } /* ----- prsSym: parse a symbol and return its type -------- */ int prsSym () { char *F="prsSym"; int i; V5 "%s: Called at <%s>\n",F,P V; decos = 0; doMacro(); if (prsAnn()) {V4 "%s: Return %d=ANNOT\n",F,ANNOT V; return ANNOT;} if (prsAch()) {V4 "%s: Return %d=ACHORD\n",F,ACHORD V; return ACHORD;} if (prsBar()) {V4 "%s: Return %d=BAR\n",F,BAR V; return BAR;} if (parse_space()) {V4 "%s: Return %d=SPACE\n",F,SPACE V; return SPACE;} if (parse_nl()) {V4 "%s: Return %d=NEWLINE\n",F,NEWLINE V; return NEWLINE;} if ((i = parse_esc())) {V4 "%s: Return %d=i (esc)\n",F,i V; return i;} if ((i = prsNote())) {V4 "%s: Return %d=i (Note)\n",F,i V; return i;} if (parse_nl()) {V4 "%s: Return %d=NEWLINE\n",F,NEWLINE V; return NEWLINE;} V4 "%s: Return 0.\n",F V; return 0; } /* ----- add_wd ----- */ char *add_wd(str) char str[]; { char *rp; int l; l = strlen(str); if (l == 0) return 0; if (nwpool+l+1>NWPOOL) rx ("Overflow while parsing vocals; increase NWPOOL and recompile.",""); strcpy(wpool+nwpool, str); rp = wpool+nwpool; nwpool = nwpool+l+1; return rp; } /* ----- parse_vocals: parse words below a line of music ----- */ /* Use '^' to mark a '-' between syllables - hope nobody needs '^' ! */ int parse_vocals (line) char line[]; { int isym; char *c,*c1,*w; char word[81]; char *wordz = word+80; // Last byte of word [jc] if ((line[0] != 'w') || (line[1] != ':')) return 0; Q = line; isym = nsym0-1; c = line+2; for (;;) { while(*c == ' ') c++; if (*c == '\0') break; c1 = c; if ((*c == '_') || (*c == '*') || (*c == '|') || (*c == '-')) { word[0] = *c; if (*c == '-') word[0] = '^'; word[1] = '\0'; c++; } else { w = word; *w = '\0'; while ((*c != ' ') && (*c != '\0') && (w < wordz)) { if ((*c == '_') || (*c == '*') || (*c == '|')) break; if (*c == '-') { if (*(c-1) != '\\') break; w--; *w = '-'; } *w = *c; w++; c++; } if (*c == '-') { *w = '^' ; w++; c++; } *w = '\0'; } /* now word contains a word, possibly with trailing '^', * or one of the special characters * | _ - */ if (!strcmp(word,"|")) { /* skip forward to next bar */ isym++; while ((symv[ivc][isym].type != BAR) && (isym= voice[ivc].nsym) { syntax("Not enough bar lines for |",c1); break; } } else { /* store word in next note */ w = word; while (*w != '\0') { /* replace * and ~ by space */ /* cd: escaping with backslash possible */ if ( ((*w == '*') || (*w == '~')) && (*(w-1) != '\\') ) *w = ' '; w++; } isym++; while ((symv[ivc][isym].type != NOTE) && (isym= voice[ivc].nsym) { syntax("Too few notes for words",c1); break; } symv[ivc][isym].wordp[nwline] = add_wd(word); } if (*c == '\0') break; } nwline++; return 1; } /* ----- prsMusLine: parse a music line into symbols ----- */ int prsMusLine (line) char line[]; { char *F = "prsMusLine"; int type,num,nbr,n,itype,i; char msg[81]; char *p1,*pmx; if (ivc >= nvoice) bug ("Trying to parse undefined voice",1); nwline = 0; nsym0 = voice[ivc].nsym; nbr = 0; P = Q = line; // Positions in music line pmx = P+strlen(P); // End of music line while (*P != 0) { // End at null byte if (vb > 6) { int v, s; for (v = 0; v < nvoice; v++) { for (s = 0; s < voice[v].nsym; s++) { V8 "%s: Voice %d symv %d has ann !%s!\n",F,v,s,TextStr(symv[v][s].ann) V; } } } if (P>pmx) break; /* emergency exit */ V6 "%s: Parse \"%s\" <=========\n",F,P V; type = prsSym(); V3 "%s: Parsed sym type %d=%s.\n",F,type,SymName(type) V; n = voice[ivc].nsym; i = n-1; if (symv[ivc][i].ann) { V8 "%s: Voice %d sym %d has ann !%s!\n",F,ivc,i,TextStr(symv[ivc][i].ann) V; } else { V6 "%s: Voice %d sym %d has no annotation.\n",F,ivc,i V; // V6 "%s: Init annotation for voice %d sym %d.\n",F,ivc,i V; // TextInit(&symv[ivc][i].ann,64); /* So that messages don't bomb */ } V6 "%s: Voice %d sym %d code (%d,%d) !%s!\n",F,ivc,i,symv[ivc][i].type,symv[ivc][i].u,TextStr(symv[ivc][i].ann) V; if (vb > 6) { int v, s; for (v = 0; v < nvoice; v++) { for (s = 0; s < voice[v].nsym; s++) { V8 "%s: Voice %d symv %d has ann !%s!\n",F,v,s,TextStr(symv[v][s].ann) V; } } } if (type == NEWLINE) { if ((n>0) && !cfmt.continueall && !cfmt.barsperstaff) { symv[ivc][i].eoln = 1; if (word) { if (last_note >= 0) symv[ivc][last_note].word_end = 1; word = 0; } } } if (type == ESCSEQ) { if (db>3) V3 "%s: Handle escape sequence <%s>\n",F, escseq V; itype = info_field(escseq); V3 "%s: Info field is type %d.\n",F, itype V; handle_inside_field(itype); } if (type == REST) { if (pplet) { /* n-plet can start on rest */ symv[ivc][i].p_plet = pplet; symv[ivc][i].q_plet = qplet; symv[ivc][i].r_plet = rplet; pplet = 0; } last_note = i; p1 = P; } if (type == NOTE) { if (!word) { symv[ivc][i].word_st = 1; word = 1; } symv[ivc][i].slur_st += nbr; nbr = 0; if (voice[ivc].end_slur) symv[ivc][i].slur_end++; voice[ivc].end_slur = 0; if (pplet) { /* start of n-plet */ symv[ivc][i].p_plet = pplet; symv[ivc][i].q_plet = qplet; symv[ivc][i].r_plet = rplet; pplet = 0; } last_note = last_real_note = i; p1 = P; } /* for slurs into ending boxes */ if (type == BAR) { if (symv[ivc][i].v == 1) voice[ivc].rem_slur = voice[ivc].end_slur; if ((symv[ivc][i].v == 2)||(symv[ivc][i].u == B_RREP)|| (symv[ivc][i].u == B_DREP)) { voice[ivc].end_slur = voice[ivc].rem_slur; last_note = -1; } } if (word && ((type == BAR)||(type == SPACE))) { if (last_real_note >= 0) symv[ivc][last_real_note].word_end = 1; word = 0; } if (!type) { V6 "%s: *P=%02X='%c'\n",F,*P,*P V; if (*P == '-') { /* a-b tie */ if (last_note >= 0) symv[ivc][last_note].slur_st++; voice[ivc].end_slur = 1; P++; } elsif (*P == '(') { P++; if (isdigit(*P)) { pplet = *P-'0'; qplet = 0; rplet = pplet; P++; if (*P == ':') { P++; if (isdigit(*P)) { qplet = *P-'0'; P++; } if (*P == ':') { P++; if (isdigit(*P)) { rplet = *P-'0'; P++; } } } } else { nbr++; } } elsif (*P == ')') { if (last_note>0) { symv[ivc][last_note].slur_end++; } else { if (unexpsym != linenum) syntax("Unexpected symbol",P); unexpsym = linenum; } P++; } elsif (*P == '>') { num = 1; P++; while (*P == '>') { num++; P++; } if (last_note<0) syntax("No note before > sign", P); else double_note (last_note, num, 1, p1); } elsif (*P == '<') { num = 1; P++; while (*P == '<') { num++; P++; } if (last_note<0) syntax("No note before < sign", P); else double_note (last_note, num, -1, p1); } elsif (*P == '*') { /* ignore stars for now */ V3 "%s: Skip '*'\n",F V; P++; } elsif (*P == '!') { /* ditto for '!' */ V3 "%s: Skip '!'\n",F V; P++; } else { if (unexpsym != linenum) { if (*P != '\0') { sprintf (msg, "Unexpected symbol '%c'", *P); } else { sprintf (msg, "Unexpected end of line"); } syntax(msg, P); unexpsym = linenum; } P++; } } } /* maybe set end-of-line marker, if symbols were added */ n = voice[ivc].nsym; if (n > nsym0) { symv[ivc][n-1].eoln = 1; if (type == CONTINUE) symv[ivc][n-1].eoln = 0; if (cfmt.barsperstaff) symv[ivc][n-1].eoln = 0; if (cfmt.continueall) symv[ivc][n-1].eoln = 0; } /* break words at end of line */ if (word && (symv[ivc][n-1].eoln == 1)) { symv[ivc][last_note].word_end = 1; word = 0; } if (vb > 4) { int v, s; for (v = 0; v < nvoice; v++) { for (s = 0; s < voice[v].nsym; s++) { V8 "%s: Voice %d symv %d has ann !%s!\n",F,v,s,TextStr(symv[v][s].ann) V; } } } return TO_BE_CONTINUED; } /* ----- is_selected: check selection for current info fields ---- */ int is_selected (xref_str,npat,pat,select_all,search_field) int npat,select_all,search_field; char xref_str[],pat[][STRL1]; { int i,j,a,b,m; /* true if select_all or if no selectors given */ if (select_all) return 1; if (isblankstr(xref_str) && (npat == 0)) return 1; for (i = 0;i= 2)) m = match(info.title2,pat[i]); if ((!m) && (numtitle >= 3)) m = match(info.title3,pat[i]); if ((!m) && (numtitle >= 4)) m = match(info.title4,pat[i]); if ((!m) && (numtitle >= 5)) m = match(info.title5,pat[i]); if ((!m) && (numtitle >= 6)) m = match(info.title6,pat[i]); } if (m) return 1; } /* check xref against string of numbers */ P = xref_str; while (*P != 0) { parse_space(); a = prsUInt(); if (!a) return 0; /* can happen if invalid chars in string */ parse_space(); if (*P == '-') { P++; parse_space(); b = prsUInt(); if (!b) { if (xrefnum >= a) return 1; } else for (i = a;i <= b;i++) if (xrefnum == i) return 1; } else { if (xrefnum == a) return 1; } if (*P == ',') P++; } return 0; } /* ----- rehash_selectors: split selectors into patterns and xrefs -- */ int rehash_selectors (sel_str, xref_str, pat) char sel_str[], xref_str[]; char pat[][STRL1]; { char *F = "rehash_selectors"; char *q; char arg[501]; char *argz = arg+500; // Last byte of arg [jc] int i,npat; npat = 0; strcpy (xref_str, ""); q = sel_str; i = 0; while (1) { if ((*q == ' ') || (*q == '\0')) { arg[i] = '\0'; i = 0; if (!isblankstr(arg)) { if (arg[0] == '-') { /* skip any flags */ ; } elsif (is_xrefstr(arg)) { strcat(xref_str, arg); strcat(xref_str, " "); } else { /* pattern with * or + */ if ((strchr(arg,'*')) || (strchr(arg,'+'))) { strcpy(pat[npat],arg); } else { /* simple pattern */ strcpy(pat[npat],"*"); strcat(pat[npat],arg); strcat(pat[npat],"*"); } npat++; } } } else { if (i <= 500) { arg[i] = *q; i++; } else { // } } if (*q == '\0') break; q++; } return npat; } /* ----- decomment_line: cut off after % ----- */ void decomment_line (ln) char ln[]; { int i; for (i = 0;iv V; lp->l = l = strlen(lp->v); if (l>STRL) { if (verbose <= 2) fprintf(stderr,"\n"); fprintf(stderr,"+++ Line %d too long, truncate from %d to %d chars\n", linenum, l, STRL); l = STRL-1; lp->v[l] = '\0'; } if (is_end_line(lp->v)) { return 0; } if (lp->v[lp->l-1] == '\n') --lp->l; lp->v[lp->l] = '\0'; V3 "%s %3d \"%s\"\n",F,linenum,lp->v V; return 1; } /* ----- read_line: returns type of line scanned --- */ int read_line(fp,do_music,lp) FILE *fp; int do_music; Str *lp; { char *F = "read_line"; int type,nsym0; if (!get_line(fp,lp)) { V3 "%s: Return E_O_F=%d.\n",F,E_O_F V; return E_O_F; } V5 "%s Line=\"%s\"\n",F,lp->v V; if (isblankstr(lp->v)) return BLANK; if (is_pseudocomment(lp->v)) return PSCOMMENT; if (is_comment(lp->v)) return COMMENT; decomment_line(lp->v); if ((type = info_field(lp->v))) { V4 "%s Line type %d from info_field()\n",F,type V; /* skip after history field. Nightmarish syntax, that. */ if (type != HISTORY) { return type; } else { for (;;) { if (!get_line(fp,lp)) return E_O_F; if (isblankstr(lp->v)) return BLANK; if (is_info_field(lp->v)) break; add_text(lp->v, TEXT_H); } type = info_field(lp->v); V5 "%s Line type %d.\n",F,type V; return type; } } if (!do_music) return COMMENT; if (parse_vocals(lp->v)) return MWORDS; /* now parse a real line of music */ if (nvoice == 0) ivc = switch_voice(DEFVOICE); V3 "%s Voice %d.\n",F,ivc V; nsym0 = voice[ivc].nsym; V3 "%s Voice %d now has %d symbols.\n",F,ivc,nsym0 V; type = prsMusLine(lp->v); V3 "%s Parsed music symbols %d-%d for voice %d\n",F, nsym0,voice[ivc].nsym-1,ivc V; return type; } /* ----- do_index: print index of abc file ------ */ void do_index(fp,xref_str,npat,pat,select_all,search_field) FILE *fp; int npat,select_all,search_field; char xref_str[],pat[][STRL1]; { char *F = "do_index"; int type,within_tune; static Str iline = {0}; unless (iline.m) { unless (iline.v = (char*)malloc(BSIZE)) { V1 "%s: ### OUT OF MEMORY (Can't get %d for iline) ###\n",F,BSIZE V; return; } iline.m = BSIZE; } linenum = 0; verbose = vb; numtitle = 0; write_history = 0; within_tune = within_block = do_this_tune = 0; reset_info (&default_info); info = default_info; for (;;) { if (!get_line(fp,&iline)) break; if (is_comment(iline.v)) continue; decomment_line (iline.v); type = info_field(iline.v); switch (type) { case XREF: if (within_block) fprintf(stderr,"+++ Tune %d not closed properly \n", xrefnum); numtitle = 0; within_tune = 0; within_block = 1; ntext = 0; break; case MACRO: V2 "Macros not implemented yet.\n" V; break; case KEY: if (!within_block) { V3 "%s: Key not within block.\n",F V; break; } if (!within_tune) { V3 "%s: Key not within tune.\n",F V; tnum2++; if (is_selected (xref_str,npat,pat,select_all,search_field)) { fprintf(stderr," %-4d %-5s %-4s", xrefnum, info.key, info.meter); if (search_field == S_SOURCE) fprintf(stderr," %-15s", info.src); elsif (search_field == S_RHYTHM) fprintf(stderr," %-8s", info.rhyth); elsif (search_field == S_COMPOSER) fprintf(stderr," %-15s", info.comp[0]); if (numtitle == 6) fprintf(stderr," %s - %s - %s", info.title,info.title5,info.title6); if (numtitle == 5) fprintf(stderr," %s - %s", info.title, info.title5); if (numtitle == 4) fprintf(stderr," %s - %s", info.title, info.title4); if (numtitle == 3) fprintf(stderr," %s - %s", info.title, info.title3); if (numtitle == 2) fprintf(stderr," %s - %s", info.title, info.title2); if (numtitle == 1) fprintf(stderr," %s", info.title); if (verbose > 1) fprintf(stderr,"\n"); tnum1++; } within_tune = 1; } else { V3 "%s: Key within tune.\n",F V; } break; } if (isblankstr(iline.v)) { if (within_block && !within_tune) fprintf(stderr,"+++ Header not closed in tune %d\n", xrefnum); within_tune = 0; within_block = 0; info = default_info; } } if (within_block && !within_tune) fprintf(stderr,"+++ Header not closed in for tune %d\n", xrefnum); }