2024.03.18

This commit is contained in:
sshlien
2024-03-18 15:24:12 -04:00
parent 34f6ef01e2
commit cb0a6541f2
4 changed files with 88 additions and 30 deletions

View File

@@ -1,2 +1,2 @@
March 13 2024 March 18 2024

View File

@@ -1,16 +1,24 @@
.TH MIDISTATS 1 "18 February 2024" .TH MIDISTATS 1 "18 March 2024"
.SH NAME .SH NAME
\fBmidistats\fP \- program to summarize the statistical properties of a midi file \fBmidistats\fP \- program to summarize the statistical properties of a midi file
.SH SYNOPSIS .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 .SH DESCRIPTION
\fImidistats\fP analyzes the contents of a midi file and outputs key If you run midistats without any options other than the name of
information and various statistical measures. Each line of output the midi input file, it will produce a table of values described
starts with the name of the variable or variable array and the here. Each line of output starts with the name of the variable or
associated values. The output is interpreted by the user interface variable array and the associated values.
midiexplorer.tcl. Both programs are still being improved. Here
is an explanation of some of the output.
.PP .PP
ntrks indicates the number of tracks in the midi file. ntrks indicates the number of tracks in the midi file.
.PP .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 .PP
The MIDI file devotes channel 9 to the percussion instruments The MIDI file devotes channel 9 to the percussion instruments

View File

@@ -6,7 +6,7 @@ abc2abc version 2.21 February 19 2024
yaps version 1.93 February 19 2024 yaps version 1.93 February 19 2024
abcmatch version 1.83 February 19 2024 abcmatch version 1.83 February 19 2024
midicopy version 1.39 November 08 2022 midicopy version 1.39 November 08 2022
midistats version 0.89 March 13 2024 midistats version 0.90 March 18 2024
24th January 2002 24th January 2002
Copyright James Allwright Copyright James Allwright

View File

@@ -17,7 +17,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * 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 /* midistrats.c is a descendent of midi2abc.c which was becoming to
large. The object of the program is to extract statistical characterisitic large. The object of the program is to extract statistical characterisitic
@@ -95,6 +95,7 @@ int trackno;
int maintrack; int maintrack;
int format; /* MIDI file type */ int format; /* MIDI file type */
int debug; int debug;
int noOutput;
int pulseanalysis; int pulseanalysis;
int percanalysis; int percanalysis;
int percpattern; int percpattern;
@@ -133,6 +134,7 @@ int percpatternhist = 0;
int pitchclassanalysis = 0; int pitchclassanalysis = 0;
int nseqfor = 0; int nseqfor = 0;
int corestats = 0; int corestats = 0;
int noOutput = 0;
/* can cope with up to 64 track MIDI files */ /* 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); trkdata.rhythmpatterns[i] = count_patterns_for(i);
/* printf("%d ",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; divisionsPerBar = division*beatsPerBar;
unitDivision = divisionsPerBar/24; unitDivision = divisionsPerBar/24;
lasttrack = ntrks; /* [SS] 2023-10-25 */ lasttrack = ntrks; /* [SS] 2023-10-25 */
printf("ntrks %d\n",ntrks); if (noOutput == 0) printf("ntrks %d\n",ntrks);
printf("ppqn %d\n",ldivision); if (noOutput == 0) printf("ppqn %d\n",ldivision);
chordthreshold = ldivision/16; /* [SS] 2018-01-21 */ chordthreshold = ldivision/16; /* [SS] 2018-01-21 */
trkdata.tempo[0] = 0; trkdata.tempo[0] = 0;
trkdata.pressure[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.numberOfGaps[i] = 0; /* [SS] 2023-09-07 */
trkdata.chanvol[i] = 0; /* [SS] 2023-10-30 */ trkdata.chanvol[i] = 0; /* [SS] 2023-10-30 */
progcolor[i] = 0; progcolor[i] = 0;
channel2prog[i] = 0; /* [SS] 2023-06-25-8/ channel2prog[i] = 0; /* [SS] 2023-06-25-8*/
channel2nnotes[i] = 0; channel2nnotes[i] = 0;
chnactivity[i] = 0; /* [SS] 2018-02-02 */ chnactivity[i] = 0; /* [SS] 2018-02-02 */
} }
@@ -641,7 +642,6 @@ printf("collisions = %d\n",ncollisions);
if (hasLyrics) printf("Lyrics\n"); if (hasLyrics) printf("Lyrics\n");
stats_interpret_pulseCounter (); stats_interpret_pulseCounter ();
printf("\n"); printf("\n");
outputChannelSummary();
} }
@@ -711,10 +711,6 @@ for (i=1;i<17;i++) {
printf(" %f",trkdata.pitchEntropy[i]); printf(" %f",trkdata.pitchEntropy[i]);
} else } else
printf("-1 0"); 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); if (lasttrack > 1) printf(" %d %d %d\n",tracknm.zeroCount,tracknm.stepCount,tracknm.jumpCount);
else else
printf(" %d %d %d\n",nm[i-1].zeroCount,nm[i-1].stepCount,nm[i-1].jumpCount); 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; last_on_tick[i] = -1;
channel_active[i] = 0; 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<2048;i++) lastTick[i] = -1;
for (i=0;i<17;i++) channel_used_in_track[i] = 0; /* [SS] 2023-09-06 */ 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; if (chan == 9 || channel_used_in_track[chan+1] == 0) continue;
trkdata.pitchEntropy[chan+1] = histogram_perplexity(chanpitchhistogram +chan*12,11); 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 (program <0 || program > 127) return; /* [SS] 2018-03-06 */
if (trkdata.program[chan+1] != 0) { if (trkdata.program[chan+1] != 0) {
beatnumber = Mf_currtime/division; 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 */ /* count number of times the program was modified for a channel */
trkdata.program[0] = trkdata.program[0]+1; trkdata.program[0] = trkdata.program[0]+1;
} else { } 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; trkdata.program[chan+1] = program;
} }
if (channel2prog[chan+1]== 0) channel2prog[chan+1] = program; /* [SS] 2023-06-25*/ if (channel2prog[chan+1]== 0) channel2prog[chan+1] = program; /* [SS] 2023-06-25*/
@@ -1021,6 +1026,7 @@ char *mess;
int i; int i;
if (type == 5) hasLyrics = 1; /* [SS] 2023-10-30 */ if (type == 5) hasLyrics = 1; /* [SS] 2023-10-30 */
if (type != 3) return; if (type != 3) return;
if (noOutput == 1) return;
printf("metatext %d ",type); printf("metatext %d ",type);
for (i=0;i<leng;i++) printf("%c",mess[i]); for (i=0;i<leng;i++) printf("%c",mess[i]);
printf("\n"); printf("\n");
@@ -1042,9 +1048,11 @@ int sf, mi;
index = sf + 7; index = sf + 7;
if (index < 0 || index >12) return; if (index < 0 || index >12) return;
if (mi) 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 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; float beatnumber;
tempo = ltempo; tempo = ltempo;
beatnumber = Mf_currtime/division; 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); 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); 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; beatnumber = Mf_currtime/division;
while ( dd-- > 0 ) while ( dd-- > 0 )
denom *= 2; denom *= 2;
if (noOutput == 1) return;
printf("timesig %d/%d %6.2f\n",nn,denom,beatnumber); 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() { void outputChannelSummary() {
int i; int i;
printf("\nprograms: "); printf("programs: ");
for(i=1;i<17;i++) printf(" %d",channel2prog[i]); for(i=1;i<17;i++) printf(" %d",channel2prog[i]);
printf("\ncnotes: "); printf("\ncnotes: ");
for(i=1;i<17;i++) printf(" %d",channel2nnotes[i]); for(i=1;i<17;i++) printf(" %d",channel2nnotes[i]);
@@ -1375,6 +1403,8 @@ int i;
printf("\n"); printf("\n");
} }
void dualDrumPattern (int perc1, int perc2) { void dualDrumPattern (int perc1, int perc2) {
int i; int i;
int channel; int channel;
@@ -1723,6 +1753,13 @@ int argc;
if ((arg != -1) && (arg <argc)) { if ((arg != -1) && (arg <argc)) {
debug = readnum(argv[arg]); debug = readnum(argv[arg]);
} }
arg = getarg("-CSV",argc,argv);
if (arg != -1) {
noOutput = 1;
stats = 1;
}
arg = getarg("-pulseanalysis",argc,argv); arg = getarg("-pulseanalysis",argc,argv);
if (arg != -1) { if (arg != -1) {
pulseanalysis = 1; pulseanalysis = 1;
@@ -1816,6 +1853,7 @@ int argc;
printf("midistats version %s\n usage :\n",VERSION); printf("midistats version %s\n usage :\n",VERSION);
printf("midistats filename <options>\n"); printf("midistats filename <options>\n");
printf(" -corestats\n"); printf(" -corestats\n");
printf(" -CSV\n");
printf(" -pulseanalysis\n"); printf(" -pulseanalysis\n");
printf(" -panal\n"); printf(" -panal\n");
printf(" -ppat\n"); printf(" -ppat\n");
@@ -1843,7 +1881,9 @@ int argc;
initfunc_for_stats(); initfunc_for_stats();
Mf_getc = filegetc; Mf_getc = filegetc;
mfread(); mfread();
stats_finish(); if (noOutput == 0) stats_finish();
if (noOutput == 0) outputChannelSummary();
if (noOutput == 1) outputChannelSummaryCsv();
} }
void loadEvents() { void loadEvents() {