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