/* Copyright (c) 2002-2004 by Stanley M. Swanson.
Distributed under the GNU General Public License, version 2 (GPL v2). */
/* vamp_main.c parses incoming commands and calls other routines */
# include "globals.h"
void read_line(void) /* next_line handling indirect @ and EOF */
{ int n,k;
while (1) { filin = fin[at_file]; n = next_line();
if (at_file>0) printf("%s\n",line);
if (n==0) continue;
if (n<0) { k = pop_file(); if (k<0) exit(0); continue; }
/* need to worry about EOF on indirect container contents */
if (flog) fprintf(flog,"%s\n",line);
deblank(); /* or enforce % as first chars ? */
if (cur_chr != '@') return;
/* new_file() strips the leading '@' */
filin = new_file(line+lch,"r"); k = stack_files(filin); continue;
}/* while (1) */
} /* read_line() */
int add_event( int r, int m, int t, int k, int type, int data)
{ int n;
if (kev>MXVAR-2) { printf("********too many events %d\n",kev+1); over_flows++; }
else { /* sort by time and enter */ n = kev; kev++;
for ( ; n>0; n--) { if (events[n-1].rep0) { i = dyn_value[j]; tok = find_token(&tok_start); dyn_rep = 1;
if (i<0) { dyn_mode = -i; dyn_notes = 1; dyn_music = 0; }
else { dyn_notes = 0; if (!dyn_mode) printf("dyn mode undefined\n");
if (i==0) { /* "instrument nnn" */ n = sscanf(tok,"%d",&i);
tok = find_token(&tok_start); }
instrument_list[dyn_voice+3] = i; instrument_list[1] = dyn_voice += 1;
for (n=0; n=0) handle instrument start */
} /* if (j>0) special initial "word" */
if (dyn_notes) { /* melody, chords, or dynamics */
if (dyn_mode<3)
{ while (tok) { if (tok[0]=='%') break;
k = match_token(tok,tokens,-chunks,1);
if (k>0) { jot[dyn_music] = k; jot[dyn_music+1] = dyn_rep;
type = chunk[k].type;
if (type==T_MEL && dyn_mode==2 || type==T_CHORD && dyn_mode==1)
printf("dyn: mixed modes %d %d \n",dyn_mode,type);
dyn_rep++; if (dyn_music<96) dyn_music += 2; }
else { n = sscanf(tok,"%d",&j);
if (n<=0) { printf("dyn: undefined symbol %s\n",tok); error_count++; }
else if(j>0) dyn_rep += j-1; }
tok = find_token(&tok_start);
} /* while (tok) {mel,chord} */
} else { /* dynamics */
while (tok) { if (tok[0]=='%') break;
k = match_token(tok,dyn_vel,9,1);
if (k>0) { data = 16*k - 8; }
else if (tok[0]=='v')
{ n = sscanf(tok+1,"%d",&data); if (n>0) k = 10; }
if (k>0) { r = dyn_rep; dyn_rep++;
add_event(r,-1,-1,-MC_ACCENT,T_SPECIAL,data); }
else { n = sscanf(tok,"%d",&j);
if (n<=0) { printf("dyn: bad dynamic level %s\n",tok); error_count++; }
else if(j>0) dyn_rep += j-1; }
tok = find_token(&tok_start);
} /* while (tok) {velocity} */
} /* else dynamics */
} else { /* instrument accent data */
while (tok) { if (tok[0]=='%') break;
k = match_token(tok,tokens,-chunks,1);
if (k>0) { type = chunk[k].type; r = dyn_rep; dyn_rep++;
if (type!=T_ACCENT && dyn_mode==2 || type!=T_PHRASE && dyn_mode==1)
printf("dyn: mixed accents %d %d voice %d \n",dyn_mode,type,dyn_voice);
add_event(r,-1,-1,k,type,dyn_voice); }
else { n = sscanf(tok,"%d",&j);
if (n<=0) { printf("dyn: undefined symbol %s\n",tok); error_count++; }
else if(j>0) dyn_rep += j-1; }
tok = find_token(&tok_start);
} /* while (tok) {accents} */
}
} /* parse_dyn() */
int get_velocities(int evtype); /* determine velocity source for generated midi */
void parse_phrasing(char* id)
{ int i,j,k,m,n,vol,oldvol,isvol,minus,defer, kp;
char *token3, *token1=id, *token;
/* init stuff */
token3 = make_id(token1,"phrase",phrase_count);
k = chunks; save_token(token3,tokens,&k);
if (Q_VERBOSE>6 && V_CLASS==1)
printf(" chunk %d %s %s %s lch %d\n",chunks,chunkname[chunks],token3,
tokens[chunks],lch);
chunk[chunks].name = tokens[chunks];
if (Q_VERBOSE>1 && V_CLASS==1) printf(" phrase id %s\n",token3);
chunk[chunks].type = T_PHRASE;
kp = efirst[chunks] = chunk[chunks].ix = macc; /* save current beginning*/
/* pointers: ip, lp, iv, lv, it, lt : phrase lengths, volume changes, timing changes */
phrasing[kp+2] = phrasing[kp+3] = phrasing[kp+4] = phrasing[kp+5] = 0;
macc += 6; iphrase = phrasing[kp] = phrasing[kp+1] = macc;
nbeat = current_beat = 0;
/* line loop stuff ... does not allow indirect references within command data */
i = -1; minus = 0; defer = 0;
vol = oldvol = mix_mel; /* default initial approx ff */ isvol = j = 0;
while (1) { next_line();
if (at_file>0) printf("%s\n",line); if (flog) fprintf(flog,"%s\n",line);
deblank();
/* end of "phrase" command */
if (cur_chr=='/')
{ if (line[lch+1]!='p') printf(" wrong meta terminator (phrase)\n");
if (macc==iphrase) { /* no data, default to 8 */ phrasing[macc] = 8; macc++; }
if (current_beat>0) macc++; /* missing ';' */
if (Q_VERBOSE>1 && V_CLASS==1)
{ for (k=iphrase; k0) { for (k=0; k1 && V_CLASS==1) printf(" %d",jot[k]); }
if (Q_VERBOSE>1 && V_CLASS==1) printf("\n");
idyn = phrasing[kp+2] = m; ldyn = phrasing[kp+3] = macc; }
get_velocities(T_MEL); /* test */
if (macc>=MXACC) { printf("******* too much phrase info\n"); over_flows++;
if (flog) fprintf(flog,"******* too much phrase info\n"); }
if (Q_VERBOSE>1 && V_CLASS==1)
printf("phrasing iphrase %d lphrase %d last %d\n",iphrase,m,phrasing[m-1]);
chunk[chunks].lx = macc; chunk[chunks].count = 0;
last_phrase = chunks; chunks++;
Q_PHRASE = 0; Q_META = 1; return;
}
/* WARNING: deldown, delup, deloff are not archived or restored by "gen" */
if (cur_chr=='[') /* single line "[ deldown delup deloff ]" */
{ n = sscanf(line+lch+1," %d %d %d", &deldown, &delup, &deloff);
printf("new delta veloc: %d down, %d up, %d offbeat\n",
deldown,delup,deloff); continue;
}
/* decode phrase syntax here... n ; v.. <> + - t.. */
/* volume change recorded immediately except after < or >
when we defer until after the next beat count to allow for
something other than the default +16 or -16 (eg. f to ff, etc.) */
while (cur_chr>0)
{ deblank(); if (cur_chr=='%' || cur_chr==0) break;
switch (cur_chr) {
case ';': if (current_beat>0) { macc++; current_beat = minus = 0; }
else printf(" zero beat count at %d beats\n",nbeat);
next_chr(); break;
case '<': vol += 16; defer = 1; next_chr(); break;
case '>': vol -= 16; defer = 1; next_chr(); break;
case '-': minus = 1; next_chr(); break;
case 'm': next_chr(); if (cur_chr=='p') { vol = 56; next_chr(); }
else if (cur_chr=='f') { vol = 72; next_chr(); }
else printf("%c not mf or mp\n",cur_chr);
isvol = 1; break;
case 'f': vol = 72; while (cur_chr=='f') { vol += 16; next_chr(); }
isvol = 1; break;
case 'p': vol = 56; while (cur_chr=='p') { vol -= 16; next_chr(); }
isvol = 1; break;
case 'v': next_chr(); k = get_integer(&i); if (k>0) { vol = i; isvol = 1; } break;
default: k = get_integer(&i);
if (k>0) { if (minus) { nbeat -= i; phrasing[macc] = (current_beat -= i); minus = 0; }
else { nbeat += i; phrasing[macc] = (current_beat += i); }
if ((oldvol != vol) && defer ) /* end of volume ramp: < or > */
{ jot[j] = nbeat; jot[j+1] = oldvol = vol; j += 2; defer = isvol = 0; } }
else { if (cur_chr>0) printf("error in phrase parse, cur_chr== %c\n",cur_chr); }
} /* switch (cur_chr) */
if (vol<0) vol = 0; /* 045.29 defer (vol>127) to make_notes() */
if ((oldvol != vol) || isvol) { isvol = 0; /* record delta volume or change initial vol. */
if (defer) { jot[j] = nbeat; jot[j+1] = oldvol; j += 2; }
else { if (nbeat>0) {jot[j] = nbeat; jot[j+1] = oldvol; j += 2; }
jot[j] = nbeat; jot[j+1] = oldvol = vol; j += 2; } }
} /* while (cur_chr !=0, !='%' */
} /* while (1) ... line looping */
} /* parse_phrasing() */
int get_velocities(int evtype) /* determine velocity source for generated midi */
{ int j,k,nb=0,v,vb,vbn,vn; float den=1.0;
if (idyn>0) { /* for melody or dance emphasis (rep==0) */
for (k=iphrase; k2 && V_CLASS==1)
printf(" %d beats in get_velocities iphrase %d lphrase %d\n",nb,iphrase,lphrase);
j = idyn; vb = vbn = phrasing[j]; vn = v = phrasing[j+1]; j += 2;
if (vb>0) vb = 0; /* take first explict volume level to start */
else if (j2 && V_CLASS==1)
printf(" vb %3d v %3d vbn %3d vn %3d k %2d j %2d den %f\n",vb,v,vbn,vn,k,j,den);
for (k=0;k=vbn) { vb = vbn; v = vn;
if (j=ldyn) { vbn = nb; break; }
if (j2 && V_CLASS==1)
printf(" vb %3d v %3d vbn %3d vn %3d k %2d j %2d den %f\n",vb,v,vbn,vn,k,j,den); }
veloc[k] = v + (k-vb)*(vn-v)*den; }
if (Q_VERBOSE>2 && V_CLASS==1) { for (k=0;k0) */
if (evtype==T_MEL) { if (idyn>0) return 2; else return 0; /* melody */ }
else if (evtype==T_CHORD || evtype==T_VAMP) { return 1; /* accent for chords or vamp */ }
else if (evtype==T_PHRASE) { return nb; }
else { printf("bad event type %d in get_velocities\n",evtype); return 0; }
} /* get_velocites() */
void parse_accent(char *id)
{ int i,j,k,m,n,vol,stac,voice;
char *token3;
/* init stuff */
kacc = macc; /* save current beginning*/
token3 = make_id(id,"accent",accent_count);
if (Q_VERBOSE>1 && V_CLASS==1) printf(" accent id %s\n",token3);
k = chunks; save_token(token3,tokens,&k);
if (Q_VERBOSE>2 && V_CLASS==1)
printf(" chunk %d %s %s %s lch %d\n",chunks,chunkname[chunks],token3,
tokens[chunks],lch);
chunk[chunks].name = tokens[chunks]; chunk[chunks].type = T_ACCENT;
efirst[chunks] = chunk[chunks].ix = macc;
/* line loop stuff ... does not allow indirect references within command data */
stac = voice = 0; vol = -1;
while (1) { next_line(); deblank();
if (at_file>0) printf("%s\n",line); if (flog) fprintf(flog,"%s\n",line);
if (cur_chr=='/')
{ if (line[lch+1]!='a') printf(" wrong meta terminator (accent)\n");
if (kacc==macc) { phrasing[macc] = mix_ch; macc++; /* no data */ }
lacc = k = macc; iacc = kacc;
if (macc>=MXACC) { printf("******* too many accents\n"); over_flows++;
if (flog) fprintf(flog,"******* too many accents\n"); }
if (Q_VERBOSE>2 && V_CLASS==1)
{ for (k=iacc; k0)
{ deblank();
if (cur_chr=='%' || cur_chr==0) break;
if (cur_chr=='{')
{ next_chr(); deblank(); k = get_integer(&i); deblank();
if (k>0 && cur_chr=='}')
{ voice = i; if (voice>16) voice = 16; next_chr(); deblank(); }
else printf(" bad voice syntax %c voice %d\n",cur_chr,i);
}
/* 043.02 use leading "..." to be consistent with abc staccato */
/* k = get_integer(&i); deblank(); */
stac = 0; while (cur_chr=='.') { stac++; next_chr(); }
k = get_integer(&i);
if (k>0) { if (i>999) voice = stac = 0;
/* 046.08 defer to make_notes() else if (i>127) i = 127; */
phrasing[macc] = 1000*(10*voice + stac) + i;
macc++; voice = stac = 0; i = -1; }
else { printf("error in accent parse, cur_chr== %c\n",cur_chr);
next_chr(); }
} /* while (cur_chr>0) */
} /* while (1) ... line looping */
} /* parse_accent() */
char copy_phrase[MAXIN], scratch[16];
int track[20];
int main(void)
{ int i,j,k,m,n,tone,dur,vol,accent=0,meas,delay,patch,chan;
int ncs, midi_out_number=0, iblnk, knt, parts;
short s; float fval;
char *token, *token1, *token2, *token3,
filnam[MAXIN], i4[4], j4[4], i2[2], j2[2], comchr;
printf("vamp (c) 2002-2004 Stanley M. Swanson; licensed GPL v2\n"
" compiled on %s\n",__DATE__);
if (Q_VERBOSE>1) printf(" restricted to one metacommand per line\n");
i = 6; lowendian(4,(char*)&i,i4); if (i4[3] != 6) qswap = 0;
if (Q_VERBOSE>1) printf(" %d %d midi out: byte swap %d \n",i4[0],i4[3],qswap);
session_prefix();
nstr = 0; /* put metacommands into token list */
while (metacmd[nstr]) { tokens[nstr] = metacmd[nstr];
nstr++; if (nstr>=MXMETA) { nstr=MXMETA; break; } }
n_meta = nstr;
Q_META = 1; Q_ABC = Q_VAMP = Q_CHORD = Q_ACCENT = Q_PHRASE = Q_LOOP = 0;
/* 045.30 chord velocity attenuation [make_notes()], accent compensation */
Q_TESTA = 8; Q_TESTB = 0;
/* initially assume smallest note is 1/8, key==C */
total_ticks = npitch = nbeat = 0;
tone = key = 60; /* midi middle C */
/* set_key() to C-natural */
for (i=2,k=0; k<13; i++, k+=2)
{ if (i==5) k--; else if (i==9) k--;
whitenote[i] = kromote[i] = barnote[i] = k; }
barnote[0] = whitenote[0] = kromote[0] = kromote[7];
barnote[1] = whitenote[1] = kromote[1] = kromote[8]; /* A, B */
measure = chordflag = 0; /* count of bars, chord brackets [] */
tictoc = ticks_in_meas = 0; /* cumulative duration within measure */
quarterticks = 120; bpm = 120.0; staccato = 0;
quantum = 60; /* midi clock ticks each default note */
ticks_in_meas = quantum; /* 046.08 prevent div by zero */
tuple_count = broken_rhythm = 0; tuple_p = tuple_q = tuple_r = 1;
/* tuples, dotted notes, etc. 020.11 */
for (k=0;k0) printf("%s\n",line);
if (n==0) continue;
if (n<0) { k = pop_file(); if (k<0) exit(0); continue; }
/* need to worry about EOF on indirect container contents */
if (flog) fprintf(flog,"%s\n",line);
deblank(); /* or enforce % as first chars ? */
/* first check for file indirection or comment */
if (cur_chr=='@')
{ if (Q_ABC) /* 035.26 scan for one melody by index */
{ copy_line(); token = token1 = NULL;
token = find_token(&tok_start); abc_index = 0;
if (token) { token1 = find_token(&tok_start);
if (token1) { n = sscanf(token1," %d",&abc_index); }
filin = new_file(token+1,"r"); k = stack_files(filin); }
else continue;
if (abc_index>0) /* discard until X:abc_index found */
{ while (1) { n = next_line(); if (n<0) break;
if (line[0]=='X' && line[1]==':')
{ k = 0; n = sscanf(line+2," %d",&k);
if (n>0 && k==abc_index) break; } } }
continue; }
filin = new_file(line+lch,"r"); k = stack_files(filin);
/* new_file() deblanks and strips a leading '@' */
continue; }
if (cur_chr=='%') { continue; /* 029.21 do not hide % */ }
if (cur_chr=='#') { /* 037.30 check for #Copyright, #(C) */
lower_the_case(line+1,scratch,10);
if (strncmp("(c)",scratch,3)==0 || strncmp("copyright",scratch,9)==0)
{ strcpy(copy_phrase,line+1); copyleft = copy_phrase; continue; }
if (commenta[0]==0) strcpy(commenta,line);
else if (commentb[0]==0) strcpy(commentb,line); continue; /* comment */}
if (Q_META==1) { /* search for initial meta command string */
k = -1; iblnk = -1; comchr = cur_chr;
for (i=1;i7 && V_CLASS==1) printf("k %d cmd[k] %s \n",j,metacmd[k]);
switch (k) {
case MC_QUIT:
if (error_count>0 || over_flows>0) {
printf("ERRORS %d buffer overflows %d\n",error_count,over_flows);
if (flog) fprintf(flog,"ERRORS %d buffer overflows %d\n",error_count,over_flows); }
exit(0); /* quit program */
case MC_MELODY: /* [m-id] */ melody_count++;
Q_ABC = -1; efirst[0] = npitch; n_meas_tick = 0; last_tone = -20;
krep = 1; /* point to repetition syntax */
abc_index = 0; /* 035.26 search @file.abc for X: */
tonal_center = key_major = mode_delta = 0;
for (k=0; k<25; k++) doremi[k] = 0;
for (k=0; k<27; k++) intervals[k] = 0;
token3 = make_id(token1,"tune",melody_count);
k = chunks; save_token(token3,tokens,&k);
if (Q_VERBOSE>4 && V_CLASS==1) printf(" chunk %d %s %s %s lch %d\n",
chunks,chunkname[chunks],token3,tokens[chunks],lch);
chunk[chunks].name = tokens[chunks]; chunk[chunks].type = T_MEL;
efirst[chunks] = chunk[chunks].ix = rep_mark[0] = npitch;
if (Q_VERBOSE>2 && V_CLASS==1)
printf(" melody id %s\n",token3);
Q_META = 0;
break;
case MC_REPEAT: /* */ repeats = 1;
n = sscanf(line+iblnk,"%d",&k); if (n>0 && k>0) repeats = k;
scan_list(loop_list,line+iblnk);
if (Q_VERBOSE>2 && V_CLASS==1) printf(" repeats %d \n",repeats);
break;
case MC_TEMPO: /* bpm [ticks] */
n = sscanf(line+iblnk," %f %d",&fval,&j);
if (n>0) bpm = fval;
/* ONLY allow quarterticks to change before abc data read */
if (n>1 && melody_count==0 && vamp_count==0 ) quarterticks = j;
printf(" %g bpm, ticks per quaternote %d \n",
bpm,quarterticks);
break;
case MC_GEN: j = lch;
lch = iblnk; cur_chr =line[lch]; deblank();
chordflag = 0; /* default melody */
for (k=0;k<17;k++) track[k] = 0; master_volume = mix_mel; volume_delta = 0;
/* for (k=0;k<4;k++) printf("chunk %d %s first %d last %d\n",
k,chunk[k].name,efirst[k],elast[k]); */
/* bug in end of tune abc */
/* if (elast[0]==efirst[0]) elast[0] = efirst[2]; */
if (Q_VERBOSE>4 && V_CLASS==1) printf("lch %d curchr %c line %s\n",lch,cur_chr,line);
if (!token1) {
printf("counts: melody %d chord %d accent %d vamp %d phrase %d\n",
melody_count, chord_count, accent_count, vamp_count, phrase_count);
if (last_mel>-1) printf("melody: %s ",tokens[last_mel]);
if (last_chord>-1) printf("chords: %s ",tokens[last_chord]);
if (last_accent>-1) printf("accent: %s ",tokens[last_accent]);
if (last_phrase>-1) printf("phrase: %s ",tokens[last_phrase]);
printf(" [defaults]\n");
break; }
/* look for isolated digit (old style "gen n file") */
if ((cur_chr=='0' || cur_chr=='1' || cur_chr=='2') && line[lch+1]==' ')
{ char *file; int chords, koda;
parts = cur_chr - '0'; k = 2; if (parts>1) k = 3;
next_chr(); deblank(); file = line+lch;
if (Q_VERBOSE>6 && V_CLASS==1) printf(" voice %d file |%s|\n",chordflag,line+lch);
if (cur_chr!='>' && cur_chr != 0)
{ if (line[j]=='>') line[j] = 0; } else { ncs = dot_sess;
sprintf(session+ncs,"%4d",ksession+1000);
session[ncs]='.'; ksession++; file = session; }
midi_file_header(1,k,quarterticks,file);
midi_info(title); k = last_intro;
if (parts!=1)
{ start_midi_music_track(instrument_list[3], 0, 0);
if (last_intro>0)
{ pedometer(-1); gen_midi_frags(last_intro,1,-1,0); }
if (last_mel>0)
{ chords = get_velocities(T_MEL); pedometer(-1); koda = 0;
for (k=0; k0)
{ start_midi_music_track(instrument_list[4], 1, 1);
if (last_intro>0)
{ pedometer (-1); gen_midi_frags(last_intro,1,-1,0); }
if (last_chord>0)
{ chords = get_velocities(T_CHORD); pedometer(-1); koda = 0;
for (k=0; k16) ktr = 0;
if (er>lastrep) lastrep = er;
if (er==(-1) && et==T_VAMP)
{ kp = 1; kpot = events[k].chunk; }
if (et==T_MEL) { km++; track[ktr]++; }
else if (et==T_CHORD) { kc++; track[ktr]++; }
else if (et==T_ACCENT) { ka++; i = events[k].chunk; track[ktr]++;
if (er<0) { kacc = iacc = chunk[i].ix; lacc = chunk[i].lx;
printf("accent event %d %d\n",iacc,lacc); }
else if (ispec<0) ispec = k; }
else if (et==T_PHRASE) { ka++; i = events[k].chunk; track[ktr]++;
if (er<1) { kk = chunk[i].ix;
kphrase = iphrase = phrasing[kk]; lphrase = phrasing[kk+1];
kdyn = idyn = phrasing[kk+2]; ldyn = phrasing[kk+3];
/* printf("phrase event %d %d dyn %d %d\n",iphrase,lphrase,idyn,ldyn); */
if (er==0 && idyn>0 && ed==0) { /* all-track dance emphasis */ track[ktr]--;
n_emph0 = get_velocities(T_PHRASE);
if(n_emph0>MXPT-1) { printf("n_emph0 %d too large \n",n_emph0); n_emph0 = MXPT; over_flows++;}
for (j=0;j0) printf(" km %d kc %d kp %d ka %d kv %d kpot %d last rep %d\n",
km,kc,kp,ka,kv,kpot,lastrep);
/* old way: ktr = 2; if (km>0 && kc>0) ktr = 3; */ /* number of tracks */
if (track[0]>0) printf("%d unspecified tracks\n",track[0]);
ktr = 1; for (k=1; k<17; k++) if (track[k]>0) ktr++;
printf(" number of midi music tracks is %d\n",ktr-1);
if (ktr<2) break;
midi_file_header(1,ktr,quarterticks,token1);
midi_info(title);
/* specified tracks (0:melody, 1:chords is default) 042.20 */
for (ii=1; ii<17; ii++) if (track[ii]>0)
{ chan = ii-1; chord = 1; koda = 0; knote_mm = 0;
master_volume = ivol; volume_delta = 0;
start_midi_music_track(instrument_list[3], chan, chord);
if (kp) { pedometer(-1); gen_midi_frags(kpot,chan,-1,koda); } /* potatoes */
i = -1; koda = 0; k = 0; idyn = ldyn = 0;
n_emph = n_emph0; if (n_emph>0) for (j=0;j0) { /* track dance emphasis */ n_emph = get_velocities(T_PHRASE);
if(n_emph>MXPT-1) { printf("n_emph %d too large \n",n_emph); n_emph = MXPT; over_flows++;}
for (j=0;j2) printf("<<<<< event %d rep %d type %d melody %d \n",k,ir,et,i); */
if (Q_VERBOSE>2)
printf("<<<<< event %d rep %d type %d ivol %d deltav %d \n",k,ir,et,ivol,volume_delta);
k++; if (k==kev) break; } /* while (rep<=ir) */
if (i<0 ) { printf("******* no music for rep %d\n", ir);
error_count++; continue; }
/* 039.12 set coda for medleys, if melody changes next rep */
if (ir==lastrep) koda = 1; else koda = 0;
if (chord==0) {
for (kk=k; kkir+1) break;
if (events[kk].chunk != i) koda = 1; }
} /* if (chord==0) */
pedometer(-1); if ((chord==0 || chord==2) && idyn>0)
{ chord = get_velocities(T_MEL);
if (Q_VERBOSE>1 && V_CLASS==1)
printf(" chord %d idyn %d ldyn %d kdyn %d\n",chord,idyn,ldyn,kdyn); }
gen_midi_frags(i,chan,chord,koda); /* think about medley */
if (Q_VERBOSE>2)
printf("generated epoch %d measures %d\n",gen_epoch,gen_epoch/ticks_in_meas);
} /* for (ir) */
write_midi_music_track();
} /* for (ii) loop tracks */
if (fout){ fclose(fout); spawn_play(token1); }
/* restore pointers for accent, phrase, and dynamics */
iacc=siacc; lacc=slacc; iphrase=siphr; lphrase=slphr; idyn=sidyn; ldyn=sldyn;
} /* generate file [wrt. event list] no digit between "gen" and "file" */
if (error_count>0 || over_flows>0) { printf("ERRORS %d\n",error_count);
if (over_flows>0) printf("buffer overflows %d\n",over_flows);
if (flog) fprintf(flog,"ERRORS %d\n",error_count); }
commenta[0] = commentb[0] = kc = 0; break;
case MC_HARMONY: j = 0; /* 030.07 if (last_mel<0) break; */
analyse_harmony(line); break;
lower_the_case(line,token_buf,MAXIN);
printf("%s\n%s\n",line,token_buf);
if(token1) k = sscanf(token1," %d",&j); if (k==0) j = 0;
k = 0; if (j<0) { j = -j; k = 1; } /* verbose if (j<0) */
find_chord(efirst[last_mel],elast[last_mel],tune_tonic,j,k);
print_stats(stdout); break;
case MC_INSTRUM: if (token1) { scan_list(instrument_list,line+iblnk); }
else { for (j=0; j */ chord_count++;
efirst[1] = npitch;
token3 = make_id(token1,"chords",chord_count);
k = chunks; save_token(token3,tokens,&k);
if (Q_VERBOSE>4 && V_CLASS==1)
printf(" chunk %d %s %s %s lch %d\n",chunks,chunkname[chunks],token3,
tokens[chunks],lch);
chunk[chunks].name = tokens[chunks]; chunk[chunks].type = T_CHORD;
efirst[chunks] = npitch; chunk[chunks].ix = npitch;
chunk[chunks].lx = kfrag; /* save initial fragment position */
if (Q_VERBOSE>2 && V_CLASS==1) printf(" chord id %s\n",token3);
Q_CHORD = 1; Q_META = 0; break;
case MC_VAMP: /* vamp */
Q_VAMP = 1; Q_META = 0; break;
case MC_PARAM: /* param */
k = sscanf(line+iblnk," %d %d %d %d %d %d ",
&stac_mel, &stac_ch, &mix_mel, &mix_ch, &pan_mel, &pan_ch);
printf("%d new parameters: stac %d %d mix %d %d pan %d %d\n",
k, stac_mel, stac_ch, mix_mel, mix_ch, pan_mel, pan_ch);
break;
case MC_XTRA: /* extra parameters */
k = sscanf(line+iblnk," %d %d %d %d %d %d", &Q_VERBOSE, &Q_BLUR,
&Q_TESTA, &Q_TESTB, &trans_mel, &trans_ch);
if (k>0) { if (Q_VERBOSE<0) { Q_PLAY = 0; Q_VERBOSE = -Q_VERBOSE; } else Q_PLAY = 1;
if (Q_VERBOSE>99) { Q_EXPERT = 1; Q_VERBOSE %= 100; } else Q_EXPERT = 0;
V_CLASS = Q_VERBOSE/10; Q_VERBOSE %= 10; }
/* V_CLASS is used to confine Q_VERBOSE to regions of code: 0 general,
1 input (main), 2 input (abc), 3 utilities, 4 output (midi), 5 harmony, 6 loops, 7-9 debug */
/* Q_EXPERT may be used to hide some advanced or experimental functions from ordinary users */
i = Q_VERBOSE + 10*V_CLASS + 100*Q_EXPERT; if (!Q_PLAY ) i = -i;
printf("%d xtra parameters: verbose[-noplay] %d blur %d testa,b %d %d transpose %d %d\n",
k, i, Q_BLUR, Q_TESTA, Q_TESTB, trans_mel, trans_ch);
break;
default: printf("unhandled option %s\n",line);
} /* switch (k) */
} else { /* here if in specific meta command */
if (Q_ABC)
{ if (cur_chr=='/' ) /* now 'melody' instead of 'abc' */
{ if (line[lch+1]!='m') printf(" wrong meta terminator (melody)\n");
tune_tonic = tonic; /* problems with key change! 038++ E_KEY */
tune_tonic = key_major; /* 038.16 key signature determines chords */
print_stats(stdout);
/* ... use harmony to get this info ... 035.16
find_chord(efirst[0],npitch,tune_tonic,0,1); */
chunk[chunks].lx = npitch; chunk[chunks].count = 0;
elast[chunks] = elast[0] = npitch; last_mel = chunks;
repeat_frags();
chunks++;
Q_ABC = 0; Q_META = 1; continue;
} /* (cur_chr=='/') */
read_abc(0,NULL); elast[0] = npitch;
}
else if (Q_VAMP)
{
if (cur_chr=='/' )
{ if (line[lch+1]!='v') printf(" wrong meta terminator (vamp)\n");
Q_VAMP = 0; Q_META = 1; continue; }
if (cur_chr=='L' && line[1]==':') { set_default_note(); continue; }
if (cur_chr=='K' && line[1]==':') { set_key(); continue; }
copy_line(); token = find_token(&tok_start);
if (!token) continue; /* blank line */
/* 035.16 CHECK for unique ID, looking backwards from most recent */
m = match_token(token,tokens,-chunks,1);
if (m>0) { printf("vamp name not unique, replacing %d\n",m); }
k = chunks; save_token(token,tokens,&k); last_vamp = k;
if (!strcmp(token,"intro") ) { last_intro = chunks;
printf("intro vamp at chunk %d\n",last_intro); }
lch = tok_start - token_buf; cur_chr = line[lch];
if (Q_VERBOSE>2 && V_CLASS==1)
printf(" chunk %d %s %s %s lch %d\n",chunks,chunkname[chunks],
token,tokens[chunks],lch);
chunk[chunks].name = tokens[chunks]; chunk[chunks].type = T_VAMP;
efirst[chunks] = npitch; chunk[chunks].ix = npitch;
read_music(); /* get abc chord encoding for measure */
/* 030.19: error if no abc ??? */
elast[chunks] = npitch; chunk[chunks].lx = npitch; chunk[chunks].count = 0;
if (Q_VERBOSE>2 && V_CLASS==1)
printf("chunk %d %s %s start %d end %d\n",chunks,chunkname[chunks],tokens[chunks],
efirst[chunks],elast[chunks]);
if (chunks1 && V_CLASS<2) { for (k=0;k 400.0) f = bpm; data = 1000.0*f; }
/* 045.03 supress _instr_ else if (token1[1]=='i') { k = -MC_INSTRUM; */
else if (token1[1]=='v') { k = -MC_ACCENT;
if (token2) n = sscanf(token2," %d", &data);
if (n==0 || data<0) data = mix_mel; /* master volume */ }
else { k = -MC_PARAM; /* ignore */ data = -1;
printf("unrecognized special event %s\n",token1); }
} else { data = 0; k = match_token(token1,tokens,-chunks,1);
if (k<=0) { printf(" event not found (%d) for %s\n",k,token1); error_count++;
type = T_SPECIAL; k = -MC_PARAM; /* ignore */ data = -1; }
else { type = chunk[k].type; /* establish default tracks */
if (type==T_MEL) data = 1;
else if (type==T_CHORD) data = 2; else if (type==T_ACCENT) data = 2;
else if (type==T_PHRASE) { if (r>0) data = 1; else data = 0;} }
/* 043.01 do not recall why this done...(restrict to reps?) m = 0; */
if (token2) n = sscanf(token2," %d", &d);
if (n>0 && (d>=0 && d<16) ) data = d; /* user specified voice (track) */
/* 045.30 voice 0, rep 0 is global phrasing (dance emphasis) */
/* error if out of bounds ??? or catch in gen with track==0 ??? */
}
if (V_CLASS==1 && Q_VERBOSE>2)
printf("event %d.%d.%d %s k %d type %d data %d\n",r,m,t,token1,k,type,data);
add_event(r, m, t, k, type, data ); }
} /* local scope for event line decode */
}
else if (Q_LOOP)
{
if (cur_chr=='/')
{ if (line[lch+1]!='l') printf(" wrong meta terminator (loop)\n");
Q_LOOP = 0; Q_META = 1; continue; }
loop_in();
}
else printf("no container flag set\n");
} /* end of meta/container scan (top-level) */
} /* while (1) */
/* end loop generation */
} /* main() */