/* 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() */