From e49858809aacc136fa20d7efd307e5f23b90cc50 Mon Sep 17 00:00:00 2001 From: Seymour Shlien Date: Wed, 15 Mar 2023 08:11:05 -0400 Subject: [PATCH] 2023.03.15 --- VERSION | 3 +- doc/drums.txt | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ doc/midistats.1 | 11 +++++++ midistats.c | 66 ++++++++++++++++++++++++++------------- 4 files changed, 139 insertions(+), 23 deletions(-) create mode 100755 doc/drums.txt diff --git a/VERSION b/VERSION index 81b90ad..09011b5 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,2 @@ -February 08 2023 - +March 15 2023 diff --git a/doc/drums.txt b/doc/drums.txt new file mode 100755 index 0000000..b92e7a9 --- /dev/null +++ b/doc/drums.txt @@ -0,0 +1,82 @@ +Advamced Percussion Analysis +in the Midistats Program + +This is an addendum to the midistats.1 file. + +The MIDI file devotes channel 9 to the percussion instruments +and over 60 percussion instruments are defined in the MIDI +standard. Though there is a lot of diversity in the percussion +track, for most MIDI files only the first 10 or so percussion +instruments are important in defining the character of the track. The +program Midiexplorer has various tools for exposing the percussion +channel which are described in the documentation. The goal +here is to find the essential characteristics of the percussion +track which distinguishes the MIDI files. This is attempted +in the program midistats. Here is a short description. + +-corestats +Produces a line with 3 numbers separated by tabs. eg +384 8349 448 +It returns the number of divisions per quarter note beat (ppqn), +the number of note onsets in the midi file, and the maximum +number of quarter note beats in midi file. + +-pulseanalysis +Counts the number of note onsets as a function of its onset time +relative to a beat, grouping them into 12 intervals and returns +the result as a discrete probability density function. Generally, +the distribution consists of a couple of peaks corresponding +to quarter notes or eigth notes. If the distribution is flat, +it indicates that the times of the note occurrences have not been +quantized into beats and fractions. Here is a sample output. +0.3496,0.0000,0.0000,0.1602,0.0000,0.0002,0.2983,0.0000,0.0000,0.1914,0.0002,0.0001 + +-panal +Counts the number of note onsets for each percussion instrument. The first +number is the code (pitch) of the instrument, the second number is the +number of occurrences. eg. +35 337 37 16 38 432 39 208 40 231 42 1088 46 384 49 42 54 1104 57 5 70 1040 85 16 + +-ppatfor n +where n is the code number of the percussion instrument. Each beat +is represented by a 4 bit number where the position of the on-bit +indicates the time in the beat when the drum onset occurs. Thus +0 indicates that there was no note onset in that beat, 1 indicates +a note onset in the beginning of the beat, 4 indicates a note onset +in the middle of the beat, and etc. The function returns a string +of numbers ranging from 0 to 7 indicating the presence of note onsets +for the selected percussion instrument for the sequence of beats +in the midi file. Here is a truncated sample of the output. + +0 0 0 0 0 0 0 0 1 0 0 4 1 0 0 4 1 0 0 4 1 0 0 4 1 0 0 4 1 0 0 4 1 4 4 0 +1 0 0 0 1 0 5 0 1 0 5 0 1 0 5 0 1 0 5 0 1 0 5 0 1 0 5 0 1 0 5 0 1 0 0 0 +1 0 5 0 1 0 5 0 1 etc. + +One can see a repeating 4 beat pattern. + +-ppat +midistats attempts to find two percussion instruments in the midi file +which come closest to acting as the bass drum and snare drum. +If it is unsuccessful, it returns a message of its failue. Otherwise, +encodes the position of these drum onsets in a 8 bit byte for each +quarter note beat in the midi file. The lower (right) 4 bits encode the +bass drum and the higher (left) 4 bits encode the snare drum in the +same manner as described above for -ppatfor. +0 0 0 0 0 0 0 0 0 0 33 145 33 145 33 145 33 145 33 145 33 145 33 145 33 145 +33 145 33 145 33 145 33 145 33 145 33 145 33 145 33 145 33 145 33 145 33 145 +33 145 33 145 33 145 33 145 33 145 33 and etc. + +-ppathist +computes and displays the histogram of the values that would appear +when running the -ppat. eg. +bass 35 337 +snare 38 432 +1 (0.1) 64 32 (2.0) 8 33 (2.1) 136 144 (9.0) 8 145 (9.1) 136 + +The bass percussion code, the number of onsets, and the snare +percussion code and the number of onsets are given in the +first two lines. In the next line the number of occurrences of +each value in the -ppat listing is given. The number in parentheses +splits the two 4-bit values with a period. Thus 33 = (2*16 + 1). + + diff --git a/doc/midistats.1 b/doc/midistats.1 index 58c309f..d56f128 100644 --- a/doc/midistats.1 +++ b/doc/midistats.1 @@ -80,6 +80,17 @@ all channels except the percussion channel. collisions. Midistats counts the bar rhythm patterns using a hashing function. Presently collisions are ignored so occasionally two distinct rhythm patterns are counted as one. +.SH Advance Percussion Analysis Tools +.PP +A number of experimental tools for analyzing the percussion channel +(track) were introduced into midistats and are accessible through +the runtime arguments. When these tools are used in a script which +runs through a collection of midi files, you can build a database +of percussion descriptors. Some more details are given in the +file drums.txt which comes with this documentation. + + + .SH AUTHOR Seymour Shlien diff --git a/midistats.c b/midistats.c index 2e6a663..a998bc4 100644 --- a/midistats.c +++ b/midistats.c @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#define VERSION "0.65 March 12 2023 midistats" +#define VERSION "0.67 March 14 2023 midistats" #include /* Microsoft Visual C++ Version 6.0 or higher */ @@ -75,7 +75,8 @@ int debug; int pulseanalysis; int percanalysis; int percpattern; -int pdfpercpattern; +int percpatternfor; +int percpatternhist; int corestats; int chordthreshold; /* number of maximum number of pulses separating note */ int beatsPerBar = 4; /* 4/4 time */ @@ -101,7 +102,8 @@ int stats = 0; /* flag - gather and print statistics */ int pulseanalysis = 0; int percanalysis = 0; int percpattern = 0; -int pdfpercpattern = 0; +int percpatternfor = 0; +int percpatternhist = 0; int corestats = 0; @@ -115,6 +117,7 @@ int last_on_tick[17]; /* for detecting chords [SS] 2019-08-02 */ int histogram[256]; unsigned char drumpat[8000]; +int percnum; @@ -981,8 +984,6 @@ for (i = 0; i 0) {printf("%d %d ",i,histogram[i]); + if (histogram[i] > 0) { + printf(" %d",i); + output_perc_pattern(i); + printf(" %d ", histogram[i]); + } } - } printf("\n"); } @@ -1032,6 +1044,7 @@ for (i=1;i<256;i++) { void output_drumpat () { int i; for (i=0;i\n"); printf(" -corestats\n"); printf(" -pulseanalysis\n"); - printf(" -percanalysis\n"); - printf(" -percpattern\n"); - printf(" -pdfpercpattern\n"); + printf(" -panal\n"); + printf(" -ppat\n"); + printf(" -ppatfor\n"); + printf(" -ppathist\n"); printf(" -ver version number\n"); printf(" -d debug parameter\n"); printf(" The input filename is assumed to be any string not\n"); - printf(" beginning with a - (hyphen). It may be placed anywhere.\n"); + printf(" beginning with a - (hyphen).\n"); exit(0); }; return arg; @@ -1269,16 +1293,16 @@ if (percanalysis) { } printf("\n"); } -if (percanalysis) { - drumpattern(40); - output_drumpat(); - } if (percpattern) { drumanalysis(); percsummary(); output_drumpat(); } -if (pdfpercpattern) { +if (percpatternfor) { + drumpattern(percnum); + output_drumpat(); + } +if (percpatternhist) { drumanalysis(); percsummary(); drumPatternHistogram(); @@ -1298,6 +1322,6 @@ int argc; arg = process_command_line_arguments(argc,argv); if(stats == 1) midistats(argc,argv); if(pulseanalysis || corestats || percanalysis ||\ - percpattern || pdfpercpattern) loadEvents(); + percpatternfor || percpattern || percpatternhist) loadEvents(); return 0; }