Comments on the coding of VAMP Stan Swanson, May 15, 2004 The code of VAMP is grouped into six files plus globals.c and globals.h. The liberal use of global variables is partly because the original code was split into six files from one, and partly due to my programming style, which prefers simple argument lists. There will be comments on some of the more important global variables below. In Linux there is a Makefile, and Windows requires only that the spawn of timidity be suppressed (see spawn_play() in vamp_midi.c). The six files are vamp_main.c -- parses input except for harmony and loops. vamp_harm.c -- parses harmony command and does analysis vamp_loops.c -- parses loop command and makes a midi file from it vamp_abc.c -- parses input "ABC" syntax for melody and vamp, deals with repeats ( see nextnote() and repeat_frags() ) vamp_midi.c -- generates MIDI output file ( most of the work is done in gen_midi_music_track() ) vamp_utils.c -- utilities for sorting, character input, token matching, file stacking, extracting notes in measures for harmony analysis... List of function declarations as of May 15, 2004 vamp_abc.c:9:void set_meter(void) /* look at line[] for meter info */ vamp_abc.c:23:void set_default_note(void) /* look for default note length */ vamp_abc.c:40:void set_key(void) /* look at line[] for key signature */ vamp_abc.c:115:int kromatic( int delta, int octave, char accidental) vamp_abc.c:135:int nextnote(int *tone, int *duration, int* vol) vamp_abc.c:230:void read_music(void) vamp_abc.c:292: int read_abc(int act, char* filnam) vamp_abc.c:311:void repeat_frags(void) vamp_harm.c:55:void print_all_chords(int tonic, int nchords) vamp_harm.c:98:int chord_number(char *gc) /* convert guitar chord string to internal code */ vamp_harm.c:107:void save_chord_scores(int meas, int *jot, int n) vamp_harm.c:115:void analyse_harmony(char *line) vamp_harm.c:270:int consonances(int nstart, int nend) vamp_harm.c:293:int find_center(int nstart, int nend, int meas, int tonic, int period, int verbose) vamp_harm.c:314:void set_chord_prefs(int tn) vamp_harm.c:387:int analyse_notes( int tonic, int verbose, int mode) vamp_harm.c:439:int print_chord_matches(int n, int *jot, float *dwells, int dur, vamp_harm.c:464:int calc_wt_sums(int *jot, float *dwells, int *diver, int *durat) vamp_harm.c:539:int test_all_chords(int tonic, int verbose, int mode) vamp_harm.c:569:int halfmeas(int ki, int kf) vamp_harm.c:691:int other_alg(int ki, int kf) vamp_harm.c:823:void print_stats(FILE *fo) vamp_loops.c:8:void print_help(void) /* print contents of help[] */ vamp_loops.c:15:void generate_loops(char *midiout) vamp_loops.c:126:void session_prefix(void) vamp_loops.c:151:int loop_in(void) vamp_main.c:7:void read_line(void) /* next_line handling indirect @ and EOF */ vamp_main.c:24:void parse_phrasing(char* id) vamp_main.c:115:int get_velocities(int evtype) /* determine velocity source for generated midi */ vamp_main.c:142:void parse_accent(char *id) vamp_main.c:197:int main(void) /* parses input and calls other routines */ vamp_midi.c:8:void lowendian(int n, char *in, char *out) vamp_midi.c:12:void intout(int i) vamp_midi.c:20:void shout(short sh) vamp_midi.c:28:void strout(char *str, int n) vamp_midi.c:34:void byteout(int v) /* positive byte output 0-127 */ vamp_midi.c:39:void delta(int v) /* MIDI variable count, eventually up to 128^4 - 1 */ vamp_midi.c:46:void command(int cmd, int chan, int note, int veloc) vamp_midi.c:53:void change(int cmd, int chan, int prog) vamp_midi.c:59:void midi_file_header(int org, int tracks, int delta_time, char *name) vamp_midi.c:78:void microseconds_in_beat(float bpm) vamp_midi.c:90:void midi_info(char *title) vamp_midi.c:152:int spawn_play(char *midifile) /* suppress system call for WINDOWS */ vamp_midi.c:175:void pack_event( int *kx, int ticks, int cmd, int chan, int d1, int d2) vamp_midi.c:185:int sort_gen_events(int *kx, int *previous, int now) vamp_midi.c:214:void set_dither(int blur) /* scaling parameters for dither */ vamp_midi.c:233:int dither(int n) /* (n==1) probably "melody", otherwise "chord" */ vamp_midi.c:249:void make_notes(int n, int *tones, int now, int dur, int vol, int chan) vamp_midi.c:264:int start_midi_music_track(int instrum, int chan, int chords) /* vamp_midi.c:318:int gen_midi_music_track(int npi, int npf, int chan, int chords) */ vamp_midi.c:441:int gen_midi_music_track(int npi, int npf, int chan, int chords) vamp_midi.c:547:int write_midi_music_track(void) vamp_midi.c:572:void gen_midi_frags(int kchunk, int chan, int chords, int coda) vamp_utils.c:8:void sort_i(int *v, int m) /* single array of integers */ vamp_utils.c:18:void sort_ii(int *v, int *u, int m) vamp_utils.c:26:void sort_dd(double *v, double *u, int m) vamp_utils.c:34:void print_help(void) /* print contents of help[] */ vamp_utils.c:39:void scan_list(int *list, char *buf) /* recover enumerated and for lists */ vamp_utils.c:53:int finstring(char *ch, int max, FILE *f) vamp_utils.c:64:int next_line(void) vamp_utils.c:71:int next_chr(void) /* next character in line, but don't over run */ vamp_utils.c:75:void deblank(void) vamp_utils.c:78:int get_integer(int *ival) /* convert digit string into decimal integer */ vamp_utils.c:85:void copy_line(void) /* make copy of line so find_token can put '\0' to end strings */ vamp_utils.c:88:void lower_the_case(char *s, char *d, int n) vamp_utils.c:99:char *find_token(char **start) vamp_utils.c:118:int match_token(char *token, char **list, int nlist, int exact) vamp_utils.c:138:int save_token(char *token, char **list, int *nlist) vamp_utils.c:151:char *make_id(char *token, char *prefix, int kount) vamp_utils.c:168:int stack_files(FILE* fi) vamp_utils.c:178:int pop_file(void) vamp_utils.c:184:int find_measures(int mel, int verbose) vamp_utils.c:271:int select_notes(int nstart, int nend, int period, int mode, int barbreak) vamp_utils.c:301:void select_accented(int beats) /* prune selected notes to accented ones */ vamp_utils.c:318:int abc_ticks(int ip, int lp) /* total abc duration tics[ip] ... tics[lp-1] */ vamp_utils.c:334:int pedometer(int dur) /* which step (beat) in phrase */ -------------------------------------------- Comments on globals.c, globals.h: /* limits for array sizes: most of these are explicitly checked when elements are added */ # define MAXOUT 50000 /* size of MIDI out buffer bout[] */ # define MXNOTE 4096 /* decoded abc stuff (melody, vamp, chords) */ # define MXLIST 23 /* maximum list elements +3 */ # define MAXIN 136 /* length of input buffers */ # define MXCHUNK 100 /* number of abc chunks input */ # define MXCHAR 1024 /* characters for string storage */ # define MXGC 2048 /* maximum characters in guitar chords */ # define MXACC 1024 /* accent entries for phrasing */ # define MXFRAG 1024 /* fragment storage (repeats, chord limits) */ # define MXVAR 100 /* events for program-variation */ # define MXPT 512 /* selected notes stone[], stick[] */ /* flags for syntax analysis and execution control: modified in main() */ int Q_META=1, Q_ABC=0, Q_PHRASE=0, Q_CHORD=0, Q_VAMP=0, Q_LOOP=0, Q_EVENT=0, Q_ACCENT=0, Q_EXPERT=0, V_CLASS=0, Q_VERBOSE=1, Q_PLAY=1, Q_BLUR=0, Q_TESTA=0, Q_TESTB=0, EXPAND_CHORDS=0; /* pseudo enums for abc syntactic constructs (non-notes) cf. nextnote() */ const int E_REST=128, E_KEY=-2, E_START_CHORD=-4, E_END_CHORD=-5, E_GUITAR_CHORD = -6, E_TIE = -7, E_BAR=-9, E_REP=-10, E_REP_1=-11, E_REP_2=-12, E_REP_last=-13; /* for chunk[].type */ const int T_MEL=1, T_VAMP=0, T_CHORD=2, T_ACCENT=-1, T_PHRASE=-2, T_SPECIAL=-4; char bout[MAXOUT]; /* MIDI output buffer (holds entire generated file) */ /* remember symbolic identifiers used in input */ char chunkname[MXCHUNK][8], sav_strings[MXCHAR], guitar_ch[MXGC], *tokens[MXCHUNK] = { "tune","chords"}; /* pitch[] and tics[] hold the decoded "ABC" input for melody and vamps */ int pitch[MXNOTE], tics[MXNOTE], scale[128]; int epoch[MXNOTE], event[MXNOTE], efirst[MXCHUNK],elast[MXCHUNK]; /* 031.29: a structure to handle named melodies, vamps, chord sequences and accents */ /* .ix and .lx may be offsets into data arrays, depending on .type */ struct {char* name; int type, count, ix, lx; } chunk[MXCHUNK]; /* 031.29 start:(stop+1) pairs for complicated chunks(count>0) */ /* melody fragments (if repeats), vamps referenced by chord sequence */ int kfrag=0, kev, frags[MXFRAG], jot[100]; /* pseudo enum for metacommand ID (== index postion of string) */ /* these are used in the top level parse switch in main() */ # define MC_QUIT 1 # define MC_MELODY 2 # define MC_VAMP 3 # define MC_CHORDS 4 # define MC_ACCENT 5 # define MC_VARIATION 6 # define MC_LOOP 7 # define MC_INSTRUM 8 # define MC_TEMPO 9 # define MC_GEN 10 # define MC_HARMONY 11 # define MC_REPEAT 12 # define MC_MIDI 13 # define MC_PARAM 14 # define MC_EVENT 15 # define MC_XTRA 16 # define MC_PHRASE 17 /* information from the accent and phrase commands goes into phrasing[] */ int phrasing[MXACC] = { 6,8, 0,0, 0,0, 8,8, /* [0:7] are default phrase chunk */ 120,1060,80,1060, 90,1060,80,1060, 100,1060,80,1060, 90,1060,80,1060 }; /* data arrays for the list command */ int accent_list[MXLIST] = {0,1,0,0}; /* {1,3,0,0,41,5} */ int key_list[MXLIST] = {0,1,0,0}; /* {0,1,0,60} */ int loop_list[MXLIST] = {0,1,0,1,2,3,4}; int instrument_list[MXLIST] = {0,5,0,111,1,25,72,106}; /* 031.09 fiddle,piano,guitar,clarinet,banjo */ /* int instrument_list[MXLIST] = {0,5,0,1,1,1,1,1}; */ /* 02x.06 all piano */ int veloc_list[MXLIST] = {0,4,0,2040,40,1040,40,20,10}; /* vel+2000 is major accent, vel+1000 is minor accent */ int rhythm_list[MXLIST] = {0,4,0,120,120,120,120}; int tone_list[MXLIST] = {0,4,0,0,4,7,5,12}; int controls[10][MXLIST]; /* control byte sequences */ int order_list[MXLIST] = {0,4,0, 0, 1, 2, 3 }; /* default r l a i */ /* stone[0..snotes], stick[] are used by the harmony analysis routines to hold notes and other ABC information for the current measure/half measure */ int nmeas, snotes, shalf, smeas, stone[MXPT], stick[MXPT]; /* bars holds indices and information about measure positions in the current melody */ struct { int s,h,e,t,m; } bars[MXPT]; /* flags for bars[].m */ # define B_LEN 1 /* nonstandard length != ticks_in_meas */ # define B_SPLIT 2 /* bad half measure split != duration_in_meas/2 */ # define B_REP 4 /* has repeat sign in measure |: or :| */ # define B_END 8 /* has alternate ending [1 [2 [3 */ # define B_KEY 16 /* key defined, redefined */