diff --git a/VERSION b/VERSION index 12d0787..5b1363d 100644 --- a/VERSION +++ b/VERSION @@ -1,2 +1,2 @@ -March 13 2024 +March 18 2024 diff --git a/doc/midistats.1 b/doc/midistats.1 index 8dceca0..f95b8a0 100644 --- a/doc/midistats.1 +++ b/doc/midistats.1 @@ -1,16 +1,24 @@ -.TH MIDISTATS 1 "18 February 2024" +.TH MIDISTATS 1 "18 March 2024" .SH NAME \fBmidistats\fP \- program to summarize the statistical properties of a midi file .SH SYNOPSIS -midistats \fIinfile\fP +This is a long manual because the program extracts many different parameters +from the midi file depending upon the options selected. This manual +attempts to describe these parameters and how they are computed. +These parameters are formatted in a way so they can be read by other +applications such midiexplorer.tcl, runstats.tcl, and numerous Python +scripts. + +Many of the options were designed specifically for analyzing the +percussion track of the midi file. They are described in a separate +section below (Other options). + .SH DESCRIPTION -\fImidistats\fP analyzes the contents of a midi file and outputs key -information and various statistical measures. Each line of output -starts with the name of the variable or variable array and the -associated values. The output is interpreted by the user interface -midiexplorer.tcl. Both programs are still being improved. Here -is an explanation of some of the output. +If you run midistats without any options other than the name of +the midi input file, it will produce a table of values described +here. Each line of output starts with the name of the variable or +variable array and the associated values. .PP ntrks indicates the number of tracks in the midi file. .PP @@ -164,7 +172,17 @@ programcmd - there may be multiple program changes in a midi channel -.SH Advanced Percussion Analysis Tools +.SH Other options + +It is recommended that you only select one of the options +described here as the program was not designed to handle a +multiple number of options. + +.PP +If you run midistats with the -CSV option, it will return the +results in a form of comma separated values that can be loaded +into a Python panda dataframe. Each line refers to one of the +16 midi channels. .PP The MIDI file devotes channel 9 to the percussion instruments diff --git a/doc/readme.txt b/doc/readme.txt index cf45a49..bb2b7c7 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -6,7 +6,7 @@ abc2abc version 2.21 February 19 2024 yaps version 1.93 February 19 2024 abcmatch version 1.83 February 19 2024 midicopy version 1.39 November 08 2022 -midistats version 0.89 March 13 2024 +midistats version 0.90 March 18 2024 24th January 2002 Copyright James Allwright diff --git a/midistats.c b/midistats.c index 243171d..dddce7c 100644 --- a/midistats.c +++ b/midistats.c @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#define VERSION "0.89 March 13 2024 midistats" +#define VERSION "0.90 March 18 2024 midistats" /* midistrats.c is a descendent of midi2abc.c which was becoming to large. The object of the program is to extract statistical characterisitic @@ -95,6 +95,7 @@ int trackno; int maintrack; int format; /* MIDI file type */ int debug; +int noOutput; int pulseanalysis; int percanalysis; int percpattern; @@ -133,6 +134,7 @@ int percpatternhist = 0; int pitchclassanalysis = 0; int nseqfor = 0; int corestats = 0; +int noOutput = 0; /* can cope with up to 64 track MIDI files */ @@ -301,7 +303,6 @@ for (i = 0; i<17; i++) { trkdata.rhythmpatterns[i] = count_patterns_for(i); /* printf("%d ",count_patterns_for (i)); */ } -printf("\n"); } @@ -466,8 +467,8 @@ void stats_header (int format, int ntrks, int ldivision) divisionsPerBar = division*beatsPerBar; unitDivision = divisionsPerBar/24; lasttrack = ntrks; /* [SS] 2023-10-25 */ - printf("ntrks %d\n",ntrks); - printf("ppqn %d\n",ldivision); + if (noOutput == 0) printf("ntrks %d\n",ntrks); + if (noOutput == 0) printf("ppqn %d\n",ldivision); chordthreshold = ldivision/16; /* [SS] 2018-01-21 */ trkdata.tempo[0] = 0; trkdata.pressure[0] = 0; @@ -481,7 +482,7 @@ void stats_header (int format, int ntrks, int ldivision) trkdata.numberOfGaps[i] = 0; /* [SS] 2023-09-07 */ trkdata.chanvol[i] = 0; /* [SS] 2023-10-30 */ progcolor[i] = 0; - channel2prog[i] = 0; /* [SS] 2023-06-25-8/ + channel2prog[i] = 0; /* [SS] 2023-06-25-8*/ channel2nnotes[i] = 0; chnactivity[i] = 0; /* [SS] 2018-02-02 */ } @@ -641,7 +642,6 @@ printf("collisions = %d\n",ncollisions); if (hasLyrics) printf("Lyrics\n"); stats_interpret_pulseCounter (); printf("\n"); -outputChannelSummary(); } @@ -711,10 +711,6 @@ for (i=1;i<17;i++) { printf(" %f",trkdata.pitchEntropy[i]); } else printf("-1 0"); - nm[i].quietTime += trkdata.quietTime[i]; - nm[i].used = channel_used_in_track[i]; - trkdata.quietTime[i] = 0; /* in case channel i is used in another track */ - trkdata.numberOfGaps[i] = 0; if (lasttrack > 1) printf(" %d %d %d\n",tracknm.zeroCount,tracknm.stepCount,tracknm.jumpCount); else printf(" %d %d %d\n",nm[i-1].zeroCount,nm[i-1].stepCount,nm[i-1].jumpCount); @@ -745,7 +741,7 @@ void stats_trackstart() last_on_tick[i] = -1; channel_active[i] = 0; } - printf("trk %d \n",tracknum); + if (noOutput == 0) printf("trk %d \n",tracknum); for (i=0;i<2048;i++) lastTick[i] = -1; for (i=0;i<17;i++) channel_used_in_track[i] = 0; /* [SS] 2023-09-06 */ @@ -764,7 +760,16 @@ void stats_trackend() if (chan == 9 || channel_used_in_track[chan+1] == 0) continue; trkdata.pitchEntropy[chan+1] = histogram_perplexity(chanpitchhistogram +chan*12,11); } - output_track_summary(); +if (noOutput == 0) output_track_summary(); +output_hasher_results(); +for (i=0;i<17;i++) { + if(trkdata.notecount[i] == 0 && trkdata.chordcount[i] == 0) continue; + nm[i].quietTime += trkdata.quietTime[i]; + nm[i].used = channel_used_in_track[i]; + trkdata.quietTime[i] = 0; /* in case channel i is used in another track */ + trkdata.numberOfGaps[i] = 0; + channel2nnotes[i] += trkdata.notecount[i] + trkdata.chordcount[i]; + } } @@ -985,11 +990,11 @@ int beatnumber; if (program <0 || program > 127) return; /* [SS] 2018-03-06 */ if (trkdata.program[chan+1] != 0) { beatnumber = Mf_currtime/division; - printf("cprogram %d %d %d\n",chan+1,program,beatnumber); + if (noOutput == 0) printf("cprogram %d %d %d\n",chan+1,program,beatnumber); /* count number of times the program was modified for a channel */ trkdata.program[0] = trkdata.program[0]+1; } else { - printf("program %d %d\n",chan+1,program); + if (noOutput == 0) printf("program %d %d\n",chan+1,program); trkdata.program[chan+1] = program; } if (channel2prog[chan+1]== 0) channel2prog[chan+1] = program; /* [SS] 2023-06-25*/ @@ -1021,6 +1026,7 @@ char *mess; int i; if (type == 5) hasLyrics = 1; /* [SS] 2023-10-30 */ if (type != 3) return; +if (noOutput == 1) return; printf("metatext %d ",type); for (i=0;i12) return; if (mi) - printf("keysig %s %d %d %6.2f\n",minor[index],sf,mi,beatnumber); + if (noOutput == 0) + printf("keysig %s %d %d %6.2f\n",minor[index],sf,mi,beatnumber); else - printf("keysig %s %d %d %6.2f\n",major[index],sf,mi,beatnumber); + if (noOutput == 0) + printf("keysig %s %d %d %6.2f\n",major[index],sf,mi,beatnumber); } @@ -1056,9 +1064,10 @@ long ltempo; float beatnumber; tempo = ltempo; beatnumber = Mf_currtime/division; + trkdata.tempo[0]++; + if (noOutput == 1) return; if (trkdata.tempo[0] == 0) printf("tempo %6.2f bpm\n",60000000.0/tempo); else if (trkdata.tempo[0] < 10) printf("ctempo %6.2f %6.2f\n",60000000.0/tempo,beatnumber); - trkdata.tempo[0]++; } @@ -1070,6 +1079,7 @@ int nn, dd, cc, bb; beatnumber = Mf_currtime/division; while ( dd-- > 0 ) denom *= 2; + if (noOutput == 1) return; printf("timesig %d/%d %6.2f\n",nn,denom,beatnumber); } @@ -1347,12 +1357,30 @@ printf("\n"); +void outputChannelSummaryCsv() { +FILE *f; +int i; +int spread; +/*f = fopen("channelDescriptor.csv","w");*/ +f = stdout; +fprintf(f,"programs,cnotes,nnotes,nzeros,nsteps,njumps,rpats,pavg,spread\n"); +for (i = 1; i<17; i++) { + if (nm[i].used > 0) spread = (100*(trkdata.npulses[0] - nm[i].quietTime)/trkdata.npulses[0]); + else spread=0; + fprintf(f,"%d,%d,%d,%d,%d,%d,%d,%d,%d\n",channel2prog[i],channel2nnotes[i],nm[i-1].totalNotes,\ + nm[i-1].zeroCount,nm[i-1].stepCount,nm[i-1].jumpCount,\ + trkdata.rhythmpatterns[i],nm[i-1].totalPitches/(1+nm[i-1].totalNotes),\ + spread); + } +//fclose(f); +} + void outputChannelSummary() { int i; - printf("\nprograms: "); + printf("programs: "); for(i=1;i<17;i++) printf(" %d",channel2prog[i]); printf("\ncnotes: "); for(i=1;i<17;i++) printf(" %d",channel2nnotes[i]); @@ -1375,6 +1403,8 @@ int i; printf("\n"); } + + void dualDrumPattern (int perc1, int perc2) { int i; int channel; @@ -1723,6 +1753,13 @@ int argc; if ((arg != -1) && (arg \n"); printf(" -corestats\n"); + printf(" -CSV\n"); printf(" -pulseanalysis\n"); printf(" -panal\n"); printf(" -ppat\n"); @@ -1843,7 +1881,9 @@ int argc; initfunc_for_stats(); Mf_getc = filegetc; mfread(); -stats_finish(); +if (noOutput == 0) stats_finish(); +if (noOutput == 0) outputChannelSummary(); +if (noOutput == 1) outputChannelSummaryCsv(); } void loadEvents() {