/* Copyright (c) 2002-2003 by Stanley M. Swanson.
Distributed under the GNU General Public License, version 2 (GPL v2). */
/* vamp_abc.c from midivamp.c 035.26 */
# include "globals.h"
void set_meter(void) /* look at line[] for meter info */
{ int i,k; char ch;
lch = 2; while ((ch=line[lch])==' ') lch++; /* remove blanks */
/* meter_num is numerator of meter, meter_denom is denominator */
meter_num = meter_denom = 4; /* defaults */
if (ch==0) return;
if (ch=='C')
{ if (line[lch+1]=='|') meter_num = meter_denom = 2; return; }
/* caution.... code works only on single digits */
if (ch>'0' && ch<='9') { meter_num = ch - '0'; lch +=2; ch = line[lch];
if (ch>'0' && ch<='9') { meter_denom = ch - '0'; } }
printf(" meter %d/%d \n",meter_num,meter_denom);
}
void set_default_note(void) /* look for default note length */
{ int i,k; char ch; default_note = 8;
quantum = (quarterticks*4)/default_note;
/* denominator of default note length (presume numerator==1) */
lch = 2; while (line[lch]==' ') lch++; /* remove blanks */
if (line[lch]==0) return; /* look for slash */
while (line[lch]!='/') { if (line[lch]==0) return; lch++; }
ch = line[lch+1];
if (ch>'0' && ch<='9') { default_note = ch - '0'; }
ch = line[lch+2];
if (ch>'0' && ch<='9') { default_note = 10*default_note + ch - '0'; }
quantum = (quarterticks*4)/default_note;
printf("default note: 1/%d quantum ticks %d\n",default_note,quantum);
} /* set_default_note */
int kromatic( int delta, int octave, char accidental);
void set_key(void) /* look at line[] for key signature */
{ char keych, mc, mb=' ',ch; int delta;
char sharps[7]= {'C','G','D','A','E','B','F' };
char flats[7] = {'C','F','B','E','A','D','G' };
int i,k,m,nsharp=0,nflat=0;
/* construct lookup table to cope with key intervals */
lch = 2; cur_chr=line[lch]; deblank(); /* remove blanks */
keych = toupper(cur_chr); next_chr(); deblank();
if (cur_chr=='#' || cur_chr=='b')
{ mb = cur_chr; next_chr(); deblank(); }
/* minors and various modes 036.20 */
tonal_center = mode_delta = 0; /* C major default */
mc = tolower(cur_chr);
if (mc=='i') { mode_delta = 0; /* ionian,major */ }
else if (mc=='d') { mode_delta = 2; /* dorian */ }
else if (mc=='p') { mode_delta = 4; /* phrygian */ }
else if (mc=='l') { mode_delta = 5; /* lydian */
next_chr(); ch = tolower(cur_chr);
if (ch=='o') mode_delta = 11; /* locrian */ }
else if (mc=='m') { mode_delta = 9; /* minor */
next_chr(); next_chr(); ch = tolower(cur_chr);
if (ch=='j') mode_delta = 0; /* major */else
if (ch=='x') mode_delta = 7; /* mixolydian */ }
else if (mc=='a') { mode_delta = 9; /* aeolian, minor */ }
else { if (mc!=0 && mc!='%')
printf("questionable mode character %c %d\n",mc,mc); }
/* first do C-natural */
for (i=2,k=0; k<13; i++, k+=2)
{ if (i==5) k--; else if (i==9) k--; kromote[i] = k; }
kromote[0] = kromote[7]; kromote[1] = kromote[8]; /* A, B */
for (i=0; i<10; i++) whitenote[i] = kromote[i]; /* save c-natural */
delta = keych - 'C';
tonic = whitenote[delta+2];
if (mb=='b') tonic--; else if (mb=='#') tonic++;
if (tonic<0) tonic += 12; else if (tonic>11) tonic -= 12;
tonal_center = tonic;
key_major = tonal_center - mode_delta;
if (key_major<0) key_major += 12;
printf("tonal_center %d mode_deltat %d key_signature %d\n",
tonal_center, mode_delta, key_major);
/* then sequentially sharp or flat notes */
/* works for major, but not easily compatible with other modes 036.21 */
/* else if (mb=='b' && nflat>0)
{ for (k=0,i=1; k6) i -= 7; kromote[i]--; } }
else if (nsharp>0)
{ for (k=0,i=5; k5) k++; k /=2; k +=2; /* get starting index relative to C */
delta = k; if (delta>6) delta -= 7; keych = 'A' + delta;
for (i=2; i<9; i++,k++)
{ m = key_major + whitenote[i]; /* printf(" i %d k %d m %d \n",i,k,m); */
if (k>6) k -= 7; if (m>11) m -= 12;
kromote[k] = m; if (k+7<9) kromote[k+7] = m; }
for (i=0; i<9; i++) barnote[i] = kromote[i]; /* 030.20 accidentals */
for (i=0;i<7;i++) printf(" %2d",kromote[i]);
pitch[npitch] = E_KEY; tics[npitch] = tonic + 100*mode_delta;
npitch++; /* 035.26 remember key 036.20 center and mode */
/* if (keych=='F' && mb!='#') mb = 'b'; */
/* obsolete 036.21 one flat rather than 6 sharps */
for (i=0;i<7;i++) { if (keych==sharps[i]) nsharp = i;
if (keych==flats[i]) nflat = i; }
printf(" set_key %c%c sharps %d flats %d\n",keych,mb,nsharp,nflat);
} /* set_key() */
int kromatic( int delta, int octave, char accidental)
{ int note, white, kode = delta+2;
/* delta is note letter - 'C'; will be negative for A, B */
note = kromote[kode]; white = whitenote[kode];
/* 031.29: change handling of accidentals to one note only */
/* if (accidental=='^') note++; else if (accidental=='_') note--;
else if (accidental=='=') printf(" IGNORING NATURAL\n"); */
/* key specified global accidentals from kromote[] are used
unless a specific accidental is given, which is relative to whitenotes[] */
note = barnote[kode]; /* 030.20 accidental scope == measure */
if (accidental=='^') { note = barnote[kode] = white+1; }
else if (accidental=='_') { note = barnote[kode] = white-1; }
else if (accidental=='=') { note = barnote[kode] = white; }
/* 032.05 problem with note = white++, white-- */
/* octave is 60 for C...B, 72 for c...b, etc. : sum gives MIDI note */
return note + octave;
} /* kromatic() */
int nextnote(int *tone, int *duration)
{ int ich,octave,note=0,delta,i,k; char ch,chn='1',chd='1',cha=' ';
while (line[lch]==' ') lch++; ich = lch; ch = line[ich];
if (ch==0) return 0; /* end of line */ lch++;
if (ch=='%') return 0; /* comment for rest of line */
if (ch=='|') { /* measure bar */ ch = line[lch]; if (tictoc>0) measure++;
if (ch=='1' || ch=='2' || ch=='3') { /* abbreviated repeat endings */
lch--; line[lch] = '['; /* expand and catch next time */ }
for (i=0; i<9; i++) barnote[i] = kromote[i]; /* 030.20 accidentals */
*tone = E_BAR; *duration = measure; return E_BAR; }
/* 028.25 add chord brackets and extended octave range */
/* interpret bracketing at call level */
/* 032.23 need to characterize right and left repeats here [: |: :] :| :: */
if (ch=='[') { ch = line[lch];
if (ch=='1' || ch=='2' || ch=='3') { /* standard repeat endings */
k = E_REP - (ch-'0'); lch++; *tone = *duration = k; return k; }
if (ch==':') /* right repeat [: */
{ k = E_REP; lch++; *tone = *duration = k; return k; }
*tone = *duration = E_START_CHORD; return E_START_CHORD; } /* begin chord bracket */
if (ch==']') { *tone = *duration = E_END_CHORD; return E_END_CHORD; } /* end chord bracket */
if (ch==':') { *tone = *duration = E_REP; return E_REP; } /* repeat */
/* 038.08 tie notes, presently ignored in midi generation */
if (ch=='-') { *tone = *duration = E_TIE; return E_TIE; }
if (ch=='(') { /* tuple [assume no slurs], only handle "(3" for now 020.11 */
ch = line[lch]; lch++;
if (ch!='3')
{ printf("nextnote: unacceptable tuple (%c \n",ch); error_count++; }
else { tuple_p = tuple_r = tuple_count = 3; tuple_q = 2;
while (line[lch]==' ') lch++; ch = line[lch]; lch++; }
} /* ch=='(' triple */
/* order of symbols for single note:
> */
if (ch=='"') { /* guitar chord */ ch = line[lch]; k = ixgch;
while (ch!='"') { guitar_ch[k] = ch; if (k6 && V_CLASS==2) printf(" guitarchord %s\n",guitar_ch+ixgch);
*tone = E_GUITAR_CHORD; *duration = ixgch; ixgch = k; return E_GUITAR_CHORD;
} /* if (ch=='"') scan off guitar chord */
if (ch=='^' || ch=='_' || ch=='=') /* accidentals: sharp, flat, natural */
{ cha = ch; ch = line[lch]; lch++;
if (Q_VERBOSE>2 && V_CLASS==2) printf("accidental %c note %c\n",cha,ch); }
if (ch>='A' && ch<='G') { note=5; delta = ch - 'C'; }
/* depends on ascii char values */
else if (ch>='a' && ch<='g'){ note=6; delta = ch - 'c'; }
else if (ch=='z' || ch=='Z') note= E_REST;
if (note) { octave = 12*note; ch = line[lch]; /* essentially peek_char() */
/* octave modifiers */ /* 028.25 extend range: A,,, to g'' */
if (ch==',') { octave -= 12; lch++; ch = line[lch];
if (ch==',') { octave -= 12; lch++; ch = line[lch];
if (ch==',') { octave -= 12; lch++; ch = line[lch]; }
} } /* allow down to A,,, */
else if ( ch=='\'') { octave += 12; lch++; ch=line[lch];
if ( ch=='\'') { octave += 12; lch++; ch=line[lch]; }
} /* allow up to g'' */
/* 020.11: add a>b, ab and complicated tuples */
if (broken_rhythm) { k = broken_rhythm; broken_rhythm = 0; }
else if (ch=='<') { k = quantum/2; broken_rhythm = quantum + k; lch++; }
else if (ch=='>') { broken_rhythm = quantum/2; k = quantum + broken_rhythm; lch++; }
else { /* handle various multipliers and divisors */
if (ch>='2' && ch<='8') { chn = ch; lch++; ch = line[lch]; }
if (ch=='/') { chd = '2'; lch++; ch = line[lch];
if (ch>='2' && ch<='8') { chd = ch; lch++; } }
k = (quantum*(chn - '0'))/(chd - '0');
if (tuple_count) { k = (k*tuple_q)/tuple_p; tuple_count--;
if (tuple_count<1) { tuple_p = tuple_q = tuple_r = 1; tuple_count = 0; } }
} /* end of multiplier and divisor section */
*duration = k;
tictoc += k; /* cumulative duration in measure */
/* 031.29 problems within chord brackets for true duration */
/* translate letter note into midi note value, using key info */
if (note=0 && Q_VERBOSE>=4 && V_CLASS==2)
printf(" note %3d duration %d \n",tone,dur);
pitch[npitch] = tone; tics[npitch] = dur;
epoch[npitch] = total_ticks; total_ticks += dur; event[npitch] = tone;
if (tone<=E_REP && tone>=E_REP_last) /* pointers to repetition info 032.20 */
{ rep_mark[krep] = npitch; if (krep<20) krep++; }
if (tone>0 && tone0 && last_tone24) k = 25;
if (Q_ABC) intervals[k]++; } last_tone = tone;
/* 038.16 change base of doremi to key_major
rather than tonic == tonal_center */
if (Q_ABC) { k = (tone - key_major + 12) %12; doremi[k]++;
doremi[k+12] += dur; doremi[24] += dur; }
} /* (tone>0) */
if (npitch0){ if (Q_VERBOSE>1 && V_CLASS==2)
printf("measure %3d notes %4d duration %4d\n",
measure,previ,tictoc);
m = -1; for (k=0; k=0) meas_tick_count[m]++;
else { m = n_meas_tick; if (m<6) { meas_tick[m] = tictoc;
meas_tick_count[m] = 1; n_meas_tick++; }
else printf("more than 6 measure durations\n"); }
} /* (tictoc>0) */
if (tictoc>ticks_in_meas) ticks_in_meas = tictoc; tictoc = 0;
} /* if (tone == E_BAR ... ) */
} /* while (3) note scan */
} /* read_music() */
/* read .abc file to get both pitch contour and rhythm */
int read_abc(int act, char* filnam)
{ int i,j,k,m,n,tone,dur;
/* need to catch blank line at end of music in indirect file */
if (line[0]=='%') return 0; /* comment line */
if (line[1]==':' && line[0]>='A' && line[0]<='Z')
{ if (Q_VERBOSE>6 && V_CLASS==2) printf("info %s\n",line);
if (abc_index && line[0]=='X') pop_file(); /* 035.26 */
if (line[0]=='K') set_key();
if (line[0]=='M') set_meter();
if (line[0]=='L') set_default_note();
if (line[0]=='T') { i = strlen(line+2); strncpy(title,line+2,i+1); }
} else { if (Q_VERBOSE>6 && V_CLASS==2) printf("music %s \n",line);
read_music();
}
return total_ticks;
} /* read_abc() */
/* convert rep_mark[0:krep] to fragments for current melody */
void repeat_frags(void)
{ int i,j,k,m, ip,lp, ticks, kr, ki, kf = kfrag, klast=0, mark[20];
if (krep<2) { if (Q_VERBOSE>2 && V_CLASS<3) printf("no repeat structure\n"); return; }
lp = rep_mark[0] /* efirst[chunks] */ ; kr = 0; rep_mark[krep] = npitch; mark[krep] = E_BAR;
/* rep_mark[0] is initial item, rep_mark[krep] is last+1; count ticks between marks */
for (k=1; k=0) ticks += tics[i]; */
ticks += abc_ticks(ip,lp); jot[k] = ticks;
if (Q_VERBOSE>2 && V_CLASS==2)
printf("position %3d E_REP mark %3d delta ticks %5d\n",lp,pitch[lp],ticks); }
/* allow only two patterns "[: :]" and "[: [1 :] [2" ; supply missing initial [: */
i = kr&1; if (mark[1]==E_REP && i==0) ki = 1; else { ki = 0; mark[0] = E_REP;
if (Q_VERBOSE>2 && V_CLASS<3) printf("missing initial repeat supplied\n"); }
if ((i && ki) || (i==0 && ki==0))
printf("repeat count %d and initial repeat %d inconsistent\n",kr,ki);
if (i==0 && jot[1]>0) printf(" lead-in of %d ticks\n",jot[1]);
/* check for legal patterns */
for (k=ki; kMXFRAG) { printf("*****insufficient space in repeat_frags() %d\n",kfrag);
if (flog) fprintf(flog,"*****insufficient space in repeat_frags() %d\n",kfrag);
over_flows++; return; }
frags[kf] = rep_mark[0]; frags[kf+1] = npitch; frags[kf+2] = frags[kf+3] = 0; kf += 2;
frags[kf] = rep_mark[0]; kf++;
for (k=ki; k1 && V_CLASS<3) printf("repeat_frags: krep %d k %d\n",krep,k);
if (k==krep) { frags[kf] = rep_mark[krep]; kf++; }
for (k=kfrag; k1 && V_CLASS<3)
printf("frag %2d position: initial %4d final %4d\n",(k-kfrag)/2,frags[k],frags[k+1]);
chunk[chunks].ix = kfrag; chunk[chunks].lx = kf;
k = kf - kfrag; if (klast) k -= 2; chunk[chunks].count = k;
kfrag = kf;
} /* repeat_frags() */