Some perhaps unreasonable limitations on the current code:
Meanwhile here is a crude synopsis of the program logic. There is considerable reliance on the logic described here; in particular the routine Read is used. For each MIDI file a structure of type piece is constructed. Within is a pointer to an array with an entry for each ‘time slot’. A time slot is a period of time of duration 2−(n+2) whole notes, where n is the first argument on the command line. An entry in the array becomes the head of a linked list of notes that begin in that time slot. An element of such a list is of type cn and holds a note value and duration. Most of the lists are empty.
The routine rex is called to report the first few chords of each piece. For each chord the first value is the number of whole notes from the beginning, followed by the MIDI note values of the chord. This has avoided many confusions. The scores for Bach’s works that I use, number the bars and in the common case of 4/4 time the bar number is one greater than the number of whole notes.
Then for each time slot with at least one non-empty list of notes two histograms are built, ka, kb for the two files, for that time slot. The subscript of the histogram is the note value. A report is made when the histograms disagree:
qn= time nv = freq; nc:nctime is the fractional whole note number at the discrepancy, freq is the MIDI note value, and the ncs are the respective histogram counts.
To compile and run the code put files r.c, mdif.c, and h.h in some new directory and in a command shell do:
gcc mdif.c r.c -fnested-functions -o mdif(I suspect that the “ -fnested-functions” may be and must be omitted on some platforms.) This places an executable file mdif in the new directory that can be run thus:
./mdif 3 X.mid Y.midto compare two MIDI files.